Updated on 2026-08-14
This commit is contained in:
commit
125122adb7
1006 changed files with 31913 additions and 10618 deletions
12
.gitignore
vendored
12
.gitignore
vendored
|
|
@ -3,12 +3,24 @@
|
|||
# Built application files
|
||||
/build
|
||||
/buildSrc
|
||||
**/build/.transforms/**
|
||||
**/build/classes/**
|
||||
**/build/generated/**
|
||||
**/build/intermediates/**
|
||||
**/build/kotlin/**
|
||||
**/build/libs/**
|
||||
**/build/outputs/**
|
||||
**/build/tmp/**
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
||||
# Google services
|
||||
|
||||
|
||||
# Huawei services
|
||||
app/agconnect-services.json
|
||||
|
||||
app/src/debug/google-services.json
|
||||
app/src/internal/google-services.json
|
||||
app/src/external/google-services.json
|
||||
|
|
|
|||
|
|
@ -11,9 +11,14 @@ plugins {
|
|||
alias(deps.plugins.firebase.crashlytics)
|
||||
alias(deps.plugins.firebase.perf)
|
||||
alias(deps.plugins.ksp)
|
||||
id(deps.plugins.agconnect.get().pluginId)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
agcp {
|
||||
manifest = false
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.wallet"
|
||||
testOptions {
|
||||
|
|
@ -53,12 +58,35 @@ android {
|
|||
keyPassword = keystoreProperties["key_password"] as String
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions += "services"
|
||||
|
||||
productFlavors {
|
||||
create("google") {
|
||||
dimension = "services"
|
||||
buildConfigField("String", "FLAVOR_NAME", "\"google\"")
|
||||
}
|
||||
create("huawei") {
|
||||
dimension = "services"
|
||||
buildConfigField("String", "FLAVOR_NAME", "\"huawei\"")
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
buildConfigField("String", "BUILD_TYPE", "\"debug\"")
|
||||
}
|
||||
release {
|
||||
buildConfigField("String", "BUILD_TYPE", "\"release\"")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
exclude(group = "org.bouncycastle", module = "bcprov-jdk15to18")
|
||||
exclude(group = "com.github.komputing.kethereum")
|
||||
exclude(group = "com.android.tools.build", module = "gradle")
|
||||
|
||||
resolutionStrategy {
|
||||
dependencySubstitution {
|
||||
|
|
@ -121,11 +149,11 @@ dependencies {
|
|||
implementation(projects.domain.quotes)
|
||||
implementation(projects.domain.notifications)
|
||||
implementation(projects.domain.notifications.models)
|
||||
implementation(projects.domain.notifications.toggles)
|
||||
implementation(projects.domain.swap.models)
|
||||
implementation(projects.domain.swap)
|
||||
implementation(projects.domain.walletManager)
|
||||
implementation(projects.domain.walletManager.models)
|
||||
implementation(projects.domain.yieldSupply)
|
||||
|
||||
implementation(projects.common)
|
||||
implementation(projects.common.routing)
|
||||
|
|
@ -174,6 +202,7 @@ dependencies {
|
|||
implementation(projects.data.notifications)
|
||||
implementation(projects.data.swap)
|
||||
implementation(projects.data.walletManager)
|
||||
implementation(projects.data.yieldSupply)
|
||||
|
||||
/** Features */
|
||||
implementation(projects.features.referral.impl)
|
||||
|
|
@ -229,8 +258,11 @@ dependencies {
|
|||
implementation(projects.features.hotWallet.api)
|
||||
implementation(projects.features.hotWallet.impl)
|
||||
implementation(projects.features.kyc.api)
|
||||
//TODO disable for release because of the permissions
|
||||
// implementation(projects.features.kyc.impl)
|
||||
debugImplementation(projects.features.kyc.impl)
|
||||
internalImplementation(projects.features.kyc.impl)
|
||||
mockedImplementation(projects.features.kyc.impl)
|
||||
releaseImplementation(projects.features.kyc.mock)
|
||||
externalImplementation(projects.features.kyc.mock)
|
||||
implementation(projects.features.welcome.api)
|
||||
implementation(projects.features.welcome.impl)
|
||||
implementation(projects.features.createWalletSelection.api)
|
||||
|
|
@ -243,8 +275,12 @@ dependencies {
|
|||
implementation(projects.features.tangempay.details.impl)
|
||||
implementation(projects.features.tangempay.main.api)
|
||||
implementation(projects.features.tangempay.main.impl)
|
||||
implementation(projects.features.tangempay.onboarding.api)
|
||||
implementation(projects.features.tangempay.onboarding.impl)
|
||||
implementation(projects.features.tokenRecieve.api)
|
||||
implementation(projects.features.tokenRecieve.impl)
|
||||
implementation(projects.features.yieldSupply.api)
|
||||
implementation(projects.features.yieldSupply.impl)
|
||||
|
||||
/** AndroidX libraries */
|
||||
implementation(deps.androidx.core.ktx)
|
||||
|
|
@ -318,7 +354,7 @@ dependencies {
|
|||
implementation(deps.coil.gif)
|
||||
implementation(deps.coil.svg)
|
||||
implementation(deps.amplitude)
|
||||
implementation(deps.kotsonGson)
|
||||
implementation(deps.appsflyer)
|
||||
implementation(deps.spongecastle.core)
|
||||
implementation(deps.lottie)
|
||||
implementation(deps.compose.accompanist.appCompatTheme)
|
||||
|
|
@ -379,4 +415,9 @@ dependencies {
|
|||
// excludes version 9999.0-empty-to-avoid-conflict-with-guava
|
||||
exclude(group = "com.google.guava", module = "listenablefuture")
|
||||
}
|
||||
|
||||
/** Huawei flavor-specific dependencies */
|
||||
"huaweiImplementation"(deps.huawei.push)
|
||||
"huaweiImplementation"(deps.agconnect.agcp)
|
||||
"huaweiImplementation"(deps.agconnect.core)
|
||||
}
|
||||
11
app/proguard-rules.pro
vendored
11
app/proguard-rules.pro
vendored
|
|
@ -7,6 +7,13 @@
|
|||
-keep class com.google.android.gms.internal.** { *; }
|
||||
-keepclasseswithmembers class com.google.firebase.FirebaseException
|
||||
|
||||
# huawei push kit
|
||||
-ignorewarnings
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
-keep class com.huawei.hianalytics.**{*;}
|
||||
-keep class com.huawei.updatesdk.**{*;}
|
||||
-keep class com.huawei.hms.**{*;}
|
||||
|
||||
# hedera sdk
|
||||
-keep class com.hedera.hashgraph.sdk.** { *; }
|
||||
-keep interface com.hedera.hashgraph.sdk.** { *; }
|
||||
|
|
@ -206,3 +213,7 @@
|
|||
-keep class **.R$* {
|
||||
<fields>;
|
||||
}
|
||||
|
||||
# appsflyer
|
||||
-keep class com.appsflyer.** { *; }
|
||||
-keep class kotlin.jvm.internal.** { *; }
|
||||
|
|
@ -13,12 +13,19 @@ import com.kaspersky.components.composesupport.config.addComposeSupport
|
|||
import com.kaspersky.kaspresso.kaspresso.Kaspresso
|
||||
import com.kaspersky.kaspresso.testcases.api.testcase.TestCase
|
||||
import com.tangem.common.allure.FailedStepScreenshotInterceptor
|
||||
import com.tangem.common.constants.TestConstants.ALLURE_LABEL_NAME
|
||||
import com.tangem.common.constants.TestConstants.ALLURE_LABEL_VALUE
|
||||
import com.tangem.common.rules.ApiEnvironmentRule
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.core.configtoggle.feature.MutableFeatureTogglesManager
|
||||
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.domain.promo.PromoRepository
|
||||
import com.tangem.domain.promo.models.PromoId
|
||||
import com.tangem.tap.MainActivity
|
||||
import dagger.hilt.android.testing.HiltAndroidRule
|
||||
import io.qameta.allure.kotlin.Allure
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Rule
|
||||
import org.junit.rules.RuleChain
|
||||
|
|
@ -46,6 +53,12 @@ abstract class BaseTestCase : TestCase(
|
|||
@Inject
|
||||
lateinit var appPreferencesStore: AppPreferencesStore
|
||||
|
||||
@Inject
|
||||
lateinit var featureTogglesManager: FeatureTogglesManager
|
||||
|
||||
@Inject
|
||||
lateinit var promoRepository: PromoRepository
|
||||
|
||||
private val hiltRule = HiltAndroidRule(this)
|
||||
private val apiEnvironmentRule = ApiEnvironmentRule()
|
||||
private val permissionRule = GrantPermissionRule.grant(
|
||||
|
|
@ -78,6 +91,7 @@ abstract class BaseTestCase : TestCase(
|
|||
additionalBeforeSection: () -> Unit = {},
|
||||
additionalAfterSection: () -> Unit = {},
|
||||
) = before {
|
||||
Allure.label(ALLURE_LABEL_NAME, ALLURE_LABEL_VALUE)
|
||||
hiltRule.inject()
|
||||
runBlocking {
|
||||
appPreferencesStore.editData { mutablePreferences ->
|
||||
|
|
@ -86,10 +100,12 @@ abstract class BaseTestCase : TestCase(
|
|||
value = false
|
||||
)
|
||||
}
|
||||
promoRepository.setNeverToShowWalletPromo(PromoId.Sepa)
|
||||
}
|
||||
apiEnvironmentRule.setup(apiConfigsManager)
|
||||
ActivityScenario.launch(MainActivity::class.java)
|
||||
Intents.init()
|
||||
setFeatureToggles()
|
||||
additionalBeforeSection()
|
||||
}.after {
|
||||
additionalAfterSection()
|
||||
|
|
@ -113,4 +129,18 @@ abstract class BaseTestCase : TestCase(
|
|||
{
|
||||
composeTestRule.onRoot(useUnmergedTree = useUnmergedTree).printToLog(tag, maxDepth)
|
||||
}
|
||||
|
||||
|
||||
private fun setFeatureToggles() {
|
||||
runBlocking {
|
||||
with(featureTogglesManager as MutableFeatureTogglesManager) {
|
||||
changeToggle("WALLET_CONNECT_REDESIGN_ENABLED", true)
|
||||
changeToggle("WALLET_BALANCE_FETCHER_ENABLED", true)
|
||||
changeToggle("SEND_VIA_SWAP_ENABLED", true)
|
||||
changeToggle("SWAP_REDESIGN_ENABLED", true)
|
||||
changeToggle("SEND_REDESIGN_ENABLED", true)
|
||||
changeToggle("NEW_ONRAMP_MAIN_ENABLED", true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,5 +3,12 @@ package com.tangem.common.constants
|
|||
object TestConstants {
|
||||
const val TOTAL_BALANCE = "$3,299.18"
|
||||
|
||||
const val RECIPIENT_ADDRESS = "0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0"
|
||||
|
||||
const val WAIT_UNTIL_TIMEOUT = 20_000L
|
||||
|
||||
const val MARKETS_MAIN_NETWORK_SUFFIX = "MAIN"
|
||||
|
||||
const val ALLURE_LABEL_NAME = "Owner"
|
||||
const val ALLURE_LABEL_VALUE = "Kaspresso"
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
package com.tangem.common.extensions
|
||||
|
||||
import androidx.test.uiautomator.By
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.wallet.R
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
|
||||
fun BaseTestCase.swipeUp(
|
||||
startHeightRatio: Float = 0.8f,
|
||||
endHeightRatio: Float = 0.03f,
|
||||
steps: Int = 15
|
||||
fun BaseTestCase.swipeVertical(
|
||||
direction: SwipeDirection,
|
||||
startHeightRatio: Float = if (direction == SwipeDirection.UP) 0.8f else 0.03f,
|
||||
endHeightRatio: Float = if (direction == SwipeDirection.UP) 0.03f else 0.8f,
|
||||
steps: Int = 15,
|
||||
) {
|
||||
device.uiDevice.swipe(
|
||||
device.uiDevice.displayWidth / 2,
|
||||
|
|
@ -14,4 +18,41 @@ fun BaseTestCase.swipeUp(
|
|||
(device.uiDevice.displayHeight * endHeightRatio).toInt(),
|
||||
steps
|
||||
)
|
||||
}
|
||||
|
||||
fun BaseTestCase.pullToRefresh() {
|
||||
swipeVertical(
|
||||
direction = SwipeDirection.DOWN,
|
||||
startHeightRatio = 0.2f,
|
||||
endHeightRatio = 0.8f,
|
||||
steps = 2000
|
||||
)
|
||||
}
|
||||
|
||||
fun BaseTestCase.swipeMarketsBlock(direction: SwipeDirection) {
|
||||
val searchBarText = device.uiDevice
|
||||
.findObject(By.textContains(getResourceString(R.string.markets_search_header_title)))
|
||||
val bounds = searchBarText.visibleBounds
|
||||
|
||||
val centerX = bounds.centerX()
|
||||
val startY = bounds.centerY()
|
||||
val endY = when (direction) {
|
||||
SwipeDirection.UP -> 50
|
||||
SwipeDirection.DOWN -> device.uiDevice.displayHeight - 100
|
||||
}
|
||||
|
||||
device.uiDevice.swipe(centerX, startY, centerX, endY, 100)
|
||||
}
|
||||
|
||||
fun BaseTestCase.openTheAppFromRecents() {
|
||||
device.uiDevice.pressRecentApps()
|
||||
|
||||
val centerX = device.uiDevice.displayWidth / 2
|
||||
val centerY = device.uiDevice.displayHeight / 3
|
||||
device.uiDevice.click(centerX, centerY)
|
||||
device.uiDevice.click(centerX, centerY)
|
||||
}
|
||||
|
||||
enum class SwipeDirection {
|
||||
UP, DOWN
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.common.extensions
|
||||
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
|
||||
fun assertElementDoesNotExist(
|
||||
elementProvider: () -> KNode,
|
||||
elementDescription: String,
|
||||
) {
|
||||
try {
|
||||
elementProvider().assertExists()
|
||||
throw AssertionError("$elementDescription should not exist but was found")
|
||||
} catch (e: AssertionError) {
|
||||
val isNotFoundError = e.message?.let { message ->
|
||||
message.contains("No node found") ||
|
||||
message.contains("scrollable container") ||
|
||||
message.contains("There are no existing nodes") ||
|
||||
message.contains("There are no existing nodes for that selector")
|
||||
} ?: false
|
||||
if (isNotFoundError) {
|
||||
return
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,4 +5,5 @@ import io.github.kakaocup.compose.node.element.KNode
|
|||
fun KNode.clickWithAssertion() {
|
||||
assertIsDisplayed()
|
||||
performClick()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
package com.tangem.common.extensions
|
||||
|
||||
import io.github.kakaocup.kakao.common.views.KBaseView
|
||||
|
||||
fun <T : KBaseView<*>> T.withDialogRoot(): T {
|
||||
return this.also { inRoot { isDialog() } }
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package com.tangem.common.utils
|
||||
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.json.JSONObject
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
fun getWcUri(
|
||||
network: String = "ethereum",
|
||||
baseUrl: String = "[REDACTED_ENV_URL]"
|
||||
): String? {
|
||||
Timber.i("Getting WC URI for network: $network")
|
||||
|
||||
val client = OkHttpClient.Builder()
|
||||
.connectTimeout(30, TimeUnit.SECONDS) // Таймаут подключения
|
||||
.readTimeout(60, TimeUnit.SECONDS) // Таймаут чтения ответа
|
||||
.writeTimeout(30, TimeUnit.SECONDS) // Таймаут записи
|
||||
.callTimeout(90, TimeUnit.SECONDS) // Общий таймаут запроса
|
||||
.build()
|
||||
|
||||
val request = Request.Builder()
|
||||
.url("$baseUrl/wc_uri?network=$network")
|
||||
.get()
|
||||
.build()
|
||||
|
||||
return try {
|
||||
client.newCall(request).execute().use { response ->
|
||||
Timber.i("Response code: ${response.code}")
|
||||
|
||||
if (response.isSuccessful) {
|
||||
val body = response.body?.string() ?: ""
|
||||
Timber.i("Response body: $body")
|
||||
|
||||
val jsonObject = JSONObject(body)
|
||||
|
||||
if (jsonObject.getBoolean("success")) {
|
||||
val wcUri = jsonObject.getString("wcUri")
|
||||
Timber.i("Got WC URI successfully: $wcUri")
|
||||
|
||||
wcUri
|
||||
} else {
|
||||
Timber.e("API returned error: ${jsonObject.optString("error", "Unknown")}")
|
||||
null
|
||||
}
|
||||
} else {
|
||||
val errorBody = response.body?.string() ?: "No error body"
|
||||
Timber.e("Request failed: ${response.code}, body: $errorBody")
|
||||
null
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error getting WC URI")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun checkServiceHealth(
|
||||
baseUrl: String = "[REDACTED_ENV_URL]"
|
||||
): String? {
|
||||
Timber.i("Checking service health")
|
||||
|
||||
val client = OkHttpClient()
|
||||
val request = Request.Builder()
|
||||
.url("$baseUrl/health")
|
||||
.get()
|
||||
.build()
|
||||
|
||||
return try {
|
||||
client.newCall(request).execute().use { response ->
|
||||
Timber.i("Response code: ${response.code}")
|
||||
|
||||
if (response.isSuccessful) {
|
||||
val body = response.body?.string() ?: ""
|
||||
Timber.i("Response body: $body")
|
||||
|
||||
if (body.isEmpty()) {
|
||||
Timber.e("Response body is empty")
|
||||
return null
|
||||
}
|
||||
|
||||
val jsonObject = JSONObject(body)
|
||||
val status = jsonObject.optString("status", "")
|
||||
|
||||
if (status.isNotEmpty()) {
|
||||
Timber.i("Got status successfully: $status")
|
||||
status
|
||||
} else {
|
||||
Timber.e("Status field is missing or empty")
|
||||
null
|
||||
}
|
||||
} else {
|
||||
val errorBody = response.body?.string() ?: "No error body"
|
||||
Timber.e("Request failed: ${response.code}, body: $errorBody")
|
||||
null
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error checking health")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.screens.*
|
||||
import com.tangem.screens.AlreadyUsedWalletDialogPageObject.thisIsMyWalletButton
|
||||
import com.tangem.tap.domain.sdk.mocks.MockContent
|
||||
import com.tangem.tap.domain.sdk.mocks.MockProvider
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
||||
fun BaseTestCase.openMainScreen(
|
||||
productType: ProductType? = null,
|
||||
mockContent: MockContent? = null,
|
||||
alreadyActivatedDialogIsShown : Boolean = false
|
||||
) {
|
||||
if (productType != null) {
|
||||
MockProvider.setMocks(productType)
|
||||
}
|
||||
if (mockContent != null) {
|
||||
MockProvider.setMocks(mockContent)
|
||||
}
|
||||
step("Click on 'Accept' button") {
|
||||
onDisclaimerScreen { acceptButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Scan' button") {
|
||||
onStoriesScreen { scanButton.clickWithAssertion() }
|
||||
}
|
||||
if (alreadyActivatedDialogIsShown) {
|
||||
step("Click on 'This is my wallet' button") {
|
||||
composeTestRule.waitForIdle()
|
||||
AlreadyUsedWalletDialogPageObject { thisIsMyWalletButton.click() }
|
||||
}
|
||||
}
|
||||
step("Assert 'Main' screen is displayed") {
|
||||
onMainScreen { screenContainer.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Market Tooltip' screen") {
|
||||
onMarketsTooltipScreen { contentContainer.clickWithAssertion() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.synchronizeAddresses(balance: String) {
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert wallet balance = '$balance'") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(balance) }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.openDeviceSettingsScreen() {
|
||||
step("Open wallet details") {
|
||||
onTopBar { moreButton.clickWithAssertion() }
|
||||
}
|
||||
step("Open 'Wallet settings' screen") {
|
||||
onDetailsScreen { walletNameButton.performClick() }
|
||||
}
|
||||
step("Click on 'Device settings' button") {
|
||||
onWalletSettingsScreen { deviceSettingsButton.clickWithAssertion() }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.Intent.*
|
||||
import android.net.Uri
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import io.github.kakaocup.kakao.intent.KIntent
|
||||
|
||||
fun openAppByDeepLink(deepLinkUri: String?) {
|
||||
val deeplinkScheme = "tangem://wc?uri="
|
||||
val context = ApplicationProvider.getApplicationContext<android.content.Context>()
|
||||
val intent = Intent(ACTION_VIEW, Uri.parse(deeplinkScheme + deepLinkUri)).apply {
|
||||
addFlags(FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
fun checkSendEMailIntentCalled() {
|
||||
val expectedIntent = KIntent {
|
||||
hasAction(ACTION_CHOOSER)
|
||||
hasExtra(EXTRA_TITLE, "Send mail...")
|
||||
hasExtraWithKey(EXTRA_INTENT)
|
||||
}
|
||||
expectedIntent.intended()
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.screens.onDeviceSettingsScreen
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
||||
fun BaseTestCase.openResetCardScreen(withBackup: Boolean = false) {
|
||||
step("Click on 'Scan card or ring' button") {
|
||||
onDeviceSettingsScreen { scanCardOrRingButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Reset to Factory Settings' button title is displayed") {
|
||||
onDeviceSettingsScreen { resetToFactorySettingsButtonTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Reset to Factory Settings' button subtitle is displayed") {
|
||||
onDeviceSettingsScreen { resetToFactorySettingsButtonSubtitle(withBackup).assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Reset to Factory Settings' button") {
|
||||
onDeviceSettingsScreen { resetToFactorySettingsButtonTitle.performClick() }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.screens.AlreadyUsedWalletDialogPageObject
|
||||
import com.tangem.screens.AlreadyUsedWalletDialogPageObject.cancelButton
|
||||
import com.tangem.screens.AlreadyUsedWalletDialogPageObject.message
|
||||
import com.tangem.screens.AlreadyUsedWalletDialogPageObject.requestSupportButton
|
||||
import com.tangem.screens.AlreadyUsedWalletDialogPageObject.thisIsMyWalletButton
|
||||
import com.tangem.screens.AlreadyUsedWalletDialogPageObject.title
|
||||
import com.tangem.screens.ScanWarningDialogPageObject
|
||||
import com.tangem.screens.onFailedTransactionDialog
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
||||
fun BaseTestCase.checkFailedTransactionDialog() {
|
||||
step("Assert failed transaction dialog is displayed") {
|
||||
onFailedTransactionDialog { dialogContainer.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert failed transaction dialog title is displayed") {
|
||||
onFailedTransactionDialog { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert failed transaction dialog text is displayed") {
|
||||
onFailedTransactionDialog { text.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Cancel' button is displayed") {
|
||||
onFailedTransactionDialog { cancelButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Support' button is displayed") {
|
||||
onFailedTransactionDialog { supportButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
fun checkScanWarningDialog() {
|
||||
step("Assert 'Scan warning' dialog title is displayed") {
|
||||
ScanWarningDialogPageObject { warningTitle.isDisplayed() }
|
||||
}
|
||||
step("Assert warning dialog message is displayed") {
|
||||
ScanWarningDialogPageObject { warningMessage.isDisplayed() }
|
||||
}
|
||||
step("Assert 'Cancel' button is displayed") {
|
||||
ScanWarningDialogPageObject { cancelButton.isDisplayed() }
|
||||
}
|
||||
step("Assert 'How to scan' button is displayed") {
|
||||
ScanWarningDialogPageObject { howToScanButton.isDisplayed() }
|
||||
}
|
||||
step("Assert 'Request support' button is displayed") {
|
||||
ScanWarningDialogPageObject { requestSupportButton.isDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
fun checkAlreadyUsedWalletDialog() {
|
||||
step("Assert 'Already used Wallet' dialog title is displayed") {
|
||||
AlreadyUsedWalletDialogPageObject { title.isDisplayed() }
|
||||
}
|
||||
step("Assert dialog message is displayed") {
|
||||
AlreadyUsedWalletDialogPageObject { message.isDisplayed() }
|
||||
}
|
||||
step("Assert 'This is my wallet' button is displayed") {
|
||||
AlreadyUsedWalletDialogPageObject { thisIsMyWalletButton.isDisplayed() }
|
||||
}
|
||||
step("Assert 'Cancel' button is displayed") {
|
||||
AlreadyUsedWalletDialogPageObject { cancelButton.isDisplayed() }
|
||||
}
|
||||
step("Assert 'Request support' button is displayed") {
|
||||
AlreadyUsedWalletDialogPageObject { requestSupportButton.isDisplayed() }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import androidx.compose.ui.test.junit4.ComposeTestRule
|
||||
import com.kaspersky.kaspresso.testcases.api.scenario.Scenario
|
||||
import com.kaspersky.kaspresso.testcases.core.testcontext.TestContext
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.screens.*
|
||||
import com.tangem.tap.domain.sdk.mocks.MockProvider
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
|
||||
class OpenMainScreenScenario(
|
||||
private val testRule: ComposeTestRule,
|
||||
private val productType: ProductType? = null,
|
||||
) : Scenario() {
|
||||
override val steps: TestContext<Unit>.() -> Unit = {
|
||||
if (productType != null) {
|
||||
MockProvider.setMocks(productType)
|
||||
}
|
||||
ComposeScreen.onComposeScreen<DisclaimerPageObject>(testRule) {
|
||||
step("Click on \"Accept\" button") {
|
||||
acceptButton.clickWithAssertion()
|
||||
}
|
||||
}
|
||||
ComposeScreen.onComposeScreen<StoriesPageObject>(testRule) {
|
||||
step("Click on \"Scan\" button") {
|
||||
scanButton.clickWithAssertion()
|
||||
}
|
||||
}
|
||||
ComposeScreen.onComposeScreen<MainScreenPageObject>(testRule) {
|
||||
step("Make sure wallet screen is visible") {
|
||||
assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
ComposeScreen.onComposeScreen<MarketsTooltipPageObject>(testRule) {
|
||||
step("Close Markets tooltip"){
|
||||
contentContainer.performClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.screens.onResetCardScreen
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
||||
fun BaseTestCase.checkResetCardScreen(withBackup: Boolean = false) {
|
||||
step("Assert title is displayed") {
|
||||
onResetCardScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Attention' image is displayed") {
|
||||
onResetCardScreen { attentionImage.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Attention' subtitle is displayed") {
|
||||
onResetCardScreen { subtitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert description is displayed") {
|
||||
onResetCardScreen { description.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Lost wallet' checkbox is displayed") {
|
||||
onResetCardScreen { lostWalletAccessCheckBox.assertIsDisplayed() }
|
||||
}
|
||||
if (withBackup) {
|
||||
step("Assert 'Lost password restore' checkbox is displayed") {
|
||||
onResetCardScreen { lostPasswordRestoreCheckBox.assertIsDisplayed() }
|
||||
}
|
||||
} else {
|
||||
step("Assert 'Lost password restore' checkbox doesn't exist") {
|
||||
onResetCardScreen { lostPasswordRestoreCheckBox.assertDoesNotExist() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.checkCheckBoxLogic(withBackup: Boolean = false) {
|
||||
if (withBackup) {
|
||||
step("Click on 'Lost wallet' checkbox") {
|
||||
onResetCardScreen { lostWalletAccessCheckBox.performClick() }
|
||||
}
|
||||
step("Assert 'Lost wallet' checkbox is enabled") {
|
||||
onResetCardScreen { lostWalletAccessCheckBox.assertIsEnabled() }
|
||||
}
|
||||
step("Assert 'Reset the card' button is disabled") {
|
||||
onResetCardScreen { resetCardButton.assertIsNotEnabled() }
|
||||
}
|
||||
step("Click on 'Lost password restore' checkbox") {
|
||||
onResetCardScreen { lostPasswordRestoreCheckBox.performClick() }
|
||||
}
|
||||
step("Assert 'Lost password restore' checkbox is enabled") {
|
||||
onResetCardScreen { lostPasswordRestoreCheckBox.assertIsEnabled() }
|
||||
}
|
||||
step("Assert 'Reset the card' button is enabled") {
|
||||
onResetCardScreen { resetCardButton.assertIsEnabled() }
|
||||
}
|
||||
step("Click on 'Lost password restore' checkbox") {
|
||||
onResetCardScreen { lostPasswordRestoreCheckBox.performClick() }
|
||||
}
|
||||
step("Assert 'Reset the card' button is disabled") {
|
||||
onResetCardScreen { resetCardButton.assertIsNotEnabled() }
|
||||
}
|
||||
step("Click on 'Lost wallet' checkbox") {
|
||||
onResetCardScreen { lostWalletAccessCheckBox.performClick() }
|
||||
}
|
||||
step("Click on 'Lost password restore' checkbox") {
|
||||
onResetCardScreen { lostPasswordRestoreCheckBox.performClick() }
|
||||
}
|
||||
step("Assert 'Reset the card' button is disabled") {
|
||||
onResetCardScreen { resetCardButton.assertIsNotEnabled() }
|
||||
}
|
||||
} else {
|
||||
step("Click on 'Lost wallet' checkbox") {
|
||||
onResetCardScreen { lostWalletAccessCheckBox.performClick() }
|
||||
}
|
||||
step("Assert 'Lost wallet' checkbox is enabled") {
|
||||
onResetCardScreen { lostWalletAccessCheckBox.assertIsEnabled() }
|
||||
}
|
||||
step("Assert 'Reset the card' button is enabled") {
|
||||
onResetCardScreen { resetCardButton.assertIsEnabled() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.screens.onWalletConnectBottomSheet
|
||||
import com.tangem.screens.onWalletConnectDetailsBottomSheet
|
||||
import com.tangem.screens.onWalletConnectScreen
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
||||
fun BaseTestCase.checkWalletConnectBottomSheet() {
|
||||
step("Assert 'Wallet Connect' bottom sheet title is displayed") {
|
||||
onWalletConnectBottomSheet { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet app icon is displayed") {
|
||||
onWalletConnectBottomSheet { appIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet app name is displayed") {
|
||||
onWalletConnectBottomSheet { appName.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet approve icon is displayed") {
|
||||
onWalletConnectBottomSheet { approveIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet app URL is displayed") {
|
||||
onWalletConnectBottomSheet { appUrl.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet connection request icon is displayed") {
|
||||
onWalletConnectBottomSheet { connectionRequestIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet connection request text is displayed") {
|
||||
onWalletConnectBottomSheet { connectionRequestText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet connection request chevron is displayed") {
|
||||
onWalletConnectBottomSheet { connectionRequestChevron.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet wallet icon is displayed") {
|
||||
onWalletConnectBottomSheet { walletIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet wallet title is displayed") {
|
||||
onWalletConnectBottomSheet { walletNameTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet wallet name is displayed") {
|
||||
onWalletConnectBottomSheet { walletName.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet networks icon is displayed") {
|
||||
onWalletConnectBottomSheet { networksIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet networks title is displayed") {
|
||||
onWalletConnectBottomSheet { networksTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet right networks icons is displayed") {
|
||||
onWalletConnectBottomSheet { networksIcons.assertIsDisplayed() }
|
||||
}
|
||||
step("'Wallet Connect' bottom sheet networks selector icon is displayed") {
|
||||
onWalletConnectBottomSheet { networksSelectorIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet 'Cancel' button is displayed") {
|
||||
onWalletConnectBottomSheet { cancelButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet 'Connect' button is displayed") {
|
||||
onWalletConnectBottomSheet { connectButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.checkWalletConnectScreen() {
|
||||
step("Assert 'Wallet Connect' title is displayed") {
|
||||
onWalletConnectScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'More' button is displayed") {
|
||||
onWalletConnectScreen { moreButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert wallet name is displayed") {
|
||||
onWalletConnectScreen { walletName.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert app icon is displayed") {
|
||||
onWalletConnectScreen { appIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert app name is displayed") {
|
||||
onWalletConnectScreen { appName.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert approve icon is displayed") {
|
||||
onWalletConnectScreen { approveIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert app URL is displayed") {
|
||||
onWalletConnectScreen { appUrl.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'New Connection' button is displayed") {
|
||||
onWalletConnectScreen { newConnectionButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.checkWalletConnectDetailsBottomSheet(dAppName: String) {
|
||||
step("Assert connection details title is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert date is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { date.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Close' button is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { closeButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert app icon is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { appIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert app name is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { appName.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert approve icon is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { approveIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert app URL is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { appUrl.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert wallet icon is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { walletIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert wallet title is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { walletTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert wallet name is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { walletName.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Connected networks' title is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { connectedNetworksTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert connected network item is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { connectedNetworkItem.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert connected network icon is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { connectedNetworkIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert connected dApp name: '$dAppName'") {
|
||||
onWalletConnectDetailsBottomSheet { connectedNetworkName.assertTextContains(dAppName) }
|
||||
}
|
||||
step("Assert connected network symbol is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { connectedNetworkSymbol.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Disconnect button' is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { disconnectButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import com.tangem.common.extensions.withDialogRoot
|
||||
import com.tangem.wallet.R
|
||||
import io.github.kakaocup.kakao.text.KButton
|
||||
import io.github.kakaocup.kakao.text.KTextView
|
||||
|
||||
object AlreadyUsedWalletDialogPageObject : BaseDialog() {
|
||||
|
||||
val title = KTextView {
|
||||
withText(R.string.security_alert_title)
|
||||
}.withDialogRoot()
|
||||
|
||||
val message = KTextView {
|
||||
withText(R.string.wallet_been_activated_message)
|
||||
}.withDialogRoot()
|
||||
|
||||
val cancelButton = KButton {
|
||||
withText(R.string.common_cancel)
|
||||
}.withDialogRoot()
|
||||
|
||||
val requestSupportButton = KButton {
|
||||
withText(R.string.alert_button_request_support)
|
||||
}.withDialogRoot()
|
||||
|
||||
val thisIsMyWalletButton = KButton {
|
||||
withText(R.string.this_is_my_wallet_title)
|
||||
}.withDialogRoot()
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
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.BaseBottomSheetTestTags
|
||||
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 BaseBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<BaseBottomSheetPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val hideButton: KNode = child {
|
||||
hasText(getResourceString(R.string.token_details_hide_token))
|
||||
hasTestTag(BaseBottomSheetTestTags.ACTION_TITLE)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onBottomSheet(function: BaseBottomSheetPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
14
app/src/androidTest/kotlin/com/tangem/screens/BaseDialog.kt
Normal file
14
app/src/androidTest/kotlin/com/tangem/screens/BaseDialog.kt
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import io.github.kakaocup.kakao.common.views.KBaseView
|
||||
|
||||
abstract class BaseDialog : KBaseView<BaseDialog>({ isRoot() }) {
|
||||
|
||||
init {
|
||||
setDialogRoot()
|
||||
}
|
||||
|
||||
private fun setDialogRoot() {
|
||||
inRoot { isDialog() }
|
||||
}
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ class BuyTokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProv
|
|||
}
|
||||
|
||||
val errorNotificationText: KNode = child {
|
||||
hasTestTag(NotificationTestTags.TEXT)
|
||||
hasTestTag(NotificationTestTags.MESSAGE)
|
||||
hasText(getResourceString(R.string.common_unknown_error))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
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.utils.LazyListItemNode
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.DeviceSettingsScreenTestTags
|
||||
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
|
||||
import com.tangem.wallet.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
|
||||
|
||||
class DeviceSettingsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<DeviceSettingsPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
private val lazyList = KLazyListNode(
|
||||
semanticsProvider = semanticsProvider,
|
||||
viewBuilderAction = { hasTestTag(DeviceSettingsScreenTestTags.LAZY_LIST) },
|
||||
itemTypeBuilder = { itemType(::LazyListItemNode) },
|
||||
positionMatcher = { position ->
|
||||
SemanticsMatcher.expectValue(
|
||||
LazyListItemPositionSemantics,
|
||||
position
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
val imageBlock: KNode = child {
|
||||
hasTestTag(DeviceSettingsScreenTestTags.IMAGE_BLOCK)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val resetToFactorySettingsButtonTitle: KNode = child {
|
||||
hasTestTag(DeviceSettingsScreenTestTags.ITEM_TITLE)
|
||||
hasText(getResourceString(R.string.card_settings_reset_card_to_factory))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val scanCardOrRingButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.scan_card_settings_button))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun resetToFactorySettingsButtonSubtitle(withBackup: Boolean = false): KNode = child {
|
||||
hasTestTag(DeviceSettingsScreenTestTags.ITEM_SUBTITLE)
|
||||
useUnmergedTree = true
|
||||
if (withBackup) {
|
||||
hasText(getResourceString(R.string.reset_card_with_backup_to_factory_message))
|
||||
} else {
|
||||
hasText(getResourceString(R.string.reset_card_without_backup_to_factory_message))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onDeviceSettingsScreen(function: DeviceSettingsPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -4,7 +4,7 @@ import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
|||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.DialogTestTags
|
||||
import com.tangem.core.ui.test.BaseDialogTestTags
|
||||
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
|
||||
|
|
@ -14,7 +14,7 @@ class DialogPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|||
ComposeScreen<DialogPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val dialogContainer: KNode = child {
|
||||
hasTestTag(DialogTestTags.DIALOG_CONTAINER)
|
||||
hasTestTag(BaseDialogTestTags.CONTAINER)
|
||||
}
|
||||
|
||||
val cancelButton: KNode = child {
|
||||
|
|
@ -31,6 +31,16 @@ class DialogPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|||
hasTestTag(BaseButtonTestTags.BUTTON)
|
||||
hasText(getResourceString(R.string.common_confirm))
|
||||
}
|
||||
|
||||
val continueButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.BUTTON)
|
||||
hasText(getResourceString(R.string.common_continue))
|
||||
}
|
||||
|
||||
val okButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.BUTTON)
|
||||
hasText(getResourceString(R.string.common_ok))
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onDialog(function: DialogPageObject.() -> Unit) =
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import com.kaspersky.kaspresso.screens.KScreen
|
||||
import com.tangem.core.ui.R
|
||||
import io.github.kakaocup.kakao.text.KButton
|
||||
import io.github.kakaocup.kakao.text.KTextView
|
||||
|
||||
object FailedCardVerificationDialogPageObject : KScreen<FailedCardVerificationDialogPageObject>() {
|
||||
|
||||
override val layoutId: Int? = null
|
||||
override val viewClass: Class<*>? = null
|
||||
|
||||
val title = KTextView {
|
||||
withId(R.id.alertTitle)
|
||||
}
|
||||
|
||||
val message = KTextView {
|
||||
withId(R.id.message)
|
||||
}
|
||||
|
||||
val cancelButton = KButton {
|
||||
withText(R.string.common_cancel)
|
||||
}
|
||||
|
||||
val understandButton = KButton {
|
||||
withText(R.string.common_understand)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
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.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.BaseDialogTestTags
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import com.tangem.common.ui.R as CommonUIR
|
||||
|
||||
class FailedTransactionDialogPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<FailedTransactionDialogPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val dialogContainer: KNode = child {
|
||||
hasTestTag(BaseDialogTestTags.CONTAINER)
|
||||
}
|
||||
|
||||
val title: KNode = child {
|
||||
hasTestTag(BaseDialogTestTags.TITLE)
|
||||
hasText(getResourceString(CommonUIR.string.send_alert_transaction_failed_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val text: KNode = child {
|
||||
hasTestTag(BaseDialogTestTags.TEXT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val cancelButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.BUTTON)
|
||||
hasText(getResourceString(R.string.common_cancel))
|
||||
}
|
||||
|
||||
val supportButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.BUTTON)
|
||||
hasText(getResourceString(R.string.common_support))
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onFailedTransactionDialog(function: FailedTransactionDialogPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -3,11 +3,11 @@ package com.tangem.screens
|
|||
import androidx.compose.ui.test.ExperimentalTestApi
|
||||
import androidx.compose.ui.test.SemanticsMatcher
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import androidx.compose.ui.test.hasAnyAncestor
|
||||
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.test.*
|
||||
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
|
|
@ -35,7 +35,11 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
}
|
||||
)
|
||||
|
||||
val synchronizeAddressesButton: KNode = child {
|
||||
val screenContainer: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.SCREEN_CONTAINER)
|
||||
}
|
||||
|
||||
val synchronizeAddressesButton: KNode = lazyList.child {
|
||||
hasText(getResourceString(R.string.common_generate_addresses))
|
||||
}
|
||||
|
||||
|
|
@ -44,6 +48,116 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
hasText(getResourceString(R.string.common_buy))
|
||||
}
|
||||
|
||||
val walletNameText: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.CARD_TITLE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val walletImage: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.CARD_IMAGE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val marketPriceBlock: KNode = child {
|
||||
hasTestTag(MarketPriceBlockTestTags.BLOCK)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val marketPriceText: KNode = child {
|
||||
hasTestTag(MarketPriceBlockTestTags.TEXT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val transactionsExplorerIcon: KNode = child {
|
||||
hasTestTag(TransactionHistoryBlockTestTags.EXPLORER_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val transactionsTitle: KNode = child {
|
||||
hasTestTag(TransactionHistoryBlockTestTags.TITLE_TEXT)
|
||||
hasText(getResourceString(R.string.common_transactions))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun transactionsExplorer(): KNode {
|
||||
return child {
|
||||
hasTestTag(TransactionHistoryBlockTestTags.EXPLORER_TEXT)
|
||||
hasText(getResourceString(R.string.common_explorer))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
val notificationContainer: KNode = child {
|
||||
hasTestTag(NotificationTestTags.CONTAINER)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val devCardNotificationIcon: KNode = child {
|
||||
hasAnySibling(withText(getResourceString(R.string.warning_developer_card_title)))
|
||||
hasTestTag(NotificationTestTags.ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val devCardNotificationTitle: KNode = child {
|
||||
hasTestTag(NotificationTestTags.TITLE)
|
||||
hasText(getResourceString(R.string.warning_developer_card_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val devCardNotificationMessage: KNode = child {
|
||||
hasTestTag(NotificationTestTags.MESSAGE)
|
||||
hasText(getResourceString(R.string.warning_developer_card_message))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val seedPhraseNotificationIcon: KNode = child {
|
||||
hasAnySibling(withText(getResourceString(R.string.warning_seedphrase_issue_title)))
|
||||
hasTestTag(NotificationTestTags.ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val seedPhraseNotificationTitle: KNode = child {
|
||||
hasTestTag(NotificationTestTags.TITLE)
|
||||
hasText(getResourceString(R.string.warning_seedphrase_issue_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val seedPhraseNotificationMessage: KNode = child {
|
||||
hasTestTag(NotificationTestTags.MESSAGE)
|
||||
hasText(getResourceString(R.string.warning_seedphrase_issue_message))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val totalBalanceContainer: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.WALLET_LIST_ITEM)
|
||||
}
|
||||
|
||||
val totalBalanceMenuRenameWallet: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.TOTAL_BALANCE_MENU_ITEM)
|
||||
hasText(getResourceString(R.string.common_rename))
|
||||
}
|
||||
|
||||
val totalBalanceMenuDeleteWallet: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.TOTAL_BALANCE_MENU_ITEM)
|
||||
hasText(getResourceString(R.string.common_delete))
|
||||
}
|
||||
|
||||
val totalBalanceText: KNode = child {
|
||||
hasParent(withTestTag(MainScreenTestTags.WALLET_BALANCE))
|
||||
}
|
||||
|
||||
val notificationYesButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.common_yes))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val notificationNoButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.common_no))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Find token list item with title and address
|
||||
*/
|
||||
|
|
@ -58,19 +172,6 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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> {
|
||||
|
|
@ -81,6 +182,14 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
}
|
||||
}
|
||||
|
||||
fun organizeTokensButtonWithoutLazySearch(): KNode {
|
||||
return child {
|
||||
hasTestTag(MainScreenTestTags.ORGANIZE_TOKENS_BUTTON)
|
||||
hasText(getResourceString(R.string.organize_tokens_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
fun tokenNetworkGroupTitle(tokenNetwork: String): KNode {
|
||||
return lazyList.child {
|
||||
hasTestTag(MainScreenTestTags.TOKEN_LIST_ITEM)
|
||||
|
|
@ -101,6 +210,12 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
}
|
||||
}
|
||||
|
||||
fun KNode.assertIsUnreachable() {
|
||||
this {
|
||||
hasAnyAncestor(withText(getResourceString(R.string.common_unreachable)))
|
||||
assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This assertion is required to properly verify the token's absence in the semantic tree.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
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.constants.TestConstants.MARKETS_MAIN_NETWORK_SUFFIX
|
||||
import com.tangem.common.utils.LazyListItemNode
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.MarketsTestTags
|
||||
import com.tangem.core.ui.test.TopAppBarTestTags
|
||||
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
|
||||
import com.tangem.features.onramp.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
|
||||
|
||||
class MarketsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<MarketsPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
private val lazyList = KLazyListNode(
|
||||
semanticsProvider = semanticsProvider,
|
||||
viewBuilderAction = { hasTestTag(MarketsTestTags.TOKENS_LIST) },
|
||||
itemTypeBuilder = { itemType(::LazyListItemNode) },
|
||||
positionMatcher = { position ->
|
||||
SemanticsMatcher.expectValue(
|
||||
LazyListItemPositionSemantics,
|
||||
position
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
val addToPortfolioButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.common_add_to_portfolio))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val mainNetworkSwitch: KNode = child<KNode> {
|
||||
hasAnyDescendant(withText(MARKETS_MAIN_NETWORK_SUFFIX))
|
||||
useUnmergedTree = true
|
||||
}.child { hasTestTag(MarketsTestTags.ADD_TO_PORTFOLIO_SWITCH) }
|
||||
|
||||
val topBarBackButton: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.CLOSE_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun tokenWithTitle(title: String): KNode {
|
||||
return lazyList.child<KNode> {
|
||||
hasText(title)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onMarketsScreen(function: MarketsPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -5,8 +5,8 @@ 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.test.TokenElementsTestTags
|
||||
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
|
|
@ -14,10 +14,10 @@ import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onCompose
|
|||
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
|
||||
import androidx.compose.ui.test.hasAnySibling as withAnySibling
|
||||
import androidx.compose.ui.test.hasTestTag as withTestTag
|
||||
import androidx.compose.ui.test.hasText as withText
|
||||
|
||||
class OrganizeTokensPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<OrganizeTokensPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
|
@ -25,10 +25,12 @@ class OrganizeTokensPageObject(semanticsProvider: SemanticsNodeInteractionsProvi
|
|||
// region TopBar
|
||||
val title: KNode = child {
|
||||
hasText(getResourceString(R.string.organize_tokens_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
private val topBarGroupButton: KNode = child {
|
||||
hasTestTag(OrganizeTokensScreenTestTags.GROUP_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val groupButton: KNode = topBarGroupButton.child {
|
||||
|
|
@ -100,10 +102,14 @@ class OrganizeTokensPageObject(semanticsProvider: SemanticsNodeInteractionsProvi
|
|||
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))))
|
||||
)
|
||||
hasParent(
|
||||
withTestTag(TokenElementsTestTags.TOKEN_NON_FIAT_BLOCK)
|
||||
.and(
|
||||
withAnySibling(
|
||||
withTestTag(TokenElementsTestTags.TOKEN_TITLE)
|
||||
.and(withAnyChild(withText(tokenTitle)))
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.ResetCardScreenTestTags
|
||||
import com.tangem.wallet.R
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import androidx.compose.ui.test.hasTestTag as withTestTag
|
||||
import androidx.compose.ui.test.hasText as withText
|
||||
|
||||
class ResetCardPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<ResetCardPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val title: KNode = child {
|
||||
hasTestTag(ResetCardScreenTestTags.TITLE)
|
||||
hasText(getResourceString(R.string.card_settings_reset_card_to_factory))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val attentionImage: KNode = child {
|
||||
hasTestTag(ResetCardScreenTestTags.ATTENTION_IMAGE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val subtitle: KNode = child {
|
||||
hasTestTag(ResetCardScreenTestTags.SUBTITLE)
|
||||
hasText(getResourceString(R.string.common_attention))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val description: KNode = child {
|
||||
hasTestTag(ResetCardScreenTestTags.DESCRIPTION)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val lostWalletAccessCheckBox: KNode = child {
|
||||
hasTestTag(ResetCardScreenTestTags.CHECKBOX)
|
||||
hasAnySibling(
|
||||
withTestTag(ResetCardScreenTestTags.CHECKBOX_TEXT) and
|
||||
withText(getResourceString(R.string.reset_card_to_factory_condition_1))
|
||||
)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val lostPasswordRestoreCheckBox: KNode = child {
|
||||
hasTestTag(ResetCardScreenTestTags.CHECKBOX)
|
||||
hasAnySibling(
|
||||
withTestTag(ResetCardScreenTestTags.CHECKBOX_TEXT) and
|
||||
withText(getResourceString(R.string.reset_card_to_factory_condition_2))
|
||||
)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val resetCardButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.BUTTON)
|
||||
hasText(getResourceString(R.string.reset_card_to_factory_button_title))
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onResetCardScreen(function: ResetCardPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import com.kaspersky.kaspresso.screens.KScreen
|
||||
import com.tangem.wallet.R
|
||||
import io.github.kakaocup.kakao.text.KTextView
|
||||
import io.github.kakaocup.kakao.text.KButton
|
||||
|
||||
object ScanWarningDialogPageObject : KScreen<ScanWarningDialogPageObject>() {
|
||||
|
||||
override val layoutId: Int? = null
|
||||
override val viewClass: Class<*>? = null
|
||||
|
||||
val warningTitle = KTextView {
|
||||
withText(R.string.common_warning)
|
||||
}
|
||||
|
||||
val warningMessage = KTextView {
|
||||
withText(R.string.alert_troubleshooting_scan_card_title)
|
||||
}
|
||||
|
||||
val tryAgainButton = KButton {
|
||||
withId(R.id.try_again_button)
|
||||
}
|
||||
|
||||
val howToScanButton = KButton {
|
||||
withId(R.id.how_to_scan_button)
|
||||
}
|
||||
|
||||
val requestSupportButton = KButton {
|
||||
withId(R.id.request_support_button)
|
||||
}
|
||||
|
||||
val cancelButton = KButton {
|
||||
withId(R.id.cancel_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.BaseSearchBarTestTags
|
||||
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 SearchBarPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<SearchBarPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val searchField: KNode = child {
|
||||
hasTestTag(BaseSearchBarTestTags.SEARCH_BAR)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onSearchBar(function: SearchBarPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -4,6 +4,7 @@ import androidx.compose.ui.test.SemanticsMatcher
|
|||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.utils.LazyListItemNode
|
||||
import com.tangem.core.ui.test.BaseSearchBarTestTags
|
||||
import com.tangem.core.ui.test.SelectCountryBottomSheetTestTags
|
||||
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
|
||||
import com.tangem.features.onramp.impl.R
|
||||
|
|
@ -12,9 +13,8 @@ import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onCompose
|
|||
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.hasText as withText
|
||||
|
||||
class SelectCountryPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<SelectCountryPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
|
@ -33,7 +33,7 @@ class SelectCountryPageObject(semanticsProvider: SemanticsNodeInteractionsProvid
|
|||
)
|
||||
|
||||
val searchBar: KNode = child {
|
||||
hasTestTag(SelectCountryBottomSheetTestTags.SEARCH_BAR)
|
||||
hasTestTag(BaseSearchBarTestTags.SEARCH_BAR)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.SendAddressScreenTestTags
|
||||
import com.tangem.features.send.v2.impl.R
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
|
||||
class SendAddressPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<SendAddressPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val addressTextField: KNode = child {
|
||||
hasTestTag(SendAddressScreenTestTags.ADDRESS_TEXT_FIELD)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val nextButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.common_next))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onSendAddressScreen(function: SendAddressPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
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.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.TopAppBarTestTags
|
||||
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 SendConfirmPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<SendConfirmPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val title: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.TITLE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val sendButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.common_send))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onSendConfirmScreen(function: SendConfirmPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -3,7 +3,7 @@ package com.tangem.screens
|
|||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.StakingSendScreenTestTags
|
||||
import com.tangem.core.ui.test.SendScreenTestTags
|
||||
import com.tangem.core.ui.test.TopAppBarTestTags
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
|
|
@ -12,11 +12,11 @@ import io.github.kakaocup.kakao.common.utilities.getResourceString
|
|||
import com.tangem.features.send.v2.impl.R as SendR
|
||||
import androidx.compose.ui.test.hasTestTag as withTestTag
|
||||
|
||||
class StakingSendPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<StakingSendPageObject>(semanticsProvider = semanticsProvider) {
|
||||
class SendPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<SendPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val screenContainer: KNode = child {
|
||||
hasTestTag(StakingSendScreenTestTags.SCREEN_CONTAINER)
|
||||
hasTestTag(SendScreenTestTags.SCREEN_CONTAINER)
|
||||
}
|
||||
|
||||
val title: KNode = child {
|
||||
|
|
@ -25,44 +25,44 @@ class StakingSendPageObject(semanticsProvider: SemanticsNodeInteractionsProvider
|
|||
}
|
||||
|
||||
val amountContainerTitle: KNode = child {
|
||||
hasTestTag(StakingSendScreenTestTags.AMOUNT_CONTAINER_TITLE)
|
||||
hasTestTag(SendScreenTestTags.AMOUNT_CONTAINER_TITLE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val amountContainerText: KNode = child {
|
||||
hasTestTag(StakingSendScreenTestTags.AMOUNT_CONTAINER_TEXT)
|
||||
hasTestTag(SendScreenTestTags.AMOUNT_CONTAINER_TEXT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val amountInputTextField: KNode = child {
|
||||
hasTestTag(StakingSendScreenTestTags.INPUT_TEXT_FIELD)
|
||||
hasTestTag(SendScreenTestTags.INPUT_TEXT_FIELD)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val secondaryAmount: KNode = child {
|
||||
hasTestTag(StakingSendScreenTestTags.SECONDARY_AMOUNT)
|
||||
hasTestTag(SendScreenTestTags.SECONDARY_AMOUNT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val currencyButton: KNode = child {
|
||||
hasTestTag(StakingSendScreenTestTags.CURRENCY_BUTTON)
|
||||
hasAnyChild(withTestTag(StakingSendScreenTestTags.CURRENCY_ICON))
|
||||
hasTestTag(SendScreenTestTags.CURRENCY_BUTTON)
|
||||
hasAnyChild(withTestTag(SendScreenTestTags.CURRENCY_ICON))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val fiatButton: KNode = child {
|
||||
hasTestTag(StakingSendScreenTestTags.CURRENCY_BUTTON)
|
||||
hasAnyChild(withTestTag(StakingSendScreenTestTags.FIAT_ICON))
|
||||
hasTestTag(SendScreenTestTags.CURRENCY_BUTTON)
|
||||
hasAnyChild(withTestTag(SendScreenTestTags.FIAT_ICON))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val maxButton: KNode = child {
|
||||
hasTestTag(StakingSendScreenTestTags.MAX_BUTTON)
|
||||
hasTestTag(SendScreenTestTags.MAX_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val previousButton: KNode = child {
|
||||
hasTestTag(StakingSendScreenTestTags.PREVIOUS_BUTTON)
|
||||
hasTestTag(SendScreenTestTags.PREVIOUS_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
|
|
@ -74,5 +74,5 @@ class StakingSendPageObject(semanticsProvider: SemanticsNodeInteractionsProvider
|
|||
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onStakingSendScreen(function: StakingSendPageObject.() -> Unit) =
|
||||
internal fun BaseTestCase.onSendScreen(function: SendPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -3,6 +3,7 @@ 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.BaseAmountBlockTestTags
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.StakingSendDetailsScreenTestTags
|
||||
import com.tangem.core.ui.test.TopAppBarTestTags
|
||||
|
|
@ -11,8 +12,8 @@ import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onCompose
|
|||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
|
||||
class StakingSendDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<StakingSendDetailsPageObject>(semanticsProvider = semanticsProvider) {
|
||||
class StakingConfirmPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<StakingConfirmPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val title: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.TITLE)
|
||||
|
|
@ -20,12 +21,12 @@ class StakingSendDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsP
|
|||
}
|
||||
|
||||
val primaryAmount: KNode = child {
|
||||
hasTestTag(StakingSendDetailsScreenTestTags.PRIMARY_AMOUNT)
|
||||
hasTestTag(BaseAmountBlockTestTags.PRIMARY_AMOUNT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val secondaryAmount: KNode = child {
|
||||
hasTestTag(StakingSendDetailsScreenTestTags.SECONDARY_AMOUNT)
|
||||
hasTestTag(BaseAmountBlockTestTags.SECONDARY_AMOUNT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
|
|
@ -47,5 +48,5 @@ class StakingSendDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsP
|
|||
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onStakingSendDetailsScreen(function: StakingSendDetailsPageObject.() -> Unit) =
|
||||
internal fun BaseTestCase.onStakingConfirmScreen(function: StakingConfirmPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -57,7 +57,7 @@ class SwapTokenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
}
|
||||
|
||||
val errorNotificationText: KNode = child {
|
||||
hasTestTag(NotificationTestTags.TEXT)
|
||||
hasTestTag(NotificationTestTags.MESSAGE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,16 +4,18 @@ 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.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.common.utils.LazyListItemNode
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.NotificationTestTags
|
||||
import com.tangem.core.ui.test.TokenDetailsScreenTestTags
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
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
|
||||
|
||||
class TokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<TokenDetailsPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
|
@ -111,6 +113,49 @@ class TokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvide
|
|||
hasText(getResourceString(R.string.common_buy))
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTestApi::class)
|
||||
val sendButton: LazyListItemNode = horizontalActionChips.childWith<LazyListItemNode> {
|
||||
hasTestTag(TokenDetailsScreenTestTags.ACTION_BUTTON)
|
||||
hasText(getResourceString(R.string.common_send))
|
||||
}
|
||||
|
||||
fun networkFeeNotificationIcon(feeCurrencyName: String): KNode = child {
|
||||
hasAnySibling(withText(getResourceString(R.string.warning_send_blocked_funds_for_fee_title, feeCurrencyName)))
|
||||
hasTestTag(NotificationTestTags.ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun networkFeeNotificationTitle(feeCurrencyName: String): KNode = child {
|
||||
hasTestTag(NotificationTestTags.TITLE)
|
||||
hasText(getResourceString(R.string.warning_send_blocked_funds_for_fee_title, feeCurrencyName))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun networkFeeNotificationMessage(
|
||||
currencyName: String,
|
||||
networkName: String,
|
||||
feeCurrencyName: String,
|
||||
feeCurrencySymbol: String,
|
||||
): KNode = child {
|
||||
hasTestTag(NotificationTestTags.MESSAGE)
|
||||
hasText(
|
||||
getResourceString(
|
||||
R.string.warning_send_blocked_funds_for_fee_message,
|
||||
currencyName,
|
||||
networkName,
|
||||
currencyName,
|
||||
feeCurrencyName,
|
||||
feeCurrencySymbol
|
||||
)
|
||||
)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun goToBuyCurrencyButton(feeCurrencySymbol: String): KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.common_buy_currency, feeCurrencySymbol))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onTokenDetailsScreen(function: TokenDetailsPageObject.() -> Unit) =
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
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.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.WalletConnectBottomSheetTestTags
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import com.tangem.features.walletconnect.impl.R as WalletConnectImplR
|
||||
|
||||
class WalletConnectBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<WalletConnectBottomSheetPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val title: KNode = child {
|
||||
hasText(getResourceString(WalletConnectImplR.string.wc_wallet_connect))
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.TITLE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val appIcon: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.APP_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val appName: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.APP_NAME)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val approveIcon: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.APPROVE_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val appUrl: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.APP_URL)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val connectionRequestIcon: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.CONNECTION_REQUEST_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val connectionRequestText: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.CONNECTION_REQUEST_TEXT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val connectionRequestChevron: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.CONNECTION_REQUEST_CHEVRON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val walletIcon: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.WALLET_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val walletNameTitle: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.WALLET_NAME_TITLE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val walletName: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.WALLET_NAME)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val networksIcon: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.NETWORKS_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val networksTitle: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.NETWORKS_TITLE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val networksIcons: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.NETWORKS_ICONS)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val networksSelectorIcon: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.NETWORKS_SELECTOR_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val cancelButton: KNode = child {
|
||||
hasText(getResourceString(R.string.common_cancel))
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val connectButton: KNode = child {
|
||||
hasText(getResourceString(R.string.wc_common_connect))
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onWalletConnectBottomSheet(function: WalletConnectBottomSheetPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.WalletConnectBottomSheetTestTags
|
||||
import com.tangem.core.ui.test.WalletConnectDetailsBottomSheetTestTags
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import com.tangem.features.walletconnect.impl.R as WalletConnectImplR
|
||||
|
||||
class WalletConnectDetailsBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<WalletConnectDetailsBottomSheetPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val title: KNode = child {
|
||||
hasTestTag(WalletConnectDetailsBottomSheetTestTags.TITLE)
|
||||
hasText(getResourceString(WalletConnectImplR.string.wc_connected_app_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val date: KNode = child {
|
||||
hasTestTag(WalletConnectDetailsBottomSheetTestTags.DATE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val closeButton: KNode = child {
|
||||
hasTestTag(WalletConnectDetailsBottomSheetTestTags.CLOSE_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val networksBlockTitle: KNode = child {
|
||||
hasText(getResourceString(WalletConnectImplR.string.wc_connected_networks))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val appIcon: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.APP_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val approveIcon: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.APPROVE_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val appName: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.APP_NAME)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val appUrl: KNode = child {
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.APP_URL)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val walletIcon: KNode = child {
|
||||
hasTestTag(WalletConnectDetailsBottomSheetTestTags.WALLET_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val walletTitle: KNode = child {
|
||||
hasTestTag(WalletConnectDetailsBottomSheetTestTags.WALLET_TITLE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val walletName: KNode = child {
|
||||
hasTestTag(WalletConnectDetailsBottomSheetTestTags.WALLET_NAME)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val connectedNetworksTitle: KNode = child {
|
||||
hasTestTag(WalletConnectDetailsBottomSheetTestTags.NETWORKS_TITLE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val connectedNetworkItem: KNode = child {
|
||||
hasTestTag(WalletConnectDetailsBottomSheetTestTags.NETWORK_ITEM)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val connectedNetworkIcon: KNode = child {
|
||||
hasTestTag(WalletConnectDetailsBottomSheetTestTags.NETWORK_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val connectedNetworkName: KNode = child {
|
||||
hasTestTag(WalletConnectDetailsBottomSheetTestTags.NETWORK_NAME)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val connectedNetworkSymbol: KNode = child {
|
||||
hasTestTag(WalletConnectDetailsBottomSheetTestTags.NETWORK_SYMBOL)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val disconnectButton: KNode = child {
|
||||
hasText(getResourceString(WalletConnectImplR.string.common_disconnect))
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onWalletConnectDetailsBottomSheet(function: WalletConnectDetailsBottomSheetPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
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.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.WalletConnectScreenTestTags
|
||||
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 WalletConnectPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<WalletConnectPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val title: KNode = child {
|
||||
hasText(getResourceString(R.string.wc_connections))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val moreButton: KNode = child {
|
||||
hasTestTag(WalletConnectScreenTestTags.MORE_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val walletName: KNode = child {
|
||||
hasTestTag(WalletConnectScreenTestTags.WALLET_NAME)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val appIcon: KNode = child {
|
||||
hasTestTag(WalletConnectScreenTestTags.APP_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val appName: KNode = child {
|
||||
hasTestTag(WalletConnectScreenTestTags.APP_NAME)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val approveIcon: KNode = child {
|
||||
hasTestTag(WalletConnectScreenTestTags.APPROVE_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val appUrl: KNode = child {
|
||||
hasTestTag(WalletConnectScreenTestTags.APP_URL)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val newConnectionButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.wc_new_connection))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onWalletConnectScreen(function: WalletConnectPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -21,7 +21,7 @@ class WalletSettingsPageObject(semanticsProvider: SemanticsNodeInteractionsProvi
|
|||
val linkMoreCardsButton: KNode = walletSettingsItem.child {
|
||||
hasText(getResourceString(R.string.details_row_title_create_backup))
|
||||
}
|
||||
val cardSettingsButton: KNode = walletSettingsItem.child {
|
||||
val deviceSettingsButton: KNode = walletSettingsItem.child {
|
||||
hasText(getResourceString(R.string.card_settings_title))
|
||||
}
|
||||
val referralProgramButton: KNode = walletSettingsItem.child {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
package com.tangem.steps
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.assertElementDoesNotExist
|
||||
import com.tangem.screens.onMainScreen
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
||||
fun BaseTestCase.checkSingleCurrencyMainScreen(cardBlockchain: String, cardTitle: String) {
|
||||
step("Assert card title equal '$cardTitle'") {
|
||||
onMainScreen { walletNameText.assertTextEquals(cardTitle) }
|
||||
}
|
||||
step("Assert 'Transactions' block is displayed") {
|
||||
onMainScreen { transactionsExplorer().assertExists() }
|
||||
}
|
||||
step("Assert 'Transactions' title is displayer") {
|
||||
onMainScreen { transactionsTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Explorer Icon' is displayed") {
|
||||
onMainScreen { transactionsExplorerIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert card image is displayed") { //TODO: Придумать нормальную проверку / реализовать скриншот-тестинг
|
||||
onMainScreen { walletImage.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Market Price' on single card main screen is displayed") {
|
||||
onMainScreen { marketPriceBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Market Price' title equals $cardBlockchain Market Price") {
|
||||
onMainScreen { marketPriceText.assertTextContains("$cardBlockchain Market Price") }
|
||||
}
|
||||
step("Assert 'Organize tokens' button is not displayed") {
|
||||
onMainScreen {
|
||||
assertElementDoesNotExist({ organizeTokensButtonWithoutLazySearch() }, "Organize tokens button")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,8 +6,9 @@ import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
|
|||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.scenarios.OpenMainScreenScenario
|
||||
import com.tangem.screens.*
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
|
|
@ -36,13 +37,10 @@ class BuyTokenTest : BaseTestCase() {
|
|||
setWireMockScenarioState(scenarioName, "Error")
|
||||
}
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert wallet balance = $balance") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Click on 'Buy' button") {
|
||||
onMainScreen { buyButton.clickWithAssertion() }
|
||||
|
|
@ -84,13 +82,10 @@ class BuyTokenTest : BaseTestCase() {
|
|||
}
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert wallet balance = '$balance'") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Click on 'Buy' button") {
|
||||
onMainScreen { buyButton.clickWithAssertion() }
|
||||
|
|
@ -175,13 +170,10 @@ class BuyTokenTest : BaseTestCase() {
|
|||
}
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert wallet balance = '$balance'") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Click on 'Buy' button") {
|
||||
onMainScreen { buyButton.clickWithAssertion() }
|
||||
|
|
@ -250,13 +242,10 @@ class BuyTokenTest : BaseTestCase() {
|
|||
}
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert wallet balance = '$balance'") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Click on 'Buy' button") {
|
||||
onMainScreen { buyButton.clickWithAssertion() }
|
||||
|
|
@ -339,13 +328,10 @@ class BuyTokenTest : BaseTestCase() {
|
|||
}
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert wallet balance = '$balance'") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Click on 'Buy' button") {
|
||||
onMainScreen { buyButton.clickWithAssertion() }
|
||||
|
|
@ -437,13 +423,10 @@ class BuyTokenTest : BaseTestCase() {
|
|||
}
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert wallet balance = '$balance'") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Click on 'Buy' button") {
|
||||
onMainScreen { buyButton.clickWithAssertion() }
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.tests
|
|||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.scenarios.OpenMainScreenScenario
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.screens.onDetailsScreen
|
||||
import com.tangem.screens.onReferralProgramScreen
|
||||
import com.tangem.screens.onTopBar
|
||||
|
|
@ -19,7 +19,9 @@ class DetailsTest : BaseTestCase() {
|
|||
@Test
|
||||
fun walletWithoutBackupDetailsTest() =
|
||||
setupHooks().run {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
onTopBar {
|
||||
step("Open wallet details") {
|
||||
moreButton.clickWithAssertion()
|
||||
|
|
@ -53,7 +55,7 @@ class DetailsTest : BaseTestCase() {
|
|||
linkMoreCardsButton.assertIsDisplayed()
|
||||
}
|
||||
step("Assert 'Card Settings' button is visible") {
|
||||
cardSettingsButton.assertIsDisplayed()
|
||||
deviceSettingsButton.assertIsDisplayed()
|
||||
}
|
||||
step("Assert 'Referral program' button is visible") {
|
||||
referralProgramButton.assertIsDisplayed()
|
||||
|
|
@ -67,7 +69,9 @@ class DetailsTest : BaseTestCase() {
|
|||
// @Test
|
||||
fun wallet2DetailsTest() =
|
||||
setupHooks().run {
|
||||
scenario(OpenMainScreenScenario(composeTestRule, ProductType.Wallet2))
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen(productType = ProductType.Wallet2, alreadyActivatedDialogIsShown = true)
|
||||
}
|
||||
onTopBar {
|
||||
step("Open wallet details") {
|
||||
moreButton.clickWithAssertion()
|
||||
|
|
@ -101,7 +105,7 @@ class DetailsTest : BaseTestCase() {
|
|||
linkMoreCardsButton.assertIsNotDisplayed()
|
||||
}
|
||||
step("Assert 'Card Settings' button is visible") {
|
||||
cardSettingsButton.assertIsDisplayed()
|
||||
deviceSettingsButton.assertIsDisplayed()
|
||||
}
|
||||
step("Assert 'Referral program' button is visible") {
|
||||
referralProgramButton.assertIsDisplayed()
|
||||
|
|
@ -115,7 +119,9 @@ class DetailsTest : BaseTestCase() {
|
|||
@Test
|
||||
fun noteDetailsTest() =
|
||||
setupHooks().run {
|
||||
scenario(OpenMainScreenScenario(composeTestRule, ProductType.Note))
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen(ProductType.Note)
|
||||
}
|
||||
onTopBar {
|
||||
step("Open wallet details") {
|
||||
moreButton.clickWithAssertion()
|
||||
|
|
@ -146,7 +152,7 @@ class DetailsTest : BaseTestCase() {
|
|||
}
|
||||
onWalletSettingsScreen {
|
||||
step("Assert 'Card Settings' button is visible") {
|
||||
cardSettingsButton.assertIsDisplayed()
|
||||
deviceSettingsButton.assertIsDisplayed()
|
||||
}
|
||||
step("Assert 'Referral program' button does not exist") {
|
||||
referralProgramButton.assertIsNotDisplayed()
|
||||
|
|
@ -162,7 +168,9 @@ class DetailsTest : BaseTestCase() {
|
|||
@Test
|
||||
fun validateReferralProgramScreenTest() =
|
||||
setupHooks().run {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Open wallet details") {
|
||||
onTopBar { moreButton.clickWithAssertion() }
|
||||
}
|
||||
|
|
|
|||
181
app/src/androidTest/kotlin/com/tangem/tests/FeedbackTest.kt
Normal file
181
app/src/androidTest/kotlin/com/tangem/tests/FeedbackTest.kt
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.RECIPIENT_ADDRESS
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.redux.StateDialog
|
||||
import com.tangem.scenarios.*
|
||||
import com.tangem.screens.*
|
||||
import com.tangem.screens.AlreadyUsedWalletDialogPageObject.requestSupportButton
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.sdk.mocks.MockProvider
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.Allure
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
import org.junit.Test
|
||||
|
||||
@HiltAndroidTest
|
||||
class FeedbackTest : BaseTestCase() {
|
||||
|
||||
@AllureId("894")
|
||||
@DisplayName("Send feedback: from details")
|
||||
@Test
|
||||
fun sendFeedbackFromDetailsTest() {
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
device.uiDevice.pressBack()
|
||||
}
|
||||
).run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click 'More' button on TopBar") {
|
||||
onTopBar { moreButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click 'Contact support' button") {
|
||||
onDetailsScreen { contactSupportButton.clickWithAssertion() }
|
||||
}
|
||||
step("Check 'Contact support' intent is called") {
|
||||
checkSendEMailIntentCalled()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("893")
|
||||
@DisplayName("Send feedback: failed transaction")
|
||||
@Test
|
||||
fun sendFeedbackFromFailedTransactionTest() {
|
||||
val balance = TOTAL_BALANCE
|
||||
val tokenName = "Polygon"
|
||||
val recipientAddress = RECIPIENT_ADDRESS
|
||||
val sendAmount = "1"
|
||||
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
device.uiDevice.pressBack()
|
||||
}
|
||||
).run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Click on token with name: '$tokenName'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() }
|
||||
}
|
||||
step("Click 'Send' button") {
|
||||
onTokenDetailsScreen { sendButton.performClick() }
|
||||
}
|
||||
step("Type '$sendAmount' in input text field") {
|
||||
onSendScreen {
|
||||
amountInputTextField.performClick()
|
||||
amountInputTextField.performTextReplacement(sendAmount)
|
||||
}
|
||||
}
|
||||
step("Assert input text field has value: '$sendAmount'") {
|
||||
onSendScreen { amountInputTextField.assertTextContains(value = sendAmount, substring = true) }
|
||||
}
|
||||
step("Click 'Next' button") {
|
||||
onSendScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Enter address") {
|
||||
onSendAddressScreen { addressTextField.performTextReplacement(recipientAddress) }
|
||||
}
|
||||
step("Click 'Next' button") {
|
||||
onSendAddressScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click 'Send' button") {
|
||||
onSendConfirmScreen {
|
||||
sendButton.assertIsEnabled()
|
||||
sendButton.performClick()
|
||||
}
|
||||
}
|
||||
step("Check 'Failed transaction' dialog") {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
checkFailedTransactionDialog()
|
||||
}
|
||||
}
|
||||
step("Click on 'Support' button") {
|
||||
onFailedTransactionDialog { supportButton.performClick() }
|
||||
}
|
||||
step("Check 'Contact support' intent is called") {
|
||||
checkSendEMailIntentCalled()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("3985")
|
||||
@DisplayName("Send feedback: from 'Warning' dialog after card scan")
|
||||
@Test
|
||||
fun sendFeedbackFromScanScreenTest() {
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
device.uiDevice.pressBack()
|
||||
MockProvider.resetEmulateError()
|
||||
}
|
||||
).run {
|
||||
Allure.step("Click on 'Accept' button") {
|
||||
onDisclaimerScreen { acceptButton.clickWithAssertion() }
|
||||
}
|
||||
step("Set scanning error") {
|
||||
MockProvider.setEmulateError(TangemSdkError.TagLost())
|
||||
}
|
||||
step("Click on 'Scan' button") {
|
||||
onStoriesScreen { scanButton.performClick() }
|
||||
}
|
||||
step("Force show 'Scan warning' dialog"){
|
||||
runOnUiThread {
|
||||
val scanFailsState = StateDialog.ScanFailsDialog(source = StateDialog.ScanFailsSource.MAIN)
|
||||
store.dispatch(GlobalAction.ShowDialog(scanFailsState))
|
||||
}
|
||||
}
|
||||
step("Check 'Scan warning' dialog") {
|
||||
checkScanWarningDialog()
|
||||
}
|
||||
step("Click on 'Request support' button") {
|
||||
ScanWarningDialogPageObject { requestSupportButton.click() }
|
||||
}
|
||||
step("Check 'Contact support' intent is called") {
|
||||
checkSendEMailIntentCalled()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("3986")
|
||||
@DisplayName("Send feedback: from scan already used wallet alert dialog")
|
||||
@Test
|
||||
fun sendFeedbackAfterScanAlreadyUsedWalletTest() {
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
device.uiDevice.pressBack()
|
||||
}
|
||||
).run {
|
||||
step("Set mocks for Wallet2") {
|
||||
MockProvider.setMocks(ProductType.Wallet2)
|
||||
}
|
||||
step("Click on 'Accept' button") {
|
||||
onDisclaimerScreen { acceptButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Scan' button") {
|
||||
onStoriesScreen { scanButton.clickWithAssertion() }
|
||||
}
|
||||
step("Check 'Already used Wallet' dialog") {
|
||||
checkAlreadyUsedWalletDialog()
|
||||
}
|
||||
step("Click on 'Request support' button") {
|
||||
AlreadyUsedWalletDialogPageObject { requestSupportButton.click() }
|
||||
}
|
||||
step("Check 'Contact support' intent is called") {
|
||||
checkSendEMailIntentCalled()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,8 @@ package com.tangem.tests
|
|||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.scenarios.OpenMainScreenScenario
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import com.tangem.screens.*
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
|
|
@ -21,13 +22,10 @@ class HideTokenTest : BaseTestCase() {
|
|||
val balance = TOTAL_BALANCE
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button" ) {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert wallet balance = $balance") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
|
|
@ -35,7 +33,7 @@ class HideTokenTest : BaseTestCase() {
|
|||
step("Assert 'Token details screen' open") {
|
||||
onTokenDetailsScreen { screenContainer.assertIsDisplayed() }
|
||||
}
|
||||
step("Click 'More button'") {
|
||||
step("Click 'More' button") {
|
||||
onTokenDetailsTopBar { moreButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click 'Hide token' button") {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.scenarios.OpenMainScreenScenario
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import org.junit.Test
|
||||
|
||||
|
|
@ -11,7 +11,9 @@ class MainScreenTest : BaseTestCase() {
|
|||
@Test
|
||||
fun goToMain() {
|
||||
setupHooks().run {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ package com.tangem.tests
|
|||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.common.extensions.SwipeDirection
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.extensions.swipeUp
|
||||
import com.tangem.scenarios.OpenMainScreenScenario
|
||||
import com.tangem.common.extensions.swipeVertical
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import com.tangem.screens.onMainScreen
|
||||
import com.tangem.screens.onOrganizeTokensScreen
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
|
|
@ -23,15 +25,16 @@ class OrganizeTokensTest : BaseTestCase() {
|
|||
setupHooks().run {
|
||||
val tokenTitle = "Ethereum"
|
||||
val tokenNetwork = "Ethereum network"
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button" ) {
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Swipe to 'Organize tokens' button") {
|
||||
swipeUp()
|
||||
swipeUp()
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
}
|
||||
step("Click 'Organize tokens' button") {
|
||||
onMainScreen { organizeTokensButton().clickWithAssertion() }
|
||||
|
|
@ -55,8 +58,8 @@ class OrganizeTokensTest : BaseTestCase() {
|
|||
onMainScreen { tokenNetworkGroupTitle(tokenNetwork).assertIsDisplayed() }
|
||||
}
|
||||
step("Swipe to 'Organize tokens' button") {
|
||||
swipeUp()
|
||||
swipeUp()
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
}
|
||||
step("Click 'Organize tokens' button") {
|
||||
onMainScreen { organizeTokensButton().clickWithAssertion() }
|
||||
|
|
@ -90,14 +93,12 @@ class OrganizeTokensTest : BaseTestCase() {
|
|||
val ethereumTitle = "Ethereum"
|
||||
val bitcoinTitle = "Bitcoin"
|
||||
val balance = TOTAL_BALANCE
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button" ) {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert wallet balance = '$balance'") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Check positions of tokens on 'Main Screen'") {
|
||||
onMainScreen {
|
||||
|
|
@ -106,8 +107,8 @@ class OrganizeTokensTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
step("Swipe to 'Organize tokens' button") {
|
||||
swipeUp()
|
||||
swipeUp()
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
}
|
||||
step("Click 'Organize tokens' button") {
|
||||
onMainScreen { organizeTokensButton().clickWithAssertion() }
|
||||
|
|
@ -129,10 +130,11 @@ class OrganizeTokensTest : BaseTestCase() {
|
|||
setupHooks().run {
|
||||
val ethereumTitle = "Ethereum"
|
||||
val bitcoinTitle = "Bitcoin"
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button" ) {
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Check positions of tokens on 'Main Screen'") {
|
||||
|
|
@ -142,8 +144,8 @@ class OrganizeTokensTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
step("Swipe to 'Organize tokens' button") {
|
||||
swipeUp()
|
||||
swipeUp()
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
}
|
||||
step("Click 'Organize tokens' button") {
|
||||
onMainScreen { organizeTokensButton().clickWithAssertion() }
|
||||
|
|
@ -178,14 +180,12 @@ class OrganizeTokensTest : BaseTestCase() {
|
|||
val polygonTitle = "Polygon"
|
||||
val polExMaticTitle = "POL (ex-MATIC)"
|
||||
val balance = TOTAL_BALANCE
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button" ) {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert wallet balance = '$balance'") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Check positions of tokens on 'Main Screen'") {
|
||||
onMainScreen {
|
||||
|
|
@ -195,8 +195,8 @@ class OrganizeTokensTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
step("Swipe to 'Organize tokens' button") {
|
||||
swipeUp()
|
||||
swipeUp()
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
}
|
||||
step("Click 'Organize tokens' button") {
|
||||
onMainScreen { organizeTokensButton().clickWithAssertion() }
|
||||
|
|
@ -235,6 +235,4 @@ class OrganizeTokensTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
83
app/src/androidTest/kotlin/com/tangem/tests/ResetCardTest.kt
Normal file
83
app/src/androidTest/kotlin/com/tangem/tests/ResetCardTest.kt
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.scenarios.*
|
||||
import com.tangem.tap.domain.sdk.mocks.content.BackupWalletMockContent
|
||||
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 ResetCardTest : BaseTestCase() {
|
||||
|
||||
@AllureId("3988")
|
||||
@DisplayName("Reset card: reset Wallet 1.0 card without backup")
|
||||
@Test
|
||||
fun resetWallet1CardWithoutBackupTest() {
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Open 'Device settings' screen") {
|
||||
openDeviceSettingsScreen()
|
||||
}
|
||||
step("Open 'Reset card' screen") {
|
||||
openResetCardScreen()
|
||||
}
|
||||
step("Check 'Reset card' screen") {
|
||||
checkResetCardScreen()
|
||||
}
|
||||
step("Check checkbox logic") {
|
||||
checkCheckBoxLogic()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("3987")
|
||||
@DisplayName("Reset card: reset Wallet 1.0 card with backup")
|
||||
@Test
|
||||
fun resetWallet1CardWithBackupTest() {
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen(mockContent = BackupWalletMockContent)
|
||||
}
|
||||
step("Open 'Device settings' screen") {
|
||||
openDeviceSettingsScreen()
|
||||
}
|
||||
step("Open 'Reset card' screen") {
|
||||
openResetCardScreen(withBackup = true)
|
||||
}
|
||||
step("Check 'Reset card' screen") {
|
||||
checkResetCardScreen(withBackup = true)
|
||||
}
|
||||
step("Check checkbox logic") {
|
||||
checkCheckBoxLogic(withBackup = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("3974")
|
||||
@DisplayName("Reset card: reset Wallet 2.0 card with backup")
|
||||
@Test
|
||||
fun resetWallet2CardWithBackupTest() {
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen(productType = ProductType.Wallet2, alreadyActivatedDialogIsShown = true)
|
||||
}
|
||||
step("Open 'Device settings' screen") {
|
||||
openDeviceSettingsScreen()
|
||||
}
|
||||
step("Open 'Reset card' screen") {
|
||||
openResetCardScreen(withBackup = true)
|
||||
}
|
||||
step("Check 'Reset card' screen") {
|
||||
checkResetCardScreen(withBackup = true)
|
||||
}
|
||||
step("Check checkbox logic") {
|
||||
checkCheckBoxLogic(withBackup = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
69
app/src/androidTest/kotlin/com/tangem/tests/SendTest.kt
Normal file
69
app/src/androidTest/kotlin/com/tangem/tests/SendTest.kt
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import com.tangem.screens.onMainScreen
|
||||
import com.tangem.screens.onTokenDetailsScreen
|
||||
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 SendTest : BaseTestCase() {
|
||||
|
||||
@AllureId("3645")
|
||||
@DisplayName("Send: check fee notification")
|
||||
@Test
|
||||
fun checkFeeNotificationTest() {
|
||||
val currencyName = "POL (ex-MATIC)"
|
||||
val feeCurrencyName = "Ethereum"
|
||||
val feeCurrencySymbol = "ETH"
|
||||
val balance = "$763.55"
|
||||
val scenarioName = "eth_network_balance"
|
||||
val scenarioState = "Empty"
|
||||
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(scenarioName)
|
||||
}
|
||||
).run {
|
||||
step("Set WireMock scenario: '$scenarioName' to state: '$scenarioState'") {
|
||||
setWireMockScenarioState(scenarioName = scenarioName, state = scenarioState)
|
||||
}
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Click on token with name: $currencyName") {
|
||||
onMainScreen { tokenWithTitleAndAddress(currencyName).clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Insufficient $feeCurrencyName to cover network fee' notification icon is displayed") {
|
||||
onTokenDetailsScreen { networkFeeNotificationIcon(feeCurrencyName).assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Insufficient $feeCurrencyName to cover network fee' notification title is displayed") {
|
||||
onTokenDetailsScreen { networkFeeNotificationTitle(feeCurrencyName).assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Insufficient $feeCurrencyName to cover network fee' notification text is displayed") {
|
||||
onTokenDetailsScreen {
|
||||
networkFeeNotificationMessage(
|
||||
currencyName,
|
||||
feeCurrencyName,
|
||||
feeCurrencyName,
|
||||
feeCurrencySymbol
|
||||
).assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
step("Assert 'Go to $feeCurrencySymbol' button is displayed") {
|
||||
onTokenDetailsScreen { goToBuyCurrencyButton(feeCurrencySymbol).assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.steps.checkSingleCurrencyMainScreen
|
||||
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 SingleCurrencyCardsScan : BaseTestCase() {
|
||||
|
||||
@AllureId("868")
|
||||
@DisplayName("Scan: Scanning single-currency cards")
|
||||
@Test
|
||||
fun singleTokenNoteScanTest() {
|
||||
val cardBlockchain = "DOGE"
|
||||
val cardType: ProductType = ProductType.Note
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen' on ${cardType.name} card") {
|
||||
openMainScreen(cardType)
|
||||
}
|
||||
step("Check 'Main' screen for ${cardType.name} $cardBlockchain card") {
|
||||
checkSingleCurrencyMainScreen(cardBlockchain = cardBlockchain, cardTitle = cardType.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,8 +5,9 @@ import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
|||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.scenarios.OpenMainScreenScenario
|
||||
import com.tangem.screens.*
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
|
|
@ -20,7 +21,7 @@ class StakingTest : BaseTestCase() {
|
|||
@Test
|
||||
fun validateStakingBlockTest() {
|
||||
val tokenTitle = "POL (ex-MATIC)"
|
||||
val balance = TOTAL_BALANCE
|
||||
val balance = "$3,299.37"
|
||||
val scenarioName = "staking_eth_pol_balances_android"
|
||||
val scenarioState = "Staked"
|
||||
|
||||
|
|
@ -35,13 +36,13 @@ class StakingTest : BaseTestCase() {
|
|||
}
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Assert wallet balance = $balance") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
step("Assert 'Organize tokens' button is displayed") {
|
||||
onMainScreen { organizeTokensButton().assertIsDisplayed() }
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
|
|
@ -75,7 +76,7 @@ class StakingTest : BaseTestCase() {
|
|||
@Test
|
||||
fun validateStakingMoreScreensTest() {
|
||||
val tokenTitle = "POL (ex-MATIC)"
|
||||
val balance = TOTAL_BALANCE
|
||||
val balance = "$3,299.37"
|
||||
val scenarioName = "staking_eth_pol_balances_android"
|
||||
val scenarioState = "Staked"
|
||||
val stakingAmount = "1"
|
||||
|
|
@ -91,13 +92,13 @@ class StakingTest : BaseTestCase() {
|
|||
}
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Assert wallet balance = $balance") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
step("Assert 'Organize tokens' button is displayed") {
|
||||
onMainScreen { organizeTokensButton().assertIsDisplayed() }
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
|
|
@ -151,73 +152,73 @@ class StakingTest : BaseTestCase() {
|
|||
onStakingDetailsScreen { stakeMoreButton.performClick() }
|
||||
}
|
||||
step("Assert 'Send' screen is displayed") {
|
||||
onStakingSendScreen { screenContainer.assertIsDisplayed() }
|
||||
onSendScreen { screenContainer.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Send' screen title is displayed") {
|
||||
onStakingSendScreen { title.assertIsDisplayed() }
|
||||
onSendScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert amount container title is displayed") {
|
||||
onStakingSendScreen { amountContainerTitle.assertIsDisplayed() }
|
||||
onSendScreen { amountContainerTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert amount container text is displayed") {
|
||||
onStakingSendScreen { amountContainerText.assertIsDisplayed() }
|
||||
onSendScreen { amountContainerText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert input text field is displayed") {
|
||||
onStakingSendScreen { amountInputTextField.assertIsDisplayed() }
|
||||
onSendScreen { amountInputTextField.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert secondary amount is displayed") {
|
||||
onStakingSendScreen { secondaryAmount.assertIsDisplayed() }
|
||||
onSendScreen { secondaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Type '$stakingAmount' in input text field") {
|
||||
onStakingSendScreen {
|
||||
onSendScreen {
|
||||
amountInputTextField.performClick()
|
||||
amountInputTextField.performTextReplacement(stakingAmount)
|
||||
}
|
||||
}
|
||||
step("Assert input text field has value: '$stakingAmount'") {
|
||||
onStakingSendScreen { amountInputTextField.assertTextContains(value = stakingAmount, substring = true) }
|
||||
onSendScreen { amountInputTextField.assertTextContains(value = stakingAmount, substring = true) }
|
||||
}
|
||||
step("Assert currency button is displayed") {
|
||||
onStakingSendScreen { currencyButton.assertIsDisplayed() }
|
||||
onSendScreen { currencyButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert fiat button is displayed") {
|
||||
onStakingSendScreen { fiatButton.assertIsDisplayed() }
|
||||
onSendScreen { fiatButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert currency button is displayed") {
|
||||
onStakingSendScreen { currencyButton.assertIsDisplayed() }
|
||||
onSendScreen { currencyButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert fiat button is displayed") {
|
||||
onStakingSendScreen { fiatButton.assertIsDisplayed() }
|
||||
onSendScreen { fiatButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Max' button is displayed") {
|
||||
onStakingSendScreen { maxButton.assertIsDisplayed() }
|
||||
onSendScreen { maxButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert previous button is displayed") {
|
||||
onStakingSendScreen { previousButton.assertIsDisplayed() }
|
||||
onSendScreen { previousButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Next' button is displayed") {
|
||||
onStakingSendScreen { nextButton.assertIsDisplayed() }
|
||||
onSendScreen { nextButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onStakingSendScreen { nextButton.performClick() }
|
||||
onSendScreen { nextButton.performClick() }
|
||||
}
|
||||
step("Assert 'Send details' screen title is displayed") {
|
||||
onStakingSendDetailsScreen { title.assertIsDisplayed() }
|
||||
onStakingConfirmScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert primary amount is displayed") {
|
||||
onStakingSendDetailsScreen { primaryAmount.assertIsDisplayed() }
|
||||
onStakingConfirmScreen { primaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert secondary amount is displayed") {
|
||||
onStakingSendDetailsScreen { secondaryAmount.assertIsDisplayed() }
|
||||
onStakingConfirmScreen { secondaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Validator' block is displayed") {
|
||||
onStakingSendDetailsScreen { validatorBlock.assertIsDisplayed() }
|
||||
onStakingConfirmScreen { validatorBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Network Fee' block is displayed") {
|
||||
onStakingSendDetailsScreen { networkFeeBlock.assertIsDisplayed() }
|
||||
onStakingConfirmScreen { networkFeeBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Stake' button is displayed") {
|
||||
onStakingSendDetailsScreen { stakeButton.assertIsDisplayed() }
|
||||
onStakingConfirmScreen { stakeButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -243,13 +244,13 @@ class StakingTest : BaseTestCase() {
|
|||
}
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Assert wallet balance = $balance") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
step("Assert 'Organize tokens' button is displayed") {
|
||||
onMainScreen { organizeTokensButton().assertIsDisplayed() }
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
|
|
@ -306,73 +307,73 @@ class StakingTest : BaseTestCase() {
|
|||
onStakingDetailsScreen { stakeButton.performClick() }
|
||||
}
|
||||
step("Assert 'Send' screen is displayed") {
|
||||
onStakingSendScreen { screenContainer.assertIsDisplayed() }
|
||||
onSendScreen { screenContainer.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Send' screen title is displayed") {
|
||||
onStakingSendScreen { title.assertIsDisplayed() }
|
||||
onSendScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert amount container title is displayed") {
|
||||
onStakingSendScreen { amountContainerTitle.assertIsDisplayed() }
|
||||
onSendScreen { amountContainerTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert amount container text is displayed") {
|
||||
onStakingSendScreen { amountContainerText.assertIsDisplayed() }
|
||||
onSendScreen { amountContainerText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert input text field is displayed") {
|
||||
onStakingSendScreen { amountInputTextField.assertIsDisplayed() }
|
||||
onSendScreen { amountInputTextField.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert secondary amount is displayed") {
|
||||
onStakingSendScreen { secondaryAmount.assertIsDisplayed() }
|
||||
onSendScreen { secondaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Type '$stakingAmount' in input text field") {
|
||||
onStakingSendScreen {
|
||||
onSendScreen {
|
||||
amountInputTextField.performClick()
|
||||
amountInputTextField.performTextReplacement(stakingAmount)
|
||||
}
|
||||
}
|
||||
step("Assert input text field has value: '$stakingAmount'") {
|
||||
onStakingSendScreen { amountInputTextField.assertTextContains(value = stakingAmount, substring = true) }
|
||||
onSendScreen { amountInputTextField.assertTextContains(value = stakingAmount, substring = true) }
|
||||
}
|
||||
step("Assert currency button is displayed") {
|
||||
onStakingSendScreen { currencyButton.assertIsDisplayed() }
|
||||
onSendScreen { currencyButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert fiat button is displayed") {
|
||||
onStakingSendScreen { fiatButton.assertIsDisplayed() }
|
||||
onSendScreen { fiatButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert currency button is displayed") {
|
||||
onStakingSendScreen { currencyButton.assertIsDisplayed() }
|
||||
onSendScreen { currencyButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert fiat button is displayed") {
|
||||
onStakingSendScreen { fiatButton.assertIsDisplayed() }
|
||||
onSendScreen { fiatButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Max' button is displayed") {
|
||||
onStakingSendScreen { maxButton.assertIsDisplayed() }
|
||||
onSendScreen { maxButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert previous button is displayed") {
|
||||
onStakingSendScreen { previousButton.assertIsDisplayed() }
|
||||
onSendScreen { previousButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Next' button is displayed") {
|
||||
onStakingSendScreen { nextButton.assertIsDisplayed() }
|
||||
onSendScreen { nextButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onStakingSendScreen { nextButton.performClick() }
|
||||
onSendScreen { nextButton.performClick() }
|
||||
}
|
||||
step("Assert 'Send details' screen title is displayed") {
|
||||
onStakingSendDetailsScreen { title.assertIsDisplayed() }
|
||||
onStakingConfirmScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert primary amount is displayed") {
|
||||
onStakingSendDetailsScreen { primaryAmount.assertIsDisplayed() }
|
||||
onStakingConfirmScreen { primaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert secondary amount is displayed") {
|
||||
onStakingSendDetailsScreen { secondaryAmount.assertIsDisplayed() }
|
||||
onStakingConfirmScreen { secondaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Validator' block is displayed") {
|
||||
onStakingSendDetailsScreen { validatorBlock.assertIsDisplayed() }
|
||||
onStakingConfirmScreen { validatorBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Network Fee' block is displayed") {
|
||||
onStakingSendDetailsScreen { networkFeeBlock.assertIsDisplayed() }
|
||||
onStakingConfirmScreen { networkFeeBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Stake' button is displayed") {
|
||||
onStakingSendDetailsScreen { stakeButton.assertIsDisplayed() }
|
||||
onStakingConfirmScreen { stakeButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@ import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
|
|||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.datasource.api.common.config.ApiConfig
|
||||
import com.tangem.datasource.api.common.config.ApiEnvironment
|
||||
import com.tangem.scenarios.OpenMainScreenScenario
|
||||
import com.tangem.screens.*
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
|
|
@ -32,13 +33,10 @@ class SwapTokenTest : BaseTestCase() {
|
|||
val balance = TOTAL_BALANCE
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert wallet balance = $balance") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
|
|
@ -111,13 +109,10 @@ class SwapTokenTest : BaseTestCase() {
|
|||
val balance = TOTAL_BALANCE
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert wallet balance = $balance") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
|
|
@ -149,7 +144,7 @@ class SwapTokenTest : BaseTestCase() {
|
|||
@ApiEnv(
|
||||
ApiEnvConfig(ApiConfig.ID.Express, ApiEnvironment.PROD)
|
||||
)
|
||||
@AllureId("3546")
|
||||
@AllureId("3547")
|
||||
@DisplayName("Swap: change network fee")
|
||||
@Test
|
||||
fun changeNetworkFeeTest() {
|
||||
|
|
@ -159,13 +154,10 @@ class SwapTokenTest : BaseTestCase() {
|
|||
val balance = TOTAL_BALANCE
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
scenario(OpenMainScreenScenario(composeTestRule))
|
||||
openMainScreen()
|
||||
}
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert wallet balance = $balance") {
|
||||
onMainScreen { walletBalance().assertTextContains(balance) }
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ package com.tangem.tests
|
|||
|
||||
import androidx.test.InstrumentationRegistry.getTargetContext
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.SwipeDirection
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.extensions.swipeUp
|
||||
import com.tangem.common.extensions.swipeVertical
|
||||
import com.tangem.screens.onDisclaimerScreen
|
||||
import com.tangem.screens.onStoriesScreen
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
|
|
@ -37,7 +38,8 @@ class TermsOfServiceTest : BaseTestCase() {
|
|||
step("Assert 'Stories' screen is opened") {
|
||||
onStoriesScreen {
|
||||
scanButton.assertIsDisplayed()
|
||||
orderButton.assertIsDisplayed()}
|
||||
orderButton.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -67,7 +69,7 @@ class TermsOfServiceTest : BaseTestCase() {
|
|||
device.uiDevice.pressRecentApps()
|
||||
}
|
||||
step("Stop app by swipe") {
|
||||
swipeUp(startHeightRatio = 0.5f)
|
||||
swipeVertical(SwipeDirection.UP, startHeightRatio = 0.5f)
|
||||
}
|
||||
step("Launch app") {
|
||||
device.apps.launch(packageName)
|
||||
|
|
@ -90,7 +92,7 @@ class TermsOfServiceTest : BaseTestCase() {
|
|||
device.uiDevice.pressRecentApps()
|
||||
}
|
||||
step("Stop app by swipe") {
|
||||
swipeUp(startHeightRatio = 0.5f)
|
||||
swipeVertical(SwipeDirection.UP, startHeightRatio = 0.5f)
|
||||
}
|
||||
step("Launch app") {
|
||||
device.apps.launch(packageName)
|
||||
|
|
@ -98,9 +100,9 @@ class TermsOfServiceTest : BaseTestCase() {
|
|||
step("Assert 'Stories' screen is opened") {
|
||||
onStoriesScreen {
|
||||
scanButton.assertIsDisplayed()
|
||||
orderButton.assertIsDisplayed()}
|
||||
orderButton.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
181
app/src/androidTest/kotlin/com/tangem/tests/WalletConnectTest.kt
Normal file
181
app/src/androidTest/kotlin/com/tangem/tests/WalletConnectTest.kt
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.common.extensions.SwipeDirection
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.extensions.swipeVertical
|
||||
import com.tangem.common.utils.getWcUri
|
||||
import com.tangem.scenarios.*
|
||||
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.Ignore
|
||||
import org.junit.Test
|
||||
|
||||
@HiltAndroidTest
|
||||
class WalletConnectTest : BaseTestCase() {
|
||||
|
||||
@AllureId("3958")
|
||||
@DisplayName("WC (React App): open session from deeplink on main screen")
|
||||
@Ignore("TODO [REDACTED_JIRA] React app deeplink doesn't work")
|
||||
@Test
|
||||
fun openWalletConnectSessionOnMainScreen() {
|
||||
val balance = TOTAL_BALANCE
|
||||
val dAppName = "React App"
|
||||
val deepLinkUri = getWcUri()
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Create WC session buy deeplink") {
|
||||
openAppByDeepLink(deepLinkUri)
|
||||
}
|
||||
step("Check 'Wallet Connect' bottom sheet") {
|
||||
checkWalletConnectBottomSheet()
|
||||
}
|
||||
step("Click on 'Connect' button") {
|
||||
onWalletConnectBottomSheet { connectButton.performClick() }
|
||||
}
|
||||
step("Click 'More' button on TopBar") {
|
||||
onTopBar { moreButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Wallet Connect' button") {
|
||||
onDetailsScreen { walletConnectButton.clickWithAssertion() }
|
||||
}
|
||||
step("Check 'Wallet Connect' screen") {
|
||||
checkWalletConnectScreen()
|
||||
}
|
||||
step("Click on app icon") {
|
||||
onWalletConnectScreen { appIcon.performClick() }
|
||||
}
|
||||
step("Check 'Wallet Connect' details bottom sheet") {
|
||||
checkWalletConnectDetailsBottomSheet(dAppName)
|
||||
}
|
||||
step("Click on 'Disconnect button' is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { disconnectButton.performClick() }
|
||||
}
|
||||
step("Assert connection is not displayed") {
|
||||
onWalletConnectScreen { appName.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("3959")
|
||||
@DisplayName("WC (React App): open session from deeplink not on main screen")
|
||||
@Ignore("TODO [REDACTED_JIRA] React app deeplink doesn't work")
|
||||
@Test
|
||||
fun openWalletConnectSessionNotOnMainScreen() {
|
||||
val balance = TOTAL_BALANCE
|
||||
val dAppName = "React App"
|
||||
val deepLinkUri = getWcUri()
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Click on 'Buy' button") {
|
||||
onMainScreen { buyButton.clickWithAssertion() }
|
||||
}
|
||||
step("Create WC session buy deeplink") {
|
||||
openAppByDeepLink(deepLinkUri)
|
||||
}
|
||||
step("Check 'Wallet Connect' bottom sheet") {
|
||||
checkWalletConnectBottomSheet()
|
||||
}
|
||||
step("Click on 'Connect' button") {
|
||||
onWalletConnectBottomSheet { connectButton.performClick() }
|
||||
}
|
||||
step("Click 'More' button on TopBar") {
|
||||
onTopBar { moreButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Wallet Connect' button") {
|
||||
onDetailsScreen { walletConnectButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet is displayed") {
|
||||
onWalletConnectBottomSheet { connectButton.clickWithAssertion() }
|
||||
}
|
||||
step("Check 'Wallet Connect' screen") {
|
||||
checkWalletConnectScreen()
|
||||
}
|
||||
step("Click on app icon") {
|
||||
onWalletConnectScreen { appIcon.performClick() }
|
||||
}
|
||||
step("Check 'Wallet Connect' details bottom sheet") {
|
||||
checkWalletConnectDetailsBottomSheet(dAppName)
|
||||
}
|
||||
step("Click on 'Disconnect button' is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { disconnectButton.performClick() }
|
||||
}
|
||||
step("Assert connection is not displayed") {
|
||||
onWalletConnectScreen { appName.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("3957")
|
||||
@DisplayName("WC (React App): open session from deeplink ")
|
||||
@Ignore("TODO [REDACTED_JIRA] React app deeplink doesn't work")
|
||||
@Test
|
||||
fun openWalletConnectSession() {
|
||||
val balance = TOTAL_BALANCE
|
||||
val dAppName = "React App"
|
||||
val deepLinkUri = getWcUri()
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Open recent apps") {
|
||||
device.uiDevice.pressRecentApps()
|
||||
}
|
||||
step("Stop app by swipe") {
|
||||
swipeVertical(SwipeDirection.UP, startHeightRatio = 0.8f)
|
||||
}
|
||||
step("Create WC session buy deeplink") {
|
||||
openAppByDeepLink(deepLinkUri)
|
||||
}
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Check 'Wallet Connect' bottom sheet") {
|
||||
checkWalletConnectBottomSheet()
|
||||
}
|
||||
step("Click on 'Connect' button") {
|
||||
onWalletConnectBottomSheet { connectButton.performClick() }
|
||||
}
|
||||
step("Click 'More' button on TopBar") {
|
||||
onTopBar { moreButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Wallet Connect' button") {
|
||||
onDetailsScreen { walletConnectButton.clickWithAssertion() }
|
||||
}
|
||||
step("Check 'Wallet Connect' screen") {
|
||||
checkWalletConnectScreen()
|
||||
}
|
||||
step("Click on app icon") {
|
||||
onWalletConnectScreen { appIcon.performClick() }
|
||||
}
|
||||
step("Check 'Wallet Connect' details bottom sheet") {
|
||||
checkWalletConnectDetailsBottomSheet(dAppName)
|
||||
}
|
||||
step("Click on 'Disconnect button' is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { disconnectButton.performClick() }
|
||||
}
|
||||
step("Assert connection is not displayed") {
|
||||
onWalletConnectScreen { appName.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
97
app/src/androidTest/kotlin/com/tangem/tests/WarningTest.kt
Normal file
97
app/src/androidTest/kotlin/com/tangem/tests/WarningTest.kt
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.screens.onMainScreen
|
||||
import com.tangem.tap.domain.sdk.mocks.content.DevWalletMockContent
|
||||
import com.tangem.tap.domain.sdk.mocks.content.Wallet2WithSeedPhraseMockContent
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
import org.junit.Test
|
||||
|
||||
@HiltAndroidTest
|
||||
class WarningTest : BaseTestCase() {
|
||||
|
||||
@AllureId("898")
|
||||
@DisplayName("Warnings: check 'Dev card' warning")
|
||||
@Test
|
||||
fun devCardWarningTest() {
|
||||
setupHooks().run {
|
||||
step("Open 'Main' screen") {
|
||||
openMainScreen(mockContent = DevWalletMockContent)
|
||||
}
|
||||
step("Assert 'Dev card' notification title is displayed") {
|
||||
onMainScreen { devCardNotificationTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Dev card' notification message is displayed") {
|
||||
onMainScreen { devCardNotificationMessage.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Dev card' notification icon is displayed") {
|
||||
onMainScreen { devCardNotificationIcon.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("3991")
|
||||
@DisplayName("Warnings: check 'Dev card' warning is not displayed for release card")
|
||||
@Test
|
||||
fun releaseCardWarningTest() {
|
||||
setupHooks().run {
|
||||
step("Open 'Main' screen") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Assert 'Dev card' notification title is not displayed") {
|
||||
onMainScreen { devCardNotificationTitle.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert 'Dev card' notification message is not displayed") {
|
||||
onMainScreen { devCardNotificationMessage.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert 'Dev card' notification icon is not displayed") {
|
||||
onMainScreen { devCardNotificationIcon.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("227")
|
||||
@DisplayName("Seed notify: check warning for wallet with seed phrase")
|
||||
@Test
|
||||
fun checkWarningForWalletWithSeedPhraseTest() {
|
||||
val scenarioName = "seedphrase_notification"
|
||||
val scenarioState = "Notified"
|
||||
setupHooks(
|
||||
additionalBeforeSection = {
|
||||
step("Setup WireMock scenario '$scenarioName' for '$scenarioState' state") {
|
||||
setWireMockScenarioState(scenarioName, scenarioState)
|
||||
}
|
||||
},
|
||||
additionalAfterSection = {
|
||||
step("Reset WireMock scenario '$scenarioName' state") {
|
||||
resetWireMockScenarioState(scenarioName)
|
||||
}
|
||||
}
|
||||
).run {
|
||||
step("Open 'Main' screen") {
|
||||
openMainScreen(mockContent = Wallet2WithSeedPhraseMockContent, alreadyActivatedDialogIsShown = true)
|
||||
}
|
||||
step("Assert 'Seed phrase' notification icon is displayed") {
|
||||
onMainScreen { seedPhraseNotificationIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Seed phrase' notification title is displayed") {
|
||||
onMainScreen { seedPhraseNotificationTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Seed phrase' notification message is displayed") {
|
||||
onMainScreen { seedPhraseNotificationMessage.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert notification 'Yes' button is displayed") {
|
||||
onMainScreen { notificationYesButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert notification 'No' button is displayed") {
|
||||
onMainScreen { notificationNoButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.tangem.tests.balance
|
||||
|
||||
import androidx.compose.ui.test.longClick
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import com.tangem.screens.onMainScreen
|
||||
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 TotalBalanceLongTapTest : BaseTestCase() {
|
||||
|
||||
@Test
|
||||
@AllureId("3965")
|
||||
@DisplayName("Total balance: check long tap on block without biometry")
|
||||
fun whenBiometryIsOffTest() {
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(TOTAL_BALANCE)
|
||||
}
|
||||
step("Long tap on total balance block") {
|
||||
onMainScreen {
|
||||
totalBalanceContainer.performTouchInput {
|
||||
longClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert 'Rename' button is not displayed") {
|
||||
onMainScreen { totalBalanceMenuRenameWallet.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert 'Delete' button is not displayed") {
|
||||
onMainScreen { totalBalanceMenuDeleteWallet.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
package com.tangem.tests.balance
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import com.tangem.screens.onMainScreen
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
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 TotalBalanceUnavailableTest : BaseTestCase() {
|
||||
|
||||
@Test
|
||||
@AllureId("148")
|
||||
@DisplayName("Total balance: check dash sign when addresses are not derived")
|
||||
fun whenDerivationsDoesNotSyncedTest() {
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Do not synchronize addresses") {
|
||||
onMainScreen { synchronizeAddressesButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert dash sign is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(DASH_SIGN) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("3993")
|
||||
@DisplayName("Total balance: check dash sign when network is unreachable")
|
||||
fun whenNetworkIsUnreachableTest() {
|
||||
val scenarioName = "eth_network_balance"
|
||||
val scenarioState = "Unreachable"
|
||||
val tokenTitle = "Ethereum"
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(scenarioName)
|
||||
}
|
||||
).run {
|
||||
step("Set WireMock scenario: '$scenarioName' to state: '$scenarioState'") {
|
||||
setWireMockScenarioState(scenarioName = scenarioName, state = scenarioState)
|
||||
}
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(DASH_SIGN)
|
||||
}
|
||||
step("Assert 'Synchronize addresses' button does not exist") {
|
||||
onMainScreen {
|
||||
flakySafely {
|
||||
synchronizeAddressesButton.assertDoesNotExist()
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert dash sign is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(DASH_SIGN) }
|
||||
}
|
||||
step("Assert $tokenTitle is unreachable") {
|
||||
onMainScreen { tokenWithTitleAndPosition(tokenTitle, 1).assertIsUnreachable() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("3994")
|
||||
@DisplayName("Total balance: check dash sign when quotes are failed")
|
||||
fun whenQuotesAreFailedTest() {
|
||||
val scenarioName = "quotes_api"
|
||||
val scenarioState = "Error"
|
||||
val tokenTitle = "Ethereum"
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(scenarioName)
|
||||
}
|
||||
).run {
|
||||
step("Set WireMock scenario: '$scenarioName' to state: '$scenarioState'") {
|
||||
setWireMockScenarioState(scenarioName = scenarioName, state = scenarioState)
|
||||
}
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(DASH_SIGN)
|
||||
}
|
||||
step("Assert 'Synchronize addresses' button does not exist") {
|
||||
onMainScreen {
|
||||
flakySafely {
|
||||
synchronizeAddressesButton.assertDoesNotExist()
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert dash sign is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(DASH_SIGN) }
|
||||
}
|
||||
step("Assert $tokenTitle is unreachable") {
|
||||
onMainScreen { tokenWithTitleAndPosition(tokenTitle, 1).assertIsUnreachable() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("3995")
|
||||
@DisplayName("Total balance: check dash sign when added custom token without rate")
|
||||
fun whenCustomTokenWithoutRateAddedTest() {
|
||||
val scenarioName = "user_tokens_api"
|
||||
val scenarioState = "CustomTokenAdded"
|
||||
val tokenTitle = "Myria"
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(scenarioName)
|
||||
}
|
||||
).run {
|
||||
step("Set WireMock scenario: '$scenarioName' to state: '$scenarioState'") {
|
||||
setWireMockScenarioState(scenarioName = scenarioName, state = scenarioState)
|
||||
}
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(DASH_SIGN)
|
||||
}
|
||||
step("Assert 'Synchronize addresses' button does not exist") {
|
||||
onMainScreen {
|
||||
flakySafely {
|
||||
synchronizeAddressesButton.assertDoesNotExist()
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert dash sign is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(DASH_SIGN) }
|
||||
}
|
||||
step("Assert $tokenTitle is unreachable") {
|
||||
onMainScreen { tokenWithTitleAndPosition(tokenTitle, 4).assertIsUnreachable() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
package com.tangem.tests.balance
|
||||
|
||||
import androidx.compose.ui.test.longClick
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.common.extensions.*
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
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 TotalBalanceUpdateTest : BaseTestCase() {
|
||||
|
||||
@Test
|
||||
@AllureId("150")
|
||||
@DisplayName("Total balance: check balance update after pull to refresh")
|
||||
fun afterPullToRefreshTest() {
|
||||
val scenarioName = "eth_network_balance"
|
||||
val scenarioState = "Empty"
|
||||
val updatedBalance = "$763.55"
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(scenarioName)
|
||||
}
|
||||
).run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(TOTAL_BALANCE)
|
||||
}
|
||||
step("Assert $TOTAL_BALANCE is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(TOTAL_BALANCE) }
|
||||
}
|
||||
step("Set WireMock scenario: '$scenarioName' to state: '$scenarioState'") {
|
||||
setWireMockScenarioState(scenarioName = scenarioName, state = scenarioState)
|
||||
}
|
||||
step("Perform pull to refresh") {
|
||||
pullToRefresh()
|
||||
}
|
||||
step("Assert Total balance is updated from $TOTAL_BALANCE to $updatedBalance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(updatedBalance) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("3997")
|
||||
@DisplayName("Total balance: check balance update after token added")
|
||||
fun afterAddTokenTest() {
|
||||
val tokenTitle = "XRP"
|
||||
val scenarioName = "quotes_api"
|
||||
val scenarioState = "Ripple"
|
||||
val updatedBalance = "$3,307.18"
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(scenarioName)
|
||||
}
|
||||
).run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(TOTAL_BALANCE)
|
||||
}
|
||||
step("Assert $TOTAL_BALANCE is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(TOTAL_BALANCE) }
|
||||
}
|
||||
step("Open 'Markets screen'") {
|
||||
swipeMarketsBlock(SwipeDirection.UP)
|
||||
composeTestRule.waitForIdle()
|
||||
}
|
||||
step("Click on $tokenTitle token") {
|
||||
onMarketsScreen { tokenWithTitle(tokenTitle).clickWithAssertion() }
|
||||
}
|
||||
step("Set WireMock scenario: '$scenarioName' to state: '$scenarioState'") {
|
||||
setWireMockScenarioState(scenarioName = scenarioName, state = scenarioState)
|
||||
}
|
||||
step("Click on 'Add to portfolio' button") {
|
||||
onMarketsScreen { addToPortfolioButton.clickWithAssertion() }
|
||||
}
|
||||
step("Toggle the main network switch") {
|
||||
onMarketsScreen { mainNetworkSwitch.performClick() }
|
||||
}
|
||||
step("Click on 'Continue' button") {
|
||||
onDialog { continueButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Continue' is not displayed") {
|
||||
onDialog { continueButton.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Go back to 'Markets: tokens list'") {
|
||||
composeTestRule.waitForIdle()
|
||||
onMarketsScreen { topBarBackButton.clickWithAssertion() }
|
||||
}
|
||||
step("Close 'Markets screen'") {
|
||||
onSearchBar { searchField.assertIsDisplayed() }
|
||||
swipeMarketsBlock(SwipeDirection.DOWN)
|
||||
}
|
||||
step("Assert $updatedBalance is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(updatedBalance) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("4000")
|
||||
@DisplayName("Total balance: check balance update after collapse/expand")
|
||||
fun afterCollapseAndExpandTest() {
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(TOTAL_BALANCE)
|
||||
}
|
||||
step("Assert $TOTAL_BALANCE is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(TOTAL_BALANCE) }
|
||||
}
|
||||
step("Press 'Home' to collapse the app") {
|
||||
device.uiDevice.pressHome()
|
||||
}
|
||||
step("Open the app from recent apps") {
|
||||
openTheAppFromRecents()
|
||||
}
|
||||
step("Assert $TOTAL_BALANCE is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(TOTAL_BALANCE) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("3998")
|
||||
@DisplayName("Total balance: check balance update after hide token")
|
||||
fun afterHideTokenTest() {
|
||||
val tokenTitle = "Polygon"
|
||||
val updatedBalance = "$3,114.34"
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(TOTAL_BALANCE)
|
||||
}
|
||||
step("Assert $TOTAL_BALANCE is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(TOTAL_BALANCE) }
|
||||
}
|
||||
step("Long click on token with name: '$tokenTitle'") {
|
||||
composeTestRule.waitForIdle()
|
||||
onMainScreen {
|
||||
tokenWithTitleAndAddress(tokenTitle).performTouchInput {
|
||||
longClick(
|
||||
position = center,
|
||||
durationMillis = 1000L
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Click 'Hide token' button") {
|
||||
onBottomSheet { hideButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click 'Hide' button in dialog") {
|
||||
onDialog {
|
||||
dialogContainer.assertIsDisplayed()
|
||||
okButton.clickWithAssertion()
|
||||
}
|
||||
}
|
||||
step("Assert $updatedBalance is displayed in total balance") {
|
||||
swipeVertical(SwipeDirection.DOWN)
|
||||
onMainScreen { totalBalanceText.assertTextContains(updatedBalance) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("4001")
|
||||
@DisplayName("Total balance: check balance update after navigation")
|
||||
fun afterNavigationTest() {
|
||||
val tokenTitle = "Polygon"
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(TOTAL_BALANCE)
|
||||
}
|
||||
step("Assert $TOTAL_BALANCE is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(TOTAL_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 { backButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert $TOTAL_BALANCE is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(TOTAL_BALANCE) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.tap.data
|
||||
package com.tangem.tap
|
||||
|
||||
import com.google.firebase.messaging.FirebaseMessaging
|
||||
import com.tangem.utils.notifications.PushNotificationsTokenProvider
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.tap.di.data
|
||||
package com.tangem.tap.di
|
||||
|
||||
import com.tangem.tap.data.FirebasePushNotificationsTokenProvider
|
||||
import com.tangem.tap.FirebasePushNotificationsTokenProvider
|
||||
import com.tangem.utils.notifications.PushNotificationsTokenProvider
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
|
|
@ -10,7 +10,7 @@ import javax.inject.Singleton
|
|||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface PushNotificationsModule {
|
||||
internal interface GooglePushModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
17
app/src/huawei/AndroidManifest.xml
Normal file
17
app/src/huawei/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application>
|
||||
<service
|
||||
android:name="com.tangem.tap.HuaweiPushService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.huawei.push.action.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<meta-data
|
||||
android:name="push_kit_auto_init_enabled"
|
||||
android:value="true" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.tangem.tap
|
||||
|
||||
import android.content.Context
|
||||
import com.google.firebase.messaging.FirebaseMessaging
|
||||
import com.huawei.agconnect.AGConnectOptionsBuilder
|
||||
import com.huawei.hms.aaid.HmsInstanceId
|
||||
import com.huawei.hms.common.ApiException
|
||||
import com.tangem.google.GoogleServicesHelper
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.notifications.PushNotificationsTokenProvider
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.tasks.await
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class HuaweiPushNotificationsTokenProvider @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val coroutineDispatcherProvider: CoroutineDispatcherProvider,
|
||||
) : PushNotificationsTokenProvider {
|
||||
|
||||
override suspend fun getToken(): String {
|
||||
val isGoogleServicesAvailable = GoogleServicesHelper.checkGoogleServicesAvailability(context)
|
||||
return if (isGoogleServicesAvailable) {
|
||||
try {
|
||||
FirebaseMessaging.getInstance().token.await()
|
||||
} catch (ex: Exception) {
|
||||
Timber.e(ex)
|
||||
""
|
||||
}
|
||||
} else {
|
||||
withContext(coroutineDispatcherProvider.io) {
|
||||
try {
|
||||
val appId = AGConnectOptionsBuilder().build(context).getString(APP_ID_KEY)
|
||||
val token = HmsInstanceId.getInstance(context).getToken(appId, TOKEN_REQUEST_MODE)
|
||||
Timber.i("Requested token from HuaweiService: $token")
|
||||
token
|
||||
} catch (e: ApiException) {
|
||||
Timber.i("Fetching token from HuaweiService failed cause: ${e.message}")
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val APP_ID_KEY = "client/app_id"
|
||||
private const val TOKEN_REQUEST_MODE = "HCM"
|
||||
}
|
||||
}
|
||||
47
app/src/huawei/java/com/tangem/tap/HuaweiPushService.kt
Normal file
47
app/src/huawei/java/com/tangem/tap/HuaweiPushService.kt
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package com.tangem.tap
|
||||
|
||||
import android.os.Bundle
|
||||
import com.huawei.hms.push.HmsMessageService
|
||||
import com.huawei.hms.push.RemoteMessage
|
||||
import com.tangem.google.GoogleServicesHelper
|
||||
import com.tangem.tap.common.pushes.PushNotificationDelegate
|
||||
import timber.log.Timber
|
||||
|
||||
class HuaweiPushService : HmsMessageService() {
|
||||
|
||||
private val pushNotificationDelegate: PushNotificationDelegate by lazy {
|
||||
PushNotificationDelegate(applicationContext)
|
||||
}
|
||||
|
||||
override fun onNewToken(token: String?, bundle: Bundle?) {
|
||||
super.onNewToken(token, bundle)
|
||||
Timber.i("HuaweiPushService: On new token from HuaweiService: $token")
|
||||
}
|
||||
|
||||
override fun onTokenError(e: Exception?, bundle: Bundle?) {
|
||||
super.onTokenError(e, bundle)
|
||||
Timber.i("HuaweiPushService: Fetching token from HuaweiService failed cause: ${e?.message}")
|
||||
}
|
||||
|
||||
override fun onMessageReceived(message: RemoteMessage?) {
|
||||
super.onMessageReceived(message)
|
||||
val isGoogleServicesAvailable = GoogleServicesHelper.checkGoogleServicesAvailability(this)
|
||||
if (isGoogleServicesAvailable) return
|
||||
val notification = message?.notification ?: return
|
||||
val channelId = notification.channelId ?: TANGEM_CHANNEL_ID
|
||||
|
||||
pushNotificationDelegate.showNotification(
|
||||
dataMap = message.dataOfMap,
|
||||
title = notification.title,
|
||||
body = notification.body,
|
||||
channelId = channelId,
|
||||
priority = message.urgency,
|
||||
imageUrl = notification.imageUrl,
|
||||
vibratePattern = notification.vibrateConfig,
|
||||
)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val TANGEM_CHANNEL_ID = "Tangem General" // General channel for notifications
|
||||
}
|
||||
}
|
||||
18
app/src/huawei/java/com/tangem/tap/di/HuaweiPushModule.kt
Normal file
18
app/src/huawei/java/com/tangem/tap/di/HuaweiPushModule.kt
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.tap.di
|
||||
|
||||
import com.tangem.tap.HuaweiPushNotificationsTokenProvider
|
||||
import com.tangem.utils.notifications.PushNotificationsTokenProvider
|
||||
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 HuaweiPushModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindPushNotificationsTokenProvider(impl: HuaweiPushNotificationsTokenProvider): PushNotificationsTokenProvider
|
||||
}
|
||||
|
|
@ -34,6 +34,7 @@
|
|||
<application
|
||||
android:name="com.tangem.tap.TangemHiltApplication"
|
||||
android:allowBackup="false"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:fullBackupContent="false"
|
||||
android:hardwareAccelerated="true"
|
||||
|
|
@ -45,7 +46,7 @@
|
|||
android:roundIcon="@mipmap/ic_launcher"
|
||||
android:supportsRtl="true"
|
||||
tools:ignore="GoogleAppIndexingWarning"
|
||||
tools:replace="android:allowBackup, android:fullBackupContent, android:label, android:largeHeap">
|
||||
tools:replace="android:allowBackup, android:dataExtractionRules, android:fullBackupContent, android:label, android:largeHeap">
|
||||
|
||||
<!--
|
||||
property to make the "android:screenOrientation" work on API <37
|
||||
|
|
@ -264,6 +265,16 @@
|
|||
android:host="promo"
|
||||
android:scheme="tangem" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="onboard-visa"
|
||||
android:scheme="tangem" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Disable android.startup completely. Used for Worker according doc -->
|
||||
|
|
|
|||
|
|
@ -1,160 +1,165 @@
|
|||
{
|
||||
"coins" : [
|
||||
"coins": [
|
||||
{
|
||||
"id" : "matic-token",
|
||||
"symbol" : "MATIC",
|
||||
"name" : "Polygon",
|
||||
"networks" : [
|
||||
"id": "matic-token",
|
||||
"symbol": "MATIC",
|
||||
"name": "Polygon",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "polygon-pos/test",
|
||||
"contractAddress" : "0x0000000000000000000000000000000000001010",
|
||||
"decimalCount" : 18
|
||||
"networkId": "polygon-pos/test",
|
||||
"contractAddress": "0x0000000000000000000000000000000000001010",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "kaspa",
|
||||
"symbol" : "KAS",
|
||||
"name" : "Kaspa",
|
||||
"networks" : [
|
||||
"id": "kaspa",
|
||||
"symbol": "KAS",
|
||||
"name": "Kaspa",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "kaspa/test"
|
||||
"networkId": "kaspa/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Dai Stablecoin-DAI",
|
||||
"symbol" : "DAI",
|
||||
"name" : "Dai Stablecoin",
|
||||
"networks" : [
|
||||
"id": "Dai Stablecoin-DAI",
|
||||
"symbol": "DAI",
|
||||
"name": "Dai Stablecoin",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "polygon-pos/test",
|
||||
"contractAddress" : "0xcB1e72786A6eb3b44C2a2429e317c8a2462CFeb1",
|
||||
"decimalCount" : 18
|
||||
"networkId": "polygon-pos/test",
|
||||
"contractAddress": "0xcB1e72786A6eb3b44C2a2429e317c8a2462CFeb1",
|
||||
"decimalCount": 18
|
||||
},
|
||||
{
|
||||
"networkId" : "binance-smart-chain/test",
|
||||
"contractAddress" : "0xec5dcb5dbf4b114c9d0f65bccab49ec54f6a0867",
|
||||
"decimalCount" : 18
|
||||
"networkId": "binance-smart-chain/test",
|
||||
"contractAddress": "0xec5dcb5dbf4b114c9d0f65bccab49ec54f6a0867",
|
||||
"decimalCount": 18
|
||||
},
|
||||
{
|
||||
"networkId" : "binance-smart-chain/test",
|
||||
"contractAddress" : "0x8a9424745056eb399fd19a0ec26a14316684e274",
|
||||
"decimalCount" : 18
|
||||
"networkId": "binance-smart-chain/test",
|
||||
"contractAddress": "0x8a9424745056eb399fd19a0ec26a14316684e274",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Dummy ERC20-DERC20",
|
||||
"symbol" : "DERC20",
|
||||
"name" : "Dummy ERC20",
|
||||
"networks" : [
|
||||
"id": "Dummy ERC20-DERC20",
|
||||
"symbol": "DERC20",
|
||||
"name": "Dummy ERC20",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "polygon-pos/test",
|
||||
"contractAddress" : "0xfe4F5145f6e09952a5ba9e956ED0C25e3Fa4c7F1",
|
||||
"decimalCount" : 18
|
||||
"networkId": "polygon-pos/test",
|
||||
"contractAddress": "0xfe4F5145f6e09952a5ba9e956ED0C25e3Fa4c7F1",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Ether-ETH",
|
||||
"symbol" : "ETH",
|
||||
"name" : "Ether",
|
||||
"networks" : [
|
||||
"id": "Ether-ETH",
|
||||
"symbol": "ETH",
|
||||
"name": "Ether",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "polygon-pos/test",
|
||||
"contractAddress" : "0x714550C2C1Ea08688607D86ed8EeF4f5E4F22323",
|
||||
"decimalCount" : 18
|
||||
"networkId": "polygon-pos/test",
|
||||
"contractAddress": "0x714550C2C1Ea08688607D86ed8EeF4f5E4F22323",
|
||||
"decimalCount": 18
|
||||
},
|
||||
{
|
||||
"networkId" : "binance-smart-chain/test",
|
||||
"contractAddress" : "0xd66c6b4f0be8ce5b39d52e0fd1344c389929b378",
|
||||
"decimalCount" : 18
|
||||
"networkId": "binance-smart-chain/test",
|
||||
"contractAddress": "0xd66c6b4f0be8ce5b39d52e0fd1344c389929b378",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Test Token-TST",
|
||||
"symbol" : "TST",
|
||||
"name" : "Test Token",
|
||||
"networks" : [
|
||||
"id": "Test Token-TST",
|
||||
"symbol": "TST",
|
||||
"name": "Test Token",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "polygon-pos/test",
|
||||
"contractAddress" : "0x2d7882bedcbfddce29ba99965dd3cdf7fcb10a1e",
|
||||
"decimalCount" : 18
|
||||
"networkId": "polygon-pos/test",
|
||||
"contractAddress": "0x2d7882bedcbfddce29ba99965dd3cdf7fcb10a1e",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "tether",
|
||||
"symbol" : "USDT",
|
||||
"name" : "Tether USD",
|
||||
"networks" : [
|
||||
"id": "tether",
|
||||
"symbol": "USDT",
|
||||
"name": "Tether USD",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "polygon-pos/test",
|
||||
"contractAddress" : "0x3813e82e6f7098b9583FC0F33a962D02018B6803",
|
||||
"decimalCount" : 6
|
||||
"networkId": "ethereum/test",
|
||||
"contractAddress": "0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0",
|
||||
"decimalCount": 18
|
||||
},
|
||||
{
|
||||
"networkId" : "binance-smart-chain/test",
|
||||
"contractAddress" : "0x337610d27c682e347c9cd60bd4b3b107c9d34ddd",
|
||||
"decimalCount" : 18
|
||||
"networkId": "polygon-pos/test",
|
||||
"contractAddress": "0x3813e82e6f7098b9583FC0F33a962D02018B6803",
|
||||
"decimalCount": 6
|
||||
},
|
||||
{
|
||||
"networkId" : "tron/test",
|
||||
"contractAddress" : "TXLAQ63Xg1NAzckPwKHvzw7CSEmLMEqcdj",
|
||||
"decimalCount" : 6
|
||||
"networkId": "binance-smart-chain/test",
|
||||
"contractAddress": "0x337610d27c682e347c9cd60bd4b3b107c9d34ddd",
|
||||
"decimalCount": 18
|
||||
},
|
||||
{
|
||||
"networkId" : "binance-smart-chain/test",
|
||||
"contractAddress" : "0x7ef95a0fee0dd31b22626fa2e10ee6a223f8a684",
|
||||
"decimalCount" : 18
|
||||
"networkId": "tron/test",
|
||||
"contractAddress": "TXLAQ63Xg1NAzckPwKHvzw7CSEmLMEqcdj",
|
||||
"decimalCount": 6
|
||||
},
|
||||
{
|
||||
"networkId": "binance-smart-chain/test",
|
||||
"contractAddress": "0x7ef95a0fee0dd31b22626fa2e10ee6a223f8a684",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "just-gov",
|
||||
"symbol" : "JST",
|
||||
"name" : "JUST GOV",
|
||||
"networks" : [
|
||||
"id": "just-gov",
|
||||
"symbol": "JST",
|
||||
"name": "JUST GOV",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "tron/test",
|
||||
"contractAddress" : "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
|
||||
"decimalCount" : 18
|
||||
"networkId": "tron/test",
|
||||
"contractAddress": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Wrapped Ether-WETH",
|
||||
"symbol" : "WETH",
|
||||
"name" : "Wrapped Ether",
|
||||
"networks" : [
|
||||
"id": "Wrapped Ether-WETH",
|
||||
"symbol": "WETH",
|
||||
"name": "Wrapped Ether",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "polygon-pos/test",
|
||||
"contractAddress" : "0xA6FA4fB5f76172d178d61B04b0ecd319C5d1C0aa",
|
||||
"decimalCount" : 18
|
||||
"networkId": "polygon-pos/test",
|
||||
"contractAddress": "0xA6FA4fB5f76172d178d61B04b0ecd319C5d1C0aa",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Wrapped Matic-WMATIC",
|
||||
"symbol" : "WMATIC",
|
||||
"name" : "Wrapped Matic",
|
||||
"networks" : [
|
||||
"id": "Wrapped Matic-WMATIC",
|
||||
"symbol": "WMATIC",
|
||||
"name": "Wrapped Matic",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "polygon-pos/test",
|
||||
"contractAddress" : "0xd0A1E359811322d97991E03f863a0C30C2cF029C",
|
||||
"decimalCount" : 18
|
||||
"networkId": "polygon-pos/test",
|
||||
"contractAddress": "0xd0A1E359811322d97991E03f863a0C30C2cF029C",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "solana",
|
||||
"symbol" : "SOL",
|
||||
"name" : "Solana",
|
||||
"networks" : [
|
||||
"id": "solana",
|
||||
"symbol": "SOL",
|
||||
"name": "Solana",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "solana/test"
|
||||
"networkId": "solana/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -162,263 +167,262 @@
|
|||
"id": "the-open-network",
|
||||
"symbol": "TON",
|
||||
"name": "Toncoin",
|
||||
"networks":
|
||||
[
|
||||
"networks": [
|
||||
{
|
||||
"networkId": "the-open-network/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Tangem Coin A-TCA",
|
||||
"symbol" : "TCA",
|
||||
"name" : "Tangem Coin A",
|
||||
"networks" : [
|
||||
"id": "Tangem Coin A-TCA",
|
||||
"symbol": "TCA",
|
||||
"name": "Tangem Coin A",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "solana/test",
|
||||
"contractAddress" : "22PTNbX31Zuztd6nD82fC8nQdT2hUfWv9XWXKuDkrFqR",
|
||||
"decimalCount" : 9
|
||||
"networkId": "solana/test",
|
||||
"contractAddress": "22PTNbX31Zuztd6nD82fC8nQdT2hUfWv9XWXKuDkrFqR",
|
||||
"decimalCount": 9
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Tangem Coin B-TCB",
|
||||
"symbol" : "TCB",
|
||||
"name" : "Tangem Coin B",
|
||||
"networks" : [
|
||||
"id": "Tangem Coin B-TCB",
|
||||
"symbol": "TCB",
|
||||
"name": "Tangem Coin B",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "solana/test",
|
||||
"contractAddress" : "HmSghNPg6KCk711YJA92aPejt8auyFkvmaED6jbHfUs4",
|
||||
"decimalCount" : 9
|
||||
"networkId": "solana/test",
|
||||
"contractAddress": "HmSghNPg6KCk711YJA92aPejt8auyFkvmaED6jbHfUs4",
|
||||
"decimalCount": 9
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "binancecoin",
|
||||
"symbol" : "BNB",
|
||||
"name" : "Binance",
|
||||
"networks" : [
|
||||
"id": "binancecoin",
|
||||
"symbol": "BNB",
|
||||
"name": "Binance",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "binancecoin/test"
|
||||
"networkId": "binancecoin/test"
|
||||
},
|
||||
{
|
||||
"networkId" : "binance-smart-chain/test"
|
||||
"networkId": "binance-smart-chain/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Hemster - 452-HEM",
|
||||
"symbol" : "HEM",
|
||||
"name" : "Hemster - 452",
|
||||
"networks" : [
|
||||
"id": "Hemster - 452-HEM",
|
||||
"symbol": "HEM",
|
||||
"name": "Hemster - 452",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "binancecoin/test",
|
||||
"contractAddress" : "HEM-452",
|
||||
"decimalCount" : 8
|
||||
"networkId": "binancecoin/test",
|
||||
"contractAddress": "HEM-452",
|
||||
"decimalCount": 8
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Binance-Peg BTCB Token-BTCB",
|
||||
"symbol" : "BTCB",
|
||||
"name" : "Binance-Peg BTCB Token",
|
||||
"networks" : [
|
||||
"id": "Binance-Peg BTCB Token-BTCB",
|
||||
"symbol": "BTCB",
|
||||
"name": "Binance-Peg BTCB Token",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "binance-smart-chain/test",
|
||||
"contractAddress" : "0x6ce8da28e2f864420840cf74474eff5fd80e65b8",
|
||||
"decimalCount" : 18
|
||||
"networkId": "binance-smart-chain/test",
|
||||
"contractAddress": "0x6ce8da28e2f864420840cf74474eff5fd80e65b8",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Binance-Peg BUSD Token-BUSD",
|
||||
"symbol" : "BUSD",
|
||||
"name" : "Binance-Peg BUSD Token",
|
||||
"networks" : [
|
||||
"id": "Binance-Peg BUSD Token-BUSD",
|
||||
"symbol": "BUSD",
|
||||
"name": "Binance-Peg BUSD Token",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "binance-smart-chain/test",
|
||||
"contractAddress" : "0xed24fc36d5ee211ea25a80239fb8c4cfd80f12ee",
|
||||
"decimalCount" : 18
|
||||
"networkId": "binance-smart-chain/test",
|
||||
"contractAddress": "0xed24fc36d5ee211ea25a80239fb8c4cfd80f12ee",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Binance-Peg USDC Token-USDC",
|
||||
"symbol" : "USDC",
|
||||
"name" : "Binance-Peg USDC Token",
|
||||
"networks" : [
|
||||
"id": "Binance-Peg USDC Token-USDC",
|
||||
"symbol": "USDC",
|
||||
"name": "Binance-Peg USDC Token",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "binance-smart-chain/test",
|
||||
"contractAddress" : "0x64544969ed7ebf5f083679233325356ebe738930",
|
||||
"decimalCount" : 18
|
||||
"networkId": "binance-smart-chain/test",
|
||||
"contractAddress": "0x64544969ed7ebf5f083679233325356ebe738930",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Binance-Peg XRP-XRP",
|
||||
"symbol" : "XRP",
|
||||
"name" : "Binance-Peg XRP",
|
||||
"networks" : [
|
||||
"id": "Binance-Peg XRP-XRP",
|
||||
"symbol": "XRP",
|
||||
"name": "Binance-Peg XRP",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "binance-smart-chain/test",
|
||||
"contractAddress" : "0xa83575490d7df4e2f47b7d38ef351a2722ca45b9",
|
||||
"decimalCount" : 18
|
||||
"networkId": "binance-smart-chain/test",
|
||||
"contractAddress": "0xa83575490d7df4e2f47b7d38ef351a2722ca45b9",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "ethereum",
|
||||
"symbol" : "ETH",
|
||||
"name" : "Ethereum",
|
||||
"networks" : [
|
||||
"id": "ethereum",
|
||||
"symbol": "ETH",
|
||||
"name": "Ethereum",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "ethereum/test"
|
||||
"networkId": "ethereum/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "ethereum-classic",
|
||||
"symbol" : "ETC",
|
||||
"name" : "Ethereum Classic",
|
||||
"networks" : [
|
||||
"id": "ethereum-classic",
|
||||
"symbol": "ETC",
|
||||
"name": "Ethereum Classic",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "ethereum-classic/test"
|
||||
"networkId": "ethereum-classic/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Weenus-WEENUS",
|
||||
"symbol" : "WEENUS",
|
||||
"name" : "Weenus",
|
||||
"networks" : [
|
||||
"id": "Weenus-WEENUS",
|
||||
"symbol": "WEENUS",
|
||||
"name": "Weenus",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "ethereum/test",
|
||||
"contractAddress" : "0xaFF4481D10270F50f203E0763e2597776068CBc5",
|
||||
"decimalCount" : 18
|
||||
"networkId": "ethereum/test",
|
||||
"contractAddress": "0xaFF4481D10270F50f203E0763e2597776068CBc5",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Xeenus-XEENUS",
|
||||
"symbol" : "XEENUS",
|
||||
"name" : "Xeenus",
|
||||
"networks" : [
|
||||
"id": "Xeenus-XEENUS",
|
||||
"symbol": "XEENUS",
|
||||
"name": "Xeenus",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "ethereum/test",
|
||||
"contractAddress" : "0x022E292b44B5a146F2e8ee36Ff44D3dd863C915c",
|
||||
"decimalCount" : 18
|
||||
"networkId": "ethereum/test",
|
||||
"contractAddress": "0x022E292b44B5a146F2e8ee36Ff44D3dd863C915c",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Yeenus-YEENUS",
|
||||
"symbol" : "YEENUS",
|
||||
"name" : "Yeenus",
|
||||
"networks" : [
|
||||
"id": "Yeenus-YEENUS",
|
||||
"symbol": "YEENUS",
|
||||
"name": "Yeenus",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "ethereum/test",
|
||||
"contractAddress" : "0xc6fDe3FD2Cc2b173aEC24cc3f267cb3Cd78a26B7",
|
||||
"decimalCount" : 8
|
||||
"networkId": "ethereum/test",
|
||||
"contractAddress": "0xc6fDe3FD2Cc2b173aEC24cc3f267cb3Cd78a26B7",
|
||||
"decimalCount": 8
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Zeenus-ZEENUS",
|
||||
"symbol" : "ZEENUS",
|
||||
"name" : "Zeenus",
|
||||
"networks" : [
|
||||
"id": "Zeenus-ZEENUS",
|
||||
"symbol": "ZEENUS",
|
||||
"name": "Zeenus",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "ethereum/test",
|
||||
"contractAddress" : "0x1f9061B953bBa0E36BF50F21876132DcF276fC6e",
|
||||
"decimalCount" : 0
|
||||
"networkId": "ethereum/test",
|
||||
"contractAddress": "0x1f9061B953bBa0E36BF50F21876132DcF276fC6e",
|
||||
"decimalCount": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "avalanche-2",
|
||||
"symbol" : "AVAX",
|
||||
"name" : "Avalanche",
|
||||
"networks" : [
|
||||
"id": "avalanche-2",
|
||||
"symbol": "AVAX",
|
||||
"name": "Avalanche",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "avalanche/test"
|
||||
"networkId": "avalanche/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "The Fuji stablecoin-FUJISTABLE",
|
||||
"symbol" : "FUJISTABLE",
|
||||
"name" : "The Fuji stablecoin",
|
||||
"networks" : [
|
||||
"id": "The Fuji stablecoin-FUJISTABLE",
|
||||
"symbol": "FUJISTABLE",
|
||||
"name": "The Fuji stablecoin",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "avalanche/test",
|
||||
"contractAddress" : "0x2058ec2791dD28b6f67DB836ddf87534F4Bbdf22",
|
||||
"decimalCount" : 6
|
||||
"networkId": "avalanche/test",
|
||||
"contractAddress": "0x2058ec2791dD28b6f67DB836ddf87534F4Bbdf22",
|
||||
"decimalCount": 6
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "To the Moon-FUJIMOON",
|
||||
"symbol" : "FUJIMOON",
|
||||
"name" : "To the Moon",
|
||||
"networks" : [
|
||||
"id": "To the Moon-FUJIMOON",
|
||||
"symbol": "FUJIMOON",
|
||||
"name": "To the Moon",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "avalanche/test",
|
||||
"contractAddress" : "0x97132C109c6816525F7f338DCb7435E1412A7668",
|
||||
"decimalCount" : 9
|
||||
"networkId": "avalanche/test",
|
||||
"contractAddress": "0x97132C109c6816525F7f338DCb7435E1412A7668",
|
||||
"decimalCount": 9
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "fantom",
|
||||
"symbol" : "FTM",
|
||||
"name" : "Fantom",
|
||||
"networks" : [
|
||||
"id": "fantom",
|
||||
"symbol": "FTM",
|
||||
"name": "Fantom",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "fantom/test"
|
||||
"networkId": "fantom/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Fantom USD-FUSD",
|
||||
"symbol" : "FUSD",
|
||||
"name" : "Fantom USD",
|
||||
"networks" : [
|
||||
"id": "Fantom USD-FUSD",
|
||||
"symbol": "FUSD",
|
||||
"name": "Fantom USD",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "fantom/test",
|
||||
"contractAddress" : "0x91ea991bd52EE3C40EdA2509701d905e1Ee54074",
|
||||
"decimalCount" : 18
|
||||
"networkId": "fantom/test",
|
||||
"contractAddress": "0x91ea991bd52EE3C40EdA2509701d905e1Ee54074",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "Wrapped Fantom-WFTM",
|
||||
"symbol" : "WFTM",
|
||||
"name" : "Wrapped Fantom",
|
||||
"networks" : [
|
||||
"id": "Wrapped Fantom-WFTM",
|
||||
"symbol": "WFTM",
|
||||
"name": "Wrapped Fantom",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "fantom/test",
|
||||
"contractAddress" : "0xf1277d1Ed8AD466beddF92ef448A132661956621",
|
||||
"decimalCount" : 18
|
||||
"networkId": "fantom/test",
|
||||
"contractAddress": "0xf1277d1Ed8AD466beddF92ef448A132661956621",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "bitcoin",
|
||||
"symbol" : "BTC",
|
||||
"name" : "Bitcoin",
|
||||
"networks" : [
|
||||
"id": "bitcoin",
|
||||
"symbol": "BTC",
|
||||
"name": "Bitcoin",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "bitcoin/test"
|
||||
"networkId": "bitcoin/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "vechain",
|
||||
"symbol" : "VET",
|
||||
"name" : "VeChain",
|
||||
"networks" : [
|
||||
"id": "vechain",
|
||||
"symbol": "VET",
|
||||
"name": "VeChain",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "vechain/test"
|
||||
"networkId": "vechain/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -435,34 +439,34 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id" : "tron",
|
||||
"symbol" : "TRX",
|
||||
"name" : "Tron",
|
||||
"networks" : [
|
||||
{
|
||||
"networkId" : "tron/test"
|
||||
}
|
||||
]
|
||||
"id": "tron",
|
||||
"symbol": "TRX",
|
||||
"name": "Tron",
|
||||
"networks": [
|
||||
{
|
||||
"networkId": "tron/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "algorand",
|
||||
"symbol" : "ALGO",
|
||||
"name" : "Algorand",
|
||||
"networks" : [
|
||||
{
|
||||
"networkId" : "algorand/test"
|
||||
}
|
||||
]
|
||||
"id": "algorand",
|
||||
"symbol": "ALGO",
|
||||
"name": "Algorand",
|
||||
"networks": [
|
||||
{
|
||||
"networkId": "algorand/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id" : "arbitrum-one",
|
||||
"symbol" : "ETH",
|
||||
"name" : "Arbitrum",
|
||||
"networks" : [
|
||||
{
|
||||
"networkId" : "arbitrum-one/test"
|
||||
}
|
||||
]
|
||||
"id": "arbitrum-one",
|
||||
"symbol": "ETH",
|
||||
"name": "Arbitrum",
|
||||
"networks": [
|
||||
{
|
||||
"networkId": "arbitrum-one/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "stellar",
|
||||
|
|
@ -485,12 +489,12 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id" : "polkadot",
|
||||
"symbol" : "DOT",
|
||||
"name" : "Polkadot",
|
||||
"networks" : [
|
||||
"id": "polkadot",
|
||||
"symbol": "DOT",
|
||||
"name": "Polkadot",
|
||||
"networks": [
|
||||
{
|
||||
"networkId" : "polkadot/test"
|
||||
"networkId": "polkadot/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -509,8 +513,7 @@
|
|||
"id": "kava",
|
||||
"symbol": "KAVA",
|
||||
"name": "Kava EVM",
|
||||
"networks":
|
||||
[
|
||||
"networks": [
|
||||
{
|
||||
"networkId": "kava/test"
|
||||
}
|
||||
|
|
@ -520,8 +523,7 @@
|
|||
"id": "telos",
|
||||
"symbol": "TLOS",
|
||||
"name": "Telos EVM",
|
||||
"networks":
|
||||
[
|
||||
"networks": [
|
||||
{
|
||||
"networkId": "telos/test"
|
||||
}
|
||||
|
|
@ -531,8 +533,7 @@
|
|||
"id": "ravencoin",
|
||||
"symbol": "RVN",
|
||||
"name": "Ravencoin",
|
||||
"networks":
|
||||
[
|
||||
"networks": [
|
||||
{
|
||||
"networkId": "ravencoin/test"
|
||||
}
|
||||
|
|
@ -542,8 +543,7 @@
|
|||
"id": "cosmos",
|
||||
"symbol": "ATOM",
|
||||
"name": "Cosmos Hub",
|
||||
"networks":
|
||||
[
|
||||
"networks": [
|
||||
{
|
||||
"networkId": "cosmos/test"
|
||||
}
|
||||
|
|
@ -798,6 +798,30 @@
|
|||
"networkId": "alephium/test"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chainlink",
|
||||
"name": "Chainlink",
|
||||
"symbol": "LINK",
|
||||
"networks": [
|
||||
{
|
||||
"networkId": "ethereum/test",
|
||||
"contractAddress": "0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "gho",
|
||||
"name": "GHO",
|
||||
"symbol": "GHO",
|
||||
"networks": [
|
||||
{
|
||||
"networkId": "ethereum/test",
|
||||
"contractAddress": "0xc4bF5CbDaBE595361438F8c6a187bDc330539c60",
|
||||
"decimalCount": 18
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,12 +29,13 @@ import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
|||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.feedback.GetCardInfoUseCase
|
||||
import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase
|
||||
import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase
|
||||
import com.tangem.domain.onboarding.repository.OnboardingRepository
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.walletconnect.usecase.initialize.WcInitializeUseCase
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.builder.ColdUserWalletBuilder
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
|
|
@ -50,7 +51,6 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
|||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository as WalletConnect2Repository
|
||||
|
||||
@EntryPoint
|
||||
@InstallIn(SingletonComponent::class)
|
||||
|
|
@ -71,8 +71,6 @@ interface ApplicationEntryPoint {
|
|||
|
||||
fun getCardScanningFeatureToggles(): CardScanningFeatureToggles
|
||||
|
||||
fun getWalletConnect2Repository(): WalletConnect2Repository
|
||||
|
||||
fun getScanCardProcessor(): ScanCardProcessor
|
||||
|
||||
fun getAppCurrencyRepository(): AppCurrencyRepository
|
||||
|
|
@ -107,7 +105,7 @@ interface ApplicationEntryPoint {
|
|||
|
||||
fun getSendFeedbackEmailUseCase(): SendFeedbackEmailUseCase
|
||||
|
||||
fun getGetCardInfoUseCase(): GetCardInfoUseCase
|
||||
fun getWalletMetaInfoUseCase(): GetWalletMetaInfoUseCase
|
||||
|
||||
fun getUrlOpener(): UrlOpener
|
||||
|
||||
|
|
@ -151,4 +149,6 @@ interface ApplicationEntryPoint {
|
|||
fun getTangemHotSdk(): TangemHotSdk
|
||||
|
||||
fun getHotWalletFeatureToggles(): HotWalletFeatureToggles
|
||||
|
||||
fun getWcInitializeUseCase(): WcInitializeUseCase
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import com.tangem.domain.settings.repositories.SettingsRepository
|
|||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.legacy.asLockable
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.wallets.usecase.ClearAllHotWalletContextualUnlockUseCase
|
||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||
import com.tangem.tap.LockTimerWorker.Companion.TAG
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
|
|
@ -22,6 +23,7 @@ import timber.log.Timber
|
|||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.time.Duration
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class LockUserWalletsTimer(
|
||||
private val context: Context,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
|
|
@ -30,6 +32,7 @@ internal class LockUserWalletsTimer(
|
|||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||
private val coroutineScope: CoroutineScope,
|
||||
private val clearAllHotWalletContextualUnlockUseCase: ClearAllHotWalletContextualUnlockUseCase,
|
||||
) : LifecycleOwner by context as LifecycleOwner,
|
||||
DefaultLifecycleObserver {
|
||||
|
||||
|
|
@ -55,6 +58,9 @@ internal class LockUserWalletsTimer(
|
|||
)
|
||||
|
||||
if (shouldOpenWelcomeScreenOnResume) {
|
||||
if (hotWalletFeatureToggles.isHotWalletEnabled) {
|
||||
clearAllHotWalletContextualUnlockUseCase.invoke()
|
||||
}
|
||||
store.dispatchNavigationAction { replaceAll(AppRoute.Welcome()) }
|
||||
settingsRepository.setShouldOpenWelcomeScreenOnResume(value = false)
|
||||
}
|
||||
|
|
@ -120,6 +126,7 @@ internal class LockUserWalletsTimer(
|
|||
start()
|
||||
}
|
||||
.onRight {
|
||||
clearAllHotWalletContextualUnlockUseCase.invoke()
|
||||
store.dispatchNavigationAction { replaceAll(AppRoute.Welcome()) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,8 @@ import androidx.lifecycle.Lifecycle
|
|||
import androidx.lifecycle.flowWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.routing.AppRoute
|
||||
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.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.di.RootAppComponentContext
|
||||
|
|
@ -40,7 +38,7 @@ import com.tangem.domain.apptheme.model.AppThemeMode
|
|||
import com.tangem.domain.card.ScanCardUseCase
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.models.wallet.isLocked
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.settings.SetGooglePayAvailabilityUseCase
|
||||
import com.tangem.domain.settings.SetGoogleServicesAvailabilityUseCase
|
||||
import com.tangem.domain.settings.ShouldInitiallyAskPermissionUseCase
|
||||
|
|
@ -49,12 +47,11 @@ import com.tangem.domain.staking.SendUnsubmittedHashesUseCase
|
|||
import com.tangem.domain.tokens.GetPolkadotCheckHasImmortalUseCase
|
||||
import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.wallets.usecase.ClearAllHotWalletContextualUnlockUseCase
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
|
||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||
import com.tangem.features.tangempay.TangemPayFeatureToggles
|
||||
import com.tangem.features.tester.api.TesterMenuLauncher
|
||||
import com.tangem.features.walletconnect.components.WalletConnectFeatureToggles
|
||||
import com.tangem.google.GoogleServicesHelper
|
||||
import com.tangem.operations.backup.BackupService
|
||||
import com.tangem.sdk.api.BackupServiceHolder
|
||||
|
|
@ -62,13 +59,9 @@ import com.tangem.sdk.api.TangemSdkManager
|
|||
import com.tangem.tap.common.ActivityResultCallbackHolder
|
||||
import com.tangem.tap.common.DialogManager
|
||||
import com.tangem.tap.common.OnActivityResultCallback
|
||||
import com.tangem.tap.common.analytics.events.Push
|
||||
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor
|
||||
import com.tangem.tap.features.intentHandler.IntentProcessor
|
||||
import com.tangem.tap.features.intentHandler.handlers.BackgroundScanIntentHandler
|
||||
import com.tangem.tap.features.intentHandler.handlers.OnPushClickedIntentHandler
|
||||
import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler
|
||||
import com.tangem.tap.features.main.MainViewModel
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphAction
|
||||
import com.tangem.tap.routing.component.RoutingComponent
|
||||
|
|
@ -116,9 +109,6 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
@Inject
|
||||
lateinit var scanCardUseCase: ScanCardUseCase
|
||||
|
||||
@Inject
|
||||
lateinit var walletConnectInteractor: WalletConnectInteractor
|
||||
|
||||
@Inject
|
||||
lateinit var settingsRepository: SettingsRepository
|
||||
|
||||
|
|
@ -171,24 +161,12 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
@Inject
|
||||
internal lateinit var deeplinkFactory: DeepLinkFactory
|
||||
|
||||
@Inject
|
||||
internal lateinit var walletConnectFeatureToggles: WalletConnectFeatureToggles
|
||||
|
||||
@Inject
|
||||
internal lateinit var urlOpener: UrlOpener
|
||||
|
||||
@Inject
|
||||
internal lateinit var testerMenuLauncher: TesterMenuLauncher
|
||||
|
||||
@Inject
|
||||
internal lateinit var intentProcessor: IntentProcessor
|
||||
|
||||
@Inject
|
||||
internal lateinit var walletConnectLinkIntentHandler: WalletConnectLinkIntentHandler
|
||||
|
||||
@Inject
|
||||
internal lateinit var onPushClickedIntentHandler: OnPushClickedIntentHandler
|
||||
|
||||
@Inject
|
||||
internal lateinit var backgroundScanIntentHandler: BackgroundScanIntentHandler
|
||||
|
||||
|
|
@ -198,10 +176,13 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
@Inject
|
||||
internal lateinit var hotWalletFeatureToggles: HotWalletFeatureToggles
|
||||
|
||||
@Inject
|
||||
internal lateinit var clearAllHotWalletContextualUnlockUseCase: ClearAllHotWalletContextualUnlockUseCase
|
||||
|
||||
@Inject
|
||||
internal lateinit var tangemPayFeatureToggles: TangemPayFeatureToggles
|
||||
|
||||
internal val viewModel: MainViewModel by viewModels()
|
||||
private val viewModel: MainViewModel by viewModels()
|
||||
|
||||
private lateinit var appThemeModeFlow: SharedFlow<AppThemeMode>
|
||||
|
||||
|
|
@ -256,6 +237,10 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
if (BuildConfig.TESTER_MENU_ENABLED) {
|
||||
lifecycle.addObserver(testerMenuLauncher.launchOnKeyEventObserver)
|
||||
}
|
||||
|
||||
if (intent != null) {
|
||||
handleDeepLink(intent = intent, isFromOnNewIntent = false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setRootContent() {
|
||||
|
|
@ -265,6 +250,7 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
val routingComponent = routingComponentFactory.create(
|
||||
context = rootComponentContext,
|
||||
initialStack = appRouterConfig.stack,
|
||||
launchMode = backgroundScanIntentHandler.getInitScreenLaunchMode(intent),
|
||||
)
|
||||
|
||||
setContent {
|
||||
|
|
@ -286,14 +272,12 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
coroutineScope = mainScope,
|
||||
userWalletsListRepository = userWalletsListRepository,
|
||||
hotWalletFeatureToggles = hotWalletFeatureToggles,
|
||||
clearAllHotWalletContextualUnlockUseCase = clearAllHotWalletContextualUnlockUseCase,
|
||||
)
|
||||
|
||||
initIntentHandlers()
|
||||
|
||||
store.dispatch(
|
||||
DaggerGraphAction.SetActivityDependencies(
|
||||
scanCardUseCase = scanCardUseCase,
|
||||
walletConnectInteractor = walletConnectInteractor,
|
||||
cardSdkConfigRepository = cardSdkConfigRepository,
|
||||
),
|
||||
)
|
||||
|
|
@ -347,18 +331,12 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
dialogManager.onStart(this)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
navigateToInitialScreenIfNeeded(intent)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
dialogManager.onStop()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
intentProcessor.removeAll()
|
||||
// workaround: kill process when activity destroy to avoid state when lock() wallets
|
||||
// and navigation to unlock screen was skipped because system kills activity but not process
|
||||
if (BuildConfig.BUILD_TYPE != MOCKED_BUILD_TYPE) {
|
||||
|
|
@ -367,14 +345,6 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun initIntentHandlers() {
|
||||
intentProcessor.addHandler(onPushClickedIntentHandler)
|
||||
|
||||
if (!walletConnectFeatureToggles.isRedesignedWalletConnectEnabled) {
|
||||
intentProcessor.addHandler(walletConnectLinkIntentHandler)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateAppTheme(appThemeMode: AppThemeMode) {
|
||||
val mode = when (appThemeMode) {
|
||||
AppThemeMode.FORCE_DARK -> AppCompatDelegate.MODE_NIGHT_YES
|
||||
|
|
@ -400,8 +370,9 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
|
||||
lifecycleScope.launch {
|
||||
intentProcessor.handleIntent(intent = intent, isFromForeground = true)
|
||||
val fromPush = intent?.extras?.containsKey(OPENED_FROM_GCM_PUSH) ?: false
|
||||
if (fromPush) {
|
||||
analyticsEventsHandler.send(Push.PushNotificationOpened)
|
||||
}
|
||||
|
||||
if (intent != null) {
|
||||
|
|
@ -443,131 +414,6 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
}
|
||||
}
|
||||
|
||||
private fun navigateToInitialScreenIfNeeded(intentWhichStartedActivity: Intent?) {
|
||||
// TODO refactor this method to return a route instead of navigating directly
|
||||
if (hotWalletFeatureToggles.isHotWalletEnabled) {
|
||||
navigateToInitialScreenIfNeededNew(intentWhichStartedActivity)
|
||||
return
|
||||
}
|
||||
|
||||
val backStack = appRouterConfig.stack ?: emptyList()
|
||||
// TODO move inital navigation to navigation component ([REDACTED_JIRA])
|
||||
val isOnlyInitialRoute = backStack.all { it is AppRoute.Initial }
|
||||
val isOnInitialScreen = backStack.all { it is AppRoute.Welcome || it is AppRoute.Home }
|
||||
val isNotScannedBefore = store.state.globalState.scanResponse == null
|
||||
val isOnboardingServiceNotActive = !store.state.globalState.onboardingState.onboardingStarted
|
||||
|
||||
when {
|
||||
!isOnInitialScreen && isNotScannedBefore && isOnboardingServiceNotActive -> {
|
||||
navigateToInitialScreen(intentWhichStartedActivity)
|
||||
}
|
||||
backStack.isEmpty() -> {
|
||||
navigateToInitialScreen(intentWhichStartedActivity)
|
||||
}
|
||||
isOnlyInitialRoute -> navigateToInitialScreen(intentWhichStartedActivity)
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Refactor this method to return a route instead of navigating directly")
|
||||
private fun navigateToInitialScreenIfNeededNew(intentWhichStartedActivity: Intent?) {
|
||||
lifecycleScope.launch {
|
||||
val userWallets = userWalletsListRepository.userWalletsSync()
|
||||
val launchMode = backgroundScanIntentHandler.getInitScreenLaunchMode(intentWhichStartedActivity)
|
||||
if (userWallets.isEmpty()) {
|
||||
val shouldShowTos = !cardRepository.isTangemTOSAccepted()
|
||||
|
||||
val route = if (shouldShowTos) {
|
||||
AppRoute.Disclaimer(isTosAccepted = false)
|
||||
} else {
|
||||
AppRoute.Home(launchMode = launchMode)
|
||||
}
|
||||
|
||||
store.dispatchNavigationAction { replaceAll(route) }
|
||||
intentProcessor.handleIntent(
|
||||
intent = intentWhichStartedActivity,
|
||||
isFromForeground = false,
|
||||
skipNavigationHandlers = false,
|
||||
)
|
||||
} else {
|
||||
if (userWallets.any { it.isLocked }) {
|
||||
store.dispatchNavigationAction {
|
||||
replaceAll(
|
||||
AppRoute.Welcome(
|
||||
launchMode = launchMode,
|
||||
intent = intentWhichStartedActivity?.let(::SerializableIntent),
|
||||
),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
store.dispatchNavigationAction {
|
||||
replaceAll(AppRoute.Wallet)
|
||||
}
|
||||
}
|
||||
|
||||
intentProcessor.handleIntent(
|
||||
intent = intentWhichStartedActivity,
|
||||
isFromForeground = false,
|
||||
skipNavigationHandlers = true,
|
||||
)
|
||||
}
|
||||
|
||||
if (intent != null) {
|
||||
handleDeepLink(intent = intent, isFromOnNewIntent = false)
|
||||
}
|
||||
|
||||
viewModel.checkForUnfinishedBackup()
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateToInitialScreen(intentWhichStartedActivity: Intent?) {
|
||||
val launchMode = backgroundScanIntentHandler.getInitScreenLaunchMode(intentWhichStartedActivity)
|
||||
|
||||
// Workaround to navigate to TangemPayDetails screen. Will be deleted in next PRs
|
||||
if (tangemPayFeatureToggles.isTangemPayEnabled) {
|
||||
store.dispatchNavigationAction {
|
||||
replaceAll(AppRoute.TangemPayDetails)
|
||||
}
|
||||
} else if (userWalletsListManager.isLockable && userWalletsListManager.hasUserWallets) {
|
||||
store.dispatchNavigationAction {
|
||||
replaceAll(
|
||||
AppRoute.Welcome(
|
||||
launchMode = launchMode,
|
||||
intent = intentWhichStartedActivity?.let(::SerializableIntent),
|
||||
),
|
||||
)
|
||||
}
|
||||
intentProcessor.handleIntent(
|
||||
intent = intentWhichStartedActivity,
|
||||
isFromForeground = false,
|
||||
skipNavigationHandlers = true,
|
||||
)
|
||||
} else {
|
||||
lifecycleScope.launch {
|
||||
val shouldShowTos = !cardRepository.isTangemTOSAccepted()
|
||||
|
||||
val route = if (shouldShowTos) {
|
||||
AppRoute.Disclaimer(isTosAccepted = false)
|
||||
} else {
|
||||
AppRoute.Home(launchMode = launchMode)
|
||||
}
|
||||
|
||||
store.dispatchNavigationAction { replaceAll(route) }
|
||||
intentProcessor.handleIntent(
|
||||
intent = intentWhichStartedActivity,
|
||||
isFromForeground = false,
|
||||
skipNavigationHandlers = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (intent != null) {
|
||||
handleDeepLink(intent = intent, isFromOnNewIntent = false)
|
||||
}
|
||||
|
||||
viewModel.checkForUnfinishedBackup()
|
||||
}
|
||||
|
||||
private fun handleDeepLink(intent: Intent, isFromOnNewIntent: Boolean) {
|
||||
val deepLinkExtras = PayloadToDeeplinkConverter.convertBundle(intent.extras)?.toUri()
|
||||
val webLink = intent.getStringExtra(WEBLINK_KEY)
|
||||
|
|
@ -636,5 +482,6 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
companion object {
|
||||
private const val APP_THEME_LOAD_TIMEOUT = 2
|
||||
private const val MOCKED_BUILD_TYPE = "mocked"
|
||||
private const val OPENED_FROM_GCM_PUSH = "google.sent_time" // every bundle from FCM contains this key
|
||||
}
|
||||
}
|
||||
|
|
@ -47,7 +47,7 @@ import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
|||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.common.LogConfig
|
||||
import com.tangem.domain.feedback.GetCardInfoUseCase
|
||||
import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase
|
||||
import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase
|
||||
|
|
@ -63,6 +63,7 @@ import com.tangem.tap.common.analytics.AnalyticsFactory
|
|||
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
|
||||
import com.tangem.tap.common.analytics.handlers.BlockchainExceptionHandler
|
||||
import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.handlers.appsflyer.AppsFlyerAnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler
|
||||
import com.tangem.tap.common.images.createCoilImageLoader
|
||||
import com.tangem.tap.common.log.TangemAppLoggerInitializer
|
||||
|
|
@ -75,9 +76,12 @@ import com.tangem.tap.proxy.redux.DaggerGraphState
|
|||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.wallet.BuildConfig
|
||||
import dagger.hilt.EntryPoints
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.rekotlin.Store
|
||||
import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository as WalletConnect2Repository
|
||||
import timber.log.Timber
|
||||
|
||||
lateinit var store: Store<AppState>
|
||||
|
||||
|
|
@ -111,9 +115,6 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
|||
private val cardScanningFeatureToggles: CardScanningFeatureToggles
|
||||
get() = entryPoint.getCardScanningFeatureToggles()
|
||||
|
||||
private val walletConnect2Repository: WalletConnect2Repository
|
||||
get() = entryPoint.getWalletConnect2Repository()
|
||||
|
||||
private val scanCardProcessor: ScanCardProcessor
|
||||
get() = entryPoint.getScanCardProcessor()
|
||||
|
||||
|
|
@ -165,8 +166,8 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
|||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase
|
||||
get() = entryPoint.getSendFeedbackEmailUseCase()
|
||||
|
||||
private val getCardInfoUseCase: GetCardInfoUseCase
|
||||
get() = entryPoint.getGetCardInfoUseCase()
|
||||
private val getWalletMetaInfoUseCase: GetWalletMetaInfoUseCase
|
||||
get() = entryPoint.getWalletMetaInfoUseCase()
|
||||
|
||||
private val urlOpener
|
||||
get() = entryPoint.getUrlOpener()
|
||||
|
|
@ -236,6 +237,9 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
|||
private val hotWalletFeatureToggles
|
||||
get() = entryPoint.getHotWalletFeatureToggles()
|
||||
|
||||
private val wcInitializeUseCase
|
||||
get() = entryPoint.getWcInitializeUseCase()
|
||||
|
||||
// endregion
|
||||
|
||||
private val appScope = MainScope()
|
||||
|
|
@ -289,15 +293,16 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
|||
|
||||
tangemAppLoggerInitializer.initialize()
|
||||
|
||||
Timber.i("APP STARTED")
|
||||
if (BuildConfig.TESTER_MENU_ENABLED) {
|
||||
Timber.i(featureTogglesManager.toString())
|
||||
Timber.i(excludedBlockchainsManager.toString())
|
||||
}
|
||||
|
||||
foregroundActivityObserver = ForegroundActivityObserver()
|
||||
registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks)
|
||||
|
||||
// We need to initialize the toggles and excludedBlockchainsManager before the MainActivity starts using them.
|
||||
runBlocking {
|
||||
awaitAll(
|
||||
async { featureTogglesManager.init() },
|
||||
async { excludedBlockchainsManager.init() },
|
||||
)
|
||||
initWithConfigDependency(environmentConfig = environmentConfigStorage.initialize())
|
||||
}
|
||||
|
||||
|
|
@ -329,7 +334,8 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
|||
)
|
||||
|
||||
appStateHolder.mainStore = store
|
||||
walletConnect2Repository.init(
|
||||
|
||||
wcInitializeUseCase.init(
|
||||
projectId = environmentConfigStorage.getConfigSync().walletConnectProjectId,
|
||||
)
|
||||
}
|
||||
|
|
@ -342,7 +348,6 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
|||
daggerGraphState = DaggerGraphState(
|
||||
networkConnectionManager = networkConnectionManager,
|
||||
cardScanningFeatureToggles = cardScanningFeatureToggles,
|
||||
walletConnectRepository = walletConnect2Repository,
|
||||
scanCardProcessor = scanCardProcessor,
|
||||
appCurrencyRepository = appCurrencyRepository,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
|
|
@ -357,7 +362,7 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
|||
settingsRepository = settingsRepository,
|
||||
blockchainSDKFactory = blockchainSDKFactory,
|
||||
sendFeedbackEmailUseCase = sendFeedbackEmailUseCase,
|
||||
getCardInfoUseCase = getCardInfoUseCase,
|
||||
getWalletMetaInfoUseCase = getWalletMetaInfoUseCase,
|
||||
issuersConfigStorage = issuersConfigStorage,
|
||||
urlOpener = urlOpener,
|
||||
shareManager = shareManager,
|
||||
|
|
@ -401,6 +406,7 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
|||
val factory = AnalyticsFactory()
|
||||
factory.addHandlerBuilder(AmplitudeAnalyticsHandler.Builder())
|
||||
factory.addHandlerBuilder(FirebaseAnalyticsHandler.Builder())
|
||||
factory.addHandlerBuilder(AppsFlyerAnalyticsHandler.Builder())
|
||||
|
||||
factory.addFilter(oneTimeEventFilter)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@ import android.content.Context
|
|||
import com.tangem.domain.redux.StateDialog
|
||||
import com.tangem.tap.common.redux.AppDialog
|
||||
import com.tangem.tap.common.redux.global.GlobalState
|
||||
import com.tangem.tap.common.ui.*
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectDialog
|
||||
import com.tangem.tap.features.details.ui.walletconnect.dialogs.*
|
||||
import com.tangem.tap.common.ui.ScanFailsDialog
|
||||
import com.tangem.tap.common.ui.SimpleAlertDialog
|
||||
import com.tangem.tap.common.ui.SimpleCancelableAlertDialog
|
||||
import com.tangem.tap.common.ui.SimpleOkDialog
|
||||
import com.tangem.tap.features.onboarding.OnboardingDialog
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupDialog
|
||||
import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.ConfirmDiscardingBackupDialog
|
||||
|
|
@ -59,88 +60,6 @@ class DialogManager : StoreSubscriber<GlobalState> {
|
|||
context = context,
|
||||
)
|
||||
is OnboardingDialog.WalletActivationError -> WalletActivationErrorDialog.create(context, state.dialog)
|
||||
is WalletConnectDialog.UnsupportedCard ->
|
||||
SimpleAlertDialog.create(
|
||||
titleRes = R.string.wallet_connect_title,
|
||||
messageRes = R.string.wallet_connect_scanner_error_not_valid_card,
|
||||
context = context,
|
||||
)
|
||||
is WalletConnectDialog.AddNetwork -> {
|
||||
val message = context.getString(
|
||||
R.string.wallet_connect_error_missing_blockchains,
|
||||
) + state.dialog.networks.joinToString()
|
||||
SimpleAlertDialog.create(
|
||||
titleRes = R.string.wallet_connect_title,
|
||||
message = message,
|
||||
context = context,
|
||||
)
|
||||
}
|
||||
is WalletConnectDialog.OpeningSessionRejected -> {
|
||||
SimpleAlertDialog.create(
|
||||
titleRes = R.string.wallet_connect_title,
|
||||
messageRes = R.string.wallet_connect_same_wcuri,
|
||||
context = context,
|
||||
)
|
||||
}
|
||||
is WalletConnectDialog.SessionTimeout -> {
|
||||
SimpleAlertDialog.create(
|
||||
titleRes = R.string.wallet_connect_title,
|
||||
messageRes = R.string.wallet_connect_error_timeout,
|
||||
context = context,
|
||||
)
|
||||
}
|
||||
is WalletConnectDialog.RequestTransaction -> TransactionDialog.create(state.dialog.data, context)
|
||||
is WalletConnectDialog.PersonalSign -> PersonalSignDialog.create(state.dialog.data, context)
|
||||
is WalletConnectDialog.BnbTransactionDialog ->
|
||||
BnbTransactionDialog.create(
|
||||
preparedData = state.dialog.data,
|
||||
context = context,
|
||||
)
|
||||
is WalletConnectDialog.UnsupportedNetwork -> {
|
||||
val warning = if (state.dialog.networks.isNullOrEmpty()) {
|
||||
context.getString(R.string.wallet_connect_scanner_error_unsupported_network)
|
||||
} else {
|
||||
context.getString(R.string.wallet_connect_error_unsupported_blockchains) +
|
||||
state.dialog.networks.joinToString()
|
||||
}
|
||||
SimpleAlertDialog.create(
|
||||
titleRes = R.string.wallet_connect_title,
|
||||
message = warning,
|
||||
context = context,
|
||||
)
|
||||
}
|
||||
is WalletConnectDialog.UnsupportedDapp -> SimpleAlertDialog.create(
|
||||
titleRes = R.string.wallet_connect_title,
|
||||
messageRes = R.string.wallet_connect_error_unsupported_dapp,
|
||||
context = context,
|
||||
)
|
||||
is WalletConnectDialog.SessionProposalDialog -> {
|
||||
SessionProposalDialog.create(
|
||||
sessionProposal = state.dialog.sessionProposal,
|
||||
networks = state.dialog.networks,
|
||||
context = context,
|
||||
onApprove = state.dialog.onApprove,
|
||||
onReject = state.dialog.onReject,
|
||||
)
|
||||
}
|
||||
is WalletConnectDialog.SignTransactionDialog -> SignTransactionDialog.create(
|
||||
preparedData = state.dialog.data,
|
||||
context = context,
|
||||
)
|
||||
is WalletConnectDialog.SignTransactionsDialog -> SignTransactionsDialog.create(
|
||||
preparedData = state.dialog.data,
|
||||
context = context,
|
||||
)
|
||||
is WalletConnectDialog.PairConnectErrorDialog -> SimpleAlertDialog.create(
|
||||
titleRes = R.string.wallet_connect_title,
|
||||
message = state.dialog.error.message,
|
||||
context = context,
|
||||
)
|
||||
is WalletConnectDialog.UnsupportedWcVersion -> SimpleAlertDialog.create(
|
||||
titleRes = R.string.common_error,
|
||||
messageRes = R.string.unsupported_wc_version,
|
||||
context = context,
|
||||
)
|
||||
is BackupDialog.UnfinishedBackupFound -> UnfinishedBackupFoundDialog.create(
|
||||
context = context,
|
||||
scanResponse = state.dialog.scanResponse,
|
||||
|
|
|
|||
|
|
@ -1,120 +0,0 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction.OpenSession.SourceType
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal sealed class WalletConnect(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent("Wallet Connect", event, params) {
|
||||
|
||||
class ScreenOpened : WalletConnect(event = "WC Screen Opened")
|
||||
class NewSessionInitiated(source: SourceType) : WalletConnect(
|
||||
event = "Session Initiated",
|
||||
params = mapOf(
|
||||
AnalyticsParam.SOURCE to when (source) {
|
||||
SourceType.QR -> "QR"
|
||||
SourceType.DEEPLINK -> "DeepLink"
|
||||
SourceType.CLIPBOARD -> "Clipboard"
|
||||
SourceType.ETC -> "etc"
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
data object SessionFailed : WalletConnect(
|
||||
event = "Session Failed",
|
||||
)
|
||||
|
||||
class DAppConnectionRequested(
|
||||
blockchainNames: List<String>,
|
||||
) : WalletConnect(
|
||||
event = "dApp Connection Requested",
|
||||
params = mapOf(
|
||||
AnalyticsParam.NETWORKS to blockchainNames.joinToString(","),
|
||||
),
|
||||
)
|
||||
|
||||
class DAppConnected(dAppName: String, dAppUrl: String, blockchainNames: List<String>) : WalletConnect(
|
||||
event = "dApp Connected",
|
||||
params = mapOf(
|
||||
AnalyticsParam.DAPP_NAME to dAppName,
|
||||
AnalyticsParam.DAPP_URL to dAppUrl,
|
||||
AnalyticsParam.BLOCKCHAIN to blockchainNames.joinToString(","),
|
||||
),
|
||||
)
|
||||
|
||||
class DAppConnectionFailed(dAppName: String, dAppUrl: String, blockchainNames: List<String>) : WalletConnect(
|
||||
event = "dApp Connection Failed",
|
||||
params = mapOf(
|
||||
AnalyticsParam.DAPP_NAME to dAppName,
|
||||
AnalyticsParam.DAPP_URL to dAppUrl,
|
||||
AnalyticsParam.BLOCKCHAIN to blockchainNames.joinToString(","),
|
||||
),
|
||||
)
|
||||
|
||||
class SessionDisconnected(dAppName: String, dAppUrl: String) : WalletConnect(
|
||||
event = "dApp Disconnected",
|
||||
params = mapOf(
|
||||
AnalyticsParam.DAPP_NAME to dAppName,
|
||||
AnalyticsParam.DAPP_URL to dAppUrl,
|
||||
),
|
||||
)
|
||||
|
||||
class SignatureRequestHandled(
|
||||
params: RequestHandledParams,
|
||||
) : WalletConnect(
|
||||
event = "Signature Request Handled",
|
||||
params = params.toParamsMap(),
|
||||
)
|
||||
|
||||
class SignatureRequestReceived(
|
||||
params: RequestHandledParams,
|
||||
) : WalletConnect(
|
||||
event = "Signature Request Received",
|
||||
params = params.toParamsMap(),
|
||||
)
|
||||
|
||||
class SignatureRequestFailed(
|
||||
params: RequestHandledParams,
|
||||
) : WalletConnect(
|
||||
event = "Signature Request Failed",
|
||||
params = params.toParamsMap(),
|
||||
)
|
||||
|
||||
data class RequestHandledParams(
|
||||
val dAppName: String,
|
||||
val dAppUrl: String,
|
||||
val methodName: String,
|
||||
val blockchain: String,
|
||||
val errorCode: String? = null,
|
||||
val errorDescription: String? = null,
|
||||
) {
|
||||
fun toParamsMap(): Map<String, String> {
|
||||
val validation = if (errorCode == null) Validation.SUCCESS.param else Validation.FAIL.param
|
||||
val code = errorCode ?: SUCCESS_CODE
|
||||
return buildMap {
|
||||
put(AnalyticsParam.DAPP_NAME, dAppName)
|
||||
put(AnalyticsParam.DAPP_URL, dAppUrl)
|
||||
put(AnalyticsParam.METHOD_NAME, methodName)
|
||||
put(AnalyticsParam.BLOCKCHAIN, blockchain)
|
||||
put(AnalyticsParam.VALIDATION, validation)
|
||||
put(AnalyticsParam.ERROR_CODE, code)
|
||||
if (errorDescription != null) {
|
||||
put(AnalyticsParam.ERROR_DESCRIPTION, errorDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class Validation(val param: String) {
|
||||
SUCCESS("Success"),
|
||||
FAIL("Fail"),
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val SUCCESS_CODE = "0"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.tap.common.analytics.handlers.appsflyer
|
||||
|
||||
import android.content.Context
|
||||
import com.appsflyer.AppsFlyerLib
|
||||
import com.tangem.core.analytics.api.EventLogger
|
||||
|
||||
interface AppsFlyerAnalyticsClient : EventLogger
|
||||
|
||||
internal class AppsFlyerClient(
|
||||
private val context: Context,
|
||||
key: String,
|
||||
appId: String,
|
||||
) : AppsFlyerAnalyticsClient {
|
||||
|
||||
private val appsFlyerLib: AppsFlyerLib = AppsFlyerLib.getInstance()
|
||||
|
||||
init {
|
||||
appsFlyerLib.init(key, null, context)
|
||||
appsFlyerLib.setAppId(appId)
|
||||
appsFlyerLib.start(context)
|
||||
}
|
||||
|
||||
override fun logEvent(event: String, params: Map<String, String>) {
|
||||
appsFlyerLib.logEvent(context, event, params)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.tangem.tap.common.analytics.handlers.appsflyer
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
|
||||
|
||||
class AppsFlyerAnalyticsHandler(
|
||||
private val client: AppsFlyerAnalyticsClient,
|
||||
) : AnalyticsHandler {
|
||||
|
||||
override fun id(): String = ID
|
||||
|
||||
override fun send(eventId: String, params: Map<String, String>) {
|
||||
client.logEvent(eventId, params)
|
||||
}
|
||||
|
||||
override fun send(event: AnalyticsEvent) {
|
||||
super.send(event)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ID = "AppsFlyer"
|
||||
}
|
||||
|
||||
class Builder : AnalyticsHandlerBuilder {
|
||||
override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsHandler? = when {
|
||||
!data.isDebug -> AppsFlyerClient(data.application, data.config.appsFlyerApiKey, data.config.appsAppId)
|
||||
data.isDebug && data.logConfig.appsflyer -> AppsFlyerLogClient(data.jsonConverter)
|
||||
else -> null
|
||||
}?.let { AppsFlyerAnalyticsHandler(it) }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.tangem.tap.common.analytics.handlers.appsflyer
|
||||
|
||||
import com.tangem.common.json.MoshiJsonConverter
|
||||
import com.tangem.tap.common.analytics.AnalyticsEventsLogger
|
||||
|
||||
internal class AppsFlyerLogClient(
|
||||
jsonConverter: MoshiJsonConverter,
|
||||
) : AppsFlyerAnalyticsClient {
|
||||
|
||||
private val logger = AnalyticsEventsLogger(AppsFlyerAnalyticsHandler.ID, jsonConverter)
|
||||
|
||||
override fun logEvent(event: String, params: Map<String, String>) {
|
||||
logger.logEvent(event, params)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.tap.common.buildconfig
|
||||
|
||||
import com.tangem.utils.buildConfig.AppConfigurationProvider
|
||||
import com.tangem.wallet.BuildConfig
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
internal class AppConfigurationProviderImpl @Inject constructor() : AppConfigurationProvider {
|
||||
|
||||
override fun isDebug(): Boolean = BuildConfig.BUILD_TYPE == "debug"
|
||||
override fun isHuawei(): Boolean = BuildConfig.FLAVOR_NAME == "huawei"
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
package com.tangem.tap.common.pushes
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import coil.executeBlocking
|
||||
import coil.request.ImageRequest
|
||||
import com.tangem.domain.common.LogConfig
|
||||
import com.tangem.tap.MainActivity
|
||||
import com.tangem.tap.common.images.createCoilImageLoader
|
||||
import com.tangem.wallet.R
|
||||
|
||||
class PushNotificationDelegate(private val context: Context) {
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
fun showNotification(
|
||||
dataMap: Map<String, String>,
|
||||
title: String?,
|
||||
body: String?,
|
||||
channelId: String,
|
||||
priority: Int,
|
||||
imageUrl: Uri? = null,
|
||||
vibratePattern: LongArray?,
|
||||
) {
|
||||
val intent = Intent(context, MainActivity::class.java).apply {
|
||||
dataMap.forEach { (key, value) ->
|
||||
putExtra(key, value)
|
||||
}
|
||||
putExtra(OPENED_FROM_GCM_PUSH, true)
|
||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
}
|
||||
|
||||
val pendingIntent = PendingIntent.getActivity(
|
||||
/* context = */ context,
|
||||
/* requestCode = */ PUSH_NOTIFICATION_REQUEST_CODE,
|
||||
/* intent = */ intent,
|
||||
/* flags = */ PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE,
|
||||
)
|
||||
|
||||
val notificationBuilder = NotificationCompat.Builder(context, channelId)
|
||||
.setSmallIcon(R.drawable.ic_tangem_24)
|
||||
.setContentTitle(title)
|
||||
.setContentText(body)
|
||||
.setPriority(priority)
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setVibrate(vibratePattern)
|
||||
.apply {
|
||||
imageUrl?.let { uri ->
|
||||
val bitmap = getBitmapImageFromUrl(uri)
|
||||
setStyle(
|
||||
NotificationCompat
|
||||
.BigPictureStyle()
|
||||
.bigPicture(bitmap),
|
||||
).setLargeIcon(bitmap)
|
||||
}
|
||||
}
|
||||
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val notificationChannel = NotificationChannel(
|
||||
channelId,
|
||||
ContextCompat.getString(context, R.string.tangem_app_name),
|
||||
NotificationManager.IMPORTANCE_HIGH,
|
||||
)
|
||||
notificationManager.createNotificationChannel(notificationChannel)
|
||||
}
|
||||
|
||||
// Generating unique notification id
|
||||
val uniqueId = (System.currentTimeMillis() % Integer.MAX_VALUE).toInt()
|
||||
|
||||
notificationManager.notify(
|
||||
/* id = */ uniqueId,
|
||||
/* notification = */ notificationBuilder.build(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getBitmapImageFromUrl(url: Uri): Bitmap? {
|
||||
return createCoilImageLoader(
|
||||
context,
|
||||
logEnabled = LogConfig.imageLoader,
|
||||
).executeBlocking(
|
||||
ImageRequest.Builder(context)
|
||||
.data(url)
|
||||
.build(),
|
||||
).drawable?.toBitmap()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val PUSH_NOTIFICATION_REQUEST_CODE = 123
|
||||
private const val OPENED_FROM_GCM_PUSH = "google.sent_time" // every bundle from FCM contains this key
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +1,17 @@
|
|||
package com.tangem.tap.common.pushes
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import coil.executeBlocking
|
||||
import coil.request.ImageRequest
|
||||
import com.google.firebase.messaging.FirebaseMessagingService
|
||||
import com.google.firebase.messaging.RemoteMessage
|
||||
import com.tangem.domain.common.LogConfig
|
||||
import com.tangem.tap.MainActivity
|
||||
import com.tangem.tap.common.images.createCoilImageLoader
|
||||
import com.tangem.tap.features.intentHandler.handlers.OnPushClickedIntentHandler
|
||||
import com.tangem.wallet.R
|
||||
import timber.log.Timber
|
||||
|
||||
@SuppressLint("MissingFirebaseInstanceTokenRefresh")
|
||||
internal class TangemPushNotificationService : FirebaseMessagingService() {
|
||||
|
||||
private val pushNotificationDelegate: PushNotificationDelegate by lazy {
|
||||
PushNotificationDelegate(applicationContext)
|
||||
}
|
||||
|
||||
override fun onNewToken(token: String) {
|
||||
super.onNewToken(token)
|
||||
Timber.d("New FCM token received: $token")
|
||||
|
|
@ -36,73 +23,18 @@ internal class TangemPushNotificationService : FirebaseMessagingService() {
|
|||
val notification = message.notification ?: return
|
||||
val channelId = notification.channelId ?: TANGEM_CHANNEL_ID
|
||||
|
||||
val intent = Intent(applicationContext, MainActivity::class.java).apply {
|
||||
message.data.forEach {
|
||||
putExtra(it.key, it.value)
|
||||
}
|
||||
putExtra(OnPushClickedIntentHandler.OPENED_FROM_GCM_PUSH, true)
|
||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
}
|
||||
val pendingIntent = PendingIntent.getActivity(
|
||||
/* context = */ this,
|
||||
/* requestCode = */ PUSH_NOTIFICATION_REQUEST_CODE,
|
||||
/* intent = */ intent,
|
||||
/* flags = */ PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE,
|
||||
pushNotificationDelegate.showNotification(
|
||||
dataMap = message.data,
|
||||
title = notification.title,
|
||||
body = notification.body,
|
||||
channelId = channelId,
|
||||
priority = message.priority,
|
||||
imageUrl = notification.imageUrl,
|
||||
vibratePattern = notification.vibrateTimings,
|
||||
)
|
||||
|
||||
val notificationBuilder =
|
||||
NotificationCompat.Builder(applicationContext, channelId)
|
||||
.setSmallIcon(R.drawable.ic_tangem_24)
|
||||
.setContentTitle(notification.title)
|
||||
.setContentText(notification.body)
|
||||
.setPriority(message.priority)
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setVibrate(notification.vibrateTimings)
|
||||
.apply {
|
||||
notification.imageUrl?.let { uri ->
|
||||
val bitmap = getBitmapImageFromUrl(uri)
|
||||
setStyle(
|
||||
NotificationCompat
|
||||
.BigPictureStyle()
|
||||
.bigPicture(bitmap),
|
||||
).setLargeIcon(bitmap)
|
||||
}
|
||||
}
|
||||
|
||||
val notificationManager = applicationContext.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val notificationChannel = NotificationChannel(
|
||||
channelId,
|
||||
ContextCompat.getString(applicationContext, R.string.tangem_app_name),
|
||||
NotificationManager.IMPORTANCE_HIGH,
|
||||
)
|
||||
notificationManager.createNotificationChannel(notificationChannel)
|
||||
}
|
||||
|
||||
// Generating unique notification id
|
||||
val uniqueId = (System.currentTimeMillis() % Integer.MAX_VALUE).toInt()
|
||||
|
||||
notificationManager.notify(
|
||||
/* id = */ uniqueId,
|
||||
/* notification = */ notificationBuilder.build(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getBitmapImageFromUrl(url: Uri): Bitmap? {
|
||||
return createCoilImageLoader(
|
||||
applicationContext,
|
||||
logEnabled = LogConfig.imageLoader,
|
||||
).executeBlocking(
|
||||
ImageRequest.Builder(applicationContext)
|
||||
.data(url)
|
||||
.build(),
|
||||
).drawable?.toBitmap()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val TANGEM_CHANNEL_ID = "Tangem General" // General channel for notifications
|
||||
const val PUSH_NOTIFICATION_REQUEST_CODE = 123
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ package com.tangem.tap.common.redux
|
|||
|
||||
import com.tangem.tap.common.redux.global.globalReducer
|
||||
import com.tangem.tap.features.details.redux.DetailsReducer
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectReducer
|
||||
import com.tangem.tap.features.welcome.redux.WelcomeReducer
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphReducer
|
||||
import org.rekotlin.Action
|
||||
|
|
@ -14,7 +13,6 @@ fun appReducer(action: Action, state: AppState?): AppState {
|
|||
return AppState(
|
||||
globalState = globalReducer(action, state),
|
||||
detailsState = DetailsReducer.reduce(action, state),
|
||||
walletConnectState = WalletConnectReducer.reduce(action, state.walletConnectState),
|
||||
welcomeState = WelcomeReducer.reduce(action, state),
|
||||
daggerGraphState = DaggerGraphReducer.reduce(action, state),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ import com.tangem.tap.common.redux.global.GlobalState
|
|||
import com.tangem.tap.common.redux.legacy.LegacyMiddleware
|
||||
import com.tangem.tap.features.details.redux.DetailsMiddleware
|
||||
import com.tangem.tap.features.details.redux.DetailsState
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectMiddleware
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectState
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupMiddleware
|
||||
import com.tangem.tap.features.wallet.redux.middlewares.TradeCryptoMiddleware
|
||||
import com.tangem.tap.features.welcome.redux.WelcomeMiddleware
|
||||
|
|
@ -19,7 +17,6 @@ import org.rekotlin.StateType
|
|||
data class AppState(
|
||||
val globalState: GlobalState = GlobalState(),
|
||||
val detailsState: DetailsState = DetailsState(),
|
||||
val walletConnectState: WalletConnectState = WalletConnectState(),
|
||||
val welcomeState: WelcomeState = WelcomeState(),
|
||||
val daggerGraphState: DaggerGraphState = DaggerGraphState(),
|
||||
) : StateType {
|
||||
|
|
@ -30,7 +27,6 @@ data class AppState(
|
|||
logMiddleware,
|
||||
GlobalMiddleware.handler,
|
||||
DetailsMiddleware().detailsMiddleware,
|
||||
WalletConnectMiddleware().walletConnectMiddleware,
|
||||
BackupMiddleware().backupMiddleware,
|
||||
WelcomeMiddleware().middleware,
|
||||
LockUserWalletsTimerMiddleware().middleware,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
package com.tangem.tap.data
|
||||
|
||||
import android.content.Context
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||
import com.tangem.datasource.local.visa.TangemPayStorage
|
||||
import com.tangem.domain.visa.model.VisaAuthTokens
|
||||
import com.tangem.sdk.storage.AndroidSecureStorageV2
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.text.encodeToByteArray
|
||||
|
||||
private const val DEFAULT_KEY = "tangem_pay_default_key"
|
||||
private const val DEFAULT_CUSTOMER_WALLET_ADDRESS_KEY = "tangem_pay_default_customer_wallet_address_key"
|
||||
|
||||
@Singleton
|
||||
internal class DefaultTangemPayStorage @Inject constructor(
|
||||
@ApplicationContext applicationContext: Context,
|
||||
private val dispatcherProvider: CoroutineDispatcherProvider,
|
||||
) : TangemPayStorage {
|
||||
|
||||
private val secureStorage by lazy {
|
||||
AndroidSecureStorageV2(
|
||||
appContext = applicationContext,
|
||||
useStrongBox = false,
|
||||
name = "tangem_pay_storage",
|
||||
)
|
||||
}
|
||||
private val moshi by lazy {
|
||||
Moshi.Builder()
|
||||
.add(KotlinJsonAdapterFactory())
|
||||
.build()
|
||||
}
|
||||
|
||||
private val tokensAdapter by lazy { moshi.adapter(VisaAuthTokens::class.java) }
|
||||
|
||||
override suspend fun storeAuthTokens(customerWalletAddress: String, tokens: VisaAuthTokens) =
|
||||
withContext(dispatcherProvider.io) {
|
||||
val json = tokensAdapter.toJson(tokens)
|
||||
|
||||
secureStorage.store(
|
||||
json.encodeToByteArray(throwOnInvalidSequence = true),
|
||||
createKey(customerWalletAddress),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getAuthTokens(customerWalletAddress: String): VisaAuthTokens? =
|
||||
withContext(dispatcherProvider.io) {
|
||||
secureStorage.get(createKey(customerWalletAddress))
|
||||
?.decodeToString(throwOnInvalidSequence = true)
|
||||
?.let(tokensAdapter::fromJson)
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the only customer wallet address, since for the f&f user can issue only one card tied to one address
|
||||
*/
|
||||
override suspend fun storeCustomerWalletAddress(customerWalletAddress: String) =
|
||||
withContext(dispatcherProvider.io) {
|
||||
secureStorage.store(
|
||||
customerWalletAddress.encodeToByteArray(throwOnInvalidSequence = true),
|
||||
DEFAULT_CUSTOMER_WALLET_ADDRESS_KEY,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getCustomerWalletAddress(): String? = withContext(dispatcherProvider.io) {
|
||||
secureStorage.get(DEFAULT_CUSTOMER_WALLET_ADDRESS_KEY)?.decodeToString(throwOnInvalidSequence = true)
|
||||
}
|
||||
|
||||
override suspend fun clear(customerWalletAddress: String) = withContext(dispatcherProvider.io) {
|
||||
secureStorage.delete(createKey(customerWalletAddress))
|
||||
}
|
||||
|
||||
private fun createKey(cardId: String): String = "${DEFAULT_KEY}_$cardId"
|
||||
}
|
||||
|
|
@ -19,6 +19,9 @@ internal class RuntimeUserWalletsStore(
|
|||
override val userWallets: Flow<List<UserWallet>>
|
||||
get() = userWalletsListManager.userWallets
|
||||
|
||||
override val userWalletsSync: List<UserWallet>
|
||||
get() = userWalletsListManager.userWalletsSync
|
||||
|
||||
override fun getSyncOrNull(key: UserWalletId): UserWallet? {
|
||||
return userWalletsListManager.userWalletsSync.firstOrNull { it.walletId == key }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package com.tangem.tap.data
|
|||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.catching
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
|
|
@ -24,6 +24,9 @@ class UserWalletsStoreRepositoryProxy(
|
|||
}
|
||||
}
|
||||
|
||||
override val userWalletsSync: List<UserWallet>
|
||||
get() = userWalletsListRepository.userWallets.value.orEmpty()
|
||||
|
||||
override fun getSyncOrNull(key: UserWalletId): UserWallet? {
|
||||
return userWalletsListRepository.userWallets.value?.find { it.walletId == key }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.tap.di
|
||||
|
||||
import com.tangem.tap.common.buildconfig.AppConfigurationProviderImpl
|
||||
import com.tangem.utils.buildConfig.AppConfigurationProvider
|
||||
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 AppConfigurationModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindAppConfigurationProvider(impl: AppConfigurationProviderImpl): AppConfigurationProvider
|
||||
}
|
||||
|
|
@ -1,10 +1,6 @@
|
|||
package com.tangem.tap.di
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.tap.features.intentHandler.IntentProcessor
|
||||
import com.tangem.tap.features.intentHandler.handlers.BackgroundScanIntentHandler
|
||||
import com.tangem.tap.features.intentHandler.handlers.OnPushClickedIntentHandler
|
||||
import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -18,17 +14,4 @@ internal object IntentHandlingModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideBackgroundScanIntentHandler(): BackgroundScanIntentHandler = BackgroundScanIntentHandler()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideWalletConnectLinkIntentHandler(): WalletConnectLinkIntentHandler = WalletConnectLinkIntentHandler()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnPushClickedIntentHandler(analyticsEventHandler: AnalyticsEventHandler): OnPushClickedIntentHandler =
|
||||
OnPushClickedIntentHandler(analyticsEventHandler)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideIntentProcessor(): IntentProcessor = IntentProcessor()
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.tap.di.data
|
||||
|
||||
import com.tangem.datasource.local.visa.TangemPayStorage
|
||||
import com.tangem.datasource.local.visa.VisaAuthTokenStorage
|
||||
import com.tangem.datasource.local.visa.VisaOTPStorage
|
||||
import com.tangem.tap.data.DefaultTangemPayStorage
|
||||
import com.tangem.tap.data.DefaultVisaAuthTokenStorage
|
||||
import com.tangem.tap.data.DefaultVisaOTPStorage
|
||||
import dagger.Binds
|
||||
|
|
@ -21,4 +23,8 @@ internal interface VisaStorageModule {
|
|||
@Binds
|
||||
@Singleton
|
||||
fun bindVisaOTPStorage(impl: DefaultVisaOTPStorage): VisaOTPStorage
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindTangemPayStorage(impl: DefaultTangemPayStorage): TangemPayStorage
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.repository.AccountsCRUDRepository
|
||||
import com.tangem.domain.account.usecase.*
|
||||
import dagger.Module
|
||||
|
|
@ -42,6 +43,12 @@ internal object AccountDomainModule {
|
|||
return RecoverCryptoPortfolioUseCase(crudRepository = accountsCRUDRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetArchivedAccountsUseCase(accountsCRUDRepository: AccountsCRUDRepository): GetArchivedAccountsUseCase {
|
||||
return GetArchivedAccountsUseCase(crudRepository = accountsCRUDRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetUnoccupiedAccountIndexUseCase(
|
||||
|
|
@ -49,4 +56,16 @@ internal object AccountDomainModule {
|
|||
): GetUnoccupiedAccountIndexUseCase {
|
||||
return GetUnoccupiedAccountIndexUseCase(crudRepository = accountsCRUDRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideIsAccountsModeEnabledUseCase(
|
||||
accountsCRUDRepository: AccountsCRUDRepository,
|
||||
accountsFeatureToggles: AccountsFeatureToggles,
|
||||
): IsAccountsModeEnabledUseCase {
|
||||
return IsAccountsModeEnabledUseCase(
|
||||
crudRepository = accountsCRUDRepository,
|
||||
accountsFeatureToggles = accountsFeatureToggles,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import android.content.Context
|
||||
import com.tangem.domain.feedback.GetCardInfoUseCase
|
||||
import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
|
||||
import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.feedback.repository.FeedbackRepository
|
||||
|
|
@ -18,8 +18,8 @@ internal object FeedbackDomainModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetCardInfoUseCase(feedbackRepository: FeedbackRepository): GetCardInfoUseCase {
|
||||
return GetCardInfoUseCase(feedbackRepository = feedbackRepository)
|
||||
fun provideGetCardInfoUseCase(feedbackRepository: FeedbackRepository): GetWalletMetaInfoUseCase {
|
||||
return GetWalletMetaInfoUseCase(feedbackRepository = feedbackRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import com.tangem.domain.nft.repository.NFTRepository
|
|||
import com.tangem.domain.quotes.single.SingleQuoteStatusFetcher
|
||||
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.wallets.repository.WalletsRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -33,29 +32,21 @@ internal object NFTDomainModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun providesFetchNFTCollectionsUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
nftRepository: NFTRepository,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): FetchNFTCollectionsUseCase = FetchNFTCollectionsUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
nftRepository = nftRepository,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesRefreshAllNFTUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
nftRepository: NFTRepository,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): RefreshAllNFTUseCase = RefreshAllNFTUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
nftRepository = nftRepository,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
|
||||
@Provides
|
||||
|
|
@ -127,16 +118,12 @@ internal object NFTDomainModule {
|
|||
fun provideDisableWalletNFTUseCase(
|
||||
walletsRepository: WalletsRepository,
|
||||
nftRepository: NFTRepository,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): DisableWalletNFTUseCase {
|
||||
return DisableWalletNFTUseCase(
|
||||
walletsRepository = walletsRepository,
|
||||
nftRepository = nftRepository,
|
||||
currenciesRepository = currenciesRepository,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,8 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.domain.notifications.*
|
||||
import com.tangem.domain.notifications.repository.NotificationsRepository
|
||||
import com.tangem.domain.notifications.repository.PushNotificationsRepository
|
||||
import com.tangem.domain.notifications.toggles.NotificationsFeatureToggles
|
||||
import com.tangem.tap.domain.notifications.DefaultNotificationsFeatureToggles
|
||||
import com.tangem.utils.notifications.PushNotificationsTokenProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -79,12 +76,6 @@ internal object NotificationsDomainModule {
|
|||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideNotificationsFeatureToggles(featureTogglesManager: FeatureTogglesManager): NotificationsFeatureToggles {
|
||||
return DefaultNotificationsFeatureToggles(featureTogglesManager = featureTogglesManager)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetNetworksAvailableForNotifications(
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.onramp.repositories.LegacyTopUpRepository
|
||||
import com.tangem.domain.onramp.*
|
||||
import com.tangem.domain.onramp.repositories.HotCryptoRepository
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
|
||||
import com.tangem.domain.onramp.repositories.*
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -27,6 +23,15 @@ internal object OnrampDomainModule {
|
|||
return GetOnrampCurrenciesUseCase(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampCurrencyUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): OnrampGetDefaultCurrencyUseCase {
|
||||
return OnrampGetDefaultCurrencyUseCase(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampSaveDefaultCurrencyUseCase(
|
||||
|
|
@ -120,6 +125,12 @@ internal object OnrampDomainModule {
|
|||
return OnrampSaveTransactionUseCase(onrampTransactionRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampSepaAvailableUseCase(onrampRepository: OnrampRepository): OnrampSepaAvailableUseCase {
|
||||
return OnrampSepaAvailableUseCase(onrampRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampUpdateTransactionStatusUseCase(
|
||||
|
|
@ -231,4 +242,34 @@ internal object OnrampDomainModule {
|
|||
fun provideGetLegacyTopUpUrlUseCase(legacyTopUpRepository: LegacyTopUpRepository): GetLegacyTopUpUrlUseCase {
|
||||
return GetLegacyTopUpUrlUseCase(legacyTopUpRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampAllOffersUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
settingsRepository: SettingsRepository,
|
||||
): GetOnrampAllOffersUseCase {
|
||||
return GetOnrampAllOffersUseCase(
|
||||
onrampRepository = onrampRepository,
|
||||
errorResolver = onrampErrorResolver,
|
||||
settingsRepository = settingsRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampOffersUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
onrampTransactionRepository: OnrampTransactionRepository,
|
||||
settingsRepository: SettingsRepository,
|
||||
): GetOnrampOffersUseCase {
|
||||
return GetOnrampOffersUseCase(
|
||||
onrampRepository = onrampRepository,
|
||||
errorResolver = onrampErrorResolver,
|
||||
onrampTransactionRepository = onrampTransactionRepository,
|
||||
settingsRepository = settingsRepository,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -15,9 +15,10 @@ internal object PromoDomainModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideShouldShowSwapPromoWalletUseCase(
|
||||
promoSettingsRepository: PromoRepository,
|
||||
promoRepository: PromoRepository,
|
||||
settingsRepository: SettingsRepository,
|
||||
): ShouldShowPromoWalletUseCase {
|
||||
return ShouldShowPromoWalletUseCase(promoSettingsRepository)
|
||||
return ShouldShowPromoWalletUseCase(promoRepository, settingsRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ internal object SettingsDomainModule {
|
|||
@Singleton
|
||||
fun providesShouldShowSaveWalletScreenUseCase(
|
||||
settingsRepository: SettingsRepository,
|
||||
): ShouldShowSaveWalletScreenUseCase {
|
||||
return ShouldShowSaveWalletScreenUseCase(settingsRepository = settingsRepository)
|
||||
): ShouldShowAskBiometryUseCase {
|
||||
return ShouldShowAskBiometryUseCase(settingsRepository = settingsRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
@ -138,10 +138,8 @@ internal object SettingsDomainModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSetSaveWalletScreenShownUseCase(
|
||||
settingsRepository: SettingsRepository,
|
||||
): SetSaveWalletScreenShownUseCase {
|
||||
return SetSaveWalletScreenShownUseCase(settingsRepository = settingsRepository)
|
||||
fun provideSetSaveWalletScreenShownUseCase(settingsRepository: SettingsRepository): SetAskBiometryShownUseCase {
|
||||
return SetAskBiometryShownUseCase(settingsRepository = settingsRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ internal object TokensDomainModule {
|
|||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
stakingIdFactory: StakingIdFactory,
|
||||
): AddCryptoCurrenciesUseCase {
|
||||
return AddCryptoCurrenciesUseCase(
|
||||
|
|
@ -56,7 +55,6 @@ internal object TokensDomainModule {
|
|||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
singleYieldBalanceFetcher = singleYieldBalanceFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
)
|
||||
}
|
||||
|
|
@ -111,13 +109,11 @@ internal object TokensDomainModule {
|
|||
currenciesRepository: CurrenciesRepository,
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): RemoveCurrencyUseCase {
|
||||
return RemoveCurrencyUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -156,7 +152,6 @@ internal object TokensDomainModule {
|
|||
dispatchers: CoroutineDispatcherProvider,
|
||||
baseCurrencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): GetCurrencyWarningsUseCase {
|
||||
return GetCurrencyWarningsUseCase(
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
|
|
@ -165,7 +160,6 @@ internal object TokensDomainModule {
|
|||
currencyChecksRepository = currencyChecksRepository,
|
||||
currencyStatusOperations = baseCurrencyStatusOperations,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -177,7 +171,6 @@ internal object TokensDomainModule {
|
|||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
singleYieldBalanceFetcher: SingleYieldBalanceFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
stakingIdFactory: StakingIdFactory,
|
||||
): FetchCurrencyStatusUseCase {
|
||||
return FetchCurrencyStatusUseCase(
|
||||
|
|
@ -186,7 +179,6 @@ internal object TokensDomainModule {
|
|||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
singleYieldBalanceFetcher = singleYieldBalanceFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
)
|
||||
}
|
||||
|
|
@ -214,9 +206,8 @@ internal object TokensDomainModule {
|
|||
fun provideGetCryptoCurrencyUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): GetCryptoCurrencyUseCase {
|
||||
return GetCryptoCurrencyUseCase(currenciesRepository, multiWalletCryptoCurrenciesSupplier, tokensFeatureToggles)
|
||||
return GetCryptoCurrencyUseCase(currenciesRepository, multiWalletCryptoCurrenciesSupplier)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
@ -238,13 +229,11 @@ internal object TokensDomainModule {
|
|||
fun provideApplyTokenListSortingUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): ApplyTokenListSortingUseCase {
|
||||
return ApplyTokenListSortingUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
|
@ -304,14 +293,10 @@ internal object TokensDomainModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideIsCryptoCurrencyCoinCouldHideUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): IsCryptoCurrencyCoinCouldHideUseCase {
|
||||
return IsCryptoCurrencyCoinCouldHideUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -330,13 +315,11 @@ internal object TokensDomainModule {
|
|||
fun provideGetBalanceNotEnoughForFeeWarningUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): GetBalanceNotEnoughForFeeWarningUseCase {
|
||||
return GetBalanceNotEnoughForFeeWarningUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
|
@ -377,16 +360,12 @@ internal object TokensDomainModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideRefreshMultiCurrencyWalletQuotesUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): RefreshMultiCurrencyWalletQuotesUseCase {
|
||||
return RefreshMultiCurrencyWalletQuotesUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -402,18 +381,13 @@ internal object TokensDomainModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideBaseCurrencyStatusOperations(
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
singleNetworkStatusSupplier: SingleNetworkStatusSupplier,
|
||||
multiNetworkStatusSupplier: MultiNetworkStatusSupplier,
|
||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
||||
singleNetworkStatusFetcher: SingleNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
singleQuoteStatusSupplier: SingleQuoteStatusSupplier,
|
||||
singleYieldBalanceSupplier: SingleYieldBalanceSupplier,
|
||||
multiYieldBalanceSupplier: MultiYieldBalanceSupplier,
|
||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
stakingIdFactory: StakingIdFactory,
|
||||
): BaseCurrencyStatusOperations {
|
||||
|
|
@ -422,15 +396,10 @@ internal object TokensDomainModule {
|
|||
quotesRepository = quotesRepository,
|
||||
singleNetworkStatusSupplier = singleNetworkStatusSupplier,
|
||||
multiNetworkStatusSupplier = multiNetworkStatusSupplier,
|
||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
||||
singleNetworkStatusFetcher = singleNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
singleQuoteStatusSupplier = singleQuoteStatusSupplier,
|
||||
singleYieldBalanceSupplier = singleYieldBalanceSupplier,
|
||||
multiYieldBalanceSupplier = multiYieldBalanceSupplier,
|
||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ import com.tangem.domain.demo.models.DemoConfig
|
|||
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
||||
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.transaction.FeeRepository
|
||||
import com.tangem.domain.transaction.TransactionRepository
|
||||
import com.tangem.domain.transaction.WalletAddressServiceRepository
|
||||
|
|
@ -63,18 +61,14 @@ internal object TransactionDomainModule {
|
|||
fun provideAssociateAssetUseCase(
|
||||
cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
singleNetworkStatusSupplier: SingleNetworkStatusSupplier,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): AssociateAssetUseCase {
|
||||
return AssociateAssetUseCase(
|
||||
cardSdkConfigRepository = cardSdkConfigRepository,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
currenciesRepository = currenciesRepository,
|
||||
singleNetworkStatusSupplier = singleNetworkStatusSupplier,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -196,8 +190,13 @@ internal object TransactionDomainModule {
|
|||
fun providePrepareAndSignUseCase(
|
||||
transactionRepository: TransactionRepository,
|
||||
cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
tangemHotWalletSignerFactory: TangemHotWalletSigner.Factory,
|
||||
): PrepareAndSignUseCase {
|
||||
return PrepareAndSignUseCase(transactionRepository, cardSdkConfigRepository)
|
||||
return PrepareAndSignUseCase(
|
||||
transactionRepository = transactionRepository,
|
||||
cardSdkConfigRepository = cardSdkConfigRepository,
|
||||
getHotTransactionSigner = { tangemHotWalletSignerFactory.create(it) },
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
@ -241,4 +240,13 @@ internal object TransactionDomainModule {
|
|||
): GetReverseResolvedEnsAddressUseCase {
|
||||
return GetReverseResolvedEnsAddressUseCase(walletAddressServiceRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun sendLargeSolanaTransactionUseCase(
|
||||
cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
): SendLargeSolanaTransactionUseCase {
|
||||
return SendLargeSolanaTransactionUseCase(cardSdkConfigRepository, walletManagersFacade)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.transaction.WalletAddressServiceRepository
|
||||
|
|
@ -9,8 +10,9 @@ import com.tangem.domain.transaction.usecase.ValidateWalletMemoUseCase
|
|||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.delegate.DefaultUserWalletsSyncDelegate
|
||||
import com.tangem.domain.wallets.delegate.UserWalletsSyncDelegate
|
||||
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||
import com.tangem.domain.wallets.hot.HotWalletAccessor
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.wallets.repository.WalletNamesMigrationRepository
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.domain.wallets.usecase.*
|
||||
|
|
@ -25,7 +27,7 @@ import dagger.hilt.InstallIn
|
|||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
@Suppress("TooManyFunctions", "LargeClass")
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object WalletsDomainModule {
|
||||
|
|
@ -133,6 +135,20 @@ internal object WalletsDomainModule {
|
|||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesIsWalletAlreadySavedUseCase(
|
||||
userWalletsListManager: UserWalletsListManager,
|
||||
userWalletsListRepository: UserWalletsListRepository,
|
||||
hotWalletFeatureToggles: HotWalletFeatureToggles,
|
||||
): IsWalletAlreadySavedUseCase {
|
||||
return IsWalletAlreadySavedUseCase(
|
||||
userWalletsListManager = userWalletsListManager,
|
||||
userWalletsListRepository = userWalletsListRepository,
|
||||
useNewRepository = hotWalletFeatureToggles.isHotWalletEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesOpenBuyTangemCardUseCase(): GenerateBuyTangemCardLinkUseCase {
|
||||
|
|
@ -352,4 +368,84 @@ internal object WalletsDomainModule {
|
|||
walletsRepository = walletsRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesIsUpgradeWalletNotificationEnabledUseCase(
|
||||
walletsRepository: WalletsRepository,
|
||||
): IsUpgradeWalletNotificationEnabledUseCase {
|
||||
return IsUpgradeWalletNotificationEnabledUseCase(
|
||||
walletsRepository = walletsRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesDismissUpgradeWalletNotificationUseCase(
|
||||
walletsRepository: WalletsRepository,
|
||||
): DismissUpgradeWalletNotificationUseCase {
|
||||
return DismissUpgradeWalletNotificationUseCase(
|
||||
walletsRepository = walletsRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesUnlockHotWalletContextualUseCase(
|
||||
hotWalletAccessor: HotWalletAccessor,
|
||||
): UnlockHotWalletContextualUseCase {
|
||||
return UnlockHotWalletContextualUseCase(
|
||||
hotWalletAccessor = hotWalletAccessor,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesGetHotWalletContextualUnlockUseCase(
|
||||
hotWalletAccessor: HotWalletAccessor,
|
||||
): GetHotWalletContextualUnlockUseCase {
|
||||
return GetHotWalletContextualUnlockUseCase(
|
||||
hotWalletAccessor = hotWalletAccessor,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesClearHotWalletContextualUnlockUseCase(
|
||||
hotWalletAccessor: HotWalletAccessor,
|
||||
): ClearHotWalletContextualUnlockUseCase {
|
||||
return ClearHotWalletContextualUnlockUseCase(
|
||||
hotWalletAccessor = hotWalletAccessor,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesClearAllHotWalletContextualUnlockUseCase(
|
||||
hotWalletAccessor: HotWalletAccessor,
|
||||
): ClearAllHotWalletContextualUnlockUseCase {
|
||||
return ClearAllHotWalletContextualUnlockUseCase(
|
||||
hotWalletAccessor = hotWalletAccessor,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesExportSeedPhraseUseCase(hotWalletAccessor: HotWalletAccessor): ExportSeedPhraseUseCase {
|
||||
return ExportSeedPhraseUseCase(
|
||||
hotWalletAccessor = hotWalletAccessor,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesColdWalletInteractionNeededUseCase(
|
||||
derivationsRepository: DerivationsRepository,
|
||||
getUserWalletUseCase: GetUserWalletUseCase,
|
||||
): ColdWalletAndHasMissedDerivationsUseCase {
|
||||
return ColdWalletAndHasMissedDerivationsUseCase(
|
||||
derivationsRepository = derivationsRepository,
|
||||
userWalletUseCase = getUserWalletUseCase,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.transaction.FeeRepository
|
||||
import com.tangem.domain.transaction.error.FeeErrorResolver
|
||||
import com.tangem.domain.yield.supply.YieldSupplyTransactionRepository
|
||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyEstimateEnterFeeUseCase
|
||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyStartEarningUseCase
|
||||
import com.tangem.domain.yield.supply.usecase.YieldSupplyStopEarningUseCase
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object YieldSupplyDomainModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideYieldSupplyStartEarningUseCase(
|
||||
yieldSupplyTransactionRepository: YieldSupplyTransactionRepository,
|
||||
): YieldSupplyStartEarningUseCase {
|
||||
return YieldSupplyStartEarningUseCase(
|
||||
yieldSupplyTransactionRepository = yieldSupplyTransactionRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideYieldSupplyStopEarningUseCase(
|
||||
yieldSupplyTransactionRepository: YieldSupplyTransactionRepository,
|
||||
): YieldSupplyStopEarningUseCase {
|
||||
return YieldSupplyStopEarningUseCase(
|
||||
yieldSupplyTransactionRepository = yieldSupplyTransactionRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideYieldSupplyEstimateEnterFeeUseCase(
|
||||
feeRepository: FeeRepository,
|
||||
feeErrorResolver: FeeErrorResolver,
|
||||
): YieldSupplyEstimateEnterFeeUseCase {
|
||||
return YieldSupplyEstimateEnterFeeUseCase(
|
||||
feeRepository = feeRepository,
|
||||
feeErrorResolver = feeErrorResolver,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.tap.di.hot
|
||||
|
||||
import com.tangem.data.wallets.hot.DefaultHotWalletAccessor
|
||||
import com.tangem.domain.wallets.hot.HotWalletAccessor
|
||||
import com.tangem.hot.sdk.TangemHotSdk
|
||||
import com.tangem.tap.features.hot.TangemHotSDKProxy
|
||||
import dagger.Binds
|
||||
|
|
@ -15,4 +17,8 @@ internal interface TangemHotSdkModule {
|
|||
@Binds
|
||||
@Singleton
|
||||
fun bindTangemHotSdk(proxy: TangemHotSDKProxy): TangemHotSdk
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindHotWalletAccessor(default: DefaultHotWalletAccessor): HotWalletAccessor
|
||||
}
|
||||
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