2020-10-15 19:18:54 +02:00
/*
* This file is part of the Flowee project
2022-04-12 21:38:08 +02:00
* Copyright (C) 2020-2022 Tom Zander <tom@flowee.org>
2020-10-15 19:18:54 +02:00
*
* 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/>.
*/
2021-05-23 00:27:34 +02:00
import QtQuick 2.11
import QtQuick . Controls 2.11
import QtQuick . Layouts 1.11
import QtQuick . Window 2.11
2021-11-29 23:16:45 +01:00
import QtQuick . Shapes 1.11 // for shape-path
2021-11-02 19:32:13 +01:00
import "widgets" as Flowee
2021-11-02 19:13:14 +01:00
import "./ControlColors.js" as ControlColors
2020-06-11 17:41:18 +02:00
import Flowee . org . pay 1.0
2021-11-24 19:54:55 +01:00
Item {
2021-11-23 16:46:37 +01:00
id: sendPanel
2021-11-27 09:26:28 +01:00
focus: true
2021-11-23 16:46:37 +01:00
2021-11-16 19:14:45 +01:00
Payment { // the model behind the Payment logic
id: payment
2021-11-18 14:25:47 +01:00
fiatPrice: Fiat . price
account: portfolio . current
2021-11-16 19:14:45 +01:00
}
2021-11-24 19:54:55 +01:00
Rectangle { // background
anchors.fill: parent
color: mainWindow . palette . window
}
2021-11-23 16:46:37 +01:00
Flickable {
id: contentArea
width: sendPanel . width - 20
2021-11-24 19:54:55 +01:00
y: 40
x: 10
height: parent . height - 40
2021-11-23 16:46:37 +01:00
contentHeight: mainColumn . height
contentWidth: width
2021-11-24 14:56:52 +01:00
clip: true
2021-11-23 16:46:37 +01:00
Column {
id: mainColumn
2021-04-22 22:04:30 +02:00
width: parent . width
2021-11-23 16:46:37 +01:00
spacing: 10
Repeater {
model: payment . details
delegate: Item {
width: mainColumn . width
height: loader . height + 6
Loader {
id: loader
width: parent . width
height: status === Loader . Ready ? item.implicitHeight : 0
sourceComponent: {
if ( modelData . type === Payment . PayToAddress )
return destinationFields
if ( modelData . type === Payment . InputSelector )
return inputFields
return null ; // should never happen
}
onLoaded: item . paymentDetail = modelData
2021-11-17 14:24:19 +01:00
}
2020-10-23 22:34:34 +02:00
2021-11-23 16:46:37 +01:00
Rectangle {
id: deleteDetailButton
anchors.right: parent . right
anchors.rightMargin: 10
y: - 3
width: 32
height: 32
visible: modelData . collapsable && ! modelData . collapsed
color: mouseArea . containsMouse ? mainWindow.palette.button : mainWindow . palette . window
border.color: mainWindow . palette . button
2020-06-12 23:37:32 +02:00
2021-11-23 16:46:37 +01:00
Image {
source: "qrc:/edit-delete.svg"
width: 24
height: 24
anchors.centerIn: parent
}
2021-04-26 19:57:00 +02:00
2021-11-23 16:46:37 +01:00
MouseArea {
id: mouseArea
anchors.fill: parent
anchors.margins: - 3
cursorShape: Qt . ArrowCursor
hoverEnabled: true
onClicked: okCancelDiag . visible = true ;
2021-11-16 19:14:45 +01:00
}
}
2021-11-23 16:46:37 +01:00
Flowee . Dialog {
id: okCancelDiag
onAccepted: payment . remove ( modelData ) ;
2022-05-18 17:32:23 +02:00
title: qsTr ( "Confirm delete" )
text: qsTr ( "Do you really want to delete this detail?" )
2021-11-23 16:46:37 +01:00
}
2021-04-29 16:15:05 +02:00
}
2021-11-23 16:46:37 +01:00
}
2020-06-12 23:37:32 +02:00
2021-11-23 16:46:37 +01:00
RowLayout {
width: parent . width
spacing: 0
Flowee . Button {
text: qsTr ( "Add Destination" )
onClicked: payment . addExtraOutput ( ) ;
}
Item { Layout.fillWidth: true }
Flowee . Button {
id: prepareButton
text: qsTr ( "Prepare" )
enabled: payment . isValid
property QtObject portfolioUsed: null
onClicked: {
portfolioUsed = portfolio . current
2022-05-18 20:16:34 +02:00
if ( payment . walletNeedsPin ) {
passwdDialog . start ( )
} else {
payment . prepare ( ) ;
}
2021-11-23 16:46:37 +01:00
}
}
2022-07-14 19:19:19 +02:00
Flowee . PasswdDialog {
2022-05-18 20:16:34 +02:00
id: passwdDialog
title: qsTr ( "Enter your PIN" )
2022-06-29 20:06:01 +02:00
2022-07-14 19:19:19 +02:00
onAccepted: {
2022-06-29 20:06:01 +02:00
payment . decrypt ( pwd ) ;
if ( payment . error === "" )
payment . prepare ( ) ;
2022-05-18 20:16:34 +02:00
}
}
2021-11-23 16:46:37 +01:00
}
2022-07-11 19:17:05 +02:00
Flowee . WarningLabel {
id: warningLabel
2021-11-30 11:11:06 +01:00
width: parent . width
2022-07-11 19:17:05 +02:00
text: payment . error
color: txid . color // make sure this is 'disabled' when the warning is not for this wallet.
2021-11-23 16:46:37 +01:00
}
Flowee . GroupBox {
id: txDetails
Layout.columnSpan: 4
title: qsTr ( "Transaction Details" )
width: parent . width
GridLayout {
columns: 2
property bool txOk: payment . txPrepared
Label {
// no need translating this one.
text: "TxId:"
Layout.alignment: Qt . AlignRight | Qt . AlignTop
}
2021-11-30 13:54:11 +01:00
Flowee . LabelWithClipboard {
2021-11-23 16:46:37 +01:00
id: txid
text: payment . txid === "" ? qsTr ( "Not prepared yet" ) : payment . txid
Layout.fillWidth: true
// Change the color when the portfolio changed since 'prepare' was clicked.
color: prepareButton . portfolioUsed === portfolio . current
? palette.text
: Qt . darker ( palette . text , ( Pay . useDarkSkin ? 1.6 : 0.4 ) )
2022-03-22 23:17:35 +01:00
menuText: qsTr ( "Copy transaction-ID" )
2021-11-23 16:46:37 +01:00
}
Label {
text: qsTr ( "Fee" ) + ":"
Layout.alignment: Qt . AlignRight
}
Flowee . BitcoinAmountLabel {
value: ! parent . txOk ? 0 : payment . assignedFee
colorize: false
color: txid . color
}
Label {
text: qsTr ( "Transaction size" ) + ":"
Layout.alignment: Qt . AlignRight
}
Label {
text: {
if ( ! parent . txOk )
return "" ;
var rc = payment . txSize ;
2021-12-04 15:43:48 +01:00
return qsTr ( "%1 bytes" ) . arg ( rc )
2021-11-23 16:46:37 +01:00
}
color: txid . color
}
Label {
text: qsTr ( "Fee per byte" ) + ":"
Layout.alignment: Qt . AlignRight
}
Label {
text: {
if ( ! parent . txOk )
return "" ;
var rc = payment . assignedFee / payment . txSize ;
var fee = rc . toFixed ( 3 ) ; // no more than 3 numbers behind the separator
fee = ( fee * 1.0 ) . toString ( ) ; // remove trailing zero's (1.000 => 1)
2021-12-04 15:43:48 +01:00
return qsTr ( "%1 sat/byte" , "fee" ) . arg ( fee ) ;
2021-11-23 16:46:37 +01:00
}
color: txid . color
}
}
}
2021-12-09 18:55:06 +01:00
Flowee . DialogButtonBox {
id: box
2021-11-23 16:46:37 +01:00
width: parent . width
2021-12-09 18:55:06 +01:00
standardButtons: DialogButtonBox . Cancel | DialogButtonBox . Ok
onStandardButtonsChanged: {
var okButton = standardButton ( DialogButtonBox . Ok )
if ( okButton !== null ) {
okButton . text = qsTr ( "Send" )
okButton . enabled = canSend
}
2021-04-23 19:59:49 +02:00
}
2021-12-09 18:55:06 +01:00
property bool canSend: payment . isValid && payment . txPrepared
&& prepareButton . portfolioUsed === portfolio . current ; // also make sure we prepared for the current portfolio.
onCanSendChanged: setEnabled ( DialogButtonBox . Ok , canSend )
onRejected: payment . reset ( ) ;
onAccepted: payment . broadcast ( ) ;
2021-04-23 19:59:49 +02:00
}
2020-06-12 20:53:01 +02:00
}
2021-04-26 21:59:22 +02:00
}
2021-04-23 19:59:49 +02:00
2021-11-30 13:50:40 +01:00
// the panel that allows us to tweak the payment (add details)
2021-11-24 19:20:06 +01:00
PaymentTweakingPanel {
anchors.fill: parent
}
2021-11-27 09:26:28 +01:00
Keys.forwardTo: Flowee . ListViewKeyHandler {
id: listViewKeyHandler
}
2021-11-24 19:20:06 +01:00
2021-11-29 23:16:45 +01:00
Control {
id: broadcastFeedback
anchors.fill: parent
states: [
State {
name: "notStarted"
when: payment . broadcastStatus === Payment . NotStarted
} ,
State {
name: "preparing"
when: payment . broadcastStatus === Payment . TxOffered
PropertyChanges { target: background ;
opacity: 1
y: 0
}
PropertyChanges { target: progressCircle ; sweepAngle: 90 }
StateChangeScript { script: ControlColors . applyLightSkin ( broadcastFeedback ) }
} ,
State {
name: "sent1" // sent to only one peer
extend: "preparing"
when: payment . broadcastStatus === Payment . TxSent1
PropertyChanges { target: progressCircle ; sweepAngle: 150 }
} ,
State {
name: "waiting" // waiting for possible rejection.
when: payment . broadcastStatus === Payment . TxWaiting
extend: "preparing"
PropertyChanges { target: progressCircle ; sweepAngle: 320 }
} ,
State {
name: "success" // no reject, great success
when: payment . broadcastStatus === Payment . TxBroadcastSuccess
extend: "preparing"
PropertyChanges { target: progressCircle
sweepAngle: 320
startAngle: - 20
}
PropertyChanges { target: checkShape ; opacity: 1 }
} ,
State {
name: "rejected" // a peer didn't like our tx
when: payment . broadcastStatus === Payment . TxRejected
extend: "preparing"
PropertyChanges { target: background ; color: "#c80000" }
PropertyChanges { target: circleShape ; opacity: 0 }
PropertyChanges {
target: txidFeedbackLabel
text: qsTr ( "Transaction rejected by network" )
}
}
]
Rectangle {
id: background
width: parent . width
height: parent . height
opacity: 0
visible: opacity != 0
color: mainWindow . floweeGreen
y: height + 2
Label {
id: title
anchors.horizontalCenter: parent . horizontalCenter
font.pointSize: 15
2021-11-30 12:02:33 +01:00
y: 25
text: qsTr ( "Payment Sent" )
2021-11-29 23:16:45 +01:00
}
// The 'progress' icon.
Shape {
id: circleShape
anchors.horizontalCenter: parent . horizontalCenter
anchors.top: title . bottom
anchors.topMargin: 10
width: 160
height: width
smooth: true
ShapePath {
strokeWidth: 20
strokeColor: "#dedede"
fillColor: "transparent"
capStyle: ShapePath . RoundCap
startX: 100 ; startY: 10
PathAngleArc {
id: progressCircle
centerX: 80
centerY: 80
radiusX: 70 ; radiusY: 70
startAngle: - 80
sweepAngle: 0
Behavior on sweepAngle { NumberAnimation { duration: 2500 } }
Behavior on startAngle { NumberAnimation { } }
}
}
Behavior on opacity { NumberAnimation { } }
}
Shape {
id: checkShape
anchors.fill: circleShape
smooth: true
opacity: 0
ShapePath {
id: checkPath
strokeWidth: 16
strokeColor: "green"
fillColor: "transparent"
capStyle: ShapePath . RoundCap
2021-11-30 12:02:33 +01:00
startX: 52 ; startY: 80
PathLine { x: 76 ; y: 110 }
PathLine { x: 125 ; y: 47 }
2021-11-29 23:16:45 +01:00
}
}
Label {
id: fiatAmount
anchors.horizontalCenter: parent . horizontalCenter
anchors.top: circleShape . bottom
anchors.topMargin: 10
font.pointSize: 24
text: Fiat . formattedPrice ( payment . effectiveFiatAmount )
2021-11-30 14:34:41 +01:00
visible: Fiat . price !== 0
2021-11-29 23:16:45 +01:00
}
Flowee . BitcoinAmountLabel {
id: cryptoAmount
anchors.horizontalCenter: parent . horizontalCenter
anchors.top: fiatAmount . bottom
anchors.topMargin: 20
2021-12-01 16:42:50 +01:00
fontPtSize: 13
2021-11-29 23:16:45 +01:00
value: payment . effectiveBchAmount
colorize: false
2021-12-01 16:42:50 +01:00
showFiat: false
2021-11-29 23:16:45 +01:00
}
2021-11-30 13:54:11 +01:00
Flowee . LabelWithClipboard {
2021-11-29 23:16:45 +01:00
id: txidFeedbackLabel
anchors.top: cryptoAmount . bottom
anchors.topMargin: 20
anchors.horizontalCenter: parent . horizontalCenter
menuText: qsTr ( "Copy transaction-ID" )
clipboardText: payment . txid
width: parent . width
horizontalAlignment: Qt . AlignHCenter
text: qsTr ( "Your payment can be found by its identifyer: %1" ) . arg ( payment . txid )
wrapMode: Text . WrapAtWordBoundaryOrAnywhere
}
RowLayout {
id: txIdFeedback
anchors.top: txidFeedbackLabel . bottom
anchors.topMargin: 10
anchors.horizontalCenter: parent . horizontalCenter
ToolButton {
2021-11-30 12:02:33 +01:00
icon.source: "qrc:/edit-copy.svg"
2021-11-29 23:16:45 +01:00
onClicked: Pay . copyToClipboard ( payment . txid ) ;
2021-11-30 12:02:33 +01:00
text: qsTr ( "Copy" )
2021-11-29 23:16:45 +01:00
}
ToolButton {
2021-11-30 12:02:33 +01:00
onClicked: Pay . openInExplorer ( payment . txid ) ;
text: qsTr ( "Internet" )
2021-11-29 23:16:45 +01:00
}
}
Label {
anchors.verticalCenter: transactionComment . verticalCenter
anchors.right: transactionComment . left
anchors.rightMargin: 10
text: qsTr ( "Comment" ) + ":"
}
Flowee . TextField {
id: transactionComment
anchors.top: txIdFeedback . bottom
anchors.topMargin: 20
anchors.horizontalCenter: parent . horizontalCenter
width: 400
onTextChanged: payment . userComment = text
}
Flowee . Button {
anchors.top: transactionComment . bottom
anchors.topMargin: 10
anchors.right: parent . right
anchors.rightMargin: 20
text: qsTr ( "Close" )
2021-12-09 22:45:26 +01:00
onClicked: {
payment . reset ( )
transactionComment . text = ""
}
2021-11-29 23:16:45 +01:00
}
Behavior on opacity { NumberAnimation { } }
Behavior on y { NumberAnimation { } }
Behavior on color { ColorAnimation { } }
}
}
2021-11-16 19:14:45 +01:00
// ============= Payment components ===============
2021-04-26 21:59:22 +02:00
2021-11-29 23:16:45 +01:00
/*
2021-12-14 13:32:58 +01:00
* Destination.
2021-11-29 23:16:45 +01:00
* The payment-output (address based) component.
*/
2021-11-16 19:14:45 +01:00
Component {
id: destinationFields
Flowee . GroupBox {
id: destinationPane
property QtObject paymentDetail: null
collapsable: paymentDetail . collapsable
2021-12-14 13:32:58 +01:00
onEffectiveCollapsedChanged: paymentDetail . collapsed = effectiveCollapsed
2021-11-16 19:14:45 +01:00
collapsed: paymentDetail . collapsed
2021-11-18 17:40:41 +01:00
title: qsTr ( "Destination" )
summary: {
var ad = paymentDetail . address
if ( ad === "" )
ad = "\'\'" ;
if ( paymentDetail . fiatFollows ) {
if ( paymentDetail . maxSelected )
var amount = qsTr ( "Max available" , "The maximum balance available" )
else
amount = Pay . priceToStringPretty ( paymentDetail . paymentAmount )
+ " " + Pay . unitName ;
}
else {
amount = Fiat . formattedPrice ( paymentDetail . fiatAmount )
}
return qsTr ( "%1 to %2" , "summary text to pay X-euro to address M" )
. arg ( amount ) . arg ( ad ) ;
}
2021-12-09 15:44:22 +01:00
Item {
implicitWidth: parent . width
implicitHeight: Math . max ( contentColumn . height , warningArea . visible ? warningArea.height : 0 )
ColumnLayout {
id: contentColumn
width: parent . width
RowLayout {
width: parent . width
Flowee . TextField {
id: destination
focus: true
property bool addressOk: ( addressType === Bitcoin . CashPKH || addressType === Bitcoin . CashSH )
2021-12-09 16:09:48 +01:00
|| ( paymentDetail . forceLegacyOk && ( addressType === Bitcoin . LegacySH || addressType === Bitcoin . LegacyPKH ) )
2021-12-09 15:44:22 +01:00
property var addressType: Pay . identifyString ( text ) ;
Layout.fillWidth: true
Layout.columnSpan: 3
onActiveFocusChanged: updateColor ( ) ;
2022-04-07 18:16:03 +02:00
onAddressOkChanged: {
2022-04-12 21:38:08 +02:00
updateColor ( ) ;
addressInfo . createInfo ( ) ;
2022-04-07 18:16:03 +02:00
}
2021-12-09 15:44:22 +01:00
placeholderText: qsTr ( "Enter Bitcoin Cash Address" )
text: destinationPane . paymentDetail . address
onTextChanged: {
destinationPane . paymentDetail . address = text
updateColor ( ) ;
2022-04-12 21:38:08 +02:00
addressInfo . createInfo ( ) ;
2021-12-09 15:44:22 +01:00
}
2021-11-16 19:14:45 +01:00
2021-12-09 15:44:22 +01:00
function updateColor ( ) {
if ( ! activeFocus && text !== "" && ! addressOk )
color = Pay . useDarkSkin ? "#ff6568" : "red"
else
color = mainWindow . palette . text
}
}
Label {
color: "green"
font.pixelSize: 24
text: destination . addressOk ? "✔" : " "
}
2021-11-18 14:25:47 +01:00
}
2021-12-09 16:09:48 +01:00
Flowee . LabelWithClipboard {
visible: text !== ""
Layout.fillWidth: true
text: paymentDetail . formattedTarget
horizontalAlignment: Qt . AlignRight
font.italic: true
}
2022-04-07 18:16:03 +02:00
Item {
id: addressInfo
width: parent . width
property QtObject info: null
visible: info != null
2022-04-12 21:38:08 +02:00
function createInfo ( ) {
if ( destination . addressOk ) {
var address = paymentDetail . formattedTarget
if ( address === "" ) // it didn't need reformatting
address = paymentDetail . address
info = Pay . researchAddress ( address , addressInfo )
}
else {
delete info ;
info = null ;
}
}
Label {
2022-04-07 18:16:03 +02:00
anchors.right: parent . right
2022-04-12 21:38:08 +02:00
font.italic: true
text: {
var info = addressInfo . info
if ( info == null )
return "" ;
if ( portfolio . current . id === info . accountId )
return qsTr ( "self" , "payment to self" )
return info . accountName
}
2022-04-07 18:16:03 +02:00
}
}
2021-12-09 15:44:22 +01:00
Label {
id: payAmount
text: qsTr ( "Amount" ) + ":"
}
RowLayout {
Flowee . FiatValueField {
id: fiatValueField
visible: Fiat . price > 0
onValueEdited: destinationPane . paymentDetail . fiatAmount = value
value: destinationPane . paymentDetail . fiatAmount
}
Flowee . CheckBox {
id: amountSelector
sliderOnIndicator: false
visible: Fiat . price > 0
enabled: false
checked: destinationPane . paymentDetail . fiatFollows
}
Flowee . BitcoinValueField {
id: bitcoinValueField
value: destinationPane . paymentDetail . paymentAmount
onValueEdited: destinationPane . paymentDetail . paymentAmount = value
}
Flowee . Button {
id: sendAll
visible: destinationPane . paymentDetail . maxAllowed
text: qsTr ( "Max" )
checkable: true
checked: destinationPane . paymentDetail . maxSelected
onClicked: destinationPane . paymentDetail . maxSelected = checked
}
2021-11-16 19:14:45 +01:00
}
2021-04-26 21:59:22 +02:00
}
2021-12-09 15:44:22 +01:00
Item {
id: warningArea
// BTC address entered warning.
visible: ( destination . addressType === Bitcoin . LegacySH || destination . addressType === Bitcoin . LegacyPKH )
2021-12-09 16:09:48 +01:00
&& paymentDetail . forceLegacyOk === false ;
2021-12-09 15:44:22 +01:00
width: parent . width - 40
height: warningColumn . height + 20 + destination . height
Rectangle {
anchors.fill: warningColumn
anchors.margins: - 10
color: warning . palette . window
border.width: 3
border.color: "red"
radius: 10
}
Flowee . ArrowPoint {
x: 20
anchors.bottom: warningColumn . top
anchors.bottomMargin: 5
rotation: - 90
color: "red"
}
Column {
id: warningColumn
x: 10
y: destination . height + 10
width: parent . width
spacing: 10
Label {
font.bold: true
font.pixelSize: warning . font . pixelSize * 1.2
text: qsTr ( "Warning" )
}
Label {
id: warning
width: parent . width
text: qsTr ( "This is a BTC address, which is an incompatible coin. Your funds could get lost and Flowee will have no way to recover them. Are you sure this is the right address?" )
wrapMode: Text . WrapAtWordBoundaryOrAnywhere
}
RowLayout {
width: parent . width
Item {
width: 1 ; height: 1
Layout.fillWidth: true
}
Button {
text: qsTr ( "Continue" )
2021-12-09 16:09:48 +01:00
onClicked: paymentDetail . forceLegacyOk = true
2021-12-09 15:44:22 +01:00
}
Button {
text: qsTr ( "Cancel" )
onClicked: {
destination . text = ""
destination . updateColor ( )
}
}
}
}
2021-04-26 21:59:22 +02:00
}
}
}
2020-06-11 17:41:18 +02:00
}
2021-11-19 11:20:01 +01:00
2021-11-23 16:46:37 +01:00
/*
* The input selector component.
*/
2021-11-19 11:20:01 +01:00
Component {
id: inputFields
Flowee . GroupBox {
2021-11-23 16:46:37 +01:00
id: inputsPane
collapsable: paymentDetail . collapsable
collapsed: paymentDetail . collapsed
2021-12-04 18:35:06 +01:00
onEffectiveCollapsedChanged: paymentDetail . collapsed = effectiveCollapsed
2021-11-23 16:46:37 +01:00
property QtObject paymentDetail: null
2021-11-30 13:50:40 +01:00
title: qsTr ( "Coin Selector" )
2021-11-23 16:46:37 +01:00
summary: qsTr ( "Selected %1 %2 in %3 coins" , "selected 2 BCH in 5 coins" , paymentDetail . selectedCount )
. arg ( Pay . priceToStringPretty ( paymentDetail . selectedValue ) )
. arg ( Pay . unitName )
. arg ( paymentDetail . selectedCount )
2021-11-27 09:26:28 +01:00
// make this tabs arrow-navigation go to our coinsListView.
Component.onCompleted: listViewKeyHandler . target = coinsListView
2021-11-24 17:41:41 +01:00
columns: 4
Label {
text: qsTr ( "Total" , "Number of coins" ) + ":"
}
Label {
text: coinsListView . count
Layout.fillWidth: true
}
Label {
text: qsTr ( "Needed" ) + ":"
}
Flowee . BitcoinAmountLabel {
id: neededAmountLabel
value: payment . paymentAmount
Layout.fillWidth: true
colorize: false
}
// next row
Label {
text: qsTr ( "Selected" ) + ":"
}
Label {
text: inputsPane . paymentDetail . selectedCount
Layout.fillWidth: true
}
Label {
text: qsTr ( "Value" ) + ":"
}
Flowee . BitcoinAmountLabel {
value: inputsPane . paymentDetail . selectedValue
Layout.fillWidth: true
colorize: false
}
2021-11-24 14:56:52 +01:00
2021-11-24 17:41:41 +01:00
// next row
ListView {
id: coinsListView
clip: true
Layout.columnSpan: 4
Layout.fillWidth: true
implicitHeight: {
var ch = contentHeight
2021-11-27 09:26:28 +01:00
var suggested = contentArea . height * 0.7
2021-11-24 17:41:41 +01:00
if ( ch < 0 || suggested < ch )
return suggested
return ch
2021-11-23 16:46:37 +01:00
}
2021-11-24 17:41:41 +01:00
model: inputsPane . paymentDetail . coins
2021-11-24 14:56:52 +01:00
2021-11-24 17:41:41 +01:00
property bool menuIsOpen: false
2021-11-23 16:46:37 +01:00
2021-11-24 17:41:41 +01:00
delegate: Rectangle {
width: ListView . view . width - 5
height: mainText . height + ageLabel . height + 12
color: index % 2 == 0 ? mainText.palette.alternateBase : mainText . palette . base
2021-11-23 16:46:37 +01:00
2021-11-24 17:41:41 +01:00
Rectangle {
id: lockedRect
color: Pay . useDarkSkin ? "#002558" : "#1a6ae2"
anchors.fill: parent
visible: locked // if the UTXO is user-locked
ToolTip {
delay: 600
text: qsTr ( "Locked coins will never be used for payments. Right-click for menu." )
2021-11-29 23:16:45 +01:00
visible: locked && rowMouseArea . containsMouse
2021-11-23 16:46:37 +01:00
}
}
2021-11-24 17:41:41 +01:00
CheckBox {
y: 6
id: selectedBox
checked: model . selected
visible: ! lockedRect . visible
}
Label {
id: mainText
y: 6
anchors.right: amountLabel . left
anchors.left: parent . left
anchors.leftMargin: 50
text: {
var fancy = cloakedAddress ;
if ( typeof fancy != "undefined" )
return fancy ;
return address ;
2021-11-23 16:46:37 +01:00
}
2021-11-24 17:41:41 +01:00
elide: Label . ElideRight
}
Flowee . BitcoinAmountLabel {
id: amountLabel
value: model . value
anchors.baseline: mainText . baseline
anchors.right: parent . right
2021-11-24 19:58:44 +01:00
// only HD wallets can use cash-fusion
anchors.rightMargin: portfolio . current . isHDWallet ? 30 : 0
2021-11-24 17:41:41 +01:00
}
Label {
id: ageLabel
text: qsTr ( "Age" ) + ": " + age
anchors.left: mainText . left
anchors.top: mainText . bottom
font.pixelSize: mainText . font . pixelSize * 0.8
}
MouseArea {
id: rowMouseArea
anchors.fill: parent
acceptedButtons: Qt . LeftButton | Qt . RightButton
hoverEnabled: locked
onClicked: {
// make it easy for the user to close a menu with either mouse
// button without instantly triggering another action.
if ( coinsListView . menuIsOpen ) {
coinsListView . menuIsOpen = false
return ;
}
if ( mouse . button == Qt . LeftButton ) {
var willCheck = ! selectedBox . checked
selectedBox . checked = willCheck
inputsPane . paymentDetail . setRowIncluded ( index , willCheck )
}
else {
coinsListView . menuIsOpen = true
// Make sure that the menu
// opens where we clicked.
mousePos . x = mouse . x
mousePos . y = mouse . y
lockingMenu . open ( ) ;
2021-11-23 16:46:37 +01:00
}
}
2021-11-24 17:41:41 +01:00
Item {
id: mousePos
width: 1 ; height: 1
Menu {
id: lockingMenu
MenuItem {
text: selectedBox . checked ? qsTr ( "Unselect All" ) : qsTr ( "Select All" )
onClicked: {
coinsListView . menuIsOpen = false
if ( selectedBox . checked )
inputsPane . paymentDetail . unselectAll ( ) ;
else
inputsPane . paymentDetail . selectAll ( ) ;
}
}
MenuItem {
text: locked ? qsTr ( "Unlock coin" ) : qsTr ( "Lock coin" )
onClicked: {
inputsPane . paymentDetail . setOutputLocked ( index , ! locked )
coinsListView . menuIsOpen = false
}
}
}
2021-11-23 16:46:37 +01:00
}
2021-11-24 17:41:41 +01:00
}
2021-12-14 13:19:29 +01:00
Flowee . CashFusionIcon {
2021-11-24 17:41:41 +01:00
id: fusedIcon
anchors.right: parent . right
anchors.verticalCenter: mainText . verticalCenter
2021-11-23 16:46:37 +01:00
}
}
}
2021-11-19 11:20:01 +01:00
}
}
2020-06-11 17:41:18 +02:00
}