Updated on 2026-08-14
This commit is contained in:
parent
6a664f4a52
commit
e2d0973392
9 changed files with 353 additions and 25 deletions
|
|
@ -183,6 +183,7 @@ abstract class BaseTestCase : TestCase(
|
|||
"GASLESS_APPROVAL_ENABLED" to true,
|
||||
"MAIN_SCREEN_QR_SCANNING_ENABLED" to true,
|
||||
"ADD_AND_MANAGE_TOKENS_ENABLED" to true,
|
||||
"ASSETS_DISCOVERY_ENABLED" to true,
|
||||
"VISA_ONBOARDING_ENABLED" to true,
|
||||
"AND_15101_TANGEM_PAY_HOT_WALLET_ONBOARDING" to true,
|
||||
"AND_15310_ADD_FUNDS_STAGE1" to true,
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@ object TestConstants {
|
|||
const val USER_TOKENS_API_SCENARIO = "user_tokens_api"
|
||||
const val REFERRAL_API_SCENARIO = "referral_api"
|
||||
const val QUOTES_API_SCENARIO = "quotes_api"
|
||||
const val CREATE_USER_WALLET_API_SCENARIO = "create_user_wallet_api"
|
||||
const val WALLET_TOKENS_API_SCENARIO = "wallet_tokens_api"
|
||||
const val MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO = "moralis_evm_token_balances_api"
|
||||
const val PROVIDERS_API_SCENARIO = "networks_providers"
|
||||
|
||||
const val SEED_PHRASE_12 = "they cram join fantasy unfair observe true theory buffalo bus exchange walk"
|
||||
const val SEED_PHRASE_15 = "genuine try deer upset connect sausage diary rule price shallow fit faculty leopard " +
|
||||
|
|
@ -60,6 +64,9 @@ object TestConstants {
|
|||
"bread much nature basic fun iron benefit egg error prosper"
|
||||
const val SVS_SEED_PHRASE_12 = "diagram thunder merit soup muscle amused refuse usual ring couch popular wash"
|
||||
|
||||
const val SEED_PHRASE_HAPPY_PATH =
|
||||
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
||||
|
||||
const val TANGEM_PAY_ELIGIBILITY_SCENARIO = "tangem_pay_eligibility"
|
||||
const val TANGEM_PAY_ACCESS_CODE = "517384"
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import androidx.compose.ui.semantics.SemanticsProperties
|
|||
import androidx.compose.ui.test.ExperimentalTestApi
|
||||
import androidx.compose.ui.test.SemanticsMatcher
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import androidx.compose.ui.test.assertCountEquals
|
||||
import androidx.compose.ui.test.hasAnyAncestor
|
||||
import androidx.compose.ui.test.swipeUp
|
||||
import com.tangem.common.BaseTestCase
|
||||
|
|
@ -23,7 +24,7 @@ import androidx.compose.ui.test.hasText as withText
|
|||
import com.tangem.core.res.R as CoreResR
|
||||
import com.tangem.core.ui.R as CoreUiR
|
||||
|
||||
class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
class MainScreenPageObject(private val semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<MainScreenPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
private val lazyList = KLazyListNode(
|
||||
|
|
@ -100,6 +101,22 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
}
|
||||
}
|
||||
|
||||
val restoringProgressText: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.SYNC_PROGRESS_TEXT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val walletImportedBanner: KNode = child {
|
||||
hasTestTag(WalletNotificationTestTags.ASSETS_DISCOVERY_BANNER)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val walletImportedBannerCheckHereButton: KNode = child {
|
||||
hasAnyAncestor(withTestTag(WalletNotificationTestTags.ASSETS_DISCOVERY_BANNER))
|
||||
hasText(getResourceString(CoreResR.string.main_manage_tokens))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTestApi::class)
|
||||
fun marketPriceBlock(): LazyListItemNode {
|
||||
collapseHeader()
|
||||
|
|
@ -253,6 +270,15 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTestApi::class)
|
||||
fun tokenRowWithTitle(tokenTitle: String): LazyListItemNode {
|
||||
return lazyList.childWith<LazyListItemNode> {
|
||||
hasTestTag(MainScreenTestTags.TOKEN_LIST_ITEM)
|
||||
hasText(tokenTitle)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find token list item with title and address
|
||||
*/
|
||||
|
|
@ -350,6 +376,12 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun assertTokensCount(expectedCount: Int) {
|
||||
semanticsProvider
|
||||
.onAllNodes(withTestTag(TokenElementsTestTags.TOKEN_PRICE))
|
||||
.assertCountEquals(expectedCount)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onMainScreen(function: MainScreenPageObject.() -> Unit) =
|
||||
|
|
|
|||
|
|
@ -0,0 +1,251 @@
|
|||
package com.tangem.tests.hotWallet
|
||||
|
||||
import androidx.test.InstrumentationRegistry.getTargetContext
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.CREATE_USER_WALLET_API_SCENARIO
|
||||
import com.tangem.common.constants.TestConstants.MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO
|
||||
import com.tangem.common.constants.TestConstants.PROVIDERS_API_SCENARIO
|
||||
import com.tangem.common.constants.TestConstants.SEED_PHRASE_12
|
||||
import com.tangem.common.constants.TestConstants.SEED_PHRASE_HAPPY_PATH
|
||||
import com.tangem.common.constants.TestConstants.USER_TOKENS_API_SCENARIO
|
||||
import com.tangem.common.constants.TestConstants.WALLET_TOKENS_API_SCENARIO
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.extensions.restartApp
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.scenarios.openMainScreenWithExistingHotWallet
|
||||
import com.tangem.screens.*
|
||||
import com.tangem.screens.accounts.onAccountDetailsScreen
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
import org.junit.Test
|
||||
import com.tangem.core.ui.R as CoreUiR
|
||||
|
||||
@HiltAndroidTest
|
||||
class AssetsDiscoveryTest : BaseTestCase() {
|
||||
|
||||
private companion object {
|
||||
const val DISCOVERY_TIMEOUT_MILLIS = 120_000L
|
||||
|
||||
const val SCENARIO_STATE_STARTED = "Started"
|
||||
const val SCENARIO_STATE_EMPTY = "Empty"
|
||||
const val SCENARIO_STATE_ALREADY_EXISTS = "AlreadyExists"
|
||||
const val SCENARIO_STATE_ASSETS_DISCOVERY_REDIRECT = "AssetsDiscoveryRedirect"
|
||||
const val SCENARIO_STATE_ASSETS_DISCOVERY_HAPPY_PATH = "AssetsDiscoveryHappyPath"
|
||||
const val SCENARIO_STATE_NON_ZERO_EVM_BALANCES = "NonZeroEvmBalances"
|
||||
const val SCENARIO_STATE_NON_ZERO_EVM_BALANCES_SLOW = "NonZeroEvmBalancesSlow"
|
||||
|
||||
val EXPECTED_DISCOVERED_TOKENS = listOf(
|
||||
"Ethereum",
|
||||
"Polygon",
|
||||
"Tether",
|
||||
)
|
||||
|
||||
val TOKENS_THAT_MUST_NOT_APPEAR = listOf(
|
||||
"Solana",
|
||||
"USDC",
|
||||
)
|
||||
|
||||
val BACKEND_PRE_POPULATED_TOKENS = listOf(
|
||||
"Bitcoin",
|
||||
"Ethereum",
|
||||
"Polygon",
|
||||
)
|
||||
}
|
||||
|
||||
@AllureId("9280")
|
||||
@DisplayName("Hot wallet: new import — Discovery → Sync → Banner → Check here happy path")
|
||||
@Test
|
||||
fun newHotWalletImportHappyPathTest() {
|
||||
val packageName = getTargetContext().packageName
|
||||
|
||||
setupHooks(
|
||||
additionalBeforeAppLaunchSection = {
|
||||
setWireMockScenarioState(PROVIDERS_API_SCENARIO, state = SCENARIO_STATE_ASSETS_DISCOVERY_REDIRECT)
|
||||
setWireMockScenarioState(CREATE_USER_WALLET_API_SCENARIO, state = SCENARIO_STATE_STARTED)
|
||||
setWireMockScenarioState(USER_TOKENS_API_SCENARIO, state = SCENARIO_STATE_ASSETS_DISCOVERY_HAPPY_PATH)
|
||||
setWireMockScenarioState(WALLET_TOKENS_API_SCENARIO, state = SCENARIO_STATE_STARTED)
|
||||
setWireMockScenarioState(MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO, state = SCENARIO_STATE_NON_ZERO_EVM_BALANCES)
|
||||
},
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(PROVIDERS_API_SCENARIO)
|
||||
resetWireMockScenarioState(CREATE_USER_WALLET_API_SCENARIO)
|
||||
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
|
||||
resetWireMockScenarioState(WALLET_TOKENS_API_SCENARIO)
|
||||
resetWireMockScenarioState(MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO)
|
||||
},
|
||||
).run {
|
||||
step("Import a new hot wallet from seed phrase") {
|
||||
openMainScreenWithExistingHotWallet(SEED_PHRASE_HAPPY_PATH)
|
||||
}
|
||||
step("Assert 'Restoring' progress loader is shown (discovery is in flight)") {
|
||||
onMainScreen { restoringProgressText.assertIsDisplayed() }
|
||||
}
|
||||
step("Wait for 'Wallet successfully imported' banner (discovery completes)") {
|
||||
flakySafely(timeoutMs = DISCOVERY_TIMEOUT_MILLIS) {
|
||||
onMainScreen { walletImportedBanner.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
step("Assert expected discovered tokens are visible in the assets list") {
|
||||
onMainScreen {
|
||||
EXPECTED_DISCOVERED_TOKENS.forEach { token ->
|
||||
tokenRowWithTitle(token).assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Tap 'Check here' (Manage tokens) on the banner") {
|
||||
onMainScreen { walletImportedBannerCheckHereButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Manage Tokens' screen is opened") {
|
||||
onManageTokensScreen { searchField.assertIsDisplayed() }
|
||||
}
|
||||
step("Return to main screen") {
|
||||
device.uiDevice.pressBack()
|
||||
waitForIdle()
|
||||
}
|
||||
step("Assert banner is hidden after navigating into Manage Tokens") {
|
||||
onMainScreen { walletImportedBanner.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Force-close and re-launch the app") {
|
||||
restartApp(packageName)
|
||||
}
|
||||
step("Assert banner is NOT shown again after relaunch") {
|
||||
onMainScreen { walletImportedBanner.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert previously discovered tokens still appear in the assets list") {
|
||||
onMainScreen {
|
||||
EXPECTED_DISCOVERED_TOKENS.forEach { token ->
|
||||
tokenRowWithTitle(token).assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert zero-balance and spam tokens are NOT shown in the assets list") {
|
||||
onMainScreen {
|
||||
TOKENS_THAT_MUST_NOT_APPEAR.forEach { token ->
|
||||
assertTokenDoesNotExist(token)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("9284")
|
||||
@DisplayName("Hot wallet: token added manually during Discovery — no duplicate created")
|
||||
@Test
|
||||
fun manualTokenAddDuringDiscoveryNoDuplicateTest() {
|
||||
val tetherTitle = "Tether"
|
||||
val ethereumNetworkTitle = "ETHEREUM"
|
||||
val accountName = getResourceString(CoreUiR.string.account_main_account_title)
|
||||
val expectedTokensCount = 4
|
||||
|
||||
setupHooks(
|
||||
additionalBeforeAppLaunchSection = {
|
||||
setWireMockScenarioState(PROVIDERS_API_SCENARIO, state = SCENARIO_STATE_ASSETS_DISCOVERY_REDIRECT)
|
||||
setWireMockScenarioState(CREATE_USER_WALLET_API_SCENARIO, state = SCENARIO_STATE_STARTED)
|
||||
setWireMockScenarioState(USER_TOKENS_API_SCENARIO, state = SCENARIO_STATE_ASSETS_DISCOVERY_HAPPY_PATH)
|
||||
setWireMockScenarioState(WALLET_TOKENS_API_SCENARIO, state = SCENARIO_STATE_STARTED)
|
||||
setWireMockScenarioState(
|
||||
MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO,
|
||||
state = SCENARIO_STATE_NON_ZERO_EVM_BALANCES_SLOW,
|
||||
)
|
||||
},
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(PROVIDERS_API_SCENARIO)
|
||||
resetWireMockScenarioState(CREATE_USER_WALLET_API_SCENARIO)
|
||||
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
|
||||
resetWireMockScenarioState(WALLET_TOKENS_API_SCENARIO)
|
||||
resetWireMockScenarioState(MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO)
|
||||
},
|
||||
).run {
|
||||
step("Import a new hot wallet from seed phrase") {
|
||||
openMainScreenWithExistingHotWallet(SEED_PHRASE_HAPPY_PATH)
|
||||
}
|
||||
step("Assert 'Restoring' progress loader is shown (discovery is in flight)") {
|
||||
onMainScreen { restoringProgressText.assertIsDisplayed() }
|
||||
}
|
||||
step("Open wallet details from top bar") {
|
||||
onMainScreenTopBar { moreButton.clickWithAssertion() }
|
||||
}
|
||||
step("Open 'Wallet settings'") {
|
||||
onDetailsScreen { walletNameButton.performClick() }
|
||||
}
|
||||
step("Open account: '$accountName'") {
|
||||
onWalletSettingsScreen { accountItem(accountName).performClick() }
|
||||
}
|
||||
step("Open 'Manage Tokens' from account details") {
|
||||
onAccountDetailsScreen { manageTokensButton.performClick() }
|
||||
}
|
||||
step("Search for '$tetherTitle' in Manage Tokens") {
|
||||
onManageTokensScreen {
|
||||
searchField.performClick()
|
||||
searchField.performTextInput(tetherTitle)
|
||||
}
|
||||
device.uiDevice.pressBack()
|
||||
waitForIdle()
|
||||
}
|
||||
step("Expand '$tetherTitle'") {
|
||||
onManageTokensScreen { tokenItem(tetherTitle).clickWithAssertion() }
|
||||
waitForIdle()
|
||||
}
|
||||
step("Enable the $ethereumNetworkTitle network") {
|
||||
onManageTokensScreen { networkSwitch(ethereumNetworkTitle).clickWithAssertion() }
|
||||
}
|
||||
step("Save Manage Tokens changes") {
|
||||
onManageTokensScreen { saveButton.clickWithAssertion() }
|
||||
waitForIdle()
|
||||
}
|
||||
step("Navigate back to main screen") {
|
||||
repeat(times = 3) {
|
||||
device.uiDevice.pressBack()
|
||||
waitForIdle()
|
||||
}
|
||||
}
|
||||
step("Wait for 'Wallet successfully imported' banner (discovery completes after delay)") {
|
||||
flakySafely(timeoutMs = DISCOVERY_TIMEOUT_MILLIS) {
|
||||
onMainScreen { walletImportedBanner.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
step("Assert '$tetherTitle' is in the assets list (manual add + discovery merged)") {
|
||||
onMainScreen { tokenRowWithTitle(tetherTitle).assertIsDisplayed() }
|
||||
}
|
||||
step("Assert assets list contains exactly $expectedTokensCount tokens (no duplicate after merge)") {
|
||||
onMainScreen { assertTokensCount(expectedTokensCount) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("9282")
|
||||
@DisplayName("Hot wallet: re-import existing wallet — 200 OK, no Discovery, tokens from backend")
|
||||
@Test
|
||||
fun reimportExistingHotWalletTest() {
|
||||
setupHooks(
|
||||
additionalBeforeAppLaunchSection = {
|
||||
setWireMockScenarioState(CREATE_USER_WALLET_API_SCENARIO, state = SCENARIO_STATE_ALREADY_EXISTS)
|
||||
setWireMockScenarioState(USER_TOKENS_API_SCENARIO, state = SCENARIO_STATE_STARTED)
|
||||
setWireMockScenarioState(MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO, state = SCENARIO_STATE_EMPTY)
|
||||
},
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(CREATE_USER_WALLET_API_SCENARIO)
|
||||
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
|
||||
resetWireMockScenarioState(MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO)
|
||||
},
|
||||
).run {
|
||||
step("Import an existing hot wallet from seed phrase") {
|
||||
openMainScreenWithExistingHotWallet(SEED_PHRASE_12)
|
||||
}
|
||||
step("Assert tokens from backend are displayed immediately") {
|
||||
BACKEND_PRE_POPULATED_TOKENS.forEach { token ->
|
||||
onMainScreen { tokenRowWithTitle(token).assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
step("Assert 'Restoring' loader is NOT displayed (discovery did not start)") {
|
||||
onMainScreen { restoringProgressText.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet successfully imported' banner is NOT displayed") {
|
||||
onMainScreen { walletImportedBanner.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,21 +14,39 @@ class WireMockRedirectInterceptor : Interceptor {
|
|||
|
||||
val request = chain.request()
|
||||
val url = request.url.toString()
|
||||
val host = request.url.host
|
||||
val sanitizedOverride = override.trimEnd('/')
|
||||
|
||||
if (url.contains(WIREMOCK_REMOTE_URL)) {
|
||||
val newUrl = url.replace(WIREMOCK_REMOTE_URL, override.trimEnd('/'))
|
||||
if (host == WIREMOCK_REMOTE_HOST) {
|
||||
val newUrl = url.replace(WIREMOCK_REMOTE_URL, sanitizedOverride)
|
||||
TangemLogger.d("WireMockRedirect: $url -> $newUrl")
|
||||
val newRequest = request.newBuilder()
|
||||
.url(newUrl)
|
||||
.build()
|
||||
return chain.proceed(newRequest)
|
||||
return chain.proceed(request.newBuilder().url(newUrl).build())
|
||||
}
|
||||
|
||||
if (host in REDIRECTABLE_THIRD_PARTY_HOSTS) {
|
||||
val newUrl = url.replace("https://$host", "$sanitizedOverride/$host")
|
||||
TangemLogger.d("WireMockRedirect (3p): $url -> $newUrl")
|
||||
return chain.proceed(request.newBuilder().url(newUrl).build())
|
||||
}
|
||||
|
||||
return chain.proceed(request)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val WIREMOCK_REMOTE_URL = "[REDACTED_ENV_URL]"
|
||||
private const val WIREMOCK_REMOTE_HOST = "wiremock.tests-d.com"
|
||||
private const val WIREMOCK_REMOTE_URL = "https://$WIREMOCK_REMOTE_HOST"
|
||||
|
||||
/**
|
||||
* Upstream hosts that have no other override knob and should be funnelled into WireMock
|
||||
* when [overriddenBaseUrl] is set. Each matched URL becomes `<override>/<host>/<original-path>`,
|
||||
* so mock mappings should live under that host-prefixed path in tangem-api-mocks. Matching
|
||||
* is done against the request's parsed host (exact equality) — substring matching would
|
||||
* incorrectly redirect look-alikes such as `deep-index.moralis.io.evil.example`.
|
||||
*/
|
||||
private val REDIRECTABLE_THIRD_PARTY_HOSTS = setOf(
|
||||
"deep-index.moralis.io",
|
||||
"solana-gateway.moralis.io",
|
||||
)
|
||||
|
||||
/**
|
||||
* Override base URL for WireMock requests.
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ object MainScreenTestTags {
|
|||
const val CARD_TITLE = "MAIN_SCREEN_CARD_TITLE"
|
||||
const val CARD_IMAGE = "MAIN_SCREEN_CARD_IMAGE"
|
||||
const val DEVICES_COUNT = "MAIN_SCREEN_DEVICES_COUNT"
|
||||
const val SYNC_PROGRESS_TEXT = "MAIN_SCREEN_SYNC_PROGRESS_TEXT"
|
||||
|
||||
const val WALLET_BALANCE = "MAIN_SCREEN_WALLET_BALANCE"
|
||||
const val TOTAL_BALANCE_MENU_ITEM = "MAIN_SCREEN_TOTAL_BALANCE_MENU_ITEM"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
package com.tangem.core.ui.test
|
||||
|
||||
object WalletNotificationTestTags {
|
||||
const val ASSETS_DISCOVERY_BANNER = "WALLET_NOTIFICATION_ASSETS_DISCOVERY_BANNER"
|
||||
}
|
||||
|
|
@ -337,6 +337,7 @@ private fun AdditionalInfo(
|
|||
id = R.string.initial_wallet_sync_restore_progress,
|
||||
formatArgs = wrappedList(animatedContent.progressPercent),
|
||||
),
|
||||
testTag = MainScreenTestTags.SYNC_PROGRESS_TEXT,
|
||||
)
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size16),
|
||||
|
|
@ -353,14 +354,14 @@ private fun AdditionalInfo(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun AdditionalInfoText(text: TextReference) {
|
||||
private fun AdditionalInfoText(text: TextReference, testTag: String = MainScreenTestTags.DEVICES_COUNT) {
|
||||
Text(
|
||||
text = text.resolveReference(),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = TangemTheme.typography.caption2,
|
||||
modifier = Modifier.testTag(MainScreenTestTags.DEVICES_COUNT),
|
||||
modifier = Modifier.testTag(testTag),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.ui.components.common
|
||||
|
||||
import androidx.compose.foundation.lazy.LazyItemScope
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
|
|
@ -16,6 +18,7 @@ import com.tangem.core.ui.extensions.resourceReference
|
|||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.ForceDarkTheme
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.test.WalletNotificationTestTags
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -73,26 +76,35 @@ internal fun LazyListScope.notifications(configs: ImmutableList<WalletNotificati
|
|||
subtitle = resourceReference(R.string.tangempay_onboarding_banner_description),
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
Notification(
|
||||
config = item.config,
|
||||
modifier = modifier.animateItem(fadeInSpec = null, fadeOutSpec = null),
|
||||
iconTint = when (item) {
|
||||
is WalletNotification.Critical -> TangemTheme.colors.icon.warning
|
||||
is WalletNotification.Informational -> TangemTheme.colors.icon.accent
|
||||
is WalletNotification.RateApp -> TangemTheme.colors.icon.attention
|
||||
is WalletNotification.UnlockWallets -> TangemTheme.colors.icon.primary1
|
||||
is WalletNotification.UsedOutdatedData -> TangemTheme.colors.text.attention
|
||||
else -> null
|
||||
},
|
||||
subtitleColor = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
else -> DefaultWalletNotification(item = item, modifier = modifier)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LazyItemScope.DefaultWalletNotification(item: WalletNotification, modifier: Modifier = Modifier) {
|
||||
val itemModifier = modifier.animateItem(fadeInSpec = null, fadeOutSpec = null)
|
||||
val taggedModifier = when (item) {
|
||||
is WalletNotification.AssetsDiscoveryCompleted ->
|
||||
itemModifier.testTag(WalletNotificationTestTags.ASSETS_DISCOVERY_BANNER)
|
||||
else -> itemModifier
|
||||
}
|
||||
Notification(
|
||||
config = item.config,
|
||||
modifier = taggedModifier,
|
||||
iconTint = when (item) {
|
||||
is WalletNotification.Critical -> TangemTheme.colors.icon.warning
|
||||
is WalletNotification.Informational -> TangemTheme.colors.icon.accent
|
||||
is WalletNotification.RateApp -> TangemTheme.colors.icon.attention
|
||||
is WalletNotification.UnlockWallets -> TangemTheme.colors.icon.primary1
|
||||
is WalletNotification.UsedOutdatedData -> TangemTheme.colors.text.attention
|
||||
else -> null
|
||||
},
|
||||
subtitleColor = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun yieldBoostPromoTitle(): AnnotatedString {
|
||||
val accent = TangemTheme.colors.text.accent
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue