/* * This file is part of the Flowee project * Copyright (C) 2024 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 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 { } } } } }