From eda4bae359c44e01486053c594729b443326eb80 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Mon, 3 Aug 2015 11:59:02 -0400 Subject: [PATCH 1/2] [GUI] Transfers now work! --- programs/light_client/ChainDataModel.cpp | 4 ++ programs/light_client/ChainDataModel.hpp | 5 ++ programs/light_client/Transaction.hpp | 23 ++++++- programs/light_client/main.cpp | 6 ++ .../qml/TransactionConfirmationForm.qml | 61 ++++++++++++------- 5 files changed, 76 insertions(+), 23 deletions(-) diff --git a/programs/light_client/ChainDataModel.cpp b/programs/light_client/ChainDataModel.cpp index 4c5e7592..62a843da 100644 --- a/programs/light_client/ChainDataModel.cpp +++ b/programs/light_client/ChainDataModel.cpp @@ -88,6 +88,10 @@ Asset* ChainDataModel::getAsset(QString symbol) return *itr; } +QDateTime ChainDataModel::chainTime() const { + return QDateTime::fromTime_t(m_dynamic_global_properties.time.sec_since_epoch()); +} + void ChainDataModel::processUpdatedObject(const fc::variant& update) { if (update.is_null()) diff --git a/programs/light_client/ChainDataModel.hpp b/programs/light_client/ChainDataModel.hpp index 465925b3..39700246 100644 --- a/programs/light_client/ChainDataModel.hpp +++ b/programs/light_client/ChainDataModel.hpp @@ -8,6 +8,7 @@ #include "Asset.hpp" #include "Account.hpp" +#include #include using graphene::chain::by_id; @@ -37,6 +38,7 @@ typedef multi_index_container< class Transaction; class ChainDataModel : public QObject { Q_OBJECT + Q_PROPERTY(QDateTime chainTime READ chainTime NOTIFY blockReceived) void processUpdatedObject(const fc::variant& update); @@ -49,6 +51,8 @@ public: Q_INVOKABLE Asset* getAsset(ObjectId id); Q_INVOKABLE Asset* getAsset(QString symbol); + QDateTime chainTime() const; + ChainDataModel(){} ChainDataModel(fc::thread& t, QObject* parent = nullptr); @@ -64,6 +68,7 @@ public Q_SLOTS: Q_SIGNALS: void queueExecute(const std::function&); void exceptionThrown(QString message); + void blockReceived(); private: fc::thread* m_rpc_thread = nullptr; diff --git a/programs/light_client/Transaction.hpp b/programs/light_client/Transaction.hpp index 861aaa07..9e08ea7e 100644 --- a/programs/light_client/Transaction.hpp +++ b/programs/light_client/Transaction.hpp @@ -3,8 +3,10 @@ #include +#include #include #include +#include class OperationBase; class Transaction : public QObject { @@ -26,13 +28,19 @@ public: return m_transaction; } -public slots: + QDateTime expiration() const + { + return QDateTime::fromTime_t(m_transaction.expiration.sec_since_epoch()); + } + +public Q_SLOTS: void setStatus(Status status) { if (status == m_status) return; m_status = status; + qDebug() << status; emit statusChanged(status); } @@ -46,13 +54,26 @@ public slots: Q_EMIT operationsChanged(); } + void setExpiration(QDateTime expiration) + { + fc::time_point_sec exp(expiration.toTime_t()); + if (exp == m_transaction.expiration) + return; + + m_transaction.expiration = exp; + emit expirationChanged(expiration); + } + signals: void statusChanged(Status status); void operationsChanged(); + void expirationChanged(QDateTime expiration); + private: Q_PROPERTY(Status status READ status WRITE setStatus NOTIFY statusChanged) Q_PROPERTY(QQmlListProperty operations READ operations NOTIFY operationsChanged) + Q_PROPERTY(QDateTime expiration READ expiration WRITE setExpiration NOTIFY expirationChanged) Status m_status = Unbroadcasted; graphene::chain::signed_transaction m_transaction; diff --git a/programs/light_client/main.cpp b/programs/light_client/main.cpp index dc0085f0..52767912 100644 --- a/programs/light_client/main.cpp +++ b/programs/light_client/main.cpp @@ -56,6 +56,12 @@ int main(int argc, char *argv[]) engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); #else engine.load(QUrl(QStringLiteral("qml/main.qml"))); + QFileSystemWatcher watcher; + qDebug() << watcher.addPath("qml/"); + QObject::connect(&watcher, &QFileSystemWatcher::directoryChanged, &engine, [&](QString path) { + qDebug() << "Changed file" << path; + engine.clearComponentCache(); + }); #endif return app.exec(); diff --git a/programs/light_client/qml/TransactionConfirmationForm.qml b/programs/light_client/qml/TransactionConfirmationForm.qml index 895bfac4..8d193f12 100644 --- a/programs/light_client/qml/TransactionConfirmationForm.qml +++ b/programs/light_client/qml/TransactionConfirmationForm.qml @@ -28,27 +28,25 @@ FormBase { trx.appendOperation(arg[op]) } - Component { - id: transactionDelegate + Rectangle { + width: Scaling.cm(10) + height: childrenRect.height + Scaling.cm(1) + radius: Scaling.mm(3) + color: "#EEEEEE" + border.width: Scaling.mm(.25) + border.color: "black" - Rectangle { - width: Scaling.cm(10) - height: childrenRect.height + Scaling.cm(1) - radius: Scaling.mm(3) - color: "#EEEEEE" - border.width: Scaling.mm(.25) - border.color: "black" - - Column { - y: Scaling.cm(.5) - x: y - width: parent.width - Scaling.cm(1) - Repeater { - model: trx.operations - Label { - property Asset transferAsset: app.model.getAsset(modelData.amountType) - property Asset feeAsset: app.model.getAsset(modelData.feeType) - text: qsTr("Transfer %1 %2 from %3 to %4\nFee: %5 %6").arg(transferAsset.formatAmount(modelData.amount)) + Column { + y: Scaling.cm(.5) + x: y + width: parent.width - Scaling.cm(1) + Repeater { + model: trx? trx.operations : [] + Label { + property Asset transferAsset: app.model.getAsset(modelData.amountType) + property Asset feeAsset: app.model.getAsset(modelData.feeType) + text: { + return qsTr("Transfer %1 %2 from %3 to %4\nFee: %5 %6").arg(transferAsset.formatAmount(modelData.amount)) .arg(transferAsset.symbol) .arg(app.model.getAccount(modelData.sender).name) .arg(app.model.getAccount(modelData.receiver).name) @@ -59,8 +57,26 @@ FormBase { } } } - Loader { - sourceComponent: trx && Array.prototype.slice.call(trx.operations).length > 0? transactionDelegate : undefined + Item { width: 1; height: 1 } + RowLayout { + Label { + text: qsTr("Transaction expires in") + } + ComboBox { + id: expirationSelector + model: [qsTr("five seconds"), qsTr("thirty seconds"), qsTr("a minute"), qsTr("an hour"), qsTr("a month"), qsTr("a year")] + + function getExpiration() { + switch(expirationSelector.currentIndex) { + case 0: return new Date(app.model.chainTime.getTime() + 1000*5) + case 1: return new Date(app.model.chainTime.getTime() + 1000*30) + case 2: return new Date(app.model.chainTime.getTime() + 1000*60) + case 3: return new Date(app.model.chainTime.getTime() + 1000*60*60) + case 4: return new Date(app.model.chainTime.getTime() + 1000*60*60*24*30) + case 5: return new Date(app.model.chainTime.getTime() + 1000*60*60*24*365) + } + } + } } UnlockingFinishButtons { app: base.app @@ -74,6 +90,7 @@ FormBase { if (app.wallet.isLocked) app.wallet.unlock(passwordField.text) else { + trx.setExpiration(expirationSelector.getExpiration()) app.signTransaction(trx) app.model.broadcast(trx) completed(trx) From 543c505e4030c52e0262ae957a4b40a739f07ff0 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Mon, 3 Aug 2015 14:59:34 -0400 Subject: [PATCH 2/2] [GUI] Tweaks, bug fixes, facelifts --- programs/light_client/qml/FormFlipper.qml | 4 +- programs/light_client/qml/Identicon.qml | 2 + .../qml/TransactionConfirmationForm.qml | 71 +++++++++++-------- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/programs/light_client/qml/FormFlipper.qml b/programs/light_client/qml/FormFlipper.qml index e104382c..923ee6c5 100644 --- a/programs/light_client/qml/FormFlipper.qml +++ b/programs/light_client/qml/FormFlipper.qml @@ -16,8 +16,8 @@ Flipable { 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})}) + back = backComponent.createObject(flipable, {app: app, enabled: Qt.binding(function(){return rotation.angle > 90})}) + front = frontComponent.createObject(flipable, {app: app, enabled: Qt.binding(function(){return rotation.angle < 90})}) front.canceled.connect(function() { canceled.apply(this, arguments) }) front.completed.connect(function() { back.display.apply(this, arguments) diff --git a/programs/light_client/qml/Identicon.qml b/programs/light_client/qml/Identicon.qml index 0189bdbe..d339c4f4 100644 --- a/programs/light_client/qml/Identicon.qml +++ b/programs/light_client/qml/Identicon.qml @@ -17,6 +17,8 @@ Canvas { Jdenticon.draw(identicon, name) else { var context = identicon.context + if (!context) return + context.reset() var draw_circle = function(context, x, y, radius) { context.beginPath() diff --git a/programs/light_client/qml/TransactionConfirmationForm.qml b/programs/light_client/qml/TransactionConfirmationForm.qml index 8d193f12..2a34f212 100644 --- a/programs/light_client/qml/TransactionConfirmationForm.qml +++ b/programs/light_client/qml/TransactionConfirmationForm.qml @@ -2,6 +2,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Dialogs 1.2 import QtQuick.Layouts 1.2 +import QtGraphicalEffects 1.0 import Graphene.Client 0.1 @@ -17,47 +18,58 @@ import "." FormBase { id: base - property Transaction trx + readonly property alias trx: __trx Component.onCompleted: console.log("Made a transaction confirmation form") Component.onDestruction: console.log("Destroyed a transaction confirmation form") onDisplay: { - trx = app.createTransaction() + trx.clearOperations() for (var op in arg) trx.appendOperation(arg[op]) } - Rectangle { - width: Scaling.cm(10) - height: childrenRect.height + Scaling.cm(1) - radius: Scaling.mm(3) - color: "#EEEEEE" - border.width: Scaling.mm(.25) - border.color: "black" + Transaction { + id: __trx + } - Column { - y: Scaling.cm(.5) - x: y - width: parent.width - Scaling.cm(1) - Repeater { - model: trx? trx.operations : [] - Label { - property Asset transferAsset: app.model.getAsset(modelData.amountType) - property Asset feeAsset: app.model.getAsset(modelData.feeType) - text: { - return qsTr("Transfer %1 %2 from %3 to %4\nFee: %5 %6").arg(transferAsset.formatAmount(modelData.amount)) - .arg(transferAsset.symbol) - .arg(app.model.getAccount(modelData.sender).name) - .arg(app.model.getAccount(modelData.receiver).name) - .arg(feeAsset.formatAmount(modelData.fee)) - .arg(feeAsset.symbol) - } + Rectangle { + id: trxBackground + anchors.fill: trxColumn + anchors.margins: Scaling.mm(-2) + layer.enabled: true + layer.effect: DropShadow { + radius: 8.0 + samples: 16 + horizontalOffset: Scaling.mm(.5) + verticalOffset: Scaling.mm(.5) + source: trxBackground + color: "#80000000" + transparentBorder: true + } + } + Column { + id: trxColumn + Layout.preferredWidth: Scaling.cm(10) + spacing: Scaling.mm(2) + + Repeater { + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + model: trx.operations + Label { + property Asset transferAsset: app.model.getAsset(modelData.amountType) + property Asset feeAsset: app.model.getAsset(modelData.feeType) + text: { + return qsTr("Transfer %1 %2 from %3 to %4\nFee: %5 %6").arg(transferAsset.formatAmount(modelData.amount)) + .arg(transferAsset.symbol) + .arg(app.model.getAccount(modelData.sender).name) + .arg(app.model.getAccount(modelData.receiver).name) + .arg(feeAsset.formatAmount(modelData.fee)) + .arg(feeAsset.symbol) } } } } - Item { width: 1; height: 1 } RowLayout { Label { text: qsTr("Transaction expires in") @@ -82,10 +94,7 @@ FormBase { app: base.app Layout.fillWidth: true rightButtonText: qsTr("Commit") - onLeftButtonClicked: { - canceled({}) - trx = null - } + onLeftButtonClicked: canceled({}) onRightButtonClicked: { if (app.wallet.isLocked) app.wallet.unlock(passwordField.text)