mirror of
https://github.com/monero-project/monero-gui.git
synced 2024-11-16 15:58:11 +00:00
cddf3c3cdb
Adding support for reserve proof added an additional
argument to the getProofClicked signal. The payment
proof button on the transaction list from history.qml
does not pass this argument and fails with insufficient
argument error.
Fixes: 0f67580e
("Advanced: ReserveProof: Add support for reserve proof")
1833 lines
81 KiB
QML
1833 lines
81 KiB
QML
// Copyright (c) 2014-2019, The Monero Project
|
|
//
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without modification, are
|
|
// permitted provided that the following conditions are met:
|
|
//
|
|
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
// conditions and the following disclaimer.
|
|
//
|
|
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
// of conditions and the following disclaimer in the documentation and/or other
|
|
// materials provided with the distribution.
|
|
//
|
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
|
// used to endorse or promote products derived from this software without specific
|
|
// prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
import QtQuick 2.0
|
|
import QtQuick.Layouts 1.1
|
|
import QtQuick.Dialogs 1.2
|
|
import QtGraphicalEffects 1.0
|
|
import moneroComponents.Wallet 1.0
|
|
import moneroComponents.WalletManager 1.0
|
|
import moneroComponents.TransactionHistory 1.0
|
|
import moneroComponents.TransactionInfo 1.0
|
|
import moneroComponents.TransactionHistoryModel 1.0
|
|
import moneroComponents.Clipboard 1.0
|
|
import FontAwesome 1.0
|
|
|
|
import "../components/effects/" as MoneroEffects
|
|
import "../components" as MoneroComponents
|
|
import "../js/Utils.js" as Utils
|
|
import "../js/TxUtils.js" as TxUtils
|
|
|
|
|
|
Rectangle {
|
|
id: root
|
|
property var model
|
|
property int sideMargin: 50
|
|
property var initialized: false
|
|
property int txMax: Math.max(5, ((appWindow.height - 250) / 60))
|
|
property int txOffset: 0
|
|
property int txPage: (txOffset / txMax) + 1
|
|
property int txCount: 0
|
|
property var sortSearchString: null
|
|
property bool sortDirection: true // true = desc, false = asc
|
|
property string sortBy: "blockheight"
|
|
property var txModelData: [] // representation of transaction data (appWindow.currentWallet.historyModel)
|
|
property var txData: [] // representation of FILTERED transation data
|
|
property var txDataCollapsed: [] // keep track of which txs are collapsed
|
|
property string historyStatusMessage: ""
|
|
property alias contentHeight: pageRoot.height
|
|
|
|
Clipboard { id: clipboard }
|
|
ListModel { id: txListViewModel }
|
|
|
|
color: "transparent"
|
|
|
|
onTxMaxChanged: root.updateDisplay(root.txOffset, root.txMax);
|
|
|
|
ColumnLayout {
|
|
id: pageRoot
|
|
anchors.topMargin: 40
|
|
|
|
anchors.left: parent.left
|
|
anchors.top: parent.top
|
|
anchors.right: parent.right
|
|
|
|
RowLayout {
|
|
Layout.preferredHeight: 24
|
|
Layout.preferredWidth: parent.width - root.sideMargin
|
|
Layout.leftMargin: sideMargin
|
|
Layout.rightMargin: sideMargin
|
|
Layout.bottomMargin: 10
|
|
|
|
MoneroComponents.Label {
|
|
fontSize: 24
|
|
text: qsTr("Transactions") + translationManager.emptyString
|
|
}
|
|
|
|
Item {
|
|
Layout.fillWidth: true
|
|
}
|
|
|
|
RowLayout {
|
|
id: sortAndFilter
|
|
visible: root.txCount > 0
|
|
property bool collapsed: false
|
|
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
|
Layout.preferredWidth: 100
|
|
Layout.preferredHeight: 15
|
|
spacing: 8
|
|
|
|
MoneroComponents.TextPlain {
|
|
Layout.alignment: Qt.AlignVCenter
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: qsTr("Sort & filter") + translationManager.emptyString
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
hoverEnabled: true
|
|
onClicked: {
|
|
sortAndFilter.collapsed = !sortAndFilter.collapsed
|
|
}
|
|
}
|
|
}
|
|
|
|
MoneroEffects.ImageMask {
|
|
id: sortCollapsedIcon
|
|
Layout.alignment: Qt.AlignVCenter
|
|
height: 8
|
|
width: 12
|
|
image: "qrc:///images/whiteDropIndicator.png"
|
|
fontAwesomeFallbackIcon: FontAwesome.arrowDown
|
|
fontAwesomeFallbackSize: 14
|
|
rotation: sortAndFilter.collapsed ? 180 : 0
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
hoverEnabled: true
|
|
onClicked: {
|
|
sortAndFilter.collapsed = !sortAndFilter.collapsed
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
Layout.fillWidth: true
|
|
Layout.topMargin: 8
|
|
Layout.leftMargin: sideMargin
|
|
Layout.rightMargin: sideMargin
|
|
visible: sortAndFilter.collapsed
|
|
|
|
MoneroComponents.LineEdit {
|
|
id: searchInput
|
|
Layout.fillWidth: true
|
|
input.topPadding: 6
|
|
input.bottomPadding: 6
|
|
fontSize: 15
|
|
labelFontSize: 14
|
|
placeholderText: qsTr("Search by Transaction ID, Address, Description, Amount or Blockheight") + translationManager.emptyString
|
|
placeholderFontSize: 15
|
|
inputHeight: 34
|
|
onTextUpdated: {
|
|
if (!sortAndFilter.collapsed) {
|
|
sortAndFilter.collapsed = true;
|
|
}
|
|
if(searchInput.text != null && searchInput.text.length >= 3){
|
|
root.sortSearchString = searchInput.text;
|
|
root.reset();
|
|
root.updateFilter();
|
|
} else {
|
|
root.sortSearchString = null;
|
|
root.reset();
|
|
root.updateFilter();
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
height: cleanButton.height
|
|
width: cleanButton.width
|
|
Layout.rightMargin: -8
|
|
Layout.leftMargin: -2
|
|
|
|
MoneroComponents.InlineButton {
|
|
id: cleanButton
|
|
buttonColor: "transparent"
|
|
fontFamily: FontAwesome.fontFamilySolid
|
|
fontStyleName: "Solid"
|
|
fontPixelSize: 18
|
|
text: FontAwesome.times
|
|
tooltip: qsTr("Clean") + translationManager.emptyString
|
|
tooltipLeft: true
|
|
visible: searchInput.text != ""
|
|
onClicked: searchInput.text = ""
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
GridLayout {
|
|
visible: sortAndFilter.collapsed
|
|
Layout.fillWidth: true
|
|
Layout.topMargin: 4
|
|
Layout.leftMargin: sideMargin
|
|
Layout.rightMargin: sideMargin
|
|
columns: 2
|
|
columnSpacing: 20
|
|
|
|
MoneroComponents.DatePicker {
|
|
id: fromDatePicker
|
|
Layout.fillWidth: true
|
|
width: 100
|
|
inputLabel.text: qsTr("Date from") + translationManager.emptyString
|
|
inputLabel.font.pixelSize: 14
|
|
onCurrentDateChanged: {
|
|
if(root.initialized){
|
|
root.reset();
|
|
root.updateFilter();
|
|
}
|
|
}
|
|
}
|
|
|
|
MoneroComponents.DatePicker {
|
|
id: toDatePicker
|
|
Layout.fillWidth: true
|
|
width: 100
|
|
inputLabel.text: qsTr("Date to") + translationManager.emptyString
|
|
|
|
onCurrentDateChanged: {
|
|
if(root.initialized){
|
|
root.reset();
|
|
root.updateFilter();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RowLayout {
|
|
Layout.topMargin: 20
|
|
Layout.bottomMargin: 20
|
|
Layout.fillWidth: true
|
|
Layout.leftMargin: sideMargin
|
|
Layout.rightMargin: sideMargin
|
|
|
|
Rectangle {
|
|
visible: sortAndFilter.collapsed
|
|
color: "transparent"
|
|
Layout.preferredWidth: childrenRect.width + 38
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: qsTr("Sort by") + ":" + translationManager.emptyString
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
visible: sortAndFilter.collapsed
|
|
id: sortBlockheight
|
|
color: "transparent"
|
|
Layout.preferredWidth: sortBlockheightText.width + 42
|
|
Layout.preferredHeight: 20
|
|
|
|
RowLayout {
|
|
clip: true
|
|
anchors.fill: parent
|
|
|
|
MoneroComponents.TextPlain {
|
|
id: sortBlockheightText
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: qsTr("Blockheight") + translationManager.emptyString
|
|
color: root.sortBy === "blockheight" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
|
|
themeTransition: false
|
|
}
|
|
|
|
MoneroEffects.ImageMask {
|
|
height: 8
|
|
width: 12
|
|
visible: root.sortBy === "blockheight" ? true : false
|
|
opacity: root.sortBy === "blockheight" ? 1 : 0.2
|
|
image: "qrc:///images/whiteDropIndicator.png"
|
|
fontAwesomeFallbackIcon: FontAwesome.arrowDown
|
|
fontAwesomeFallbackSize: 14
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
rotation: {
|
|
if(root.sortBy === "blockheight"){
|
|
return root.sortDirection ? 0 : 180
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
Layout.fillWidth: true
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
hoverEnabled: true
|
|
onClicked: {
|
|
if(root.sortBy !== "blockheight") {
|
|
root.sortDirection = true;
|
|
} else {
|
|
root.sortDirection = !root.sortDirection
|
|
}
|
|
|
|
root.sortBy = "blockheight";
|
|
root.updateSort();
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
visible: sortAndFilter.collapsed
|
|
color: "transparent"
|
|
Layout.preferredWidth: sortDateText.width + 42
|
|
Layout.preferredHeight: 20
|
|
|
|
RowLayout {
|
|
clip: true
|
|
anchors.fill: parent
|
|
|
|
MoneroComponents.TextPlain {
|
|
id: sortDateText
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: qsTr("Date") + translationManager.emptyString
|
|
color: root.sortBy === "timestamp" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
|
|
themeTransition: false
|
|
}
|
|
|
|
MoneroEffects.ImageMask {
|
|
height: 8
|
|
width: 12
|
|
visible: root.sortBy === "timestamp" ? true : false
|
|
opacity: root.sortBy === "timestamp" ? 1 : 0.2
|
|
image: "qrc:///images/whiteDropIndicator.png"
|
|
fontAwesomeFallbackIcon: FontAwesome.arrowDown
|
|
fontAwesomeFallbackSize: 14
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
rotation: {
|
|
if(root.sortBy === "timestamp"){
|
|
return root.sortDirection ? 0 : 180
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
Layout.fillWidth: true
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
hoverEnabled: true
|
|
onClicked: {
|
|
if(root.sortBy !== "timestamp") {
|
|
root.sortDirection = true;
|
|
} else {
|
|
root.sortDirection = !root.sortDirection
|
|
}
|
|
|
|
root.sortBy = "timestamp";
|
|
root.updateSort();
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
visible: sortAndFilter.collapsed
|
|
color: "transparent"
|
|
Layout.preferredWidth: sortAmountText.width + 42
|
|
Layout.preferredHeight: 20
|
|
|
|
RowLayout {
|
|
clip: true
|
|
anchors.fill: parent
|
|
|
|
MoneroComponents.TextPlain {
|
|
id: sortAmountText
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: qsTr("Amount") + translationManager.emptyString
|
|
color: root.sortBy === "amount" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
|
|
themeTransition: false
|
|
}
|
|
|
|
MoneroEffects.ImageMask {
|
|
height: 8
|
|
width: 12
|
|
visible: root.sortBy === "amount" ? true : false
|
|
opacity: root.sortBy === "amount" ? 1 : 0.2
|
|
image: "qrc:///images/whiteDropIndicator.png"
|
|
fontAwesomeFallbackIcon: FontAwesome.arrowDown
|
|
fontAwesomeFallbackSize: 14
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
rotation: {
|
|
if(root.sortBy === "amount"){
|
|
return root.sortDirection ? 0 : 180
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
Layout.fillWidth: true
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
hoverEnabled: true
|
|
onClicked: {
|
|
if(root.sortBy !== "amount") {
|
|
root.sortDirection = true;
|
|
} else {
|
|
root.sortDirection = !root.sortDirection
|
|
}
|
|
|
|
root.sortBy = "amount";
|
|
root.updateSort();
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
visible: !sortAndFilter.collapsed
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
// status message
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: root.historyStatusMessage
|
|
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
}
|
|
|
|
Item {
|
|
Layout.fillWidth: true
|
|
}
|
|
|
|
RowLayout {
|
|
id: pagination
|
|
visible: root.txCount > 0
|
|
spacing: 0
|
|
Layout.alignment: Qt.AlignRight
|
|
Layout.preferredWidth: childrenRect.width
|
|
Layout.preferredHeight: 20
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.preferredWidth: childrenRect.width + 2
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: qsTr("Page") + ":" + translationManager.emptyString
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.preferredWidth: childrenRect.width + 10
|
|
Layout.leftMargin: 4
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
id: paginationText
|
|
text: root.txPage + "/" + Math.ceil(root.txCount / root.txMax)
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
MouseArea {
|
|
// jump to page functionality
|
|
property int pages: Math.ceil(root.txCount / root.txMax)
|
|
anchors.fill: parent
|
|
hoverEnabled: pages > 1
|
|
cursorShape: hoverEnabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
onEntered: parent.color = MoneroComponents.Style.orange
|
|
onExited: parent.color = MoneroComponents.Style.defaultFontColor
|
|
onClicked: {
|
|
if(pages === 1)
|
|
return;
|
|
|
|
inputDialog.labelText = qsTr("Jump to page (1-%1)").arg(pages) + translationManager.emptyString;
|
|
inputDialog.onAcceptedCallback = function() {
|
|
var pageNumber = parseInt(inputDialog.inputText);
|
|
if (!isNaN(pageNumber) && pageNumber >= 1 && pageNumber <= pages) {
|
|
root.paginationJump(parseInt(pageNumber));
|
|
return;
|
|
}
|
|
|
|
appWindow.showStatusMessage(qsTr("Invalid page. Must be a number within the specified range."), 4);
|
|
}
|
|
inputDialog.onRejectedCallback = null;
|
|
inputDialog.open()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: paginationPrev
|
|
Layout.preferredWidth: 18
|
|
Layout.preferredHeight: 20
|
|
color: "transparent"
|
|
opacity: enabled ? 1.0 : 0.2
|
|
enabled: false
|
|
|
|
MoneroEffects.ImageMask {
|
|
id: prevIcon
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.left: parent.left
|
|
height: 8
|
|
width: 12
|
|
image: "qrc:///images/whiteDropIndicator.png"
|
|
fontAwesomeFallbackIcon: FontAwesome.arrowDown
|
|
fontAwesomeFallbackSize: 14
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
rotation: 90
|
|
}
|
|
|
|
MouseArea {
|
|
enabled: parent.enabled
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
root.paginationPrevClicked();
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: paginationNext
|
|
Layout.preferredWidth: 18
|
|
Layout.preferredHeight: 20
|
|
color: "transparent"
|
|
opacity: enabled ? 1.0 : 0.2
|
|
enabled: false
|
|
|
|
MoneroEffects.ImageMask {
|
|
id: nextIcon
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.right: parent.right
|
|
height: 8
|
|
width: 12
|
|
image: "qrc:///images/whiteDropIndicator.png"
|
|
fontAwesomeFallbackIcon: FontAwesome.arrowDown
|
|
fontAwesomeFallbackSize: 14
|
|
rotation: 270
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
root.paginationNextClicked();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ListView {
|
|
visible: true
|
|
id: txListview
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: contentHeight;
|
|
model: txListViewModel
|
|
interactive: false
|
|
|
|
delegate: Rectangle {
|
|
id: delegate
|
|
property bool collapsed: root.txDataCollapsed.indexOf(hash) >= 0 ? true : false
|
|
anchors.left: parent ? parent.left : undefined
|
|
anchors.right: parent ? parent.right : undefined
|
|
height: {
|
|
if(!collapsed) return 60;
|
|
return 320;
|
|
}
|
|
color: {
|
|
if(!collapsed) return "transparent"
|
|
return MoneroComponents.Style.blackTheme ? "#06FFFFFF" : "#04000000"
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.top: parent.top
|
|
anchors.bottom: parent.bottom
|
|
anchors.left: parent.left
|
|
width: sideMargin
|
|
color: "transparent"
|
|
|
|
Rectangle {
|
|
visible: !isFailed && !isPending
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 24
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
width: 10
|
|
height: 10
|
|
radius: 8
|
|
color: isout ? "#d85a00" : "#2eb358"
|
|
}
|
|
|
|
MoneroComponents.TextPlain {
|
|
visible: isFailed || isPending
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 24
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
font.family: FontAwesome.fontFamilySolid
|
|
font.styleName: isFailed ? "Solid" : ""
|
|
font.pixelSize: 15
|
|
text: isFailed ? FontAwesome.times : FontAwesome.clockO
|
|
color: isFailed ? "#FF0000" : MoneroComponents.Style.defaultFontColor
|
|
themeTransition: false
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
spacing: 0
|
|
clip: true
|
|
height: parent.height
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.leftMargin: sideMargin
|
|
anchors.rightMargin: sideMargin
|
|
|
|
RowLayout {
|
|
spacing: 0
|
|
Layout.fillWidth: true
|
|
height: 60
|
|
Layout.preferredHeight: 60
|
|
|
|
ColumnLayout {
|
|
spacing: 0
|
|
clip: true
|
|
Layout.preferredHeight: 120
|
|
Layout.minimumWidth: 180
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 10
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: (isout ? qsTr("Sent") : qsTr("Received")) + (isFailed ? " (" + qsTr("Failed") + ")" : (isPending ? " (" + qsTr("Pending") + ")" : "")) + translationManager.emptyString
|
|
color: MoneroComponents.Style.historyHeaderTextColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
themeTransitionBlackColor: MoneroComponents.Style._b_historyHeaderTextColor
|
|
themeTransitionWhiteColor: MoneroComponents.Style._w_historyHeaderTextColor
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: (amount == 0 ? qsTr("Unknown amount") : displayAmount) + translationManager.emptyString
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
MouseArea {
|
|
state: "copyable"
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onEntered: parent.color = MoneroComponents.Style.orange
|
|
onExited: parent.color = MoneroComponents.Style.defaultFontColor
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 10
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 10
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: isout ? qsTr("Fee") : confirmationsRequired === 60 ? qsTr("Mined") : qsTr("Fee") + translationManager.emptyString
|
|
color: MoneroComponents.Style.historyHeaderTextColor
|
|
themeTransitionBlackColor: MoneroComponents.Style._b_historyHeaderTextColor
|
|
themeTransitionWhiteColor: MoneroComponents.Style._w_historyHeaderTextColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: {
|
|
if(!isout && confirmationsRequired === 60) return qsTr("Yes") + translationManager.emptyString;
|
|
if(fee !== "") return Utils.removeTrailingZeros(fee) + " XMR";
|
|
return "-";
|
|
}
|
|
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
MouseArea {
|
|
state: "copyable"
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onEntered: parent.color = MoneroComponents.Style.orange
|
|
onExited: parent.color = MoneroComponents.Style.defaultFontColor
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 10
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
spacing: 0
|
|
clip: true
|
|
Layout.preferredHeight: 120
|
|
Layout.minimumWidth: 230
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 10
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: (isout ? qsTr("To") : qsTr("In")) + translationManager.emptyString
|
|
color: MoneroComponents.Style.historyHeaderTextColor
|
|
themeTransitionBlackColor: MoneroComponents.Style._b_historyHeaderTextColor
|
|
themeTransitionWhiteColor: MoneroComponents.Style._w_historyHeaderTextColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
id: addressField
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: {
|
|
if (isout) {
|
|
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 {
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 10
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 10
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: qsTr("Confirmations") + translationManager.emptyString
|
|
color: MoneroComponents.Style.historyHeaderTextColor
|
|
themeTransitionBlackColor: MoneroComponents.Style._b_historyHeaderTextColor
|
|
themeTransitionWhiteColor: MoneroComponents.Style._w_historyHeaderTextColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
property bool confirmed: confirmations < confirmationsRequired ? false : true
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: confirmed ? confirmations : confirmations + "/" + confirmationsRequired
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
MouseArea {
|
|
state: "copyable"
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onEntered: parent.color = MoneroComponents.Style.orange
|
|
onExited: parent.color = MoneroComponents.Style.defaultFontColor
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 10
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
spacing: 0
|
|
clip: true
|
|
Layout.preferredHeight: 120
|
|
Layout.minimumWidth: 130
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 10
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: qsTr("Date")
|
|
color: MoneroComponents.Style.historyHeaderTextColor
|
|
themeTransitionBlackColor: MoneroComponents.Style._b_historyHeaderTextColor
|
|
themeTransitionWhiteColor: MoneroComponents.Style._w_historyHeaderTextColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: persistentSettings.historyHumanDates ? dateHuman : dateTime
|
|
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
MouseArea {
|
|
state: "copyable"
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onEntered: {
|
|
parent.color = MoneroComponents.Style.orange
|
|
if (persistentSettings.historyHumanDates) {
|
|
parent.text = dateTime;
|
|
}
|
|
}
|
|
onExited: {
|
|
parent.color = MoneroComponents.Style.defaultFontColor
|
|
if (persistentSettings.historyHumanDates) {
|
|
parent.text = dateHuman
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 10
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 10
|
|
}
|
|
|
|
Item {
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 50
|
|
|
|
MoneroComponents.StandardButton {
|
|
id: btnDetails
|
|
text: FontAwesome.info
|
|
small: true
|
|
label.font.family: FontAwesome.fontFamily
|
|
fontSize: 18
|
|
width: 34
|
|
tooltip: qsTr("Transaction details") + translationManager.emptyString
|
|
tooltipLeft: true
|
|
|
|
MouseArea {
|
|
state: "details"
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
z: parent.z + 1
|
|
|
|
onEntered: {
|
|
parent.opacity = 0.8;
|
|
parent.tooltipPopup.open()
|
|
}
|
|
onExited: {
|
|
parent.opacity = 1.0;
|
|
parent.tooltipPopup.close()
|
|
}
|
|
}
|
|
}
|
|
|
|
Image {
|
|
visible: !isout && confirmationsRequired === 60
|
|
anchors.left: btnDetails.right
|
|
anchors.leftMargin: 16
|
|
width: 28
|
|
height: 28
|
|
source: "qrc:///images/miningxmr.png"
|
|
}
|
|
|
|
MoneroComponents.StandardButton {
|
|
visible: isout
|
|
enabled: currentWallet ? !currentWallet.isHwBacked() : false
|
|
anchors.left: btnDetails.right
|
|
anchors.leftMargin: 10
|
|
text: FontAwesome.productHunt
|
|
small: true
|
|
label.font.family: FontAwesome.fontFamilyBrands
|
|
fontSize: 18
|
|
width: 34
|
|
tooltip: qsTr("Generate payment proof") + translationManager.emptyString
|
|
tooltipLeft: true
|
|
|
|
MouseArea {
|
|
state: "proof"
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
z: parent.z + 1
|
|
|
|
onEntered: {
|
|
parent.opacity = 0.8;
|
|
parent.tooltipPopup.open()
|
|
}
|
|
onExited: {
|
|
parent.opacity = 1.0;
|
|
parent.tooltipPopup.close()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
spacing: 0
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 40
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: qsTr("Description") + translationManager.emptyString
|
|
color: MoneroComponents.Style.historyHeaderTextColor
|
|
themeTransitionBlackColor: MoneroComponents.Style._b_historyHeaderTextColor
|
|
themeTransitionWhiteColor: MoneroComponents.Style._w_historyHeaderTextColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
id: txNoteText
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: tx_note !== "" ? tx_note : "-"
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
MouseArea {
|
|
state: "copyable"
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onEntered: parent.color = MoneroComponents.Style.orange
|
|
onExited: parent.color = MoneroComponents.Style.defaultFontColor
|
|
}
|
|
}
|
|
|
|
MoneroEffects.ImageMask {
|
|
anchors.top: parent.top
|
|
anchors.left: txNoteText.right
|
|
anchors.leftMargin: 12
|
|
image: "qrc:///images/edit.svg"
|
|
fontAwesomeFallbackIcon: FontAwesome.pencilSquare
|
|
fontAwesomeFallbackSize: 22
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
opacity: 0.75
|
|
width: 23
|
|
height: 21
|
|
|
|
MouseArea {
|
|
id: txNoteArea
|
|
state: "set_tx_note"
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onEntered: parent.opacity = 0.4;
|
|
onExited: parent.opacity = 0.75;
|
|
cursorShape: Qt.PointingHandCursor
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 10
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: qsTr("Transaction ID") + translationManager.emptyString
|
|
color: MoneroComponents.Style.historyHeaderTextColor
|
|
themeTransitionBlackColor: MoneroComponents.Style._b_historyHeaderTextColor
|
|
themeTransitionWhiteColor: MoneroComponents.Style._w_historyHeaderTextColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: hash
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
MouseArea {
|
|
state: "copyable"
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onEntered: parent.color = MoneroComponents.Style.orange
|
|
onExited: parent.color = MoneroComponents.Style.defaultFontColor
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 10
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: qsTr("Transaction key") + translationManager.emptyString
|
|
color: MoneroComponents.Style.historyHeaderTextColor
|
|
themeTransitionBlackColor: MoneroComponents.Style._b_historyHeaderTextColor
|
|
themeTransitionWhiteColor: MoneroComponents.Style._w_historyHeaderTextColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: qsTr("Click to reveal")
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
state: "txkey_hidden"
|
|
|
|
MouseArea {
|
|
state: "copyable_txkey"
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onEntered: parent.color = MoneroComponents.Style.orange
|
|
onExited: parent.color = MoneroComponents.Style.defaultFontColor
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 10
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: qsTr("Blockheight") + translationManager.emptyString
|
|
color: MoneroComponents.Style.historyHeaderTextColor
|
|
themeTransitionBlackColor: MoneroComponents.Style._b_historyHeaderTextColor
|
|
themeTransitionWhiteColor: MoneroComponents.Style._w_historyHeaderTextColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 20
|
|
|
|
MoneroComponents.TextPlain {
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 14
|
|
text: (blockheight > 0 ? blockheight : qsTr('Pending')) + translationManager.emptyString;
|
|
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
MouseArea {
|
|
state: "copyable"
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onEntered: parent.color = MoneroComponents.Style.orange
|
|
onExited: parent.color = MoneroComponents.Style.defaultFontColor
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color: "transparent"
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 10
|
|
}
|
|
}
|
|
|
|
Item {
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: collapseArea
|
|
objectName: "collapseArea"
|
|
cursorShape: Qt.PointingHandCursor
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
// detect clicks on text (for copying), otherwise toggle collapse
|
|
var doCollapse = true;
|
|
var res = Utils.qmlEach(delegate, ['containsMouse', 'preventStealing', 'scrollGestureEnabled'], ['collapseArea'], []);
|
|
for(var i = 0; i < res.length; i+=1){
|
|
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_address') (address ? root.toClipboard(address) : root.toClipboard(addressField.text));
|
|
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 === 'set_tx_note') root.editDescription(hash, tx_note, root.txPage);
|
|
if(res[i].state === 'details') root.showTxDetails(hash, paymentId, destinations, subaddrAccount, subaddrIndex, dateTime, displayAmount, isout);
|
|
if(res[i].state === 'proof') root.showTxProof(hash, paymentId, destinations, subaddrAccount, subaddrIndex);
|
|
doCollapse = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(doCollapse){
|
|
collapsed = !collapsed;
|
|
|
|
// remember collapsed state
|
|
if(collapsed){
|
|
root.txDataCollapsed.push(hash);
|
|
} else {
|
|
root.removeFromCollapsedList(hash);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.top: parent.top
|
|
anchors.bottom: parent.bottom
|
|
anchors.right: parent.right
|
|
width: sideMargin
|
|
|
|
color: "transparent"
|
|
|
|
MoneroEffects.ImageMask {
|
|
id: collapsedIcon
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 24
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
height: 8
|
|
width: 12
|
|
image: "qrc:///images/whiteDropIndicator.png"
|
|
rotation: delegate.collapsed ? 180 : 0
|
|
color: MoneroComponents.Style.defaultFontColor
|
|
fontAwesomeFallbackIcon: FontAwesome.arrowDown
|
|
fontAwesomeFallbackSize: 14
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: parent.top
|
|
height: 1
|
|
color: MoneroComponents.Style.appWindowBorderColor
|
|
|
|
MoneroEffects.ColorTransition {
|
|
targetObj: parent
|
|
blackColor: MoneroComponents.Style._b_appWindowBorderColor
|
|
whiteColor: MoneroComponents.Style._w_appWindowBorderColor
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: parent.bottom
|
|
height: 1
|
|
color: MoneroComponents.Style.appWindowBorderColor
|
|
|
|
MoneroEffects.ColorTransition {
|
|
targetObj: parent
|
|
blackColor: MoneroComponents.Style._b_appWindowBorderColor
|
|
whiteColor: MoneroComponents.Style._w_appWindowBorderColor
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
visible: sortAndFilter.collapsed
|
|
Layout.topMargin: 10
|
|
Layout.bottomMargin: 10
|
|
Layout.leftMargin: sideMargin
|
|
Layout.rightMargin: sideMargin
|
|
|
|
MoneroComponents.TextPlain {
|
|
// status message
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignHCenter
|
|
font.family: MoneroComponents.Style.fontRegular.name
|
|
font.pixelSize: 15
|
|
text: root.historyStatusMessage;
|
|
color: MoneroComponents.Style.dimmedFontColor
|
|
themeTransitionBlackColor: MoneroComponents.Style._b_dimmedFontColor
|
|
themeTransitionWhiteColor: MoneroComponents.Style._w_dimmedFontColor
|
|
}
|
|
}
|
|
|
|
MoneroComponents.CheckBox2 {
|
|
id: showAdvancedCheckbox
|
|
Layout.topMargin: 30
|
|
Layout.bottomMargin: 20
|
|
Layout.leftMargin: sideMargin
|
|
Layout.rightMargin: sideMargin
|
|
checked: persistentSettings.historyShowAdvanced
|
|
onClicked: persistentSettings.historyShowAdvanced = !persistentSettings.historyShowAdvanced
|
|
text: qsTr("Advanced options") + translationManager.emptyString
|
|
}
|
|
|
|
ColumnLayout {
|
|
visible: persistentSettings.historyShowAdvanced
|
|
Layout.leftMargin: sideMargin
|
|
Layout.rightMargin: sideMargin
|
|
spacing: 20
|
|
|
|
MoneroComponents.CheckBox {
|
|
id: humanDatesCheckBox
|
|
checked: persistentSettings.historyHumanDates
|
|
onClicked: {
|
|
persistentSettings.historyHumanDates = !persistentSettings.historyHumanDates
|
|
root.updateDisplay(root.txOffset, root.txMax);
|
|
}
|
|
text: qsTr("Human readable date format") + translationManager.emptyString
|
|
}
|
|
|
|
MoneroComponents.StandardButton {
|
|
visible: !isIOS
|
|
small: true
|
|
text: qsTr("Export all history") + translationManager.emptyString
|
|
onClicked: {
|
|
writeCSVFileDialog.open();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function refresh(){
|
|
if(appWindow.currentWallet != null && typeof appWindow.currentWallet.history !== "undefined" ) {
|
|
currentWallet.history.refresh(currentWallet.currentSubaddressAccount);
|
|
}
|
|
|
|
if (typeof root.model !== 'undefined' && root.model != null) {
|
|
toDatePicker.currentDate = root.model.transactionHistory.lastDateTime
|
|
}
|
|
|
|
// extract from model, create JS array of txs
|
|
root.updateTransactionsFromModel();
|
|
|
|
// fill listview, update UI
|
|
root.updateDisplay(root.txOffset, root.txMax);
|
|
}
|
|
|
|
function reset(keepDate) {
|
|
root.txOffset = 0;
|
|
|
|
if (typeof root.model !== 'undefined' && root.model != null) {
|
|
if (!keepDate) {
|
|
root.model.dateFromFilter = "2014-04-18" // genesis block
|
|
root.model.dateToFilter = "9999-09-09" // fix before september 9999
|
|
}
|
|
// negative values disable filters here;
|
|
root.model.amountFromFilter = -1;
|
|
root.model.amountToFilter = -1;
|
|
root.model.directionFilter = TransactionInfo.Direction_Both;
|
|
}
|
|
}
|
|
|
|
function updateFilter(currentPage){
|
|
// applying filters
|
|
root.txData = JSON.parse(JSON.stringify(root.txModelData)); // deepcopy
|
|
|
|
const timezoneOffset = new Date().getTimezoneOffset() * 60;
|
|
var fromDate = Math.floor(fromDatePicker.currentDate.getTime() / 86400000) * 86400 + timezoneOffset;
|
|
var toDate = (Math.floor(toDatePicker.currentDate.getTime() / 86400000) + 1) * 86400 + timezoneOffset;
|
|
|
|
var txs = [];
|
|
for (var i = 0; i < root.txData.length; i++){
|
|
var item = root.txData[i];
|
|
var matched = "";
|
|
|
|
// daterange filtering
|
|
if(item.timestamp < fromDate || item.timestamp > toDate){
|
|
continue;
|
|
}
|
|
|
|
// search string filtering
|
|
if(root.sortSearchString == null || root.sortSearchString === ""){
|
|
txs.push(root.txData[i]);
|
|
continue;
|
|
}
|
|
|
|
if(root.sortSearchString.length >= 1){
|
|
if(item.amount && item.amount.toString().startsWith(root.sortSearchString)){
|
|
txs.push(item);
|
|
} else if(item.address !== "" && item.address.toLowerCase().startsWith(root.sortSearchString.toLowerCase())){
|
|
txs.push(item);
|
|
} else if(item.receivingAddress !== "" && item.receivingAddress.toLowerCase().startsWith(root.sortSearchString.toLowerCase())){
|
|
txs.push(item);
|
|
} else if(item.receivingAddressLabel !== "" && item.receivingAddressLabel.toLowerCase().startsWith(root.sortSearchString.toLowerCase())){
|
|
txs.push(item);
|
|
} else if(item.addressBookName !== "" && item.addressBookName.toLowerCase().startsWith(root.sortSearchString.toLowerCase())){
|
|
txs.push(item);
|
|
} else if(typeof item.blockheight !== "undefined" && item.blockheight.toString().startsWith(root.sortSearchString)) {
|
|
txs.push(item);
|
|
} else if(item.tx_note.toLowerCase().indexOf(root.sortSearchString.toLowerCase()) !== -1) {
|
|
txs.push(item);
|
|
} else if (item.hash.startsWith(root.sortSearchString)){
|
|
txs.push(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
root.txData = txs;
|
|
root.txCount = root.txData.length;
|
|
|
|
root.updateSort();
|
|
root.updateDisplay(root.txOffset, root.txMax);
|
|
if (currentPage) {
|
|
root.paginationJump(parseInt(currentPage));
|
|
}
|
|
}
|
|
|
|
function updateSort(){
|
|
// applying sorts
|
|
root.txOffset = 0;
|
|
root.txData.sort(function(a, b) {
|
|
return a[root.sortBy] - b[root.sortBy];
|
|
});
|
|
|
|
if(root.sortDirection)
|
|
root.txData.reverse();
|
|
|
|
root.updateDisplay(root.txOffset, root.txMax);
|
|
}
|
|
|
|
function updateDisplay(tx_offset, tx_max) {
|
|
txListViewModel.clear();
|
|
|
|
// limit results as per tx_max (root.txMax)
|
|
var txs = root.txData.slice(tx_offset, tx_offset + tx_max);
|
|
|
|
// collapse tx if there is a single result
|
|
if(root.txPage === 1 && txs.length === 1)
|
|
root.txDataCollapsed.push(txs[0]['hash']);
|
|
|
|
// populate listview
|
|
for (var i = 0; i < txs.length; i++){
|
|
txListViewModel.append(txs[i]);
|
|
}
|
|
|
|
root.updateHistoryStatusMessage();
|
|
|
|
// determine pagination button states
|
|
var count = txData.length;
|
|
if(count <= root.txMax) {
|
|
paginationPrev.enabled = false;
|
|
paginationNext.enabled = false;
|
|
return;
|
|
}
|
|
|
|
if(root.txOffset < root.txMax)
|
|
paginationPrev.enabled = false;
|
|
else
|
|
paginationPrev.enabled = true;
|
|
|
|
if((root.txOffset + root.txMax) >= count)
|
|
paginationNext.enabled = false;
|
|
else
|
|
paginationNext.enabled = true;
|
|
}
|
|
|
|
function updateTransactionsFromModel() {
|
|
// This function copies the items of `appWindow.currentWallet.historyModel` to `root.txModelData`, as a list of javascript objects
|
|
if(currentWallet == null || typeof currentWallet.history === "undefined" ) return;
|
|
|
|
var _model = root.model;
|
|
var total = 0
|
|
var count = _model.rowCount()
|
|
root.txModelData = [];
|
|
|
|
for (var i = 0; i < count; ++i) {
|
|
var idx = _model.index(i, 0);
|
|
var isPending = model.data(idx, TransactionHistoryModel.TransactionPendingRole);
|
|
var isFailed = model.data(idx, TransactionHistoryModel.TransactionFailedRole);
|
|
var isout = _model.data(idx, TransactionHistoryModel.TransactionIsOutRole);
|
|
var amount = _model.data(idx, TransactionHistoryModel.TransactionAmountRole);
|
|
var hash = _model.data(idx, TransactionHistoryModel.TransactionHashRole);
|
|
var paymentId = _model.data(idx, TransactionHistoryModel.TransactionPaymentIdRole);
|
|
var destinations = _model.data(idx, TransactionHistoryModel.TransactionDestinationsRole);
|
|
var time = _model.data(idx, TransactionHistoryModel.TransactionTimeRole);
|
|
var date = _model.data(idx, TransactionHistoryModel.TransactionDateRole);
|
|
var blockheight = _model.data(idx, TransactionHistoryModel.TransactionBlockHeightRole);
|
|
var confirmations = _model.data(idx, TransactionHistoryModel.TransactionConfirmationsRole);
|
|
var confirmationsRequired = _model.data(idx, TransactionHistoryModel.TransactionConfirmationsRequiredRole);
|
|
var fee = _model.data(idx, TransactionHistoryModel.TransactionFeeRole);
|
|
var subaddrAccount = model.data(idx, TransactionHistoryModel.TransactionSubaddrAccountRole);
|
|
var subaddrIndex = model.data(idx, TransactionHistoryModel.TransactionSubaddrIndexRole);
|
|
var timestamp = new Date(date + " " + time).getTime() / 1000;
|
|
var dateHuman = Utils.ago(timestamp);
|
|
|
|
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 tx_note = currentWallet.getUserNote(hash);
|
|
var address = "";
|
|
var addressBookName = "";
|
|
var receivingAddress = "";
|
|
var receivingAddressLabel = "";
|
|
|
|
if (isout) {
|
|
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)
|
|
total = walletManager.subi(total, amount)
|
|
else
|
|
total = walletManager.addi(total, amount)
|
|
|
|
root.txModelData.push({
|
|
"i": i,
|
|
"isPending": isPending,
|
|
"isFailed": isFailed,
|
|
"isout": isout,
|
|
"amount": amount,
|
|
"displayAmount": displayAmount,
|
|
"hash": hash,
|
|
"paymentId": paymentId,
|
|
"address": address,
|
|
"addressBookName": addressBookName,
|
|
"destinations": destinations,
|
|
"tx_note": tx_note,
|
|
"dateHuman": dateHuman,
|
|
"dateTime": date + " " + time,
|
|
"blockheight": blockheight,
|
|
"address": address,
|
|
"timestamp": timestamp,
|
|
"fee": fee,
|
|
"confirmations": confirmations,
|
|
"confirmationsRequired": confirmationsRequired,
|
|
"receivingAddress": receivingAddress,
|
|
"receivingAddressLabel": receivingAddressLabel,
|
|
"subaddrAccount": subaddrAccount,
|
|
"subaddrIndex": subaddrIndex
|
|
});
|
|
}
|
|
|
|
root.txData = JSON.parse(JSON.stringify(root.txModelData)); // deepcopy
|
|
root.txCount = root.txData.length;
|
|
}
|
|
|
|
function update(currentPage) {
|
|
// handle outside mutation of tx model; incoming/outgoing funds or new blocks. Update table.
|
|
currentWallet.history.refresh(currentWallet.currentSubaddressAccount);
|
|
|
|
root.updateTransactionsFromModel();
|
|
root.updateFilter(currentPage);
|
|
}
|
|
|
|
function editDescription(_hash, _tx_note, currentPage){
|
|
inputDialog.labelText = qsTr("Set description:") + translationManager.emptyString;
|
|
inputDialog.onAcceptedCallback = function() {
|
|
appWindow.currentWallet.setUserNote(_hash, inputDialog.inputText);
|
|
appWindow.showStatusMessage(qsTr("Updated description."),3);
|
|
root.update(currentPage);
|
|
}
|
|
inputDialog.onRejectedCallback = null;
|
|
inputDialog.open(_tx_note);
|
|
}
|
|
|
|
function paginationPrevClicked(){
|
|
root.txOffset -= root.txMax;
|
|
updateDisplay(root.txOffset, root.txMax);
|
|
}
|
|
|
|
function paginationNextClicked(){
|
|
root.txOffset += root.txMax;
|
|
updateDisplay(root.txOffset, root.txMax);
|
|
}
|
|
|
|
function paginationJump(pageNumber){
|
|
root.txOffset = root.txMax * Math.ceil(pageNumber - 1 || 0);
|
|
updateDisplay(root.txOffset, root.txMax);
|
|
}
|
|
|
|
function removeFromCollapsedList(hash){
|
|
root.txDataCollapsed = root.txDataCollapsed.filter(function(item) {
|
|
return item !== hash
|
|
});
|
|
}
|
|
|
|
function updateHistoryStatusMessage(){
|
|
if(root.txModelData.length <= 0){
|
|
root.historyStatusMessage = qsTr("No transaction history yet.") + translationManager.emptyString;
|
|
} else if (root.txData.length <= 0){
|
|
root.historyStatusMessage = qsTr("No results.") + translationManager.emptyString;
|
|
} else {
|
|
root.historyStatusMessage = qsTr("%1 transactions total, showing %2.").arg(root.txData.length).arg(txListViewModel.count) + translationManager.emptyString;
|
|
}
|
|
}
|
|
|
|
function getTxKey(hash, elem){
|
|
if (elem.parent.state != 'ready'){
|
|
currentWallet.getTxKeyAsync(hash, function(hash, txKey) {
|
|
elem.parent.text = txKey ? txKey : '-';
|
|
elem.parent.state = 'ready';
|
|
});
|
|
} else {
|
|
toClipboard(elem.parent.text);
|
|
}
|
|
}
|
|
|
|
function showTxDetails(hash, paymentId, destinations, subaddrAccount, subaddrIndex, dateTime, amount, isout) {
|
|
var tx_note = currentWallet.getUserNote(hash)
|
|
var rings = currentWallet.getRings(hash)
|
|
var address_label = subaddrIndex == 0 ? (qsTr("Primary address") + translationManager.emptyString) : currentWallet.getSubaddressLabel(subaddrAccount, subaddrIndex)
|
|
var address = currentWallet.address(subaddrAccount, subaddrIndex)
|
|
const hasPaymentId = parseInt(paymentId, 16);
|
|
const integratedAddress = !isout && hasPaymentId ? currentWallet.integratedAddress(paymentId) : null;
|
|
|
|
if (rings)
|
|
rings = rings.replace(/\|/g, '\n')
|
|
|
|
currentWallet.getTxKeyAsync(hash, function(hash, tx_key) {
|
|
informationPopup.title = qsTr("Transaction details") + translationManager.emptyString;
|
|
informationPopup.content = buildTxDetailsString(hash, hasPaymentId ? paymentId : null, tx_key, tx_note, destinations, rings, address, address_label, integratedAddress, dateTime, amount);
|
|
informationPopup.onCloseCallback = null
|
|
informationPopup.open();
|
|
});
|
|
}
|
|
|
|
function showTxProof(hash, paymentId, destinations, subaddrAccount, subaddrIndex){
|
|
var address = TxUtils.destinationsToAddress(destinations);
|
|
if(address === undefined){
|
|
console.log('getProof: Error fetching address')
|
|
return;
|
|
}
|
|
|
|
var checked = (TxUtils.checkTxID(hash) && TxUtils.checkAddress(address, appWindow.persistentSettings.nettype));
|
|
if(!checked){
|
|
console.log('getProof: Error checking TxId and/or address');
|
|
}
|
|
|
|
console.log("getProof: Generate clicked: txid " + hash + ", address " + address);
|
|
middlePanel.getProofClicked(hash, address, '', null);
|
|
informationPopup.title = qsTr("Payment proof") + translationManager.emptyString;
|
|
informationPopup.text = qsTr("Generating payment proof") + "..." + translationManager.emptyString;
|
|
informationPopup.onCloseCallback = null
|
|
informationPopup.open()
|
|
}
|
|
|
|
function toClipboard(text){
|
|
console.log("Copied to clipboard");
|
|
clipboard.setText(text);
|
|
appWindow.showStatusMessage(qsTr("Copied to clipboard"),3);
|
|
}
|
|
|
|
function buildTxDetailsString(tx_id, paymentId, tx_key,tx_note, destinations, rings, address, address_label, integratedAddress, dateTime, amount) {
|
|
var trStart = '<tr><td style="white-space: nowrap; padding-top:5px"><b>',
|
|
trMiddle = '</b></td><td style="padding-left:10px;padding-top:5px;">',
|
|
trEnd = "</td></tr>";
|
|
|
|
return '<table border="0">'
|
|
+ (tx_id ? trStart + qsTr("Tx ID:") + trMiddle + tx_id + trEnd : "")
|
|
+ (dateTime ? trStart + qsTr("Date") + ":" + trMiddle + dateTime + trEnd : "")
|
|
+ (amount ? trStart + qsTr("Amount") + ":" + trMiddle + amount + trEnd : "")
|
|
+ (address ? trStart + qsTr("Address:") + trMiddle + address + trEnd : "")
|
|
+ (paymentId ? trStart + qsTr("Payment ID:") + trMiddle + paymentId + trEnd : "")
|
|
+ (integratedAddress ? trStart + qsTr("Integrated address") + ":" + trMiddle + integratedAddress + trEnd : "")
|
|
+ (tx_key ? trStart + qsTr("Tx key:") + trMiddle + tx_key + trEnd : "")
|
|
+ (tx_note ? trStart + qsTr("Tx note:") + trMiddle + tx_note + trEnd : "")
|
|
+ (destinations ? trStart + qsTr("Destinations:") + trMiddle + destinations + trEnd : "")
|
|
+ (rings ? trStart + qsTr("Rings:") + trMiddle + rings + trEnd : "")
|
|
+ "</table>"
|
|
+ translationManager.emptyString;
|
|
}
|
|
|
|
FileDialog {
|
|
id: writeCSVFileDialog
|
|
title: qsTr("Please choose a folder") + translationManager.emptyString
|
|
selectFolder: true
|
|
onRejected: {
|
|
console.log("csv write canceled")
|
|
}
|
|
onAccepted: {
|
|
var dataDir = walletManager.urlToLocalPath(writeCSVFileDialog.fileUrl);
|
|
var written = currentWallet.history.writeCSV(currentWallet.currentSubaddressAccount, dataDir);
|
|
|
|
if(written !== ""){
|
|
informationPopup.title = qsTr("Success") + translationManager.emptyString;
|
|
var text = qsTr("CSV file written to: %1").arg(written) + "\n\n"
|
|
text += qsTr("Tip: Use your favorite spreadsheet software to sort on blockheight.") + "\n\n" + translationManager.emptyString;
|
|
informationPopup.text = text;
|
|
informationPopup.icon = StandardIcon.Information;
|
|
} else {
|
|
informationPopup.title = qsTr("Error") + translationManager.emptyString;
|
|
informationPopup.text = qsTr("Error exporting transaction data.") + "\n\n" + translationManager.emptyString;
|
|
informationPopup.icon = StandardIcon.Critical;
|
|
}
|
|
informationPopup.onCloseCallback = null;
|
|
informationPopup.open();
|
|
}
|
|
Component.onCompleted: {
|
|
var _folder = 'file://' + appWindow.accountsDir;
|
|
try {
|
|
_folder = 'file://' + desktopFolder;
|
|
}
|
|
catch(err) {}
|
|
finally {
|
|
writeCSVFileDialog.folder = _folder;
|
|
}
|
|
}
|
|
}
|
|
|
|
function onPageCompleted() {
|
|
// setup date filter scope according to real transactions
|
|
if(appWindow.currentWallet != null){
|
|
root.model = appWindow.currentWallet.historyModel;
|
|
root.model.sortRole = TransactionHistoryModel.TransactionBlockHeightRole
|
|
root.model.sort(0, Qt.DescendingOrder);
|
|
var count = root.model.rowCount()
|
|
if (count > 0) {
|
|
//date of the first transaction
|
|
fromDatePicker.currentDate = root.model.data(root.model.index((count - 1), 0), TransactionHistoryModel.TransactionDateRole);
|
|
} else {
|
|
//date of monero birth (2014-04-18)
|
|
fromDatePicker.currentDate = model.transactionHistory.firstDateTime
|
|
}
|
|
}
|
|
|
|
root.reset();
|
|
root.refresh();
|
|
root.initialized = true;
|
|
root.updateFilter();
|
|
}
|
|
|
|
function onPageClosed(){
|
|
root.initialized = false;
|
|
root.reset(true);
|
|
root.clearFields();
|
|
}
|
|
|
|
function searchInHistory(searchTerm){
|
|
searchInput.text = searchTerm;
|
|
searchInput.forceActiveFocus();
|
|
searchInput.cursorPosition = searchInput.text.length;
|
|
sortAndFilter.collapsed = true;
|
|
}
|
|
|
|
function clearFields() {
|
|
sortAndFilter.collapsed = false;
|
|
searchInput.text = "";
|
|
root.txDataCollapsed = [];
|
|
}
|
|
}
|