Merchant page

This commit is contained in:
dsc
2018-12-08 16:55:29 +01:00
committed by skftn
parent 48a267f631
commit 85cd428dcb
28 changed files with 1250 additions and 452 deletions

View File

@@ -32,7 +32,7 @@ import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.2
import "../components"
import "../components" as MoneroComponents
import moneroComponents.Clipboard 1.0
import moneroComponents.Wallet 1.0
import moneroComponents.WalletManager 1.0
@@ -46,115 +46,7 @@ Rectangle {
id: pageReceive
color: "transparent"
property var model
property var current_address
property int current_subaddress_table_index: 0
property alias receiveHeight: mainLayout.height
property alias addressText : pageReceive.current_address
function makeQRCodeString() {
var XMR_URI_SCHEME = "monero:"
var XMR_AMOUNT = "tx_amount"
var qrCodeString =""
var amount = amountToReceiveLine.text
qrCodeString += (XMR_URI_SCHEME + current_address)
if (amount !== ""){
qrCodeString += ("?" + XMR_AMOUNT + "=" + amount)
}
return qrCodeString
}
function update() {
const max_tracking = 3;
if (!appWindow.currentWallet || !trackingEnabled.checked) {
trackingLineText.text = "";
trackingModel.clear();
return
}
if (appWindow.currentWallet.connected() == Wallet.ConnectionStatus_Disconnected) {
trackingLineText.text = qsTr("WARNING: no connection to daemon");
trackingModel.clear();
return
}
var model = appWindow.currentWallet.historyModel
var count = model.rowCount()
var totalAmount = 0
var nTransactions = 0
var blockchainHeight = null
var txs = []
for (var i = 0; i < count && txs.length < max_tracking; ++i) {
var idx = model.index(i, 0)
var isout = model.data(idx, TransactionHistoryModel.TransactionIsOutRole);
var subaddrAccount = model.data(idx, TransactionHistoryModel.TransactionSubaddrAccountRole);
var subaddrIndex = model.data(idx, TransactionHistoryModel.TransactionSubaddrIndexRole);
if (!isout && subaddrAccount == appWindow.currentWallet.currentSubaddressAccount && subaddrIndex == current_subaddress_table_index) {
var amount = model.data(idx, TransactionHistoryModel.TransactionAtomicAmountRole);
totalAmount = walletManager.addi(totalAmount, amount)
nTransactions += 1
var txid = model.data(idx, TransactionHistoryModel.TransactionHashRole);
var blockHeight = model.data(idx, TransactionHistoryModel.TransactionBlockHeightRole);
var in_txpool = false;
var confirmations = 0;
var displayAmount = 0;
if (blockHeight == 0) {
in_txpool = true;
} else {
if (blockchainHeight == null)
blockchainHeight = appWindow.currentWallet.blockChainHeight()
confirmations = blockchainHeight - blockHeight - 1
displayAmount = model.data(idx, TransactionHistoryModel.TransactionDisplayAmountRole);
}
txs.push({
"amount": displayAmount,
"confirmations": confirmations,
"blockheight": blockHeight,
"in_txpool": in_txpool,
"txid": txid
})
}
}
// Update tracking status label
if (nTransactions == 0) {
trackingLineText.text = qsTr("No transaction found yet...") + translationManager.emptyString
return
}
else if(nTransactions === 1){
trackingLineText.text = qsTr("Transaction found") + ":" + translationManager.emptyString;
} else {
trackingLineText.text = qsTr("%1 transactions found").arg(nTransactions) + ":" + translationManager.emptyString
}
toReceiveSatisfiedLine.text = "";
var expectedAmount = walletManager.amountFromString(amountToReceiveLine.text)
if (expectedAmount && expectedAmount != amount) {
var displayTotalAmount = walletManager.displayAmount(totalAmount)
if (amount > expectedAmount) toReceiveSatisfiedLine.text += qsTr("With more Monero");
else if (amount < expectedAmount) toReceiveSatisfiedLine.text = qsTr("With not enough Monero")
toReceiveSatisfiedLine.text += ": " + "<br>" +
qsTr("Expected") + ": " + amountToReceiveLine.text + "<br>" +
qsTr("Total received") + ": " + displayTotalAmount + translationManager.emptyString;
}
trackingModel.clear();
txs.forEach(function(tx){
trackingModel.append({
"amount": tx.amount,
"confirmations": tx.confirmations,
"blockheight": tx.blockHeight,
"in_txpool": tx.in_txpool,
"txid": tx.txid
});
});
//setTrackingLineText(text + "<br>" + list.join("<br>"))
}
function renameSubaddressLabel(_index){
inputDialog.labelText = qsTr("Set the label of the selected address:") + translationManager.emptyString;
@@ -171,7 +63,7 @@ Rectangle {
/* main layout */
ColumnLayout {
id: mainLayout
anchors.margins: (isMobile)? 17 : 40
anchors.margins: (isMobile)? 17 * scaleRatio : 20 * scaleRatio
anchors.topMargin: 40 * scaleRatio
anchors.left: parent.left
@@ -188,24 +80,10 @@ Rectangle {
id: addressRow
spacing: 0
LabelSubheader {
MoneroComponents.LabelSubheader {
Layout.fillWidth: true
textFormat: Text.RichText
text: "<style type='text/css'>a {text-decoration: none; color: #FF6C3C; font-size: 14px;}</style>" +
qsTr("Addresses") +
"<font size='2'> </font><a href='#'>" +
qsTr("Help") + "</a>" +
translationManager.emptyString
onLinkActivated: {
receivePageDialog.title = qsTr("Tracking payments") + translationManager.emptyString;
receivePageDialog.text = qsTr(
"<p>This QR code includes the address you selected above and" +
"the amount you entered below. Share it with others (right-click->Save) " +
"so they can more easily send you exact amounts.</p>"
)
receivePageDialog.icon = StandardIcon.Information
receivePageDialog.open()
}
text: qsTr("Addresses")
}
ColumnLayout {
@@ -245,9 +123,9 @@ Rectangle {
anchors.rightMargin: 80
color: "transparent"
Label {
MoneroComponents.Label {
id: idLabel
color: index === current_subaddress_table_index ? "white" : "#757575"
color: index === appWindow.current_subaddress_table_index ? "white" : "#757575"
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 6
@@ -256,7 +134,7 @@ Rectangle {
text: "#" + index
}
Label {
MoneroComponents.Label {
id: nameLabel
color: "#a5a5a5"
anchors.verticalCenter: parent.verticalCenter
@@ -267,7 +145,7 @@ Rectangle {
text: label
}
Label {
MoneroComponents.Label {
color: "white"
anchors.verticalCenter: parent.verticalCenter
anchors.left: nameLabel.right
@@ -299,7 +177,7 @@ Rectangle {
}
}
IconButton {
MoneroComponents.IconButton {
id: renameButton
imageSource: "../images/editIcon.png"
anchors.verticalCenter: parent.verticalCenter
@@ -313,7 +191,7 @@ Rectangle {
}
}
IconButton {
MoneroComponents.IconButton {
id: copyButton
imageSource: "../images/copyToClipboard.png"
anchors.verticalCenter: parent.verticalCenter
@@ -329,20 +207,17 @@ Rectangle {
}
onCurrentItemChanged: {
// reset global vars
current_subaddress_table_index = subaddressListView.currentIndex;
current_address = appWindow.currentWallet.address(
appWindow.current_subaddress_table_index = subaddressListView.currentIndex;
appWindow.current_address = appWindow.currentWallet.address(
appWindow.currentWallet.currentSubaddressAccount,
subaddressListView.currentIndex
);
// reset tracking table
trackingModel.clear();
}
}
}
// 'fake' row for 'create new address'
ColumnLayout{
ColumnLayout {
id: createAddressRow
Layout.fillWidth: true
spacing: 0
@@ -353,13 +228,13 @@ Rectangle {
height: 1
}
Rectangle{
Rectangle {
id: createAddressRect
Layout.preferredHeight: subaddressListRow.subaddressListItemHeight
color: "transparent"
Layout.fillWidth: true
Label {
MoneroComponents.Label {
color: "#757575"
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
@@ -396,7 +271,8 @@ Rectangle {
}
RowLayout {
CheckBox2 {
Layout.topMargin: 22 * scaleRatio
MoneroComponents.CheckBox2 {
id: showAdvancedCheckbox
checked: persistentSettings.receiveShowAdvanced
onClicked: {
@@ -405,282 +281,72 @@ Rectangle {
text: qsTr("Advanced options") + translationManager.emptyString
}
}
GridLayout {
id: advancedRow
columns: (isMobile)? 1 : 2
Layout.fillWidth: true
columnSpacing: 32 * scaleRatio
RowLayout {
Layout.topMargin: 6 * scaleRatio
visible: persistentSettings.receiveShowAdvanced
Layout.fillWidth: true
ColumnLayout {
Layout.alignment: Qt.AlignTop
MoneroComponents.LineEditMulti {
id: paymentUrl
Layout.fillWidth: true
spacing: 20 * scaleRatio
LabelSubheader {
Layout.fillWidth: true
textFormat: Text.RichText
text: "<style type='text/css'>a {text-decoration: none; color: #FF6C3C; font-size: 14px;}</style>" +
qsTr("QR Code") +
"<font size='2'> </font><a href='#'>" +
qsTr("Help") + "</a>" +
translationManager.emptyString
onLinkActivated: {
receivePageDialog.title = qsTr("QR Code") + translationManager.emptyString;
receivePageDialog.text = qsTr(
"<p>This QR code includes the address you selected above and " +
"the amount you entered below. Share it with others (right-click->Save) " +
"so they can more easily send you exact amounts.</p>"
)
receivePageDialog.icon = StandardIcon.Information
receivePageDialog.open()
}
}
ColumnLayout {
id: amountRow
Layout.fillWidth: true
Layout.minimumWidth: 200
spacing: parent.spacing
LineEdit {
id: amountToReceiveLine
Layout.fillWidth: true
labelText: qsTr("Amount") + translationManager.emptyString
placeholderText: qsTr("Amount to receive") + translationManager.emptyString
fontBold: true
inlineIcon: true
onTextChanged: {
if(amountToReceiveLine.text.indexOf('.') === 0){
amountToReceiveLine.text = '0' + amountToReceiveLine.text;
}
}
validator: RegExpValidator {
regExp: /^(\d{1,8})?([\.]\d{1,12})?$/
}
}
Rectangle {
color: "white"
Layout.fillWidth: true
Layout.maximumWidth: mainLayout.qrCodeSize
Layout.preferredHeight: width
radius: 4
Image {
id: qrCode
anchors.fill: parent
anchors.margins: 1
smooth: false
fillMode: Image.PreserveAspectFit
source: "image://qrcode/" + makeQRCodeString()
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: {
if (mouse.button == Qt.RightButton)
qrMenu.open()
}
onPressAndHold: qrFileDialog.open()
}
}
Menu {
id: qrMenu
title: "QrCode"
y: parent.height / 2
MenuItem {
text: qsTr("Save As") + translationManager.emptyString;
onTriggered: qrFileDialog.open()
}
}
}
LineEditMulti {
id: paymentUrl
Layout.fillWidth: true
labelText: qsTr("Payment URL") + translationManager.emptyString
text: makeQRCodeString()
readOnly: true
copyButton: true
wrapMode: Text.WrapAnywhere
}
}
labelText: qsTr("Payment URL") + translationManager.emptyString
text: TxUtils.makeQRCodeString(appWindow.current_address)
readOnly: true
copyButton: true
wrapMode: Text.WrapAnywhere
}
}
ColumnLayout {
id: trackingRow
Layout.alignment: Qt.AlignTop
GridLayout{
visible: persistentSettings.receiveShowAdvanced
Layout.topMargin: 10 * scaleRatio
columns: 2
columnSpacing: 30 * scaleRatio
RowLayout {
property int qrSize: 220 * scaleRatio
Layout.fillWidth: true
spacing: 0 * scaleRatio
LabelSubheader {
Layout.fillWidth: true
textFormat: Text.RichText
text: "<style type='text/css'>a {text-decoration: none; color: #FF6C3C; font-size: 14px;}</style>" +
qsTr("Tracking") +
"<font size='2'> </font><a href='#'>" +
qsTr("Help") + "</a>" +
translationManager.emptyString
onLinkActivated: {
receivePageDialog.title = qsTr("Tracking payments") + translationManager.emptyString;
receivePageDialog.text = qsTr(
"<p><font size='+2'>This is a simple sales tracker:</font></p>" +
"<p>Let your customer scan that QR code to make a payment (if that customer has software which " +
"supports QR code scanning).</p>" +
"<p>This page will automatically scan the blockchain and the tx pool " +
"for incoming transactions using this QR code. If you input an amount, it will also check " +
"that incoming transactions total up to that amount.</p>" +
"<p>It's up to you whether to accept unconfirmed transactions or not. It is likely they'll be " +
"confirmed in short order, but there is still a possibility they might not, so for larger " +
"values you may want to wait for one or more confirmation(s).</p>"
)
receivePageDialog.icon = StandardIcon.Information
receivePageDialog.open()
}
}
Rectangle {
id: qrContainer
radius: 4 * scaleRatio
color: "white"
Layout.preferredWidth: parent.qrSize
Layout.preferredHeight: parent.qrSize
ListModel {
id: trackingModel
}
RowLayout{
Layout.topMargin: 14
Layout.bottomMargin: 10
visible: trackingTableRow.visible
Label {
id: trackingLineText
color: "white"
fontFamily: Style.fontLight.name
fontSize: 16 * scaleRatio
text: ""
}
}
ColumnLayout {
id: trackingTableRow
visible: trackingListView.count >= 1
Layout.fillWidth: true
Layout.minimumWidth: 240
Layout.preferredHeight: 46 * trackingListView.count
ListView {
id: trackingListView
Layout.fillWidth: true
Image {
id: qrCode
anchors.fill: parent
clip: true
boundsBehavior: ListView.StopAtBounds
model: trackingModel
delegate: Item {
id: trackingTableItem
height: 46
width: parent.width
Layout.fillWidth: true
anchors.margins: 1 * scaleRatio
Rectangle{
anchors.right: parent.right
anchors.left: parent.left
anchors.top: parent.top
height: 1
color: "#404040"
visible: index !== 0
}
smooth: false
fillMode: Image.PreserveAspectFit
source: "image://qrcode/" + TxUtils.makeQRCodeString(appWindow.current_address)
Image {
id: arrowImage
source: "../images/upArrow-green.png"
height: 18 * scaleRatio
width: 12 * scaleRatio
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 8
}
Label {
id: trackingConfirmationLine
color: "white"
anchors.top: parent.top
anchors.topMargin: 6
anchors.left: arrowImage.right
anchors.leftMargin: 10
fontSize: 14 * scaleRatio
text: {
if(in_txpool){
return "Awaiting in txpool"
} else {
if(confirmations > 1){
if(confirmations > 100){
return "100+ " + qsTr("confirmations") + translationManager.emptyString;
} else {
return confirmations + " " + qsTr("confirmations") + translationManager.emptyString;
}
} else {
return "1 " + qsTr("confirmation") + translationManager.emptyString;
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: {
if (mouse.button == Qt.RightButton){
qrMenu.x = this.mouseX;
qrMenu.y = this.mouseY;
qrMenu.open()
}
}
Label {
id: trackingAmountLine
color: "#2eb358"
anchors.top: trackingConfirmationLine.bottom
anchors.left: arrowImage.right
anchors.leftMargin: 10
fontSize: 14 * scaleRatio
fontBold: true
text: amount
}
IconButton {
id: clipboardButton
imageSource: "../images/copyToClipboard.png"
onClicked: {
console.log("tx_id copied to clipboard");
clipboard.setText(txid);
appWindow.showStatusMessage(qsTr("Transaction ID copied to clipboard"),3);
}
anchors.right: parent.right
anchors.top: undefined
anchors.verticalCenter: parent.verticalCenter
}
onPressAndHold: qrFileDialog.open()
}
}
}
RowLayout {
visible: trackingTableRow.visible && x.text !== "" && amountToReceiveLine.text !== ""
Layout.topMargin: 14 * scaleRatio
Layout.fillWidth: true
Layout.preferredHeight: 40 * scaleRatio
Menu {
id: qrMenu
title: "QrCode"
Label {
id: toReceiveSatisfiedLine
color: "white"
fontFamily: Style.fontLight.name
fontSize: 14 * scaleRatio
textFormat: Text.RichText
text: ""
height: 40 * scaleRatio
}
}
RowLayout {
Layout.fillWidth: true
Layout.minimumWidth: 200
Layout.topMargin: trackingTableRow.visible ? 20 * scaleRatio : 32 * scaleRatio
CheckBox {
id: trackingEnabled
text: qsTr("Enable") + translationManager.emptyString
MenuItem {
text: qsTr("Save As") + translationManager.emptyString;
onTriggered: qrFileDialog.open()
}
}
}
}
@@ -693,12 +359,12 @@ Rectangle {
FileDialog {
id: qrFileDialog
title: "Please choose a name"
title: qsTr("Please choose a name")
folder: shortcuts.pictures
selectExisting: false
nameFilters: ["Image (*.png)"]
onAccepted: {
if(!walletManager.saveQrCode(makeQRCodeString(), walletManager.urlToLocalPath(fileUrl))) {
if(!walletManager.saveQrCode(TxUtils.makeQRCodeString(appWindow.current_address), walletManager.urlToLocalPath(fileUrl))) {
console.log("Failed to save QrCode to file " + walletManager.urlToLocalPath(fileUrl) )
receivePageDialog.title = qsTr("Save QrCode") + translationManager.emptyString;
receivePageDialog.text = qsTr("Failed to save QrCode to ") + walletManager.urlToLocalPath(fileUrl) + translationManager.emptyString;
@@ -709,27 +375,14 @@ Rectangle {
}
}
Timer {
id: timer
interval: 2000; running: false; repeat: true
onTriggered: update()
}
function onPageCompleted() {
console.log("Receive page loaded");
subaddressListView.model = appWindow.currentWallet.subaddressModel;
if (appWindow.currentWallet) {
current_address = appWindow.currentWallet.address(appWindow.currentWallet.currentSubaddressAccount, 0)
appWindow.current_address = appWindow.currentWallet.address(appWindow.currentWallet.currentSubaddressAccount, 0)
appWindow.currentWallet.subaddress.refresh(appWindow.currentWallet.currentSubaddressAccount)
current_subaddress_table_index = 0;
subaddressListView.currentIndex = 0;
}
update()
timer.running = true
trackingEnabled.checked = false
}
function clearFields() {
@@ -737,8 +390,5 @@ Rectangle {
}
function onPageClosed() {
timer.running = false
trackingEnabled.checked = false
trackingModel.clear()
}
}