You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

167 lines
6.0 KiB

from datetime import datetime, timedelta
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, TxMinedInfo
from .qetypes import QEAmount
class QETransactionListModel(QAbstractListModel):
def __init__(self, wallet, parent=None, *, onchain_domain=None, include_lightning=True):
super().__init__(parent)
self.wallet = wallet
self.onchain_domain = onchain_domain
self.include_lightning = include_lightning
self.init_model()
_logger = get_logger(__name__)
# define listmodel rolemap
_ROLE_NAMES=('txid','fee_sat','height','confirmations','timestamp','monotonic_timestamp',
'incoming','value','balance','date','label','txpos_in_block','fee',
'inputs','outputs','section','type','lightning','payment_hash','key','complete')
_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):
return len(self.tx_history)
def roleNames(self):
return self._ROLE_MAP
def data(self, index, role):
tx = self.tx_history[index.row()]
role_index = role - Qt.UserRole
try:
value = tx[self._ROLE_NAMES[role_index]]
except KeyError as e:
self._logger.error(f'non-existing key "{self._ROLE_NAMES[role_index]}" requested')
value = None
if isinstance(value, (bool, list, int, str, QEAmount)) or value is None:
return value
if isinstance(value, Satoshis):
return value.value
return str(value)
def clear(self):
self.beginResetModel()
self.tx_history = []
self.endResetModel()
def tx_to_model(self, tx):
#self._logger.debug(str(tx))
item = tx
item['key'] = item['txid'] if 'txid' in item else item['payment_hash']
if not 'lightning' in item:
item['lightning'] = False
if item['lightning']:
item['value'] = QEAmount(amount_sat=item['value'].value, amount_msat=item['amount_msat'])
item['balance'] = QEAmount(amount_sat=item['balance'].value, amount_msat=item['amount_msat'])
if item['type'] == 'payment':
item['incoming'] = True if item['direction'] == 'received' else False
item['confirmations'] = 0
else:
item['value'] = QEAmount(amount_sat=item['value'].value)
item['balance'] = QEAmount(amount_sat=item['balance'].value)
# newly arriving txs have no (block) timestamp
# TODO?
if not item['timestamp']:
item['timestamp'] = datetime.timestamp(datetime.now())
txts = datetime.fromtimestamp(item['timestamp'])
today = datetime.today().replace(hour=0, minute=0, second=0, microsecond=0)
if (txts > today):
item['section'] = 'today'
elif (txts > today - timedelta(days=1)):
item['section'] = 'yesterday'
elif (txts > today - timedelta(days=7)):
item['section'] = 'lastweek'
elif (txts > today - timedelta(days=31)):
item['section'] = 'lastmonth'
else:
item['section'] = 'older'
item['date'] = self.format_date_by_section(item['section'], datetime.fromtimestamp(item['timestamp']))
if 'txid' in item:
tx = self.wallet.get_input_tx(item['txid'])
item['complete'] = tx.is_complete()
#else:
#item['complete'] = True
return item
def format_date_by_section(self, section, date):
#TODO: l10n
dfmt = {
'today': '%H:%M:%S',
'yesterday': '%H:%M:%S',
'lastweek': '%a, %H:%M:%S',
'lastmonth': '%a %d, %H:%M:%S',
'older': '%G-%m-%d %H:%M:%S'
}
if section not in dfmt:
section = 'older'
return date.strftime(dfmt[section])
# initial model data
@pyqtSlot()
def init_model(self):
history = self.wallet.get_full_history(onchain_domain=self.onchain_domain,
include_lightning=self.include_lightning)
txs = []
for key, tx in history.items():
txs.append(self.tx_to_model(tx))
self.clear()
self.beginInsertRows(QModelIndex(), 0, len(txs) - 1)
self.tx_history = txs
self.tx_history.reverse()
self.endInsertRows()
def update_tx(self, txid, info):
i = 0
for tx in self.tx_history:
if 'txid' in tx and tx['txid'] == txid:
tx['height'] = info.height
tx['confirmations'] = info.conf
tx['timestamp'] = info.timestamp
tx['date'] = self.format_date_by_section(tx['section'], 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(str, str)
def update_tx_label(self, key, label):
i = 0
for tx in self.tx_history:
if tx['key'] == key:
tx['label'] = label
index = self.index(i,0)
self.dataChanged.emit(index, index, [self._ROLE_RMAP['label']])
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 'height' in tx and 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