qml: introduce InfoBanner allowing a clickable sticky message to stay below header and
implement ln utxo reserve check with warning. Clicking shows a suggestion to swap.
This commit is contained in:
committed by
ThomasV
parent
3fd64b60ab
commit
f76218ea83
@@ -447,6 +447,7 @@ Item {
|
|||||||
Connections {
|
Connections {
|
||||||
target: Daemon
|
target: Daemon
|
||||||
function onWalletLoaded() {
|
function onWalletLoaded() {
|
||||||
|
infobanner.hide() // start hidden when switching wallets
|
||||||
if (_intentUri) {
|
if (_intentUri) {
|
||||||
invoiceParser.recipient = _intentUri
|
invoiceParser.recipient = _intentUri
|
||||||
_intentUri = ''
|
_intentUri = ''
|
||||||
@@ -497,6 +498,27 @@ Item {
|
|||||||
})
|
})
|
||||||
dialog.open()
|
dialog.open()
|
||||||
}
|
}
|
||||||
|
function onBalanceChanged() {
|
||||||
|
// ln low reserve warning
|
||||||
|
if (Daemon.currentWallet.isLowReserve) {
|
||||||
|
var message = [
|
||||||
|
qsTr('You do not have enough on-chain funds to protect your Lightning channels.'),
|
||||||
|
qsTr('You should have at least %1 on-chain in order to be able to sweep channel outputs.').arg(Config.formatSats(Config.lnUtxoReserve) + ' ' + Config.baseUnit)
|
||||||
|
].join(' ')
|
||||||
|
infobanner.show(message, function() {
|
||||||
|
var dialog = app.messageDialog.createObject(app, {
|
||||||
|
text: message + '\n\n' + qsTr('Do you want to perform a swap?'),
|
||||||
|
yesno: true
|
||||||
|
})
|
||||||
|
dialog.accepted.connect(function() {
|
||||||
|
app.startSwap()
|
||||||
|
})
|
||||||
|
dialog.open()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
infobanner.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
|
|||||||
124
electrum/gui/qml/components/controls/InfoBanner.qml
Normal file
124
electrum/gui/qml/components/controls/InfoBanner.qml
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Controls.Material
|
||||||
|
import QtQuick.Controls.Material.impl
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string message
|
||||||
|
property bool autohide: false
|
||||||
|
property color color: constants.colorAlpha(constants.colorWarning, 0.1)
|
||||||
|
property url icon: Qt.resolvedUrl('../../../icons/warning.png')
|
||||||
|
property alias font: messageLabel.font
|
||||||
|
|
||||||
|
property bool _hide: true
|
||||||
|
property var _clicked_fn
|
||||||
|
|
||||||
|
clip:true
|
||||||
|
z: 1
|
||||||
|
layer.enabled: height > 0
|
||||||
|
layer.effect: ElevationEffect {
|
||||||
|
elevation: constants.paddingXLarge
|
||||||
|
fullWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
state: 'hidden'
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: 'hidden'; when: _hide
|
||||||
|
PropertyChanges { target: root; implicitHeight: 0 }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: 'expanded'; when: !_hide
|
||||||
|
PropertyChanges { target: root; implicitHeight: layout.implicitHeight }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
transitions: [
|
||||||
|
Transition {
|
||||||
|
from: 'hidden'; to: 'expanded'
|
||||||
|
SequentialAnimation {
|
||||||
|
PropertyAction { target: root; property: 'visible'; value: true }
|
||||||
|
NumberAnimation { target: root; properties: 'implicitHeight'; duration: 300; easing.type: Easing.OutQuad }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Transition {
|
||||||
|
from: 'expanded'; to: 'hidden'
|
||||||
|
SequentialAnimation {
|
||||||
|
NumberAnimation { target: root; properties: 'implicitHeight'; duration: 100; easing.type: Easing.OutQuad }
|
||||||
|
PropertyAction { target: root; property: 'visible'; value: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
function show(message, on_clicked=undefined) {
|
||||||
|
root.message = message
|
||||||
|
root._clicked_fn = on_clicked
|
||||||
|
root._hide = false
|
||||||
|
if (autohide)
|
||||||
|
closetimer.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide() {
|
||||||
|
closetimer.stop()
|
||||||
|
root._hide = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: rect
|
||||||
|
width: root.width
|
||||||
|
height: layout.height
|
||||||
|
color: root.color
|
||||||
|
anchors.bottom: root.bottom
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: layout
|
||||||
|
width: parent.width
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.margins: constants.paddingLarge
|
||||||
|
spacing: constants.paddingSmall
|
||||||
|
|
||||||
|
Image {
|
||||||
|
source: root.icon
|
||||||
|
Layout.preferredWidth: constants.iconSizeLarge
|
||||||
|
Layout.preferredHeight: constants.iconSizeLarge
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: messageLabel
|
||||||
|
Layout.fillWidth: true
|
||||||
|
font.pixelSize: constants.fontSizeSmall
|
||||||
|
color: Material.foreground
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
text: root.message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
Layout.preferredHeight: 2
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: Material.accentColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
if (root._clicked_fn)
|
||||||
|
root._clicked_fn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: closetimer
|
||||||
|
interval: 5000
|
||||||
|
repeat: false
|
||||||
|
onTriggered: _hide = true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -33,6 +33,7 @@ ApplicationWindow
|
|||||||
|
|
||||||
property alias stack: mainStackView
|
property alias stack: mainStackView
|
||||||
property alias keyboardFreeZone: _keyboardFreeZone
|
property alias keyboardFreeZone: _keyboardFreeZone
|
||||||
|
property alias infobanner: _infobanner
|
||||||
|
|
||||||
property variant activeDialogs: []
|
property variant activeDialogs: []
|
||||||
|
|
||||||
@@ -244,22 +245,34 @@ ApplicationWindow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StackView {
|
ColumnLayout {
|
||||||
id: mainStackView
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: _keyboardFreeZone.height - header.height
|
height: _keyboardFreeZone.height - header.height
|
||||||
initialItem: Component {
|
spacing: 0
|
||||||
WalletMainView {}
|
|
||||||
|
InfoBanner {
|
||||||
|
id: _infobanner
|
||||||
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRoot() {
|
StackView {
|
||||||
return mainStackView.get(0)
|
id: mainStackView
|
||||||
}
|
Layout.fillHeight: true
|
||||||
function pushOnRoot(item) {
|
Layout.fillWidth: true
|
||||||
if (mainStackView.depth > 1) {
|
|
||||||
mainStackView.replace(mainStackView.get(1), item)
|
initialItem: Component {
|
||||||
} else {
|
WalletMainView {}
|
||||||
mainStackView.push(item)
|
}
|
||||||
|
|
||||||
|
function getRoot() {
|
||||||
|
return mainStackView.get(0)
|
||||||
|
}
|
||||||
|
function pushOnRoot(item) {
|
||||||
|
if (mainStackView.depth > 1) {
|
||||||
|
mainStackView.replace(mainStackView.get(1), item)
|
||||||
|
} else {
|
||||||
|
mainStackView.push(item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -291,6 +291,12 @@ class QEConfig(AuthMixin, QObject):
|
|||||||
self.config.SWAPSERVER_NPUB = swapserver_npub
|
self.config.SWAPSERVER_NPUB = swapserver_npub
|
||||||
self.swapServerNPubChanged.emit()
|
self.swapServerNPubChanged.emit()
|
||||||
|
|
||||||
|
lnUtxoReserveChanged = pyqtSignal()
|
||||||
|
@pyqtProperty(QEAmount, notify=lnUtxoReserveChanged)
|
||||||
|
def lnUtxoReserve(self):
|
||||||
|
self._lnutxoreserve = QEAmount(amount_sat=self.config.LN_UTXO_RESERVE)
|
||||||
|
return self._lnutxoreserve
|
||||||
|
|
||||||
@pyqtSlot('qint64', result=str)
|
@pyqtSlot('qint64', result=str)
|
||||||
@pyqtSlot(QEAmount, result=str)
|
@pyqtSlot(QEAmount, result=str)
|
||||||
def formatSatsForEditing(self, satoshis):
|
def formatSatsForEditing(self, satoshis):
|
||||||
|
|||||||
@@ -513,6 +513,10 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
|||||||
self._lightningcanreceive.satsInt = int(self.wallet.lnworker.num_sats_can_receive())
|
self._lightningcanreceive.satsInt = int(self.wallet.lnworker.num_sats_can_receive())
|
||||||
return self._lightningcanreceive
|
return self._lightningcanreceive
|
||||||
|
|
||||||
|
@pyqtProperty(bool, notify=balanceChanged)
|
||||||
|
def isLowReserve(self):
|
||||||
|
return self.wallet.is_low_reserve()
|
||||||
|
|
||||||
@pyqtProperty(QEAmount, notify=dataChanged)
|
@pyqtProperty(QEAmount, notify=dataChanged)
|
||||||
def minChannelFunding(self):
|
def minChannelFunding(self):
|
||||||
return self._minchannelfunding
|
return self._minchannelfunding
|
||||||
|
|||||||
Reference in New Issue
Block a user