feat: Transaction deep link sharing

This commit is contained in:
Emil Sawicki 2024-10-14 06:36:03 +02:00
parent 5d12440562
commit 2000e112e6
31 changed files with 279 additions and 6 deletions

View File

@ -5,6 +5,7 @@ const DEFAULT_FLAG_DAPPS_ENABLED = false
const DEFAULT_FLAG_SWAP_ENABLED = true
const DEFAULT_FLAG_CONNECTOR_ENABLED* = false
const DEFAULT_FLAG_SEND_VIA_PERSONAL_CHAT_ENABLED = true
const DEFAULT_FLAG_TRANSACTION_DEEP_LINK_ENABLED = false
proc boolToEnv*(defaultValue: bool): string =
return if defaultValue: "1" else: "0"
@ -15,6 +16,7 @@ QtObject:
swapEnabled: bool
connectorEnabled: bool
sendViaPersonalChatEnabled: bool
transactionDeepLinkEnabled: bool
proc setup(self: FeatureFlags) =
self.QObject.setup()
@ -22,6 +24,7 @@ QtObject:
self.swapEnabled = getEnv("FLAG_SWAP_ENABLED", boolToEnv(DEFAULT_FLAG_SWAP_ENABLED)) != "0"
self.connectorEnabled = getEnv("FLAG_CONNECTOR_ENABLED", boolToEnv(DEFAULT_FLAG_CONNECTOR_ENABLED)) != "0"
self.sendViaPersonalChatEnabled = getEnv("FLAG_SEND_VIA_PERSONAL_CHAT_ENABLED", boolToEnv(DEFAULT_FLAG_SEND_VIA_PERSONAL_CHAT_ENABLED)) != "0"
self.transactionDeepLinkEnabled = getEnv("FLAG_TRANSACTION_DEEP_LINK_ENABLED", boolToEnv(DEFAULT_FLAG_TRANSACTION_DEEP_LINK_ENABLED)) != "0"
proc delete*(self: FeatureFlags) =
self.QObject.delete()
@ -53,3 +56,9 @@ QtObject:
QtProperty[bool] sendViaPersonalChatEnabled:
read = getSendViaPersonalChatEnabled
proc getTransactionDeepLinkEnabled*(self: FeatureFlags): bool {.slot.} =
return self.transactionDeepLinkEnabled
QtProperty[bool] transactionDeepLinkEnabled:
read = getTransactionDeepLinkEnabled

View File

@ -1657,6 +1657,8 @@ method activateStatusDeepLink*[T](self: Module[T], statusDeepLink: string) =
self.onStatusUrlRequested(StatusUrlAction.DisplayUserProfile, communityId="", channelId="", url="",
urlData.contact.publicKey, urlData.community.shard)
return
if urlData.transaction.txType >= 0:
self.view.emitShowTransactionModal(urlData.transaction.txType, urlData.transaction.asset, urlData.transaction.amount, urlData.transaction.address, urlData.transaction.chainId, urlData.transaction.toAsset)
method onDeactivateChatLoader*[T](self: Module[T], sectionId: string, chatId: string) =
if (sectionId.len > 0 and self.chatSectionModules.contains(sectionId)):

View File

@ -37,3 +37,7 @@ proc parseContactSharedUrl*(self: Controller, url: string): ContactUrlDataDto =
proc parseSharedUrl*(self: Controller, url: string): UrlDataDto =
return self.sharedUrlsService.parseSharedUrl(url)
proc parseTransactionSharedUrl*(self: Controller, url: string): TransactionUrlDataDto =
let data = self.sharedUrlsService.parseSharedUrl(url)
return data.transaction

View File

@ -27,6 +27,9 @@ method parseContactSharedUrl*(self: AccessInterface, url: string): string {.base
method parseSharedUrl*(self: AccessInterface, url: string): UrlDataDto {.base.} =
raise newException(ValueError, "No implementation available")
method parseTransactionSharedUrl*(self: AccessInterface, url: string): string {.base.} =
raise newException(ValueError, "No implementation available")
# This way (using concepts) is used only for the modules managed by AppController
type
DelegateInterface* = concept c

View File

@ -63,3 +63,7 @@ method parseCommunityChannelSharedUrl*(self: Module, url: string): string =
method parseContactSharedUrl*(self: Module, url: string): string =
let contactData = self.controller.parseContactSharedUrl(url)
return $contactData
method parseTransactionSharedUrl*(self: Module, url: string): string =
let transactionData = self.controller.parseTransactionSharedUrl(url)
return $transactionData

View File

@ -25,4 +25,7 @@ QtObject:
return self.delegate.parseCommunityChannelSharedUrl(url)
proc parseContactSharedUrl*(self: View, url: string): string {.slot.} =
return self.delegate.parseContactSharedUrl(url)
return self.delegate.parseContactSharedUrl(url)
proc parseTransactionSharedUrl*(self: View, url: string): string {.slot.} =
return self.delegate.parseTransactionSharedUrl(url)

View File

@ -382,3 +382,8 @@ QtObject:
proc stopTokenHoldersManagement*(self: View) {.slot.} =
self.delegate.stopTokenHoldersManagement()
proc showTransactionModal*(self: View, txType: int, asset: string, amount: string, address: string, chainId: int, toAsset: string) {.signal.}
proc emitShowTransactionModal*(self: View, txType: int, asset: string, amount: string, address: string, chainId: int, toAsset: string) =
self.showTransactionModal(txType, asset, amount, address, chainId, toAsset)

View File

@ -8,6 +8,7 @@ import app_service/service/currency/service as currency_service
import app_service/service/currency/dto as currency_dto
import app_service/service/keycard/service as keycard_service
import app_service/service/network/network_item
import app_service/service/shared_urls/dto/url_data as shared_urls_dto
import app/modules/shared_modules/keycard_popup/io_interface as keycard_shared_module
import app/modules/shared/wallet_utils
@ -137,6 +138,9 @@ proc signMessage*(self: Controller, address: string, hashedPassword: string, has
proc sendRouterTransactionsWithSignatures*(self: Controller, uuid: string, signatures: TransactionsSignatures): string =
return self.transactionService.sendRouterTransactionsWithSignatures(uuid, signatures)
proc shareTransactionURL*(self: Controller, urlData: shared_urls_dto.TransactionURLDataDto): string =
return self.transactionService.shareTransactionURL(urlData)
proc areTestNetworksEnabled*(self: Controller): bool =
return self.walletAccountService.areTestNetworksEnabled()

View File

@ -2,6 +2,7 @@ import Tables
import app/modules/shared_models/currency_amount
import app_service/service/transaction/dto
import app_service/service/transaction/router_transactions_dto
import app_service/service/shared_urls/dto/url_data
import app_service/service/network/network_item
import app/modules/shared_models/collectibles_model as collectibles
from app_service/service/keycard/service import KeycardEvent
@ -90,4 +91,7 @@ method getNetworkItem*(self: AccessInterface, chainId: int): NetworkItem {.base.
raise newException(ValueError, "No implementation available")
method getNetworkChainId*(self: AccessInterface, shortName: string): int {.base.} =
raise newException(ValueError, "No implementation available")
method shareTransactionURL*(self: AccessInterface, urlData: TransactionURLDataDto): string {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -14,6 +14,7 @@ import app_service/service/transaction/service as transaction_service
import app_service/service/keycard/service as keycard_service
import app_service/service/keycard/constants as keycard_constants
import app_service/service/transaction/dto
import app_service/service/shared_urls/dto/url_data as shared_urls_dto
import app/modules/shared_models/currency_amount
import app_service/service/network/network_item as network_service_item
@ -410,3 +411,6 @@ method splitAndFormatAddressPrefix*(self: Module, text : string, updateInStore:
method transactionSendingComplete*(self: Module, txHash: string, status: string) =
self.clearTmpData(self.tmpKeepPinPass)
self.view.sendtransactionSendingCompleteSignal(txHash, status)
method shareTransactionURL*(self: Module, urlData: shared_urls_dto.TransactionURLDataDto): string =
return self.controller.shareTransactionURL(urlData)

View File

@ -3,6 +3,7 @@ import NimQml, Tables, json, sequtils, strutils, stint, chronicles
import ./io_interface, ./network_route_model, ./network_route_item, ./suggested_route_item, ./transaction_routes
import app_service/service/network/service as network_service
import app_service/service/transaction/dto as transaction_dto
import app_service/service/shared_urls/dto/url_data as shared_urls_dto
import app_service/common/utils as common_utils
import app_service/service/eth/utils as eth_utils
@ -287,6 +288,16 @@ QtObject:
parseChainIds(disabledToChainIDs),
lockedInAmountsTable)
proc shareTransactionURL*(self: View, txType: int, asset: string, amount: string, address: string, chainId: int, toAsset: string): string {.slot.} =
return self.delegate.shareTransactionURL(shared_urls_dto.TransactionURLDataDto(
txType: txType,
asset: asset,
amount: amount,
address: address,
chainId: chainId,
toAsset: toAsset
))
proc transactionSendingComplete*(self: View, txHash: string, status: string) {.signal.}
proc sendtransactionSendingCompleteSignal*(self: View, txHash: string, status: string) =
self.transactionSendingComplete(txHash, status)

View File

@ -25,10 +25,19 @@ type ContactUrlDataDto* = object
description*: string
publicKey*: string
type TransactionURLDataDto* = object
txType*: int
asset*: string
amount*: string
address*: string
chainId*: int
toAsset*: string
type UrlDataDto* = object
community*: CommunityUrlDataDto
channel*: CommunityChannelUrlDataDto
contact*: ContactUrlDataDto
transaction*: TransactionURLDataDto
notASupportedStatusLink*: bool # If this is true, it was not a supported status link, so we should open it in a browser
proc getShard*(jsonObj: JsonNode): Shard =
@ -69,8 +78,18 @@ proc toContactUrlDataDto*(jsonObj: JsonNode): ContactUrlDataDto =
discard jsonObj.getProp("description", result.description)
discard jsonObj.getProp("publicKey", result.publicKey)
proc toTransactionUrlDataDto*(jsonObj: JsonNode): TransactionURLDataDto =
result = TransactionURLDataDto()
discard jsonObj.getProp("txType", result.txType)
discard jsonObj.getProp("asset", result.asset)
discard jsonObj.getProp("amount", result.amount)
discard jsonObj.getProp("address", result.address)
discard jsonObj.getProp("chainId", result.chainId)
discard jsonObj.getProp("toAsset", result.toAsset)
proc toUrlDataDto*(jsonObj: JsonNode): UrlDataDto =
result = UrlDataDto()
result.transaction.txType = -1
var communityObj: JsonNode
if (jsonObj.getProp("community", communityObj)):
@ -84,6 +103,10 @@ proc toUrlDataDto*(jsonObj: JsonNode): UrlDataDto =
if (jsonObj.getProp("contact", contactObj)):
result.contact = contactObj.toContactUrlDataDto()
var txObj: JsonNode
if (jsonObj.getProp("tx", txObj)):
result.transaction = txObj.toTransactionUrlDataDto()
proc toJsonNode*(communityUrlDataDto: CommunityUrlDataDto): JsonNode =
var jsonObj = newJObject()
jsonObj["displayName"] = %* communityUrlDataDto.displayName
@ -113,3 +136,16 @@ proc `$`*(contactUrlDataDto: ContactUrlDataDto): string =
jsonObj["description"] = %* contactUrlDataDto.description
jsonObj["publicKey"] = %* contactUrlDataDto.publicKey
return $jsonObj
proc `%`*(transactionURLData: TransactionURLDataDto): JsonNode =
return %* [{
"txType": transactionURLData.txType,
"asset": transactionURLData.asset,
"amount": transactionURLData.amount,
"address": transactionURLData.address,
"chainId": transactionURLData.chainId,
"toAsset": transactionURLData.toAsset,
}]
proc `$`*(transactionURLData: TransactionURLDataDto): string =
return $(%transactionURLData)

View File

@ -19,6 +19,7 @@ import app_service/service/wallet_account/service as wallet_account_service
import app_service/service/network/service as network_service
import app_service/service/token/service as token_service
import app_service/service/settings/service as settings_service
import app_service/service/shared_urls/dto/url_data as shared_urls_dto
import ./dto as transaction_dto
import ./dtoV2
import ./dto_conversion
@ -504,3 +505,14 @@ proc sendRouterTransactionsWithSignatures*(self: Service, uuid: string, signatur
error "unexpected sending transactions response"
return "unexpected sending transactions response"
return ""
proc shareTransactionURL*(self: Service, urlData: shared_urls_dto.TransactionURLDataDto): string =
try:
let response = transactions.shareTransactionURL(%urlData)
if response.error != nil:
error "Error sharing transaction url. Error: ", message = response.error
return ""
return response.result.getStr
except Exception as e:
error "Error sharing transaction url", message = e.msg
return ""

View File

@ -1,4 +1,5 @@
import Tables, json, stint, json_serialization, stew/shims/strformat, logging
import ../app_service/common/utils
import ./core as core
@ -117,4 +118,7 @@ proc sendRouterTransactionsWithSignatures*(resultOut: var JsonNode, uuid: string
return prepareResponse(resultOut, response)
except Exception as e:
warn e.msg
return e.msg
return e.msg
proc shareTransactionURL*(urlData: JsonNode): RpcResponse[JsonNode] =
return callPrivateRPC("shareTransactionURL".prefix, urlData)

View File

@ -47,6 +47,7 @@ StackLayout {
property bool communitySettingsDisabled
property bool sendViaPersonalChatEnabled
property bool transactionDeepLinkEnabled
property var emojiPopup
property var stickersPopup
@ -163,6 +164,7 @@ StackLayout {
root.sectionItemModel.memberRole === Constants.memberRole.tokenMaster
hasViewOnlyPermissions: root.permissionsStore.viewOnlyPermissionsModel.count > 0
sendViaPersonalChatEnabled: root.sendViaPersonalChatEnabled
transactionDeepLinkEnabled: root.transactionDeepLinkEnabled
hasUnrestrictedViewOnlyPermission: {
viewOnlyUnrestrictedPermissionHelper.revision

View File

@ -58,6 +58,7 @@ Item {
property bool amISectionAdmin: false
property bool sendViaPersonalChatEnabled
property bool transactionDeepLinkEnabled
signal openStickerPackPopup(string stickerPackId)
@ -243,6 +244,7 @@ Item {
stickersLoaded: root.stickersLoaded
isBlocked: model.blocked
sendViaPersonalChatEnabled: root.sendViaPersonalChatEnabled
transactionDeepLinkEnabled: root.transactionDeepLinkEnabled
onOpenStickerPackPopup: {
root.openStickerPackPopup(stickerPackId)
}

View File

@ -55,6 +55,7 @@ ColumnLayout {
}
property bool sendViaPersonalChatEnabled
property bool transactionDeepLinkEnabled
signal showReplyArea(messageId: string)
signal forceInputFocus()
@ -97,6 +98,7 @@ ColumnLayout {
isChatBlocked: root.isBlocked || !root.isUserAllowedToSendMessage
channelEmoji: !chatContentModule ? "" : (chatContentModule.chatDetails.emoji || "")
sendViaPersonalChatEnabled: root.sendViaPersonalChatEnabled
transactionDeepLinkEnabled: root.transactionDeepLinkEnabled
onShowReplyArea: (messageId, senderId) => {
root.showReplyArea(messageId)
}

View File

@ -49,6 +49,7 @@ Item {
property bool isOneToOne: false
property bool sendViaPersonalChatEnabled
property bool transactionDeepLinkEnabled
signal openStickerPackPopup(string stickerPackId)
signal showReplyArea(string messageId, string author)
@ -284,6 +285,7 @@ Item {
isChatBlocked: root.isChatBlocked
sendViaPersonalChatEnabled: root.sendViaPersonalChatEnabled
transactionDeepLinkEnabled: root.transactionDeepLinkEnabled
chatId: root.chatId
messageId: model.id

View File

@ -76,6 +76,7 @@ StatusSectionLayout {
property var collectiblesModel
property bool sendViaPersonalChatEnabled
property bool transactionDeepLinkEnabled
readonly property bool contentLocked: {
if (!rootStore.chatCommunitySectionModule.isCommunity()) {
@ -244,6 +245,7 @@ StatusSectionLayout {
canPost: !root.rootStore.chatCommunitySectionModule.isCommunity() || root.canPost
amISectionAdmin: root.amISectionAdmin
sendViaPersonalChatEnabled: root.sendViaPersonalChatEnabled
transactionDeepLinkEnabled: root.transactionDeepLinkEnabled
onOpenStickerPackPopup: {
Global.openPopup(statusStickerPackClickPopup, {packId: stickerPackId, store: root.stickersPopup.store} )
}

View File

@ -0,0 +1,40 @@
import QtQuick 2.15
import StatusQ.Controls 0.1
StatusButton {
id: root
text: qsTr("Share")
type: StatusBaseButton.Type.Normal
size: StatusBaseButton.Size.Tiny
horizontalPadding: 8
verticalPadding: 3
implicitHeight: 22
radius: 20
font.pixelSize: 12
Timer {
id: shareStateTimer
interval: 2000
repeat: false
}
states: State {
name: "success"
when: shareStateTimer.running
PropertyChanges {
target: shareButton
text: qsTr("Copied")
type: StatusBaseButton.Type.Success
icon.name: "tiny/checkmark"
tooltip.text: qsTr("Copied to clipboard")
}
}
onClicked: {
shareStateTimer.restart()
}
}

View File

@ -25,3 +25,4 @@ SwapProvidersTermsAndConditionsText 1.0 SwapProvidersTermsAndConditionsText.qml
TokenSelector 1.0 TokenSelector.qml
TokenSelectorButton 1.0 TokenSelectorButton.qml
TokenSelectorCompactButton 1.0 TokenSelectorCompactButton.qml
ShareButton 1.0 ShareButton.qml

View File

@ -1,9 +1,10 @@
import QtQml.Models 2.15
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQml.Models 2.15
import utils 1.0
import StatusQ 0.1
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Backpressure 0.1
@ -11,8 +12,8 @@ import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
import StatusQ.Popups.Dialog 0.1
import shared.popups.send.controls 1.0
import shared.controls 1.0
import shared.popups.send.controls 1.0
import AppLayouts.Wallet.controls 1.0
import AppLayouts.Wallet.panels 1.0
@ -27,6 +28,8 @@ StatusDialog {
required property SwapModalAdaptor swapAdaptor
required property int loginType
property bool transactionDeepLinkEnabled
objectName: "swapModal"
implicitWidth: 556
@ -146,6 +149,21 @@ StatusDialog {
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
text: qsTr("Swap")
}
ShareButton {
id: shareButton
visible: root.transactionDeepLinkEnabled
enabled: !!root.swapInputParamsForm.fromTokensKey || !!root.swapInputParamsForm.selectedAccountAddress || !!root.swapInputParamsForm.fromTokenAmount || !!root.swapInputParamsForm.toTokenKey
onClicked: {
const url = root.swapAdaptor.swapStore.getShareTransactionUrl(Constants.SendType.Swap,
root.swapInputParamsForm.fromTokensKey,
root.swapInputParamsForm.fromTokenAmount,
root.swapInputParamsForm.selectedAccountAddress,
root.swapInputParamsForm.selectedNetworkChainId,
root.swapInputParamsForm.toTokenKey)
ClipboardUtils.setText(url)
}
}
StatusBaseText {
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
text: qsTr("On:")

View File

@ -52,4 +52,8 @@ QtObject {
function getWei2Eth(wei, decimals) {
return globalUtils.wei2Eth(wei, decimals)
}
function getShareTransactionUrl(txType, asset, amount, address, chainId, toAsset) {
return walletSectionSendInst.shareTransactionURL(txType, asset, amount, address, chainId, toAsset)
}
}

View File

@ -5,4 +5,5 @@ QtObject {
property bool dappsEnabled
property bool swapEnabled
property bool sendViaPersonalChatEnabled
property bool transactionDeepLinkEnabled
}

View File

@ -45,6 +45,7 @@ import AppLayouts.Profile.stores 1.0 as ProfileStores
import AppLayouts.Wallet.popups 1.0 as WalletPopups
import AppLayouts.Wallet.stores 1.0 as WalletStores
import AppLayouts.stores 1.0 as AppStores
import AppLayouts.Wallet.popups.swap 1.0 as WalletSwapPopups
import mainui.activitycenter.stores 1.0
import mainui.activitycenter.popups 1.0
@ -95,6 +96,7 @@ Item {
dappsEnabled: featureFlags ? featureFlags.dappsEnabled : false
swapEnabled: featureFlags ? featureFlags.swapEnabled : false
sendViaPersonalChatEnabled: featureFlags ? featureFlags.sendViaPersonalChatEnabled : false
transactionDeepLinkEnabled: featureFlags ? featureFlags.transactionDeepLinkEnabled : false
}
required property bool isCentralizedMetricsEnabled
@ -388,11 +390,47 @@ Item {
""
)
}
function onShowTransactionModal(txType, asset, amount, address, chainId, toAsset) {
if (txType === Constants.SendType.Swap) {
d.swapFormData.fromTokensKey = asset
d.swapFormData.toTokenKey = toAsset
d.swapFormData.fromTokenAmount = amount
d.swapFormData.selectedAccountAddress = address
d.swapFormData.selectedNetworkChainId = chainId
Global.openSwapModalRequested(d.swapFormData)
return
}
sendModal.preSelectedSendType = txType
sendModal.preDefinedAmountToSend = amount
sendModal.preSelectedHoldingID = asset
switch(txType) {
case Constants.SendType.ERC721Transfer:
sendModal.preSelectedHoldingType = Constants.TokenType.ERC721
break
case Constants.SendType.ERC1155Transfer:
sendModal.preSelectedHoldingType = Constants.TokenType.ERC1155
break
case Constants.SendType.Transfer:
case Constants.SendType.Bridge:
sendModal.preSelectedHoldingType = Constants.TokenType.ERC20
break
default:
console.error("Unsupported txType: %1 to open transaction modal").arg(txType)
return
}
sendModal.open(address)
}
}
QtObject {
id: d
property WalletSwapPopups.SwapInputParamsForm swapFormData: WalletSwapPopups.SwapInputParamsForm {
selectedAccountAddress: WalletStores.RootStore.selectedAddress
}
property var activityCenterPopupObj: null
function openActivityCenterPopup() {
@ -429,6 +467,7 @@ Item {
buyCryptoStore: appMain.buyCryptoStore
networkConnectionStore: appMain.networkConnectionStore
isDevBuild: !production
transactionDeepLinkEnabled: appMain.featureFlagsStore.transactionDeepLinkEnabled
onOpenExternalLink: globalConns.onOpenLink(link)
onSaveDomainToUnfurledWhitelist: {
@ -1383,6 +1422,7 @@ Item {
emojiPopup: statusEmojiPopup.item
stickersPopup: statusStickersPopupLoader.item
sendViaPersonalChatEnabled: featureFlagsStore.sendViaPersonalChatEnabled && appMain.networkConnectionStore.sendBuyBridgeEnabled
transactionDeepLinkEnabled: featureFlagsStore.transactionDeepLinkEnabled && appMain.networkConnectionStore.sendBuyBridgeEnabled
onProfileButtonClicked: {
Global.changeAppSectionBySectionType(Constants.appSection.profile);
@ -1534,6 +1574,7 @@ Item {
transactionStore: appMain.transactionStore
walletAssetsStore: appMain.walletAssetsStore
currencyStore: appMain.currencyStore
transactionDeepLinkEnabled: featureFlagsStore.transactionDeepLinkEnabled && appMain.networkConnectionStore.sendBuyBridgeEnabled
onProfileButtonClicked: {
Global.changeAppSectionBySectionType(Constants.appSection.profile);
@ -1648,6 +1689,7 @@ Item {
collectiblesStore: appMain.walletCollectiblesStore
showCustomRoutingMode: !production
transactionDeepLinkEnabled: featureFlagsStore.transactionDeepLinkEnabled
onClosed: {
sendModal.closed()

View File

@ -51,6 +51,7 @@ QtObject {
property NetworkConnectionStore networkConnectionStore
property WalletStore.BuyCryptoStore buyCryptoStore
property bool isDevBuild
property bool transactionDeepLinkEnabled
signal openExternalLink(string link)
signal saveDomainToUnfurledWhitelist(string domain)
@ -1253,6 +1254,7 @@ QtObject {
swapFormData: swapInputParamsForm
swapOutputData: SwapOutputData{}
}
transactionDeepLinkEnabled: root.transactionDeepLinkEnabled
loginType: root.rootStore.loginType
onClosed: destroy()
}

View File

@ -64,6 +64,8 @@ StatusDialog {
property int loginType
property bool showCustomRoutingMode
property bool transactionDeepLinkEnabled
// In case selected address is incorrect take first account from the list
readonly property alias selectedAccount: selectedSenderAccountEntry.item
@ -469,6 +471,38 @@ StatusDialog {
amountToSend.forceActiveFocus()
}
}
ShareButton {
id: shareButton
visible: {
if (!popup.transactionDeepLinkEnabled)
return false
switch (store.sendType) {
case Constants.SendType.Bridge:
case Constants.SendType.Transfer:
case Constants.SendType.ERC721Transfer:
case Constants.SendType.ERC1155Transfer:
return true
default:
return false
}
}
enabled: d.isSelectedHoldingValidAsset || (!d.isCollectiblesTransfer && amountToSend.ready) || recipientInputLoader.ready
onClicked: {
let asset = ""
if (!!d.selectedHolding) {
asset = d.isCollectiblesTransfer ? d.selectedHolding.symbol : d.selectedHolding.tokensKey
}
let recipient = ""
if (recipientInputLoader.ready) {
recipient = popup.store.selectedSenderAccountAddress
}
const url = popup.store.getShareTransactionUrl(store.sendType, asset, amountToSend.asNumber, recipient, 0)
ClipboardUtils.setText(url)
}
}
}
RowLayout {
visible: d.isSelectedHoldingValidAsset && !d.isCollectiblesTransfer

View File

@ -157,6 +157,14 @@ QtObject {
}
}
function getShareTransactionUrl(txType, asset, amount, address, chainId) {
return walletSectionSendInst.shareTransactionURL(txType, asset, amount, address, chainId, "")
}
function getShortChainIds(chainShortNames) {
return walletSectionSendInst.getShortChainIds(chainShortNames)
}
function formatCurrencyAmountFromBigInt(balance, symbol, decimals, options = null) {
return currencyStore.formatCurrencyAmountFromBigInt(balance, symbol, decimals, options)
}

View File

@ -135,6 +135,7 @@ Loader {
property bool hasMention: false
property bool sendViaPersonalChatEnabled
property bool transactionDeepLinkEnabled
property bool stickersLoaded: false
property string sticker
@ -759,7 +760,10 @@ Loader {
const linkPreviewType = root.linkPreviewModel.getLinkPreviewType(link)
if (linkPreviewType === Constants.LinkPreviewType.Standard || !Utils.isStatusDeepLink(link)) {
if (linkPreviewType === Constants.LinkPreviewType.Standard
|| !Utils.isStatusDeepLink(link)
|| (!root.transactionDeepLinkEnabled && Utils.isStatusTransactionDeepLink(link)))
{
Global.openLink(link)
return
}

View File

@ -293,6 +293,10 @@ QtObject {
return link.includes(Constants.deepLinkPrefix) || link.includes(Constants.externalStatusLink)
}
function isStatusTransactionDeepLink(link) {
return isStatusDeepLink(link) && link.indexOf("/tx/") > -1
}
function removeGifUrls(message) {
return message.replace(/(?:https?|ftp):\/\/[\n\S]*(\.gif)+/gm, '');
}

@ -1 +1 @@
Subproject commit 0141cab5ef0ec2f21ad0b04413936d08cc6e8265
Subproject commit 984560cfb0b1acd25dbc1055b5de7f6b6fceb548