keep all models and various UI items updated on new transactions
This commit is contained in:
@@ -45,6 +45,8 @@ Frame {
|
||||
}
|
||||
}
|
||||
|
||||
// instead of all these explicit connections, we should expose
|
||||
// formatted balances directly as a property
|
||||
Connections {
|
||||
target: Config
|
||||
function onBaseUnitChanged() { setBalances() }
|
||||
@@ -56,5 +58,12 @@ Frame {
|
||||
function onWalletLoaded() { setBalances() }
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Daemon.currentWallet
|
||||
function onBalanceChanged() {
|
||||
setBalances()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: setBalances()
|
||||
}
|
||||
|
||||
@@ -133,4 +133,10 @@ Pane {
|
||||
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Network
|
||||
function onHeightChanged(height) {
|
||||
Daemon.currentWallet.historyModel.updateBlockchainHeight(height)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,4 +347,11 @@ Pane {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Daemon.currentWallet
|
||||
function onRequestStatusChanged(key, status) {
|
||||
Daemon.currentWallet.requestModel.updateRequest(key, status)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,11 +13,10 @@ Dialog {
|
||||
|
||||
parent: Overlay.overlay
|
||||
modal: true
|
||||
standardButtons: Dialog.Ok
|
||||
|
||||
width: parent.width - constants.paddingXLarge
|
||||
height: parent.height - constants.paddingXLarge
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
Overlay.modal: Rectangle {
|
||||
color: "#aa000000"
|
||||
@@ -42,6 +41,7 @@ Dialog {
|
||||
icon.width: 32
|
||||
icon.height: 32
|
||||
onClicked: dialog.close()
|
||||
visible: false
|
||||
}
|
||||
}
|
||||
GridLayout {
|
||||
@@ -122,13 +122,19 @@ Dialog {
|
||||
text: qsTr('Address')
|
||||
}
|
||||
Label {
|
||||
Layout.columnSpan: 2
|
||||
Layout.fillWidth: true
|
||||
font.family: FixedFont
|
||||
font.pixelSize: constants.fontSizeLarge
|
||||
wrapMode: Text.WrapAnywhere
|
||||
text: modelItem.address
|
||||
}
|
||||
ToolButton {
|
||||
icon.source: '../../icons/copy.png'
|
||||
icon.color: 'transparent'
|
||||
onClicked: {
|
||||
AppController.textToClipboard(modelItem.address)
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ class QERequestListModel(QAbstractListModel):
|
||||
_ROLE_NAMES=('key','type','timestamp','message','amount','status','address')
|
||||
_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_RMAP = dict(zip(_ROLE_NAMES, _ROLE_KEYS))
|
||||
|
||||
def rowCount(self, index):
|
||||
return len(self.requests)
|
||||
@@ -87,3 +88,15 @@ class QERequestListModel(QAbstractListModel):
|
||||
self.endRemoveRows()
|
||||
break
|
||||
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
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
from datetime import datetime
|
||||
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
|
||||
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
|
||||
|
||||
from electrum.logging import get_logger
|
||||
from electrum.util import Satoshis
|
||||
from electrum.util import Satoshis, TxMinedInfo
|
||||
|
||||
class QETransactionListModel(QAbstractListModel):
|
||||
def __init__(self, wallet, parent=None):
|
||||
@@ -18,6 +20,7 @@ class QETransactionListModel(QAbstractListModel):
|
||||
'inputs','outputs')
|
||||
_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_RMAP = dict(zip(_ROLE_NAMES, _ROLE_KEYS))
|
||||
|
||||
def rowCount(self, index):
|
||||
return len(self.tx_history)
|
||||
@@ -55,3 +58,28 @@ class QETransactionListModel(QAbstractListModel):
|
||||
self.tx_history.reverse()
|
||||
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
|
||||
|
||||
@@ -28,7 +28,7 @@ class QEWallet(QObject):
|
||||
dataChanged = pyqtSignal()
|
||||
|
||||
isUptodateChanged = pyqtSignal()
|
||||
requestStatus = pyqtSignal()
|
||||
requestStatusChanged = pyqtSignal([str,int], arguments=['key','status'])
|
||||
requestCreateSuccess = pyqtSignal()
|
||||
requestCreateError = pyqtSignal([str,str], arguments=['code','error'])
|
||||
|
||||
@@ -37,6 +37,7 @@ class QEWallet(QObject):
|
||||
def __init__(self, wallet, parent=None):
|
||||
super().__init__(parent)
|
||||
self.wallet = wallet
|
||||
|
||||
self._historyModel = QETransactionListModel(wallet)
|
||||
self._addressModel = QEAddressListModel(wallet)
|
||||
self._requestModel = QERequestListModel(wallet)
|
||||
@@ -53,10 +54,9 @@ class QEWallet(QObject):
|
||||
self.notification_timer.timeout.connect(self.notify_transactions)
|
||||
|
||||
self._network_signal.connect(self.on_network_qt)
|
||||
interests = ['wallet_updated', 'network_updated', 'blockchain_updated',
|
||||
'new_transaction', 'status', 'verified', 'on_history',
|
||||
'channel', 'channels_updated', 'payment_failed',
|
||||
'payment_succeeded', 'invoice_status', 'request_status']
|
||||
interests = ['wallet_updated', 'new_transaction', 'status', 'verified',
|
||||
'on_history', 'channel', 'channels_updated', 'payment_failed',
|
||||
'payment_succeeded', 'invoice_status', 'request_status']
|
||||
# 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
|
||||
@@ -77,13 +77,24 @@ class QEWallet(QObject):
|
||||
if event == 'status':
|
||||
self.isUptodateChanged.emit()
|
||||
elif event == 'request_status':
|
||||
self._logger.info(str(args))
|
||||
self.requestStatus.emit()
|
||||
wallet, addr, c = args
|
||||
if wallet == self.wallet:
|
||||
self._logger.debug('request status %d for address %s' % (c, addr))
|
||||
self.requestStatusChanged.emit(addr, c)
|
||||
elif event == 'new_transaction':
|
||||
wallet, tx = args
|
||||
if wallet == self.wallet:
|
||||
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:
|
||||
self._logger.debug('unhandled event: %s %s' % (event, str(args)))
|
||||
|
||||
@@ -115,8 +126,7 @@ class QEWallet(QObject):
|
||||
except queue.Empty:
|
||||
break
|
||||
|
||||
from .qeapp import ElectrumQmlApplication
|
||||
config = ElectrumQmlApplication._config
|
||||
config = self.wallet.config
|
||||
# Combine the transactions if there are at least three
|
||||
if len(txns) >= 3:
|
||||
total_amount = 0
|
||||
@@ -222,10 +232,7 @@ class QEWallet(QObject):
|
||||
self._logger.info('no change output??? : %s' % str(tx.to_json()['outputs']))
|
||||
return
|
||||
|
||||
from .qeapp import ElectrumQmlApplication
|
||||
self.config = ElectrumQmlApplication._config
|
||||
|
||||
use_rbf = bool(self.config.get('use_rbf', True))
|
||||
use_rbf = bool(self.wallet.config.get('use_rbf', True))
|
||||
tx.set_rbf(use_rbf)
|
||||
|
||||
def cb(result):
|
||||
@@ -235,7 +242,7 @@ class QEWallet(QObject):
|
||||
self._logger.info('tx not complete')
|
||||
return
|
||||
|
||||
self.network = ElectrumQmlApplication._daemon.network
|
||||
self.network = self.wallet.network # TODO not always defined?
|
||||
|
||||
try:
|
||||
self._logger.info('running broadcast in thread')
|
||||
@@ -318,3 +325,8 @@ class QEWallet(QObject):
|
||||
def delete_request(self, key: str):
|
||||
self.wallet.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)
|
||||
|
||||
Reference in New Issue
Block a user