1
0

Merge pull request #8845 from accumulator/feepicker

qml: consolidate fee slider ui in various places to a single FeePicker control
This commit is contained in:
accumulator
2024-02-16 13:01:34 +01:00
committed by GitHub
6 changed files with 299 additions and 343 deletions

View File

@@ -30,7 +30,7 @@ ElDialog {
function updateAmountText() { function updateAmountText() {
btcValue.text = Config.formatSats(finalizer.effectiveAmount, false) btcValue.text = Config.formatSats(finalizer.effectiveAmount, false)
fiatValue.text = Daemon.fx.enabled fiatValue.text = Daemon.fx.enabled
? '(' + Daemon.fx.fiatValue(finalizer.effectiveAmount, false) + ' ' + Daemon.fx.fiatCurrency + ')' ? Daemon.fx.fiatValue(finalizer.effectiveAmount, false)
: '' : ''
} }
@@ -57,119 +57,82 @@ ElDialog {
Label { Label {
id: amountLabel id: amountLabel
Layout.fillWidth: true Layout.columnSpan: 2
Layout.minimumWidth: implicitWidth
text: qsTr('Amount to send') text: qsTr('Amount to send')
color: Material.accentColor color: Material.accentColor
} }
RowLayout {
Layout.fillWidth: true
Label {
id: btcValue
font.bold: true
font.family: FixedFont
}
Label { TextHighlightPane {
text: Config.baseUnit
color: Material.accentColor
}
Label {
id: fiatValue
Layout.fillWidth: true
font.pixelSize: constants.fontSizeMedium
}
Component.onCompleted: updateAmountText()
Connections {
target: finalizer
function onEffectiveAmountChanged() {
updateAmountText()
}
}
}
Label {
text: qsTr('Mining fee')
color: Material.accentColor
}
FormattedAmount {
amount: finalizer.fee
}
Label {
visible: !finalizer.extraFee.isEmpty
text: qsTr('Extra fee')
color: Material.accentColor
}
FormattedAmount {
visible: !finalizer.extraFee.isEmpty
amount: finalizer.extraFee
}
Label {
text: qsTr('Fee rate')
color: Material.accentColor
}
RowLayout {
Label {
id: feeRate
text: finalizer.feeRate
font.family: FixedFont
}
Label {
text: UI_UNIT_NAME.FEERATE_SAT_PER_VB
color: Material.accentColor
}
}
Label {
text: qsTr('Target')
color: Material.accentColor
}
Label {
id: targetdesc
text: finalizer.target
}
RowLayout {
Layout.columnSpan: 2 Layout.columnSpan: 2
Layout.fillWidth: true Layout.fillWidth: true
GridLayout {
Slider { columns: 2
id: feeslider Label {
Layout.fillWidth: true id: btcValue
leftPadding: constants.paddingMedium Layout.alignment: Qt.AlignRight
font.pixelSize: constants.fontSizeXLarge
snapMode: Slider.SnapOnRelease font.family: FixedFont
stepSize: 1 font.bold: true
from: 0
to: finalizer.sliderSteps
onValueChanged: {
if (activeFocus)
finalizer.sliderPos = value
} }
Component.onCompleted: {
value = finalizer.sliderPos Label {
Layout.fillWidth: true
text: Config.baseUnit
color: Material.accentColor
font.pixelSize: constants.fontSizeXLarge
} }
Label {
id: fiatValue
Layout.alignment: Qt.AlignRight
visible: Daemon.fx.enabled
font.pixelSize: constants.fontSizeMedium
color: constants.mutedForeground
}
Label {
Layout.fillWidth: true
visible: Daemon.fx.enabled
text: Daemon.fx.fiatCurrency
font.pixelSize: constants.fontSizeMedium
color: constants.mutedForeground
}
Component.onCompleted: updateAmountText()
Connections { Connections {
target: finalizer target: finalizer
function onSliderPosChanged() { function onEffectiveAmountChanged() {
feeslider.value = finalizer.sliderPos updateAmountText()
} }
} }
} }
}
FeeMethodComboBox { Label {
id: target Layout.columnSpan: 2
feeslider: finalizer text: qsTr('Fee')
color: Material.accentColor
}
TextHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
height: feepicker.height
FeePicker {
id: feepicker
width: parent.width
finalizer: dialog.finalizer
Label {
visible: !finalizer.extraFee.isEmpty
text: qsTr('Extra fee')
color: Material.accentColor
}
FormattedAmount {
visible: !finalizer.extraFee.isEmpty
amount: finalizer.extraFee
}
} }
} }

View File

@@ -56,113 +56,101 @@ ElDialog {
} }
Label { Label {
Layout.preferredWidth: 1
Layout.fillWidth: true
text: qsTr('Total size')
color: Material.accentColor
}
Label {
Layout.preferredWidth: 1
Layout.fillWidth: true
text: cpfpfeebumper.totalSize + ' ' + UI_UNIT_NAME.TXSIZE_VBYTES
}
Label {
text: qsTr('Input amount')
color: Material.accentColor
}
FormattedAmount {
amount: cpfpfeebumper.inputAmount
}
Label {
text: qsTr('Output amount')
color: Material.accentColor
}
FormattedAmount {
amount: cpfpfeebumper.outputAmount
valid: cpfpfeebumper.valid
}
RowLayout {
Layout.columnSpan: 2 Layout.columnSpan: 2
Slider { Layout.topMargin: constants.paddingSmall
id: feeslider text: qsTr('Child tx fee')
leftPadding: constants.paddingMedium color: Material.accentColor
snapMode: Slider.SnapOnRelease }
stepSize: 1
from: 0 TextHighlightPane {
to: cpfpfeebumper.sliderSteps Layout.columnSpan: 2
onValueChanged: { Layout.fillWidth: true
if (activeFocus) height: feepicker_childinfo.height
cpfpfeebumper.sliderPos = value
FeePicker {
id: feepicker_childinfo
width: parent.width
finalizer: dialog.cpfpfeebumper
targetLabel: qsTr('Target total')
feeLabel: qsTr('Fee for child')
feeRateLabel: qsTr('Fee rate for child')
showPicker: false
}
}
Label {
Layout.columnSpan: 2
Layout.topMargin: constants.paddingSmall
text: qsTr('Total')
color: Material.accentColor
}
TextHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
GridLayout {
width: parent.width
columns: 2
Label {
Layout.preferredWidth: 1
Layout.fillWidth: true
text: qsTr('Total size')
color: Material.accentColor
} }
Component.onCompleted: {
value = cpfpfeebumper.sliderPos Label {
Layout.preferredWidth: 2
Layout.fillWidth: true
text: cpfpfeebumper.valid
? cpfpfeebumper.totalSize + ' ' + UI_UNIT_NAME.TXSIZE_VBYTES
: ''
} }
Connections {
target: cpfpfeebumper Label {
function onSliderPosChanged() { Layout.preferredWidth: 1
feeslider.value = cpfpfeebumper.sliderPos Layout.fillWidth: true
text: qsTr('Total fee')
color: Material.accentColor
}
FormattedAmount {
Layout.preferredWidth: 2
Layout.fillWidth: true
amount: cpfpfeebumper.totalFee
valid: cpfpfeebumper.valid
}
Label {
Layout.preferredWidth: 1
Layout.fillWidth: true
text: qsTr('Total fee rate')
color: Material.accentColor
}
RowLayout {
Layout.preferredWidth: 2
Layout.fillWidth: true
Label {
text: cpfpfeebumper.valid ? cpfpfeebumper.totalFeeRate : ''
font.family: FixedFont
}
Label {
visible: cpfpfeebumper.valid
text: UI_UNIT_NAME.FEERATE_SAT_PER_VB
color: Material.accentColor
} }
} }
}
FeeMethodComboBox { FeePicker {
id: feemethod id: feepicker
feeslider: cpfpfeebumper Layout.columnSpan: 2
} Layout.fillWidth: true
} finalizer: dialog.cpfpfeebumper
showTxInfo: false
Label { }
visible: feemethod.currentValue
text: qsTr('Target')
color: Material.accentColor
}
Label {
visible: feemethod.currentValue
text: cpfpfeebumper.target
}
Label {
text: qsTr('Fee for child')
color: Material.accentColor
}
FormattedAmount {
amount: cpfpfeebumper.feeForChild
valid: cpfpfeebumper.valid
}
Label {
text: qsTr('Total fee')
color: Material.accentColor
}
FormattedAmount {
amount: cpfpfeebumper.totalFee
valid: cpfpfeebumper.valid
}
Label {
text: qsTr('Total fee rate')
color: Material.accentColor
}
RowLayout {
Label {
text: cpfpfeebumper.valid ? cpfpfeebumper.totalFeeRate : ''
font.family: FixedFont
}
Label {
visible: cpfpfeebumper.valid
text: UI_UNIT_NAME.FEERATE_SAT_PER_VB
color: Material.accentColor
} }
} }

View File

@@ -49,17 +49,12 @@ ElDialog {
} }
Label { Label {
Layout.preferredWidth: 1
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr('Method') text: qsTr('Method')
color: Material.accentColor color: Material.accentColor
} }
RowLayout { RowLayout {
Layout.preferredWidth: 1
Layout.fillWidth: true
Layout.minimumWidth: bumpMethodComboBox.implicitWidth
ElComboBox { ElComboBox {
id: bumpMethodComboBox id: bumpMethodComboBox
@@ -79,15 +74,11 @@ ElDialog {
} }
Label { Label {
Layout.preferredWidth: 1
Layout.fillWidth: true
text: qsTr('Old fee') text: qsTr('Old fee')
color: Material.accentColor color: Material.accentColor
} }
FormattedAmount { FormattedAmount {
Layout.preferredWidth: 1
Layout.fillWidth: true
amount: rbffeebumper.oldfee amount: rbffeebumper.oldfee
} }
@@ -110,71 +101,22 @@ ElDialog {
} }
Label { Label {
Layout.columnSpan: 2
Layout.topMargin: constants.paddingSmall
text: qsTr('New fee') text: qsTr('New fee')
color: Material.accentColor color: Material.accentColor
} }
FormattedAmount { TextHighlightPane {
amount: rbffeebumper.fee
valid: rbffeebumper.valid
}
Label {
text: qsTr('New fee rate')
color: Material.accentColor
}
RowLayout {
Label {
id: feeRate
text: rbffeebumper.valid ? rbffeebumper.feeRate : ''
font.family: FixedFont
}
Label {
visible: rbffeebumper.valid
text: UI_UNIT_NAME.FEERATE_SAT_PER_VB
color: Material.accentColor
}
}
Label {
text: qsTr('Target')
color: Material.accentColor
}
Label {
id: targetdesc
text: rbffeebumper.target
}
RowLayout {
Layout.columnSpan: 2 Layout.columnSpan: 2
Slider { Layout.fillWidth: true
id: feeslider height: feepicker.height
leftPadding: constants.paddingMedium
snapMode: Slider.SnapOnRelease FeePicker {
stepSize: 1 id: feepicker
from: 0 width: parent.width
to: rbffeebumper.sliderSteps finalizer: dialog.rbffeebumper
onValueChanged: {
if (activeFocus)
rbffeebumper.sliderPos = value
}
Component.onCompleted: {
value = rbffeebumper.sliderPos
}
Connections {
target: rbffeebumper
function onSliderPosChanged() {
feeslider.value = rbffeebumper.sliderPos
}
}
}
FeeMethodComboBox {
id: target
feeslider: rbffeebumper
} }
} }

View File

@@ -73,71 +73,22 @@ ElDialog {
} }
Label { Label {
Layout.columnSpan: 2
Layout.topMargin: constants.paddingSmall
text: qsTr('New fee') text: qsTr('New fee')
color: Material.accentColor color: Material.accentColor
} }
FormattedAmount { TextHighlightPane {
amount: txcanceller.fee
valid: txcanceller.valid
}
Label {
text: qsTr('New fee rate')
color: Material.accentColor
}
RowLayout {
Label {
id: feeRate
text: txcanceller.valid ? txcanceller.feeRate : ''
font.family: FixedFont
}
Label {
visible: txcanceller.valid
text: UI_UNIT_NAME.FEERATE_SAT_PER_VB
color: Material.accentColor
}
}
Label {
text: qsTr('Target')
color: Material.accentColor
}
Label {
id: targetdesc
text: txcanceller.target
}
RowLayout {
Layout.columnSpan: 2 Layout.columnSpan: 2
Slider { Layout.fillWidth: true
id: feeslider height: feepicker.height
leftPadding: constants.paddingMedium
snapMode: Slider.SnapOnRelease FeePicker {
stepSize: 1 id: feepicker
from: 0 width: parent.width
to: txcanceller.sliderSteps finalizer: dialog.txcanceller
onValueChanged: {
if (activeFocus)
txcanceller.sliderPos = value
}
Component.onCompleted: {
value = txcanceller.sliderPos
}
Connections {
target: txcanceller
function onSliderPosChanged() {
feeslider.value = txcanceller.sliderPos
}
}
}
FeeMethodComboBox {
id: target
feeslider: txcanceller
} }
} }

View File

@@ -0,0 +1,121 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import QtQuick.Controls.Material
import org.electrum 1.0
Item {
id: root
required property QtObject finalizer
default property alias additionalItems: rootLayout.children
property string targetLabel: qsTr('Target')
property string feeLabel: qsTr('Mining fee')
property string feeRateLabel: qsTr('Fee rate')
property bool showTxInfo: true
property bool showPicker: true
implicitHeight: rootLayout.height
GridLayout {
id: rootLayout
width: parent.width
columns: 2
Label {
Layout.fillWidth: true
Layout.preferredWidth: 1
text: feeLabel
color: Material.accentColor
visible: showTxInfo
}
FormattedAmount {
Layout.fillWidth: true
Layout.preferredWidth: 2
amount: finalizer.fee
valid: finalizer.valid
visible: showTxInfo
}
Label {
Layout.fillWidth: true
Layout.preferredWidth: 1
text: feeRateLabel
color: Material.accentColor
visible: showTxInfo
}
RowLayout {
Layout.fillWidth: true
Layout.preferredWidth: 2
visible: showTxInfo
Label {
id: feeRate
text: finalizer.valid ? finalizer.feeRate : ''
font.family: FixedFont
}
Label {
Layout.fillWidth: true
text: finalizer.valid ? UI_UNIT_NAME.FEERATE_SAT_PER_VBYTE : ''
color: Material.accentColor
}
}
Label {
Layout.fillWidth: true
Layout.preferredWidth: 1
text: targetLabel
color: Material.accentColor
visible: showPicker
}
Label {
Layout.fillWidth: true
Layout.preferredWidth: 2
text: finalizer.target
visible: showPicker
}
RowLayout {
Layout.columnSpan: 2
Layout.fillWidth: true
visible: showPicker
Slider {
id: feeslider
Layout.fillWidth: true
leftPadding: constants.paddingMedium
snapMode: Slider.SnapOnRelease
stepSize: 1
from: 0
to: finalizer.sliderSteps
onValueChanged: {
if (activeFocus)
finalizer.sliderPos = value
}
Component.onCompleted: {
value = finalizer.sliderPos
}
Connections {
target: finalizer
function onSliderPosChanged() {
feeslider.value = finalizer.sliderPos
}
}
}
FeeMethodComboBox {
id: target
feeslider: finalizer
}
}
}
}

View File

@@ -7,7 +7,7 @@ from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from electrum.logging import get_logger from electrum.logging import get_logger
from electrum.i18n import _ from electrum.i18n import _
from electrum.transaction import PartialTxOutput, PartialTransaction, Transaction, TxOutpoint from electrum.transaction import PartialTxOutput, PartialTransaction, Transaction, TxOutpoint
from electrum.util import NotEnoughFunds, profiler from electrum.util import NotEnoughFunds, profiler, quantize_feerate
from electrum.wallet import CannotBumpFee, CannotDoubleSpendTx, CannotCPFP, BumpFeeStrategy from electrum.wallet import CannotBumpFee, CannotDoubleSpendTx, CannotCPFP, BumpFeeStrategy
from electrum.plugin import run_hook from electrum.plugin import run_hook
@@ -719,7 +719,6 @@ class QETxCpfpFeeBumper(TxFeeSlider, TxMonMixin):
self._input_amount = QEAmount() self._input_amount = QEAmount()
self._output_amount = QEAmount() self._output_amount = QEAmount()
self._fee_for_child = QEAmount()
self._total_fee = QEAmount() self._total_fee = QEAmount()
self._total_fee_rate = 0 self._total_fee_rate = 0
self._total_size = 0 self._total_size = 0
@@ -754,17 +753,6 @@ class QETxCpfpFeeBumper(TxFeeSlider, TxMonMixin):
self._total_fee_rate = totalfeerate self._total_fee_rate = totalfeerate
self.totalFeeRateChanged.emit() self.totalFeeRateChanged.emit()
feeForChildChanged = pyqtSignal()
@pyqtProperty(QEAmount, notify=feeForChildChanged)
def feeForChild(self):
return self._fee_for_child
@feeForChild.setter
def feeForChild(self, feeforchild):
if self._fee_for_child != feeforchild:
self._fee_for_child.copyFrom(feeforchild)
self.feeForChildChanged.emit()
inputAmountChanged = pyqtSignal() inputAmountChanged = pyqtSignal()
@pyqtProperty(QEAmount, notify=inputAmountChanged) @pyqtProperty(QEAmount, notify=inputAmountChanged)
def inputAmount(self): def inputAmount(self):
@@ -850,12 +838,12 @@ class QETxCpfpFeeBumper(TxFeeSlider, TxMonMixin):
comb_fee = fee + self._parent_fee comb_fee = fee + self._parent_fee
comb_feerate = comb_fee / self._total_size comb_feerate = comb_fee / self._total_size
self._fee_for_child.satsInt = fee self._fee.satsInt = fee
self._output_amount.satsInt = self._max_fee - fee self._output_amount.satsInt = self._max_fee - fee
self.outputAmountChanged.emit() self.outputAmountChanged.emit()
self._total_fee.satsInt = fee + self._parent_fee self._total_fee.satsInt = fee + self._parent_fee
self._total_fee_rate = f'{comb_feerate:.1f}' self._total_fee_rate = str(quantize_feerate(comb_feerate))
try: try:
self._new_tx = self._wallet.wallet.cpfp(self._parent_tx, fee) self._new_tx = self._wallet.wallet.cpfp(self._parent_tx, fee)
@@ -864,6 +852,9 @@ class QETxCpfpFeeBumper(TxFeeSlider, TxMonMixin):
self.warning = str(e) self.warning = str(e)
return return
child_feerate = fee / self._new_tx.estimated_size()
self.feeRate = str(quantize_feerate(child_feerate))
self.update_inputs_from_tx(self._new_tx) self.update_inputs_from_tx(self._new_tx)
self.update_outputs_from_tx(self._new_tx) self.update_outputs_from_tx(self._new_tx)