feat(dapps) implement wallet connect URI input

Other changes

- start Wallet Connect SDK using web engine after wallet is ready
- source WC project ID from the constants in nim
- close list when opening the `ConnectDappModal`
- remove the old POC modal instantiation
- rename ConnectDappPopup to Modal for consistency
- move specific dapps related user settings to their place in the component
- add DAppsStore to be used for dapps abstraction

Updates #14556
This commit is contained in:
Stefan 2024-05-01 18:15:42 +02:00 committed by Stefan Dunca
parent 0de54bb584
commit 1f60410db8
14 changed files with 247 additions and 134 deletions

View File

@ -1,6 +1,6 @@
import NimQml, strutils, os
import ../../constants
import constants
# Local App Settings keys:
const LAS_KEY_LANGUAGE* = "global/language"
@ -207,3 +207,9 @@ QtObject:
of LAS_KEY_FAKE_LOADING_SCREEN_ENABLED: self.fakeLoadingScreenEnabledChanged()
of LAS_KEY_SHARDED_COMMUNITIES_ENABLED: self.wakuV2ShardedCommunitiesEnabledChanged()
of LAS_KEY_TRANSLATIONS_ENABLED: self.translationsEnabledChanged()
proc getWalletConnectProjectID*(self: LocalAppSettings): string {.slot.} =
return constants.WALLET_CONNECT_PROJECT_ID
QtProperty[string] walletConnectProjectID:
read = getWalletConnectProjectID

View File

@ -46,6 +46,7 @@ Button {
property color textHoverColor: textColor
property color disabledTextColor
property color borderColor: "transparent"
property int borderWidth: 0
property bool textFillWidth: false
property int radius: size === StatusBaseButton.Size.Tiny ? 6 : 8
@ -126,6 +127,7 @@ Button {
background: Rectangle {
radius: root.radius
border.color: root.borderColor
border.width: root.borderWidth
color: {
if (!root.enabled || !root.interactive)
return disabledColor

View File

@ -104,6 +104,8 @@ QtObject {
property color white: getColor('white')
property color transparent: "#00000000"
property color green: getColor('green')
property color blue: getColor('blue')
property color darkBlue: getColor('blue2')

View File

@ -90,6 +90,7 @@ StatusButton {
text: qsTr("Connect a dApp via WalletConnect")
onClicked: {
root.connectDapp()
popup.close()
}
}
}

View File

@ -11,6 +11,8 @@ import StatusQ.Popups 0.1
import SortFilterProxyModel 0.2
import shared.popups.walletconnect 1.0
import utils 1.0
import "../controls"
@ -81,7 +83,26 @@ Item {
visible: !root.walletStore.showSavedAddresses && Global.featureFlags.dappsEnabled
onConnectDapp: {
console.warn("TODO: run ConnectDappPopup...")
connectDappLoader.active = true
}
Loader {
id: connectDappLoader
active: false
onLoaded: item.open()
sourceComponent: ConnectDappModal {
visible: true
onClosed: connectDappLoader.active = false
onPair: (uri) => {
this.close()
console.debug(`TODO(#14556): ConnectionRequestDappModal with ${uri}`)
}
}
}
}

View File

@ -1,45 +0,0 @@
/////////////////////////////////////////////////////
// WalletConnect POC - to remove this file
/////////////////////////////////////////////////////
import QtQuick 2.15
import AppLayouts.Wallet.stores 1.0 as WalletStores
import shared.popups.walletconnect 1.0
Item {
id: root
required property var controller
property alias modal: modal
property alias sdk: sdk
property alias url: sdk.url
POCWalletConnectModal {
id: modal
controller: root.controller
sdk: sdk
}
WalletConnectSDK {
id: sdk
projectId: controller.projectId
active: WalletStores.RootStore.walletSectionInst.walletReady && (controller.hasActivePairings || modal.opened)
onSessionRequestEvent: (details) => {
modal.openWithSessionRequestEvent(details)
}
}
Connections {
target: root.controller
function onRequestOpenWalletConnectPopup(uri) {
modal.openWithUri(uri)
}
}
}

View File

@ -27,6 +27,7 @@ import shared.stores 1.0
import shared.popups.send 1.0
import shared.popups.send.views 1.0
import shared.stores.send 1.0
import shared.popups.walletconnect 1.0
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
@ -43,11 +44,6 @@ import AppLayouts.Communities.stores 1.0
import AppLayouts.Wallet.stores 1.0 as WalletStore
import AppLayouts.Wallet.popups 1.0 as WalletPopups
/////////////////////////////////////////////////////
// WalletConnect POC - to remove
import AppLayouts.Wallet.views.pocwalletconnect 1.0
/////////////////////////////////////////////////////
import mainui.activitycenter.stores 1.0
import mainui.activitycenter.popups 1.0
@ -82,6 +78,18 @@ Item {
walletAssetStore: appMain.walletAssetsStore
tokensStore: appMain.tokensStore
}
readonly property DAppsStore dappsStore: DAppsStore {
wCSDK: WalletConnectSDK {
active: WalletStore.RootStore.walletSectionInst.walletReady
projectId: WalletStore.RootStore.appSettings.walletConnectProjectID
onSessionRequestEvent: (details) => {
// TODO #14556
console.debug(`@dd onSessionRequestEvent: ${JSON.stringify(details)}`)
}
}
}
// set from main.qml
property var sysPalette
@ -2032,23 +2040,4 @@ Item {
onClosed: userAgreementLoader.active = false
}
}
/////////////////////////////////////////////////////
// WalletConnect POC - to remove
POCWalletConnect {
id: walletConnect
anchors.top: parent.bottom
width: 100
height: 100
controller: WalletStore.RootStore.walletSectionInst.walletConnectController
Connections {
target: Global
function onPopupWalletConnect() {
walletConnect.modal.open()
}
}
}
/////////////////////////////////////////////////////
}

View File

@ -0,0 +1,67 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml.Models 2.14
import StatusQ.Core 0.1
import StatusQ.Popups.Dialog 0.1
import StatusQ.Controls 0.1
import utils 1.0
import "ConnectDappModal"
StatusDialog {
id: root
signal pair(string uri)
width: 480
implicitHeight: 633
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
title: qsTr("Connect a dApp via WalletConnect")
padding: 20
contentItem: ColumnLayout {
StatusBaseText {
text: "WalletConnect URI"
}
WCUriInput {
id: uriInput
}
// Spacer
ColumnLayout {}
StatusLinkText {
text: qsTr("How to copy the dApp URI")
Layout.alignment: Qt.AlignHCenter
Layout.margins: 18
normalColor: linkColor
onClicked: {
console.warn("TODO: open help...")
}
}
}
footer: StatusDialogFooter {
id: footer
rightButtons: ObjectModel {
StatusButton {
height: 44
text: qsTr("Done")
enabled: uriInput.valid && uriInput.text.length > 0
onClicked: root.pair(uriInput.text)
}
}
}
}

View File

@ -0,0 +1,120 @@
import QtQuick 2.15
import QtQml 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import StatusQ.Core 0.1
import StatusQ.Popups 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
ColumnLayout {
id: root
readonly property bool valid: input.valid && input.text.length > 0
readonly property alias text: input.text
StatusBaseInput {
id: input
Layout.fillWidth: true
Layout.preferredHeight: 132
placeholderText: qsTr("Paste URI")
verticalAlignment: TextInput.AlignTop
valid: {
let uri = input.text
if(uri.length === 0) {
errorText.text = ""
return true
}
if(containsOnlyEmoji(uri)) {
errorText.text = qsTr("WalletConnect URI too cool")
return false
} else if(!validURI(uri)) {
errorText.text = qsTr("WalletConnect URI invalid")
return false
} else if(wcUriAlreadyUsed(uri)) {
errorText.text = qsTr("WalletConnect URI already used")
return false
} else if(wcUriExpired(uri)) {
errorText.text = qsTr("WalletConnect URI has expired")
return false
}
errorText.text = ""
return true
}
function validURI(uri) {
var regex = /^wc:[0-9a-fA-F-]*@([1-9][0-9]*)(\?([a-zA-Z-]+=[^&]+)(&[a-zA-Z-]+=[^&]+)*)?$/
return regex.test(uri)
}
function containsOnlyEmoji(uri) {
var emojiRegex = new RegExp("[\\u203C-\\u3299\\u1F000-\\u1F644]");
return !emojiRegex.test(uri);
}
function wcUriAlreadyUsed(uri) {
// TODO: Check if URI is already used
return false
}
function wcUriExpired(uri) {
// TODO: Check if URI is expired
return false
}
rightComponent: Item {
width: pasteButton.implicitWidth
height: pasteButton.implicitHeight
readonly property bool showIcon: input.valid && input.text.length > 0
StatusIcon {
anchors.centerIn: parent
icon: "tiny/tiny-checkmark"
color: Theme.palette.green
visible: showIcon
}
StatusButton {
id: pasteButton
text: qsTr("Paste")
size: StatusBaseButton.Size.Small
visible: !showIcon
borderWidth: enabled ? 1 : 0
borderColor: textColor
enabled: input.edit.canPaste
onClicked: {
input.edit.paste()
input.edit.focus = true
}
}
}
multiline: true
}
StatusBaseText {
id: errorText
visible: !input.valid && input.text.length !== 0
Layout.alignment: Qt.AlignRight
color: Theme.palette.dangerColor1
}
}

View File

@ -1,57 +0,0 @@
import QtQuick 2.15
import StatusQ.Core 0.1
import StatusQ.Popups 0.1
import StatusQ.Controls 0.1
import utils 1.0
StatusModal {
id: root
width: Constants.dapps.connectDappPopupWidth
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
headerSettings.title: qsTr("Connect a Dapp via WalletConnect")
StatusScrollView {
id: scrollView
anchors.fill: parent
padding: 0
contentWidth: availableWidth
Item {
id: content
implicitWidth: loader.implicitWidth
implicitHeight: loader.implicitHeight
width: scrollView.availableWidth
Loader {
id: loader
width: parent.width
sourceComponent: {
// TODO
return undefined
}
}
}
}
rightButtons: [
StatusButton {
id: primaryButton
height: Constants.dapps.footerButtonsHeight
text: qsTr("Done")
visible: text !== ""
enabled: root.store.primaryPopupButtonEnabled
onClicked: {
console.warn("TODO: done...")
}
}
]
}

View File

@ -1,2 +1,2 @@
WalletConnectSDK 1.0 WalletConnectSDK.qml
ConnectDappPopup 1.0 ConnectDappPopup.qml
ConnectDappModal 1.0 ConnectDappModal.qml

View File

@ -0,0 +1,11 @@
import QtQuick 2.15
import shared.popups.walletconnect 1.0
QtObject {
id: root
required property WalletConnectSDK wCSDK
// Here we will have business logic calls and expose connections history models
}

View File

@ -7,3 +7,4 @@ PermissionsStore 1.0 PermissionsStore.qml
TokenBalanceHistoryStore 1.0 TokenBalanceHistoryStore.qml
TokenMarketValuesStore 1.0 TokenMarketValuesStore.qml
NetworkConnectionStore 1.0 NetworkConnectionStore.qml
DAppsStore 1.0 DAppsStore.qml

View File

@ -788,11 +788,6 @@ QtObject {
}
}
readonly property QtObject dapps: QtObject {
readonly property int connectDappPopupWidth: 480
readonly property int footerButtonsHeight: 44
}
readonly property QtObject localPairingAction: QtObject {
readonly property int actionUnknown: 0
readonly property int actionConnect: 1