From a56c9687c84b4f446e512c9895d65f408cd54de4 Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Wed, 22 Feb 2023 14:17:57 +0100 Subject: [PATCH] qml: initial async wallet load --- electrum/gui/qml/qedaemon.py | 49 +++++++++++++++++++++++++----------- electrum/gui/qml/qewallet.py | 18 ++++++++++++- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/electrum/gui/qml/qedaemon.py b/electrum/gui/qml/qedaemon.py index 04448c2d2..729d50369 100644 --- a/electrum/gui/qml/qedaemon.py +++ b/electrum/gui/qml/qedaemon.py @@ -1,4 +1,5 @@ import os +import threading from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject @@ -118,12 +119,14 @@ class QEDaemon(AuthMixin, QObject): _use_single_password = False _password = None + _backendWalletLoaded = pyqtSignal([str], arguments=['password']) + availableWalletsChanged = pyqtSignal() fxChanged = pyqtSignal() newWalletWizardChanged = pyqtSignal() serverConnectWizardChanged = pyqtSignal() - walletLoaded = pyqtSignal() + walletLoaded = pyqtSignal([str,str], arguments=['name','path']) walletRequiresPassword = pyqtSignal([str,str], arguments=['name','path']) walletOpenError = pyqtSignal([str], arguments=["error"]) walletDeleteError = pyqtSignal([str,str], arguments=['code', 'message']) @@ -132,6 +135,9 @@ class QEDaemon(AuthMixin, QObject): super().__init__(parent) self.daemon = daemon self.qefx = QEFX(daemon.fx, daemon.config) + + self._backendWalletLoaded.connect(self._on_backend_wallet_loaded) + self._walletdb = QEWalletDB() self._walletdb.validPasswordChanged.connect(self.passwordValidityCheck) @@ -171,14 +177,14 @@ class QEDaemon(AuthMixin, QObject): if not self._walletdb.ready: return - try: - wallet = self.daemon.load_wallet(self._path, password) - if wallet is not None: - self._current_wallet = QEWallet.getInstanceFor(wallet) - if not wallet_already_open: - self.availableWallets.updateWallet(self._path) - self._current_wallet.password = password - self.walletLoaded.emit() + def load_wallet_task(): + try: + wallet = self.daemon.load_wallet(self._path, password) + + if wallet is None: + self._logger.info('could not open wallet') + self.walletOpenError.emit('could not open wallet') + return if self.daemon.config.get('single_password'): self._use_single_password = self.daemon.update_password_for_directory(old_password=password, new_password=password) @@ -189,13 +195,26 @@ class QEDaemon(AuthMixin, QObject): self._logger.info('use single password disabled by config') self.daemon.config.save_last_wallet(wallet) + run_hook('load_wallet', wallet) - else: - self._logger.info('could not open wallet') - self.walletOpenError.emit('could not open wallet') - except WalletFileException as e: - self._logger.error(str(e)) - self.walletOpenError.emit(str(e)) + + self._backendWalletLoaded.emit(password) + except WalletFileException as e: + self._logger.error(str(e)) + self.walletOpenError.emit(str(e)) + + threading.Thread(target=load_wallet_task).start() + + @pyqtSlot() + @pyqtSlot(str) + def _on_backend_wallet_loaded(self, password = None): + self._logger.debug('_on_backend_wallet_loaded') + wallet = self.daemon._wallets[self._path] + self._current_wallet = QEWallet.getInstanceFor(wallet) + self.availableWallets.updateWallet(self._path) + self._current_wallet.password = password + self.walletLoaded.emit(self._name, self._path) + @pyqtSlot(QEWallet) @pyqtSlot(QEWallet, bool) diff --git a/electrum/gui/qml/qewallet.py b/electrum/gui/qml/qewallet.py index 31d615ec4..7794a070b 100644 --- a/electrum/gui/qml/qewallet.py +++ b/electrum/gui/qml/qewallet.py @@ -5,7 +5,7 @@ import time from typing import TYPE_CHECKING, Optional, Tuple from functools import partial -from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer +from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer, QMetaObject, Qt from electrum import bitcoin from electrum.i18n import _ @@ -113,6 +113,9 @@ class QEWallet(AuthMixin, QObject, QtEventListener): self.sync_progress_timer.setInterval(2000) self.sync_progress_timer.timeout.connect(self.update_sync_progress) + # post-construction init in GUI thread + # QMetaObject.invokeMethod(self, 'qt_init', Qt.QueuedConnection) + # 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 @@ -123,6 +126,19 @@ class QEWallet(AuthMixin, QObject, QtEventListener): self.synchronizing = True # start in sync state + # @pyqtSlot() + # def qt_init(self): + # self.notification_timer = QTimer(self) + # self.notification_timer.setSingleShot(False) + # self.notification_timer.setInterval(500) # msec + # self.notification_timer.timeout.connect(self.notify_transactions) + # + # self.sync_progress_timer = QTimer(self) + # self.sync_progress_timer.setSingleShot(False) + # self.sync_progress_timer.setInterval(2000) + # self.sync_progress_timer.timeout.connect(self.update_sync_progress) + + @pyqtProperty(bool, notify=isUptodateChanged) def isUptodate(self): return self._isUpToDate