From 17f38a930e33c25392dd565f484009e5eddba56a Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Sun, 26 Jun 2016 18:04:45 +0300 Subject: [PATCH] Added "Receive" page. Hide all pages except "Transfer" and "Receive". --- LeftPanel.qml | 50 ++++++++- MiddlePanel.qml | 5 + components/IconButton.qml | 72 +++++++++++++ components/Input.qml | 1 + components/LineEdit.qml | 3 +- get_libwallet_api.sh | 2 + main.qml | 4 +- pages/Receive.qml | 184 ++++++++++++++++++++++++++++++++ qml.qrc | 2 + src/libwalletqt/Wallet.cpp | 25 ++++- src/libwalletqt/Wallet.h | 16 ++- wizard/WizardCreateWallet.qml | 4 +- wizard/WizardRecoveryWallet.qml | 2 +- 13 files changed, 359 insertions(+), 11 deletions(-) create mode 100644 components/IconButton.qml create mode 100644 pages/Receive.qml diff --git a/LeftPanel.qml b/LeftPanel.qml index 95b5aa6f..0c1ccd12 100644 --- a/LeftPanel.qml +++ b/LeftPanel.qml @@ -34,10 +34,12 @@ Rectangle { property alias unlockedBalanceText: unlockedBalanceText.text property alias balanceText: balanceText.text + property alias networkStatus : networkStatus signal dashboardClicked() signal historyClicked() signal transferClicked() + signal receiveClicked() signal settingsClicked() signal addressBookClicked() signal miningClicked() @@ -47,9 +49,11 @@ Rectangle { if(pos === "Dashboard") menuColumn.previousButton = dashboardButton else if(pos === "History") menuColumn.previousButton = historyButton else if(pos === "Transfer") menuColumn.previousButton = transferButton + else if(pos === "Receive") menuColumn.previousButton = receiveButton else if(pos === "AddressBook") menuColumn.previousButton = addressBookButton else if(pos === "Mining") menuColumn.previousButton = miningButton else if(pos === "Settings") menuColumn.previousButton = settingsButton + menuColumn.previousButton.checked = true } @@ -120,7 +124,7 @@ Rectangle { font.family: "Arial" font.pixelSize: 26 color: "#000000" - text: "78.9245" + text: "N/A" } } @@ -144,7 +148,7 @@ Rectangle { font.family: "Arial" font.pixelSize: 18 color: "#000000" - text: "2324.9245" + text: "N/A" } } @@ -179,7 +183,11 @@ Rectangle { anchors.right: parent.right anchors.top: parent.top - property var previousButton: dashboardButton + property var previousButton: transferButton + + // ------------- Dashboard tab --------------- + + /* MenuButton { id: dashboardButton anchors.left: parent.left @@ -195,6 +203,7 @@ Rectangle { } } + Rectangle { anchors.left: parent.left anchors.right: parent.right @@ -202,7 +211,10 @@ Rectangle { color: dashboardButton.checked || transferButton.checked ? "#1C1C1C" : "#505050" height: 1 } + */ + + // ------------- Transfer tab --------------- MenuButton { id: transferButton anchors.left: parent.left @@ -221,10 +233,35 @@ Rectangle { anchors.left: parent.left anchors.right: parent.right anchors.leftMargin: 16 - color: transferButton.checked || historyButton.checked ? "#1C1C1C" : "#505050" + color: transferButton.checked || receiveButton.checked ? "#1C1C1C" : "#505050" height: 1 } + // ------------- Receive tab --------------- + MenuButton { + id: receiveButton + anchors.left: parent.left + anchors.right: parent.right + text: qsTr("Receive") + symbol: qsTr("R") + dotColor: "#AAFFBB" + onClicked: { + parent.previousButton.checked = false + parent.previousButton = receiveButton + panel.receiveClicked() + } + } + /* + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: 16 + color: transferButton.checked || historyButton.checked ? "#1C1C1C" : "#505050" + height: 1 + }*/ + + // ------------- History tab --------------- + /* MenuButton { id: historyButton anchors.left: parent.left @@ -246,6 +283,7 @@ Rectangle { color: historyButton.checked || addressBookButton.checked ? "#1C1C1C" : "#505050" height: 1 } + // ------------- AddressBook tab --------------- MenuButton { id: addressBookButton @@ -269,6 +307,7 @@ Rectangle { height: 1 } + // ------------- Mining tab --------------- MenuButton { id: miningButton anchors.left: parent.left @@ -291,6 +330,7 @@ Rectangle { height: 1 } + // ------------- Settings tab --------------- MenuButton { id: settingsButton anchors.left: parent.left @@ -304,9 +344,11 @@ Rectangle { panel.settingsClicked() } } + */ } NetworkStatusItem { + id: networkStatus anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom diff --git a/MiddlePanel.qml b/MiddlePanel.qml index edb4963d..4d65636c 100644 --- a/MiddlePanel.qml +++ b/MiddlePanel.qml @@ -31,6 +31,7 @@ import QtQuick 2.2 Rectangle { color: "#F0EEEE" signal paymentClicked(string address, string paymentId, double amount, int mixinCount) + signal generatePaymentIdInvoked() states: [ State { @@ -42,6 +43,9 @@ Rectangle { }, State { name: "Transfer" PropertyChanges { target: loader; source: "pages/Transfer.qml" } + }, State { + name: "Receive" + PropertyChanges { target: loader; source: "pages/Receive.qml" } }, State { name: "AddressBook" PropertyChanges { target: loader; source: "pages/AddressBook.qml" } @@ -79,6 +83,7 @@ Rectangle { } + /* connect "payment" click */ Connections { ignoreUnknownSignals: false target: loader.item diff --git a/components/IconButton.qml b/components/IconButton.qml new file mode 100644 index 00000000..042439f1 --- /dev/null +++ b/components/IconButton.qml @@ -0,0 +1,72 @@ +// Copyright (c) 2014-2015, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +import QtQuick 2.0 + +Item { + property alias imageSource : buttonImage.source + + signal clicked(var mouse) + + + id: button + width: parent.height + height: parent.height + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + + Image { + id: buttonImage + source: "" + x : (parent.width - width) / 2 + y : (parent.height - height) /2 + z: 100 + } + + MouseArea { + id: buttonArea + anchors.fill: parent + + + onPressed: { + buttonImage.x = buttonImage.x + 2 + buttonImage.y = buttonImage.y + 2 + } + onReleased: { + buttonImage.x = buttonImage.x - 2 + buttonImage.y = buttonImage.y - 2 + } + + onClicked: { + parent.clicked(mouse) + } + } + +} diff --git a/components/Input.qml b/components/Input.qml index c10994d0..78bec8ea 100644 --- a/components/Input.qml +++ b/components/Input.qml @@ -32,6 +32,7 @@ import QtQuick 2.2 TextField { font.family: "Arial" + horizontalAlignment: TextInput.AlignLeft style: TextFieldStyle { textColor: "#3F3F3F" diff --git a/components/LineEdit.qml b/components/LineEdit.qml index 37c2390d..81786881 100644 --- a/components/LineEdit.qml +++ b/components/LineEdit.qml @@ -32,8 +32,10 @@ Item { property alias placeholderText: input.placeholderText property alias text: input.text property alias validator: input.validator + property alias readOnly : input.readOnly property int fontSize: 18 + height: 37 Rectangle { @@ -56,6 +58,5 @@ Item { anchors.leftMargin: 4 anchors.rightMargin: 4 font.pixelSize: parent.fontSize - } } diff --git a/get_libwallet_api.sh b/get_libwallet_api.sh index c9f67ff8..9f8750d0 100755 --- a/get_libwallet_api.sh +++ b/get_libwallet_api.sh @@ -2,6 +2,7 @@ BITMONERO_URL=https://github.com/mbg033/bitmonero +BITMONERO_BRANCH=fee-mul CPU_CORE_COUNT=$(grep -c ^processor /proc/cpuinfo) pushd $(pwd) ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" @@ -13,6 +14,7 @@ BITMONERO_DIR=$ROOT_DIR/bitmonero if [ ! -d $BITMONERO_DIR ]; then git clone --depth=1 $BITMONERO_URL $BITMONERO_DIR + git checkout $BITMONERO_BRANCH else cd $BITMONERO_DIR; git pull; diff --git a/main.qml b/main.qml index 6f90bcf8..c2292798 100644 --- a/main.qml +++ b/main.qml @@ -226,6 +226,7 @@ ApplicationWindow { property bool allow_background_mining : true property bool testnet: true property string daemon_address: "localhost:38081" + property string payment_id } Item { @@ -274,6 +275,7 @@ ApplicationWindow { onDashboardClicked: middlePanel.state = "Dashboard" onHistoryClicked: middlePanel.state = "History" onTransferClicked: middlePanel.state = "Transfer" + onReceiveClicked: middlePanel.state = "Receive" onAddressBookClicked: middlePanel.state = "AddressBook" onMiningClicked: middlePanel.state = "Minning" onSettingsClicked: middlePanel.state = "Settings" @@ -294,7 +296,7 @@ ApplicationWindow { anchors.left: leftPanel.right anchors.right: rightPanel.left height: parent.height - state: "Dashboard" + state: "Transfer" } TipItem { diff --git a/pages/Receive.qml b/pages/Receive.qml new file mode 100644 index 00000000..623c629d --- /dev/null +++ b/pages/Receive.qml @@ -0,0 +1,184 @@ +// Copyright (c) 2014-2015, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import QtQuick 2.0 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.1 + +import "../components" +import moneroComponents 1.0 + +Rectangle { + + color: "#F0EEEE" + property alias addressText : addressLine.text + property alias paymentIdText : paymentIdLine.text + property alias integratedAddressText : integratedAddressLine.text + + function updatePaymentId() { + var payment_id = appWindow.persistentSettings.payment_id + if (payment_id.length === 0) { + payment_id = appWindow.wallet.generatePaymentId() + appWindow.persistentSettings.payment_id = payment_id + appWindow.wallet.payment_id = payment_id + } + paymentIdLine.text = payment_id + addressLine.text = appWindow.wallet.address + integratedAddressLine.text = appWindow.wallet.integratedAddress(payment_id) + } + + Clipboard { id: clipboard } + + + /* main layout */ + ColumnLayout { + id: mainLayout + anchors.margins: 40 + anchors.left: parent.left + anchors.top: parent.top + anchors.right: parent.right + + spacing: 20 + property int labelWidth: 120 + property int editWidth: 400 + property int lineEditFontSize: 12 + + + RowLayout { + id: addressRow + + Label { + id: addressLabel + fontSize: 14 + text: qsTr("Address") + width: mainLayout.labelWidth + } + + LineEdit { + id: addressLine + fontSize: mainLayout.lineEditFontSize + placeholderText: "ReadOnly wallet address displayed here"; + readOnly: true + width: mainLayout.editWidth + Layout.fillWidth: true + IconButton { + imageSource: "../images/copyToClipboard.png" + onClicked: { + if (addressLine.text.length > 0) { + clipboard.setText(addressLine.text) + } + } + } + } + } + + RowLayout { + id: integratedAddressRow + Label { + id: integratedAddressLabel + fontSize: 14 + text: qsTr("Integrated address") + width: mainLayout.labelWidth + } + + + LineEdit { + + id: integratedAddressLine + fontSize: mainLayout.lineEditFontSize + placeholderText: "ReadOnly wallet integrated address displayed here"; + readOnly: true + width: mainLayout.editWidth + Layout.fillWidth: true + IconButton { + imageSource: "../images/copyToClipboard.png" + onClicked: { + if (integratedAddressLine.text.length > 0) { + clipboard.setText(integratedAddressLine.text) + } + } + } + + } + } + + RowLayout { + id: paymentIdRow + Label { + id: paymentIdLabel + fontSize: 14 + text: qsTr("Payment ID") + width: mainLayout.labelWidth + } + + + LineEdit { + id: paymentIdLine + fontSize: mainLayout.lineEditFontSize + placeholderText: "PaymentID here"; + readOnly: false + + width: mainLayout.editWidth + Layout.fillWidth: true + + IconButton { + imageSource: "../images/copyToClipboard.png" + onClicked: { + if (paymentIdLine.text.length > 0) { + clipboard.setText(paymentIdLine.text) + } + } + } + } + + StandardButton { + id: generatePaymentId + width: 80 + fontSize: 14 + shadowReleasedColor: "#FF4304" + shadowPressedColor: "#B32D00" + releasedColor: "#FF6C3C" + pressedColor: "#FF4304" + text: qsTr("Generate") + anchors.right: parent.right + onClicked: { + appWindow.persistentSettings.payment_id = appWindow.wallet.generatePaymentId(); + updatePaymentId() + } + } + } + + } + + Component.onCompleted: { + console.log("Receive page loaded"); + updatePaymentId() + } + +} diff --git a/qml.qrc b/qml.qrc index bfa55389..36861fe4 100644 --- a/qml.qrc +++ b/qml.qrc @@ -111,5 +111,7 @@ wizard/WizardRecoveryWallet.qml wizard/WizardMemoTextInput.qml wizard/utils.js + pages/Receive.qml + components/IconButton.qml diff --git a/src/libwalletqt/Wallet.cpp b/src/libwalletqt/Wallet.cpp index 4e6b6787..da9cba01 100644 --- a/src/libwalletqt/Wallet.cpp +++ b/src/libwalletqt/Wallet.cpp @@ -88,10 +88,11 @@ bool Wallet::refresh() return result; } -PendingTransaction *Wallet::createTransaction(const QString &dst_addr, quint64 amount, quint32 mixin_count) +PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QString &payment_id, + quint64 amount, quint32 mixin_count) { Bitmonero::PendingTransaction * ptImpl = m_walletImpl->createTransaction( - dst_addr.toStdString(), amount, mixin_count); + dst_addr.toStdString(), payment_id.toStdString(), amount, mixin_count); PendingTransaction * result = new PendingTransaction(ptImpl, this); return result; } @@ -112,6 +113,26 @@ TransactionHistory *Wallet::history() } +QString Wallet::generatePaymentId() const +{ + return QString::fromStdString(Bitmonero::Wallet::genPaymentId()); +} + +QString Wallet::integratedAddress(const QString &paymentId) const +{ + return QString::fromStdString(m_walletImpl->integratedAddress(paymentId.toStdString())); +} + +QString Wallet::paymentId() const +{ + return m_paymentId; +} + +void Wallet::setPaymentId(const QString &paymentId) +{ + m_paymentId = paymentId; +} + Wallet::Wallet(Bitmonero::Wallet *w, QObject *parent) : QObject(parent), m_walletImpl(w), m_history(nullptr) diff --git a/src/libwalletqt/Wallet.h b/src/libwalletqt/Wallet.h index 4991476a..675ff52e 100644 --- a/src/libwalletqt/Wallet.h +++ b/src/libwalletqt/Wallet.h @@ -23,6 +23,7 @@ class Wallet : public QObject Q_PROPERTY(quint64 balance READ balance) Q_PROPERTY(quint64 unlockedBalance READ unlockedBalance) Q_PROPERTY(TransactionHistory * history READ history) + Q_PROPERTY(QString paymentId READ paymentId WRITE setPaymentId) public: enum Status { @@ -75,7 +76,7 @@ public: Q_INVOKABLE bool refresh(); //! creates transaction - Q_INVOKABLE PendingTransaction * createTransaction(const QString &dst_addr, + Q_INVOKABLE PendingTransaction * createTransaction(const QString &dst_addr, const QString &payment_id, quint64 amount, quint32 mixin_count); //! deletes transaction and frees memory @@ -84,6 +85,18 @@ public: //! returns transaction history TransactionHistory * history(); + //! generate payment id + Q_INVOKABLE QString generatePaymentId() const; + + //! integrated address + Q_INVOKABLE QString integratedAddress(const QString &paymentId) const; + + + //! saved payment id + QString paymentId() const; + + void setPaymentId(const QString &paymentId); + // TODO: setListenter() when it implemented in API signals: void updated(); @@ -99,6 +112,7 @@ private: Bitmonero::Wallet * m_walletImpl; // history lifetime managed by wallet; TransactionHistory * m_history; + QString m_paymentId; }; #endif // WALLET_H diff --git a/wizard/WizardCreateWallet.qml b/wizard/WizardCreateWallet.qml index 0aad0052..d39d52d2 100644 --- a/wizard/WizardCreateWallet.qml +++ b/wizard/WizardCreateWallet.qml @@ -60,7 +60,9 @@ Item { var wallet_filename = oshelper.temporaryFilename(); if (typeof settingsObject.wallet === 'undefined') { //var wallet = walletManager.createWallet(wallet_filename, "", settingsObject.language) - var wallet = walletManager.createWallet(wallet_filename, "", settingsObject.wallet_language) + var testnet = appWindow.persistentSettings.testnet; + var wallet = walletManager.createWallet(wallet_filename, "", settingsObject.wallet_language, + testnet) uiItem.wordsTextItem.memoText = wallet.seed // saving wallet in "global" settings object // TODO: wallet should have a property pointing to the file where it stored or loaded from diff --git a/wizard/WizardRecoveryWallet.qml b/wizard/WizardRecoveryWallet.qml index 19530157..aded7661 100644 --- a/wizard/WizardRecoveryWallet.qml +++ b/wizard/WizardRecoveryWallet.qml @@ -49,7 +49,7 @@ Item { } function recoveryWallet(settingsObject) { - var testnet = true; + var testnet = appWindow.persistentSettings.testnet; var wallet = walletManager.recoveryWallet(oshelper.temporaryFilename(), settingsObject.words, testnet); var success = wallet.status === Wallet.Status_Ok; if (success) {