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)