/* * This file is part of the Flowee project * Copyright (C) 2020-2021 Tom Zander * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.14 import QtQuick.Controls 2.14 import QtQuick.Layouts 1.14 import QtQuick.Shapes 1.15 // for shape-path import Flowee.org.pay 1.0 Pane { id: receivePane padding: 0 height: qrCode.height + grid.height property QtObject account: root.account property QtObject request: account.createPaymentRequest(receivePane) Image { id: qrCode width: 300 height: 300 source: "image://qr/" + receivePane.request.qr smooth: false anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top anchors.topMargin: 20 opacity: receivePane.request.state === PaymentRequest.Unpaid ? 1: 0 MouseArea { anchors.fill: parent onClicked: { Flowee.copyToClipboard(receivePane.request.qr) clipboardFeedback.opacity = 1 } } Rectangle { id: clipboardFeedback opacity: 0 width: 200 height: feedbackText.height + 20 radius: 10 color: Flowee.useDarkSkin ? "#333" : "#ddd" anchors.centerIn: parent Label { id: feedbackText width: parent.width - 20 x: 10 y: 10 text: qsTr("Copied to clipboard") wrapMode: Text.WordWrap } Behavior on opacity { OpacityAnimator {} } /// after 10 seconds, remove feedback. Timer { interval: 10000 running: clipboardFeedback.opacity === 1 onTriggered: clipboardFeedback.opacity = 0 } } Behavior on opacity { OpacityAnimator {} } } // the "payment received" screen. Rectangle { anchors.top: parent.top anchors.topMargin: 20 anchors.left: parent.left anchors.right: parent.right anchors.bottom: qrCode.bottom radius: 10 gradient: Gradient { GradientStop { position: 0.6 color: { var state = receivePane.request.state; if (state === PaymentRequest.PaymentSeen || state === PaymentRequest.Unpaid) return receivePane.palette.base if (state === PaymentRequest.DoubleSpentSeen) return "#640e0f" // red return "#3e8b4e" // in all other cases: green } Behavior on color { ColorAnimation {} } } GradientStop { position: 0.1 color: root.palette.base } } opacity: receivePane.request.state === PaymentRequest.Unpaid ? 0: 1 // animating timer to indicate our checking the security of the transaction. // (i.e. waiting for the double spent proof) Item { id: feedback width: 160 height: 160 y: (parent.height - height) / 3 * 2 visible: receivePane.request.state !== PaymentRequest.DoubleSpentSeen Shape { id: circleShape anchors.fill: parent opacity: progressCircle.sweepAngle === 340 ? 0 : 1 x: 40 ShapePath { strokeWidth: 20 strokeColor: "#9ea0b0" fillColor: "transparent" capStyle: ShapePath.RoundCap startX: 100; startY: 10 PathAngleArc { id: progressCircle centerX: 80 centerY: 80 radiusX: 70; radiusY: 70 startAngle: -80 sweepAngle: receivePane.request.state === PaymentRequest.Unpaid ? 0: 340 Behavior on sweepAngle { NumberAnimation { duration: Flowee.dspTimeout } } } } Label { anchors.centerIn: parent text: qsTr("Checking") // checking security } Behavior on opacity { OpacityAnimator {} } } Label { color: "green" text: "✔" opacity: 1 - circleShape.opacity font.pixelSize: 130 anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right } } Label { id: feedbackLabel text: { var s = receivePane.request.state; if (s === PaymentRequest.DoubleSpentSeen) // double-spent-proof received return qsTr("Transaction high risk") if (s === PaymentRequest.PaymentSeen) return qsTr("Payment Seen") if (s === PaymentRequest.PaymentSeenOk) return qsTr("Payment Accepted") if (s === PaymentRequest.Confirmed) return qsTr("Payment Settled") return "INTERNAL ERROR"; } width: parent.width - 40 anchors.verticalCenter: feedback.verticalCenter anchors.left: feedback.visible ? feedback.right : parent.left anchors.leftMargin: 20 wrapMode: Text.WrapAtWordBoundaryOrAnywhere font.pointSize: 20 } Label { visible: receivePane.request.state === PaymentRequest.DoubleSpentSeen anchors.top: feedbackLabel.bottom anchors.right: parent.right anchors.rightMargin: 10 width: parent.width - 20 horizontalAlignment: Qt.AlignRight wrapMode: Text.WrapAtWordBoundaryOrAnywhere text: qsTr("Instant payment failed. Wait for confirmation. (double spent proof received)") } Behavior on opacity { OpacityAnimator {} } } // entry-fields GridLayout { id: grid anchors.left: parent.left anchors.right: parent.right anchors.top: qrCode.bottom anchors.topMargin: 30 columns: 2 Label { text: qsTr("Description") + ":" } TextField { id: description Layout.fillWidth: true enabled: receivePane.request.state === PaymentRequest.Unpaid onTextChanged: receivePane.request.message = text } Label { id: payAmount text: qsTr("Amount") + ":" } BitcoinValueField { id: bitcoinValueField fontPtSize: payAmount.font.pointSize enabled: receivePane.request.state === PaymentRequest.Unpaid onValueChanged: receivePane.request.amount = value } CheckBox { id: legacyAddress Layout.columnSpan: 2 text: qsTr("Legacy address") enabled: receivePane.request.state === PaymentRequest.Unpaid onCheckStateChanged: receivePane.request.legacy = checked } RowLayout { Layout.columnSpan: 2 Layout.fillWidth: true Pane { Layout.fillWidth: true } Button { text: qsTr("Remember", "payment request") visible: receivePane.request.state === PaymentRequest.Unpaid || receivePane.request.state === PaymentRequest.DoubleSpentSeen onClicked: { receivePane.request.rememberPaymentRequest(); receivePane.visible = false; } } Button { text: receivePane.request.state === PaymentRequest.Unpaid ? qsTr("Cancel") : qsTr("Close") onClicked: receivePane.visible = false } } } }