feat: Transaction deep link sharing

This commit is contained in:
Emil Sawicki 2024-10-14 06:36:03 +02:00
parent 03db15529e
commit aefe804dc4
30 changed files with 280 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
@ -404,3 +405,6 @@ method splitAndFormatAddressPrefix*(self: Module, text : string, updateInStore:
method transactionSendingComplete*(self: Module, txHash: string, status: string) =
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,41 @@
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
font.weight: Font.Normal
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

@ -44,6 +44,7 @@ import AppLayouts.Chat.stores 1.0 as ChatStores
import AppLayouts.Communities.stores 1.0
import AppLayouts.Wallet.stores 1.0 as WalletStores
import AppLayouts.Wallet.popups 1.0 as WalletPopups
import AppLayouts.Wallet.popups.swap 1.0 as WalletSwapPopups
import mainui.activitycenter.stores 1.0
import mainui.activitycenter.popups 1.0
@ -93,6 +94,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
@ -386,11 +388,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() {
@ -426,6 +464,7 @@ Item {
buyCryptoStore: appMain.buyCryptoStore
networkConnectionStore: appMain.networkConnectionStore
isDevBuild: !production
transactionDeepLinkEnabled: appMain.featureFlagsStore.transactionDeepLinkEnabled
onOpenExternalLink: globalConns.onOpenLink(link)
onSaveDomainToUnfurledWhitelist: {
@ -1369,6 +1408,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);
@ -1519,6 +1559,7 @@ Item {
transactionStore: appMain.transactionStore
walletAssetsStore: appMain.walletAssetsStore
currencyStore: appMain.currencyStore
transactionDeepLinkEnabled: featureFlagsStore.transactionDeepLinkEnabled && appMain.networkConnectionStore.sendBuyBridgeEnabled
onProfileButtonClicked: {
Global.changeAppSectionBySectionType(Constants.appSection.profile);
@ -1633,6 +1674,7 @@ Item {
collectiblesStore: appMain.walletCollectiblesStore
showCustomRoutingMode: !production
transactionDeepLinkEnabled: featureFlagsStore.transactionDeepLinkEnabled
onClosed: {
sendModal.closed()

View File

@ -50,6 +50,7 @@ QtObject {
property NetworkConnectionStore networkConnectionStore
property WalletStore.BuyCryptoStore buyCryptoStore
property bool isDevBuild
property bool transactionDeepLinkEnabled
signal openExternalLink(string link)
signal saveDomainToUnfurledWhitelist(string domain)
@ -1249,6 +1250,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,11 +760,14 @@ 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
}
Global.activateDeepLink(link)
}

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, '');
}