[GUI] Add option to encrypt transfer memos
Also, refactor common unlocking finish/cancel buttons into a reusable component
This commit is contained in:
parent
8a8130f620
commit
02682e761c
6 changed files with 106 additions and 43 deletions
|
|
@ -28,12 +28,25 @@ TransferOperation* OperationBuilder::transfer(ObjectId sender, ObjectId receiver
|
||||||
QString TransferOperation::memo() const {
|
QString TransferOperation::memo() const {
|
||||||
if (!m_op.memo)
|
if (!m_op.memo)
|
||||||
return QString::null;
|
return QString::null;
|
||||||
|
if (memoIsEncrypted())
|
||||||
|
return tr("Encrypted Memo");
|
||||||
QString memo = QString::fromStdString(m_op.memo->get_message({}, {}));
|
QString memo = QString::fromStdString(m_op.memo->get_message({}, {}));
|
||||||
while (memo.endsWith('\0'))
|
while (memo.endsWith('\0'))
|
||||||
memo.chop(1);
|
memo.chop(1);
|
||||||
return memo;
|
return memo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TransferOperation::memoIsEncrypted() const
|
||||||
|
{
|
||||||
|
if (!m_op.memo)
|
||||||
|
return false;
|
||||||
|
if (m_op.memo->message.empty())
|
||||||
|
return false;
|
||||||
|
if (m_op.memo->from == public_key_type() && m_op.memo->to == public_key_type())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool TransferOperation::canEncryptMemo(Wallet* wallet, ChainDataModel* model) const
|
bool TransferOperation::canEncryptMemo(Wallet* wallet, ChainDataModel* model) const
|
||||||
{
|
{
|
||||||
if (!m_op.memo) return false;
|
if (!m_op.memo) return false;
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ class TransferOperation : public OperationBase {
|
||||||
Q_PROPERTY(qint64 amount READ amount WRITE setAmount NOTIFY amountChanged)
|
Q_PROPERTY(qint64 amount READ amount WRITE setAmount NOTIFY amountChanged)
|
||||||
Q_PROPERTY(ObjectId amountType READ amountType WRITE setAmountType NOTIFY amountTypeChanged)
|
Q_PROPERTY(ObjectId amountType READ amountType WRITE setAmountType NOTIFY amountTypeChanged)
|
||||||
Q_PROPERTY(QString memo READ memo WRITE setMemo NOTIFY memoChanged)
|
Q_PROPERTY(QString memo READ memo WRITE setMemo NOTIFY memoChanged)
|
||||||
|
Q_PROPERTY(bool memoIsEncrypted READ memoIsEncrypted NOTIFY memoChanged)
|
||||||
|
|
||||||
graphene::chain::transfer_operation m_op;
|
graphene::chain::transfer_operation m_op;
|
||||||
|
|
||||||
|
|
@ -60,6 +61,7 @@ public:
|
||||||
/// performed by calling encryptMemo()
|
/// performed by calling encryptMemo()
|
||||||
QString memo() const;
|
QString memo() const;
|
||||||
|
|
||||||
|
bool memoIsEncrypted()const;
|
||||||
Q_INVOKABLE bool canEncryptMemo(Wallet* wallet, ChainDataModel* model) const;
|
Q_INVOKABLE bool canEncryptMemo(Wallet* wallet, ChainDataModel* model) const;
|
||||||
Q_INVOKABLE bool canDecryptMemo(Wallet* wallet, ChainDataModel* model) const;
|
Q_INVOKABLE bool canDecryptMemo(Wallet* wallet, ChainDataModel* model) const;
|
||||||
Q_INVOKABLE QString decryptedMemo(Wallet* wallet, ChainDataModel* model) const;
|
Q_INVOKABLE QString decryptedMemo(Wallet* wallet, ChainDataModel* model) const;
|
||||||
|
|
|
||||||
|
|
@ -62,36 +62,19 @@ FormBase {
|
||||||
Loader {
|
Loader {
|
||||||
sourceComponent: trx && Array.prototype.slice.call(trx.operations).length > 0? transactionDelegate : undefined
|
sourceComponent: trx && Array.prototype.slice.call(trx.operations).length > 0? transactionDelegate : undefined
|
||||||
}
|
}
|
||||||
RowLayout {
|
UnlockingFinishButtons {
|
||||||
|
app: base.app
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Item { Layout.fillWidth: true }
|
onLeftButtonClicked: {
|
||||||
Button {
|
canceled({})
|
||||||
text: qsTr("Cancel")
|
trx = null
|
||||||
onClicked: {
|
|
||||||
canceled({})
|
|
||||||
trx = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TextField {
|
onRightButtonClicked: {
|
||||||
id: passwordField
|
if (app.wallet.isLocked)
|
||||||
Layout.preferredWidth: app.wallet.isLocked? Scaling.cm(4) : 0
|
app.wallet.unlock(passwordField.text)
|
||||||
echoMode: TextInput.Password
|
else {
|
||||||
placeholderText: qsTr("Wallet password")
|
app.wallet.sign(trx)
|
||||||
visible: width > 0
|
completed(trx)
|
||||||
onAccepted: finishButton.clicked()
|
|
||||||
|
|
||||||
Behavior on Layout.preferredWidth { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } }
|
|
||||||
}
|
|
||||||
Button {
|
|
||||||
id: finishButton
|
|
||||||
text: app.wallet.isLocked? qsTr("Unlock") : qsTr("Finish")
|
|
||||||
onClicked: {
|
|
||||||
if (app.wallet.isLocked)
|
|
||||||
app.wallet.unlock(passwordField.text)
|
|
||||||
else {
|
|
||||||
app.wallet.sign(trx)
|
|
||||||
completed(trx)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import QtQuick 2.5
|
import QtQuick 2.5
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
import QtQuick.Dialogs 1.2
|
|
||||||
import QtQuick.Layouts 1.2
|
import QtQuick.Layouts 1.2
|
||||||
|
|
||||||
import Graphene.Client 0.1
|
import Graphene.Client 0.1
|
||||||
|
|
@ -19,7 +18,7 @@ FormBase {
|
||||||
property alias receiverAccount: recipientPicker.account
|
property alias receiverAccount: recipientPicker.account
|
||||||
|
|
||||||
function operation() {
|
function operation() {
|
||||||
if (!transferButton.enabled) return app.operationBuilder.transfer(0,0,0,0, memoField.text, 0)
|
if (!finishLine.rightButtonEnabled) return app.operationBuilder.transfer(0,0,0,0, memoField.text, 0)
|
||||||
|
|
||||||
return app.operationBuilder.transfer(senderPicker.account.id, recipientPicker.account.id,
|
return app.operationBuilder.transfer(senderPicker.account.id, recipientPicker.account.id,
|
||||||
amountField.value * amountField.precisionAdjustment,
|
amountField.value * amountField.precisionAdjustment,
|
||||||
|
|
@ -56,10 +55,18 @@ FormBase {
|
||||||
placeholderText: qsTr("Recipient")
|
placeholderText: qsTr("Recipient")
|
||||||
layoutDirection: Qt.RightToLeft
|
layoutDirection: Qt.RightToLeft
|
||||||
}
|
}
|
||||||
TextField {
|
RowLayout {
|
||||||
id: memoField
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
placeholderText: qsTr("Memo")
|
TextField {
|
||||||
|
id: memoField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
placeholderText: qsTr("Memo")
|
||||||
|
}
|
||||||
|
CheckBox {
|
||||||
|
id: encryptMemoField
|
||||||
|
text: qsTr("Encrypt Memo")
|
||||||
|
checked: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
@ -97,18 +104,25 @@ FormBase {
|
||||||
return qsTr("Fee:<br/>") + amountField.maxBalance.type.formatAmount(operation().fee) + " CORE"
|
return qsTr("Fee:<br/>") + amountField.maxBalance.type.formatAmount(operation().fee) + " CORE"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item { Layout.fillWidth: true }
|
}
|
||||||
Button {
|
UnlockingFinishButtons {
|
||||||
text: qsTr("Cancel")
|
id: finishLine
|
||||||
onClicked: canceled({})
|
app: base.app
|
||||||
}
|
rightButtonText: {
|
||||||
Button {
|
return !senderAccount ||
|
||||||
id: transferButton
|
|
||||||
text: !senderAccount ||
|
|
||||||
!senderAccount.isLoaded ||
|
!senderAccount.isLoaded ||
|
||||||
senderPicker.accountControlLevel >= 1? qsTr("Transfer") : qsTr("Propose")
|
senderPicker.accountControlLevel >= 1? qsTr("Transfer") : qsTr("Propose")
|
||||||
enabled: senderPicker.account && recipientPicker.account && senderPicker.account !== recipientPicker.account && amountField.value
|
}
|
||||||
onClicked: completed([operation()])
|
rightButtonEnabled: senderPicker.account && recipientPicker.account && senderPicker.account !== recipientPicker.account && amountField.value
|
||||||
|
requiresUnlocking: encryptMemoField.checked
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
onLeftButtonClicked: canceled({})
|
||||||
|
onRightButtonClicked: {
|
||||||
|
var op = operation()
|
||||||
|
if (encryptMemoField.checked)
|
||||||
|
op.encryptMemo(app.wallet, app.model)
|
||||||
|
completed([op])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
50
programs/light_client/qml/UnlockingFinishButtons.qml
Normal file
50
programs/light_client/qml/UnlockingFinishButtons.qml
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
import QtQuick.Layouts 1.2
|
||||||
|
|
||||||
|
import "."
|
||||||
|
|
||||||
|
import Graphene.Client 0.1
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
property string leftButtonText: qsTr("Cancel")
|
||||||
|
property string unlockButtonText: qsTr("Unlock")
|
||||||
|
property string rightButtonText: qsTr("Finish")
|
||||||
|
property bool leftButtonEnabled: true
|
||||||
|
property bool rightButtonEnabled: true
|
||||||
|
property bool requiresUnlocking: true
|
||||||
|
property GrapheneApplication app
|
||||||
|
|
||||||
|
signal leftButtonClicked
|
||||||
|
signal rightButtonClicked
|
||||||
|
|
||||||
|
Item { Layout.fillWidth: true }
|
||||||
|
Button {
|
||||||
|
text: leftButtonText
|
||||||
|
onClicked: leftButtonClicked()
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: passwordField
|
||||||
|
property bool shown: requiresUnlocking && app.wallet.isLocked
|
||||||
|
property real desiredWidth: shown? Scaling.cm(4) : 0
|
||||||
|
Layout.preferredWidth: desiredWidth
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
placeholderText: qsTr("Wallet password")
|
||||||
|
visible: desiredWidth > 0
|
||||||
|
onAccepted: rightButton.clicked()
|
||||||
|
|
||||||
|
Behavior on desiredWidth { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } }
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
id: rightButton
|
||||||
|
text: passwordField.shown? unlockButtonText : rightButtonText
|
||||||
|
enabled: rightButtonEnabled
|
||||||
|
onClicked: {
|
||||||
|
if (passwordField.visible)
|
||||||
|
return app.wallet.unlock(passwordField.text)
|
||||||
|
|
||||||
|
rightButtonClicked()
|
||||||
|
}
|
||||||
|
Behavior on implicitWidth { NumberAnimation {} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
<file>TransactionConfirmationForm.qml</file>
|
<file>TransactionConfirmationForm.qml</file>
|
||||||
<file>FormBox.qml</file>
|
<file>FormBox.qml</file>
|
||||||
<file>FormFlipper.qml</file>
|
<file>FormFlipper.qml</file>
|
||||||
|
<file>UnlockingFinishButtons.qml</file>
|
||||||
<file>Scaling.qml</file>
|
<file>Scaling.qml</file>
|
||||||
<file>Identicon.qml</file>
|
<file>Identicon.qml</file>
|
||||||
<file>AccountPicker.qml</file>
|
<file>AccountPicker.qml</file>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue