Files
pay/guis/desktop/TransactionDetails.qml
T
tomFlowee e671d41a10 Skip fees when unknown
We can't calculate fees when we don't know all inputs. In that case we
simply return negative fees, which the UI then does not show.
2024-07-03 18:03:17 +02:00

339 lines
14 KiB
QML

/*
* This file is part of the Flowee project
* Copyright (C) 2020-2024 Tom Zander <tom@flowee.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import "../Flowee" as Flowee
import Flowee.org.pay
QQC2.ApplicationWindow {
id: root
visible: false
minimumWidth: 200
minimumHeight: 200
width: 400
height: 500
title: qsTr("Transaction Details")
modality: Qt.NonModal
flags: Qt.Widget
function openTab(walletIndex) {
transactions.push(portfolio.current.txInfo(walletIndex, root))
tabList.model = transactions.length
// open the newly created tab
tabbar.currentIndex = transactions.length - 1
}
property var transactions: []
background: Rectangle { color: palette.window }
Rectangle {
width: parent.width
height: tabbar.headerHeight
color: Pay.useDarkSkin ? palette.window : mainWindow.floweeBlue
Rectangle {
anchors.fill: parent
opacity: 0.2
color: Pay.useDarkSkin ? "black" : "white"
}
}
Flowee.TabBar {
id: tabbar
anchors.fill: parent
Repeater {
id: tabList
delegate: Flickable {
id: delegateRoot
anchors.fill: parent
contentHeight: content.height + 20
clip: true
property QtObject txInfo: root.transactions[index];
// properties for the tabbar
property string title: txInfo.txid
property string icon: ""
Flowee.CloseIcon {
anchors.right: parent.right
y: 6
anchors.rightMargin: 6
onClicked: {
root.transactions.splice(index, 1);
if (root.transactions.length == 0) {
root.close();
}
else {
tabbar.currentIndex = Math.max(0, index - 1)
tabList.model = transactions.length
}
}
}
Column {
id: content
width: parent.width - 20
x: 10
y: 10
spacing: 10
GridLayout {
width: parent.width
columns: 2
Flowee.Label {
text: qsTr("First Seen") + ":"
Layout.alignment: Qt.AlignRight
}
Flowee.Label {
Layout.fillWidth: true
text: Qt.formatDateTime(txInfo.date)
}
Flowee.Label {
visible: minedDateLabel.visible
Layout.alignment: Qt.AlignTop | Qt.AlignRight
text: {
var h = txInfo.height;
if (h === -2)
var s = qsTr("Rejected")
if (h === -1)
s = qsTr("Unconfirmed")
else
s = qsTr("Mined at");
return s + ":";
}
}
Flowee.Label {
id: minedDateLabel
visible: text !== ""
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
Layout.fillWidth: true
text: {
let txHeight = txInfo.minedHeight;
if (txHeight < 1)
return "";
var answer = txHeight + "\n" + Pay.formatBlockTime(txHeight)
let blockAge = Pay.chainHeight - txHeight + 1;
answer += "\n";
answer += qsTr("%1 blocks ago", "", blockAge).arg(blockAge);
return answer;
}
}
Flowee.Label {
Layout.alignment: Qt.AlignRight
text: qsTr("Comment") + ":"
}
Flowee.TextField {
id: editableLabel
Layout.fillWidth: true
text: txInfo.userComment
onTextChanged: txInfo.userComment = text
}
Flowee.FiatTxInfo {
txInfo: delegateRoot.txInfo
Layout.fillWidth: true
Layout.columnSpan: 2
}
// We can't calculate the fees of just any transaction,
// only for the ones this account created.
Flowee.Label {
id: feesSection
text: qsTr("Fees paid") + ":"
visible: txInfo.fees >= 0
Layout.alignment: Qt.AlignRight
}
Flowee.Label {
visible: feesSection.visible
text: qsTr("%1 Satoshi / 1000 bytes")
.arg((txInfo.fees * 1000 / txInfo.size).toFixed(0))
}
Item {
visible: feesSection.visible
width: 1; height: 1
}
Flowee.BitcoinAmountLabel {
visible: feesSection.visible
value: txInfo.fees
fiatTimestamp: txInfo.date
colorize: false
}
Flowee.Label {
text: qsTr("Size") + ":"
Layout.alignment: Qt.AlignRight
}
Flowee.Label {
text: qsTr("%1 bytes").arg(txInfo.size)
}
Item {
width: 1; height: 1
visible: txInfo.isCoinbase
}
Flowee.Label {
text: qsTr("Is Coinbase")
visible: txInfo.isCoinbase
}
// txid line
Flowee.Label {
text: "TXID:"
Layout.alignment: Qt.AlignTop | Qt.AlignRight
}
Flowee.LabelWithClipboard {
menuText: qsTr("Copy transaction-ID")
text: txInfo.txid
font.pixelSize: root.font.pixelSize * 0.9
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
Layout.fillWidth: true
}
}
Flowee.Label {
id: inputsList
text: {
if (txInfo == null)
return "";
if (txInfo.isFused)
return qsTr("Fused from my addresses");
if (txInfo.createdByUs)
return qsTr("Sent from my addresses");
if (txInfo.isFused)
return qsTr("Sent from addresses");
return "";
}
visible: title !== ""
font.bold: true
}
Repeater {
model: inputsList.visible ? txInfo.knownInputs : 0
delegate: Item {
Layout.alignment: Qt.AlignRight
width: content.width
height: {
if (modelData === null)
return 6;
var neededWidth = inAddress.implicitWidth + 10 + amount.implicitWidth;
if (fusedIcon.visible)
neededWidth += 6 + fusedIcon.width
if (neededWidth < content.width)
return inAddress.height + 10;
return inAddress.height + amount.height + 16;
}
Flowee.CFIcon {
id: fusedIcon
visible: modelData.fromFused
}
Flowee.AddressLabel {
id: inAddress
txInfo: modelData
x: fusedIcon.visible ? fusedIcon.width + 6 : 0
width: Math.min(implicitWidth, parent.width - (fusedIcon.visible ? fusedIcon.width: 0))
showCopyIcon: false;
}
Flowee.BitcoinAmountLabel {
id: amount
visible: modelData !== null
value: modelData === null ? 0 : (-1 * modelData.value)
fiatTimestamp: txInfo.date
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: 10
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: inAddress.showCopyIcon = true;
onExited: inAddress.showCopyIcon = false;
propagateComposedEvents: true;
}
}
}
Flowee.Label {
text: {
if (txInfo == null)
return "";
if (txInfo.isFused)
return qsTr("Fused into my addresses");
if (txInfo.createdByUs)
return qsTr("Received at addresses");
return qsTr("Received at my addresses");
}
font.bold: true
}
Repeater {
model: txInfo.knownOutputs
delegate: Item {
Layout.alignment: Qt.AlignRight
width: content.width
height: {
var neededWidth = outAddress.implicitWidth + 10 + outAmount.implicitWidth;
if (ctIcon.visible)
neededWidth += 6 + ctIcon.width
if (neededWidth < width)
return outAmount.height + 10;
return outAddress.height + outAmount.height + 16;
}
Image {
id: ctIcon
visible: modelData.hasCashToken
source: "qrc:/CashTokens.svg";
width: 24
height: 24
}
Flowee.AddressLabel {
id: outAddress
txInfo: modelData
highlight: modelData.forMe
x: ctIcon.visible ? ctIcon.width + 6 : 0
width: Math.min(implicitWidth, parent.width - (ctIcon.visible ? ctIcon.width: 0))
showCopyIcon: false;
}
Flowee.BitcoinAmountLabel {
id: outAmount
value: modelData.value
fiatTimestamp: txInfo.date
colorize: modelData.forMe
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: 10
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: outAddress.showCopyIcon = true;
onExited: outAddress.showCopyIcon = false;
propagateComposedEvents: true;
}
}
}
}
}
}
}
}