Updated on 2026-08-14
This commit is contained in:
parent
d050fa2654
commit
bbb3c9d6bb
16 changed files with 112 additions and 115 deletions
|
|
@ -7,10 +7,10 @@ import com.tangem.screens.AlreadyUsedWalletDialogPageObject.message
|
||||||
import com.tangem.screens.AlreadyUsedWalletDialogPageObject.requestSupportButton
|
import com.tangem.screens.AlreadyUsedWalletDialogPageObject.requestSupportButton
|
||||||
import com.tangem.screens.AlreadyUsedWalletDialogPageObject.thisIsMyWalletButton
|
import com.tangem.screens.AlreadyUsedWalletDialogPageObject.thisIsMyWalletButton
|
||||||
import com.tangem.screens.AlreadyUsedWalletDialogPageObject.title
|
import com.tangem.screens.AlreadyUsedWalletDialogPageObject.title
|
||||||
import com.tangem.screens.ScanWarningDialogPageObject
|
|
||||||
import com.tangem.screens.onActionIsUnavailableDialog
|
import com.tangem.screens.onActionIsUnavailableDialog
|
||||||
import com.tangem.screens.onDataNotLoadedDialog
|
import com.tangem.screens.onDataNotLoadedDialog
|
||||||
import com.tangem.screens.onFailedTransactionDialog
|
import com.tangem.screens.onFailedTransactionDialog
|
||||||
|
import com.tangem.screens.onScanWarningDialog
|
||||||
import io.qameta.allure.kotlin.Allure.step
|
import io.qameta.allure.kotlin.Allure.step
|
||||||
|
|
||||||
fun BaseTestCase.checkFailedTransactionDialog() {
|
fun BaseTestCase.checkFailedTransactionDialog() {
|
||||||
|
|
@ -31,21 +31,21 @@ fun BaseTestCase.checkFailedTransactionDialog() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkScanWarningDialog() {
|
fun BaseTestCase.checkScanWarningDialog() {
|
||||||
step("Assert 'Scan warning' dialog title is displayed") {
|
step("Assert 'Scan warning' dialog title is displayed") {
|
||||||
ScanWarningDialogPageObject { warningTitle.isDisplayed() }
|
onScanWarningDialog { warningTitle.assertIsDisplayed() }
|
||||||
}
|
}
|
||||||
step("Assert warning dialog message is displayed") {
|
step("Assert warning dialog message is displayed") {
|
||||||
ScanWarningDialogPageObject { warningMessage.isDisplayed() }
|
onScanWarningDialog { warningMessage.assertIsDisplayed() }
|
||||||
}
|
}
|
||||||
step("Assert 'Cancel' button is displayed") {
|
step("Assert 'Cancel' button is displayed") {
|
||||||
ScanWarningDialogPageObject { cancelButton.isDisplayed() }
|
onScanWarningDialog { cancelButton.assertIsDisplayed() }
|
||||||
}
|
}
|
||||||
step("Assert 'How to scan' button is displayed") {
|
step("Assert 'How to scan' button is displayed") {
|
||||||
ScanWarningDialogPageObject { howToScanButton.isDisplayed() }
|
onScanWarningDialog { howToScanButton.assertIsDisplayed() }
|
||||||
}
|
}
|
||||||
step("Assert 'Request support' button is displayed") {
|
step("Assert 'Request support' button is displayed") {
|
||||||
ScanWarningDialogPageObject { requestSupportButton.isDisplayed() }
|
onScanWarningDialog { requestSupportButton.assertIsDisplayed() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,42 @@
|
||||||
package com.tangem.screens
|
package com.tangem.screens
|
||||||
|
|
||||||
import com.kaspersky.kaspresso.screens.KScreen
|
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||||
|
import com.tangem.common.BaseTestCase
|
||||||
|
import com.tangem.tap.features.scanfails.ui.ScanFailsDialogTestTags
|
||||||
import com.tangem.wallet.R
|
import com.tangem.wallet.R
|
||||||
import io.github.kakaocup.kakao.text.KTextView
|
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||||
import io.github.kakaocup.kakao.text.KButton
|
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
|
||||||
|
|
||||||
object ScanWarningDialogPageObject : KScreen<ScanWarningDialogPageObject>() {
|
class ScanWarningDialogPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||||
|
ComposeScreen<ScanWarningDialogPageObject>(semanticsProvider = semanticsProvider) {
|
||||||
|
|
||||||
override val layoutId: Int? = null
|
val warningTitle: KNode = child {
|
||||||
override val viewClass: Class<*>? = null
|
hasText(getResourceString(R.string.common_warning))
|
||||||
|
useUnmergedTree = true
|
||||||
val warningTitle = KTextView {
|
|
||||||
withText(R.string.common_warning)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val warningMessage = KTextView {
|
val warningMessage: KNode = child {
|
||||||
withText(R.string.alert_troubleshooting_scan_card_title)
|
hasText(getResourceString(R.string.alert_troubleshooting_scan_card_title))
|
||||||
|
useUnmergedTree = true
|
||||||
}
|
}
|
||||||
|
|
||||||
val tryAgainButton = KButton {
|
val howToScanButton: KNode = child {
|
||||||
withId(R.id.try_again_button)
|
hasTestTag(ScanFailsDialogTestTags.HOW_TO_SCAN_BUTTON)
|
||||||
|
useUnmergedTree = true
|
||||||
}
|
}
|
||||||
|
|
||||||
val howToScanButton = KButton {
|
val requestSupportButton: KNode = child {
|
||||||
withId(R.id.how_to_scan_button)
|
hasTestTag(ScanFailsDialogTestTags.REQUEST_SUPPORT_BUTTON)
|
||||||
|
useUnmergedTree = true
|
||||||
}
|
}
|
||||||
|
|
||||||
val requestSupportButton = KButton {
|
val cancelButton: KNode = child {
|
||||||
withId(R.id.request_support_button)
|
hasTestTag(ScanFailsDialogTestTags.CANCEL_BUTTON)
|
||||||
|
useUnmergedTree = true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val cancelButton = KButton {
|
internal fun BaseTestCase.onScanWarningDialog(function: ScanWarningDialogPageObject.() -> Unit) =
|
||||||
withId(R.id.cancel_button)
|
onComposeScreen(composeTestRule, function)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -7,13 +7,26 @@ import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
import com.tangem.common.extensions.clickAndWaitFor
|
import com.tangem.common.extensions.clickAndWaitFor
|
||||||
import com.tangem.common.extensions.clickWithAssertion
|
import com.tangem.common.extensions.clickWithAssertion
|
||||||
import com.tangem.domain.redux.StateDialog
|
import com.tangem.domain.card.ScanFailsRequester
|
||||||
|
import kotlinx.coroutines.MainScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import com.tangem.scenarios.checkFailedTransactionDialog
|
import com.tangem.scenarios.checkFailedTransactionDialog
|
||||||
import com.tangem.scenarios.checkScanWarningDialog
|
import com.tangem.scenarios.checkScanWarningDialog
|
||||||
import com.tangem.scenarios.openMainScreen
|
import com.tangem.scenarios.openMainScreen
|
||||||
import com.tangem.scenarios.synchronizeAddresses
|
import com.tangem.scenarios.synchronizeAddresses
|
||||||
import com.tangem.screens.*
|
import com.tangem.screens.ThirdPartyAppPageObject
|
||||||
import com.tangem.tap.common.redux.global.GlobalAction
|
import com.tangem.screens.onCreateWalletStartScreen
|
||||||
|
import com.tangem.screens.onDetailsScreen
|
||||||
|
import com.tangem.screens.onDisclaimerScreen
|
||||||
|
import com.tangem.screens.onFailedTransactionDialog
|
||||||
|
import com.tangem.screens.onMainScreen
|
||||||
|
import com.tangem.screens.onScanWarningDialog
|
||||||
|
import com.tangem.screens.onSendAddressScreen
|
||||||
|
import com.tangem.screens.onSendConfirmScreen
|
||||||
|
import com.tangem.screens.onSendScreen
|
||||||
|
import com.tangem.screens.onStoriesScreen
|
||||||
|
import com.tangem.screens.onTokenDetailsScreen
|
||||||
|
import com.tangem.screens.onTopBar
|
||||||
import com.tangem.tap.domain.sdk.mocks.MockProvider
|
import com.tangem.tap.domain.sdk.mocks.MockProvider
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
import dagger.hilt.android.testing.HiltAndroidTest
|
import dagger.hilt.android.testing.HiltAndroidTest
|
||||||
|
|
@ -164,8 +177,10 @@ class FeedbackTest : BaseTestCase() {
|
||||||
}
|
}
|
||||||
step("Force show 'Scan warning' dialog"){
|
step("Force show 'Scan warning' dialog"){
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
val scanFailsState = StateDialog.ScanFailsDialog(source = StateDialog.ScanFailsSource.MAIN)
|
val requester = store.state.daggerGraphState.scanFailsRequester!!
|
||||||
store.dispatch(GlobalAction.ShowDialog(scanFailsState))
|
MainScope().launch {
|
||||||
|
requester.show(ScanFailsRequester.Source.MAIN)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
step("Check 'Scan warning' dialog") {
|
step("Check 'Scan warning' dialog") {
|
||||||
|
|
@ -173,7 +188,7 @@ class FeedbackTest : BaseTestCase() {
|
||||||
checkScanWarningDialog()
|
checkScanWarningDialog()
|
||||||
}
|
}
|
||||||
step("Click on 'Request support' button") {
|
step("Click on 'Request support' button") {
|
||||||
ScanWarningDialogPageObject { requestSupportButton.click() }
|
onScanWarningDialog { requestSupportButton.performClick() }
|
||||||
}
|
}
|
||||||
step("Assert 'Gmail' app is open") {
|
step("Assert 'Gmail' app is open") {
|
||||||
ThirdPartyAppPageObject { assertElementWithTextExists(gmailText) }
|
ThirdPartyAppPageObject { assertElementWithTextExists(gmailText) }
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import com.tangem.domain.apptheme.GetAppThemeModeUseCase
|
||||||
import com.tangem.domain.apptheme.repository.AppThemeModeRepository
|
import com.tangem.domain.apptheme.repository.AppThemeModeRepository
|
||||||
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
||||||
import com.tangem.domain.card.ScanCardProcessor
|
import com.tangem.domain.card.ScanCardProcessor
|
||||||
|
import com.tangem.domain.card.ScanFailsRequester
|
||||||
import com.tangem.domain.card.repository.CardRepository
|
import com.tangem.domain.card.repository.CardRepository
|
||||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||||
import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
|
import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
|
||||||
|
|
@ -151,4 +152,6 @@ interface ApplicationEntryPoint {
|
||||||
fun getAppsFlyerClientFactory(): AppsFlyerClient.Factory
|
fun getAppsFlyerClientFactory(): AppsFlyerClient.Factory
|
||||||
|
|
||||||
fun getCustomerIoFeatureToggles(): CustomerIoFeatureToggles
|
fun getCustomerIoFeatureToggles(): CustomerIoFeatureToggles
|
||||||
|
|
||||||
|
fun getScanFailsRequester(): ScanFailsRequester
|
||||||
}
|
}
|
||||||
|
|
@ -239,6 +239,9 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
|
||||||
private val customerIoFeatureToggles: CustomerIoFeatureToggles
|
private val customerIoFeatureToggles: CustomerIoFeatureToggles
|
||||||
get() = entryPoint.getCustomerIoFeatureToggles()
|
get() = entryPoint.getCustomerIoFeatureToggles()
|
||||||
|
|
||||||
|
private val scanFailsRequester
|
||||||
|
get() = entryPoint.getScanFailsRequester()
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
private val appScope = MainScope()
|
private val appScope = MainScope()
|
||||||
|
|
@ -368,6 +371,7 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
|
||||||
userWalletsListRepository = userWalletsListRepository,
|
userWalletsListRepository = userWalletsListRepository,
|
||||||
tangemHotSdk = tangemHotSdk,
|
tangemHotSdk = tangemHotSdk,
|
||||||
trackingContextProxy = trackingContextProxy,
|
trackingContextProxy = trackingContextProxy,
|
||||||
|
scanFailsRequester = scanFailsRequester,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,8 @@ import com.tangem.common.CompletionResult
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
import com.tangem.core.analytics.models.AnalyticsParam
|
import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
|
import com.tangem.domain.card.ScanFailsRequester
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
import com.tangem.domain.redux.StateDialog
|
|
||||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
|
||||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||||
import com.tangem.tap.common.extensions.inject
|
import com.tangem.tap.common.extensions.inject
|
||||||
import com.tangem.tap.common.redux.AppState
|
import com.tangem.tap.common.redux.AppState
|
||||||
|
|
@ -54,12 +53,14 @@ private fun handleFailureChooseBehaviour(
|
||||||
store.dispatch(GlobalAction.ScanFailsCounter.Increment)
|
store.dispatch(GlobalAction.ScanFailsCounter.Increment)
|
||||||
if (store.state.globalState.scanCardFailsCounter >= 2) {
|
if (store.state.globalState.scanCardFailsCounter >= 2) {
|
||||||
val scanFailsSource = when (analyticsSource) {
|
val scanFailsSource = when (analyticsSource) {
|
||||||
is AnalyticsParam.ScreensSources.SignIn -> StateDialog.ScanFailsSource.SIGN_IN
|
is AnalyticsParam.ScreensSources.SignIn -> ScanFailsRequester.Source.SIGN_IN
|
||||||
is AnalyticsParam.ScreensSources.Settings -> StateDialog.ScanFailsSource.SETTINGS
|
is AnalyticsParam.ScreensSources.Settings -> ScanFailsRequester.Source.SETTINGS
|
||||||
is AnalyticsParam.ScreensSources.Intro -> StateDialog.ScanFailsSource.INTRO
|
is AnalyticsParam.ScreensSources.Intro -> ScanFailsRequester.Source.INTRO
|
||||||
else -> StateDialog.ScanFailsSource.MAIN
|
else -> ScanFailsRequester.Source.MAIN
|
||||||
|
}
|
||||||
|
scope.launch {
|
||||||
|
store.inject(DaggerGraphState::scanFailsRequester).show(scanFailsSource)
|
||||||
}
|
}
|
||||||
store.dispatchDialogShow(StateDialog.ScanFailsDialog(scanFailsSource))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
store.dispatch(GlobalAction.ScanFailsCounter.Reset)
|
store.dispatch(GlobalAction.ScanFailsCounter.Reset)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package com.tangem.tap.domain.model
|
package com.tangem.tap.domain.model
|
||||||
|
|
||||||
import com.tangem.domain.features.addCustomToken.CustomCurrency
|
|
||||||
import com.tangem.tap.common.redux.global.CryptoCurrencyName
|
import com.tangem.tap.common.redux.global.CryptoCurrencyName
|
||||||
import com.tangem.blockchain.common.Blockchain as SdkBlockchain
|
import com.tangem.blockchain.common.Blockchain as SdkBlockchain
|
||||||
import com.tangem.blockchain.common.Token as SdkToken
|
import com.tangem.blockchain.common.Token as SdkToken
|
||||||
|
|
@ -29,20 +28,4 @@ sealed interface Currency {
|
||||||
) : Currency {
|
) : Currency {
|
||||||
override val currencySymbol: CryptoCurrencyName = blockchain.currency
|
override val currencySymbol: CryptoCurrencyName = blockchain.currency
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun fromCustomCurrency(customCurrency: CustomCurrency): Currency {
|
|
||||||
return when (customCurrency) {
|
|
||||||
is CustomCurrency.CustomBlockchain -> Blockchain(
|
|
||||||
blockchain = customCurrency.network,
|
|
||||||
derivationPath = customCurrency.derivationPath?.rawPath,
|
|
||||||
)
|
|
||||||
is CustomCurrency.CustomToken -> Token(
|
|
||||||
token = customCurrency.token,
|
|
||||||
blockchain = customCurrency.network,
|
|
||||||
derivationPath = customCurrency.derivationPath?.rawPath,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -9,18 +9,19 @@ import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.core.analytics.models.Basic
|
import com.tangem.core.analytics.models.Basic
|
||||||
import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
|
import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
|
||||||
import com.tangem.domain.card.ScanCardException
|
import com.tangem.domain.card.ScanCardException
|
||||||
|
import com.tangem.domain.card.ScanFailsRequester
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
import com.tangem.domain.redux.StateDialog
|
|
||||||
import com.tangem.tap.common.analytics.events.TangemSdkErrorEvent
|
import com.tangem.tap.common.analytics.events.TangemSdkErrorEvent
|
||||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
|
||||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||||
import com.tangem.tap.common.extensions.inject
|
import com.tangem.tap.common.extensions.inject
|
||||||
import com.tangem.tap.domain.scanCard.chains.*
|
import com.tangem.tap.domain.scanCard.chains.*
|
||||||
import com.tangem.tap.domain.scanCard.utils.ScanCardExceptionConverter
|
import com.tangem.tap.domain.scanCard.utils.ScanCardExceptionConverter
|
||||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||||
|
import com.tangem.tap.scope
|
||||||
import com.tangem.tap.store
|
import com.tangem.tap.store
|
||||||
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
|
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
internal object UseCaseScanProcessor {
|
internal object UseCaseScanProcessor {
|
||||||
private val scanCardExceptionConverter = ScanCardExceptionConverter()
|
private val scanCardExceptionConverter = ScanCardExceptionConverter()
|
||||||
|
|
@ -57,7 +58,7 @@ internal object UseCaseScanProcessor {
|
||||||
val chains = buildList {
|
val chains = buildList {
|
||||||
add(
|
add(
|
||||||
FailedScansCounterChain(
|
FailedScansCounterChain(
|
||||||
{ showMaxUnsuccessfulScansReachedDialog(analyticsSource) },
|
{ showScanFailsDialog(analyticsSource) },
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
add(AnalyticsChain(Basic.CardWasScanned(analyticsSource)))
|
add(AnalyticsChain(Basic.CardWasScanned(analyticsSource)))
|
||||||
|
|
@ -71,14 +72,16 @@ internal object UseCaseScanProcessor {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showMaxUnsuccessfulScansReachedDialog(source: AnalyticsParam.ScreensSources) {
|
private fun showScanFailsDialog(source: AnalyticsParam.ScreensSources) {
|
||||||
val scanFailsSource = when (source) {
|
val scanFailsSource = when (source) {
|
||||||
is AnalyticsParam.ScreensSources.SignIn -> StateDialog.ScanFailsSource.SIGN_IN
|
is AnalyticsParam.ScreensSources.SignIn -> ScanFailsRequester.Source.SIGN_IN
|
||||||
is AnalyticsParam.ScreensSources.Settings -> StateDialog.ScanFailsSource.SETTINGS
|
is AnalyticsParam.ScreensSources.Settings -> ScanFailsRequester.Source.SETTINGS
|
||||||
is AnalyticsParam.ScreensSources.Intro -> StateDialog.ScanFailsSource.INTRO
|
is AnalyticsParam.ScreensSources.Intro -> ScanFailsRequester.Source.INTRO
|
||||||
else -> StateDialog.ScanFailsSource.MAIN
|
else -> ScanFailsRequester.Source.MAIN
|
||||||
|
}
|
||||||
|
scope.launch {
|
||||||
|
store.inject(DaggerGraphState::scanFailsRequester).show(scanFailsSource)
|
||||||
}
|
}
|
||||||
store.dispatchDialogShow(StateDialog.ScanFailsDialog(scanFailsSource))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun proceedWithException(
|
private suspend fun proceedWithException(
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,7 @@ import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||||
import com.tangem.tap.common.analytics.events.ScanFailsDialogAnalytics
|
import com.tangem.tap.common.analytics.events.ScanFailsDialogAnalytics
|
||||||
import com.tangem.tap.features.scanfails.ui.ScanFailsUM
|
import com.tangem.tap.features.scanfails.ui.ScanFailsUM
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import kotlinx.coroutines.flow.update
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
@ -61,34 +62,43 @@ internal fun ScanFailsDialogContent(state: ScanFailsUM) {
|
||||||
text = stringResourceSafe(R.string.alert_button_how_to_scan),
|
text = stringResourceSafe(R.string.alert_button_how_to_scan),
|
||||||
onClick = state.onHowToScan,
|
onClick = state.onHowToScan,
|
||||||
color = TangemTheme.colors.text.accent,
|
color = TangemTheme.colors.text.accent,
|
||||||
|
modifier = Modifier.testTag(ScanFailsDialogTestTags.HOW_TO_SCAN_BUTTON),
|
||||||
)
|
)
|
||||||
|
|
||||||
DialogTextButton(
|
DialogTextButton(
|
||||||
text = stringResourceSafe(R.string.alert_button_request_support),
|
text = stringResourceSafe(R.string.alert_button_request_support),
|
||||||
onClick = state.onRequestSupport,
|
onClick = state.onRequestSupport,
|
||||||
color = TangemTheme.colors.text.accent,
|
color = TangemTheme.colors.text.accent,
|
||||||
|
modifier = Modifier.testTag(ScanFailsDialogTestTags.REQUEST_SUPPORT_BUTTON),
|
||||||
)
|
)
|
||||||
|
|
||||||
DialogTextButton(
|
DialogTextButton(
|
||||||
text = stringResourceSafe(R.string.common_cancel),
|
text = stringResourceSafe(R.string.common_cancel),
|
||||||
onClick = state.onDismiss,
|
onClick = state.onDismiss,
|
||||||
color = TangemTheme.colors.text.warning,
|
color = TangemTheme.colors.text.warning,
|
||||||
|
modifier = Modifier.testTag(ScanFailsDialogTestTags.CANCEL_BUTTON),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DialogTextButton(text: String, onClick: () -> Unit, color: Color) {
|
private fun DialogTextButton(text: String, onClick: () -> Unit, color: Color, modifier: Modifier = Modifier) {
|
||||||
Text(
|
Text(
|
||||||
text = text.uppercase(),
|
text = text.uppercase(),
|
||||||
color = color,
|
color = color,
|
||||||
style = TangemTheme.typography.button,
|
style = TangemTheme.typography.button,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = Modifier.clickable(onClick = onClick),
|
modifier = modifier.clickable(onClick = onClick),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object ScanFailsDialogTestTags {
|
||||||
|
const val HOW_TO_SCAN_BUTTON = "scan_fails_how_to_scan_button"
|
||||||
|
const val REQUEST_SUPPORT_BUTTON = "scan_fails_request_support_button"
|
||||||
|
const val CANCEL_BUTTON = "scan_fails_cancel_button"
|
||||||
|
}
|
||||||
|
|
||||||
// region Preview
|
// region Preview
|
||||||
@Preview(showBackground = true, widthDp = 360)
|
@Preview(showBackground = true, widthDp = 360)
|
||||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import com.tangem.domain.apptheme.repository.AppThemeModeRepository
|
||||||
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
||||||
import com.tangem.domain.card.ScanCardProcessor
|
import com.tangem.domain.card.ScanCardProcessor
|
||||||
import com.tangem.domain.card.ScanCardUseCase
|
import com.tangem.domain.card.ScanCardUseCase
|
||||||
|
import com.tangem.domain.card.ScanFailsRequester
|
||||||
import com.tangem.domain.card.repository.CardRepository
|
import com.tangem.domain.card.repository.CardRepository
|
||||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||||
|
|
@ -73,4 +74,5 @@ data class DaggerGraphState(
|
||||||
val userWalletsListRepository: UserWalletsListRepository? = null,
|
val userWalletsListRepository: UserWalletsListRepository? = null,
|
||||||
val tangemHotSdk: TangemHotSdk? = null,
|
val tangemHotSdk: TangemHotSdk? = null,
|
||||||
val trackingContextProxy: TrackingContextProxy? = null,
|
val trackingContextProxy: TrackingContextProxy? = null,
|
||||||
|
val scanFailsRequester: ScanFailsRequester? = null,
|
||||||
) : StateType
|
) : StateType
|
||||||
|
|
@ -52,6 +52,7 @@ internal fun RootContent(
|
||||||
wcContent: @Composable (modifier: Modifier) -> Unit,
|
wcContent: @Composable (modifier: Modifier) -> Unit,
|
||||||
hotAccessCodeContent: @Composable (modifier: Modifier) -> Unit,
|
hotAccessCodeContent: @Composable (modifier: Modifier) -> Unit,
|
||||||
rootDetectedWarningContent: @Composable (modifier: Modifier) -> Unit,
|
rootDetectedWarningContent: @Composable (modifier: Modifier) -> Unit,
|
||||||
|
scanFailsContent: @Composable (modifier: Modifier) -> Unit,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
|
@ -89,6 +90,8 @@ internal fun RootContent(
|
||||||
|
|
||||||
rootDetectedWarningContent(Modifier.fillMaxSize())
|
rootDetectedWarningContent(Modifier.fillMaxSize())
|
||||||
|
|
||||||
|
scanFailsContent(Modifier.fillMaxSize())
|
||||||
|
|
||||||
TangemSnackbarHost(
|
TangemSnackbarHost(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.BottomCenter)
|
.align(Alignment.BottomCenter)
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ import com.tangem.hot.sdk.android.create
|
||||||
import com.tangem.sdk.api.BackupServiceHolder
|
import com.tangem.sdk.api.BackupServiceHolder
|
||||||
import com.tangem.tap.common.SnackbarHandler
|
import com.tangem.tap.common.SnackbarHandler
|
||||||
import com.tangem.tap.common.analytics.events.Onboarding
|
import com.tangem.tap.common.analytics.events.Onboarding
|
||||||
|
import com.tangem.tap.features.scanfails.ScanFailsComponent
|
||||||
|
import com.tangem.tap.features.scanfails.ScanFailsRequesterProxy
|
||||||
import com.tangem.tap.features.demo.DemoHelper
|
import com.tangem.tap.features.demo.DemoHelper
|
||||||
import com.tangem.tap.features.hot.TangemHotSDKProxy
|
import com.tangem.tap.features.hot.TangemHotSDKProxy
|
||||||
import com.tangem.tap.features.root.RootDetectedWarningComponent
|
import com.tangem.tap.features.root.RootDetectedWarningComponent
|
||||||
|
|
@ -75,6 +77,8 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
||||||
private val cardRepository: CardRepository,
|
private val cardRepository: CardRepository,
|
||||||
private val onboardingRepository: OnboardingRepository,
|
private val onboardingRepository: OnboardingRepository,
|
||||||
private val trackingContextProxy: TrackingContextProxy,
|
private val trackingContextProxy: TrackingContextProxy,
|
||||||
|
private val scanFailsComponentFactory: ScanFailsComponent.Factory,
|
||||||
|
private val scanFailsRequesterProxy: ScanFailsRequesterProxy,
|
||||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||||
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
|
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
|
||||||
private val backupServiceHolder: BackupServiceHolder,
|
private val backupServiceHolder: BackupServiceHolder,
|
||||||
|
|
@ -97,6 +101,11 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
||||||
.create(child("rootDetectedWarningComponent"), Unit)
|
.create(child("rootDetectedWarningComponent"), Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val scanFailsComponent: ScanFailsComponent by lazy {
|
||||||
|
scanFailsComponentFactory
|
||||||
|
.create(child("scanFailsComponent"), Unit)
|
||||||
|
}
|
||||||
|
|
||||||
private val navigation = navigationProvider.getOrCreateTyped<AppRoute>()
|
private val navigation = navigationProvider.getOrCreateTyped<AppRoute>()
|
||||||
|
|
||||||
private val stack: Value<ChildStack<AppRoute, Child>> = childStack(
|
private val stack: Value<ChildStack<AppRoute, Child>> = childStack(
|
||||||
|
|
@ -197,6 +206,7 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
||||||
wcContent = { wcRoutingComponent.Content(it) },
|
wcContent = { wcRoutingComponent.Content(it) },
|
||||||
hotAccessCodeContent = { hotAccessCodeRequestComponent.Content(it) },
|
hotAccessCodeContent = { hotAccessCodeRequestComponent.Content(it) },
|
||||||
rootDetectedWarningContent = { rootDetectedWarningComponent.Content(it) },
|
rootDetectedWarningContent = { rootDetectedWarningComponent.Content(it) },
|
||||||
|
scanFailsContent = { scanFailsComponent.Content(it) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -240,10 +250,12 @@ internal class DefaultRoutingComponent @AssistedInject constructor(
|
||||||
onCreate = {
|
onCreate = {
|
||||||
tangemHotSDKProxy.sdkState.value = TangemHotSdk.create(activity)
|
tangemHotSDKProxy.sdkState.value = TangemHotSdk.create(activity)
|
||||||
hotAccessCodeRequesterProxy.componentRequester.value = hotAccessCodeRequestComponent
|
hotAccessCodeRequesterProxy.componentRequester.value = hotAccessCodeRequestComponent
|
||||||
|
scanFailsRequesterProxy.componentRequester.value = scanFailsComponent
|
||||||
},
|
},
|
||||||
onDestroy = {
|
onDestroy = {
|
||||||
tangemHotSDKProxy.sdkState.value = null
|
tangemHotSDKProxy.sdkState.value = null
|
||||||
hotAccessCodeRequesterProxy.componentRequester.value = null
|
hotAccessCodeRequesterProxy.componentRequester.value = null
|
||||||
|
scanFailsRequesterProxy.componentRequester.value = null
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
package com.tangem.domain.features.addCustomToken
|
|
||||||
|
|
||||||
import com.tangem.blockchain.common.Blockchain
|
|
||||||
import com.tangem.blockchain.common.Token
|
|
||||||
import com.tangem.crypto.hdWallet.DerivationPath
|
|
||||||
|
|
||||||
/**
|
|
||||||
[REDACTED_AUTHOR]
|
|
||||||
*/
|
|
||||||
sealed class CustomCurrency(
|
|
||||||
val network: Blockchain,
|
|
||||||
val derivationPath: DerivationPath?,
|
|
||||||
) {
|
|
||||||
|
|
||||||
@Deprecated("It will be removed in next releases")
|
|
||||||
class CustomBlockchain(
|
|
||||||
network: Blockchain,
|
|
||||||
derivationPath: DerivationPath?,
|
|
||||||
) : CustomCurrency(network, derivationPath)
|
|
||||||
|
|
||||||
@Deprecated("It will be removed in next releases")
|
|
||||||
class CustomToken(
|
|
||||||
val token: Token,
|
|
||||||
network: Blockchain,
|
|
||||||
derivationPath: DerivationPath?,
|
|
||||||
) : CustomCurrency(network, derivationPath)
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package com.tangem.domain.redux
|
|
||||||
|
|
||||||
import org.rekotlin.Action
|
|
||||||
|
|
||||||
sealed class OnboardingManageTokensAction : Action {
|
|
||||||
data object CurrenciesSaved : OnboardingManageTokensAction()
|
|
||||||
}
|
|
||||||
|
|
@ -13,8 +13,6 @@ import com.tangem.core.ui.event.triggeredEvent
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.core.ui.extensions.stringReference
|
import com.tangem.core.ui.extensions.stringReference
|
||||||
import com.tangem.core.ui.message.SnackbarMessage
|
import com.tangem.core.ui.message.SnackbarMessage
|
||||||
import com.tangem.domain.redux.OnboardingManageTokensAction
|
|
||||||
import com.tangem.domain.redux.ReduxStateHolder
|
|
||||||
import com.tangem.features.managetokens.analytics.ManageTokensAnalyticEvent
|
import com.tangem.features.managetokens.analytics.ManageTokensAnalyticEvent
|
||||||
import com.tangem.features.managetokens.component.ManageTokensMode
|
import com.tangem.features.managetokens.component.ManageTokensMode
|
||||||
import com.tangem.features.managetokens.component.ManageTokensSource
|
import com.tangem.features.managetokens.component.ManageTokensSource
|
||||||
|
|
@ -41,7 +39,6 @@ import javax.inject.Inject
|
||||||
internal class OnboardingManageTokensModel @Inject constructor(
|
internal class OnboardingManageTokensModel @Inject constructor(
|
||||||
override val dispatchers: CoroutineDispatcherProvider,
|
override val dispatchers: CoroutineDispatcherProvider,
|
||||||
private val messageSender: UiMessageSender,
|
private val messageSender: UiMessageSender,
|
||||||
private val reduxStateHolder: ReduxStateHolder,
|
|
||||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||||
manageTokensListManagerFactory: ManageTokensListManager.Factory,
|
manageTokensListManagerFactory: ManageTokensListManager.Factory,
|
||||||
manageTokensUseCasesFacadeFactory: ManageTokensUseCasesFacade.Factory,
|
manageTokensUseCasesFacadeFactory: ManageTokensUseCasesFacade.Factory,
|
||||||
|
|
@ -294,10 +291,6 @@ internal class OnboardingManageTokensModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun returnToParentComponent() {
|
private fun returnToParentComponent() {
|
||||||
// old onboarding
|
|
||||||
reduxStateHolder.dispatch(OnboardingManageTokensAction.CurrenciesSaved)
|
|
||||||
|
|
||||||
// new one
|
|
||||||
modelScope.launch {
|
modelScope.launch {
|
||||||
returnToParentComponentFlow.emit(Unit)
|
returnToParentComponentFlow.emit(Unit)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue