Browse Source

keep all models and various UI items updated on new transactions

patch-4
Sander van Grieken 3 years ago
parent
commit
d88cd75460
  1. 9
      electrum/gui/qml/components/BalanceSummary.qml
  2. 6
      electrum/gui/qml/components/History.qml
  3. 7
      electrum/gui/qml/components/Receive.qml
  4. 24
      electrum/gui/qml/components/RequestDialog.qml
  5. 13
      electrum/gui/qml/qerequestlistmodel.py
  6. 30
      electrum/gui/qml/qetransactionlistmodel.py
  7. 42
      electrum/gui/qml/qewallet.py

9
electrum/gui/qml/components/BalanceSummary.qml

@ -45,6 +45,8 @@ Frame {
} }
} }
// instead of all these explicit connections, we should expose
// formatted balances directly as a property
Connections { Connections {
target: Config target: Config
function onBaseUnitChanged() { setBalances() } function onBaseUnitChanged() { setBalances() }
@ -56,5 +58,12 @@ Frame {
function onWalletLoaded() { setBalances() } function onWalletLoaded() { setBalances() }
} }
Connections {
target: Daemon.currentWallet
function onBalanceChanged() {
setBalances()
}
}
Component.onCompleted: setBalances() Component.onCompleted: setBalances()
} }

6
electrum/gui/qml/components/History.qml

@ -133,4 +133,10 @@ Pane {
} }
Connections {
target: Network
function onHeightChanged(height) {
Daemon.currentWallet.historyModel.updateBlockchainHeight(height)
}
}
} }

7
electrum/gui/qml/components/Receive.qml

@ -347,4 +347,11 @@ Pane {
} }
} }
Connections {
target: Daemon.currentWallet
function onRequestStatusChanged(key, status) {
Daemon.currentWallet.requestModel.updateRequest(key, status)
}
}
} }

24
electrum/gui/qml/components/RequestDialog.qml

@ -13,11 +13,10 @@ Dialog {
parent: Overlay.overlay parent: Overlay.overlay
modal: true modal: true
standardButtons: Dialog.Ok
width: parent.width - constants.paddingXLarge width: parent.width
height: parent.height - constants.paddingXLarge height: parent.height
x: (parent.width - width) / 2
y: (parent.height - height) / 2
Overlay.modal: Rectangle { Overlay.modal: Rectangle {
color: "#aa000000" color: "#aa000000"
@ -42,6 +41,7 @@ Dialog {
icon.width: 32 icon.width: 32
icon.height: 32 icon.height: 32
onClicked: dialog.close() onClicked: dialog.close()
visible: false
} }
} }
GridLayout { GridLayout {
@ -122,13 +122,19 @@ Dialog {
text: qsTr('Address') text: qsTr('Address')
} }
Label { Label {
Layout.columnSpan: 2
Layout.fillWidth: true Layout.fillWidth: true
font.family: FixedFont font.family: FixedFont
font.pixelSize: constants.fontSizeLarge font.pixelSize: constants.fontSizeLarge
wrapMode: Text.WrapAnywhere wrapMode: Text.WrapAnywhere
text: modelItem.address text: modelItem.address
} }
ToolButton {
icon.source: '../../icons/copy.png'
icon.color: 'transparent'
onClicked: {
AppController.textToClipboard(modelItem.address)
}
}
Label { Label {
text: qsTr('Status') text: qsTr('Status')
@ -162,4 +168,12 @@ Dialog {
} }
} }
Connections {
target: Daemon.currentWallet
function onRequestStatusChanged(key, code) {
if (key != modelItem.key)
return
modelItem = Daemon.currentWallet.get_request(key)
}
}
} }

13
electrum/gui/qml/qerequestlistmodel.py

@ -17,6 +17,7 @@ class QERequestListModel(QAbstractListModel):
_ROLE_NAMES=('key','type','timestamp','message','amount','status','address') _ROLE_NAMES=('key','type','timestamp','message','amount','status','address')
_ROLE_KEYS = range(Qt.UserRole + 1, Qt.UserRole + 1 + len(_ROLE_NAMES)) _ROLE_KEYS = range(Qt.UserRole + 1, Qt.UserRole + 1 + len(_ROLE_NAMES))
_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))
def rowCount(self, index): def rowCount(self, index):
return len(self.requests) return len(self.requests)
@ -87,3 +88,15 @@ class QERequestListModel(QAbstractListModel):
self.endRemoveRows() self.endRemoveRows()
break break
i = i + 1 i = i + 1
@pyqtSlot(str, int)
def updateRequest(self, key, status):
self._logger.debug('updating request for %s to %d' % (key,status))
i = 0
for item in self.requests:
if item['key'] == key:
req = self.wallet.get_request(key)
item['status'] = req.get_status_str(status)
index = self.index(i,0)
self.dataChanged.emit(index, index, [self._ROLE_RMAP['status']])
i = i + 1

30
electrum/gui/qml/qetransactionlistmodel.py

@ -1,8 +1,10 @@
from datetime import datetime
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
from electrum.logging import get_logger from electrum.logging import get_logger
from electrum.util import Satoshis from electrum.util import Satoshis, TxMinedInfo
class QETransactionListModel(QAbstractListModel): class QETransactionListModel(QAbstractListModel):
def __init__(self, wallet, parent=None): def __init__(self, wallet, parent=None):
@ -18,6 +20,7 @@ class QETransactionListModel(QAbstractListModel):
'inputs','outputs') 'inputs','outputs')
_ROLE_KEYS = range(Qt.UserRole + 1, Qt.UserRole + 1 + len(_ROLE_NAMES)) _ROLE_KEYS = range(Qt.UserRole + 1, Qt.UserRole + 1 + len(_ROLE_NAMES))
_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))
def rowCount(self, index): def rowCount(self, index):
return len(self.tx_history) return len(self.tx_history)
@ -55,3 +58,28 @@ class QETransactionListModel(QAbstractListModel):
self.tx_history.reverse() self.tx_history.reverse()
self.endInsertRows() self.endInsertRows()
def update_tx(self, txid, info):
i = 0
for tx in self.tx_history:
if tx['txid'] == txid:
tx['height'] = info.height
tx['confirmations'] = info.conf
tx['timestamp'] = info.timestamp
tx['date'] = datetime.fromtimestamp(info.timestamp)
index = self.index(i,0)
roles = [self._ROLE_RMAP[x] for x in ['height','confirmations','timestamp','date']]
self.dataChanged.emit(index, index, roles)
return
i = i + 1
@pyqtSlot(int)
def updateBlockchainHeight(self, height):
self._logger.debug('updating height to %d' % height)
i = 0
for tx in self.tx_history:
if tx['height'] > 0:
tx['confirmations'] = height - tx['height'] + 1
index = self.index(i,0)
roles = [self._ROLE_RMAP['confirmations']]
self.dataChanged.emit(index, index, roles)
i = i + 1

42
electrum/gui/qml/qewallet.py

@ -28,7 +28,7 @@ class QEWallet(QObject):
dataChanged = pyqtSignal() dataChanged = pyqtSignal()
isUptodateChanged = pyqtSignal() isUptodateChanged = pyqtSignal()
requestStatus = pyqtSignal() requestStatusChanged = pyqtSignal([str,int], arguments=['key','status'])
requestCreateSuccess = pyqtSignal() requestCreateSuccess = pyqtSignal()
requestCreateError = pyqtSignal([str,str], arguments=['code','error']) requestCreateError = pyqtSignal([str,str], arguments=['code','error'])
@ -37,6 +37,7 @@ class QEWallet(QObject):
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._historyModel = QETransactionListModel(wallet) self._historyModel = QETransactionListModel(wallet)
self._addressModel = QEAddressListModel(wallet) self._addressModel = QEAddressListModel(wallet)
self._requestModel = QERequestListModel(wallet) self._requestModel = QERequestListModel(wallet)
@ -53,10 +54,9 @@ class QEWallet(QObject):
self.notification_timer.timeout.connect(self.notify_transactions) self.notification_timer.timeout.connect(self.notify_transactions)
self._network_signal.connect(self.on_network_qt) self._network_signal.connect(self.on_network_qt)
interests = ['wallet_updated', 'network_updated', 'blockchain_updated', interests = ['wallet_updated', 'new_transaction', 'status', 'verified',
'new_transaction', 'status', 'verified', 'on_history', 'on_history', 'channel', 'channels_updated', 'payment_failed',
'channel', 'channels_updated', 'payment_failed', 'payment_succeeded', 'invoice_status', 'request_status']
'payment_succeeded', 'invoice_status', 'request_status']
# To avoid leaking references to "self" that prevent the # To avoid leaking references to "self" that prevent the
# window from being GC-ed when closed, callbacks should be # window from being GC-ed when closed, callbacks should be
# methods of this class only, and specifically not be # methods of this class only, and specifically not be
@ -77,13 +77,24 @@ class QEWallet(QObject):
if event == 'status': if event == 'status':
self.isUptodateChanged.emit() self.isUptodateChanged.emit()
elif event == 'request_status': elif event == 'request_status':
self._logger.info(str(args)) wallet, addr, c = args
self.requestStatus.emit() if wallet == self.wallet:
self._logger.debug('request status %d for address %s' % (c, addr))
self.requestStatusChanged.emit(addr, c)
elif event == 'new_transaction': elif event == 'new_transaction':
wallet, tx = args wallet, tx = args
if wallet == self.wallet: if wallet == self.wallet:
self.add_tx_notification(tx) self.add_tx_notification(tx)
self._historyModel.init_model() self._historyModel.init_model() # TODO: be less dramatic
elif event == 'verified':
wallet, txid, info = args
if wallet == self.wallet:
self._historyModel.update_tx(txid, info)
elif event == 'wallet_updated':
wallet, = args
if wallet == self.wallet:
self._logger.debug('wallet %s updated' % str(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)))
@ -115,8 +126,7 @@ class QEWallet(QObject):
except queue.Empty: except queue.Empty:
break break
from .qeapp import ElectrumQmlApplication config = self.wallet.config
config = ElectrumQmlApplication._config
# Combine the transactions if there are at least three # Combine the transactions if there are at least three
if len(txns) >= 3: if len(txns) >= 3:
total_amount = 0 total_amount = 0
@ -222,10 +232,7 @@ class QEWallet(QObject):
self._logger.info('no change output??? : %s' % str(tx.to_json()['outputs'])) self._logger.info('no change output??? : %s' % str(tx.to_json()['outputs']))
return return
from .qeapp import ElectrumQmlApplication use_rbf = bool(self.wallet.config.get('use_rbf', True))
self.config = ElectrumQmlApplication._config
use_rbf = bool(self.config.get('use_rbf', True))
tx.set_rbf(use_rbf) tx.set_rbf(use_rbf)
def cb(result): def cb(result):
@ -235,7 +242,7 @@ class QEWallet(QObject):
self._logger.info('tx not complete') self._logger.info('tx not complete')
return return
self.network = ElectrumQmlApplication._daemon.network self.network = self.wallet.network # TODO not always defined?
try: try:
self._logger.info('running broadcast in thread') self._logger.info('running broadcast in thread')
@ -318,3 +325,8 @@ class QEWallet(QObject):
def delete_request(self, key: str): def delete_request(self, key: str):
self.wallet.delete_request(key) self.wallet.delete_request(key)
self._requestModel.delete_request(key) self._requestModel.delete_request(key)
@pyqtSlot('QString', result='QVariant')
def get_request(self, key: str):
req = self.wallet.get_request(key)
return self._requestModel.request_to_model(req)

Loading…
Cancel
Save