From f25a1ea36004ed4ea54c0f6f697b8aade605ed70 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Fri, 24 Jul 2015 15:55:58 -0400 Subject: [PATCH] [GUI] Lay out more transaction infrastructure A little more backend development, and create some GUI framework for a confirmation dialog --- programs/light_client/Transaction.cpp | 1 + programs/light_client/Transaction.hpp | 15 ++++--- programs/light_client/Wallet.hpp | 4 +- programs/light_client/qml/FormBox.qml | 5 ++- programs/light_client/qml/FormFlipper.qml | 51 ++++++++++++++++++++++ programs/light_client/qml/TransferForm.qml | 35 +++++++++------ programs/light_client/qml/main.qml | 13 ++++-- programs/light_client/qml/qml.qrc | 1 + 8 files changed, 100 insertions(+), 25 deletions(-) create mode 100644 programs/light_client/qml/FormFlipper.qml diff --git a/programs/light_client/Transaction.cpp b/programs/light_client/Transaction.cpp index f50e9dac..64f54374 100644 --- a/programs/light_client/Transaction.cpp +++ b/programs/light_client/Transaction.cpp @@ -43,6 +43,7 @@ OperationBase* Transaction::operationAt(int index) const { void Transaction::appendOperation(OperationBase* op) { + op->setParent(this); m_transaction.operations.push_back(op->genericOperation()); Q_EMIT operationsChanged(); } diff --git a/programs/light_client/Transaction.hpp b/programs/light_client/Transaction.hpp index 1e268d4a..7081054b 100644 --- a/programs/light_client/Transaction.hpp +++ b/programs/light_client/Transaction.hpp @@ -18,14 +18,9 @@ public: QQmlListProperty operations(); OperationBase* operationAt(int index) const; - void appendOperation(OperationBase* op); int operationCount() const { return m_transaction.operations.size(); } - void clearOperations() { - m_transaction.operations.clear(); - Q_EMIT operationsChanged(); - } public slots: void setStatus(Status status) @@ -37,6 +32,16 @@ public slots: emit statusChanged(status); } + /** + * @brief Append the operation to the transaction + * @param op The operation to append. This Transaction will take ownership of the operation. + */ + void appendOperation(OperationBase* op); + void clearOperations() { + m_transaction.operations.clear(); + Q_EMIT operationsChanged(); + } + signals: void statusChanged(Status status); void operationsChanged(); diff --git a/programs/light_client/Wallet.hpp b/programs/light_client/Wallet.hpp index 9a0f60a5..070634df 100644 --- a/programs/light_client/Wallet.hpp +++ b/programs/light_client/Wallet.hpp @@ -56,6 +56,8 @@ FC_REFLECT( wallet_file, class Wallet : public QObject { Q_OBJECT + Q_PROPERTY(bool isOpen READ isOpen NOTIFY isOpenChanged) + Q_PROPERTY(bool isLocked READ isLocked NOTIFY isLockedChanged) public: Wallet( QObject* parent = nullptr ); ~Wallet(); @@ -148,5 +150,3 @@ class Wallet : public QObject map _label_to_key; QString _brain_key; }; - - diff --git a/programs/light_client/qml/FormBox.qml b/programs/light_client/qml/FormBox.qml index 653f40fe..dae5a1ec 100644 --- a/programs/light_client/qml/FormBox.qml +++ b/programs/light_client/qml/FormBox.qml @@ -29,7 +29,8 @@ Rectangle { var form = formType.createObject(formContainer, params) formContainer.data = [form] - form.finished.connect(function(){state = "HIDDEN"}) + form.canceled.connect(function(){state = "HIDDEN"; internal.callbackArgs = []}) + form.completed.connect(function(){state = "HIDDEN"; internal.callbackArgs = arguments}) if (closedCallback instanceof Function) internal.callback = closedCallback state = "SHOWN" @@ -89,6 +90,7 @@ Rectangle { if (internal.callback instanceof Function) internal.callback() internal.callback = undefined + internal.callbackArgs = [] } } }, @@ -145,5 +147,6 @@ Rectangle { QtObject { id: internal property var callback + property var callbackArgs } } diff --git a/programs/light_client/qml/FormFlipper.qml b/programs/light_client/qml/FormFlipper.qml new file mode 100644 index 00000000..52c7d09d --- /dev/null +++ b/programs/light_client/qml/FormFlipper.qml @@ -0,0 +1,51 @@ +import QtQuick 2.5 + +import Graphene.Client 0.1 + +Flipable { + id: flipable + anchors.fill: parent + + property Component frontComponent + property Component backComponent + property GrapheneApplication app + signal canceled + signal completed + + property bool flipped: false + + Component.onCompleted: { + back = backComponent.createObject(flipable, {app: app, enabled: Qt.binding(function(){return flipped})}) + front = frontComponent.createObject(flipable, {app: app, enabled: Qt.binding(function(){return !flipped})}) + front.canceled.connect(function() { canceled.apply(this, arguments) }) + front.completed.connect(function() { + if (back.hasOwnProperty("arguments")) + back.arguments = arguments + flipped = true + }) + back.canceled.connect(function() { + if (front.hasOwnProperty("arguments")) + front.arguments = arguments + flipped = false + }) + back.completed.connect(function() { completed.apply(this, arguments) }) + } + + transform: Rotation { + id: rotation + origin.x: flipable.width/2 + origin.y: flipable.height/2 + axis.x: 0; axis.y: 1; axis.z: 0 // set axis.y to 1 to rotate around y-axis + angle: 0 // the default angle + } + + states: State { + name: "back" + PropertyChanges { target: rotation; angle: 180 } + when: flipable.flipped + } + + transitions: Transition { + NumberAnimation { target: rotation; property: "angle"; duration: 500 } + } +} diff --git a/programs/light_client/qml/TransferForm.qml b/programs/light_client/qml/TransferForm.qml index 52294392..30044519 100644 --- a/programs/light_client/qml/TransferForm.qml +++ b/programs/light_client/qml/TransferForm.qml @@ -15,14 +15,21 @@ Rectangle { anchors.fill: parent property GrapheneApplication app - signal finished + signal canceled + signal completed(TransferOperation op) /// The Account object for the sender property alias senderAccount: senderPicker.account /// The Account object for the receiver property alias receiverAccount: recipientPicker.account - /// The operation created in this form - property var operation + + function operation() { + if (!transferButton.enabled) return app.operationBuilder.transfer(0,0,0,0, memoField.text, 0) + + return app.operationBuilder.transfer(senderPicker.account.id, recipientPicker.account.id, + amountField.value * amountField.precisionAdjustment, + amountField.maxBalance.type.id, memoField.text, 0) + } Component.onCompleted: console.log("Made a transfer form") Component.onDestruction: console.log("Destroyed a transfer form") @@ -77,6 +84,12 @@ Rectangle { property Balance maxBalance: assetField.enabled && senderPicker.showBalance >= 0? senderPicker.balances[senderPicker.showBalance] : null + property int precisionAdjustment: maxBalance? Math.pow(10, maxBalance.type.precision) : 1 + + // Workaround to preserve value in case form gets disabled then re-enabled + onEnabledChanged: if (!enabled) __valueBackup = value + onMaximumValueChanged: if (enabled && maximumValue > __valueBackup) value = __valueBackup + property real __valueBackup } ComboBox { id: assetField @@ -89,25 +102,21 @@ Rectangle { Text { font.pixelSize: assetField.height / 2.5 text: { - var balance = amountField.maxBalance - if (!balance || !balance.type) return "" - var precisionAdjustment = Math.pow(10, balance.type.precision) - - var op = app.operationBuilder.transfer(0, 0, amountField.value * precisionAdjustment, - balance.type.id, memoField.text, 0) - - return qsTr("Fee:
") + op.fee / precisionAdjustment + " CORE" + if (!senderPicker.account) + return "" + return qsTr("Fee:
") + operation().fee / amountField.precisionAdjustment + " CORE" } } Item { Layout.fillWidth: true } Button { text: qsTr("Cancel") - onClicked: finished() + onClicked: canceled() } Button { + id: transferButton text: qsTr("Transfer") enabled: senderPicker.account && recipientPicker.account && senderPicker.account !== recipientPicker.account && amountField.value - onClicked: console.log(amountField.value) + onClicked: completed(operation) } } } diff --git a/programs/light_client/qml/main.qml b/programs/light_client/qml/main.qml index e6774b13..f117f342 100644 --- a/programs/light_client/qml/main.qml +++ b/programs/light_client/qml/main.qml @@ -60,10 +60,15 @@ ApplicationWindow { Button { text: "Transfer" - onClicked: formBox.showForm(Qt.createComponent("TransferForm.qml"), {}, - function() { - console.log("Closed form") - }) + onClicked: { + var front = Qt.createComponent("TransferForm.qml") + // TODO: make back into a preview and confirm dialog + var back = Qt.createComponent("TransferForm.qml") + formBox.showForm(Qt.createComponent("FormFlipper.qml"), {frontComponent: front, backComponent: back}, + function() { + console.log("Closed form") + }) + } } TextField { id: nameField diff --git a/programs/light_client/qml/qml.qrc b/programs/light_client/qml/qml.qrc index ed16a610..cda31e3e 100644 --- a/programs/light_client/qml/qml.qrc +++ b/programs/light_client/qml/qml.qrc @@ -3,6 +3,7 @@ main.qml TransferForm.qml FormBox.qml + FormFlipper.qml Scaling.qml Identicon.qml AccountPicker.qml