mirror of
https://github.com/monero-project/monero-gui.git
synced 2025-01-03 09:29:38 +00:00
History: display details of transactions with multiple recipients
This commit is contained in:
parent
2946127ed7
commit
7b2c886ddc
4 changed files with 209 additions and 67 deletions
|
@ -16,6 +16,7 @@ Text {
|
||||||
property alias tooltipLeft: tooltip.tooltipLeft
|
property alias tooltipLeft: tooltip.tooltipLeft
|
||||||
property alias tooltipIconVisible: tooltip.tooltipIconVisible
|
property alias tooltipIconVisible: tooltip.tooltipIconVisible
|
||||||
property alias tooltipPopup: tooltip.tooltipPopup
|
property alias tooltipPopup: tooltip.tooltipPopup
|
||||||
|
property alias tooltipWrapMode: tooltip.tooltipWrapMode
|
||||||
font.family: MoneroComponents.Style.fontMedium.name
|
font.family: MoneroComponents.Style.fontMedium.name
|
||||||
font.bold: false
|
font.bold: false
|
||||||
font.pixelSize: 14
|
font.pixelSize: 14
|
||||||
|
|
|
@ -36,6 +36,7 @@ import "." as MoneroComponents
|
||||||
Rectangle {
|
Rectangle {
|
||||||
property alias text: tooltip.text
|
property alias text: tooltip.text
|
||||||
property alias tooltipPopup: popup
|
property alias tooltipPopup: popup
|
||||||
|
property alias tooltipWrapMode: tooltip.wrapMode
|
||||||
property bool tooltipIconVisible: false
|
property bool tooltipIconVisible: false
|
||||||
property bool tooltipLeft: false
|
property bool tooltipLeft: false
|
||||||
property bool tooltipBottom: tooltipIconVisible ? false : true
|
property bool tooltipBottom: tooltipIconVisible ? false : true
|
||||||
|
|
|
@ -2,13 +2,33 @@ function destinationsToAmount(destinations){
|
||||||
// Gets amount from destinations line
|
// Gets amount from destinations line
|
||||||
// input: "20.000000000000: 9tLGyK277MnYrDc7Vzi6TB1pJvstFoviziFwsqQNFbwA9rvg5RxYVYjEezFKDjvDHgAzTELJhJHVx6JAaWZKeVqSUZkXeKk"
|
// input: "20.000000000000: 9tLGyK277MnYrDc7Vzi6TB1pJvstFoviziFwsqQNFbwA9rvg5RxYVYjEezFKDjvDHgAzTELJhJHVx6JAaWZKeVqSUZkXeKk"
|
||||||
// returns: 20.000000000000
|
// returns: 20.000000000000
|
||||||
return destinations.split(" ")[0].split(":")[0];
|
var numberOfDestinations = (destinations.match(/:/g) || []).length;
|
||||||
|
var amountList = "";
|
||||||
|
for (var i = 0; i < numberOfDestinations; i++) {
|
||||||
|
var destinationAndAmount = destinations.split("<br> ")[i];
|
||||||
|
var amount = destinationAndAmount.split(":")[0];
|
||||||
|
if (i+1 != numberOfDestinations) {
|
||||||
|
amountList += amount + " ";
|
||||||
|
} else {
|
||||||
|
amountList += amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return amountList;
|
||||||
}
|
}
|
||||||
|
|
||||||
function destinationsToAddress(destinations){
|
function destinationsToAddress(destinations){
|
||||||
var address = destinations.split(" ")[1];
|
var numberOfDestinations = (destinations.match(/:/g) || []).length;
|
||||||
if(address === undefined) return ""
|
var addressList = "";
|
||||||
return address;
|
for (var i = 0; i < numberOfDestinations; i++) {
|
||||||
|
var destinationAndAmount = destinations.split("<br> ")[i];
|
||||||
|
var address = destinationAndAmount.split(": ")[1];
|
||||||
|
if (i+1 != numberOfDestinations) {
|
||||||
|
addressList += address + " ";
|
||||||
|
} else {
|
||||||
|
addressList += address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addressList;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addressTruncate(address, range){
|
function addressTruncate(address, range){
|
||||||
|
|
|
@ -573,7 +573,7 @@ Rectangle {
|
||||||
anchors.right: parent ? parent.right : undefined
|
anchors.right: parent ? parent.right : undefined
|
||||||
height: {
|
height: {
|
||||||
if(!collapsed) return 60;
|
if(!collapsed) return 60;
|
||||||
return 320;
|
return 200 + middleColumn.height;
|
||||||
}
|
}
|
||||||
color: {
|
color: {
|
||||||
if(!collapsed) return "transparent"
|
if(!collapsed) return "transparent"
|
||||||
|
@ -628,9 +628,10 @@ Rectangle {
|
||||||
Layout.preferredHeight: 60
|
Layout.preferredHeight: 60
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
id: leftColumn
|
||||||
spacing: 0
|
spacing: 0
|
||||||
clip: true
|
clip: true
|
||||||
Layout.preferredHeight: 120
|
Layout.preferredHeight: 100 + amountRectangle.height
|
||||||
Layout.minimumWidth: 180
|
Layout.minimumWidth: 180
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
@ -656,23 +657,63 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
id: amountRectangle
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: 20
|
Layout.preferredHeight: amountColumn.height
|
||||||
|
Component.onCompleted: {
|
||||||
|
var amountListArray = [];
|
||||||
|
amountListArray = amountList.split(" ");
|
||||||
|
for (var i = 0; i < amountListArray.length; i++) {
|
||||||
|
amountFieldModel.append({amountArray: amountListArray[i]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MoneroComponents.TextPlain {
|
ListModel {
|
||||||
font.family: MoneroComponents.Style.fontRegular.name
|
id: amountFieldModel
|
||||||
font.pixelSize: 15
|
}
|
||||||
text: (amount == 0 ? qsTr("Unknown amount") : displayAmount) + translationManager.emptyString
|
|
||||||
color: MoneroComponents.Style.defaultFontColor
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
MouseArea {
|
ColumnLayout {
|
||||||
state: "copyable"
|
id: amountColumn
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
Repeater {
|
||||||
onEntered: parent.color = MoneroComponents.Style.orange
|
id: amountFieldRepeater
|
||||||
onExited: parent.color = MoneroComponents.Style.defaultFontColor
|
model: amountFieldModel
|
||||||
|
|
||||||
|
MoneroComponents.TextPlain {
|
||||||
|
id: amountField
|
||||||
|
font.family: MoneroComponents.Style.fontRegular.name
|
||||||
|
font.pixelSize: 15
|
||||||
|
textFormat: Text.RichText
|
||||||
|
color: MoneroComponents.Style.defaultFontColor
|
||||||
|
text: {
|
||||||
|
if (numberOfDestinations > 1) {
|
||||||
|
if(!collapsed) {
|
||||||
|
if (index == 0) {
|
||||||
|
return displayAmount;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return amountFieldModel.get(index).amountArray + " XMR"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (amount == 0) {
|
||||||
|
return qsTr("Unknown amount") + translationManager.emptyString
|
||||||
|
} else {
|
||||||
|
return displayAmount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
state: "copyable"
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
onEntered: parent.color = MoneroComponents.Style.orange
|
||||||
|
onExited: parent.color = MoneroComponents.Style.defaultFontColor
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -740,9 +781,10 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
id: middleColumn
|
||||||
spacing: 0
|
spacing: 0
|
||||||
clip: true
|
clip: true
|
||||||
Layout.preferredHeight: 120
|
Layout.preferredHeight: 100 + addressRectangle.height
|
||||||
Layout.minimumWidth: 230
|
Layout.minimumWidth: 230
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
@ -768,51 +810,101 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
id: addressRectangle
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: 20
|
Layout.preferredHeight: addressColumn.height
|
||||||
|
Component.onCompleted: {
|
||||||
|
var addressListArray = [];
|
||||||
|
addressListArray = addressList.split(" ");
|
||||||
|
for (var i = 0; i < addressListArray.length; i++) {
|
||||||
|
addressFieldModel.append({addressArray: addressListArray[i]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MoneroComponents.TextPlain {
|
ListModel {
|
||||||
id: addressField
|
id: addressFieldModel
|
||||||
font.family: MoneroComponents.Style.fontRegular.name
|
}
|
||||||
font.pixelSize: 15
|
|
||||||
text: {
|
ColumnLayout {
|
||||||
if (isout) {
|
id: addressColumn
|
||||||
if (address) {
|
|
||||||
return (addressBookName ? FontAwesome.addressBook + " " + addressBookName : TxUtils.addressTruncate(address, 8));
|
Repeater {
|
||||||
}
|
id: addressFieldRepeater
|
||||||
if (amount != 0) {
|
model: addressFieldModel
|
||||||
return qsTr("Unknown recipient") + translationManager.emptyString;
|
|
||||||
} else {
|
MoneroComponents.TextPlain {
|
||||||
return qsTr("My wallet") + translationManager.emptyString;
|
id: addressField
|
||||||
}
|
font.family: MoneroComponents.Style.fontRegular.name
|
||||||
} else {
|
font.pixelSize: 15
|
||||||
if (receivingAddress) {
|
textFormat: Text.RichText
|
||||||
if (subaddrIndex == 0) {
|
color: MoneroComponents.Style.defaultFontColor
|
||||||
return qsTr("Address") + " #0" + " (" + qsTr("Primary address") + ")" + translationManager.emptyString;
|
property var addressFromAddressListArray: ""
|
||||||
|
tooltip: numberOfDestinations > 1 ? (!collapsed ? "" : addressFromAddressListArray)
|
||||||
|
: address ? address
|
||||||
|
: receivingAddress ? receivingAddress
|
||||||
|
: ""
|
||||||
|
tooltipWrapMode: Text.Wrap
|
||||||
|
text: {
|
||||||
|
if (numberOfDestinations > 1) {
|
||||||
|
if(!collapsed) {
|
||||||
|
if (index == 0) {
|
||||||
|
return qsTr("Multiple recipients") + " (" + numberOfDestinations + ")" + translationManager.emptyString;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addressFromAddressListArray = addressFieldModel.get(index).addressArray;
|
||||||
|
var addressOnAddressBook = currentWallet ? currentWallet.addressBook.getDescription(addressFromAddressListArray) : null;
|
||||||
|
if (addressOnAddressBook) {
|
||||||
|
return FontAwesome.addressBook + " " + addressOnAddressBook;
|
||||||
|
} else {
|
||||||
|
return TxUtils.addressTruncate(addressFieldModel.get(index).addressArray, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (receivingAddressLabel) {
|
if (isout) {
|
||||||
return qsTr("Address") + " #" + subaddrIndex + " (" + receivingAddressLabel + ")" + translationManager.emptyString;
|
if (address) {
|
||||||
|
return (addressBookName ? FontAwesome.addressBook + " " + addressBookName : TxUtils.addressTruncate(address, 8));
|
||||||
|
}
|
||||||
|
if (amount != 0) {
|
||||||
|
return qsTr("Unknown recipient") + translationManager.emptyString;
|
||||||
|
} else {
|
||||||
|
return qsTr("My wallet") + translationManager.emptyString;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return qsTr("Address") + " #" + subaddrIndex + " (" + TxUtils.addressTruncate(receivingAddress, 4) + ")" + translationManager.emptyString;
|
if (receivingAddress) {
|
||||||
|
if (subaddrIndex == 0) {
|
||||||
|
return qsTr("Address") + " #0" + " (" + qsTr("Primary address") + ")" + translationManager.emptyString;
|
||||||
|
} else {
|
||||||
|
if (receivingAddressLabel) {
|
||||||
|
return qsTr("Address") + " #" + subaddrIndex + " (" + receivingAddressLabel + ")" + translationManager.emptyString;
|
||||||
|
} else {
|
||||||
|
return qsTr("Address") + " #" + subaddrIndex + " (" + TxUtils.addressTruncate(receivingAddress, 4) + ")" + translationManager.emptyString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return qsTr("Unknown address") + translationManager.emptyString;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
return qsTr("Unknown address") + translationManager.emptyString;
|
|
||||||
|
MouseArea {
|
||||||
|
state: isout ? "copyable_address" : "copyable_receiving_address"
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
onEntered: {
|
||||||
|
parent.color = MoneroComponents.Style.orange
|
||||||
|
tooltip ? parent.tooltipPopup.open() : ""
|
||||||
|
}
|
||||||
|
onExited: {
|
||||||
|
parent.color = MoneroComponents.Style.defaultFontColor
|
||||||
|
tooltip ? parent.tooltipPopup.close() : ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
color: MoneroComponents.Style.defaultFontColor
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
state: isout ? "copyable_address" : "copyable_receiving_address"
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
onEntered: parent.color = MoneroComponents.Style.orange
|
|
||||||
onExited: parent.color = MoneroComponents.Style.defaultFontColor
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -875,10 +967,12 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
id: rightColumn
|
||||||
spacing: 0
|
spacing: 0
|
||||||
clip: true
|
clip: true
|
||||||
Layout.preferredHeight: 120
|
Layout.preferredHeight: 120
|
||||||
Layout.minimumWidth: 130
|
Layout.minimumWidth: 130
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
@ -1245,7 +1339,9 @@ Rectangle {
|
||||||
for(var i = 0; i < res.length; i+=1){
|
for(var i = 0; i < res.length; i+=1){
|
||||||
if(res[i].containsMouse === true){
|
if(res[i].containsMouse === true){
|
||||||
if(res[i].state === 'copyable' && res[i].parent.hasOwnProperty('text')) toClipboard(res[i].parent.text);
|
if(res[i].state === 'copyable' && res[i].parent.hasOwnProperty('text')) toClipboard(res[i].parent.text);
|
||||||
if(res[i].state === 'copyable_address') (address ? root.toClipboard(address) : root.toClipboard(addressField.text));
|
if(res[i].state === 'copyable_address') (address ? root.toClipboard(address)
|
||||||
|
: res[i].parent.addressFromAddressListArray ? root.toClipboard(res[i].parent.addressFromAddressListArray)
|
||||||
|
: root.toClipboard(res[i].parent.text));
|
||||||
if(res[i].state === 'copyable_receiving_address') root.toClipboard(currentWallet.address(subaddrAccount, subaddrIndex));
|
if(res[i].state === 'copyable_receiving_address') root.toClipboard(currentWallet.address(subaddrAccount, subaddrIndex));
|
||||||
if(res[i].state === 'copyable_txkey') root.getTxKey(hash, res[i]);
|
if(res[i].state === 'copyable_txkey') root.getTxKey(hash, res[i]);
|
||||||
if(res[i].state === 'set_tx_note') root.editDescription(hash, tx_note);
|
if(res[i].state === 'set_tx_note') root.editDescription(hash, tx_note);
|
||||||
|
@ -1434,7 +1530,11 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(root.sortSearchString.length >= 1){
|
if(root.sortSearchString.length >= 1){
|
||||||
if(item.amount && item.amount.toString().startsWith(root.sortSearchString)){
|
if(item.displayAmount && item.displayAmount.startsWith(root.sortSearchString)){
|
||||||
|
txs.push(item);
|
||||||
|
} else if(item.amountList != "" && item.amountList.toLowerCase().includes(root.sortSearchString.toLowerCase())){
|
||||||
|
txs.push(item);
|
||||||
|
} else if(item.addressList != "" && item.addressList.toLowerCase().includes(root.sortSearchString.toLowerCase())){
|
||||||
txs.push(item);
|
txs.push(item);
|
||||||
} else if(item.address !== "" && item.address.toLowerCase().startsWith(root.sortSearchString.toLowerCase())){
|
} else if(item.address !== "" && item.address.toLowerCase().startsWith(root.sortSearchString.toLowerCase())){
|
||||||
txs.push(item);
|
txs.push(item);
|
||||||
|
@ -1538,26 +1638,43 @@ Rectangle {
|
||||||
var subaddrIndex = model.data(idx, TransactionHistoryModel.TransactionSubaddrIndexRole);
|
var subaddrIndex = model.data(idx, TransactionHistoryModel.TransactionSubaddrIndexRole);
|
||||||
var timestamp = new Date(date + " " + time).getTime() / 1000;
|
var timestamp = new Date(date + " " + time).getTime() / 1000;
|
||||||
var dateHuman = Utils.ago(timestamp);
|
var dateHuman = Utils.ago(timestamp);
|
||||||
|
var numberOfDestinations = (destinations.match(/:/g) || []).length;
|
||||||
|
var amountList = TxUtils.destinationsToAmount(destinations);
|
||||||
|
|
||||||
if (amount === 0) {
|
if (numberOfDestinations >1) {
|
||||||
// transactions to the same account have amount === 0, while the 'destinations string'
|
var totalAmount = 0;
|
||||||
// has the correct amount, so we try to fetch it from that instead.
|
for (var i = 0; i < numberOfDestinations; i++) {
|
||||||
amount = Number(TxUtils.destinationsToAmount(destinations));
|
var amountFromAmountList = amountList.split(" ")[i];
|
||||||
|
var amountAsNumber = Number(amountFromAmountList);
|
||||||
|
totalAmount += amountAsNumber;
|
||||||
|
}
|
||||||
|
var displayAmount = Utils.removeTrailingZeros(totalAmount.toFixed(12)) + " XMR";
|
||||||
|
} else {
|
||||||
|
if (amount === 0) {
|
||||||
|
// transactions to the same account have amount === 0, while the 'destinations string'
|
||||||
|
// has the correct amount, so we try to fetch it from that instead.
|
||||||
|
amount = Number(TxUtils.destinationsToAmount(destinations));
|
||||||
|
}
|
||||||
|
var displayAmount = Utils.removeTrailingZeros(amount.toFixed(12)) + " XMR";
|
||||||
}
|
}
|
||||||
var displayAmount = Utils.removeTrailingZeros(amount.toFixed(12)) + " XMR";
|
|
||||||
|
|
||||||
var tx_note = currentWallet.getUserNote(hash);
|
var tx_note = currentWallet.getUserNote(hash);
|
||||||
var address = "";
|
var address = "";
|
||||||
var addressBookName = "";
|
var addressBookName = "";
|
||||||
var receivingAddress = "";
|
var receivingAddress = "";
|
||||||
var receivingAddressLabel = "";
|
var receivingAddressLabel = "";
|
||||||
|
var addressList = "";
|
||||||
|
|
||||||
if (isout) {
|
if (numberOfDestinations >1) {
|
||||||
address = TxUtils.destinationsToAddress(destinations);
|
addressList = TxUtils.destinationsToAddress(destinations);
|
||||||
addressBookName = currentWallet ? currentWallet.addressBook.getDescription(address) : null;
|
|
||||||
} else {
|
} else {
|
||||||
receivingAddress = currentWallet ? currentWallet.address(subaddrAccount, subaddrIndex) : null;
|
if (isout) {
|
||||||
receivingAddressLabel = currentWallet ? appWindow.currentWallet.getSubaddressLabel(subaddrAccount, subaddrIndex) : null;
|
address = TxUtils.destinationsToAddress(destinations);
|
||||||
|
addressBookName = currentWallet ? currentWallet.addressBook.getDescription(address) : null;
|
||||||
|
} else {
|
||||||
|
receivingAddress = currentWallet ? currentWallet.address(subaddrAccount, subaddrIndex) : null;
|
||||||
|
receivingAddressLabel = currentWallet ? appWindow.currentWallet.getSubaddressLabel(subaddrAccount, subaddrIndex) : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isout)
|
if (isout)
|
||||||
|
@ -1572,11 +1689,14 @@ Rectangle {
|
||||||
"isout": isout,
|
"isout": isout,
|
||||||
"amount": amount,
|
"amount": amount,
|
||||||
"displayAmount": displayAmount,
|
"displayAmount": displayAmount,
|
||||||
|
"amountList": amountList,
|
||||||
"hash": hash,
|
"hash": hash,
|
||||||
"paymentId": paymentId,
|
"paymentId": paymentId,
|
||||||
"address": address,
|
"address": address,
|
||||||
|
"addressList": addressList,
|
||||||
"addressBookName": addressBookName,
|
"addressBookName": addressBookName,
|
||||||
"destinations": destinations,
|
"destinations": destinations,
|
||||||
|
"numberOfDestinations": numberOfDestinations,
|
||||||
"tx_note": tx_note,
|
"tx_note": tx_note,
|
||||||
"dateHuman": dateHuman,
|
"dateHuman": dateHuman,
|
||||||
"dateTime": date + " " + time,
|
"dateTime": date + " " + time,
|
||||||
|
|
Loading…
Reference in a new issue