Compare commits

...

4 Commits

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 87 KiB

@ -433,6 +433,7 @@ Popup {
id: addSubCategoryButton
width: 50; height: 50
text: qsTr("+")
hoverEnabled: true
visible: Backend.hasSubCategory(Backend.getCategoryIdByName(productCategoryBox.currentText))
background: Rectangle {
color: parent.hovered ? "#698b22" : "#506a1a"//"#605185"
@ -500,7 +501,8 @@ Popup {
id: removeSubCategoryButton
width: 50; height: 50
text: qsTr("x")
background: Rectangle {
hoverEnabled: true
background: Rectangle {
color: parent.hovered ? "#b22222" : "#921c1c"
radius: productDialog.inputRadius
}

@ -250,80 +250,156 @@ Page {
id: sendTabColumn
anchors.fill: parent
spacing: 20 // spacing between each item inside the column
// addressField
TextField {
id: addressField
anchors.horizontalCenter: parent.horizontalCenter
width: 500/*parent.width*/; height: 50
placeholderText: qsTr("Receiver address")
color: balanceTxColumn.textColor
selectByMouse: true
maximumLength: 95//200 // TODO: set to 200 when Seraphis goes live
background: Rectangle {
color: balanceTxColumn.baseColor
border.color: balanceTxColumn.borderColor
border.width: parent.activeFocus ? 2 : 1
radius: balanceTxColumn.radius
}
rightPadding: resolveButton.visible ? (15 + resolveButton.width) : leftPadding
Button {
id: resolveButton
text: qsTr("Resolve")
anchors.right: parent.right
anchors.rightMargin: 10
anchors.verticalCenter: parent.verticalCenter
hoverEnabled: true
visible: Wallet.isValidOpenAliasAddress(addressField.text)
////onClicked: // TODO: handle OpenAlias resolution
background: Rectangle {
color: NeroshopComponents.Style.moneroGrayColor
radius: 10
ListModel {
id: recipientModel
ListElement {}
}
Repeater {
id: recipientRepeater
model: recipientModel
delegate: Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: 5
// addressField
TextField {
id: addressField
width: 450/*parent.width*/; height: 50
placeholderText: qsTr("Receiver address")
color: balanceTxColumn.textColor
selectByMouse: true
maximumLength: 95//200 // TODO: set to 200 when Seraphis goes live
background: Rectangle {
color: balanceTxColumn.baseColor
border.color: balanceTxColumn.borderColor
border.width: parent.activeFocus ? 2 : 1
radius: balanceTxColumn.radius
}
rightPadding: resolveButton.visible ? (15 + resolveButton.width) : leftPadding
Button {
id: resolveButton
text: qsTr("Resolve")
anchors.right: parent.right
anchors.rightMargin: 10
anchors.verticalCenter: parent.verticalCenter
hoverEnabled: true
visible: Wallet.isValidOpenAliasAddress(addressField.text)
////onClicked: // TODO: handle OpenAlias resolution
background: Rectangle {
color: NeroshopComponents.Style.moneroGrayColor
radius: 10
}
contentItem: Text {
text: parent.text
color: "#ffffff"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
MouseArea {
anchors.fill: parent
onPressed: mouse.accepted = false
cursorShape: Qt.PointingHandCursor
}
}
}
contentItem: Text {
text: parent.text
color: "#ffffff"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
// amountField
TextField {
id: amountField
width: 200/*parent.width*/; height: addressField.height
placeholderText: qsTr("Amount")//0.000000000000
color: balanceTxColumn.textColor
selectByMouse: true
validator: RegExpValidator{ regExp: new RegExp("^-?[0-9]+(\\.[0-9]{1," + Number(12) + "})?$") }
background: Rectangle {
color: balanceTxColumn.baseColor
border.color: balanceTxColumn.borderColor
border.width: parent.activeFocus ? 2 : 1
radius: balanceTxColumn.radius
}
rightPadding: 15 + allButton.width
Button {
id: allButton
text: qsTr("\uf534")
anchors.right: parent.right
anchors.rightMargin: 10
anchors.verticalCenter: parent.verticalCenter
implicitWidth: 32; implicitHeight: 24
hoverEnabled: true
onClicked: amountField.text = Wallet.getBalanceUnlocked().toFixed(12)
background: Rectangle {
color: NeroshopComponents.Style.moneroGrayColor
radius: 10//amountField.background.radius//5
}
contentItem: Text {
text: parent.text
color: "#ffffff"
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.bold: true
font.family: FontAwesome.fontFamily
}
MouseArea {
anchors.fill: parent
onPressed: mouse.accepted = false
cursorShape: Qt.PointingHandCursor
}
}
}
}
}
// amountField
TextField {
id: amountField
//removeRecipientButton
Button {
id: removeRecipientButton
width: 20; height: 20
anchors.verticalCenter: amountField.verticalCenter
text: qsTr(FontAwesome.xmark)
hoverEnabled: true
visible: (recipientRepeater.count > 1)
background: Rectangle {
color: "transparent"//parent.hovered ? "firebrick" : "transparent"
radius: 5
opacity: 0.7
}
contentItem: Text {
text: parent.text
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.bold: true
font.family: FontAwesome.fontFamily
}
onClicked: {
recipientModel.remove(index)
}
MouseArea {
anchors.fill: parent
onPressed: mouse.accepted = false
cursorShape: Qt.PointingHandCursor
}
}
} // Row
} // Repeater
// addRecipientButton
Button {
id: addRecipientButton
anchors.horizontalCenter: parent.horizontalCenter
width: 500/*parent.width*/; height: 50
placeholderText: qsTr("Amount")//0.000000000000
color: balanceTxColumn.textColor
selectByMouse: true
validator: RegExpValidator{ regExp: new RegExp("^-?[0-9]+(\\.[0-9]{1," + Number(12) + "})?$") }
background: Rectangle {
color: balanceTxColumn.baseColor
border.color: balanceTxColumn.borderColor
border.width: parent.activeFocus ? 2 : 1
radius: balanceTxColumn.radius
text: qsTr("+ Add Recipient")
width: 140; height: contentItem.content + 30
background: Rectangle {
color: parent.hovered ? "#698b22" : "#506a1a"
radius: 5
}
rightPadding: 15 + allButton.width
Button {
id: allButton
text: qsTr("\uf534")
anchors.right: parent.right
anchors.rightMargin: 10
anchors.verticalCenter: parent.verticalCenter
implicitWidth: 32; implicitHeight: 24
hoverEnabled: true
onClicked: amountField.text = Wallet.getBalanceUnlocked().toFixed(12)
background: Rectangle {
color: NeroshopComponents.Style.moneroGrayColor
radius: 10//amountField.background.radius//5
}
contentItem: Text {
text: parent.text
color: "#ffffff"
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.bold: true
font.family: FontAwesome.fontFamily
}
contentItem: Text {
text: parent.text
color: "#ffffff"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
onClicked: {
recipientModel.append({})
}
MouseArea {
anchors.fill: parent
onPressed: mouse.accepted = false
cursorShape: Qt.PointingHandCursor
}
}
// sendButton
@ -343,11 +419,21 @@ Page {
verticalAlignment: Text.AlignVCenter
}
onClicked: {
if(!Wallet.isSynced()) {
messageBox.text = qsTr("wallet must be fully synced with daemon")
messageBox.open()
return
}
if(settingsDialog.requirePasswordOnWithdrawal) {
walletPasswordSendPrompt.open()
walletPasswordSendPrompt.editAt(1).forceActiveFocus()
}
else Wallet.transfer(addressField.text, amountField.text)
else Wallet.transfer(recipientRepeater.itemAt(0).children[0].text, recipientRepeater.itemAt(0).children[1].text)
}
MouseArea {
anchors.fill: parent
onPressed: mouse.accepted = false
cursorShape: Qt.PointingHandCursor
}
}
}
@ -392,10 +478,28 @@ Page {
password_edit.text = ""
return;
}
Wallet.transfer(addressField.text, amountField.text)
if(recipientRepeater.count == 1) {
Wallet.transfer(recipientRepeater.itemAt(0).children[0].text, recipientRepeater.itemAt(0).children[1].text)
} else {
let recipients = [];
for (let i = 0; i < recipientRepeater.count; i++) {
let address = recipientRepeater.itemAt(i).children[0].text;
let amount = recipientRepeater.itemAt(i).children[1].text;
// Create an object with address and amount fields
let recipientObject = {
address: address,
amount: amount
};
// Push the object into the recipients array
recipients.push(recipientObject);
}
Wallet.transfer(recipients)
}
// TODO: clear address and amount field if transfer was successful
/*addressField.text = ""
amountField.text = ""*/
onCloseCallback()
close()
}

@ -302,7 +302,7 @@ void neroshop::Wallet::transfer(const std::string& address, double amount) {
worker.detach(); // join may block but detach won't//void transfer_result = future_result.get();
}
//-------------------------------------------------------
void neroshop::Wallet::transfer(const std::vector<std::pair<std::string, double>>& payment_addresses) { // untested
void neroshop::Wallet::transfer(const std::vector<std::pair<std::string, double>>& payment_addresses) {
if(!monero_wallet_obj.get()) throw std::runtime_error("monero_wallet_full is not opened");
if(!monero_wallet_obj.get()->is_synced()) throw std::runtime_error("wallet is not synced with a daemon");
@ -312,10 +312,10 @@ void neroshop::Wallet::transfer(const std::vector<std::pair<std::string, double>
// Calculate the total amount owed
double total_amount = 0.000000000000;
for (const auto& address : payment_addresses) {
total_amount += address.second;
for (const auto& recipient : payment_addresses) {
total_amount += recipient.second;
}
std::cout << "Total amount to pay: " << total_amount << " (xmr)\n";
std::cout << "Total amount to pay: " << std::fixed << std::setprecision(12) << total_amount << " (xmr)\n";
// Check if balance is sufficient
uint64_t total_to_piconero = total_amount / PICONERO;
std::cout << "Wallet balance (spendable): " << monero_wallet_obj->get_unlocked_balance() << " (picos)\n";
@ -325,19 +325,23 @@ void neroshop::Wallet::transfer(const std::vector<std::pair<std::string, double>
}
// Add each destination
std::vector<std::shared_ptr<monero_destination>> destinations; // specify the recipients and their amounts
for(const auto& address : payment_addresses) {
for(const auto& recipient : payment_addresses) {
// Check if address is valid
if(!monero_utils::is_valid_address(address.first, monero_wallet_obj->get_network_type())) {
neroshop::print(address.first + " is not a valid Monero address", 1);
if(!monero_utils::is_valid_address(recipient.first, monero_wallet_obj->get_network_type())) {
neroshop::print(recipient.first + " is not a valid Monero address", 1);
continue; // skip to the next address
}
// Convert monero to piconero
uint64_t monero_to_piconero = address.second / PICONERO; //std::cout << neroshop::string::precision(address.second, 12) << " xmr to piconero: " << monero_to_piconero << "\n";
destinations.push_back(std::make_shared<monero_destination>(address.first, monero_to_piconero));
uint64_t monero_to_piconero = recipient.second / PICONERO; //std::cout << neroshop::string::precision(recipient.second, 12) << " xmr to piconero: " << monero_to_piconero << "\n";
destinations.push_back(std::make_shared<monero_destination>(recipient.first, monero_to_piconero));
// Print address and amount
std::cout << "Address: " << address.first << ", Amount: " << address.second << std::endl;
std::cout << "Address: " << recipient.first << ", Amount: " << recipient.second << std::endl;
}
tx_config.m_destinations = destinations;
if(tx_config.m_destinations.empty()) {
std::cerr << "\033[1;91mNo destinations for this transfer" << "\033[0m\n";
return;
}
// Create the transaction, confirm with the user, and relay to the network
std::shared_ptr<monero_tx_wallet> created_tx = monero_wallet_obj->create_tx(tx_config);

@ -98,6 +98,20 @@ void neroshop::WalletController::transfer(const QString& address, double amount)
_wallet->transfer(address.toStdString(), amount);
}
void neroshop::WalletController::transfer(const QVariantList &recipients) {
if (!_wallet) throw std::runtime_error("neroshop::Wallet is not initialized");
std::vector<std::pair<std::string, double>> payment_addresses;
for (const QVariant &recipient : recipients) {
QVariantMap recipientMap = recipient.toMap();
QString address = recipientMap["address"].toString();
double amount = recipientMap["amount"].toDouble();
payment_addresses.push_back(std::make_pair(address.toStdString(), amount));
}
_wallet->transfer(payment_addresses);
}
QString neroshop::WalletController::signMessage(const QString& message) const {
if (!_wallet)
throw std::runtime_error("neroshop::Wallet is not initialized");
@ -112,6 +126,29 @@ bool neroshop::WalletController::verifyMessage(const QString& message, const QSt
return _wallet->verify_message(message.toStdString(), signature.toStdString());
}
QString neroshop::WalletController::makeUri(const QString& address, double tx_amount, const QString& tx_description, const QString& recipient_name) const {
if(!_wallet) throw std::runtime_error("neroshop::Wallet is not initialized");
return QString::fromStdString(_wallet->make_uri(address.toStdString(), tx_amount, tx_description.toStdString(), recipient_name.toStdString()));
}
QVariantMap neroshop::WalletController::parseUriToObject(const QString& uri) const {
if(!_wallet) throw std::runtime_error("neroshop::Wallet is not initialized");
QVariantMap uri_object;
std::string address;
double tx_amount;
std::string tx_description;
std::string recipient_name;
Wallet::parse_uri(uri.toStdString(), address, tx_amount, tx_description, recipient_name);
uri_object.insert("address", QString::fromStdString(address));
uri_object.insert("tx_amount", tx_amount);
uri_object.insert("tx_description", QString::fromStdString(tx_description));
uri_object.insert("recipient_name", QString::fromStdString(recipient_name));
return uri_object;
}
int neroshop::WalletController::getWalletType() const {
if (!_wallet)
throw std::runtime_error("neroshop::Wallet is not initialized");

@ -35,8 +35,11 @@ public:
Q_INVOKABLE bool verifyPassword(const QString& password);
Q_INVOKABLE QVariantMap/*QMap<QString, QVariant>*/ createUniqueSubaddressObject(unsigned int account_idx, const QString & label = "");
Q_INVOKABLE void transfer(const QString& address, double amount);
Q_INVOKABLE void transfer(const QVariantList &recipients);
Q_INVOKABLE QString signMessage(const QString& message) const;
Q_INVOKABLE bool verifyMessage(const QString& message, const QString& signature) const;
Q_INVOKABLE QString makeUri(const QString& address, double tx_amount, const QString& tx_description, const QString& recipient_name) const;
Q_INVOKABLE QVariantMap parseUriToObject(const QString& uri) const;
Q_INVOKABLE double getSyncPercentage() const;
Q_INVOKABLE unsigned int getSyncHeight() const;

Loading…
Cancel
Save