status-desktop/ui/imports/shared/popups/walletconnect/ConnectDAppModal.qml

407 lines
11 KiB
QML

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml.Models 2.14
import SortFilterProxyModel 0.2
import QtGraphicalEffects 1.15
import StatusQ 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Popups.Dialog 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import shared.controls 1.0
// TODO extract the components to StatusQ
import shared.popups.send.controls 1.0
import AppLayouts.Wallet.controls 1.0
import utils 1.0
StatusDialog {
id: root
width: 480
implicitHeight: d.connectionStatus === root.notConnectedStatus ? 633 : 681
required property var accounts
required property var flatNetworks
readonly property alias selectedAccount: d.selectedAccount
readonly property alias selectedChains: d.selectedChains
readonly property int notConnectedStatus: 0
readonly property int connectionSuccessfulStatus: 1
readonly property int connectionFailedStatus: 2
function openWithFilter(dappChains, proposer) {
d.connectionStatus = root.notConnectedStatus
d.afterTwoSecondsFromStatus = false
let m = proposer.metadata
dappCard.name = m.name
dappCard.url = m.url
if(m.icons.length > 0) {
dappCard.iconUrl = m.icons[0]
} else {
dappCard.iconUrl = ""
}
d.dappChains.clear()
for (let i = 0; i < dappChains.length; i++) {
// Convert to int
d.dappChains.append({ chainId: parseInt(dappChains[i]) })
}
root.open()
}
function pairSuccessful(session) {
d.connectionStatus = root.connectionSuccessfulStatus
closeAndRetryTimer.start()
}
function pairFailed(session, err) {
d.connectionStatus = root.connectionFailedStatus
closeAndRetryTimer.start()
}
Timer {
id: closeAndRetryTimer
interval: 2000
running: false
repeat: false
onTriggered: {
d.afterTwoSecondsFromStatus = true
}
}
signal connect()
signal decline()
signal disconnect()
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
title: qsTr("Connection request")
padding: 20
contentItem: ColumnLayout {
spacing: 20
clip: true
DAppCard {
id: dappCard
Layout.alignment: Qt.AlignHCenter
Layout.leftMargin: 12
Layout.rightMargin: Layout.leftMargin
Layout.topMargin: 20
Layout.bottomMargin: Layout.topMargin
}
ContextCard {
Layout.fillWidth: true
}
PermissionsCard {
Layout.fillWidth: true
Layout.leftMargin: 12
Layout.rightMargin: Layout.leftMargin
Layout.topMargin: 20
Layout.bottomMargin: Layout.topMargin
}
}
footer: StatusDialogFooter {
id: footer
rightButtons: ObjectModel {
StatusButton {
height: 44
text: qsTr("Decline")
visible: d.connectionStatus === root.notConnectedStatus
onClicked: root.decline()
}
StatusButton {
height: 44
text: qsTr("Disconnect")
visible: d.connectionStatus === root.connectionSuccessfulStatus
type: StatusBaseButton.Type.Danger
onClicked: root.disconnect()
}
StatusButton {
height: 44
text: d.connectionStatus === root.notConnectedStatus
? qsTr("Connect")
: qsTr("Close")
onClicked: {
if (d.connectionStatus === root.notConnectedStatus)
root.connect()
else
root.close()
}
}
}
}
component ContextCard: Rectangle {
id: contextCard
implicitWidth: contextLayout.implicitWidth
implicitHeight: contextLayout.implicitHeight
radius: 8
// TODO: the color matched the design color (grey4); It is also matching the intention or we should add some another color to the theme? (e.g. sectionBorder)?
border.color: Theme.palette.baseColor2
border.width: 1
color: "transparent"
ColumnLayout {
id: contextLayout
anchors.fill: parent
RowLayout {
Layout.margins: 16
StatusBaseText {
text: qsTr("Connect with")
Layout.fillWidth: true
}
AccountSelector {
id: accountsDropdown
Layout.preferredWidth: 204
control.enabled: d.connectionStatus === root.notConnectedStatus && count > 1
model: d.accountsProxy
onCurrentAccountChanged: d.selectedAccount = currentAccount
}
}
Rectangle {
Layout.fillWidth: true
height: 1
color: contextCard.border.color
}
RowLayout {
Layout.margins: 16
StatusBaseText {
text: qsTr("On")
Layout.fillWidth: true
}
NetworkFilter {
id: networkFilter
Layout.preferredWidth: accountsDropdown.Layout.preferredWidth
flatNetworks: d.filteredChains
showTitle: true
multiSelection: true
selectionAllowed: d.connectionStatus === root.notConnectedStatus && d.allChainIdsAggregator.value.length > 1
selection: d.selectedChains
onSelectionChanged: {
if (d.selectedChains !== networkFilter.selection) {
d.selectedChains = networkFilter.selection
}
}
}
}
}
}
component DAppCard: ColumnLayout {
property alias name: appNameText.text
property alias url: appUrlText.text
property string iconUrl: ""
Rectangle {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: 72
Layout.preferredHeight: Layout.preferredWidth
radius: width / 2
color: Theme.palette.primaryColor3
StatusRoundedImage {
id: iconDisplay
anchors.fill: parent
visible: !fallbackImage.visible
image.source: iconUrl
}
StatusIcon {
id: fallbackImage
anchors.centerIn: parent
width: 40
height: 40
icon: "dapp"
color: Theme.palette.primaryColor1
visible: iconDisplay.image.isLoading || iconDisplay.image.isError || !iconUrl
}
}
StatusBaseText {
id: appNameText
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: 4
font.bold: true
font.pixelSize: 17
}
// TODO replace with the proper URL control
StatusLinkText {
id: appUrlText
Layout.alignment: Qt.AlignHCenter
font.pixelSize: 15
}
Rectangle {
Layout.preferredWidth: pairingStatusLayout.implicitWidth + 32
Layout.preferredHeight: pairingStatusLayout.implicitHeight + 14
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 16
visible: d.connectionStatus !== root.notConnectedStatus
color: d.connectionStatus === root.connectionSuccessfulStatus
? d.afterTwoSecondsFromStatus
? Theme.palette.successColor2
: Theme.palette.successColor3
: d.afterTwoSecondsFromStatus
? "transparent"
: Theme.palette.dangerColor3
border.color: d.connectionStatus === root.connectionSuccessfulStatus
? Theme.palette.successColor2
: Theme.palette.dangerColor2
border.width: 1
radius: height / 2
RowLayout {
id: pairingStatusLayout
anchors.centerIn: parent
spacing: 8
Rectangle {
width: 6
height: 6
radius: width / 2
visible: d.connectionStatus === root.connectionSuccessfulStatus
color: Theme.palette.successColor1
}
StatusIcon {
Layout.preferredWidth: 16
Layout.preferredHeight: 16
visible: d.connectionStatus !== root.connectionSuccessfulStatus
color: Theme.palette.dangerColor1
icon: "warning"
}
StatusBaseText {
text: {
if (d.connectionStatus === root.connectionSuccessfulStatus)
return qsTr("Connected. You can now go back to the dApp.")
else if (d.connectionStatus === root.connectionFailedStatus)
return qsTr("Error connecting to dApp. Close and try again")
return ""
}
font.pixelSize: 12
color: d.connectionStatus === root.connectionSuccessfulStatus ? Theme.palette.directColor1 : Theme.palette.dangerColor1
}
}
}
}
component PermissionsCard: ColumnLayout {
spacing: 8
StatusBaseText {
text: qsTr("Uniswap Interface will be able to:")
font.pixelSize: 13
color: Theme.palette.baseColor1
}
StatusBaseText {
text: qsTr("Check your account balance and activity")
font.pixelSize: 13
}
StatusBaseText {
text: qsTr("Request transactions and message signing")
font.pixelSize: 13
}
}
QtObject {
id: d
property SortFilterProxyModel accountsProxy: SortFilterProxyModel {
sourceModel: root.accounts
sorters: RoleSorter { roleName: "position"; sortOrder: Qt.AscendingOrder }
}
property var selectedAccount: ({})
property var selectedChains: allChainIdsAggregator.value
readonly property var filteredChains: LeftJoinModel {
leftModel: d.dappChains
rightModel: root.flatNetworks
joinRole: "chainId"
}
readonly property FunctionAggregator allChainIdsAggregator: FunctionAggregator {
model: d.filteredChains
initialValue: []
roleName: "chainId"
aggregateFunction: (aggr, value) => [...aggr, value]
}
readonly property var dappChains: ListModel {}
property int connectionStatus: notConnectedStatus
property bool afterTwoSecondsFromStatus: false
}
}