whitespace, imports, code style
This commit is contained in:
@@ -2,7 +2,6 @@ import os
|
||||
import signal
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
try:
|
||||
@@ -15,11 +14,10 @@ try:
|
||||
except Exception:
|
||||
sys.exit("Error: Could not import PyQt5.QtQml on Linux systems, you may try 'sudo apt-get install python3-pyqt5.qtquick'")
|
||||
|
||||
from PyQt5.QtCore import (Qt, QCoreApplication, QObject, QLocale, QTranslator, QTimer, pyqtSignal,
|
||||
QT_VERSION_STR, PYQT_VERSION_STR)
|
||||
from PyQt5.QtCore import (Qt, QCoreApplication, QLocale, QTranslator, QTimer, QT_VERSION_STR, PYQT_VERSION_STR)
|
||||
from PyQt5.QtGui import QGuiApplication
|
||||
|
||||
from electrum.i18n import _, set_language, languages
|
||||
from electrum.i18n import _
|
||||
from electrum.plugin import run_hook
|
||||
from electrum.util import profiler
|
||||
from electrum.logging import Logger
|
||||
@@ -29,7 +27,6 @@ if TYPE_CHECKING:
|
||||
from electrum.daemon import Daemon
|
||||
from electrum.simple_config import SimpleConfig
|
||||
from electrum.plugin import Plugins
|
||||
from electrum.wallet import Abstract_Wallet
|
||||
|
||||
from .qeapp import ElectrumQmlApplication, Exception_Hook
|
||||
|
||||
@@ -86,7 +83,7 @@ class ElectrumGui(BaseElectrumGui, Logger):
|
||||
self.timer = QTimer(self.app)
|
||||
self.timer.setSingleShot(False)
|
||||
self.timer.setInterval(500) # msec
|
||||
self.timer.timeout.connect(lambda: None) # periodically enter python scope
|
||||
self.timer.timeout.connect(lambda: None) # periodically enter python scope
|
||||
|
||||
# hook for crash reporter
|
||||
Exception_Hook.maybe_setup(config=config, slot=self.app.appController.crash)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from functools import wraps, partial
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot, pyqtProperty
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot
|
||||
|
||||
from electrum.logging import get_logger
|
||||
|
||||
|
||||
def auth_protect(func=None, reject=None, method='pin', message=''):
|
||||
if func is None:
|
||||
return partial(auth_protect, reject=reject, method=method, message=message)
|
||||
@@ -20,6 +21,7 @@ def auth_protect(func=None, reject=None, method='pin', message=''):
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class AuthMixin:
|
||||
_auth_logger = get_logger(__name__)
|
||||
authRequired = pyqtSignal([str, str], arguments=['method', 'authMessage'])
|
||||
@@ -29,14 +31,14 @@ class AuthMixin:
|
||||
self._auth_logger.debug('Proceeding with authed fn()')
|
||||
try:
|
||||
self._auth_logger.debug(str(getattr(self, '__auth_fcall')))
|
||||
(func,args,kwargs,reject) = getattr(self, '__auth_fcall')
|
||||
(func, args, kwargs, reject) = getattr(self, '__auth_fcall')
|
||||
r = func(self, *args, **kwargs)
|
||||
return r
|
||||
except Exception as e:
|
||||
self._auth_logger.error(f'Error executing wrapped fn(): {repr(e)}')
|
||||
raise e
|
||||
finally:
|
||||
delattr(self,'__auth_fcall')
|
||||
delattr(self, '__auth_fcall')
|
||||
|
||||
@pyqtSlot()
|
||||
def authCancel(self):
|
||||
@@ -45,7 +47,7 @@ class AuthMixin:
|
||||
return
|
||||
|
||||
try:
|
||||
(func,args,kwargs,reject) = getattr(self, '__auth_fcall')
|
||||
(func, args, kwargs, reject) = getattr(self, '__auth_fcall')
|
||||
if reject is not None:
|
||||
if hasattr(self, reject):
|
||||
getattr(self, reject)()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import itertools
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
|
||||
from PyQt5.QtCore import pyqtSlot
|
||||
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
|
||||
|
||||
from electrum.logging import get_logger
|
||||
@@ -17,27 +17,30 @@ class QEAddressListModel(QAbstractListModel):
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
# define listmodel rolemap
|
||||
_ROLE_NAMES=('type','iaddr','address','label','balance','numtx', 'held')
|
||||
_ROLE_NAMES=('type', 'iaddr', 'address', 'label', 'balance', 'numtx', 'held')
|
||||
_ROLE_KEYS = range(Qt.UserRole, Qt.UserRole + len(_ROLE_NAMES))
|
||||
_ROLE_MAP = dict(zip(_ROLE_KEYS, [bytearray(x.encode()) for x in _ROLE_NAMES]))
|
||||
|
||||
def __init__(self, wallet: 'Abstract_Wallet', parent=None):
|
||||
super().__init__(parent)
|
||||
self.wallet = wallet
|
||||
self.setDirty()
|
||||
self._receive_addresses = []
|
||||
self._change_addresses = []
|
||||
|
||||
self._dirty = True
|
||||
self.initModel()
|
||||
|
||||
def rowCount(self, index):
|
||||
return len(self.receive_addresses) + len(self.change_addresses)
|
||||
return len(self._receive_addresses) + len(self._change_addresses)
|
||||
|
||||
def roleNames(self):
|
||||
return self._ROLE_MAP
|
||||
|
||||
def data(self, index, role):
|
||||
if index.row() > len(self.receive_addresses) - 1:
|
||||
address = self.change_addresses[index.row() - len(self.receive_addresses)]
|
||||
if index.row() > len(self._receive_addresses) - 1:
|
||||
address = self._change_addresses[index.row() - len(self._receive_addresses)]
|
||||
else:
|
||||
address = self.receive_addresses[index.row()]
|
||||
address = self._receive_addresses[index.row()]
|
||||
role_index = role - Qt.UserRole
|
||||
value = address[self._ROLE_NAMES[role_index]]
|
||||
if isinstance(value, (bool, list, int, str, QEAmount)) or value is None:
|
||||
@@ -48,18 +51,19 @@ class QEAddressListModel(QAbstractListModel):
|
||||
|
||||
def clear(self):
|
||||
self.beginResetModel()
|
||||
self.receive_addresses = []
|
||||
self.change_addresses = []
|
||||
self._receive_addresses = []
|
||||
self._change_addresses = []
|
||||
self.endResetModel()
|
||||
|
||||
def addr_to_model(self, address):
|
||||
item = {}
|
||||
item['address'] = address
|
||||
item['numtx'] = self.wallet.adb.get_address_history_len(address)
|
||||
item['label'] = self.wallet.get_label_for_address(address)
|
||||
c, u, x = self.wallet.get_addr_balance(address)
|
||||
item['balance'] = QEAmount(amount_sat=c + u + x)
|
||||
item['held'] = self.wallet.is_frozen_address(address)
|
||||
item = {
|
||||
'address': address,
|
||||
'numtx': self.wallet.adb.get_address_history_len(address),
|
||||
'label': self.wallet.get_label_for_address(address),
|
||||
'balance': QEAmount(amount_sat=c + u + x),
|
||||
'held': self.wallet.is_frozen_address(address)
|
||||
}
|
||||
return item
|
||||
|
||||
@pyqtSlot()
|
||||
@@ -86,21 +90,21 @@ class QEAddressListModel(QAbstractListModel):
|
||||
self.beginInsertRows(QModelIndex(), 0, n_addresses - 1)
|
||||
if self.wallet.wallet_type != 'imported':
|
||||
for i, address in enumerate(r_addresses):
|
||||
insert_row('receive', self.receive_addresses, address, i)
|
||||
insert_row('receive', self._receive_addresses, address, i)
|
||||
for i, address in enumerate(c_addresses):
|
||||
insert_row('change', self.change_addresses, address, i)
|
||||
insert_row('change', self._change_addresses, address, i)
|
||||
else:
|
||||
for i, address in enumerate(r_addresses):
|
||||
insert_row('imported', self.receive_addresses, address, i)
|
||||
insert_row('imported', self._receive_addresses, address, i)
|
||||
self.endInsertRows()
|
||||
|
||||
self._dirty = False
|
||||
|
||||
@pyqtSlot(str)
|
||||
def updateAddress(self, address):
|
||||
for i, a in enumerate(itertools.chain(self.receive_addresses, self.change_addresses)):
|
||||
for i, a in enumerate(itertools.chain(self._receive_addresses, self._change_addresses)):
|
||||
if a['address'] == address:
|
||||
self.do_update(i,a)
|
||||
self.do_update(i, a)
|
||||
return
|
||||
|
||||
def do_update(self, modelindex, modelitem):
|
||||
|
||||
@@ -26,7 +26,6 @@ class QEBip39RecoveryListModel(QAbstractListModel):
|
||||
|
||||
recoveryFailed = pyqtSignal()
|
||||
stateChanged = pyqtSignal()
|
||||
# userinfoChanged = pyqtSignal()
|
||||
|
||||
# define listmodel rolemap
|
||||
_ROLE_NAMES=('description', 'derivation_path', 'script_type')
|
||||
@@ -112,7 +111,7 @@ class QEBip39RecoveryListModel(QAbstractListModel):
|
||||
if isinstance(e, concurrent.futures.CancelledError):
|
||||
self.state = QEBip39RecoveryListModel.State.Cancelled
|
||||
return
|
||||
self._logger.error(f"recovery error", exc_info=exc_info)
|
||||
self._logger.error(f'recovery error', exc_info=exc_info)
|
||||
self.state = QEBip39RecoveryListModel.State.Failed
|
||||
self._thread.stop()
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
|
||||
from electrum import mnemonic
|
||||
from electrum import keystore
|
||||
from electrum.i18n import _
|
||||
from electrum.bip32 import is_bip32_derivation, normalize_bip32_derivation, xpub_type
|
||||
from electrum.bip32 import is_bip32_derivation, xpub_type
|
||||
from electrum.logging import get_logger
|
||||
from electrum.slip39 import decode_mnemonic, Slip39Error
|
||||
from electrum.util import get_asyncio_loop
|
||||
@@ -13,7 +13,6 @@ from electrum.transaction import tx_from_any
|
||||
from electrum.mnemonic import Mnemonic, is_any_2fa_seed_type
|
||||
from electrum.old_mnemonic import wordlist as old_wordlist
|
||||
|
||||
from .qetypes import QEAmount
|
||||
|
||||
class QEBitcoin(QObject):
|
||||
_logger = get_logger(__name__)
|
||||
@@ -79,7 +78,7 @@ class QEBitcoin(QObject):
|
||||
if is_checksum:
|
||||
seed_type = 'bip39'
|
||||
seed_valid = True
|
||||
elif seed_variant == 'slip39': # TODO: incomplete impl, this code only validates a single share.
|
||||
elif seed_variant == 'slip39': # TODO: incomplete impl, this code only validates a single share.
|
||||
try:
|
||||
share = decode_mnemonic(seed)
|
||||
seed_type = 'slip39'
|
||||
|
||||
@@ -17,7 +17,7 @@ from .util import QtEventListener, event_listener
|
||||
class QEChannelDetails(AuthMixin, QObject, QtEventListener):
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
class State: # subset, only ones we currently need in UI
|
||||
class State: # subset, only ones we currently need in UI
|
||||
Closed = ChannelState.CLOSED
|
||||
Redeemed = ChannelState.REDEEMED
|
||||
|
||||
|
||||
@@ -29,6 +29,11 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
|
||||
def __init__(self, wallet, parent=None):
|
||||
super().__init__(parent)
|
||||
self.wallet = wallet
|
||||
self._channels = []
|
||||
|
||||
self._fm_backups = None
|
||||
self._fm_nobackups = None
|
||||
|
||||
self.initModel()
|
||||
|
||||
# To avoid leaking references to "self" that prevent the
|
||||
@@ -52,19 +57,19 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
|
||||
self.unregister_callbacks()
|
||||
|
||||
def rowCount(self, index):
|
||||
return len(self.channels)
|
||||
return len(self._channels)
|
||||
|
||||
# also expose rowCount as a property
|
||||
countChanged = pyqtSignal()
|
||||
@pyqtProperty(int, notify=countChanged)
|
||||
def count(self):
|
||||
return len(self.channels)
|
||||
return len(self._channels)
|
||||
|
||||
def roleNames(self):
|
||||
return self._ROLE_MAP
|
||||
|
||||
def data(self, index, role):
|
||||
tx = self.channels[index.row()]
|
||||
tx = self._channels[index.row()]
|
||||
role_index = role - Qt.UserRole
|
||||
value = tx[self._ROLE_NAMES[role_index]]
|
||||
if isinstance(value, (bool, list, int, str, QEAmount)) or value is None:
|
||||
@@ -75,21 +80,22 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
|
||||
|
||||
def clear(self):
|
||||
self.beginResetModel()
|
||||
self.channels = []
|
||||
self._channels = []
|
||||
self.endResetModel()
|
||||
|
||||
def channel_to_model(self, lnc):
|
||||
lnworker = self.wallet.lnworker
|
||||
item = {}
|
||||
item['cid'] = lnc.channel_id.hex()
|
||||
item['node_id'] = lnc.node_id.hex()
|
||||
item['node_alias'] = lnworker.get_node_alias(lnc.node_id) or ''
|
||||
item['short_cid'] = lnc.short_id_for_GUI()
|
||||
item['state'] = lnc.get_state_for_GUI()
|
||||
item['state_code'] = int(lnc.get_state())
|
||||
item['is_backup'] = lnc.is_backup()
|
||||
item['is_trampoline'] = lnworker.is_trampoline_peer(lnc.node_id)
|
||||
item['capacity'] = QEAmount(amount_sat=lnc.get_capacity())
|
||||
item = {
|
||||
'cid': lnc.channel_id.hex(),
|
||||
'node_id': lnc.node_id.hex(),
|
||||
'node_alias': lnworker.get_node_alias(lnc.node_id) or '',
|
||||
'short_cid': lnc.short_id_for_GUI(),
|
||||
'state': lnc.get_state_for_GUI(),
|
||||
'state_code': int(lnc.get_state()),
|
||||
'is_backup': lnc.is_backup(),
|
||||
'is_trampoline': lnworker.is_trampoline_peer(lnc.node_id),
|
||||
'capacity': QEAmount(amount_sat=lnc.get_capacity())
|
||||
}
|
||||
if lnc.is_backup():
|
||||
item['can_send'] = QEAmount()
|
||||
item['can_receive'] = QEAmount()
|
||||
@@ -111,7 +117,7 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
|
||||
numOpenChannelsChanged = pyqtSignal()
|
||||
@pyqtProperty(int, notify=numOpenChannelsChanged)
|
||||
def numOpenChannels(self):
|
||||
return sum([1 if x['state_code'] == ChannelState.OPEN else 0 for x in self.channels])
|
||||
return sum([1 if x['state_code'] == ChannelState.OPEN else 0 for x in self._channels])
|
||||
|
||||
@pyqtSlot()
|
||||
def initModel(self):
|
||||
@@ -134,20 +140,20 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
|
||||
|
||||
self.clear()
|
||||
self.beginInsertRows(QModelIndex(), 0, len(channels) - 1)
|
||||
self.channels = channels
|
||||
self._channels = channels
|
||||
self.endInsertRows()
|
||||
|
||||
self.countChanged.emit()
|
||||
|
||||
def on_channel_updated(self, channel):
|
||||
for i, c in enumerate(self.channels):
|
||||
for i, c in enumerate(self._channels):
|
||||
if c['cid'] == channel.channel_id.hex():
|
||||
self.do_update(i,channel)
|
||||
self.do_update(i, channel)
|
||||
break
|
||||
|
||||
def do_update(self, modelindex, channel):
|
||||
self._logger.debug(f'updating our channel {channel.short_id_for_GUI()}')
|
||||
modelitem = self.channels[modelindex]
|
||||
modelitem = self._channels[modelindex]
|
||||
modelitem.update(self.channel_to_model(channel))
|
||||
|
||||
mi = self.createIndex(modelindex, 0)
|
||||
@@ -163,7 +169,7 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
|
||||
item = self.channel_to_model(channel)
|
||||
self._logger.debug(item)
|
||||
self.beginInsertRows(QModelIndex(), 0, 0)
|
||||
self.channels.insert(0,item)
|
||||
self._channels.insert(0, item)
|
||||
self.endInsertRows()
|
||||
self.countChanged.emit()
|
||||
return
|
||||
@@ -171,11 +177,11 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
|
||||
@pyqtSlot(str)
|
||||
def removeChannel(self, cid):
|
||||
self._logger.debug('remove channel with cid %s' % cid)
|
||||
for i, channel in enumerate(self.channels):
|
||||
for i, channel in enumerate(self._channels):
|
||||
if cid == channel['cid']:
|
||||
self._logger.debug(cid)
|
||||
self.beginRemoveRows(QModelIndex(), i, i)
|
||||
self.channels.remove(channel)
|
||||
self._channels.remove(channel)
|
||||
self.endRemoveRows()
|
||||
self.countChanged.emit()
|
||||
return
|
||||
|
||||
@@ -27,9 +27,10 @@ class QEChannelOpener(QObject, AuthMixin):
|
||||
conflictingBackup = pyqtSignal([str], arguments=['message'])
|
||||
channelOpening = pyqtSignal([str], arguments=['peer'])
|
||||
channelOpenError = pyqtSignal([str], arguments=['message'])
|
||||
channelOpenSuccess = pyqtSignal([str,bool,int,bool], arguments=['cid','has_onchain_backup','min_depth','tx_complete'])
|
||||
channelOpenSuccess = pyqtSignal([str, bool, int, bool],
|
||||
arguments=['cid', 'has_onchain_backup', 'min_depth', 'tx_complete'])
|
||||
|
||||
dataChanged = pyqtSignal() # generic notify signal
|
||||
dataChanged = pyqtSignal() # generic notify signal
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
@@ -41,6 +42,10 @@ class QEChannelOpener(QObject, AuthMixin):
|
||||
self._opentx = None
|
||||
self._txdetails = None
|
||||
|
||||
self._finalizer = None
|
||||
self._node_pubkey = None
|
||||
self._connect_str_resolved = None
|
||||
|
||||
walletChanged = pyqtSignal()
|
||||
@pyqtProperty(QEWallet, notify=walletChanged)
|
||||
def wallet(self):
|
||||
@@ -124,7 +129,7 @@ class QEChannelOpener(QObject, AuthMixin):
|
||||
self.validChanged.emit()
|
||||
return
|
||||
|
||||
self._logger.debug('amount=%s' % str(self._amount))
|
||||
self._logger.debug(f'amount={self._amount}')
|
||||
if not self._amount or not (self._amount.satsInt > 0 or self._amount.isMax):
|
||||
self._valid = False
|
||||
self.validChanged.emit()
|
||||
@@ -136,9 +141,9 @@ class QEChannelOpener(QObject, AuthMixin):
|
||||
@pyqtSlot(str, result=bool)
|
||||
def validateConnectString(self, connect_str):
|
||||
try:
|
||||
node_id, rest = extract_nodeid(connect_str)
|
||||
extract_nodeid(connect_str)
|
||||
except ConnStringFormatError as e:
|
||||
self._logger.debug(f"invalid connect_str. {e!r}")
|
||||
self._logger.debug(f'invalid connect_str. {e!r}')
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -199,13 +204,13 @@ class QEChannelOpener(QObject, AuthMixin):
|
||||
chan.constraints.funding_txn_minimum_depth, funding_tx.is_complete())
|
||||
|
||||
# TODO: handle incomplete TX
|
||||
#if not funding_tx.is_complete():
|
||||
#self._txdetails = QETxDetails(self)
|
||||
#self._txdetails.rawTx = funding_tx
|
||||
#self._txdetails.wallet = self._wallet
|
||||
#self.txDetailsChanged.emit()
|
||||
# if not funding_tx.is_complete():
|
||||
# self._txdetails = QETxDetails(self)
|
||||
# self._txdetails.rawTx = funding_tx
|
||||
# self._txdetails.wallet = self._wallet
|
||||
# self.txDetailsChanged.emit()
|
||||
|
||||
except (CancelledError,TimeoutError):
|
||||
except (CancelledError, TimeoutError):
|
||||
error = _('Could not connect to channel peer')
|
||||
except Exception as e:
|
||||
error = str(e)
|
||||
@@ -216,7 +221,6 @@ class QEChannelOpener(QObject, AuthMixin):
|
||||
self._logger.exception("Problem opening channel: %s", error)
|
||||
self.channelOpenError.emit(error)
|
||||
|
||||
|
||||
self._logger.debug('starting open thread')
|
||||
self.channelOpening.emit(conn_str)
|
||||
threading.Thread(target=open_thread, daemon=True).start()
|
||||
|
||||
@@ -7,13 +7,14 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QRegularEx
|
||||
from electrum.bitcoin import TOTAL_COIN_SUPPLY_LIMIT_IN_BTC
|
||||
from electrum.i18n import set_language, languages
|
||||
from electrum.logging import get_logger
|
||||
from electrum.util import DECIMAL_POINT_DEFAULT, base_unit_name_to_decimal_point
|
||||
from electrum.invoices import PR_DEFAULT_EXPIRATION_WHEN_CREATING
|
||||
from electrum.simple_config import SimpleConfig
|
||||
from electrum.util import base_unit_name_to_decimal_point
|
||||
|
||||
from .qetypes import QEAmount
|
||||
from .auth import AuthMixin, auth_protect
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from electrum.simple_config import SimpleConfig
|
||||
|
||||
|
||||
class QEConfig(AuthMixin, QObject):
|
||||
_logger = get_logger(__name__)
|
||||
@@ -251,7 +252,7 @@ class QEConfig(AuthMixin, QObject):
|
||||
return self.config.BTC_AMOUNTS_DECIMAL_POINT
|
||||
|
||||
def max_precision(self):
|
||||
return self.decimal_point() + 0 #self.extra_precision
|
||||
return self.decimal_point() + 0 # self.extra_precision
|
||||
|
||||
@pyqtSlot(str, result=QEAmount)
|
||||
def unitsToSats(self, unitAmount):
|
||||
@@ -275,4 +276,4 @@ class QEConfig(AuthMixin, QObject):
|
||||
|
||||
@pyqtSlot('quint64', result=float)
|
||||
def satsToUnits(self, satoshis):
|
||||
return satoshis / pow(10,self.config.decimal_point)
|
||||
return satoshis / pow(10, self.config.decimal_point)
|
||||
|
||||
@@ -28,23 +28,24 @@ class QEWalletListModel(QAbstractListModel):
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
# define listmodel rolemap
|
||||
_ROLE_NAMES= ('name','path','active')
|
||||
_ROLE_NAMES= ('name', 'path', 'active')
|
||||
_ROLE_KEYS = range(Qt.UserRole, Qt.UserRole + len(_ROLE_NAMES))
|
||||
_ROLE_MAP = dict(zip(_ROLE_KEYS, [bytearray(x.encode()) for x in _ROLE_NAMES]))
|
||||
|
||||
def __init__(self, daemon, parent=None):
|
||||
QAbstractListModel.__init__(self, parent)
|
||||
self.daemon = daemon
|
||||
self._wallets = []
|
||||
self.reload()
|
||||
|
||||
def rowCount(self, index):
|
||||
return len(self.wallets)
|
||||
return len(self._wallets)
|
||||
|
||||
def roleNames(self):
|
||||
return self._ROLE_MAP
|
||||
|
||||
def data(self, index, role):
|
||||
(wallet_name, wallet_path) = self.wallets[index.row()]
|
||||
(wallet_name, wallet_path) = self._wallets[index.row()]
|
||||
role_index = role - Qt.UserRole
|
||||
role_name = self._ROLE_NAMES[role_index]
|
||||
if role_name == 'name':
|
||||
@@ -58,7 +59,7 @@ class QEWalletListModel(QAbstractListModel):
|
||||
def reload(self):
|
||||
self._logger.debug('enumerating available wallets')
|
||||
self.beginResetModel()
|
||||
self.wallets = []
|
||||
self._wallets = []
|
||||
self.endResetModel()
|
||||
|
||||
available = []
|
||||
@@ -72,18 +73,18 @@ class QEWalletListModel(QAbstractListModel):
|
||||
self.add_wallet(wallet_path = path)
|
||||
|
||||
def add_wallet(self, wallet_path):
|
||||
self.beginInsertRows(QModelIndex(), len(self.wallets), len(self.wallets))
|
||||
self.beginInsertRows(QModelIndex(), len(self._wallets), len(self._wallets))
|
||||
wallet_name = os.path.basename(wallet_path)
|
||||
wallet_path = standardize_path(wallet_path)
|
||||
item = (wallet_name, wallet_path)
|
||||
self.wallets.append(item)
|
||||
self._wallets.append(item)
|
||||
self.endInsertRows()
|
||||
|
||||
def remove_wallet(self, path):
|
||||
i = 0
|
||||
wallets = []
|
||||
remove = -1
|
||||
for wallet_name, wallet_path in self.wallets:
|
||||
for wallet_name, wallet_path in self._wallets:
|
||||
if wallet_path == path:
|
||||
remove = i
|
||||
else:
|
||||
@@ -92,12 +93,12 @@ class QEWalletListModel(QAbstractListModel):
|
||||
|
||||
if remove >= 0:
|
||||
self.beginRemoveRows(QModelIndex(), i, i)
|
||||
self.wallets = wallets
|
||||
self._wallets = wallets
|
||||
self.endRemoveRows()
|
||||
|
||||
@pyqtSlot(str, result=bool)
|
||||
def wallet_name_exists(self, name):
|
||||
for wallet_name, wallet_path in self.wallets:
|
||||
for wallet_name, wallet_path in self._wallets:
|
||||
if name == wallet_name:
|
||||
return True
|
||||
return False
|
||||
@@ -105,7 +106,7 @@ class QEWalletListModel(QAbstractListModel):
|
||||
@pyqtSlot(str)
|
||||
def updateWallet(self, path):
|
||||
i = 0
|
||||
for wallet_name, wallet_path in self.wallets:
|
||||
for wallet_name, wallet_path in self._wallets:
|
||||
if wallet_path == path:
|
||||
mi = self.createIndex(i, i)
|
||||
self.dataChanged.emit(mi, mi, self._ROLE_KEYS)
|
||||
@@ -166,7 +167,7 @@ class QEDaemon(AuthMixin, QObject):
|
||||
@pyqtSlot(str, str)
|
||||
def loadWallet(self, path=None, password=None):
|
||||
if path is None:
|
||||
self._path = self.daemon.config.get('wallet_path') # command line -w option
|
||||
self._path = self.daemon.config.get('wallet_path') # command line -w option
|
||||
if self._path is None:
|
||||
self._path = self.daemon.config.GUI_LAST_WALLET
|
||||
else:
|
||||
@@ -201,7 +202,7 @@ class QEDaemon(AuthMixin, QObject):
|
||||
self.loadingChanged.emit()
|
||||
|
||||
try:
|
||||
local_password = password # need this in local scope
|
||||
local_password = password # need this in local scope
|
||||
wallet = self.daemon.load_wallet(self._path, local_password)
|
||||
|
||||
if wallet is None:
|
||||
@@ -238,7 +239,7 @@ class QEDaemon(AuthMixin, QObject):
|
||||
|
||||
@pyqtSlot()
|
||||
@pyqtSlot(str)
|
||||
def _on_backend_wallet_loaded(self, password = None):
|
||||
def _on_backend_wallet_loaded(self, password=None):
|
||||
self._logger.debug('_on_backend_wallet_loaded')
|
||||
wallet = self.daemon.get_wallet(self._path)
|
||||
assert wallet is not None
|
||||
@@ -247,7 +248,6 @@ class QEDaemon(AuthMixin, QObject):
|
||||
self._current_wallet.password = password if password else None
|
||||
self.walletLoaded.emit(self._name, self._path)
|
||||
|
||||
|
||||
@pyqtSlot(QEWallet)
|
||||
@pyqtSlot(QEWallet, bool)
|
||||
@pyqtSlot(QEWallet, bool, bool)
|
||||
|
||||
@@ -11,6 +11,7 @@ from electrum.simple_config import SimpleConfig
|
||||
from .qetypes import QEAmount
|
||||
from .util import QtEventListener, event_listener
|
||||
|
||||
|
||||
class QEFX(QObject, QtEventListener):
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
@@ -94,7 +95,7 @@ class QEFX(QObject, QtEventListener):
|
||||
self.fx.set_exchange(source)
|
||||
self.rateSourceChanged.emit()
|
||||
|
||||
enabledUpdated = pyqtSignal() # curiously, enabledChanged is clashing, so name it enabledUpdated
|
||||
enabledUpdated = pyqtSignal() # curiously, enabledChanged is clashing, so name it enabledUpdated
|
||||
@pyqtProperty(bool, notify=enabledUpdated)
|
||||
def enabled(self):
|
||||
return self.fx.is_enabled()
|
||||
|
||||
@@ -275,7 +275,7 @@ class QEInvoice(QObject, QtEventListener):
|
||||
self._timer.start()
|
||||
else:
|
||||
self.update_userinfo()
|
||||
self.determine_can_pay() # status went to PR_EXPIRED
|
||||
self.determine_can_pay() # status went to PR_EXPIRED
|
||||
|
||||
@pyqtSlot()
|
||||
def updateStatusString(self):
|
||||
@@ -293,7 +293,7 @@ class QEInvoice(QObject, QtEventListener):
|
||||
if self.amount.isEmpty:
|
||||
self.userinfo = _('Enter the amount you want to send')
|
||||
|
||||
if amount.isEmpty and self.status == PR_UNPAID: # unspecified amount
|
||||
if amount.isEmpty and self.status == PR_UNPAID: # unspecified amount
|
||||
return
|
||||
|
||||
if self.invoiceType == QEInvoice.Type.LightningInvoice:
|
||||
@@ -403,6 +403,7 @@ class QEInvoiceParser(QEInvoice):
|
||||
|
||||
self._recipient = ''
|
||||
self._pi = None
|
||||
self._lnurlData = None
|
||||
|
||||
self.clear()
|
||||
|
||||
@@ -476,7 +477,7 @@ class QEInvoiceParser(QEInvoice):
|
||||
self.setValidOnchainInvoice(invoice)
|
||||
self.validationSuccess.emit()
|
||||
else:
|
||||
self.validationError.emit('unknown', f"invoice error:\n{pr.error}")
|
||||
self.validationError.emit('unknown', f'invoice error:\n{pr.error}')
|
||||
|
||||
def validateRecipient(self, recipient):
|
||||
if not recipient:
|
||||
@@ -485,7 +486,8 @@ class QEInvoiceParser(QEInvoice):
|
||||
|
||||
self._pi = PaymentIdentifier(self._wallet.wallet, recipient)
|
||||
if not self._pi.is_valid() or self._pi.type not in [PaymentIdentifierType.SPK, PaymentIdentifierType.BIP21,
|
||||
PaymentIdentifierType.BIP70, PaymentIdentifierType.BOLT11, PaymentIdentifierType.LNURLP]:
|
||||
PaymentIdentifierType.BIP70, PaymentIdentifierType.BOLT11,
|
||||
PaymentIdentifierType.LNURLP]:
|
||||
self.validationError.emit('unknown', _('Unknown invoice'))
|
||||
return
|
||||
|
||||
@@ -552,6 +554,7 @@ class QEInvoiceParser(QEInvoice):
|
||||
|
||||
def resolve_pi(self):
|
||||
assert self._pi.need_resolve()
|
||||
|
||||
def on_finished(pi):
|
||||
if pi.is_error():
|
||||
pass
|
||||
@@ -604,7 +607,7 @@ class QEInvoiceParser(QEInvoice):
|
||||
|
||||
# assure no shenanigans with the bolt11 invoice we get back
|
||||
lninvoice = Invoice.from_bech32(invoice)
|
||||
if orig_amount * 1000 != lninvoice.amount_msat: # TODO msat precision can cause trouble here
|
||||
if orig_amount * 1000 != lninvoice.amount_msat: # TODO msat precision can cause trouble here
|
||||
raise Exception('Unexpected amount in invoice, differs from lnurl-pay specified amount')
|
||||
|
||||
self.recipient = invoice
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from abc import abstractmethod
|
||||
from typing import TYPE_CHECKING, List, Dict, Any
|
||||
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer
|
||||
from PyQt5.QtCore import pyqtSlot, QTimer
|
||||
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
|
||||
|
||||
from electrum.logging import get_logger
|
||||
@@ -29,6 +29,7 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
|
||||
def __init__(self, wallet: 'Abstract_Wallet', parent=None):
|
||||
super().__init__(parent)
|
||||
self.wallet = wallet
|
||||
self._invoices = []
|
||||
|
||||
self._timer = QTimer(self)
|
||||
self._timer.setSingleShot(True)
|
||||
@@ -41,13 +42,13 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
|
||||
raise e
|
||||
|
||||
def rowCount(self, index):
|
||||
return len(self.invoices)
|
||||
return len(self._invoices)
|
||||
|
||||
def roleNames(self):
|
||||
return self._ROLE_MAP
|
||||
|
||||
def data(self, index, role):
|
||||
invoice = self.invoices[index.row()]
|
||||
invoice = self._invoices[index.row()]
|
||||
role_index = role - Qt.UserRole
|
||||
value = invoice[self._ROLE_NAMES[role_index]]
|
||||
|
||||
@@ -59,7 +60,7 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
|
||||
|
||||
def clear(self):
|
||||
self.beginResetModel()
|
||||
self.invoices = []
|
||||
self._invoices = []
|
||||
self.endResetModel()
|
||||
|
||||
@pyqtSlot()
|
||||
@@ -71,7 +72,7 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
|
||||
|
||||
self.clear()
|
||||
self.beginInsertRows(QModelIndex(), 0, len(invoices) - 1)
|
||||
self.invoices = invoices
|
||||
self._invoices = invoices
|
||||
self.endInsertRows()
|
||||
|
||||
self.set_status_timer()
|
||||
@@ -79,7 +80,7 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
|
||||
def add_invoice(self, invoice: BaseInvoice):
|
||||
# skip if already in list
|
||||
key = invoice.get_id()
|
||||
for x in self.invoices:
|
||||
for x in self._invoices:
|
||||
if x['key'] == key:
|
||||
return
|
||||
|
||||
@@ -87,7 +88,7 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
|
||||
self._logger.debug(str(item))
|
||||
|
||||
self.beginInsertRows(QModelIndex(), 0, 0)
|
||||
self.invoices.insert(0, item)
|
||||
self._invoices.insert(0, item)
|
||||
self.endInsertRows()
|
||||
|
||||
self.set_status_timer()
|
||||
@@ -97,29 +98,29 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
|
||||
self.add_invoice(self.get_invoice_for_key(key))
|
||||
|
||||
def delete_invoice(self, key: str):
|
||||
for i, invoice in enumerate(self.invoices):
|
||||
for i, invoice in enumerate(self._invoices):
|
||||
if invoice['key'] == key:
|
||||
self.beginRemoveRows(QModelIndex(), i, i)
|
||||
self.invoices.pop(i)
|
||||
self._invoices.pop(i)
|
||||
self.endRemoveRows()
|
||||
break
|
||||
self.set_status_timer()
|
||||
|
||||
def get_model_invoice(self, key: str):
|
||||
for invoice in self.invoices:
|
||||
for invoice in self._invoices:
|
||||
if invoice['key'] == key:
|
||||
return invoice
|
||||
return None
|
||||
|
||||
@pyqtSlot(str, int)
|
||||
def updateInvoice(self, key, status):
|
||||
self._logger.debug('updating invoice for %s to %d' % (key,status))
|
||||
for i, item in enumerate(self.invoices):
|
||||
self._logger.debug(f'updating invoice for {key} to {status}')
|
||||
for i, item in enumerate(self._invoices):
|
||||
if item['key'] == key:
|
||||
invoice = self.get_invoice_for_key(key)
|
||||
item['status'] = status
|
||||
item['status_str'] = invoice.get_status_str(status)
|
||||
index = self.index(i,0)
|
||||
index = self.index(i, 0)
|
||||
self.dataChanged.emit(index, index, [self._ROLE_RMAP['status'], self._ROLE_RMAP['status_str']])
|
||||
return
|
||||
|
||||
@@ -137,7 +138,7 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
|
||||
|
||||
def set_status_timer(self):
|
||||
nearest_interval = LN_EXPIRY_NEVER
|
||||
for invoice in self.invoices:
|
||||
for invoice in self._invoices:
|
||||
if invoice['status'] != PR_EXPIRED:
|
||||
if invoice['expiry'] > 0 and invoice['expiry'] != LN_EXPIRY_NEVER:
|
||||
interval = status_update_timer_interval(invoice['timestamp'] + invoice['expiry'])
|
||||
@@ -150,11 +151,11 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
|
||||
|
||||
@pyqtSlot()
|
||||
def updateStatusStrings(self):
|
||||
for i, item in enumerate(self.invoices):
|
||||
for i, item in enumerate(self._invoices):
|
||||
invoice = self.get_invoice_for_key(item['key'])
|
||||
item['status'] = self.wallet.get_invoice_status(invoice)
|
||||
item['status_str'] = invoice.get_status_str(item['status'])
|
||||
index = self.index(i,0)
|
||||
index = self.index(i, 0)
|
||||
self.dataChanged.emit(index, index, [self._ROLE_RMAP['status'], self._ROLE_RMAP['status_str']])
|
||||
|
||||
self.set_status_timer()
|
||||
@@ -206,6 +207,7 @@ class QEInvoiceListModel(QEAbstractInvoiceListModel, QtEventListener):
|
||||
def get_invoice_as_dict(self, invoice: Invoice):
|
||||
return self.wallet.export_invoice(invoice)
|
||||
|
||||
|
||||
class QERequestListModel(QEAbstractInvoiceListModel, QtEventListener):
|
||||
def __init__(self, wallet, parent=None):
|
||||
super().__init__(wallet, parent)
|
||||
|
||||
@@ -45,7 +45,7 @@ class QELnPaymentDetails(QObject):
|
||||
@key.setter
|
||||
def key(self, key: str):
|
||||
if self._key != key:
|
||||
self._logger.debug('key set -> %s' % key)
|
||||
self._logger.debug(f'key set -> {key}')
|
||||
self._key = key
|
||||
self.keyChanged.emit()
|
||||
self.update()
|
||||
@@ -104,7 +104,7 @@ class QELnPaymentDetails(QObject):
|
||||
self._label = tx['label']
|
||||
self._date = format_time(tx['timestamp'])
|
||||
self._timestamp = tx['timestamp']
|
||||
self._status = 'settled' # TODO: other states? get_lightning_history is deciding the filter for us :(
|
||||
self._status = 'settled' # TODO: other states? get_lightning_history is deciding the filter for us :(
|
||||
self._phash = tx['payment_hash']
|
||||
self._preimage = tx['preimage']
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject
|
||||
|
||||
from electrum.logging import get_logger
|
||||
from electrum import constants
|
||||
@@ -173,12 +173,11 @@ class QENetwork(QObject, QtEventListener):
|
||||
|
||||
@event_listener
|
||||
def on_event_unknown_channels(self, unknown):
|
||||
if unknown == 0 and self._gossipUnknownChannels == 0: # TODO: backend sends a lot of unknown=0 events
|
||||
if unknown == 0 and self._gossipUnknownChannels == 0: # TODO: backend sends a lot of unknown=0 events
|
||||
return
|
||||
self._logger.debug(f'unknown channels {unknown}')
|
||||
self._gossipUnknownChannels = unknown
|
||||
self.gossipUpdated.emit()
|
||||
#self.lightning_gossip_num_queries = unknown
|
||||
|
||||
def on_gossip_setting_changed(self):
|
||||
if not self.network:
|
||||
@@ -205,7 +204,8 @@ class QENetwork(QObject, QtEventListener):
|
||||
net_params = self.network.get_parameters()
|
||||
try:
|
||||
server = ServerAddr.from_str_with_inference(server)
|
||||
if not server: raise Exception("failed to parse")
|
||||
if not server:
|
||||
raise Exception('failed to parse')
|
||||
except Exception:
|
||||
return
|
||||
net_params = net_params._replace(server=server, auto_connect=self._qeconfig.autoConnect)
|
||||
@@ -215,7 +215,7 @@ class QENetwork(QObject, QtEventListener):
|
||||
def serverWithStatus(self):
|
||||
server = self._server
|
||||
if not self.network.is_connected(): # connecting or disconnected
|
||||
return f"{server} (connecting...)"
|
||||
return f'{server} (connecting...)'
|
||||
return server
|
||||
|
||||
@pyqtProperty(str, notify=statusChanged)
|
||||
@@ -244,7 +244,7 @@ class QENetwork(QObject, QtEventListener):
|
||||
|
||||
@pyqtProperty(str, notify=dataChanged)
|
||||
def networkName(self):
|
||||
return constants.net.__name__.replace('Bitcoin','')
|
||||
return constants.net.__name__.replace('Bitcoin', '')
|
||||
|
||||
@pyqtProperty('QVariantMap', notify=proxyChanged)
|
||||
def proxy(self):
|
||||
@@ -275,7 +275,7 @@ class QENetwork(QObject, QtEventListener):
|
||||
'peers': self._gossipPeers,
|
||||
'unknown_channels': self._gossipUnknownChannels,
|
||||
'db_nodes': self._gossipDbNodes,
|
||||
'db_channels': self._gossipDbChannels ,
|
||||
'db_channels': self._gossipDbChannels,
|
||||
'db_policies': self._gossipDbPolicies
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ from electrum.qrreader import get_qr_reader
|
||||
from electrum.i18n import _
|
||||
from electrum.util import profiler, get_asyncio_loop
|
||||
|
||||
|
||||
class QEQRParser(QObject):
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
@@ -28,6 +29,7 @@ class QEQRParser(QObject):
|
||||
|
||||
self._busy = False
|
||||
self._image = None
|
||||
self._data = None
|
||||
|
||||
self._text = text
|
||||
self.qrreader = get_qr_reader()
|
||||
@@ -118,10 +120,12 @@ class QEQRParser(QObject):
|
||||
result.append(QPoint(x+self.scan_pos_x, y+self.scan_pos_y))
|
||||
return result
|
||||
|
||||
|
||||
class QEQRImageProvider(QQuickImageProvider):
|
||||
def __init__(self, max_size, parent=None):
|
||||
super().__init__(QQuickImageProvider.Image)
|
||||
self._max_size = max_size
|
||||
self.qimg = None
|
||||
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
@@ -161,6 +165,7 @@ class QEQRImageProvider(QQuickImageProvider):
|
||||
self.qimg.fill(QColor('gray'))
|
||||
return self.qimg, self.qimg.size()
|
||||
|
||||
|
||||
# helper for placing icon exactly where it should go on the QR code
|
||||
# pyqt5 is unwilling to accept slots on QEQRImageProvider, so we need to define
|
||||
# a separate class (sigh)
|
||||
@@ -187,6 +192,11 @@ class QEQRImageProviderHelper(QObject):
|
||||
qr.box_size = math.floor(pixelsize/modules)
|
||||
# calculate icon width in modules
|
||||
icon_modules = int(modules / 5)
|
||||
icon_modules += (icon_modules+1)%2 # force odd
|
||||
icon_modules += (icon_modules+1) % 2 # force odd
|
||||
|
||||
return { 'modules': modules, 'box_size': qr.box_size, 'icon_modules': icon_modules, 'valid' : valid }
|
||||
return {
|
||||
'modules': modules,
|
||||
'box_size': qr.box_size,
|
||||
'icon_modules': icon_modules,
|
||||
'valid': valid
|
||||
}
|
||||
|
||||
@@ -83,7 +83,6 @@ class QERequestDetails(QObject, QtEventListener):
|
||||
self.keyChanged.emit()
|
||||
self.initRequest()
|
||||
|
||||
statusChanged = pyqtSignal()
|
||||
@pyqtProperty(int, notify=statusChanged)
|
||||
def status(self):
|
||||
return self._wallet.wallet.get_invoice_status(self._req)
|
||||
@@ -133,7 +132,6 @@ class QERequestDetails(QObject, QtEventListener):
|
||||
def bip21(self):
|
||||
return self._req.get_bip21_URI() if self._req else ''
|
||||
|
||||
|
||||
def initRequest(self):
|
||||
if self._wallet is None or self._key is None:
|
||||
return
|
||||
@@ -160,7 +158,6 @@ class QERequestDetails(QObject, QtEventListener):
|
||||
self._timer.setInterval(interval) # msec
|
||||
self._timer.start()
|
||||
|
||||
|
||||
@pyqtSlot()
|
||||
def updateStatusString(self):
|
||||
self.statusChanged.emit()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
|
||||
|
||||
from electrum.logging import get_logger
|
||||
from electrum.util import Satoshis, format_time
|
||||
from electrum.util import Satoshis
|
||||
from electrum.interface import ServerAddr, PREFERRED_NETWORK_PROTOCOL
|
||||
from electrum import blockchain
|
||||
|
||||
@@ -22,6 +22,7 @@ class QEServerListModel(QAbstractListModel, QtEventListener):
|
||||
super().__init__(parent)
|
||||
|
||||
self._chaintips = 0
|
||||
self._servers = []
|
||||
|
||||
self.network = network
|
||||
self.initModel()
|
||||
@@ -44,13 +45,13 @@ class QEServerListModel(QAbstractListModel, QtEventListener):
|
||||
self.initModel()
|
||||
|
||||
def rowCount(self, index):
|
||||
return len(self.servers)
|
||||
return len(self._servers)
|
||||
|
||||
def roleNames(self):
|
||||
return self._ROLE_MAP
|
||||
|
||||
def data(self, index, role):
|
||||
server = self.servers[index.row()]
|
||||
server = self._servers[index.row()]
|
||||
role_index = role - Qt.UserRole
|
||||
value = server[self._ROLE_NAMES[role_index]]
|
||||
|
||||
@@ -62,7 +63,7 @@ class QEServerListModel(QAbstractListModel, QtEventListener):
|
||||
|
||||
def clear(self):
|
||||
self.beginResetModel()
|
||||
self.servers = []
|
||||
self._servers = []
|
||||
self.endResetModel()
|
||||
|
||||
chaintipsChanged = pyqtSignal()
|
||||
@@ -97,14 +98,15 @@ class QEServerListModel(QAbstractListModel, QtEventListener):
|
||||
self._logger.debug(f'chain {chain_id} has name={name}, max_forkpoint=@{b.get_max_forkpoint()}, height={b.height()}')
|
||||
|
||||
for i in interfaces:
|
||||
server = {}
|
||||
server['chain'] = name
|
||||
server['chain_height'] = b.height()
|
||||
server['is_primary'] = i == self.network.interface
|
||||
server['is_connected'] = True
|
||||
server['name'] = str(i.server)
|
||||
server['address'] = i.server.to_friendly_name()
|
||||
server['height'] = i.tip
|
||||
server = {
|
||||
'chain': name,
|
||||
'chain_height': b.height(),
|
||||
'is_primary': i == self.network.interface,
|
||||
'is_connected': True,
|
||||
'name': str(i.server),
|
||||
'address': i.server.to_friendly_name(),
|
||||
'height': i.tip
|
||||
}
|
||||
|
||||
servers.append(server)
|
||||
|
||||
@@ -120,17 +122,18 @@ class QEServerListModel(QAbstractListModel, QtEventListener):
|
||||
port = d.get(protocol)
|
||||
if port:
|
||||
s = ServerAddr(_host, port, protocol=protocol)
|
||||
server = {}
|
||||
server['chain'] = ''
|
||||
server['chain_height'] = 0
|
||||
server['height'] = 0
|
||||
server['is_primary'] = False
|
||||
server['is_connected'] = False
|
||||
server['name'] = s.net_addr_str()
|
||||
server = {
|
||||
'chain': '',
|
||||
'chain_height': 0,
|
||||
'height': 0,
|
||||
'is_primary': False,
|
||||
'is_connected': False,
|
||||
'name': s.net_addr_str()
|
||||
}
|
||||
server['address'] = server['name']
|
||||
|
||||
servers.append(server)
|
||||
|
||||
self.beginInsertRows(QModelIndex(), 0, len(servers) - 1)
|
||||
self.servers = servers
|
||||
self._servers = servers
|
||||
self.endInsertRows()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from datetime import datetime, timedelta
|
||||
from typing import TYPE_CHECKING, Dict, Any
|
||||
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
|
||||
|
||||
from electrum.logging import get_logger
|
||||
@@ -19,9 +19,9 @@ class QETransactionListModel(QAbstractListModel, QtEventListener):
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
# define listmodel rolemap
|
||||
_ROLE_NAMES=('txid','fee_sat','height','confirmations','timestamp','monotonic_timestamp',
|
||||
'incoming','value','date','label','txpos_in_block','fee',
|
||||
'inputs','outputs','section','type','lightning','payment_hash','key','complete')
|
||||
_ROLE_NAMES=('txid', 'fee_sat', 'height', 'confirmations', 'timestamp', 'monotonic_timestamp',
|
||||
'incoming', 'value', '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))
|
||||
@@ -34,11 +34,13 @@ class QETransactionListModel(QAbstractListModel, QtEventListener):
|
||||
self.onchain_domain = onchain_domain
|
||||
self.include_lightning = include_lightning
|
||||
|
||||
self.tx_history = []
|
||||
|
||||
self.register_callbacks()
|
||||
self.destroyed.connect(lambda: self.on_destroy())
|
||||
self.requestRefresh.connect(lambda: self.initModel())
|
||||
|
||||
self.setDirty()
|
||||
self._dirty = True
|
||||
self.initModel()
|
||||
|
||||
def on_destroy(self):
|
||||
@@ -159,19 +161,19 @@ class QETransactionListModel(QAbstractListModel, QtEventListener):
|
||||
txts = datetime.fromtimestamp(timestamp)
|
||||
today = datetime.today().replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
if (txts > today):
|
||||
if txts > today:
|
||||
return 'today'
|
||||
elif (txts > today - timedelta(days=1)):
|
||||
elif txts > today - timedelta(days=1):
|
||||
return 'yesterday'
|
||||
elif (txts > today - timedelta(days=7)):
|
||||
elif txts > today - timedelta(days=7):
|
||||
return 'lastweek'
|
||||
elif (txts > today - timedelta(days=31)):
|
||||
elif txts > today - timedelta(days=31):
|
||||
return 'lastmonth'
|
||||
else:
|
||||
return 'older'
|
||||
|
||||
def format_date_by_section(self, section, date):
|
||||
#TODO: l10n
|
||||
# TODO: l10n
|
||||
dfmt = {
|
||||
'today': '%H:%M:%S',
|
||||
'yesterday': '%H:%M:%S',
|
||||
@@ -194,7 +196,6 @@ class QETransactionListModel(QAbstractListModel, QtEventListener):
|
||||
)
|
||||
return tx_mined_info
|
||||
|
||||
# initial model data
|
||||
@pyqtSlot()
|
||||
@pyqtSlot(bool)
|
||||
def initModel(self, force: bool = False):
|
||||
@@ -231,7 +232,7 @@ class QETransactionListModel(QAbstractListModel, QtEventListener):
|
||||
tx['section'] = self.get_section_by_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 ['section','height','confirmations','timestamp','date']]
|
||||
roles = [self._ROLE_RMAP[x] for x in ['section', 'height', 'confirmations', 'timestamp', 'date']]
|
||||
self.dataChanged.emit(index, index, roles)
|
||||
return
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
|
||||
|
||||
from electrum.i18n import _
|
||||
from electrum.logging import get_logger
|
||||
from electrum.util import format_time, AddTransactionException, TxMinedInfo
|
||||
from electrum.util import format_time, TxMinedInfo
|
||||
from electrum.transaction import tx_from_any, Transaction
|
||||
from electrum.network import Network
|
||||
|
||||
@@ -12,6 +12,7 @@ from .qewallet import QEWallet
|
||||
from .qetypes import QEAmount
|
||||
from .util import QtEventListener, event_listener
|
||||
|
||||
|
||||
class QETxDetails(QObject, QtEventListener):
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
@@ -68,13 +69,13 @@ class QETxDetails(QObject, QtEventListener):
|
||||
@event_listener
|
||||
def on_event_verified(self, wallet, txid, info):
|
||||
if wallet == self._wallet.wallet and txid == self._txid:
|
||||
self._logger.debug('verified event for our txid %s' % txid)
|
||||
self._logger.debug(f'verified event for our txid {txid}')
|
||||
self.update()
|
||||
|
||||
@event_listener
|
||||
def on_event_new_transaction(self, wallet, tx):
|
||||
if wallet == self._wallet.wallet and tx.txid() == self._txid:
|
||||
self._logger.debug('new_transaction event for our txid %s' % self._txid)
|
||||
self._logger.debug(f'new_transaction event for our txid {txid}')
|
||||
self.update()
|
||||
|
||||
walletChanged = pyqtSignal()
|
||||
@@ -292,7 +293,7 @@ class QETxDetails(QObject, QtEventListener):
|
||||
group_id = item.get('group_id')
|
||||
if group_id:
|
||||
full_history = self._wallet.wallet.get_full_history()
|
||||
group_item = full_history['group:'+ group_id]
|
||||
group_item = full_history['group:' + group_id]
|
||||
self._lnamount.satsInt = int(group_item['ln_value'].value)
|
||||
else:
|
||||
self._lnamount.satsInt = int(item['amount_msat'] / 1000)
|
||||
|
||||
@@ -287,11 +287,11 @@ class QETxFinalizer(TxFeeSlider):
|
||||
if self._canRbf != canRbf:
|
||||
self._canRbf = canRbf
|
||||
self.canRbfChanged.emit()
|
||||
self.rbf = self._canRbf # if we can RbF, we do RbF
|
||||
self.rbf = self._canRbf # if we can RbF, we do RbF
|
||||
|
||||
@profiler
|
||||
def make_tx(self, amount):
|
||||
self._logger.debug('make_tx amount = %s' % str(amount))
|
||||
self._logger.debug(f'make_tx amount={amount}')
|
||||
|
||||
if self.f_make_tx:
|
||||
tx = self.f_make_tx(amount)
|
||||
@@ -299,7 +299,7 @@ class QETxFinalizer(TxFeeSlider):
|
||||
# default impl
|
||||
coins = self._wallet.wallet.get_spendable_coins(None)
|
||||
outputs = [PartialTxOutput.from_address_and_value(self.address, amount)]
|
||||
tx = self._wallet.wallet.make_unsigned_transaction(coins=coins,outputs=outputs, fee=None,rbf=self._rbf)
|
||||
tx = self._wallet.wallet.make_unsigned_transaction(coins=coins, outputs=outputs, fee=None, rbf=self._rbf)
|
||||
|
||||
self._logger.debug('fee: %d, inputs: %d, outputs: %d' % (tx.get_fee(), len(tx.inputs()), len(tx.outputs())))
|
||||
|
||||
@@ -312,7 +312,7 @@ class QETxFinalizer(TxFeeSlider):
|
||||
|
||||
try:
|
||||
# make unsigned transaction
|
||||
tx = self.make_tx(amount = '!' if self._amount.isMax else self._amount.satsInt)
|
||||
tx = self.make_tx(amount='!' if self._amount.isMax else self._amount.satsInt)
|
||||
except NotEnoughFunds:
|
||||
self.warning = _("Not enough funds")
|
||||
self._valid = False
|
||||
@@ -373,10 +373,7 @@ class QETxFinalizer(TxFeeSlider):
|
||||
self.f_accept(self._tx)
|
||||
return
|
||||
|
||||
self._wallet.sign(self._tx,
|
||||
broadcast=True,
|
||||
on_success=partial(self.on_signed_tx, False)
|
||||
)
|
||||
self._wallet.sign(self._tx, broadcast=True, on_success=partial(self.on_signed_tx, False))
|
||||
|
||||
@pyqtSlot()
|
||||
def sign(self):
|
||||
@@ -384,10 +381,7 @@ class QETxFinalizer(TxFeeSlider):
|
||||
self._logger.error('no valid tx')
|
||||
return
|
||||
|
||||
self._wallet.sign(self._tx,
|
||||
broadcast=False,
|
||||
on_success=partial(self.on_signed_tx, True)
|
||||
)
|
||||
self._wallet.sign(self._tx, broadcast=False, on_success=partial(self.on_signed_tx, True))
|
||||
|
||||
def on_signed_tx(self, save: bool, tx: Transaction):
|
||||
self._logger.debug('on_signed_tx')
|
||||
@@ -405,12 +399,13 @@ class QETxFinalizer(TxFeeSlider):
|
||||
return [str(self._tx), txqr[0], txqr[1]]
|
||||
|
||||
|
||||
# mixin for watching an existing TX based on its txid for verified event
|
||||
# requires self._wallet to contain a QEWallet instance
|
||||
# exposes txid qt property
|
||||
# calls get_tx() once txid is set
|
||||
# calls tx_verified and emits txMined signal once tx is verified
|
||||
class TxMonMixin(QtEventListener):
|
||||
""" mixin for watching an existing TX based on its txid for verified event.
|
||||
requires self._wallet to contain a QEWallet instance.
|
||||
exposes txid qt property.
|
||||
calls get_tx() once txid is set.
|
||||
calls tx_verified and emits txMined signal once tx is verified.
|
||||
"""
|
||||
txMined = pyqtSignal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
@@ -505,7 +500,6 @@ class QETxRbfFeeBumper(TxFeeSlider, TxMonMixin):
|
||||
self.bumpMethodChanged.emit()
|
||||
self.update()
|
||||
|
||||
|
||||
def get_tx(self):
|
||||
assert self._txid
|
||||
self._orig_tx = self._wallet.wallet.db.get_transaction(self._txid)
|
||||
@@ -783,7 +777,7 @@ class QETxCpfpFeeBumper(TxFeeSlider, TxMonMixin):
|
||||
return fee
|
||||
|
||||
def update(self):
|
||||
if not self._txid: # not initialized yet
|
||||
if not self._txid: # not initialized yet
|
||||
return
|
||||
|
||||
assert self._parent_tx
|
||||
|
||||
@@ -11,10 +11,11 @@ from electrum.i18n import _
|
||||
# should also capture millisats amounts and MAX/'!' indicators
|
||||
# and (unformatted) string representations
|
||||
|
||||
|
||||
class QEAmount(QObject):
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
def __init__(self, *, amount_sat: int = 0, amount_msat: int = 0, is_max: bool = False, from_invoice = None, parent=None):
|
||||
def __init__(self, *, amount_sat: int = 0, amount_msat: int = 0, is_max: bool = False, from_invoice=None, parent=None):
|
||||
super().__init__(parent)
|
||||
self._amount_sat = int(amount_sat) if amount_sat is not None else None
|
||||
self._amount_msat = int(amount_msat) if amount_msat is not None else None
|
||||
@@ -31,7 +32,7 @@ class QEAmount(QObject):
|
||||
|
||||
@pyqtProperty('qint64', notify=valueChanged)
|
||||
def satsInt(self):
|
||||
if self._amount_sat is None: # should normally be defined when accessing this property
|
||||
if self._amount_sat is None: # should normally be defined when accessing this property
|
||||
self._logger.warning('amount_sat is undefined, returning 0')
|
||||
return 0
|
||||
return self._amount_sat
|
||||
@@ -44,7 +45,7 @@ class QEAmount(QObject):
|
||||
|
||||
@pyqtProperty('qint64', notify=valueChanged)
|
||||
def msatsInt(self):
|
||||
if self._amount_msat is None: # should normally be defined when accessing this property
|
||||
if self._amount_msat is None: # should normally be defined when accessing this property
|
||||
self._logger.warning('amount_msat is undefined, returning 0')
|
||||
return 0
|
||||
return self._amount_msat
|
||||
@@ -86,7 +87,7 @@ class QEAmount(QObject):
|
||||
|
||||
def copyFrom(self, amount):
|
||||
if not amount:
|
||||
self._logger.warning('copyFrom with None argument. assuming 0') # TODO
|
||||
self._logger.warning('copyFrom with None argument. assuming 0') # TODO
|
||||
amount = QEAmount()
|
||||
self.satsInt = amount.satsInt
|
||||
self.msatsInt = amount.msatsInt
|
||||
|
||||
@@ -2,18 +2,17 @@ import asyncio
|
||||
import queue
|
||||
import threading
|
||||
import time
|
||||
from typing import TYPE_CHECKING, Optional, Tuple, Callable
|
||||
from typing import TYPE_CHECKING, Callable
|
||||
from functools import partial
|
||||
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer, QMetaObject, Qt
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer
|
||||
|
||||
from electrum import bitcoin
|
||||
from electrum.i18n import _
|
||||
from electrum.invoices import InvoiceError, PR_DEFAULT_EXPIRATION_WHEN_CREATING, PR_PAID, PR_BROADCASTING, PR_BROADCAST
|
||||
from electrum.invoices import InvoiceError, PR_PAID, PR_BROADCASTING, PR_BROADCAST
|
||||
from electrum.logging import get_logger
|
||||
from electrum.network import TxBroadcastError, BestEffortRequestFailed
|
||||
from electrum.transaction import PartialTxOutput, PartialTransaction, Transaction
|
||||
from electrum.util import parse_max_spend, InvalidPassword, event_listener, AddTransactionException, get_asyncio_loop
|
||||
from electrum.transaction import PartialTransaction, Transaction
|
||||
from electrum.util import InvalidPassword, event_listener, AddTransactionException, get_asyncio_loop
|
||||
from electrum.plugin import run_hook
|
||||
from electrum.wallet import Multisig_Wallet
|
||||
from electrum.crypto import pw_decode_with_version_and_mac
|
||||
@@ -30,6 +29,7 @@ if TYPE_CHECKING:
|
||||
from electrum.wallet import Abstract_Wallet
|
||||
from .qeinvoice import QEInvoice
|
||||
|
||||
|
||||
class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
__instances = []
|
||||
|
||||
@@ -53,12 +53,14 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
# shared signal for many static wallet properties
|
||||
dataChanged = pyqtSignal()
|
||||
|
||||
balanceChanged = pyqtSignal()
|
||||
requestStatusChanged = pyqtSignal([str,int], arguments=['key','status'])
|
||||
requestCreateSuccess = pyqtSignal([str], arguments=['key'])
|
||||
requestCreateError = pyqtSignal([str], arguments=['error'])
|
||||
invoiceStatusChanged = pyqtSignal([str,int], arguments=['key','status'])
|
||||
invoiceCreateSuccess = pyqtSignal()
|
||||
invoiceCreateError = pyqtSignal([str,str], arguments=['code','error'])
|
||||
paymentAuthRejected = pyqtSignal()
|
||||
paymentSucceeded = pyqtSignal([str], arguments=['key'])
|
||||
paymentFailed = pyqtSignal([str,str], arguments=['key','reason'])
|
||||
requestNewPassword = pyqtSignal()
|
||||
@@ -196,7 +198,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
if wallet == self.wallet:
|
||||
self._logger.info(f'removed transaction {tx.txid()}')
|
||||
self.addressModel.setDirty()
|
||||
self.historyModel.initModel(True) #setDirty()
|
||||
self.historyModel.initModel(True) # setDirty()?
|
||||
self.balanceChanged.emit()
|
||||
|
||||
@qt_event_listener
|
||||
@@ -206,7 +208,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
self.balanceChanged.emit()
|
||||
self.synchronizing = not wallet.is_up_to_date()
|
||||
if not self.synchronizing:
|
||||
self.historyModel.initModel() # refresh if dirty
|
||||
self.historyModel.initModel() # refresh if dirty
|
||||
|
||||
@event_listener
|
||||
def on_event_channel(self, wallet, channel):
|
||||
@@ -224,7 +226,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
def on_event_payment_succeeded(self, wallet, key):
|
||||
if wallet == self.wallet:
|
||||
self.paymentSucceeded.emit(key)
|
||||
self.historyModel.initModel(True) # TODO: be less dramatic
|
||||
self.historyModel.initModel(True) # TODO: be less dramatic
|
||||
|
||||
@event_listener
|
||||
def on_event_payment_failed(self, wallet, key, reason):
|
||||
@@ -426,13 +428,11 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
@pyqtProperty(bool, notify=dataChanged)
|
||||
def canSignWithoutCosigner(self):
|
||||
if isinstance(self.wallet, Multisig_Wallet):
|
||||
if self.wallet.wallet_type == '2fa': # 2fa is multisig, but it handles cosigning itself
|
||||
if self.wallet.wallet_type == '2fa': # 2fa is multisig, but it handles cosigning itself
|
||||
return True
|
||||
return self.wallet.m == 1
|
||||
return True
|
||||
|
||||
balanceChanged = pyqtSignal()
|
||||
|
||||
@pyqtProperty(QEAmount, notify=balanceChanged)
|
||||
def frozenBalance(self):
|
||||
c, u, x = self.wallet.get_frozen_balance()
|
||||
@@ -499,9 +499,11 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
success = self.do_sign(tx, broadcast)
|
||||
|
||||
if success:
|
||||
if on_success: on_success(tx)
|
||||
if on_success:
|
||||
on_success(tx)
|
||||
else:
|
||||
if on_failure: on_failure()
|
||||
if on_failure:
|
||||
on_failure()
|
||||
|
||||
def do_sign(self, tx, broadcast):
|
||||
try:
|
||||
@@ -534,14 +536,16 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
# this assumes a 2fa wallet, but there are no other tc_sign_wrapper hooks, so that's ok
|
||||
def on_sign_complete(self, broadcast, cb: Callable[[Transaction], None] = None, tx: Transaction = None):
|
||||
self.otpSuccess.emit()
|
||||
if cb: cb(tx)
|
||||
if cb:
|
||||
cb(tx)
|
||||
if broadcast:
|
||||
self.broadcast(tx)
|
||||
|
||||
# this assumes a 2fa wallet, but there are no other tc_sign_wrapper hooks, so that's ok
|
||||
def on_sign_failed(self, cb: Callable[[], None] = None, error: str = None):
|
||||
self.otpFailed.emit('error', error)
|
||||
if cb: cb()
|
||||
if cb:
|
||||
cb()
|
||||
|
||||
def request_otp(self, on_submit):
|
||||
self._otp_on_submit = on_submit
|
||||
@@ -577,7 +581,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
|
||||
threading.Thread(target=broadcast_thread, daemon=True).start()
|
||||
|
||||
#TODO: properly catch server side errors, e.g. bad-txns-inputs-missingorspent
|
||||
# TODO: properly catch server side errors, e.g. bad-txns-inputs-missingorspent
|
||||
|
||||
def save_tx(self, tx: 'PartialTransaction'):
|
||||
assert tx
|
||||
@@ -585,7 +589,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
try:
|
||||
if not self.wallet.adb.add_transaction(tx):
|
||||
self.saveTxError.emit(tx.txid(), 'conflict',
|
||||
_("Transaction could not be saved.") + "\n" + _("It conflicts with current history."))
|
||||
_("Transaction could not be saved.") + "\n" + _("It conflicts with current history."))
|
||||
return
|
||||
self.wallet.save_db()
|
||||
self.saveTxSuccess.emit(tx.txid())
|
||||
@@ -595,7 +599,6 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
self.saveTxError.emit(tx.txid(), 'error', str(e))
|
||||
return False
|
||||
|
||||
paymentAuthRejected = pyqtSignal()
|
||||
def ln_auth_rejected(self):
|
||||
self.paymentAuthRejected.emit()
|
||||
|
||||
@@ -724,7 +727,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
xpub = self.wallet.get_fingerprint()
|
||||
decrypted = pw_decode_with_version_and_mac(encrypted, xpub)
|
||||
return True
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@pyqtSlot()
|
||||
|
||||
@@ -85,7 +85,7 @@ class QEWalletDB(QObject):
|
||||
|
||||
@pyqtProperty('QString', notify=passwordChanged)
|
||||
def password(self):
|
||||
return '' # no read access
|
||||
return '' # no read access
|
||||
|
||||
@password.setter
|
||||
def password(self, wallet_password):
|
||||
@@ -142,7 +142,6 @@ class QEWalletDB(QObject):
|
||||
self.invalidPassword.emit()
|
||||
else: # storage not encrypted; but it might still have a keystore pw
|
||||
# FIXME hack... load both db and full wallet, just to tell if it has keystore pw.
|
||||
# this also completely ignores db.requires_split(), db.get_action(), etc
|
||||
try:
|
||||
db = WalletDB(self._storage.read(), storage=self._storage, upgrade=True)
|
||||
except WalletRequiresSplit as e:
|
||||
|
||||
@@ -13,9 +13,13 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
class QEAbstractWizard(QObject):
|
||||
""" Concrete subclasses of QEAbstractWizard must also inherit from a concrete AbstractWizard subclass.
|
||||
QEAbstractWizard forms the base for all QML GUI based wizards, while AbstractWizard defines
|
||||
the base for non-gui wizard flow navigation functionality.
|
||||
"""
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
def __init__(self, parent = None):
|
||||
def __init__(self, parent=None):
|
||||
QObject.__init__(self, parent)
|
||||
|
||||
@pyqtSlot(result=str)
|
||||
@@ -45,32 +49,33 @@ class QEAbstractWizard(QObject):
|
||||
|
||||
|
||||
class QENewWalletWizard(NewWalletWizard, QEAbstractWizard):
|
||||
|
||||
createError = pyqtSignal([str], arguments=["error"])
|
||||
createSuccess = pyqtSignal()
|
||||
|
||||
def __init__(self, daemon: 'QEDaemon', plugins: 'Plugins', parent = None):
|
||||
def __init__(self, daemon: 'QEDaemon', plugins: 'Plugins', parent=None):
|
||||
NewWalletWizard.__init__(self, daemon.daemon, plugins)
|
||||
QEAbstractWizard.__init__(self, parent)
|
||||
self._qedaemon = daemon
|
||||
self._path = None
|
||||
self._password = None
|
||||
|
||||
# attach view names and accept handlers
|
||||
self.navmap_merge({
|
||||
'wallet_name': { 'gui': 'WCWalletName' },
|
||||
'wallet_type': { 'gui': 'WCWalletType' },
|
||||
'keystore_type': { 'gui': 'WCKeystoreType' },
|
||||
'create_seed': { 'gui': 'WCCreateSeed' },
|
||||
'confirm_seed': { 'gui': 'WCConfirmSeed' },
|
||||
'have_seed': { 'gui': 'WCHaveSeed' },
|
||||
'script_and_derivation': { 'gui': 'WCScriptAndDerivation' },
|
||||
'have_master_key': { 'gui': 'WCHaveMasterKey' },
|
||||
'multisig': { 'gui': 'WCMultisig' },
|
||||
'multisig_cosigner_keystore': { 'gui': 'WCCosignerKeystore' },
|
||||
'multisig_cosigner_key': { 'gui': 'WCHaveMasterKey' },
|
||||
'multisig_cosigner_seed': { 'gui': 'WCHaveSeed' },
|
||||
'multisig_cosigner_script_and_derivation': { 'gui': 'WCScriptAndDerivation' },
|
||||
'imported': { 'gui': 'WCImport' },
|
||||
'wallet_password': { 'gui': 'WCWalletPassword' }
|
||||
'wallet_name': {'gui': 'WCWalletName'},
|
||||
'wallet_type': {'gui': 'WCWalletType'},
|
||||
'keystore_type': {'gui': 'WCKeystoreType'},
|
||||
'create_seed': {'gui': 'WCCreateSeed'},
|
||||
'confirm_seed': {'gui': 'WCConfirmSeed'},
|
||||
'have_seed': {'gui': 'WCHaveSeed'},
|
||||
'script_and_derivation': {'gui': 'WCScriptAndDerivation'},
|
||||
'have_master_key': {'gui': 'WCHaveMasterKey'},
|
||||
'multisig': {'gui': 'WCMultisig'},
|
||||
'multisig_cosigner_keystore': {'gui': 'WCCosignerKeystore'},
|
||||
'multisig_cosigner_key': {'gui': 'WCHaveMasterKey'},
|
||||
'multisig_cosigner_seed': {'gui': 'WCHaveSeed'},
|
||||
'multisig_cosigner_script_and_derivation': {'gui': 'WCScriptAndDerivation'},
|
||||
'imported': {'gui': 'WCImport'},
|
||||
'wallet_password': {'gui': 'WCWalletPassword'}
|
||||
})
|
||||
|
||||
pathChanged = pyqtSignal()
|
||||
@@ -127,15 +132,14 @@ class QENewWalletWizard(NewWalletWizard, QEAbstractWizard):
|
||||
|
||||
|
||||
class QEServerConnectWizard(ServerConnectWizard, QEAbstractWizard):
|
||||
|
||||
def __init__(self, daemon: 'QEDaemon', parent=None):
|
||||
ServerConnectWizard.__init__(self, daemon.daemon)
|
||||
QEAbstractWizard.__init__(self, parent)
|
||||
|
||||
# attach view names
|
||||
self.navmap_merge({
|
||||
'autoconnect': { 'gui': 'WCAutoConnect' },
|
||||
'proxy_ask': { 'gui': 'WCProxyAsk' },
|
||||
'proxy_config': { 'gui': 'WCProxyConfig' },
|
||||
'server_config': { 'gui': 'WCServerConfig' },
|
||||
'autoconnect': {'gui': 'WCAutoConnect'},
|
||||
'proxy_ask': {'gui': 'WCProxyAsk'},
|
||||
'proxy_config': {'gui': 'WCProxyConfig'},
|
||||
'server_config': {'gui': 'WCServerConfig'},
|
||||
})
|
||||
|
||||
@@ -31,6 +31,7 @@ class QtEventListener(EventListener):
|
||||
# decorator for members of the QtEventListener class
|
||||
def qt_event_listener(func):
|
||||
func = event_listener(func)
|
||||
|
||||
@wraps(func)
|
||||
def decorator(self, *args):
|
||||
self.qt_callback_signal.emit( (func,) + args)
|
||||
@@ -56,10 +57,11 @@ def status_update_timer_interval(exp):
|
||||
|
||||
return interval
|
||||
|
||||
|
||||
# TODO: copied from desktop client, this could be moved to a set of common code.
|
||||
class TaskThread(QThread, Logger):
|
||||
'''Thread that runs background tasks. Callbacks are guaranteed
|
||||
to happen in the context of its parent.'''
|
||||
"""Thread that runs background tasks. Callbacks are guaranteed
|
||||
to happen in the context of its parent."""
|
||||
|
||||
class Task(NamedTuple):
|
||||
task: Callable
|
||||
|
||||
@@ -19,6 +19,10 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
class QEAbstractWizard(QDialog, MessageBoxMixin):
|
||||
""" Concrete subclasses of QEAbstractWizard must also inherit from a concrete AbstractWizard subclass.
|
||||
QEAbstractWizard forms the base for all QtWidgets GUI based wizards, while AbstractWizard defines
|
||||
the base for non-gui wizard flow navigation functionality.
|
||||
"""
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
requestNext = pyqtSignal()
|
||||
|
||||
Reference in New Issue
Block a user