add can send/can receive (totals and per-channel), fiat, channel ratio indicator
This commit is contained in:
@@ -22,7 +22,8 @@ Pane {
|
|||||||
|
|
||||||
Label {
|
Label {
|
||||||
Layout.columnSpan: 2
|
Layout.columnSpan: 2
|
||||||
text: ''
|
text: qsTr('You have %1 open channels').arg(listview.count)
|
||||||
|
color: Material.accentColor
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
@@ -30,8 +31,20 @@ Pane {
|
|||||||
color: Material.accentColor
|
color: Material.accentColor
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
RowLayout {
|
||||||
text: ''
|
Layout.fillWidth: true
|
||||||
|
Label {
|
||||||
|
text: Config.formatSats(Daemon.currentWallet.lightningCanSend)
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: Config.baseUnit
|
||||||
|
color: Material.accentColor
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: Daemon.fx.enabled
|
||||||
|
? '(' + Daemon.fx.fiatValue(Daemon.currentWallet.lightningCanSend) + ' ' + Daemon.fx.fiatCurrency + ')'
|
||||||
|
: ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
@@ -39,20 +52,23 @@ Pane {
|
|||||||
color: Material.accentColor
|
color: Material.accentColor
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
|
||||||
text: ''
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.columnSpan: 2
|
Layout.fillWidth: true
|
||||||
|
Label {
|
||||||
Button {
|
text: Config.formatSats(Daemon.currentWallet.lightningCanReceive)
|
||||||
text: qsTr('Open Channel')
|
}
|
||||||
onClicked: app.stack.push(Qt.resolvedUrl('OpenChannel.qml'))
|
Label {
|
||||||
|
text: Config.baseUnit
|
||||||
|
color: Material.accentColor
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: Daemon.fx.enabled
|
||||||
|
? '(' + Daemon.fx.fiatValue(Daemon.currentWallet.lightningCanReceive) + ' ' + Daemon.fx.fiatCurrency + ')'
|
||||||
|
: ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Frame {
|
Frame {
|
||||||
id: channelsFrame
|
id: channelsFrame
|
||||||
@@ -92,7 +108,7 @@ Pane {
|
|||||||
model: Daemon.currentWallet.channelModel
|
model: Daemon.currentWallet.channelModel
|
||||||
|
|
||||||
delegate: ChannelDelegate {
|
delegate: ChannelDelegate {
|
||||||
highlighted: ListView.isCurrentItem
|
//highlighted: ListView.isCurrentItem
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollIndicator.vertical: ScrollIndicator { }
|
ScrollIndicator.vertical: ScrollIndicator { }
|
||||||
@@ -100,6 +116,15 @@ Pane {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
text: qsTr('Open Channel')
|
||||||
|
onClicked: app.stack.push(Qt.resolvedUrl('OpenChannel.qml'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,4 +27,8 @@ Item {
|
|||||||
property color colorDebit: "#ffff8080"
|
property color colorDebit: "#ffff8080"
|
||||||
property color mutedForeground: 'gray' //Qt.lighter(Material.background, 2)
|
property color mutedForeground: 'gray' //Qt.lighter(Material.background, 2)
|
||||||
property color colorMine: "yellow"
|
property color colorMine: "yellow"
|
||||||
|
|
||||||
|
property color colorLightningLocal: "blue"
|
||||||
|
property color colorLightningRemote: "yellow"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ ItemDelegate {
|
|||||||
id: walleticon
|
id: walleticon
|
||||||
source: "../../../icons/lightning.png"
|
source: "../../../icons/lightning.png"
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
Layout.rowSpan: 2
|
Layout.rowSpan: 3
|
||||||
Layout.preferredWidth: constants.iconSizeLarge
|
Layout.preferredWidth: constants.iconSizeLarge
|
||||||
Layout.preferredHeight: constants.iconSizeLarge
|
Layout.preferredHeight: constants.iconSizeLarge
|
||||||
}
|
}
|
||||||
@@ -58,17 +58,57 @@ ItemDelegate {
|
|||||||
Label {
|
Label {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: model.short_cid
|
text: model.short_cid
|
||||||
|
color: constants.mutedForeground
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: Config.formatSats(model.capacity)
|
text: Config.formatSats(model.capacity)
|
||||||
|
font.family: FixedFont
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: Config.baseUnit
|
text: Config.baseUnit
|
||||||
|
color: Material.accentColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: chviz
|
||||||
|
Layout.fillWidth: true
|
||||||
|
height: 10
|
||||||
|
onWidthChanged: {
|
||||||
|
var cap = model.capacity.satsInt * 1000
|
||||||
|
var twocap = cap * 2
|
||||||
|
b1.width = width * (cap - model.can_send.msatsInt) / twocap
|
||||||
|
b2.width = width * model.can_send.msatsInt / twocap
|
||||||
|
b3.width = width * model.can_receive.msatsInt / twocap
|
||||||
|
b4.width = width * (cap - model.can_receive.msatsInt) / twocap
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
id: b1
|
||||||
|
x: 0
|
||||||
|
height: parent.height
|
||||||
|
color: 'gray'
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
id: b2
|
||||||
|
anchors.left: b1.right
|
||||||
|
height: parent.height
|
||||||
|
color: constants.colorLightningLocal
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
id: b3
|
||||||
|
anchors.left: b2.right
|
||||||
|
height: parent.height
|
||||||
|
color: constants.colorLightningRemote
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
id: b4
|
||||||
|
anchors.left: b3.right
|
||||||
|
height: parent.height
|
||||||
|
color: 'gray'
|
||||||
|
}
|
||||||
|
}
|
||||||
Rectangle {
|
Rectangle {
|
||||||
Layout.columnSpan: 2
|
Layout.columnSpan: 2
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|||||||
@@ -5,24 +5,11 @@ from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
|
|||||||
|
|
||||||
from electrum.logging import get_logger
|
from electrum.logging import get_logger
|
||||||
from electrum.util import Satoshis, register_callback
|
from electrum.util import Satoshis, register_callback
|
||||||
|
from electrum.lnutil import LOCAL, REMOTE
|
||||||
|
|
||||||
from .qetypes import QEAmount
|
from .qetypes import QEAmount
|
||||||
|
|
||||||
class QEChannelListModel(QAbstractListModel):
|
class QEChannelListModel(QAbstractListModel):
|
||||||
def __init__(self, wallet, parent=None):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.wallet = wallet
|
|
||||||
self.init_model()
|
|
||||||
|
|
||||||
interests = ['channel', 'channels_updated', 'gossip_peers',
|
|
||||||
'ln_gossip_sync_progress', 'unknown_channels',
|
|
||||||
'channel_db', 'gossip_db_loaded']
|
|
||||||
# To avoid leaking references to "self" that prevent the
|
|
||||||
# window from being GC-ed when closed, callbacks should be
|
|
||||||
# methods of this class only, and specifically not be
|
|
||||||
# partials, lambdas or methods of subobjects. Hence...
|
|
||||||
register_callback(self.on_network, interests)
|
|
||||||
|
|
||||||
_logger = get_logger(__name__)
|
_logger = get_logger(__name__)
|
||||||
|
|
||||||
# define listmodel rolemap
|
# define listmodel rolemap
|
||||||
@@ -33,6 +20,43 @@ class QEChannelListModel(QAbstractListModel):
|
|||||||
_ROLE_MAP = dict(zip(_ROLE_KEYS, [bytearray(x.encode()) for x in _ROLE_NAMES]))
|
_ROLE_MAP = dict(zip(_ROLE_KEYS, [bytearray(x.encode()) for x in _ROLE_NAMES]))
|
||||||
_ROLE_RMAP = dict(zip(_ROLE_NAMES, _ROLE_KEYS))
|
_ROLE_RMAP = dict(zip(_ROLE_NAMES, _ROLE_KEYS))
|
||||||
|
|
||||||
|
_network_signal = pyqtSignal(str, object)
|
||||||
|
|
||||||
|
def __init__(self, wallet, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.wallet = wallet
|
||||||
|
self.init_model()
|
||||||
|
|
||||||
|
self._network_signal.connect(self.on_network_qt)
|
||||||
|
interests = ['channel', 'channels_updated', 'gossip_peers',
|
||||||
|
'ln_gossip_sync_progress', 'unknown_channels',
|
||||||
|
'channel_db', 'gossip_db_loaded']
|
||||||
|
# To avoid leaking references to "self" that prevent the
|
||||||
|
# window from being GC-ed when closed, callbacks should be
|
||||||
|
# methods of this class only, and specifically not be
|
||||||
|
# partials, lambdas or methods of subobjects. Hence...
|
||||||
|
register_callback(self.on_network, interests)
|
||||||
|
|
||||||
|
def on_network(self, event, *args):
|
||||||
|
if event == 'channel':
|
||||||
|
# Handle in GUI thread (_network_signal -> on_network_qt)
|
||||||
|
self._network_signal.emit(event, args)
|
||||||
|
else:
|
||||||
|
self.on_network_qt(event, args)
|
||||||
|
|
||||||
|
def on_network_qt(self, event, args=None):
|
||||||
|
if event == 'channel':
|
||||||
|
wallet, channel = args
|
||||||
|
if wallet == self.wallet:
|
||||||
|
self.on_channel_updated(channel)
|
||||||
|
elif event == 'channels_updated':
|
||||||
|
wallet, = args
|
||||||
|
if wallet == self.wallet:
|
||||||
|
self.init_model() # TODO: remove/add less crude than full re-init
|
||||||
|
else:
|
||||||
|
self._logger.debug('unhandled event %s: %s' % (event, repr(args)))
|
||||||
|
|
||||||
|
|
||||||
def rowCount(self, index):
|
def rowCount(self, index):
|
||||||
return len(self.channels)
|
return len(self.channels)
|
||||||
|
|
||||||
@@ -62,6 +86,8 @@ class QEChannelListModel(QAbstractListModel):
|
|||||||
item['short_cid'] = lnc.short_id_for_GUI()
|
item['short_cid'] = lnc.short_id_for_GUI()
|
||||||
item['state'] = lnc.get_state_for_GUI()
|
item['state'] = lnc.get_state_for_GUI()
|
||||||
item['capacity'] = QEAmount(amount_sat=lnc.get_capacity())
|
item['capacity'] = QEAmount(amount_sat=lnc.get_capacity())
|
||||||
|
item['can_send'] = QEAmount(amount_msat=lnc.available_to_spend(LOCAL))
|
||||||
|
item['can_receive'] = QEAmount(amount_msat=lnc.available_to_spend(REMOTE))
|
||||||
self._logger.debug(repr(item))
|
self._logger.debug(repr(item))
|
||||||
return item
|
return item
|
||||||
|
|
||||||
@@ -85,18 +111,6 @@ class QEChannelListModel(QAbstractListModel):
|
|||||||
self.channels = channels
|
self.channels = channels
|
||||||
self.endInsertRows()
|
self.endInsertRows()
|
||||||
|
|
||||||
def on_network(self, event, *args):
|
|
||||||
if event == 'channel':
|
|
||||||
wallet, channel = args
|
|
||||||
if wallet == self.wallet:
|
|
||||||
self.on_channel_updated(channel)
|
|
||||||
elif event == 'channels_updated':
|
|
||||||
wallet, = args
|
|
||||||
if wallet == self.wallet:
|
|
||||||
self.init_model() # TODO: remove/add less crude than full re-init
|
|
||||||
else:
|
|
||||||
self._logger.debug('unhandled event %s: %s' % (event, repr(args)))
|
|
||||||
|
|
||||||
def on_channel_updated(self, channel):
|
def on_channel_updated(self, channel):
|
||||||
i = 0
|
i = 0
|
||||||
for c in self.channels:
|
for c in self.channels:
|
||||||
|
|||||||
@@ -121,9 +121,14 @@ class QEWallet(QObject):
|
|||||||
if wallet == self.wallet:
|
if wallet == self.wallet:
|
||||||
self._logger.debug('wallet %s updated' % str(wallet))
|
self._logger.debug('wallet %s updated' % str(wallet))
|
||||||
self.balanceChanged.emit()
|
self.balanceChanged.emit()
|
||||||
elif event in ['channel','channels_updated']:
|
elif event == 'channel':
|
||||||
# TODO update balance/can-spend etc
|
wallet, channel = args
|
||||||
pass
|
if wallet == self.wallet:
|
||||||
|
self.balanceChanged.emit()
|
||||||
|
elif event == 'channels_updated':
|
||||||
|
wallet, = args
|
||||||
|
if wallet == self.wallet:
|
||||||
|
self.balanceChanged.emit()
|
||||||
else:
|
else:
|
||||||
self._logger.debug('unhandled event: %s %s' % (event, str(args)))
|
self._logger.debug('unhandled event: %s %s' % (event, str(args)))
|
||||||
|
|
||||||
@@ -279,6 +284,21 @@ class QEWallet(QObject):
|
|||||||
self._lightningbalance = QEAmount(amount_sat=self.wallet.lnworker.get_balance())
|
self._lightningbalance = QEAmount(amount_sat=self.wallet.lnworker.get_balance())
|
||||||
return self._lightningbalance
|
return self._lightningbalance
|
||||||
|
|
||||||
|
@pyqtProperty(QEAmount, notify=balanceChanged)
|
||||||
|
def lightningCanSend(self):
|
||||||
|
if not self.isLightning:
|
||||||
|
return QEAmount()
|
||||||
|
self._lightningcansend = QEAmount(amount_sat=self.wallet.lnworker.num_sats_can_send())
|
||||||
|
return self._lightningcansend
|
||||||
|
|
||||||
|
@pyqtProperty(QEAmount, notify=balanceChanged)
|
||||||
|
def lightningCanReceive(self):
|
||||||
|
if not self.isLightning:
|
||||||
|
return QEAmount()
|
||||||
|
self._lightningcanreceive = QEAmount(amount_sat=self.wallet.lnworker.num_sats_can_receive())
|
||||||
|
return self._lightningcanreceive
|
||||||
|
|
||||||
|
|
||||||
@pyqtSlot('QString', int, int, bool)
|
@pyqtSlot('QString', int, int, bool)
|
||||||
def send_onchain(self, address, amount, fee=None, rbf=False):
|
def send_onchain(self, address, amount, fee=None, rbf=False):
|
||||||
self._logger.info('send_onchain: %s %d' % (address,amount))
|
self._logger.info('send_onchain: %s %d' % (address,amount))
|
||||||
|
|||||||
Reference in New Issue
Block a user