529 lines
16 KiB
QML
529 lines
16 KiB
QML
import QtQuick 2.15
|
|
import QtQuick.Layouts 1.15
|
|
import QtQml.Models 2.15
|
|
|
|
import StatusQ.Core 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 StatusQ.Core.Utils 0.1 as StatusQ
|
|
|
|
import utils 1.0
|
|
|
|
import AppLayouts.Wallet.services.dapps.types 1.0
|
|
|
|
StatusDialog {
|
|
id: root
|
|
|
|
objectName: "dappsRequestModal"
|
|
|
|
implicitWidth: 480
|
|
|
|
required property string dappName
|
|
required property string dappUrl
|
|
required property url dappIcon
|
|
required property string method
|
|
required property var payloadData
|
|
property string maxFeesText: ""
|
|
property string maxFeesEthText: ""
|
|
property bool enoughFunds: false
|
|
property string estimatedTimeText: ""
|
|
|
|
required property var account
|
|
property var network: null
|
|
|
|
signal sign()
|
|
signal reject()
|
|
|
|
title: qsTr("Sign request")
|
|
|
|
padding: 20
|
|
|
|
onPayloadDataChanged: d.updateDisplay()
|
|
onMethodChanged: d.updateDisplay()
|
|
Component.onCompleted: d.updateDisplay()
|
|
|
|
contentItem: StatusScrollView {
|
|
id: scrollView
|
|
padding: 0
|
|
ColumnLayout {
|
|
spacing: 20
|
|
clip: true
|
|
|
|
width: scrollView.availableWidth
|
|
|
|
IntentionPanel {
|
|
Layout.fillWidth: true
|
|
|
|
dappName: root.dappName
|
|
dappIcon: root.dappIcon
|
|
account: root.account
|
|
}
|
|
|
|
ContentPanel {
|
|
Layout.fillWidth: true
|
|
Layout.maximumHeight: 340
|
|
}
|
|
|
|
// TODO: externalize as a TargetPanel
|
|
ColumnLayout {
|
|
spacing: 8
|
|
|
|
StatusBaseText {
|
|
text: qsTr("Sign with")
|
|
font.pixelSize: 13
|
|
color: Theme.palette.directColor1
|
|
}
|
|
|
|
// TODO #14762: implement proper control to display the accounts details
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 76
|
|
|
|
radius: 8
|
|
border.width: 1
|
|
border.color: Theme.palette.baseColor2
|
|
color: "transparent"
|
|
|
|
RowLayout {
|
|
spacing: 12
|
|
anchors.fill: parent
|
|
anchors.margins: 16
|
|
|
|
StatusSmartIdenticon {
|
|
width: 40
|
|
height: 40
|
|
|
|
asset: StatusAssetSettings {
|
|
color: Theme.palette.primaryColor1
|
|
isImage: false
|
|
isLetterIdenticon: true
|
|
useAcronymForLetterIdenticon: false
|
|
emoji: root.account.emoji
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
Layout.alignment: Qt.AlignLeft
|
|
|
|
StatusBaseText {
|
|
text: root.account.name
|
|
|
|
Layout.alignment: Qt.AlignLeft
|
|
|
|
font.pixelSize: 13
|
|
}
|
|
StatusBaseText {
|
|
text: StatusQ.Utils.elideAndFormatWalletAddress(root.account.address, 6, 4)
|
|
|
|
Layout.alignment: Qt.AlignLeft
|
|
|
|
font.pixelSize: 13
|
|
|
|
color: Theme.palette.baseColor1
|
|
}
|
|
}
|
|
|
|
Item {Layout.fillWidth: true }
|
|
}
|
|
}
|
|
|
|
StatusBaseText {
|
|
text: qsTr("Network")
|
|
font.pixelSize: 13
|
|
color: Theme.palette.directColor1
|
|
}
|
|
|
|
// TODO #14762: implement proper control to display the chain
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 76
|
|
|
|
visible: root.network !== null
|
|
|
|
radius: 8
|
|
border.width: 1
|
|
border.color: Theme.palette.baseColor2
|
|
color: "transparent"
|
|
|
|
RowLayout {
|
|
spacing: 12
|
|
anchors.fill: parent
|
|
anchors.margins: 16
|
|
|
|
StatusSmartIdenticon {
|
|
width: 40
|
|
height: 40
|
|
|
|
asset: StatusAssetSettings {
|
|
isImage: true
|
|
name: !!root.network ? Style.svg("tiny/" + root.network.iconUrl) : ""
|
|
}
|
|
}
|
|
|
|
StatusBaseText {
|
|
text: !!root.network ? root.network.chainName : ""
|
|
|
|
Layout.alignment: Qt.AlignLeft
|
|
|
|
font.pixelSize: 13
|
|
}
|
|
Item {Layout.fillWidth: true }
|
|
}
|
|
}
|
|
|
|
StatusBaseText {
|
|
text: qsTr("Fees")
|
|
font.pixelSize: 13
|
|
color: Theme.palette.directColor1
|
|
visible: d.isTransaction()
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 76
|
|
|
|
visible: root.network !== null && d.isTransaction()
|
|
|
|
radius: 8
|
|
border.width: 1
|
|
border.color: Theme.palette.baseColor2
|
|
color: "transparent"
|
|
|
|
RowLayout {
|
|
spacing: 12
|
|
anchors.fill: parent
|
|
anchors.margins: 16
|
|
|
|
StatusBaseText {
|
|
text: qsTr("Max. fees on %1").arg(!!root.network && root.network.chainName)
|
|
|
|
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
|
|
|
font.pixelSize: 13
|
|
color: Theme.palette.baseColor1
|
|
}
|
|
|
|
Item {Layout.fillWidth: true }
|
|
|
|
ColumnLayout {
|
|
StatusBaseText {
|
|
text: root.maxFeesText
|
|
|
|
Layout.alignment: Qt.AlignRight
|
|
|
|
font.pixelSize: 13
|
|
color: root.enoughFunds ? Theme.palette.directColor1 : Theme.palette.dangerColor1
|
|
}
|
|
|
|
StatusBaseText {
|
|
text: root.maxFeesEthText
|
|
|
|
Layout.alignment: Qt.AlignRight
|
|
|
|
font.pixelSize: 13
|
|
color: root.enoughFunds ? Theme.palette.baseColor1 : Theme.palette.dangerColor1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
header: StatusDialogHeader {
|
|
leftComponent: Item {
|
|
width: 46
|
|
height: 46
|
|
|
|
StatusSmartIdenticon {
|
|
anchors.fill: parent
|
|
anchors.margins: 3
|
|
|
|
asset: StatusAssetSettings {
|
|
width: 40
|
|
height: 40
|
|
bgRadius: bgWidth / 2
|
|
imgIsIdenticon: false
|
|
isImage: true
|
|
useAcronymForLetterIdenticon: false
|
|
name: root.dappIcon
|
|
}
|
|
bridgeBadge.visible: true
|
|
bridgeBadge.width: 16
|
|
bridgeBadge.height: 16
|
|
bridgeBadge.image.source: "assets/sign.svg"
|
|
bridgeBadge.border.width: 3
|
|
bridgeBadge.border.color: "transparent"
|
|
bridgeBadge.color: Theme.palette.miscColor1
|
|
}
|
|
}
|
|
headline.title: qsTr("Sign request")
|
|
headline.subtitle: root.dappUrl
|
|
}
|
|
|
|
footer: StatusDialogFooter {
|
|
id: footer
|
|
|
|
leftButtons: ObjectModel {
|
|
MaxFeesDisplay {
|
|
}
|
|
Item {
|
|
width: 20
|
|
}
|
|
EstimatedTimeDisplay {
|
|
visible: !!root.estimatedTimeText
|
|
}
|
|
}
|
|
|
|
rightButtons: ObjectModel {
|
|
StatusButton {
|
|
objectName: "rejectButton"
|
|
|
|
height: 44
|
|
text: qsTr("Reject")
|
|
|
|
onClicked: {
|
|
root.reject()
|
|
}
|
|
}
|
|
StatusButton {
|
|
height: 44
|
|
text: qsTr("Sign")
|
|
|
|
onClicked: {
|
|
root.sign()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
component MaxFeesDisplay: ColumnLayout {
|
|
StatusBaseText {
|
|
text: qsTr("Max fees:")
|
|
|
|
font.pixelSize: 12
|
|
color: Theme.palette.directColor1
|
|
}
|
|
StatusBaseText {
|
|
id: maxFeesDisplay
|
|
text: root.maxFeesText
|
|
|
|
visible: !!root.maxFeesText
|
|
|
|
font.pixelSize: 16
|
|
color: root.enoughFunds ? Theme.palette.directColor1 : Theme.palette.dangerColor1
|
|
}
|
|
StatusBaseText {
|
|
text: qsTr("No fees")
|
|
|
|
visible: !maxFeesDisplay.visible
|
|
|
|
font.pixelSize: maxFeesDisplay.font.pixelSize
|
|
font.weight: maxFeesDisplay.font.weight
|
|
}
|
|
}
|
|
|
|
component EstimatedTimeDisplay: ColumnLayout {
|
|
StatusBaseText {
|
|
text: qsTr("Est. time:")
|
|
font.pixelSize: 12
|
|
color: Theme.palette.directColor1
|
|
}
|
|
StatusBaseText {
|
|
text: root.estimatedTimeText
|
|
font.pixelSize: 16
|
|
}
|
|
}
|
|
|
|
component IntentionPanel: ColumnLayout {
|
|
spacing: 8
|
|
|
|
required property string dappName
|
|
required property url dappIcon
|
|
required property var account
|
|
|
|
// Icons
|
|
Item {
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 40
|
|
Layout.alignment: Qt.AlignHCenter
|
|
Layout.bottomMargin: 8
|
|
|
|
StatusRoundedImage {
|
|
id: dappIconComponent
|
|
|
|
width: height
|
|
height: parent.height
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.horizontalCenterOffset: -16
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
image.source: root.dappIcon
|
|
}
|
|
StatusRoundIcon {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.horizontalCenterOffset: 16
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
asset: StatusAssetSettings {
|
|
width: 24
|
|
height: 24
|
|
color: Theme.palette.primaryColor1
|
|
bgWidth: 40
|
|
bgHeight: 40
|
|
bgColor: Theme.palette.desktopBlue10
|
|
bgRadius: bgWidth / 2
|
|
bgBorderWidth: 2
|
|
bgBorderColor: Theme.palette.statusAppLayout.backgroundColor
|
|
source: "assets/sign.svg"
|
|
}
|
|
}
|
|
}
|
|
|
|
// Names and intentions
|
|
StatusBaseText {
|
|
text: qsTr("%1 wants you to %2 with %3").arg(dappName).arg(d.userDisplayNaming).arg(account.name)
|
|
|
|
Layout.preferredWidth: 400
|
|
Layout.alignment: Qt.AlignHCenter
|
|
|
|
font.pixelSize: 15
|
|
font.weight: Font.DemiBold
|
|
|
|
wrapMode: Text.WordWrap
|
|
horizontalAlignment: Text.AlignHCenter
|
|
}
|
|
|
|
// TODO #14762: externalize as a InfoPill and merge base implementation with
|
|
// the existing IssuePill reusable component
|
|
Rectangle {
|
|
Layout.preferredWidth: operationStatusLayout.implicitWidth + 24
|
|
Layout.preferredHeight: operationStatusLayout.implicitHeight + 14
|
|
|
|
Layout.alignment: Qt.AlignHCenter
|
|
|
|
visible: true
|
|
|
|
border.color: Theme.palette.successColor2
|
|
border.width: 1
|
|
color: "transparent"
|
|
radius: height / 2
|
|
|
|
RowLayout {
|
|
id: operationStatusLayout
|
|
|
|
spacing: 8
|
|
|
|
anchors.centerIn: parent
|
|
|
|
StatusIcon {
|
|
Layout.preferredWidth: 16
|
|
Layout.preferredHeight: 16
|
|
|
|
visible: true
|
|
|
|
color: Theme.palette.directColor1
|
|
icon: "info"
|
|
}
|
|
|
|
StatusBaseText {
|
|
text: qsTr("Only sign if you trust the dApp")
|
|
|
|
font.pixelSize: 12
|
|
color: Theme.palette.directColor1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
component ContentPanel: Rectangle {
|
|
id: contentPanelRect
|
|
border.width: 1
|
|
border.color: Theme.palette.baseColor2
|
|
color: "transparent"
|
|
radius: 8
|
|
|
|
implicitHeight: contentScrollView.implicitHeight + (2 * contentText.anchors.margins)
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: contentScrollView.enabled || !enabled ? undefined : Qt.PointingHandCursor
|
|
enabled: contentScrollView.height < contentScrollView.contentHeight
|
|
|
|
onClicked: {
|
|
contentScrollView.enabled = !contentScrollView.enabled
|
|
}
|
|
z: contentScrollView.z + 1
|
|
}
|
|
|
|
StatusScrollView {
|
|
id: contentScrollView
|
|
anchors.fill: parent
|
|
|
|
contentWidth: availableWidth
|
|
contentHeight: contentText.contentHeight
|
|
|
|
padding: 0
|
|
|
|
enabled: false
|
|
|
|
StatusBaseText {
|
|
id: contentText
|
|
anchors.fill: parent
|
|
anchors.margins: 20
|
|
|
|
width: contentScrollView.availableWidth
|
|
|
|
text: d.payloadToDisplay
|
|
|
|
wrapMode: Text.WrapAnywhere
|
|
}
|
|
}
|
|
}
|
|
|
|
QtObject {
|
|
id: d
|
|
|
|
property string payloadToDisplay: ""
|
|
property string userDisplayNaming: ""
|
|
|
|
function isTransaction() {
|
|
return root.method === SessionRequest.methods.signTransaction.name || root.method === SessionRequest.methods.sendTransaction.name
|
|
}
|
|
|
|
function updateDisplay() {
|
|
if (!root.payloadData)
|
|
return
|
|
|
|
switch (root.method) {
|
|
case SessionRequest.methods.personalSign.name: {
|
|
payloadToDisplay = SessionRequest.methods.personalSign.getMessageFromData(root.payloadData)
|
|
userDisplayNaming = SessionRequest.methods.personalSign.requestDisplay
|
|
break
|
|
}
|
|
case SessionRequest.methods.signTypedData_v4.name: {
|
|
let messageObject = SessionRequest.methods.signTypedData_v4.getMessageFromData(root.payloadData)
|
|
payloadToDisplay = JSON.stringify(JSON.parse(messageObject), null, 2)
|
|
userDisplayNaming = SessionRequest.methods.signTypedData_v4.requestDisplay
|
|
break
|
|
}
|
|
case SessionRequest.methods.signTransaction.name: {
|
|
let tx = SessionRequest.methods.signTransaction.getTxObjFromData(root.payloadData)
|
|
payloadToDisplay = JSON.stringify(tx, null, 2)
|
|
userDisplayNaming = SessionRequest.methods.signTransaction.requestDisplay
|
|
break
|
|
}
|
|
case SessionRequest.methods.sendTransaction.name: {
|
|
let tx = SessionRequest.methods.sendTransaction.getTxObjFromData(root.payloadData)
|
|
payloadToDisplay = JSON.stringify(tx, null, 2)
|
|
userDisplayNaming = SessionRequest.methods.sendTransaction.requestDisplay
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|