5yNk1v!mMm*w~?~IW^IVEv9Te;&@9IBp{Xg;^NmUJbba!OcJ$;VN(}Xh
zDlgBTZBE61SE$4wE4+ELsbVd2$ffJz{4^?{^@B+{a&qHPng!^><1enFcRF5L<|3Kd
z*ow-^sJ;<5iA3}zr1r`bJKD>$s%9Pi`z?<7p-o+KL0Fee@G`+8wdM+tK`
zM{atTwwRYhT^T4$OG|T1*FUJ#$U5Q=KxGZD7&y9N1JX3opYR1B3s9BFhbcnWuA9*!
z8H@!43(1UW;t~@rtT@zkQ__m#Vq>kT__}BDU0=TzfqgMtYN+${sWeEdMy962Eb2G5
zV<{D?Dfqe^N{3gPA{lsjUrkNf6qlCX5IeB|jA<hg`XGrL3w7Pstm^7w($uMrE>jP5Q?$toPw$eRU?>M;HXo
z_`%6YxoKghT%>vu>O%hJSi{preH_&sKCp4LBMlO1!48>fu&KaeL2(=W@k8Jfz)WLb
z22lVakAEe7`=-9w)Q=a%MyO)trtml_0u1o{e(dlobZ!{{XO~
zSw*(5N7M6e?lcw@sAq0RLR?HlcE!ow{BdyvIGN*uV&>-TgoK1JqG$>&Kn0&E<#+t1qF*9TU$9h3#X){ebVBc
z)2SFm^?6~xw3stj?C$L;hYRD`S;bMsgNsgH1aaUPo337}CH0}IiZ1YI^FZM>Ncyo%
z|A~I^hb7dSq642v!txk;8$eh+yF(cW(glo_RXC_KIyxF!&)pJpaf!$PM%=JQBxU90
z?XSh}DJ6mg`mj5Wr9*ywb+n?^>^i&H`-{!aT
z+jD^p3xN!oosN_=T31meptXtQu@2oXBHdrA+2EpnSv)c&Q^79%E5p
zHjG^Io?U+r*1RvzN$Xn+g!HVMd|fT$EY;N^wt*Y61xu$-a9WiXrz;1PN_aDKb8`~|
z0|RDY;={L~`6#ySpAN4e4NYW^57#IB=E5ik2L~njvbsUci`=*oG2xB}gNeE+)DOQT
z{`m1jlSeR|>$3O0^b%K(T_@)F*l&FjTk$okzNtxZeWH$%H}uTAt%{4AJ3-0;ZwKmM
zlF$_{Id`haq$pC|&sJi@02TlMMXwcjlN53KRy9;*Y2fW_5tYj2nUB)t*`BhkprRrt
zD3odl1R2;+iII_HLf5W6YkleN;n5As+|byV@RLLMW$LI~p7)=f9Arf|9&bw~X}O>C
zw9)4Hcf3SR=w%2f{sM3~M}j{d+x%h+pYb4M;*ad_-@pG+ex`wN0=pDRa&j`yI29DC
z;pFtL=H1FE6#rABd3r|te5>S6=Xd8l81UfR;*#6r$F=s|P>^lyetq_EadX?<23iXw
z;*F{${)(99t{!~}11w07i*h$Vf{g$I!>TPr`JV+!PKH!qkIZ6bELK31G7r*_g5P%j
z6nRZksYC$nK4|dEAG2H|W#N2Daj)J}3p59uTwKQ1*0HOrZn?^Vtg^DQVP5g2;;ems
zFBpERLO?r#OcyF=fI5Oc&G*HM{43gk+l`+-?E`7kor?w+hci8G?|`Y~!zW(P$ZJXb
z3$ietS;*kN^|(73H)XrKx*|#a5U!@y^R#snL4C_uLl%vWjt&cwGNVZ|xf)lQ?AfF8
zoaHr^m)d_Ea`!ZocHVSEkTJrX_GLD=Ua)!5K5uT7R#XgNhut-rw6gIcggyd&XlwQ5
zY_)*##>Pe)xzT%>x*Cx&H|&j5AB{FLBV*&CcJ@G4eQOTb+cOG*>}TirL0dL-peGIw
zzq}TZX>Bscd%@vA{oUE8jhcSSA|*ID_a0em4B>}Qrs(-vyu4TZPvSTZg+Rr`K9(PTD8WGUiAEJf`5N-QOT&=!ME&N)#lWfs}r3N@9y52y7rjb2BqP?3>hawqFmLe0yOmELc*Uu7F82W`={f<>~2p
zvF1Z0_y<#rWjr~|Y_~hUiXP8zQE%C}Ijh`TcZQ4(xL^bToSmd2q=%BBXnUgCt~v~}
zgc4(YTe5Hx)W;s*{S<=PD$u~Vd^nH!kU;E;`+fzc_pqH^t?CH^Ef{9ZM
ze%Ma55I|ki`!PU~9n|KBUXudnsW!0B9#5Z;M|k@k#r7@!#r8Yz{dz;IvEQv-B$euO
zA&1tBh&;6y2-vfTm!o(IRK?TtEatYs%IYw=djqj9qiTqwkIXpPW#1+<&|^S}K?Jpz
zWf(dt4PY1e!7>9sXl|;-Ea2yEiNDE$&pfBfgFWcR)A^*8^3&gzs-qT|w
zFDvWhO}J#mr2^4Vw^b(~)G@(>SI+(Ce38y8#VC5j;*#Mr#k^=t2of<27?39Yew6Bt
zFzbO!fK%$v11)wZDaPbLyLZDY_U59ag1LJ-7#D7$4gG9-^Let5Cx7AaX88uwjQ)2c
zvN^3xgAznWpKKf^MMzKIF`=6jvy`htf+3S6v+Vm5*=*=aF-JBC%}>T~Ueo(XTJ|u(
moTO}heO+wNSs+^ESoKD+h=Kr<0TTSH0_bTW5mg#?;r|1ja!P{$
literal 0
HcmV?d00001
diff --git a/src/qml/res/src/pending.svg b/src/qml/res/src/pending.svg
new file mode 100644
index 0000000000..cef63eeb79
--- /dev/null
+++ b/src/qml/res/src/pending.svg
@@ -0,0 +1,4 @@
+
From b5020363c7c053a2a378ca3c778a1305156d5012 Mon Sep 17 00:00:00 2001
From: johnny9 <985648+johnny9@users.noreply.github.com>
Date: Fri, 22 Nov 2024 01:01:54 -0500
Subject: [PATCH 05/10] qml: Introduce BitcoinAmount
BitcoinAmount is a helper object can be used to manage inputs in
sats or btc.
---
src/Makefile.qt.include | 3 +
src/qml/bitcoin.cpp | 2 +
src/qml/bitcoinamount.cpp | 127 ++++++++++++++++++++++++++++++++++++++
src/qml/bitcoinamount.h | 52 ++++++++++++++++
4 files changed, 184 insertions(+)
create mode 100644 src/qml/bitcoinamount.cpp
create mode 100644 src/qml/bitcoinamount.h
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 87e1a9e5d4..33875650ab 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -45,6 +45,7 @@ QT_MOC_CPP = \
qml/models/moc_peerlistsortproxy.cpp \
qml/models/moc_walletlistmodel.cpp \
qml/moc_appmode.cpp \
+ qml/moc_bitcoinamount.cpp \
qml/moc_walletcontroller.cpp \
qt/moc_addressbookpage.cpp \
qt/moc_addresstablemodel.cpp \
@@ -128,6 +129,7 @@ BITCOIN_QT_H = \
qml/models/walletlistmodel.h \
qml/appmode.h \
qml/bitcoin.h \
+ qml/bitcoinamount.h \
qml/guiconstants.h \
qml/imageprovider.h \
qml/util.h \
@@ -308,6 +310,7 @@ BITCOIN_QT_WALLET_CPP = \
BITCOIN_QML_BASE_CPP = \
qml/bitcoin.cpp \
+ qml/bitcoinamount.cpp \
qml/components/blockclockdial.cpp \
qml/controls/linegraph.cpp \
qml/models/chainmodel.cpp \
diff --git a/src/qml/bitcoin.cpp b/src/qml/bitcoin.cpp
index 0e5d0f9ce7..7b641c3054 100644
--- a/src/qml/bitcoin.cpp
+++ b/src/qml/bitcoin.cpp
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
#ifdef __ANDROID__
#include
#endif
@@ -317,6 +318,7 @@ int QmlGuiMain(int argc, char* argv[])
qmlRegisterType("org.bitcoincore.qt", 1, 0, "BlockClockDial");
qmlRegisterType("org.bitcoincore.qt", 1, 0, "LineGraph");
qmlRegisterUncreatableType("org.bitcoincore.qt", 1, 0, "PeerDetailsModel", "");
+ qmlRegisterType("org.bitcoincore.qt", 1, 0, "BitcoinAmount");
engine.load(QUrl(QStringLiteral("qrc:///qml/pages/main.qml")));
diff --git a/src/qml/bitcoinamount.cpp b/src/qml/bitcoinamount.cpp
new file mode 100644
index 0000000000..9abd30ad6d
--- /dev/null
+++ b/src/qml/bitcoinamount.cpp
@@ -0,0 +1,127 @@
+// Copyright (c) 2024 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include
+
+#include
+#include
+
+
+BitcoinAmount::BitcoinAmount(QObject *parent) : QObject(parent)
+{
+ m_unit = Unit::BTC;
+}
+
+int BitcoinAmount::decimals(Unit unit)
+{
+ switch (unit) {
+ case Unit::BTC: return 8;
+ case Unit::SAT: return 0;
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
+}
+
+QString BitcoinAmount::sanitize(const QString &text)
+{
+ QString result = text;
+
+ // Remove any invalid characters
+ result.remove(QRegExp("[^0-9.]"));
+
+ // Ensure only one decimal point
+ QStringList parts = result.split('.');
+ if (parts.size() > 2) {
+ result = parts[0] + "." + parts[1];
+ }
+
+ // Limit decimal places to 8
+ if (parts.size() == 2 && parts[1].length() > 8) {
+ result = parts[0] + "." + parts[1].left(8);
+ }
+
+ return result;
+}
+
+BitcoinAmount::Unit BitcoinAmount::unit() const
+{
+ return m_unit;
+}
+
+void BitcoinAmount::setUnit(const Unit unit)
+{
+ m_unit = unit;
+ Q_EMIT unitChanged();
+}
+
+QString BitcoinAmount::unitLabel() const
+{
+ switch (m_unit) {
+ case Unit::BTC: return "₿";
+ case Unit::SAT: return "Sat";
+ }
+ assert(false);
+}
+
+QString BitcoinAmount::amount() const
+{
+ return m_amount;
+}
+
+void BitcoinAmount::setAmount(const QString& new_amount)
+{
+ m_amount = sanitize(new_amount);
+ Q_EMIT amountChanged();
+}
+
+long long BitcoinAmount::toSatoshis(QString& amount, const Unit unit)
+{
+
+ int num_decimals = decimals(unit);
+
+ QStringList parts = amount.remove(' ').split(".");
+
+ QString whole = parts[0];
+ QString decimals;
+
+ if(parts.size() > 1)
+ {
+ decimals = parts[1];
+ }
+ QString str = whole + decimals.leftJustified(num_decimals, '0', true);
+
+ return str.toLongLong();
+}
+
+QString BitcoinAmount::convert(const QString &amount, Unit unit)
+{
+ if (amount == "") {
+ return amount;
+ }
+
+ QString result = amount;
+ int decimalPosition = result.indexOf(".");
+
+ if (decimalPosition == -1) {
+ decimalPosition = result.length();
+ result.append(".");
+ }
+
+ if (unit == Unit::BTC) {
+ int numDigitsAfterDecimal = result.length() - decimalPosition - 1;
+ if (numDigitsAfterDecimal < 8) {
+ result.append(QString(8 - numDigitsAfterDecimal, '0'));
+ }
+ result.remove(decimalPosition, 1);
+ } else if (unit == Unit::SAT) {
+ result.remove(decimalPosition, 1);
+ int newDecimalPosition = decimalPosition - 8;
+ if (newDecimalPosition < 1) {
+ result = QString("0").repeated(-newDecimalPosition) + result;
+ newDecimalPosition = 0;
+ }
+ result.insert(newDecimalPosition, ".");
+ }
+
+ return result;
+}
diff --git a/src/qml/bitcoinamount.h b/src/qml/bitcoinamount.h
new file mode 100644
index 0000000000..29615e4e6f
--- /dev/null
+++ b/src/qml/bitcoinamount.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2024 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_QML_BITCOINAMOUNT_H
+#define BITCOIN_QML_BITCOINAMOUNT_H
+
+#include
+#include
+#include
+
+class BitcoinAmount : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(Unit unit READ unit WRITE setUnit NOTIFY unitChanged)
+ Q_PROPERTY(QString unitLabel READ unitLabel NOTIFY unitChanged)
+ Q_PROPERTY(QString amount READ amount WRITE setAmount NOTIFY amountChanged)
+
+public:
+ enum class Unit {
+ BTC,
+ SAT
+ };
+ Q_ENUM(Unit)
+
+ explicit BitcoinAmount(QObject *parent = nullptr);
+
+ Unit unit() const;
+ void setUnit(Unit unit);
+ QString unitLabel() const;
+ QString amount() const;
+ void setAmount(const QString& new_amount);
+
+public Q_SLOTS:
+ QString sanitize(const QString &text);
+ QString convert(const QString &text, Unit unit);
+
+Q_SIGNALS:
+ void unitChanged();
+ void unitLabelChanged();
+ void amountChanged();
+
+private:
+ long long toSatoshis(QString &amount, const Unit unit);
+ int decimals(Unit unit);
+
+ Unit m_unit;
+ QString m_unitLabel;
+ QString m_amount;
+};
+
+#endif // BITCOIN_QML_BITCOINAMOUNT_H
From 9fb36634c3ffa13c6afd583d9779351c2cf96f75 Mon Sep 17 00:00:00 2001
From: johnny9 <985648+johnny9@users.noreply.github.com>
Date: Fri, 22 Nov 2024 01:19:33 -0500
Subject: [PATCH 06/10] qml: Introduce RequestPayment page
This page contains the form for the user to fill out to create
a payment request.
---
src/Makefile.qt.include | 1 +
src/qml/bitcoin_qml.qrc | 1 +
src/qml/pages/wallet/DesktopWallets.qml | 3 +-
src/qml/pages/wallet/RequestPayment.qml | 151 ++++++++++++++++++++++++
4 files changed, 154 insertions(+), 2 deletions(-)
create mode 100644 src/qml/pages/wallet/RequestPayment.qml
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 33875650ab..c36b050572 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -444,6 +444,7 @@ QML_RES_QML = \
qml/pages/wallet/CreatePassword.qml \
qml/pages/wallet/CreateWalletWizard.qml \
qml/pages/wallet/DesktopWallets.qml \
+ qml/pages/wallet/RequestPayment.qml \
qml/pages/wallet/WalletBadge.qml \
qml/pages/wallet/WalletSelect.qml
diff --git a/src/qml/bitcoin_qml.qrc b/src/qml/bitcoin_qml.qrc
index c16acb2b1f..16c2d88d9c 100644
--- a/src/qml/bitcoin_qml.qrc
+++ b/src/qml/bitcoin_qml.qrc
@@ -78,6 +78,7 @@
pages/wallet/CreatePassword.qml
pages/wallet/CreateWalletWizard.qml
pages/wallet/DesktopWallets.qml
+ pages/wallet/RequestPayment.qml
pages/wallet/WalletBadge.qml
pages/wallet/WalletSelect.qml
diff --git a/src/qml/pages/wallet/DesktopWallets.qml b/src/qml/pages/wallet/DesktopWallets.qml
index 59a7ac15e4..03c4231427 100644
--- a/src/qml/pages/wallet/DesktopWallets.qml
+++ b/src/qml/pages/wallet/DesktopWallets.qml
@@ -129,9 +129,8 @@ Page {
id: sendTab
CoreText { text: "Send" }
}
- Item {
+ RequestPayment {
id: receiveTab
- CoreText { text: "Receive" }
}
Item {
id: blockClockTab
diff --git a/src/qml/pages/wallet/RequestPayment.qml b/src/qml/pages/wallet/RequestPayment.qml
new file mode 100644
index 0000000000..317b5190c8
--- /dev/null
+++ b/src/qml/pages/wallet/RequestPayment.qml
@@ -0,0 +1,151 @@
+// Copyright (c) 2024 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+import org.bitcoincore.qt 1.0
+
+import "../../controls"
+import "../../components"
+import "../settings"
+
+PageStack {
+ id: stackView
+ initialItem: pageComponent
+
+ Component {
+ id: pageComponent
+ Page {
+ id: root
+ background: null
+
+ header: NavigationBar2 {
+ id: navbar
+ centerItem: Item {
+ id: header
+ Layout.fillWidth: true
+
+ CoreText {
+ anchors.left: parent.left
+ text: qsTr("Request a payment")
+ font.pixelSize: 21
+ bold: true
+ }
+ }
+ }
+
+ ScrollView {
+ clip: true
+ width: parent.width
+ height: parent.height
+ contentWidth: width
+
+ ColumnLayout {
+ id: columnLayout
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: Math.min(parent.width, 450)
+ spacing: 30
+
+ CoreText {
+ Layout.alignment: Qt.AlignHCenter
+ text: qsTr("All fields are optional.")
+ color: Theme.color.neutral7
+ font.pixelSize: 15
+ }
+
+ LabeledTextInput {
+ id: label
+ Layout.fillWidth: true
+ labelText: qsTr("Label")
+ placeholderText: qsTr("Enter label...")
+ }
+
+ Item {
+ BitcoinAmount {
+ id: bitcoinAmount
+ }
+
+ height: 50
+ Layout.fillWidth: true
+ CoreText {
+ anchors.left: parent.left
+ anchors.top: parent.top
+ color: Theme.color.neutral7
+ text: "Amount"
+ font.pixelSize: 15
+ }
+
+ TextField {
+ id: amountInput
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ leftPadding: 0
+ font.family: "Inter"
+ font.styleName: "Regular"
+ font.pixelSize: 18
+ color: Theme.color.neutral9
+ placeholderTextColor: Theme.color.neutral7
+ background: Item {}
+ placeholderText: "0.00000000"
+ onTextEdited: {
+ amountInput.text = bitcoinAmount.sanitize(amountInput.text)
+ }
+ }
+ Item {
+ width: unitLabel.width + flipIcon.width
+ height: Math.max(unitLabel.height, flipIcon.height)
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (bitcoinAmount.unit == BitcoinAmount.BTC) {
+ amountInput.text = bitcoinAmount.convert(amountInput.text, BitcoinAmount.BTC)
+ bitcoinAmount.unit = BitcoinAmount.SAT
+ } else {
+ amountInput.text = bitcoinAmount.convert(amountInput.text, BitcoinAmount.SAT)
+ bitcoinAmount.unit = BitcoinAmount.BTC
+ }
+ }
+ }
+ CoreText {
+ id: unitLabel
+ anchors.right: flipIcon.left
+ anchors.verticalCenter: parent.verticalCenter
+ text: bitcoinAmount.unitLabel
+ font.pixelSize: 18
+ color: Theme.color.neutral7
+ }
+ Icon {
+ id: flipIcon
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ source: "image://images/flip-vertical"
+ color: Theme.color.neutral8
+ size: 30
+ }
+ }
+ }
+
+ LabeledTextInput {
+ id: message
+ Layout.fillWidth: true
+ labelText: qsTr("Message")
+ placeholderText: qsTr("Enter message...")
+ }
+
+ ContinueButton {
+ id: continueButton
+ Layout.preferredWidth: Math.min(300, parent.width - 2 * Layout.leftMargin)
+ Layout.leftMargin: 20
+ Layout.rightMargin: 20
+ Layout.alignment: Qt.AlignCenter
+ text: qsTr("Continue")
+ }
+ }
+ }
+ }
+ }
+}
From adff8f265a830ca4ef6651e0f7bbe3538efda7b5 Mon Sep 17 00:00:00 2001
From: johnny9 <985648+johnny9@users.noreply.github.com>
Date: Fri, 22 Nov 2024 01:25:34 -0500
Subject: [PATCH 07/10] qml: Introduce RequestConfirmation page
This page contains the details of a payment request. It is
pushed onto the RequestPayment page's stack after the user
has clicke don Continue.
---
src/Makefile.qt.include | 1 +
src/qml/bitcoin_qml.qrc | 1 +
src/qml/pages/wallet/RequestConfirmation.qml | 167 +++++++++++++++++++
src/qml/pages/wallet/RequestPayment.qml | 7 +
4 files changed, 176 insertions(+)
create mode 100644 src/qml/pages/wallet/RequestConfirmation.qml
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index c36b050572..775bc28a96 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -444,6 +444,7 @@ QML_RES_QML = \
qml/pages/wallet/CreatePassword.qml \
qml/pages/wallet/CreateWalletWizard.qml \
qml/pages/wallet/DesktopWallets.qml \
+ qml/pages/wallet/RequestConfirmation.qml \
qml/pages/wallet/RequestPayment.qml \
qml/pages/wallet/WalletBadge.qml \
qml/pages/wallet/WalletSelect.qml
diff --git a/src/qml/bitcoin_qml.qrc b/src/qml/bitcoin_qml.qrc
index 16c2d88d9c..b82aeed18e 100644
--- a/src/qml/bitcoin_qml.qrc
+++ b/src/qml/bitcoin_qml.qrc
@@ -78,6 +78,7 @@
pages/wallet/CreatePassword.qml
pages/wallet/CreateWalletWizard.qml
pages/wallet/DesktopWallets.qml
+ pages/wallet/RequestConfirmation.qml
pages/wallet/RequestPayment.qml
pages/wallet/WalletBadge.qml
pages/wallet/WalletSelect.qml
diff --git a/src/qml/pages/wallet/RequestConfirmation.qml b/src/qml/pages/wallet/RequestConfirmation.qml
new file mode 100644
index 0000000000..aed4931ab5
--- /dev/null
+++ b/src/qml/pages/wallet/RequestConfirmation.qml
@@ -0,0 +1,167 @@
+// Copyright (c) 2024 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+import org.bitcoincore.qt 1.0
+
+import "../../controls"
+import "../../components"
+import "../settings"
+
+Page {
+ id: root
+ background: null
+ property string label: "alice"
+ property string message: "payment for goods"
+ property string amount: "0.000"
+
+ header: NavigationBar2 {
+ id: navbar
+ leftItem: NavButton {
+ iconSource: "image://images/caret-left"
+ text: qsTr("Back")
+ onClicked: {
+ root.StackView.view.pop()
+ }
+ }
+ centerItem: Item {
+ id: header
+ Layout.fillWidth: true
+
+ CoreText {
+ anchors.left: parent.left
+ text: qsTr("Payment request")
+ font.pixelSize: 21
+ bold: true
+ }
+ }
+ }
+
+ ScrollView {
+ clip: true
+ width: parent.width
+ height: parent.height
+ contentWidth: width
+
+ ColumnLayout {
+ id: columnLayout
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: Math.min(parent.width, 450)
+ spacing: 30
+
+ Image {
+ width: 60
+ height: 60
+ Layout.alignment: Qt.AlignHCenter
+ source: "image://images/pending"
+ sourceSize.width: 60
+ sourceSize.height: 60
+ }
+
+ CoreText {
+ Layout.alignment: Qt.AlignHCenter
+ text: qsTr("Created just now")
+ color: Theme.color.neutral7
+ font.pixelSize: 18
+ }
+
+ LabeledTextInput {
+ id: labelInput
+ Layout.fillWidth: true
+ labelText: qsTr("Label")
+ visible: label != ""
+ enabled: false
+ text: label
+ }
+
+ Item {
+ BitcoinAmount {
+ id: bitcoinAmount
+ }
+
+ height: 50
+ Layout.fillWidth: true
+ visible: amount != ""
+ CoreText {
+ anchors.left: parent.left
+ anchors.top: parent.top
+ color: Theme.color.neutral7
+ text: qsTr("Amount")
+ font.pixelSize: 15
+ }
+
+ TextField {
+ id: bitcoinAmountText
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ leftPadding: 0
+ font.family: "Inter"
+ font.styleName: "Regular"
+ font.pixelSize: 18
+ color: Theme.color.neutral9
+ placeholderTextColor: Theme.color.neutral7
+ background: Item {}
+ placeholderText: "0.00000000"
+ text: request.amount
+ enabled: false
+ onTextChanged: {
+ bitcoinAmountText.text = bitcoinAmount.sanitize(bitcoinAmountText.text)
+ }
+ }
+ }
+
+
+ LabeledTextInput {
+ id: messageInput
+ Layout.fillWidth: true
+ labelText: qsTr("Message")
+ visible: message != ""
+ enabled: false
+ text: message
+ }
+
+ Item {
+ height: addressLabel.height + addressText.height
+ Layout.fillWidth: true
+ CoreText {
+ id: addressLabel
+ anchors.left: parent.left
+ anchors.top: parent.top
+ color: Theme.color.neutral7
+ text: qsTr("Address")
+ font.pixelSize: 15
+ }
+
+ CoreText {
+ id: addressText
+ anchors.left: parent.left
+ anchors.right: copyIcon.left
+ anchors.top: addressLabel.bottom
+ leftPadding: 0
+ font.family: "Inter"
+ font.styleName: "Regular"
+ font.pixelSize: 18
+ horizontalAlignment: Text.AlignLeft
+ color: Theme.color.neutral9
+ text: "bc1q wvlv mha3 cvhy q6qz tjzu mq2d 63ff htzy xxu6 q8"
+ }
+
+ Icon {
+ id: copyIcon
+ anchors.right: parent.right
+ anchors.verticalCenter: addressText.verticalCenter
+ source: "image://images/copy"
+ color: Theme.color.neutral8
+ size: 30
+ enabled: true
+ onClicked: {
+ Clipboard.setText(addressText.text)
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/qml/pages/wallet/RequestPayment.qml b/src/qml/pages/wallet/RequestPayment.qml
index 317b5190c8..0b04650f25 100644
--- a/src/qml/pages/wallet/RequestPayment.qml
+++ b/src/qml/pages/wallet/RequestPayment.qml
@@ -143,9 +143,16 @@ PageStack {
Layout.rightMargin: 20
Layout.alignment: Qt.AlignCenter
text: qsTr("Continue")
+ onClicked: stackView.push(confirmationComponent)
}
}
}
}
}
+
+ Component {
+ id: confirmationComponent
+ RequestConfirmation {
+ }
+ }
}
From 8d15b2ac2ffe502096db08d467efef0b9590d51b Mon Sep 17 00:00:00 2001
From: johnny9 <985648+johnny9@users.noreply.github.com>
Date: Thu, 28 Nov 2024 23:53:50 -0500
Subject: [PATCH 08/10] qml: Allow TextFields to be selectable in
RequestPayment
---
src/qml/controls/LabeledTextInput.qml | 1 +
src/qml/pages/wallet/RequestConfirmation.qml | 1 +
src/qml/pages/wallet/RequestPayment.qml | 1 +
3 files changed, 3 insertions(+)
diff --git a/src/qml/controls/LabeledTextInput.qml b/src/qml/controls/LabeledTextInput.qml
index efa82f98f4..57030dd125 100644
--- a/src/qml/controls/LabeledTextInput.qml
+++ b/src/qml/controls/LabeledTextInput.qml
@@ -40,6 +40,7 @@ Item {
color: Theme.color.neutral9
placeholderTextColor: Theme.color.neutral7
background: Item {}
+ selectByMouse: true
onTextEdited: root.textEdited()
}
diff --git a/src/qml/pages/wallet/RequestConfirmation.qml b/src/qml/pages/wallet/RequestConfirmation.qml
index aed4931ab5..215d677175 100644
--- a/src/qml/pages/wallet/RequestConfirmation.qml
+++ b/src/qml/pages/wallet/RequestConfirmation.qml
@@ -107,6 +107,7 @@ Page {
placeholderText: "0.00000000"
text: request.amount
enabled: false
+ selectByMouse: true
onTextChanged: {
bitcoinAmountText.text = bitcoinAmount.sanitize(bitcoinAmountText.text)
}
diff --git a/src/qml/pages/wallet/RequestPayment.qml b/src/qml/pages/wallet/RequestPayment.qml
index 0b04650f25..93f3b8d261 100644
--- a/src/qml/pages/wallet/RequestPayment.qml
+++ b/src/qml/pages/wallet/RequestPayment.qml
@@ -89,6 +89,7 @@ PageStack {
placeholderTextColor: Theme.color.neutral7
background: Item {}
placeholderText: "0.00000000"
+ selectByMouse: true
onTextEdited: {
amountInput.text = bitcoinAmount.sanitize(amountInput.text)
}
From 74e87a9d6ecb686a3d9cb423fa7e8bdc6a3f5139 Mon Sep 17 00:00:00 2001
From: johnny9 <985648+johnny9@users.noreply.github.com>
Date: Mon, 9 Dec 2024 08:44:11 -0500
Subject: [PATCH 09/10] qml: Merge ReqeustPayment and RequestConfirmation into
one form
---
src/qml/pages/wallet/RequestConfirmation.qml | 168 ----------
src/qml/pages/wallet/RequestPayment.qml | 318 ++++++++++++-------
2 files changed, 199 insertions(+), 287 deletions(-)
delete mode 100644 src/qml/pages/wallet/RequestConfirmation.qml
diff --git a/src/qml/pages/wallet/RequestConfirmation.qml b/src/qml/pages/wallet/RequestConfirmation.qml
deleted file mode 100644
index 215d677175..0000000000
--- a/src/qml/pages/wallet/RequestConfirmation.qml
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright (c) 2024 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-import QtQuick 2.15
-import QtQuick.Controls 2.15
-import QtQuick.Layouts 1.15
-import org.bitcoincore.qt 1.0
-
-import "../../controls"
-import "../../components"
-import "../settings"
-
-Page {
- id: root
- background: null
- property string label: "alice"
- property string message: "payment for goods"
- property string amount: "0.000"
-
- header: NavigationBar2 {
- id: navbar
- leftItem: NavButton {
- iconSource: "image://images/caret-left"
- text: qsTr("Back")
- onClicked: {
- root.StackView.view.pop()
- }
- }
- centerItem: Item {
- id: header
- Layout.fillWidth: true
-
- CoreText {
- anchors.left: parent.left
- text: qsTr("Payment request")
- font.pixelSize: 21
- bold: true
- }
- }
- }
-
- ScrollView {
- clip: true
- width: parent.width
- height: parent.height
- contentWidth: width
-
- ColumnLayout {
- id: columnLayout
- anchors.horizontalCenter: parent.horizontalCenter
- width: Math.min(parent.width, 450)
- spacing: 30
-
- Image {
- width: 60
- height: 60
- Layout.alignment: Qt.AlignHCenter
- source: "image://images/pending"
- sourceSize.width: 60
- sourceSize.height: 60
- }
-
- CoreText {
- Layout.alignment: Qt.AlignHCenter
- text: qsTr("Created just now")
- color: Theme.color.neutral7
- font.pixelSize: 18
- }
-
- LabeledTextInput {
- id: labelInput
- Layout.fillWidth: true
- labelText: qsTr("Label")
- visible: label != ""
- enabled: false
- text: label
- }
-
- Item {
- BitcoinAmount {
- id: bitcoinAmount
- }
-
- height: 50
- Layout.fillWidth: true
- visible: amount != ""
- CoreText {
- anchors.left: parent.left
- anchors.top: parent.top
- color: Theme.color.neutral7
- text: qsTr("Amount")
- font.pixelSize: 15
- }
-
- TextField {
- id: bitcoinAmountText
- anchors.left: parent.left
- anchors.bottom: parent.bottom
- leftPadding: 0
- font.family: "Inter"
- font.styleName: "Regular"
- font.pixelSize: 18
- color: Theme.color.neutral9
- placeholderTextColor: Theme.color.neutral7
- background: Item {}
- placeholderText: "0.00000000"
- text: request.amount
- enabled: false
- selectByMouse: true
- onTextChanged: {
- bitcoinAmountText.text = bitcoinAmount.sanitize(bitcoinAmountText.text)
- }
- }
- }
-
-
- LabeledTextInput {
- id: messageInput
- Layout.fillWidth: true
- labelText: qsTr("Message")
- visible: message != ""
- enabled: false
- text: message
- }
-
- Item {
- height: addressLabel.height + addressText.height
- Layout.fillWidth: true
- CoreText {
- id: addressLabel
- anchors.left: parent.left
- anchors.top: parent.top
- color: Theme.color.neutral7
- text: qsTr("Address")
- font.pixelSize: 15
- }
-
- CoreText {
- id: addressText
- anchors.left: parent.left
- anchors.right: copyIcon.left
- anchors.top: addressLabel.bottom
- leftPadding: 0
- font.family: "Inter"
- font.styleName: "Regular"
- font.pixelSize: 18
- horizontalAlignment: Text.AlignLeft
- color: Theme.color.neutral9
- text: "bc1q wvlv mha3 cvhy q6qz tjzu mq2d 63ff htzy xxu6 q8"
- }
-
- Icon {
- id: copyIcon
- anchors.right: parent.right
- anchors.verticalCenter: addressText.verticalCenter
- source: "image://images/copy"
- color: Theme.color.neutral8
- size: 30
- enabled: true
- onClicked: {
- Clipboard.setText(addressText.text)
- }
- }
- }
- }
- }
-}
diff --git a/src/qml/pages/wallet/RequestPayment.qml b/src/qml/pages/wallet/RequestPayment.qml
index 93f3b8d261..dc44ec7526 100644
--- a/src/qml/pages/wallet/RequestPayment.qml
+++ b/src/qml/pages/wallet/RequestPayment.qml
@@ -11,149 +11,229 @@ import "../../controls"
import "../../components"
import "../settings"
-PageStack {
- id: stackView
- initialItem: pageComponent
-
- Component {
- id: pageComponent
- Page {
- id: root
- background: null
-
- header: NavigationBar2 {
- id: navbar
- centerItem: Item {
- id: header
- Layout.fillWidth: true
+Page {
+ id: root
+ background: null
+
+ property int requestCounter: 0
+
+ ScrollView {
+ clip: true
+ width: parent.width
+ height: parent.height
+ contentWidth: width
+
+ CoreText {
+ id: title
+ anchors.left: contentRow.left
+ anchors.top: parent.top
+ anchors.topMargin: 20
+ text: qsTr("Request a payment")
+ font.pixelSize: 21
+ bold: true
+ }
- CoreText {
- anchors.left: parent.left
- text: qsTr("Request a payment")
- font.pixelSize: 21
- bold: true
+ RowLayout {
+ id: contentRow
+ anchors.top: title.bottom
+ anchors.topMargin: 40
+ anchors.horizontalCenter: parent.horizontalCenter
+ spacing: 30
+ ColumnLayout {
+ id: columnLayout
+ Layout.minimumWidth: 450
+ Layout.maximumWidth: 470
+
+ spacing: 5
+
+ Item {
+ BitcoinAmount {
+ id: bitcoinAmount
}
- }
- }
-
- ScrollView {
- clip: true
- width: parent.width
- height: parent.height
- contentWidth: width
-
- ColumnLayout {
- id: columnLayout
- anchors.horizontalCenter: parent.horizontalCenter
- width: Math.min(parent.width, 450)
- spacing: 30
+ height: amountInput.height
+ Layout.fillWidth: true
CoreText {
- Layout.alignment: Qt.AlignHCenter
- text: qsTr("All fields are optional.")
- color: Theme.color.neutral7
- font.pixelSize: 15
+ id: amountLabel
+ width: 110
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ horizontalAlignment: Text.AlignLeft
+ color: Theme.color.neutral9
+ text: "Amount"
+ font.pixelSize: 18
}
- LabeledTextInput {
- id: label
- Layout.fillWidth: true
- labelText: qsTr("Label")
- placeholderText: qsTr("Enter label...")
+ TextField {
+ id: amountInput
+ anchors.left: amountLabel.right
+ anchors.verticalCenter: parent.verticalCenter
+ leftPadding: 0
+ font.family: "Inter"
+ font.styleName: "Regular"
+ font.pixelSize: 18
+ color: Theme.color.neutral9
+ placeholderTextColor: Theme.color.neutral7
+ background: Item {}
+ placeholderText: "0.00000000"
+ selectByMouse: true
+ onTextEdited: {
+ amountInput.text = bitcoinAmount.sanitize(amountInput.text)
+ }
}
-
Item {
- BitcoinAmount {
- id: bitcoinAmount
+ width: unitLabel.width + flipIcon.width
+ height: Math.max(unitLabel.height, flipIcon.height)
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (bitcoinAmount.unit == BitcoinAmount.BTC) {
+ amountInput.text = bitcoinAmount.convert(amountInput.text, BitcoinAmount.BTC)
+ bitcoinAmount.unit = BitcoinAmount.SAT
+ } else {
+ amountInput.text = bitcoinAmount.convert(amountInput.text, BitcoinAmount.SAT)
+ bitcoinAmount.unit = BitcoinAmount.BTC
+ }
+ }
}
-
- height: 50
- Layout.fillWidth: true
CoreText {
- anchors.left: parent.left
- anchors.top: parent.top
+ id: unitLabel
+ anchors.right: flipIcon.left
+ anchors.verticalCenter: parent.verticalCenter
+ text: bitcoinAmount.unitLabel
+ font.pixelSize: 18
color: Theme.color.neutral7
- text: "Amount"
- font.pixelSize: 15
}
+ Icon {
+ id: flipIcon
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ source: "image://images/flip-vertical"
+ color: Theme.color.neutral8
+ size: 30
+ }
+ }
+ }
+
+ Separator {
+ Layout.fillWidth: true
+ }
+
+ LabeledTextInput {
+ id: label
+ Layout.fillWidth: true
+ labelText: qsTr("Label")
+ placeholderText: qsTr("Enter label...")
+ }
+
+ Separator {
+ Layout.fillWidth: true
+ }
- TextField {
- id: amountInput
- anchors.left: parent.left
- anchors.bottom: parent.bottom
- leftPadding: 0
- font.family: "Inter"
- font.styleName: "Regular"
+ LabeledTextInput {
+ id: message
+ Layout.fillWidth: true
+ labelText: qsTr("Message")
+ placeholderText: qsTr("Enter message...")
+ }
+
+ Separator {
+ Layout.fillWidth: true
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.minimumHeight: addressLabel.height + copyLabel.height
+ Layout.topMargin: 10
+ height: addressLabel.height + copyLabel.height
+ CoreText {
+ id: addressLabel
+ anchors.left: parent.left
+ anchors.top: parent.top
+ horizontalAlignment: Text.AlignLeft
+ width: 110
+ text: qsTr("Address")
+ font.pixelSize: 18
+ color: Theme.color.neutral9
+ }
+ CoreText {
+ id: copyLabel
+ anchors.left: parent.left
+ anchors.top: addressLabel.bottom
+ horizontalAlignment: Text.AlignLeft
+ width: 110
+ text: qsTr("copy")
+ font.pixelSize: 18
+ color: Theme.color.neutral7
+ }
+
+ Rectangle {
+ anchors.left: addressLabel.right
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ color: Theme.color.neutral2
+ radius: 5
+ CoreText {
+ id: address
+ anchors.fill: parent
+ anchors.leftMargin: 5
+ horizontalAlignment: Text.AlignLeft
font.pixelSize: 18
color: Theme.color.neutral9
- placeholderTextColor: Theme.color.neutral7
- background: Item {}
- placeholderText: "0.00000000"
- selectByMouse: true
- onTextEdited: {
- amountInput.text = bitcoinAmount.sanitize(amountInput.text)
- }
- }
- Item {
- width: unitLabel.width + flipIcon.width
- height: Math.max(unitLabel.height, flipIcon.height)
- anchors.right: parent.right
- anchors.verticalCenter: parent.verticalCenter
- MouseArea {
- anchors.fill: parent
- onClicked: {
- if (bitcoinAmount.unit == BitcoinAmount.BTC) {
- amountInput.text = bitcoinAmount.convert(amountInput.text, BitcoinAmount.BTC)
- bitcoinAmount.unit = BitcoinAmount.SAT
- } else {
- amountInput.text = bitcoinAmount.convert(amountInput.text, BitcoinAmount.SAT)
- bitcoinAmount.unit = BitcoinAmount.BTC
- }
- }
- }
- CoreText {
- id: unitLabel
- anchors.right: flipIcon.left
- anchors.verticalCenter: parent.verticalCenter
- text: bitcoinAmount.unitLabel
- font.pixelSize: 18
- color: Theme.color.neutral7
- }
- Icon {
- id: flipIcon
- anchors.right: parent.right
- anchors.verticalCenter: parent.verticalCenter
- source: "image://images/flip-vertical"
- color: Theme.color.neutral8
- size: 30
- }
+ wrap: true
}
}
+ }
- LabeledTextInput {
- id: message
- Layout.fillWidth: true
- labelText: qsTr("Message")
- placeholderText: qsTr("Enter message...")
+ ContinueButton {
+ id: continueButton
+ Layout.fillWidth: true
+ Layout.topMargin: 30
+ text: qsTr("Create bitcoin address")
+ onClicked: {
+ if (!clearRequest.visible) {
+ requestCounter = requestCounter + 1
+ clearRequest.visible = true
+ title.text = qsTr("Payment request #" + requestCounter)
+ address.text = "bc1q f5xe y2tf 89k9 zy6k gnru wszy 5fsa truy 9te1 bu"
+ continueButton.text = qsTr("Copy payment request")
+ }
}
+ }
- ContinueButton {
- id: continueButton
- Layout.preferredWidth: Math.min(300, parent.width - 2 * Layout.leftMargin)
- Layout.leftMargin: 20
- Layout.rightMargin: 20
- Layout.alignment: Qt.AlignCenter
- text: qsTr("Continue")
- onClicked: stackView.push(confirmationComponent)
+ ContinueButton {
+ id: clearRequest
+ Layout.fillWidth: true
+ Layout.topMargin: 10
+ visible: false
+ borderColor: Theme.color.neutral6
+ borderHoverColor: Theme.color.orangeLight1
+ borderPressedColor: Theme.color.orangeLight2
+ backgroundColor: "transparent"
+ backgroundHoverColor: "transparent"
+ backgroundPressedColor: "transparent"
+ text: qsTr("Clear")
+ onClicked: {
+ clearRequest.visible = false
+ title.text = qsTr("Request a payment")
+ address.text = ""
+ continueButton.text = qsTr("Create bitcoin address")
}
}
}
- }
- }
- Component {
- id: confirmationComponent
- RequestConfirmation {
+ Rectangle {
+ id: qrPlaceholder
+ Layout.alignment: Qt.AlignTop
+ Layout.minimumWidth: 150
+ Layout.maximumWidth: 150
+ color: Theme.color.neutral2
+ width: 150
+ height: 150
+ }
}
}
}
From 622a11401d781d13c33fb0f86d5fafacd22f9bf0 Mon Sep 17 00:00:00 2001
From: johnny9 <985648+johnny9@users.noreply.github.com>
Date: Mon, 9 Dec 2024 09:43:53 -0500
Subject: [PATCH 10/10] qml: Remove RequestConfirmation.qml from builds
---
src/Makefile.qt.include | 1 -
src/qml/bitcoin_qml.qrc | 1 -
2 files changed, 2 deletions(-)
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 775bc28a96..c36b050572 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -444,7 +444,6 @@ QML_RES_QML = \
qml/pages/wallet/CreatePassword.qml \
qml/pages/wallet/CreateWalletWizard.qml \
qml/pages/wallet/DesktopWallets.qml \
- qml/pages/wallet/RequestConfirmation.qml \
qml/pages/wallet/RequestPayment.qml \
qml/pages/wallet/WalletBadge.qml \
qml/pages/wallet/WalletSelect.qml
diff --git a/src/qml/bitcoin_qml.qrc b/src/qml/bitcoin_qml.qrc
index b82aeed18e..16c2d88d9c 100644
--- a/src/qml/bitcoin_qml.qrc
+++ b/src/qml/bitcoin_qml.qrc
@@ -78,7 +78,6 @@
pages/wallet/CreatePassword.qml
pages/wallet/CreateWalletWizard.qml
pages/wallet/DesktopWallets.qml
- pages/wallet/RequestConfirmation.qml
pages/wallet/RequestPayment.qml
pages/wallet/WalletBadge.qml
pages/wallet/WalletSelect.qml