Browse Source

add can send/can receive (totals and per-channel), fiat, channel ratio indicator

patch-4
Sander van Grieken 3 years ago
parent
commit
c3db1e5cc1
  1. 53
      electrum/gui/qml/components/Channels.qml
  2. 4
      electrum/gui/qml/components/Constants.qml
  3. 42
      electrum/gui/qml/components/controls/ChannelDelegate.qml
  4. 54
      electrum/gui/qml/qechannellistmodel.py
  5. 26
      electrum/gui/qml/qewallet.py

53
electrum/gui/qml/components/Channels.qml

@ -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'))
}
}
} }
} }

4
electrum/gui/qml/components/Constants.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"
} }

42
electrum/gui/qml/components/controls/ChannelDelegate.qml

@ -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

54
electrum/gui/qml/qechannellistmodel.py

@ -5,15 +5,29 @@ 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):
_logger = get_logger(__name__)
# define listmodel rolemap
_ROLE_NAMES=('cid','state','initiator','capacity','can_send','can_receive',
'l_csv_delat','r_csv_delay','send_frozen','receive_frozen',
'type','node_id','node_alias','short_cid','funding_tx')
_ROLE_KEYS = range(Qt.UserRole, Qt.UserRole + len(_ROLE_NAMES))
_ROLE_MAP = dict(zip(_ROLE_KEYS, [bytearray(x.encode()) for x in _ROLE_NAMES]))
_ROLE_RMAP = dict(zip(_ROLE_NAMES, _ROLE_KEYS))
_network_signal = pyqtSignal(str, object)
def __init__(self, wallet, parent=None): def __init__(self, wallet, parent=None):
super().__init__(parent) super().__init__(parent)
self.wallet = wallet self.wallet = wallet
self.init_model() self.init_model()
self._network_signal.connect(self.on_network_qt)
interests = ['channel', 'channels_updated', 'gossip_peers', interests = ['channel', 'channels_updated', 'gossip_peers',
'ln_gossip_sync_progress', 'unknown_channels', 'ln_gossip_sync_progress', 'unknown_channels',
'channel_db', 'gossip_db_loaded'] 'channel_db', 'gossip_db_loaded']
@ -23,15 +37,25 @@ class QEChannelListModel(QAbstractListModel):
# partials, lambdas or methods of subobjects. Hence... # partials, lambdas or methods of subobjects. Hence...
register_callback(self.on_network, interests) register_callback(self.on_network, interests)
_logger = get_logger(__name__) 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)))
# define listmodel rolemap
_ROLE_NAMES=('cid','state','initiator','capacity','can_send','can_receive',
'l_csv_delat','r_csv_delay','send_frozen','receive_frozen',
'type','node_id','node_alias','short_cid','funding_tx')
_ROLE_KEYS = range(Qt.UserRole, Qt.UserRole + len(_ROLE_NAMES))
_ROLE_MAP = dict(zip(_ROLE_KEYS, [bytearray(x.encode()) for x in _ROLE_NAMES]))
_ROLE_RMAP = dict(zip(_ROLE_NAMES, _ROLE_KEYS))
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:

26
electrum/gui/qml/qewallet.py

@ -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))

Loading…
Cancel
Save