mirror of
https://github.com/monero-project/monero-gui
synced 2024-11-29 09:05:11 +01:00
commit
5a682b37ec
@ -61,6 +61,7 @@ Rectangle {
|
||||
signal miningClicked()
|
||||
signal signClicked()
|
||||
signal keysClicked()
|
||||
signal merchantClicked()
|
||||
|
||||
function selectItem(pos) {
|
||||
menuColumn.previousButton.checked = false
|
||||
@ -68,6 +69,7 @@ Rectangle {
|
||||
else if(pos === "History") menuColumn.previousButton = historyButton
|
||||
else if(pos === "Transfer") menuColumn.previousButton = transferButton
|
||||
else if(pos === "Receive") menuColumn.previousButton = receiveButton
|
||||
else if(pos === "Merchant") menuColumn.previousButton = merchantButton
|
||||
else if(pos === "AddressBook") menuColumn.previousButton = addressBookButton
|
||||
else if(pos === "Mining") menuColumn.previousButton = miningButton
|
||||
else if(pos === "TxKey") menuColumn.previousButton = txkeyButton
|
||||
@ -446,6 +448,32 @@ Rectangle {
|
||||
height: 1
|
||||
}
|
||||
|
||||
// ------------- Merchant tab ---------------
|
||||
|
||||
MoneroComponents.MenuButton {
|
||||
id: merchantButton
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text: qsTr("Merchant") + translationManager.emptyString
|
||||
symbol: qsTr("U") + translationManager.emptyString
|
||||
dotColor: "#FF4F41"
|
||||
under: receiveButton
|
||||
onClicked: {
|
||||
parent.previousButton.checked = false
|
||||
parent.previousButton = merchantButton
|
||||
panel.merchantClicked()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: merchantButton.present
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 16
|
||||
color: "#313131"
|
||||
height: 1
|
||||
}
|
||||
|
||||
// ------------- History tab ---------------
|
||||
|
||||
MoneroComponents.MenuButton {
|
||||
|
@ -38,6 +38,8 @@ import moneroComponents.Wallet 1.0
|
||||
import "components" as MoneroComponents
|
||||
import "./pages"
|
||||
import "./pages/settings"
|
||||
import "./pages/merchant"
|
||||
import "components" as MoneroComponents
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
@ -56,6 +58,7 @@ Rectangle {
|
||||
|
||||
property Transfer transferView: Transfer { }
|
||||
property Receive receiveView: Receive { }
|
||||
property Merchant merchantView: Merchant { }
|
||||
property TxKey txkeyView: TxKey { }
|
||||
property SharedRingDB sharedringdbView: SharedRingDB { }
|
||||
property History historyView: History { }
|
||||
@ -72,11 +75,16 @@ Rectangle {
|
||||
signal getProofClicked(string txid, string address, string message);
|
||||
signal checkProofClicked(string txid, string address, string message, string signature);
|
||||
|
||||
Rectangle {
|
||||
// grey background on merchantView
|
||||
visible: currentView === merchantView
|
||||
color: MoneroComponents.Style.moneroGrey
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
Image {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.fill: parent
|
||||
visible: currentView !== merchantView
|
||||
source: "../images/middlePanelBg.jpg"
|
||||
}
|
||||
|
||||
@ -123,6 +131,10 @@ Rectangle {
|
||||
name: "Receive"
|
||||
PropertyChanges { target: root; currentView: receiveView }
|
||||
PropertyChanges { target: mainFlickable; contentHeight: receiveView.receiveHeight + 100 }
|
||||
}, State {
|
||||
name: "Merchant"
|
||||
PropertyChanges { target: root; currentView: merchantView }
|
||||
PropertyChanges { target: mainFlickable; contentHeight: merchantView.merchantHeight + 100 }
|
||||
}, State {
|
||||
name: "TxKey"
|
||||
PropertyChanges { target: root; currentView: txkeyView }
|
||||
@ -172,8 +184,8 @@ Rectangle {
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 18
|
||||
anchors.topMargin: appWindow.persistentSettings.customDecorations ? 50 : 0
|
||||
anchors.margins: currentView !== merchantView ? 20 * scaleRatio : 0
|
||||
anchors.topMargin: appWindow.persistentSettings.customDecorations ? 50 * scaleRatio : 0
|
||||
spacing: 0
|
||||
|
||||
Flickable {
|
||||
|
@ -12,6 +12,7 @@ QtObject {
|
||||
property string orange: "#FF6C3C"
|
||||
property string white: "#FFFFFF"
|
||||
property string green: "#2EB358"
|
||||
property string moneroGrey: "#4C4C4C"
|
||||
|
||||
property string defaultFontColor: "white"
|
||||
property string dimmedFontColor: "#BBBBBB"
|
||||
|
@ -47,7 +47,7 @@ Rectangle {
|
||||
property string title
|
||||
property int mouseX: 0
|
||||
property bool containsMouse: false
|
||||
property alias basicButtonVisible: goToBasicVersionButton.visible
|
||||
property bool basicButtonVisible: false
|
||||
property bool customDecorations: persistentSettings.customDecorations
|
||||
property bool showWhatIsButton: true
|
||||
property bool showMinimizeButton: false
|
||||
@ -56,6 +56,9 @@ Rectangle {
|
||||
property bool showMoneroLogo: false
|
||||
property bool small: false
|
||||
property alias titleBarGradientImageOpacity: titleBarGradientImage.opacity
|
||||
property bool orange: false
|
||||
property string buttonHoverColor: "#262626"
|
||||
property string buttonHoverColorOrange: "#44FFFFFF"
|
||||
|
||||
signal closeClicked
|
||||
signal maximizeClicked
|
||||
@ -70,11 +73,19 @@ Rectangle {
|
||||
|
||||
Image {
|
||||
id: titleBarGradientImage
|
||||
visible: !titleBar.orange
|
||||
anchors.fill: parent
|
||||
height: titleBar.height
|
||||
width: titleBar.width
|
||||
source: "../images/titlebarGradient.jpg"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: titleBar.orange
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
color: "#ff6600"
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
@ -82,11 +93,11 @@ Rectangle {
|
||||
width: 125
|
||||
height: parent.height
|
||||
anchors.centerIn: parent
|
||||
visible: customDecorations && showMoneroLogo
|
||||
visible: customDecorations
|
||||
z: parent.z + 1
|
||||
|
||||
Image {
|
||||
visible: !isMobile
|
||||
visible: !isMobile && showMoneroLogo && !titleBar.orange
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 11
|
||||
@ -94,6 +105,16 @@ Rectangle {
|
||||
height: 28
|
||||
source: "../images/titlebarLogo.png"
|
||||
}
|
||||
|
||||
Image {
|
||||
visible: !isMobile && showMoneroLogo && titleBar.orange
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 11
|
||||
width: 132
|
||||
height: 22
|
||||
source: "../images/moneroLogo_white.png"
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
@ -115,7 +136,7 @@ Rectangle {
|
||||
color: "transparent"
|
||||
height: titleBar.height
|
||||
width: height
|
||||
visible: isMobile
|
||||
visible: !titleBar.orange && titleBar.basicButtonVisible
|
||||
z: parent.z + 2
|
||||
|
||||
Image {
|
||||
@ -130,7 +151,7 @@ Rectangle {
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: goToBasicVersionButton.color = "#262626";
|
||||
onEntered: { goToBasicVersionButton.color = titleBar.orange ? titleBar.buttonHoverColorOrange : titleBar.buttonHoverColor }
|
||||
onExited: goToBasicVersionButton.color = "transparent";
|
||||
onClicked: {
|
||||
releaseFocus()
|
||||
@ -166,7 +187,13 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: minimizeButton.color = "#262626";
|
||||
onEntered: {
|
||||
if(titleBar.orange){
|
||||
minimizeButton.color = titleBar.buttonHoverColorOrange;
|
||||
} else {
|
||||
minimizeButton.color = titleBar.buttonHoverColor;
|
||||
}
|
||||
}
|
||||
onExited: minimizeButton.color = "transparent";
|
||||
onClicked: minimizeClicked();
|
||||
}
|
||||
@ -193,7 +220,13 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: maximizeButton.color = "#262626";
|
||||
onEntered: {
|
||||
if(titleBar.orange){
|
||||
maximizeButton.color = titleBar.buttonHoverColorOrange;
|
||||
} else {
|
||||
maximizeButton.color = titleBar.buttonHoverColor;
|
||||
}
|
||||
}
|
||||
onExited: maximizeButton.color = "transparent";
|
||||
onClicked: maximizeClicked();
|
||||
}
|
||||
@ -219,7 +252,13 @@ Rectangle {
|
||||
onClicked: closeClicked();
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: closeButton.color = "#262626";
|
||||
onEntered: {
|
||||
if(titleBar.orange){
|
||||
closeButton.color = titleBar.buttonHoverColorOrange;
|
||||
} else {
|
||||
closeButton.color = titleBar.buttonHoverColor;
|
||||
}
|
||||
}
|
||||
onExited: closeButton.color = "transparent";
|
||||
}
|
||||
}
|
||||
@ -227,6 +266,7 @@ Rectangle {
|
||||
|
||||
// window borders
|
||||
Rectangle {
|
||||
visible: !titleBar.orange
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
@ -236,10 +276,10 @@ Rectangle {
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: titleBar.small && !titleBar.orange
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
visible: titleBar.small
|
||||
height: 1
|
||||
color: "#2F2F2F"
|
||||
z: parent.z + 1
|
||||
|
BIN
images/merchant/arrow_right.png
Normal file
BIN
images/merchant/arrow_right.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
images/merchant/bg.png
Normal file
BIN
images/merchant/bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
images/merchant/input_box.png
Normal file
BIN
images/merchant/input_box.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
@ -64,3 +64,14 @@ function isValidOpenAliasAddress(address) {
|
||||
// we can get an awful lot of valid domains, including non ASCII chars... accept anything
|
||||
return true
|
||||
}
|
||||
|
||||
function makeQRCodeString(addr, amount) {
|
||||
var XMR_URI_SCHEME = "monero:"
|
||||
var XMR_AMOUNT = "tx_amount"
|
||||
var qrCodeString =""
|
||||
qrCodeString += (XMR_URI_SCHEME + addr)
|
||||
if (amount !== undefined && amount !== ""){
|
||||
qrCodeString += ("?" + XMR_AMOUNT + "=" + amount)
|
||||
}
|
||||
return qrCodeString
|
||||
}
|
||||
|
36
js/Utils.js
36
js/Utils.js
@ -48,4 +48,38 @@ function showSeedPage() {
|
||||
passwordDialog.open();
|
||||
if(isMobile) hideMenu();
|
||||
updateBalance();
|
||||
}
|
||||
}
|
||||
|
||||
function ago(epoch) {
|
||||
// Returns '<delta> [seconds|minutes|hours|days] ago' string given an epoch
|
||||
|
||||
var now = new Date().getTime() / 1000;
|
||||
var delta = now - epoch;
|
||||
|
||||
if(delta < 60) {
|
||||
return delta + " " + qsTr("seconds ago")
|
||||
} else if (delta >= 60 && delta <= 3600) {
|
||||
if(delta >= 60 && delta < 120){
|
||||
return 1 + " " + qsTr("minute ago")
|
||||
} else {
|
||||
return parseInt(Math.floor(delta / 60)) + " " + qsTr("minutes ago")
|
||||
}
|
||||
} else if (delta >= 3600 && delta <= 86400) {
|
||||
if(delta >= 3600 && delta < 7200) {
|
||||
return 1 + " " + qsTr("hour ago")
|
||||
} else {
|
||||
return parseInt(Math.floor(delta / 60 / 60)) + " " + qsTr("hours ago")
|
||||
}
|
||||
} else if (delta >= 86400){
|
||||
if(delta >= 86400 && delta < 172800) {
|
||||
return 1 + " " + qsTr("day ago")
|
||||
} else {
|
||||
var _delta = parseInt(Math.floor(delta / 24 / 60 / 60));
|
||||
if(_delta === 1) {
|
||||
return 1 + " " + qsTr("day ago")
|
||||
} else {
|
||||
return _delta + " " + qsTr("days ago")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
23
main.qml
23
main.qml
@ -86,6 +86,11 @@ ApplicationWindow {
|
||||
// true if wallet ever synchronized
|
||||
property bool walletInitialized : false
|
||||
|
||||
// Current selected address / subaddress (Receive page)
|
||||
property var current_address
|
||||
property var current_address_label: "Primary"
|
||||
property int current_subaddress_table_index: 0
|
||||
|
||||
function altKeyReleased() { ctrlPressed = false; }
|
||||
|
||||
function showPageRequest(page) {
|
||||
@ -1371,6 +1376,15 @@ ApplicationWindow {
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onMerchantClicked: {
|
||||
middlePanel.state = "Merchant";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
if(isMobile) {
|
||||
hideMenu();
|
||||
}
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onTxkeyClicked: {
|
||||
middlePanel.state = "TxKey";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
@ -1825,6 +1839,15 @@ ApplicationWindow {
|
||||
onTriggered: checkUpdates()
|
||||
}
|
||||
|
||||
function titlebarToggleOrange(flag){
|
||||
// toggle titlebar orange style
|
||||
if(flag !== undefined){
|
||||
titleBar.orange = flag;
|
||||
} else {
|
||||
titleBar.orange = !titleBar.orange;
|
||||
}
|
||||
}
|
||||
|
||||
function releaseFocus() {
|
||||
// Workaround to release focus from textfield when scrolling (https://bugreports.qt.io/browse/QTBUG-34867)
|
||||
if(isAndroid) {
|
||||
|
@ -97,6 +97,7 @@ SOURCES = *.qml \
|
||||
components/*.qml \
|
||||
pages/*.qml \
|
||||
pages/settings/*.qml \
|
||||
pages/merchant/*.qml \
|
||||
wizard/*.qml \
|
||||
wizard/*js
|
||||
}
|
||||
@ -458,7 +459,9 @@ OTHER_FILES += \
|
||||
DISTFILES += \
|
||||
notes.txt \
|
||||
monero/src/wallet/CMakeLists.txt \
|
||||
components/MobileHeader.qml
|
||||
components/MobileHeader.qml \
|
||||
pages/merchant/Merchant.qml \
|
||||
pages/merchant/MerchantCheckbox.qml
|
||||
|
||||
|
||||
# windows application icon
|
||||
|
@ -39,7 +39,7 @@ Rectangle {
|
||||
|
||||
ColumnLayout {
|
||||
id: columnLayout
|
||||
anchors.margins: (isMobile)? 17 : 40
|
||||
anchors.margins: (isMobile)? 17 * scaleRatio : 20 * scaleRatio
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
|
@ -53,7 +53,7 @@ Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: (isMobile)? 17 * scaleRatio : 20 * scaleRatio
|
||||
anchors.topMargin: 40 * scaleRatio
|
||||
|
||||
spacing: 30 * scaleRatio
|
||||
|
@ -39,10 +39,10 @@ Rectangle {
|
||||
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
anchors.margins: (isMobile)? 17 * scaleRatio : 20 * scaleRatio
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 40 * scaleRatio
|
||||
spacing: 20 * scaleRatio
|
||||
Layout.fillWidth: true
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ Rectangle {
|
||||
/* main layout */
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: (isMobile)? 17 * scaleRatio : 20 * scaleRatio
|
||||
anchors.topMargin: 40 * scaleRatio
|
||||
|
||||
anchors.left: parent.left
|
||||
|
@ -86,12 +86,9 @@ Rectangle {
|
||||
|
||||
// sign / verify
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: 20 * scaleRatio
|
||||
anchors.margins: (isMobile ? 17 : 20) * scaleRatio
|
||||
anchors.topMargin: 40 * scaleRatio
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.margins: (isMobile)? 17 * scaleRatio : 20 * scaleRatio
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
Rectangle {
|
||||
|
@ -103,7 +103,7 @@ Rectangle {
|
||||
|
||||
ColumnLayout {
|
||||
id: pageRoot
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: (isMobile)? 17 * scaleRatio : 20 * scaleRatio
|
||||
anchors.topMargin: 40 * scaleRatio
|
||||
|
||||
anchors.left: parent.left
|
||||
@ -421,7 +421,7 @@ Rectangle {
|
||||
anchors.top: pageRoot.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: (isMobile)? 17 * scaleRatio : 20 * scaleRatio
|
||||
anchors.topMargin: 32 * scaleRatio
|
||||
spacing: 26 * scaleRatio
|
||||
enabled: !viewOnly || pageRoot.enabled
|
||||
|
@ -45,7 +45,7 @@ Rectangle {
|
||||
/* main layout */
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
anchors.margins: 40 * scaleRatio
|
||||
anchors.margins: (isMobile)? 17 * scaleRatio : 20 * scaleRatio
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
|
699
pages/merchant/Merchant.qml
Normal file
699
pages/merchant/Merchant.qml
Normal file
@ -0,0 +1,699 @@
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Controls 2.0
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Dialogs 1.2
|
||||
|
||||
import moneroComponents.Clipboard 1.0
|
||||
import moneroComponents.Wallet 1.0
|
||||
import moneroComponents.WalletManager 1.0
|
||||
import moneroComponents.TransactionHistory 1.0
|
||||
import moneroComponents.TransactionHistoryModel 1.0
|
||||
import moneroComponents.Subaddress 1.0
|
||||
import moneroComponents.SubaddressModel 1.0
|
||||
|
||||
import "../../js/Windows.js" as Windows
|
||||
import "../../js/TxUtils.js" as TxUtils
|
||||
import "../../js/Utils.js" as Utils
|
||||
import "../../components" as MoneroComponents
|
||||
import "../../pages"
|
||||
import "."
|
||||
|
||||
Item {
|
||||
id: root
|
||||
anchors.margins: 0
|
||||
|
||||
property int minWidth: 900 * scaleRatio
|
||||
property int qrCodeSize: 220 * scaleRatio
|
||||
property bool enableTracking: false
|
||||
property string trackingError: "" // setting this will show a message @ tracking table
|
||||
property alias merchantHeight: mainLayout.height
|
||||
property string addressLabel: ""
|
||||
property var hiddenAmounts: []
|
||||
|
||||
function onPageCompleted() {
|
||||
appWindow.titlebarToggleOrange();
|
||||
appWindow.hideMenu();
|
||||
|
||||
// prepare tracking
|
||||
trackingCheckbox.checked = root.enableTracking
|
||||
root.update();
|
||||
timer.running = true;
|
||||
|
||||
// set currently selected account indication
|
||||
var _addressLabel = appWindow.currentWallet.getSubaddressLabel(
|
||||
appWindow.currentWallet.currentSubaddressAccount,
|
||||
appWindow.current_subaddress_table_index);
|
||||
if(_addressLabel === ""){
|
||||
root.addressLabel = "#" + appWindow.current_subaddress_table_index;
|
||||
} else {
|
||||
root.addressLabel = _addressLabel;
|
||||
}
|
||||
}
|
||||
|
||||
function onPageClosed() {
|
||||
appWindow.titlebarToggleOrange();
|
||||
|
||||
// reset component objects
|
||||
timer.running = false
|
||||
root.enableTracking = false
|
||||
trackingModel.clear()
|
||||
|
||||
appWindow.showMenu();
|
||||
}
|
||||
|
||||
Image {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 300 * scaleRatio
|
||||
source: "../../images/merchant/bg.png"
|
||||
smooth: false
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
visible: parent.width >= root.minWidth
|
||||
spacing: 0
|
||||
|
||||
// emulates max-width + center for container
|
||||
property int maxWidth: 1200 * scaleRatio
|
||||
property int defaultMargin: 50 * scaleRatio
|
||||
property int horizontalMargin: {
|
||||
if(appWindow.width >= maxWidth){
|
||||
return ((appWindow.width - maxWidth) / 2) + defaultMargin;
|
||||
} else {
|
||||
return defaultMargin;
|
||||
}
|
||||
}
|
||||
|
||||
anchors.leftMargin: horizontalMargin
|
||||
anchors.rightMargin: horizontalMargin
|
||||
anchors.margins: defaultMargin
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
|
||||
Item {
|
||||
height: 220 * scaleRatio
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
Rectangle {
|
||||
id: tracker
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
height: 220 * scaleRatio
|
||||
width: (parent.width - qrImg.width) - 50 * scaleRatio
|
||||
radius: 5
|
||||
|
||||
ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
spacing: 0
|
||||
height: 56 * scaleRatio
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.preferredWidth: 260 * scaleRatio
|
||||
Layout.preferredHeight: parent.height
|
||||
Layout.fillHeight: true
|
||||
spacing: 8 * scaleRatio
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: 10 * scaleRatio
|
||||
}
|
||||
|
||||
Text {
|
||||
font.pixelSize: 16 * scaleRatio
|
||||
font.bold: true
|
||||
color: "#767676"
|
||||
text: qsTr("Sales")
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1 * scaleRatio
|
||||
color: "#d9d9d9"
|
||||
}
|
||||
|
||||
MerchantTrackingList {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 400 * scaleRatio
|
||||
model: trackingModel
|
||||
message: {
|
||||
if(!root.enableTracking){
|
||||
return qsTr(
|
||||
"<style>p{font-size:14px;}</style>" +
|
||||
"<p>This page will automatically scan the blockchain and the tx pool " +
|
||||
"for incoming transactions using the QR code.</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>"
|
||||
);
|
||||
} else if(root.trackingError !== ""){
|
||||
return root.trackingError;
|
||||
} else if(trackingModel.count < 1){
|
||||
return qsTr("Currently monitoring incoming transactions, none found yet.");
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
onHideAmountToggled: {
|
||||
if(root.hiddenAmounts.indexOf(txid) < 0){
|
||||
root.hiddenAmounts.push(txid);
|
||||
} else {
|
||||
root.hiddenAmounts = root.hiddenAmounts.filter(function(_txid) { return _txid !== txid });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DropShadow {
|
||||
anchors.fill: source
|
||||
cached: true
|
||||
horizontalOffset: 3
|
||||
verticalOffset: 3
|
||||
radius: 8.0
|
||||
samples: 16
|
||||
color: "#20000000"
|
||||
smooth: true
|
||||
source: tracker
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: qrImg
|
||||
color: "white"
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
|
||||
height: root.qrCodeSize
|
||||
width: root.qrCodeSize
|
||||
|
||||
Layout.maximumWidth: root.qrCodeSize
|
||||
Layout.preferredHeight: width
|
||||
radius: 5
|
||||
|
||||
Image {
|
||||
id: qrCode
|
||||
anchors.fill: parent
|
||||
anchors.margins: 1 * scaleRatio
|
||||
|
||||
smooth: false
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "image://qrcode/" + TxUtils.makeQRCodeString(appWindow.current_address, amountToReceive.text)
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
onClicked: {
|
||||
if (mouse.button == Qt.RightButton){
|
||||
qrMenu.x = this.mouseX;
|
||||
qrMenu.y = this.mouseY;
|
||||
qrMenu.open()
|
||||
}
|
||||
}
|
||||
onPressAndHold: qrFileDialog.open()
|
||||
}
|
||||
}
|
||||
|
||||
Menu {
|
||||
id: qrMenu
|
||||
title: "QrCode"
|
||||
|
||||
MenuItem {
|
||||
text: qsTr("Save As") + translationManager.emptyString;
|
||||
onTriggered: qrFileDialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DropShadow {
|
||||
anchors.fill: source
|
||||
cached: true
|
||||
horizontalOffset: 3
|
||||
verticalOffset: 3
|
||||
radius: 8.0
|
||||
samples: 16
|
||||
color: "#30000000"
|
||||
smooth: true
|
||||
source: qrImg
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredHeight: 40 * scaleRatio
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
Item {
|
||||
width: (parent.width - qrImg.width) - (50 * scaleRatio)
|
||||
height: 32 * scaleRatio
|
||||
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.pixelSize: 12 * scaleRatio
|
||||
font.bold: false
|
||||
color: "white"
|
||||
text: "<style type='text/css'>a {text-decoration: none; color: #FF6C3C; font-size: 12px;}</style>Currently selected address: " + addressLabel + " <a href='#'>(Change)</a>"
|
||||
textFormat: Text.RichText
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: appWindow.showPageRequest("Receive")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
width: 220 * scaleRatio
|
||||
height: 32 * scaleRatio
|
||||
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.pixelSize: 12 * scaleRatio
|
||||
font.bold: false
|
||||
color: "white"
|
||||
text: qsTr("(right-click, save as)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredHeight: 120 * scaleRatio
|
||||
Layout.topMargin: 20 * scaleRatio
|
||||
Layout.fillWidth: true
|
||||
|
||||
Rectangle {
|
||||
id: payment_url_container
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
implicitHeight: 120 * scaleRatio
|
||||
width: (parent.width - qrImg.width) - (50 * scaleRatio)
|
||||
radius: 5
|
||||
|
||||
ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
spacing: 0
|
||||
height: 56 * scaleRatio
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.preferredWidth: 260 * scaleRatio
|
||||
Layout.preferredHeight: parent.height
|
||||
Layout.fillHeight: true
|
||||
spacing: 8
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: 10 * scaleRatio
|
||||
}
|
||||
|
||||
Text {
|
||||
font.pixelSize: 14 * scaleRatio
|
||||
font.bold: true
|
||||
color: "#767676"
|
||||
text: qsTr("Payment URL")
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
// @TODO: PaymentURL explanation
|
||||
// Rectangle {
|
||||
// // help box
|
||||
// Layout.alignment: Qt.AlignLeft
|
||||
// Layout.preferredWidth: 40 * scaleRatio
|
||||
// Layout.fillHeight: true
|
||||
// color: "transparent"
|
||||
|
||||
// Text {
|
||||
// anchors.verticalCenter: parent.verticalCenter
|
||||
// anchors.right: parent.right
|
||||
// anchors.rightMargin: 20 * scaleRatio
|
||||
// font.pixelSize: 16 * scaleRatio
|
||||
// font.bold: true
|
||||
// color: "#767676"
|
||||
// text:"?"
|
||||
// }
|
||||
|
||||
// MouseArea {
|
||||
// anchors.fill: parent
|
||||
// cursorShape: Qt.PointingHandCursor
|
||||
// onClicked: {
|
||||
// merchantPageDialog.title = qsTr("Payment URL") + translationManager.emptyString;
|
||||
// merchantPageDialog.text = qsTr("payment url explanation")
|
||||
// merchantPageDialog.icon = StandardIcon.Information
|
||||
// merchantPageDialog.open()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
|
||||
color: "#d9d9d9"
|
||||
}
|
||||
|
||||
Text {
|
||||
property string _color: "#767676"
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 20 * scaleRatio
|
||||
Layout.topMargin: 10 * scaleRatio
|
||||
|
||||
wrapMode: Text.WrapAnywhere
|
||||
elide: Text.ElideRight
|
||||
|
||||
font.pixelSize: 12 * scaleRatio
|
||||
font.bold: true
|
||||
color: _color
|
||||
text: TxUtils.makeQRCodeString(appWindow.current_address, amountToReceive.text)
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: {
|
||||
parent.color = MoneroComponents.Style.orange
|
||||
}
|
||||
onExited: {
|
||||
parent.color = parent._color
|
||||
}
|
||||
onClicked: {
|
||||
console.log("Copied to clipboard");
|
||||
clipboard.setText(parent.text);
|
||||
appWindow.showStatusMessage(qsTr("Copied to clipboard"), 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DropShadow {
|
||||
anchors.fill: source
|
||||
cached: true
|
||||
horizontalOffset: 3
|
||||
verticalOffset: 3
|
||||
radius: 8.0
|
||||
samples: 16
|
||||
color: "#20000000"
|
||||
smooth: true
|
||||
source: payment_url_container
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
width: 220 * scaleRatio
|
||||
height: 32 * scaleRatio
|
||||
|
||||
ColumnLayout {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
Text {
|
||||
font.pixelSize: 14 * scaleRatio
|
||||
font.bold: false
|
||||
color: "white"
|
||||
text: qsTr("Amount to receive") + " (XMR)"
|
||||
}
|
||||
|
||||
Image {
|
||||
height: 28 * scaleRatio
|
||||
width: 220 * scaleRatio
|
||||
source: "../../images/merchant/input_box.png"
|
||||
|
||||
TextField {
|
||||
id: amountToReceive
|
||||
topPadding: 0
|
||||
leftPadding: 10 * scaleRatio
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 3 * scaleRatio
|
||||
font.pixelSize: 16 * scaleRatio
|
||||
font.bold: true
|
||||
horizontalAlignment: TextInput.AlignLeft
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
selectByMouse: true
|
||||
color: "#424242"
|
||||
selectionColor: "#3f3fe3"
|
||||
selectedTextColor: "white"
|
||||
|
||||
background: Rectangle {
|
||||
color: "transparent"
|
||||
}
|
||||
onTextChanged: {
|
||||
if (amountToReceive.text.indexOf('.') === 0) {
|
||||
amountToReceive.text = '0' + amountToReceive.text;
|
||||
}
|
||||
}
|
||||
validator: RegExpValidator {
|
||||
regExp: /^(\d{1,8})?([\.]\d{1,12})?$/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
height: 2 * scaleRatio
|
||||
width: 220 * scaleRatio
|
||||
}
|
||||
|
||||
Text {
|
||||
// @TODO: When we have XMR/USD rate avi. in the future.
|
||||
visible: false
|
||||
font.pixelSize: 14 * scaleRatio
|
||||
font.bold: false
|
||||
color: "white"
|
||||
text: qsTr("Amount to receive") + " (USD)"
|
||||
opacity: 0.2
|
||||
}
|
||||
|
||||
Image {
|
||||
visible: false
|
||||
height: 28 * scaleRatio
|
||||
width: 220 * scaleRatio
|
||||
source: "../../images/merchant/input_box.png"
|
||||
opacity: 0.2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.topMargin: 32 * scaleRatio
|
||||
Layout.preferredHeight: 40 * scaleRatio
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 16 * scaleRatio
|
||||
|
||||
MerchantCheckbox {
|
||||
id: trackingCheckbox
|
||||
checked: root.enableTracking
|
||||
text: qsTr("Enable sales tracker")
|
||||
|
||||
onChanged: {
|
||||
root.enableTracking = this.checked;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: content
|
||||
font.pixelSize: 14 * scaleRatio
|
||||
font.bold: false
|
||||
color: "white"
|
||||
text: qsTr("Leave this page")
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: appWindow.showPageRequest("Receive")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
// Shows when the window is too small
|
||||
visible: parent.width < root.minWidth
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 100 * scaleRatio;
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
height: 120 * scaleRatio
|
||||
width: 400 * scaleRatio
|
||||
radius: 5
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pixelSize: 14 * scaleRatio
|
||||
font.bold: true
|
||||
color: MoneroComponents.Style.moneroGrey
|
||||
text: qsTr("The merchant page requires a larger window")
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
const max_tracking = 3;
|
||||
|
||||
if (!appWindow.currentWallet || !root.enableTracking) {
|
||||
root.trackingError = "";
|
||||
trackingModel.clear();
|
||||
return
|
||||
}
|
||||
|
||||
if (appWindow.currentWallet.connected() == Wallet.ConnectionStatus_Disconnected) {
|
||||
root.trackingError = 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 = []
|
||||
|
||||
// Currently selected subaddress as per Receive page
|
||||
var current_subaddress_table_index = appWindow.current_subaddress_table_index;
|
||||
|
||||
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 timeDate = model.data(idx, TransactionHistoryModel.TransactionDateRole);
|
||||
var timeHour = model.data(idx, TransactionHistoryModel.TransactionTimeRole);
|
||||
var timeEpoch = new Date(timeDate + "T" + timeHour + "Z") .getTime() / 1000;
|
||||
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,
|
||||
"time_epoch": timeEpoch,
|
||||
"time_date": timeDate + " " + timeHour,
|
||||
"hide_amount": root.hiddenAmounts.indexOf(txid) >= 0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Update tracking status label
|
||||
if (nTransactions == 0) {
|
||||
root.trackingError = qsTr("Currently monitoring incoming transactions, none found yet.") + translationManager.emptyString
|
||||
return
|
||||
}
|
||||
|
||||
trackingModel.clear();
|
||||
txs.forEach(function(tx){
|
||||
trackingModel.append({
|
||||
"amount": tx.amount,
|
||||
"blockheight": tx.blockheight,
|
||||
"confirmations": tx.confirmations,
|
||||
"blockheight": tx.blockHeight,
|
||||
"in_txpool": tx.in_txpool,
|
||||
"txid": tx.txid,
|
||||
"time_epoch": tx.time_epoch,
|
||||
"time_date": tx.time_date,
|
||||
"hide_amount": tx.hide_amount
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: trackingModel
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
interval: 3000; running: false; repeat: true
|
||||
onTriggered: update()
|
||||
}
|
||||
|
||||
MessageDialog {
|
||||
id: merchantPageDialog
|
||||
standardButtons: StandardButton.Ok
|
||||
}
|
||||
|
||||
FileDialog {
|
||||
id: qrFileDialog
|
||||
title: "Please choose a name"
|
||||
folder: shortcuts.pictures
|
||||
selectExisting: false
|
||||
nameFilters: ["Image (*.png)"]
|
||||
onAccepted: {
|
||||
if(!walletManager.saveQrCode(TxUtils.makeQRCodeString(appWindow.current_address, amountToReceive.text), 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;
|
||||
receivePageDialog.icon = StandardIcon.Error
|
||||
receivePageDialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Clipboard { id: clipboard }
|
||||
}
|
63
pages/merchant/MerchantCheckbox.qml
Normal file
63
pages/merchant/MerchantCheckbox.qml
Normal file
@ -0,0 +1,63 @@
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
|
||||
RowLayout {
|
||||
id: root
|
||||
spacing: 10 * scaleRatio
|
||||
property bool checked: false;
|
||||
property alias text: content.text
|
||||
signal changed;
|
||||
|
||||
Rectangle {
|
||||
id: checkbox
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
implicitHeight: 22 * scaleRatio
|
||||
width: 22 * scaleRatio
|
||||
radius: 5
|
||||
|
||||
Image {
|
||||
id: imageChecked
|
||||
visible: root.checked
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
source: "../../images/checkedBlackIcon.png"
|
||||
opacity: 0.6
|
||||
width: 12 * scaleRatio
|
||||
height: 8 * scaleRatio
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: content
|
||||
font.pixelSize: 14 * scaleRatio
|
||||
font.bold: false
|
||||
color: "white"
|
||||
text: ""
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.checked = !root.checked;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
DropShadow {
|
||||
anchors.fill: source
|
||||
cached: true
|
||||
horizontalOffset: 3
|
||||
verticalOffset: 3
|
||||
radius: 8.0
|
||||
samples: 16
|
||||
color: "#20000000"
|
||||
smooth: true
|
||||
source: checkbox
|
||||
}
|
||||
}
|
231
pages/merchant/MerchantTrackingList.qml
Normal file
231
pages/merchant/MerchantTrackingList.qml
Normal file
@ -0,0 +1,231 @@
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Dialogs 1.2
|
||||
|
||||
import "../../js/Utils.js" as Utils
|
||||
import "../../components" as MoneroComponents
|
||||
|
||||
ListView {
|
||||
id: trackingListView
|
||||
|
||||
// items will not be drawn when a message is set
|
||||
property string message: ""
|
||||
|
||||
boundsBehavior: ListView.StopAtBounds
|
||||
Layout.fillWidth: true
|
||||
clip: true
|
||||
|
||||
signal hideAmountToggled(string txid)
|
||||
|
||||
function viewTx(txid){
|
||||
// @TODO: implement blockexplorer-like page. Redirect to history for now
|
||||
appWindow.showPageRequest("History");
|
||||
}
|
||||
|
||||
TextEdit {
|
||||
// message box
|
||||
visible: parent.message !== ""
|
||||
anchors.fill: parent
|
||||
anchors.margins: 20 * scaleRatio
|
||||
anchors.topMargin: 10 * scaleRatio
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
font.pixelSize: 14 * scaleRatio
|
||||
font.bold: false
|
||||
color: "#767676"
|
||||
textFormat: Text.RichText
|
||||
text: parent.message
|
||||
selectionColor: MoneroComponents.Style.dimmedFontColor
|
||||
selectByMouse: true
|
||||
readOnly: true
|
||||
onFocusChanged: {if(focus === false) deselect() }
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
id: trackingTableItem
|
||||
visible: trackingListView.message === ""
|
||||
height: 53 * scaleRatio
|
||||
width: parent.width
|
||||
Layout.fillWidth: true
|
||||
|
||||
RowLayout {
|
||||
id: container
|
||||
height: parent.height
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
Layout.preferredHeight: parent.height
|
||||
Layout.preferredWidth: 20 * scaleRatio
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
Layout.preferredHeight: 40 * scaleRatio
|
||||
Layout.preferredWidth: 240 * scaleRatio
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 18 * scaleRatio
|
||||
|
||||
TextEdit {
|
||||
id: dateString
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pixelSize: 12 * scaleRatio
|
||||
font.bold: false
|
||||
color: "#707070"
|
||||
text: time_date + " (" + Utils.ago(time_epoch) + ") "
|
||||
selectionColor: MoneroComponents.Style.dimmedFontColor
|
||||
selectByMouse: true
|
||||
readOnly: true
|
||||
onFocusChanged: {if(focus === false) deselect() }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.left: dateString.right
|
||||
anchors.leftMargin: 2
|
||||
width: hideAmount.width + 2
|
||||
height: 20
|
||||
color: 'transparent'
|
||||
|
||||
TextEdit {
|
||||
id: hideAmount
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 1 * scaleRatio
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
readOnly: true
|
||||
font.pixelSize: 12 * scaleRatio
|
||||
font.bold: false
|
||||
color: "#707070"
|
||||
text: hide_amount ? "(" + qsTr("show") + ")" : "(" + qsTr("hide") + ")"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
trackingListView.hideAmountToggled(txid);
|
||||
hide_amount = !hide_amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 18 * scaleRatio
|
||||
|
||||
TextEdit {
|
||||
id: amountText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pixelSize: 14 * scaleRatio
|
||||
font.bold: true
|
||||
color: hide_amount ? "#707070" : "#009F1E"
|
||||
text: hide_amount ? '-' : '+' + amount
|
||||
selectionColor: MoneroComponents.Style.dimmedFontColor
|
||||
selectByMouse: true
|
||||
readOnly: true
|
||||
onFocusChanged: {if(focus === false) deselect() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 0
|
||||
Layout.preferredHeight: parent.height
|
||||
Layout.preferredWidth: 240 * scaleRatio
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: parent.height
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: 150 * scaleRatio
|
||||
Layout.preferredHeight: parent.height
|
||||
|
||||
TextEdit {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pixelSize: 12 * scaleRatio
|
||||
font.bold: false
|
||||
color: "#a8a8a8"
|
||||
text: {
|
||||
if(in_txpool){
|
||||
return qsTr("Awaiting in txpool") + translationManager.emptyString;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
selectionColor: MoneroComponents.Style.dimmedFontColor
|
||||
selectByMouse: true
|
||||
readOnly: true
|
||||
onFocusChanged: {if(focus === false) deselect() }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
viewTx(txid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: 30 * scaleRatio
|
||||
Layout.preferredHeight: parent.height
|
||||
|
||||
Image {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
Layout.preferredWidth: 12 * scaleRatio
|
||||
Layout.preferredHeight: 21 * scaleRatio
|
||||
source: "../../images/merchant/arrow_right.png"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
viewTx(txid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: 10 * scaleRatio
|
||||
Layout.preferredHeight: parent.height
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
anchors.top: container.bottom
|
||||
height: 1
|
||||
color: "#F0F0F0"
|
||||
}
|
||||
}
|
||||
}
|
@ -46,7 +46,7 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: (isMobile)? 17 * scaleRatio : 20 * scaleRatio
|
||||
anchors.topMargin: 0
|
||||
spacing: 30 * scaleRatio
|
||||
|
||||
|
@ -55,7 +55,7 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: (isMobile)? 17 * scaleRatio : 20 * scaleRatio
|
||||
anchors.topMargin: 0
|
||||
spacing: 6 * scaleRatio
|
||||
|
||||
|
@ -47,7 +47,7 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: (isMobile)? 17 * scaleRatio : 20 * scaleRatio
|
||||
anchors.topMargin: 0
|
||||
spacing: 10
|
||||
|
||||
|
@ -39,7 +39,7 @@ Rectangle{
|
||||
/* main layout */
|
||||
ColumnLayout {
|
||||
id: root
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: (isMobile)? 17 * scaleRatio : 20 * scaleRatio
|
||||
anchors.topMargin: 0
|
||||
|
||||
anchors.left: parent.left
|
||||
|
@ -46,7 +46,7 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: (isMobile)? 17 * scaleRatio : 20 * scaleRatio
|
||||
anchors.topMargin: 0
|
||||
spacing: 0
|
||||
|
||||
|
6
qml.qrc
6
qml.qrc
@ -247,5 +247,11 @@
|
||||
<file>images/miningxmr@2x.png</file>
|
||||
<file>images/eyeHide.png</file>
|
||||
<file>images/eyeShow.png</file>
|
||||
<file>pages/merchant/Merchant.qml</file>
|
||||
<file>pages/merchant/MerchantCheckbox.qml</file>
|
||||
<file>pages/merchant/MerchantTrackingList.qml</file>
|
||||
<file>images/merchant/arrow_right.png</file>
|
||||
<file>images/merchant/bg.png</file>
|
||||
<file>images/merchant/input_box.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
Loading…
Reference in New Issue
Block a user