Files
pay/modules/send-sweep/SendPage.qml
T
tomFlowee 6dc315cc77 Fix race condition, add autostartSkipped signal
This fixes the issue that the "sweep from browser" would consume the
property before the QR scanner had time to decide it should skip
scanning due to that property existing.
2024-10-28 10:24:58 +01:00

373 lines
13 KiB
QML

/*
* This file is part of the Flowee project
* Copyright (C) 2024 Tom Zander <tom@flowee.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import "../Flowee" as Flowee
import "../mobile" as Mobile;
import Flowee.org.pay;
import Flowee.org.pay.SendSweep;
Mobile.Page {
id: root
headerText: qsTr("Sweep coins")
Item { // data
QRScanner {
id: scanner
scanType: QRScanner.PrivateKeyWIF
autostart: Intent.sweepKey === ""
helpText: qsTr("Scan QR (WIF) to find funds", "Please note that WIF and QR are names")
onFinished: {
var rc = scanResult
if (rc === "") { // scanning interrupted
thePile.pop();
return;
}
root.forceActiveFocus();
sweeper.privKey = rc;
}
onAutostartSkipped: {
/*
* This page can be opened as part of the Intent feature,
* if it has then we need to set the privatekey and at
* the same time clear out the property to prepare for
* next usage.
*/
var fromIntent = Intent.sweepKey
if (fromIntent !== "") {
Intent.sweepKey = ""; // prepare for next usage.
sweeper.privKey = fromIntent;
}
}
}
SweepHandler {
id: sweeper
account: pay.portfolio.current
}
}
Column {
width: parent.width
spacing: 6
Flowee.Label {
text: qsTr("Sweeping from address:")
font.bold: true
width: parent.width
horizontalAlignment: Qt.AlignHCenter
wrapMode: Text.Wrap
}
Flowee.Label {
text: sweeper.sweepAddress
width: parent.width
horizontalAlignment: Qt.AlignHCenter
fontSizeMode: Text.HorizontalFit
}
Flowee.Label {
id: coinsLabel
visible: sweeper.numOutputsFound > 0 || sweeper.prepared
text: qsTr("Found %1 coins on address.", "this is a simple number", sweeper.numOutputsFound).arg(sweeper.numOutputsFound)
}
Flowee.Label {
visible: sweeper.numTokensFound > 0
text: qsTr("Ignoring %1 tokens.", "Number of CashTokens", sweeper.numTokensFound).arg(sweeper.numTokensFound)
}
Flowee.Progressbar {
width: parent.width
visible: !sweeper.prepared && sweeper.error === SweepHandler.NoError
progress: sweeper.downloadProgress / 1000
}
Item {
id: busyIndicator
visible: !sweeper.prepared && sweeper.error === SweepHandler.NoError
width: 105
height: visible ? 105 : 1
anchors.horizontalCenter: parent.horizontalCenter
RotationAnimation on rotation {
loops: Animation.Infinite
from: 0
to: 360
duration: 6000
running: busyIndicator.visible
}
Repeater {
model: 6
Item {
width: 105
height: 35
y: 35
Rectangle {
color: mainWindow.floweeGreen
width: 30
height: 30
x: 70
radius: 15
}
rotation: 360 / 6 * index
}
}
}
Rectangle {
color: mainWindow.errorRedBg
width: parent.width
height: sweepErrorLabel.text === "" ? 0 : sweepErrorLabel.height + 20
radius: 6
Flowee.Label {
id: sweepErrorLabel
width: parent.width - 20
wrapMode: Text.Wrap
horizontalAlignment: Qt.AlignHCenter
anchors.centerIn: parent
text: {
var err = sweeper.error;
if (err === SweepHandler.InvalidInput)
return qsTr("Failed to understand QR");
if (err === SweepHandler.NoBackendFound)
return "No indexing servers found";
if (err === SweepHandler.FileError)
return "File not found error"; // not translated as this should never happen.
if (err === SweepHandler.DataInconsistency)
return qsTr("Indexer results invalid. Please try again.");
if (err === SweepHandler.NoError)
return "";
}
}
}
Flowee.BitcoinAmountLabel {
font.pixelSize: coinsLabel.font.pixelSize * 1.2
visible: sweeper.prepared
value: sweeper.sweepTotal
anchors.right: parent.right
}
}
Mobile.AccountSelectorWidget {
id: walletSelector
visible: !portfolio.singleAccountSetup
y: 320
onSelectedAccountChanged: sweeper.account = selectedAccount
}
Flowee.Label {
visible: walletSelector.visible
anchors.bottom: walletSelector.top
text: qsTr("Transfer to:")
}
Mobile.SlideToApprove {
id: slideToApprove
anchors.bottom: parent.bottom
anchors.bottomMargin: 10
width: parent.width
enabled: sweeper.prepared && sweeper.numOutputsFound > 0
visible: !sweeper.account.needsPinToOpen
onActivated: {
root.hideHeader = true;
background.y = 0;
background.opacity = 1;
sweeper.markUserApproved();
}
}
QQC2.Control {
id: broadcastFeedback
anchors.leftMargin: -10 // go against the margins Page gave us to show more fullscreen.
anchors.rightMargin: -10
anchors.fill: parent
font.pixelSize: root.font.pixelSize * 1.2
property int status: sweeper.broadcastStatus
property double bitcoinAmount: sweeper.sweepTotal
property int fiatAmount: bitcoinAmount / 100000000 * Fiat.price
property string targetAddress: sweeper.targetAddress
states: [
State {
name: "notStarted"
when: broadcastFeedback.status === FloweePay.NotStarted
},
State {
name: "preparing"
when: broadcastFeedback.status === FloweePay.TxOffered
PropertyChanges { target: progressIcon; sweepAngle: 90 }
},
State {
name: "sent1" // sent to only one peer
extend: "preparing"
when: broadcastFeedback.status === FloweePay.TxSent1
PropertyChanges { target: progressIcon; sweepAngle: 150 }
PropertyChanges { target: statusLabel; text: qsTr("Sending Payment") }
},
State {
name: "waiting" // waiting for possible rejection.
when: broadcastFeedback.status === FloweePay.TxWaiting
extend: "preparing"
PropertyChanges { target: progressIcon; sweepAngle: 320 }
},
State {
name: "success" // no reject, great success
when: broadcastFeedback.status === FloweePay.TxBroadcastSuccess
extend: "preparing"
PropertyChanges { target: progressIcon
sweepAngle: 320
startAngle: -20
}
PropertyChanges { target: progressIcon; showCheck: true }
PropertyChanges { target: statusLabel; text: qsTr("Payment Sent") }
},
State {
name: "rejected" // a peer didn't like our tx
when: broadcastFeedback.status === FloweePay.TxRejected
extend: "preparing"
PropertyChanges { target: background; color: "#7f0000" }
PropertyChanges { target: progressIcon; opacity: 0 }
PropertyChanges { target: statusLabel; text: qsTr("Failed") }
PropertyChanges { target: errorLabel; text: qsTr("Transaction rejected by network") }
}
]
Rectangle {
id: background
width: parent.width
height: parent.height
opacity: 0
visible: opacity > 0
color: "#7bb688"
y: height + 2
MouseArea {
anchors.fill: parent // eat all mouse events.
}
Flowee.Label {
id: statusLabel
anchors.horizontalCenter: parent.horizontalCenter
font.bold: true
y: 30
color: "#e8e8e8"
}
Flowee.ProgressCheckIcon {
id: progressIcon
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: statusLabel.bottom
anchors.topMargin: 20
}
Column {
width: parent.width
anchors.top: progressIcon.bottom
anchors.topMargin: 6
spacing: 6
Rectangle {
id: errorTextPane
visible: errorLabel.text !== ""
color: mainWindow.errorRedBg
radius: 10
width: parent.width
height: errorLabel.height + 20
Flowee.Label {
id: errorLabel
wrapMode: Text.Wrap
x: 10
y: 10
width: parent.width - 20
horizontalAlignment: Qt.AlignHCenter
}
}
Flowee.Label {
id: fiatLabel
anchors.horizontalCenter: parent.horizontalCenter
color: statusLabel.color
font.pixelSize: statusLabel.font.pixelSize * 2.5
text: Fiat.formattedPrice(broadcastFeedback.fiatAmount)
visible: Fiat.price !== 0
}
Flowee.BitcoinAmountLabel {
id: cryptoAmount
anchors.horizontalCenter: parent.horizontalCenter
value: broadcastFeedback.bitcoinAmount
colorize: false
showFiat: false
color: statusLabel.color
}
Item { width: 10; height: 10 } // spacer
Flowee.Label {
id: addressLabel
color: statusLabel.color
visible: broadcastFeedback.targetAddress !== ""
width: parent.width - 20
x: 10
horizontalAlignment: Qt.AlignHCenter
wrapMode: Text.Wrap
text: qsTr("The payment has been sent to:", "Followed by the address")
}
Flowee.Label {
color: statusLabel.color
visible: broadcastFeedback.targetAddress !== ""
width: parent.width - 20
x: 10
horizontalAlignment: Qt.AlignHCenter
text: broadcastFeedback.targetAddress
fontSizeMode: Text.HorizontalFit
}
}
Rectangle {
id: closeButtonBg
color: statusLabel.color
radius: 10
width: parent.width - 20
x: 10
height: closeButtonLabel.height + 25
anchors.bottom: parent.bottom
anchors.bottomMargin: 10
Flowee.Label {
id: closeButtonLabel
text: qsTr("Close")
anchors.centerIn: parent
color: background.color
}
MouseArea {
anchors.fill: parent
anchors.margins: -10
focus: true
onClicked: {
var mainView = thePile.get(0);
mainView.currentIndex = 0; // go to the 'main' tab.
thePile.pop();
}
}
}
Behavior on opacity { NumberAnimation { } }
Behavior on y { NumberAnimation { } }
Behavior on color { ColorAnimation { } }
}
}
}