Browse Source

qml: add LabelSync toggle

master
Sander van Grieken 2 years ago
parent
commit
b6863b4854
  1. 3
      electrum/gui/qml/__init__.py
  2. 20
      electrum/gui/qml/components/Preferences.qml
  3. 14
      electrum/gui/qml/qeapp.py
  4. 1
      electrum/plugin.py
  5. 14
      electrum/plugins/labels/labels.py
  6. 31
      electrum/plugins/labels/qml.py
  7. 9
      electrum/plugins/trustedcoin/qml.py

3
electrum/gui/qml/__init__.py

@ -41,6 +41,7 @@ class ElectrumTranslator(QTranslator):
def translate(self, context, source_text, disambiguation, n):
return _(source_text, context=context)
class ElectrumGui(BaseElectrumGui, Logger):
@profiler
@ -91,7 +92,7 @@ class ElectrumGui(BaseElectrumGui, Logger):
Exception_Hook.maybe_setup(config=config, slot=self.app.appController.crash)
# Initialize any QML plugins
run_hook('init_qml', self)
run_hook('init_qml', self.app)
self.app.engine.load('electrum/gui/qml/components/main.qml')
def close(self):

20
electrum/gui/qml/components/Preferences.qml

@ -217,6 +217,25 @@ Pane {
}
}
RowLayout {
Layout.columnSpan: 2
Layout.fillWidth: true
Layout.leftMargin: -constants.paddingSmall
spacing: 0
Switch {
id: syncLabels
onCheckedChanged: {
if (activeFocus)
AppController.setPluginEnabled('labels', checked)
}
}
Label {
Layout.fillWidth: true
text: qsTr('Synchronize labels')
wrapMode: Text.Wrap
}
}
PrefsHeading {
Layout.columnSpan: 2
text: qsTr('Wallet behavior')
@ -384,5 +403,6 @@ Pane {
useFallbackAddress.checked = Config.useFallbackAddress
enableDebugLogs.checked = Config.enableDebugLogs
useRecoverableChannels.checked = Config.useRecoverableChannels
syncLabels.checked = AppController.isPluginEnabled('labels')
}
}

14
electrum/gui/qml/qeapp.py

@ -19,6 +19,7 @@ from electrum.logging import Logger, get_logger
from electrum.bip21 import BITCOIN_BIP21_URI_SCHEME, LIGHTNING_URI_SCHEME
from electrum.base_crash_reporter import BaseCrashReporter, EarlyExceptionsQueue
from electrum.network import Network
from electrum.plugin import run_hook
from .qeconfig import QEConfig
from .qedaemon import QEDaemon
@ -70,10 +71,11 @@ class QEAppController(BaseCrashReporter, QObject):
sendingBugreportFailure = pyqtSignal(str)
secureWindowChanged = pyqtSignal()
def __init__(self, qedaemon: 'QEDaemon', plugins: 'Plugins'):
def __init__(self, qeapp: 'ElectrumQmlApplication', qedaemon: 'QEDaemon', plugins: 'Plugins'):
BaseCrashReporter.__init__(self, None, None, None)
QObject.__init__(self)
self._app = qeapp
self._qedaemon = qedaemon
self._plugins = plugins
self.config = qedaemon.daemon.config
@ -224,12 +226,18 @@ class QEAppController(BaseCrashReporter, QObject):
return s
@pyqtSlot(str, bool)
def setPluginEnabled(self, plugin, enabled):
def setPluginEnabled(self, plugin: str, enabled: bool):
if enabled:
self._plugins.enable(plugin)
# note: all enabled plugins will receive this hook:
run_hook('init_qml', self._app)
else:
self._plugins.disable(plugin)
@pyqtSlot(str, result=bool)
def isPluginEnabled(self, plugin: str):
return bool(self._plugins.get(plugin))
@pyqtSlot(result=bool)
def isAndroid(self):
return 'ANDROID_DATA' in os.environ
@ -369,7 +377,7 @@ class ElectrumQmlApplication(QGuiApplication):
self._qeconfig = QEConfig(config)
self._qenetwork = QENetwork(daemon.network, self._qeconfig)
self.daemon = QEDaemon(daemon)
self.appController = QEAppController(self.daemon, self.plugins)
self.appController = QEAppController(self, self.daemon, self.plugins)
self._maxAmount = QEAmount(is_max=True)
self.context.setContextProperty('AppController', self.appController)
self.context.setContextProperty('Config', self._qeconfig)

1
electrum/plugin.py

@ -218,6 +218,7 @@ def hook(func):
hook_names.add(func.__name__)
return func
def run_hook(name, *args):
results = []
f_list = hooks.get(name, [])

14
electrum/plugins/labels/labels.py

@ -134,9 +134,11 @@ class LabelsPlugin(BasePlugin):
response = await self.do_get("/labels/since/%d/for/%s" % (nonce, wallet_id))
except Exception as e:
raise ErrorConnectingServer(e) from e
if response["labels"] is None:
if response["labels"] is None or len(response["labels"]) == 0:
self.logger.info('no new labels')
return
self.logger.debug(f"labels received {response!r}")
self.logger.info(f'received {len(response["labels"])} labels')
result = {}
for label in response["labels"]:
try:
@ -157,7 +159,6 @@ class LabelsPlugin(BasePlugin):
if force or not wallet._get_label(key):
wallet._set_label(key, value)
self.logger.info(f"received {len(response)} labels")
self.set_nonce(wallet, response["nonce"] + 1)
self.on_pulled(wallet)
@ -173,15 +174,18 @@ class LabelsPlugin(BasePlugin):
self.logger.info(repr(e))
def pull(self, wallet: 'Abstract_Wallet', force: bool):
if not wallet.network: raise Exception(_('You are offline.'))
if not wallet.network:
raise Exception(_('You are offline.'))
return asyncio.run_coroutine_threadsafe(self.pull_thread(wallet, force), wallet.network.asyncio_loop).result()
def push(self, wallet: 'Abstract_Wallet'):
if not wallet.network: raise Exception(_('You are offline.'))
if not wallet.network:
raise Exception(_('You are offline.'))
return asyncio.run_coroutine_threadsafe(self.push_thread(wallet), wallet.network.asyncio_loop).result()
def start_wallet(self, wallet: 'Abstract_Wallet'):
if not wallet.network: return # 'offline' mode
if not wallet.network:
return # 'offline' mode
mpk = wallet.get_fingerprint()
if not mpk:
return

31
electrum/plugins/labels/qml.py

@ -1,6 +1,6 @@
import threading
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty, pyqtSlot
from PyQt5.QtCore import pyqtSignal, pyqtSlot
from electrum.i18n import _
from electrum.plugin import hook
@ -10,6 +10,7 @@ from electrum.gui.qml.plugins import PluginQObject
from .labels import LabelsPlugin
class Plugin(LabelsPlugin):
class QSignalObject(PluginQObject):
@ -63,6 +64,8 @@ class Plugin(LabelsPlugin):
def __init__(self, *args):
LabelsPlugin.__init__(self, *args)
self._app = None
self.so = None
@hook
def load_wallet(self, wallet):
@ -77,9 +80,9 @@ class Plugin(LabelsPlugin):
wallet = self._app.daemon.currentWallet.wallet
def push_thread(wallet):
def push_thread(_wallet):
try:
self.push(wallet)
self.push(_wallet)
self.so.upload_finished(True)
self._app.appController.userNotify.emit(_('Labels uploaded'))
except Exception as e:
@ -87,7 +90,7 @@ class Plugin(LabelsPlugin):
self.so.upload_finished(False)
self._app.appController.userNotify.emit(repr(e))
threading.Thread(target=push_thread,args=[wallet]).start()
threading.Thread(target=push_thread, args=[wallet]).start()
def pull_async(self):
if not self._app.daemon.currentWallet:
@ -96,9 +99,10 @@ class Plugin(LabelsPlugin):
return
wallet = self._app.daemon.currentWallet.wallet
def pull_thread(wallet):
def pull_thread(_wallet):
try:
self.pull(wallet, True)
self.pull(_wallet, True)
self.so.download_finished(True)
self._app.appController.userNotify.emit(_('Labels downloaded'))
except Exception as e:
@ -106,8 +110,7 @@ class Plugin(LabelsPlugin):
self.so.download_finished(False)
self._app.appController.userNotify.emit(repr(e))
threading.Thread(target=pull_thread,args=[wallet]).start()
threading.Thread(target=pull_thread, args=[wallet]).start()
def on_pulled(self, wallet):
self.logger.info('on pulled')
@ -117,9 +120,15 @@ class Plugin(LabelsPlugin):
_wallet.labelsUpdated.emit()
@hook
def init_qml(self, gui):
self.logger.debug(f'init_qml hook called, gui={str(type(gui))}')
self._app = gui.app
def init_qml(self, app):
self.logger.debug(f'init_qml hook called, gui={str(type(app))}')
self.logger.debug(f'app={self._app!r}, so={self.so!r}')
self._app = app
# important: QSignalObject needs to be parented, as keeping a ref
# in the plugin is not enough to avoid gc
self.so = Plugin.QSignalObject(self, self._app)
# If the user just enabled the plugin, the 'load_wallet' hook would not
# get called for already loaded wallets, hence we call it manually for those:
for wallet_name, wallet in app.daemon.daemon._wallets.items():
self.load_wallet(wallet)

9
electrum/plugins/trustedcoin/qml.py

@ -19,9 +19,10 @@ from .trustedcoin import (TrustedCoinPlugin, server, ErrorConnectingServer,
TrustedCoinException, make_xpub)
if TYPE_CHECKING:
from electrum.gui.qml import ElectrumGui
from electrum.gui.qml import ElectrumQmlApplication
from electrum.wallet import Abstract_Wallet
class Plugin(TrustedCoinPlugin):
class QSignalObject(PluginQObject):
@ -287,9 +288,9 @@ class Plugin(TrustedCoinPlugin):
self.start_request_thread(wallet)
@hook
def init_qml(self, gui: 'ElectrumGui'):
self.logger.debug(f'init_qml hook called, gui={str(type(gui))}')
self._app = gui.app
def init_qml(self, app: 'ElectrumQmlApplication'):
self.logger.debug(f'init_qml hook called, gui={str(type(app))}')
self._app = app
# important: QSignalObject needs to be parented, as keeping a ref
# in the plugin is not enough to avoid gc
self.so = Plugin.QSignalObject(self, self._app)

Loading…
Cancel
Save