mirror of
https://github.com/monero-project/monero-gui
synced 2024-11-24 11:17:15 +01:00
1834 lines
81 KiB
QML
1834 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, '');
|
|
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 = [];
|
|
}
|
|
}
|