Updated on 2026-08-14
This commit is contained in:
parent
2a1369fce6
commit
5a99de87fb
29 changed files with 194 additions and 47 deletions
|
|
@ -326,6 +326,7 @@ internal class ChildFactory @Inject constructor(
|
|||
amount = route.amount,
|
||||
tag = route.tag,
|
||||
destinationAddress = route.destinationAddress,
|
||||
entryType = route.entryType.toSendEntryType(),
|
||||
),
|
||||
componentFactory = sendComponentFactoryV2,
|
||||
)
|
||||
|
|
@ -687,4 +688,9 @@ internal class ChildFactory @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun AppRoute.Send.EntryType.toSendEntryType(): SendComponent.EntryType = when (this) {
|
||||
AppRoute.Send.EntryType.Manual -> SendComponent.EntryType.Manual
|
||||
AppRoute.Send.EntryType.QR -> SendComponent.EntryType.QR
|
||||
}
|
||||
|
|
@ -68,13 +68,20 @@ sealed class AppRoute(val path: String) : Route {
|
|||
val amount: String? = null,
|
||||
val tag: String? = null,
|
||||
val destinationAddress: String? = null,
|
||||
val entryType: EntryType = EntryType.Manual,
|
||||
) : AppRoute(
|
||||
path = "/send/${userWalletId.stringValue}/${currency.id.value}?" +
|
||||
"&$transactionId" +
|
||||
"&$amount" +
|
||||
"&$tag" +
|
||||
"&$destinationAddress",
|
||||
)
|
||||
) {
|
||||
@Serializable
|
||||
enum class EntryType {
|
||||
Manual,
|
||||
QR,
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Details(
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@ sealed class MainScreenAnalyticsEvent(
|
|||
event = "Notice - Limits Info",
|
||||
)
|
||||
|
||||
class ButtonQrScan : MainScreenAnalyticsEvent(
|
||||
event = "Button - QR Scan",
|
||||
)
|
||||
|
||||
class ButtonExplore : MainScreenAnalyticsEvent(
|
||||
event = "Button - Explore",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,10 @@ internal class Bip321PaymentUriParser(
|
|||
val matchingCurrencies = allCurrencies.filter { it.network.id in matchingNetworkIds }
|
||||
if (matchingCurrencies.isEmpty()) {
|
||||
return PaymentUriParser.ParseResult.RecognizedError(
|
||||
ClassifiedQrContent.Error.UnsupportedNetwork,
|
||||
ClassifiedQrContent.Error.UnsupportedNetwork(
|
||||
raw = qrCode,
|
||||
blockchain = matchingCoins.firstOrNull()?.network?.name,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@ internal class Eip681PaymentUriParser(
|
|||
val matchingCoins = findMatchingCoins(parsed.chainId, coins)
|
||||
if (matchingCoins.isEmpty()) {
|
||||
return PaymentUriParser.ParseResult.RecognizedError(
|
||||
ClassifiedQrContent.Error.UnsupportedNetwork,
|
||||
ClassifiedQrContent.Error.UnsupportedNetwork(
|
||||
raw = qrCode,
|
||||
blockchain = parsed.chainId?.let { blockchainDataProvider.getBlockchainNameByChainId(it) },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +45,10 @@ internal class Eip681PaymentUriParser(
|
|||
PaymentUriParser.ParseResult.Success(result)
|
||||
} else {
|
||||
PaymentUriParser.ParseResult.RecognizedError(
|
||||
ClassifiedQrContent.Error.UnsupportedNetwork,
|
||||
ClassifiedQrContent.Error.UnsupportedNetwork(
|
||||
raw = qrCode,
|
||||
blockchain = matchingCoins.firstOrNull()?.network?.name,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,8 +43,12 @@ internal class QrContentClassifierParser(
|
|||
)
|
||||
}
|
||||
|
||||
if (blockchainDataProvider.isSupportedAddress(qrCode)) {
|
||||
return ClassifiedQrContent.Error.UnsupportedNetwork
|
||||
val supportedBlockchain = blockchainDataProvider.findSupportedBlockchainName(qrCode)
|
||||
if (supportedBlockchain != null) {
|
||||
return ClassifiedQrContent.Error.UnsupportedNetwork(
|
||||
raw = qrCode,
|
||||
blockchain = supportedBlockchain,
|
||||
)
|
||||
}
|
||||
|
||||
return ClassifiedQrContent.Error.Unrecognized(qrCode)
|
||||
|
|
@ -76,7 +80,8 @@ internal class QrContentClassifierParser(
|
|||
fun getShareSchemes(network: Network): List<String>
|
||||
fun validateAddress(network: Network, address: String): Boolean
|
||||
fun getChainId(network: Network): Long?
|
||||
fun isSupportedAddress(address: String): Boolean
|
||||
fun findSupportedBlockchainName(address: String): String?
|
||||
fun getBlockchainNameByChainId(chainId: Long): String?
|
||||
}
|
||||
|
||||
internal class DefaultBlockchainDataProvider : BlockchainDataProvider {
|
||||
|
|
@ -92,12 +97,20 @@ internal class QrContentClassifierParser(
|
|||
return runCatching { network.toBlockchain().getChainId()?.toLong() }.getOrNull()
|
||||
}
|
||||
|
||||
override fun isSupportedAddress(address: String): Boolean {
|
||||
override fun findSupportedBlockchainName(address: String): String? {
|
||||
return Blockchain.entries
|
||||
.filter { !it.isTestnet() }
|
||||
.any { blockchain ->
|
||||
.firstOrNull { blockchain ->
|
||||
runCatching { blockchain.validateAddress(address) }.getOrDefault(false)
|
||||
}
|
||||
}?.fullName
|
||||
}
|
||||
|
||||
override fun getBlockchainNameByChainId(chainId: Long): String? {
|
||||
return Blockchain.entries
|
||||
.filter { !it.isTestnet() }
|
||||
.firstOrNull { blockchain ->
|
||||
runCatching { blockchain.getChainId()?.toLong() == chainId }.getOrDefault(false)
|
||||
}?.fullName
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ internal class Eip681PaymentUriParserTest {
|
|||
private val blockchainDataProvider = mockk<QrContentClassifierParser.BlockchainDataProvider> {
|
||||
every { getShareSchemes(any()) } returns emptyList()
|
||||
every { getChainId(any()) } returns null
|
||||
every { getBlockchainNameByChainId(any()) } returns null
|
||||
}
|
||||
private val parser = Eip681PaymentUriParser(blockchainDataProvider)
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ internal class QrContentClassifierTest {
|
|||
every { getShareSchemes(any()) } returns emptyList()
|
||||
every { validateAddress(any(), any()) } returns false
|
||||
every { getChainId(any()) } returns null
|
||||
every { isSupportedAddress(any()) } returns false
|
||||
every { findSupportedBlockchainName(any()) } returns null
|
||||
every { getBlockchainNameByChainId(any()) } returns null
|
||||
}
|
||||
private val paymentUriParser = mockk<PaymentUriParser> {
|
||||
every { parse(any(), any(), any()) } returns PaymentUriParser.ParseResult.NotRecognized
|
||||
|
|
|
|||
|
|
@ -41,13 +41,17 @@ internal class DefaultWcPairUseCase @AssistedInject constructor(
|
|||
|
||||
@Suppress("LongMethod")
|
||||
override operator fun invoke(): Flow<WcPairState> {
|
||||
val (uri: String, source: WcPairRequest.Source) = pairRequest
|
||||
return flow {
|
||||
Timber.tag(WC_TAG).i("start pair flow $pairRequest")
|
||||
analytics.send(WcAnalyticEvents.NewPairInitiated(source))
|
||||
analytics.send(
|
||||
WcAnalyticEvents.NewPairInitiated(
|
||||
source = pairRequest.source,
|
||||
screen = pairRequest.screen,
|
||||
),
|
||||
)
|
||||
emit(WcPairState.Loading)
|
||||
|
||||
val pairResult = sdkDelegate.pair(uri)
|
||||
val pairResult = sdkDelegate.pair(pairRequest.uri)
|
||||
.onLeft {
|
||||
Timber.tag(WC_TAG).e(it, "Failed to call pair $pairRequest")
|
||||
analytics.send(
|
||||
|
|
|
|||
|
|
@ -3,28 +3,31 @@ package com.tangem.domain.qrscanning.models
|
|||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import java.math.BigDecimal
|
||||
|
||||
sealed class ClassifiedQrContent {
|
||||
sealed interface ClassifiedQrContent {
|
||||
|
||||
data class WalletConnect(val uri: String) : ClassifiedQrContent()
|
||||
data class WalletConnect(val uri: String) : ClassifiedQrContent
|
||||
|
||||
data class PaymentUri(
|
||||
val address: String,
|
||||
val amount: BigDecimal?,
|
||||
val memo: String?,
|
||||
val matchingCurrencies: List<CryptoCurrency>,
|
||||
) : ClassifiedQrContent()
|
||||
) : ClassifiedQrContent
|
||||
|
||||
data class PlainAddress(
|
||||
val address: String,
|
||||
val matchingCurrencies: List<CryptoCurrency>,
|
||||
) : ClassifiedQrContent()
|
||||
) : ClassifiedQrContent
|
||||
|
||||
sealed class Error : ClassifiedQrContent() {
|
||||
sealed interface Error : ClassifiedQrContent {
|
||||
|
||||
/** QR code not recognized by any parser */
|
||||
data class Unrecognized(val raw: String) : Error()
|
||||
data class Unrecognized(val raw: String) : Error
|
||||
|
||||
/** Network or token recognized but not available in user's wallet */
|
||||
data object UnsupportedNetwork : Error()
|
||||
data class UnsupportedNetwork(
|
||||
val raw: String,
|
||||
val blockchain: String?,
|
||||
) : Error
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,12 @@ data class WcPairRequest(
|
|||
val uri: String,
|
||||
val source: Source,
|
||||
val userWalletId: UserWalletId,
|
||||
val screen: Screen? = null,
|
||||
) {
|
||||
enum class Source { QR, DEEPLINK, CLIPBOARD, ETC }
|
||||
|
||||
enum class Screen(val analyticsName: String) {
|
||||
MAIN("Main Screen"),
|
||||
WALLET_CONNECT("Wallet Connect Screen"),
|
||||
}
|
||||
}
|
||||
|
|
@ -22,16 +22,23 @@ sealed class WcAnalyticEvents(
|
|||
|
||||
class ScreenOpened : WcAnalyticEvents(event = "WC Screen Opened"), AppsFlyerIncludedEvent
|
||||
|
||||
class NewPairInitiated(source: WcPairRequest.Source) : WcAnalyticEvents(
|
||||
class NewPairInitiated(
|
||||
source: WcPairRequest.Source,
|
||||
screen: WcPairRequest.Screen?,
|
||||
) : WcAnalyticEvents(
|
||||
event = "Session Initiated",
|
||||
params = mapOf(
|
||||
AnalyticsParam.SOURCE to when (source) {
|
||||
WcPairRequest.Source.QR -> "QR"
|
||||
WcPairRequest.Source.DEEPLINK -> "DeepLink"
|
||||
WcPairRequest.Source.CLIPBOARD -> "Clipboard"
|
||||
WcPairRequest.Source.ETC -> "etc"
|
||||
},
|
||||
),
|
||||
params = buildMap {
|
||||
put(
|
||||
AnalyticsParam.SOURCE,
|
||||
when (source) {
|
||||
WcPairRequest.Source.QR -> "QR"
|
||||
WcPairRequest.Source.DEEPLINK -> "DeepLink"
|
||||
WcPairRequest.Source.CLIPBOARD -> "Clipboard"
|
||||
WcPairRequest.Source.ETC -> "etc"
|
||||
},
|
||||
)
|
||||
screen?.analyticsName?.let { put(SCREEN, it) }
|
||||
},
|
||||
)
|
||||
|
||||
class PairButtonConnect(
|
||||
|
|
@ -289,6 +296,7 @@ sealed class WcAnalyticEvents(
|
|||
|
||||
const val NETWORKS = "Networks"
|
||||
const val DOMAIN_VERIFICATION = "Domain Verification"
|
||||
const val SCREEN = "Screen"
|
||||
const val WC_CATEGORY_NAME = "Wallet Connect"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,15 @@ interface SendComponent : ComposableContentComponent {
|
|||
val amount: String? = null,
|
||||
val tag: String? = null,
|
||||
val destinationAddress: String? = null,
|
||||
val entryType: EntryType = EntryType.Manual,
|
||||
val callback: ModelCallback? = null,
|
||||
)
|
||||
|
||||
enum class EntryType {
|
||||
Manual,
|
||||
QR,
|
||||
}
|
||||
|
||||
interface Factory : ComponentFactory<Params, SendComponent>
|
||||
|
||||
interface ModelCallback {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.BLOCKCHAIN
|
|||
import com.tangem.core.analytics.models.AnalyticsParam.Key.ERROR_CODE
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.SOURCE
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.TYPE
|
||||
import com.tangem.core.analytics.models.AppsFlyerIncludedEvent
|
||||
|
||||
/**
|
||||
|
|
@ -32,11 +33,13 @@ sealed class CommonSendAnalyticEvents(
|
|||
data class AmountScreenOpened(
|
||||
val categoryName: String,
|
||||
val source: CommonSendSource,
|
||||
val type: SendEntryType = SendEntryType.Manual,
|
||||
) : CommonSendAnalyticEvents(
|
||||
category = categoryName,
|
||||
event = "Amount Screen Opened",
|
||||
params = mapOf(
|
||||
SOURCE to source.analyticsName,
|
||||
TYPE to type.analyticsName,
|
||||
),
|
||||
), AppsFlyerIncludedEvent
|
||||
|
||||
|
|
@ -95,6 +98,7 @@ sealed class CommonSendAnalyticEvents(
|
|||
val toDerivationIndex: Int?,
|
||||
val sendBlockchain: String,
|
||||
val sendToken: String,
|
||||
val type: SendEntryType = SendEntryType.Manual,
|
||||
) : CommonSendAnalyticEvents(
|
||||
category = categoryName,
|
||||
event = "Confirm Screen Opened",
|
||||
|
|
@ -108,6 +112,7 @@ sealed class CommonSendAnalyticEvents(
|
|||
"$fromDerivationIndex, $toDerivationIndex",
|
||||
)
|
||||
}
|
||||
put(TYPE, type.analyticsName)
|
||||
},
|
||||
), AppsFlyerIncludedEvent
|
||||
|
||||
|
|
@ -221,6 +226,11 @@ sealed class CommonSendAnalyticEvents(
|
|||
Confirm,
|
||||
}
|
||||
|
||||
enum class SendEntryType(val analyticsName: String) {
|
||||
QR("QR"),
|
||||
Manual("Manually"),
|
||||
}
|
||||
|
||||
enum class CommonSendSource(val analyticsName: String) {
|
||||
Send("Send"),
|
||||
Swap("Swap"),
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package com.tangem.features.send.v2.networkselection.model
|
|||
import androidx.compose.runtime.Stable
|
||||
import com.tangem.common.getTotalCryptoAmount
|
||||
import com.tangem.common.getTotalFiatAmount
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.features.send.v2.send.analytics.SendAnalyticEvents
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
|
|
@ -44,6 +46,7 @@ import javax.inject.Inject
|
|||
internal class NetworkSelectionModel @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val multiAccountStatusListSupplier: MultiAccountStatusListSupplier,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
|
|
@ -51,6 +54,10 @@ internal class NetworkSelectionModel @Inject constructor(
|
|||
|
||||
private val params: NetworkSelectionComponent.Params = paramsContainer.require()
|
||||
|
||||
init {
|
||||
analyticsEventHandler.send(SendAnalyticEvents.ChooseTokenScreenOpened())
|
||||
}
|
||||
|
||||
private val searchQuery = MutableStateFlow("")
|
||||
private val expandedWallets = MutableStateFlow(
|
||||
params.walletGroups.firstOrNull()
|
||||
|
|
@ -227,7 +234,15 @@ internal class NetworkSelectionModel @Inject constructor(
|
|||
text = cryptoAmount.format { crypto(currency) },
|
||||
isFlickering = isFlickering,
|
||||
),
|
||||
onItemClick = { params.onTokenSelected(context.userWalletId, currency) },
|
||||
onItemClick = {
|
||||
analyticsEventHandler.send(
|
||||
SendAnalyticEvents.TokenSelected(
|
||||
token = currency.symbol,
|
||||
blockchain = currency.network.name,
|
||||
),
|
||||
)
|
||||
params.onTokenSelected(context.userWalletId, currency)
|
||||
},
|
||||
onItemLongClick = null,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
|
|||
sendToken = fromCurrency.symbol,
|
||||
fromDerivationIndex = fromDerivationIndex,
|
||||
toDerivationIndex = null,
|
||||
type = model.consumeEntryType(),
|
||||
),
|
||||
)
|
||||
if (model.currentRoute.value.isEditMode) {
|
||||
|
|
@ -116,6 +117,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
|
|||
CommonSendAnalyticEvents.AmountScreenOpened(
|
||||
categoryName = model.analyticCategoryName,
|
||||
source = model.analyticsSendSource,
|
||||
type = model.consumeEntryType(),
|
||||
),
|
||||
)
|
||||
activeComponent.updateState(model.uiState.value.amountUM)
|
||||
|
|
|
|||
|
|
@ -50,6 +50,21 @@ internal sealed class SendAnalyticEvents(
|
|||
},
|
||||
), AppsFlyerIncludedEvent
|
||||
|
||||
class ChooseTokenScreenOpened : SendAnalyticEvents(
|
||||
event = "Choose Token Screen Opened",
|
||||
)
|
||||
|
||||
class TokenSelected(
|
||||
val token: String,
|
||||
val blockchain: String,
|
||||
) : SendAnalyticEvents(
|
||||
event = "Token Selected",
|
||||
params = mapOf(
|
||||
TOKEN_PARAM to token,
|
||||
BLOCKCHAIN to blockchain,
|
||||
),
|
||||
)
|
||||
|
||||
data class ConvertTokenButtonClicked(
|
||||
val token: String,
|
||||
val blockchain: String,
|
||||
|
|
|
|||
|
|
@ -105,6 +105,8 @@ internal class SendModel @Inject constructor(
|
|||
private val params: SendComponent.Params = paramsContainer.require()
|
||||
private val cryptoCurrency = params.currency
|
||||
|
||||
private var isEntryTypeConsumed = false
|
||||
|
||||
val analyticCategoryName = CommonSendAnalyticEvents.SEND_CATEGORY
|
||||
val analyticsSendSource = CommonSendAnalyticEvents.CommonSendSource.Send
|
||||
|
||||
|
|
@ -264,6 +266,15 @@ internal class SendModel @Inject constructor(
|
|||
showAlertError()
|
||||
}
|
||||
|
||||
fun consumeEntryType(): CommonSendAnalyticEvents.SendEntryType {
|
||||
if (isEntryTypeConsumed) return CommonSendAnalyticEvents.SendEntryType.Manual
|
||||
isEntryTypeConsumed = true
|
||||
return when (params.entryType) {
|
||||
SendComponent.EntryType.QR -> CommonSendAnalyticEvents.SendEntryType.QR
|
||||
SendComponent.EntryType.Manual -> CommonSendAnalyticEvents.SendEntryType.Manual
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun prepareTransferTransaction(): Either<Throwable, TransactionData> {
|
||||
val predefinedValues = predefinedValues
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusFlow.value
|
||||
|
|
|
|||
|
|
@ -202,6 +202,7 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
address = dialogConfig.address,
|
||||
amount = dialogConfig.amount?.parseBigDecimal(currency.decimals),
|
||||
tag = dialogConfig.memo,
|
||||
entryType = AppRoute.Send.EntryType.Manual,
|
||||
)
|
||||
},
|
||||
onDismiss = model.innerWalletRouter.dialogNavigation::dismiss,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.compose.runtime.Stable
|
|||
import arrow.core.getOrElse
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.arkivanov.decompose.router.slot.dismiss
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
|
|
@ -767,6 +768,7 @@ internal class WalletModel @Inject constructor(
|
|||
userWalletId = stateHolder.getSelectedWalletId(),
|
||||
uri = target.uri,
|
||||
source = source,
|
||||
screen = WcPairRequest.Screen.MAIN,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -777,6 +779,7 @@ internal class WalletModel @Inject constructor(
|
|||
address = target.address,
|
||||
amount = target.amount?.parseBigDecimal(target.currency.decimals),
|
||||
tag = target.memo,
|
||||
entryType = AppRoute.Send.EntryType.QR,
|
||||
)
|
||||
}
|
||||
is QrSendTarget.Multiple -> {
|
||||
|
|
@ -789,9 +792,17 @@ internal class WalletModel @Inject constructor(
|
|||
private fun handleQrError(error: ClassifiedQrContent.Error) {
|
||||
when (error) {
|
||||
is ClassifiedQrContent.Error.Unrecognized -> {
|
||||
analyticsEventsHandler.send(
|
||||
WalletScreenAnalyticsEvent.MainScreen.NoticeUnrecognizedQr(),
|
||||
)
|
||||
uiMessageSender.send(WalletAlertUM.qrCodeUnrecognized())
|
||||
}
|
||||
is ClassifiedQrContent.Error.UnsupportedNetwork -> {
|
||||
analyticsEventsHandler.send(
|
||||
WalletScreenAnalyticsEvent.MainScreen.NoticeNoAvailableTokens(
|
||||
blockchain = error.blockchain,
|
||||
),
|
||||
)
|
||||
uiMessageSender.send(WalletAlertUM.qrCodeUnsupportedNetwork())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -382,6 +382,7 @@ internal class WalletContentClickIntentsImplementor @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onScanQrClick() {
|
||||
analyticsEventHandler.send(MainScreenAnalyticsEvent.ButtonQrScan())
|
||||
router.openQrScanner()
|
||||
}
|
||||
}
|
||||
|
|
@ -186,6 +186,7 @@ internal class DefaultWalletRouter @Inject constructor(
|
|||
address: String,
|
||||
amount: String?,
|
||||
tag: String?,
|
||||
entryType: AppRoute.Send.EntryType,
|
||||
) {
|
||||
router.push(
|
||||
AppRoute.Send(
|
||||
|
|
@ -194,6 +195,7 @@ internal class DefaultWalletRouter @Inject constructor(
|
|||
destinationAddress = address,
|
||||
amount = amount,
|
||||
tag = tag,
|
||||
entryType = entryType,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,14 @@ internal interface InnerWalletRouter {
|
|||
fun openQrScanner()
|
||||
|
||||
/** Open send screen with prefilled destination */
|
||||
fun openSend(userWalletId: UserWalletId, currency: CryptoCurrency, address: String, amount: String?, tag: String?)
|
||||
fun openSend(
|
||||
userWalletId: UserWalletId,
|
||||
currency: CryptoCurrency,
|
||||
address: String,
|
||||
amount: String?,
|
||||
tag: String?,
|
||||
entryType: AppRoute.Send.EntryType = AppRoute.Send.EntryType.Manual,
|
||||
)
|
||||
|
||||
/** Open network selection bottom sheet for multiple QR matches */
|
||||
fun openNetworkSelectionBottomSheet(target: QrSendTarget.Multiple)
|
||||
|
|
|
|||
|
|
@ -167,6 +167,17 @@ sealed class WalletScreenAnalyticsEvent {
|
|||
|
||||
class NoticeSeedPhraseSupportButtonDeclined : MainScreen(event = "Button - Support Declined")
|
||||
|
||||
class NoticeUnrecognizedQr : MainScreen(
|
||||
event = "Notice - Unrecognized QR",
|
||||
)
|
||||
|
||||
class NoticeNoAvailableTokens(blockchain: String?) : MainScreen(
|
||||
event = "Notice - No Available Tokens",
|
||||
params = buildMap {
|
||||
if (blockchain != null) put("Blockchain", blockchain)
|
||||
},
|
||||
)
|
||||
|
||||
// region Referral Promo
|
||||
class ReferralPromo : MainScreen(event = "Referral Banner")
|
||||
class ReferralPromoButtonParticipate : MainScreen(event = "Button - Referral Participate")
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import com.tangem.core.decompose.navigation.inner.InnerRouter
|
|||
import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheetUM
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.walletconnect.model.WcPairRequest
|
||||
import com.tangem.features.account.PortfolioSelectorComponent
|
||||
import com.tangem.features.walletconnect.connections.model.WcPairModel
|
||||
|
|
@ -127,5 +126,7 @@ internal class WcPairComponent(
|
|||
}
|
||||
}
|
||||
|
||||
data class Params(val userWalletId: UserWalletId, val wcUrl: String, val source: WcPairRequest.Source)
|
||||
data class Params(
|
||||
val request: WcPairRequest,
|
||||
)
|
||||
}
|
||||
|
|
@ -86,6 +86,7 @@ internal class WcConnectionsModel @Inject constructor(
|
|||
userWalletId = params.userWalletId,
|
||||
uri = result.qrCode,
|
||||
source = source,
|
||||
screen = WcPairRequest.Screen.WALLET_CONNECT,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import com.tangem.domain.models.wallet.UserWallet
|
|||
import com.tangem.domain.walletconnect.WcAnalyticEvents
|
||||
import com.tangem.domain.walletconnect.model.WcPairError
|
||||
import com.tangem.domain.walletconnect.model.WcPairError.Unknown
|
||||
import com.tangem.domain.walletconnect.model.WcPairRequest
|
||||
import com.tangem.domain.walletconnect.model.WcSessionApprove
|
||||
import com.tangem.domain.walletconnect.model.WcSessionProposal
|
||||
import com.tangem.domain.walletconnect.model.sdkcopy.WcAppMetaData
|
||||
|
|
@ -75,13 +74,7 @@ internal class WcPairModel @Inject constructor(
|
|||
) : Model(), WcPairComponentCallback {
|
||||
|
||||
private val params: WcPairComponent.Params = paramsContainer.require()
|
||||
private val wcPairUseCase = wcPairUseCaseFactory.create(
|
||||
WcPairRequest(
|
||||
userWalletId = params.userWalletId,
|
||||
uri = params.wcUrl,
|
||||
source = params.source,
|
||||
),
|
||||
)
|
||||
private val wcPairUseCase = wcPairUseCaseFactory.create(params.request)
|
||||
|
||||
val stackNavigation = StackNavigation<WcAppInfoRoutes>()
|
||||
val portfolioFetcher: PortfolioFetcher = portfolioFetcherFactory.create(
|
||||
|
|
@ -109,7 +102,7 @@ internal class WcPairModel @Inject constructor(
|
|||
modelScope.launch {
|
||||
val portfolioBalance = portfolioFetcher.data.first().balances
|
||||
.firstNotNullOfOrNull { (walletId, balance) ->
|
||||
if (params.userWalletId == walletId) balance else null
|
||||
if (params.request.userWalletId == walletId) balance else null
|
||||
}
|
||||
if (portfolioBalance == null) {
|
||||
router.pop()
|
||||
|
|
|
|||
|
|
@ -89,9 +89,7 @@ internal class DefaultWcRoutingComponent @AssistedInject constructor(
|
|||
appComponentContext = childContext,
|
||||
portfolioSelectorComponentFactory = portfolioSelectorComponentFactory,
|
||||
params = WcPairComponent.Params(
|
||||
userWalletId = config.request.userWalletId,
|
||||
wcUrl = config.request.uri,
|
||||
source = config.request.source,
|
||||
request = config.request,
|
||||
),
|
||||
)
|
||||
is WcInnerRoute.UnsupportedMethodAlert -> AlertsComponent(
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# https://github.com/tangem/tangem-sdk-android/
|
||||
# https://github.com/tangem/vico
|
||||
|
||||
tangemBlockchainSdk = "develop-1454"
|
||||
tangemBlockchainSdk = "develop-1455"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "develop-598"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue