qml: initial plugin support, with labelsync mostly implemented
This commit is contained in:
@@ -63,7 +63,7 @@ class ElectrumGui(Logger):
|
||||
|
||||
self.gui_thread = threading.current_thread()
|
||||
self.plugins = plugins
|
||||
self.app = ElectrumQmlApplication(sys.argv, config, daemon)
|
||||
self.app = ElectrumQmlApplication(sys.argv, config, daemon, plugins)
|
||||
# timer
|
||||
self.timer = QTimer(self.app)
|
||||
self.timer.setSingleShot(False)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import QtQuick 2.6
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Controls.Material 2.0
|
||||
|
||||
import org.electrum 1.0
|
||||
@@ -12,175 +12,212 @@ Pane {
|
||||
|
||||
property string title: qsTr("Preferences")
|
||||
|
||||
padding: 0
|
||||
|
||||
property var _baseunits: ['BTC','mBTC','bits','sat']
|
||||
|
||||
Flickable {
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
contentHeight: rootLayout.height
|
||||
interactive: height < contentHeight
|
||||
|
||||
GridLayout {
|
||||
id: rootLayout
|
||||
columns: 2
|
||||
width: parent.width
|
||||
|
||||
Label {
|
||||
text: qsTr('Language')
|
||||
TabBar {
|
||||
id: tabbar
|
||||
Layout.fillWidth: true
|
||||
currentIndex: swipeview.currentIndex
|
||||
TabButton {
|
||||
text: qsTr('Preferences')
|
||||
font.pixelSize: constants.fontSizeLarge
|
||||
}
|
||||
|
||||
ElComboBox {
|
||||
id: language
|
||||
enabled: false
|
||||
TabButton {
|
||||
text: qsTr('Plugins')
|
||||
font.pixelSize: constants.fontSizeLarge
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr('Base unit')
|
||||
}
|
||||
SwipeView {
|
||||
id: swipeview
|
||||
|
||||
ElComboBox {
|
||||
id: baseUnit
|
||||
model: _baseunits
|
||||
onCurrentValueChanged: {
|
||||
if (activeFocus)
|
||||
Config.baseUnit = currentValue
|
||||
}
|
||||
}
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
currentIndex: tabbar.currentIndex
|
||||
|
||||
Switch {
|
||||
id: thousands
|
||||
Layout.columnSpan: 2
|
||||
text: qsTr('Add thousands separators to bitcoin amounts')
|
||||
onCheckedChanged: {
|
||||
if (activeFocus)
|
||||
Config.thousandsSeparator = checked
|
||||
}
|
||||
}
|
||||
Flickable {
|
||||
contentHeight: prefsPane.height
|
||||
interactive: height < contentHeight
|
||||
clip: true
|
||||
|
||||
Switch {
|
||||
id: checkSoftware
|
||||
Layout.columnSpan: 2
|
||||
text: qsTr('Automatically check for software updates')
|
||||
enabled: false
|
||||
}
|
||||
Pane {
|
||||
id: prefsPane
|
||||
GridLayout {
|
||||
columns: 2
|
||||
width: parent.width
|
||||
|
||||
Switch {
|
||||
id: fiatEnable
|
||||
text: qsTr('Fiat Currency')
|
||||
onCheckedChanged: {
|
||||
if (activeFocus)
|
||||
Daemon.fx.enabled = checked
|
||||
}
|
||||
}
|
||||
Label {
|
||||
text: qsTr('Language')
|
||||
}
|
||||
|
||||
ElComboBox {
|
||||
id: currencies
|
||||
model: Daemon.fx.currencies
|
||||
enabled: Daemon.fx.enabled
|
||||
onCurrentValueChanged: {
|
||||
if (activeFocus)
|
||||
Daemon.fx.fiatCurrency = currentValue
|
||||
}
|
||||
}
|
||||
ElComboBox {
|
||||
id: language
|
||||
enabled: false
|
||||
}
|
||||
|
||||
Switch {
|
||||
id: historicRates
|
||||
text: qsTr('Historic rates')
|
||||
enabled: Daemon.fx.enabled
|
||||
Layout.columnSpan: 2
|
||||
onCheckedChanged: {
|
||||
if (activeFocus)
|
||||
Daemon.fx.historicRates = checked
|
||||
}
|
||||
}
|
||||
Label {
|
||||
text: qsTr('Base unit')
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr('Source')
|
||||
enabled: Daemon.fx.enabled
|
||||
}
|
||||
ElComboBox {
|
||||
id: baseUnit
|
||||
model: _baseunits
|
||||
onCurrentValueChanged: {
|
||||
if (activeFocus)
|
||||
Config.baseUnit = currentValue
|
||||
}
|
||||
}
|
||||
|
||||
ElComboBox {
|
||||
id: rateSources
|
||||
enabled: Daemon.fx.enabled
|
||||
model: Daemon.fx.rateSources
|
||||
onModelChanged: {
|
||||
currentIndex = rateSources.indexOfValue(Daemon.fx.rateSource)
|
||||
}
|
||||
onCurrentValueChanged: {
|
||||
if (activeFocus)
|
||||
Daemon.fx.rateSource = currentValue
|
||||
}
|
||||
}
|
||||
Switch {
|
||||
id: thousands
|
||||
Layout.columnSpan: 2
|
||||
text: qsTr('Add thousands separators to bitcoin amounts')
|
||||
onCheckedChanged: {
|
||||
if (activeFocus)
|
||||
Config.thousandsSeparator = checked
|
||||
}
|
||||
}
|
||||
|
||||
Switch {
|
||||
id: spendUnconfirmed
|
||||
text: qsTr('Spend unconfirmed')
|
||||
Layout.columnSpan: 2
|
||||
onCheckedChanged: {
|
||||
if (activeFocus)
|
||||
Config.spendUnconfirmed = checked
|
||||
}
|
||||
}
|
||||
Switch {
|
||||
id: checkSoftware
|
||||
Layout.columnSpan: 2
|
||||
text: qsTr('Automatically check for software updates')
|
||||
enabled: false
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr('PIN')
|
||||
}
|
||||
Switch {
|
||||
id: fiatEnable
|
||||
text: qsTr('Fiat Currency')
|
||||
onCheckedChanged: {
|
||||
if (activeFocus)
|
||||
Daemon.fx.enabled = checked
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Label {
|
||||
text: Config.pinCode == '' ? qsTr('Off'): qsTr('On')
|
||||
color: Material.accentColor
|
||||
Layout.rightMargin: constants.paddingMedium
|
||||
}
|
||||
Button {
|
||||
text: qsTr('Enable')
|
||||
visible: Config.pinCode == ''
|
||||
onClicked: {
|
||||
var dialog = pinSetup.createObject(preferences, {mode: 'enter'})
|
||||
dialog.accepted.connect(function() {
|
||||
Config.pinCode = dialog.pincode
|
||||
dialog.close()
|
||||
})
|
||||
dialog.open()
|
||||
}
|
||||
}
|
||||
Button {
|
||||
text: qsTr('Change')
|
||||
visible: Config.pinCode != ''
|
||||
onClicked: {
|
||||
var dialog = pinSetup.createObject(preferences, {mode: 'change', pincode: Config.pinCode})
|
||||
dialog.accepted.connect(function() {
|
||||
Config.pinCode = dialog.pincode
|
||||
dialog.close()
|
||||
})
|
||||
dialog.open()
|
||||
}
|
||||
}
|
||||
Button {
|
||||
text: qsTr('Remove')
|
||||
visible: Config.pinCode != ''
|
||||
onClicked: {
|
||||
Config.pinCode = ''
|
||||
ElComboBox {
|
||||
id: currencies
|
||||
model: Daemon.fx.currencies
|
||||
enabled: Daemon.fx.enabled
|
||||
onCurrentValueChanged: {
|
||||
if (activeFocus)
|
||||
Daemon.fx.fiatCurrency = currentValue
|
||||
}
|
||||
}
|
||||
|
||||
Switch {
|
||||
id: historicRates
|
||||
text: qsTr('Historic rates')
|
||||
enabled: Daemon.fx.enabled
|
||||
Layout.columnSpan: 2
|
||||
onCheckedChanged: {
|
||||
if (activeFocus)
|
||||
Daemon.fx.historicRates = checked
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr('Source')
|
||||
enabled: Daemon.fx.enabled
|
||||
}
|
||||
|
||||
ElComboBox {
|
||||
id: rateSources
|
||||
enabled: Daemon.fx.enabled
|
||||
model: Daemon.fx.rateSources
|
||||
onModelChanged: {
|
||||
currentIndex = rateSources.indexOfValue(Daemon.fx.rateSource)
|
||||
}
|
||||
onCurrentValueChanged: {
|
||||
if (activeFocus)
|
||||
Daemon.fx.rateSource = currentValue
|
||||
}
|
||||
}
|
||||
|
||||
Switch {
|
||||
id: spendUnconfirmed
|
||||
text: qsTr('Spend unconfirmed')
|
||||
Layout.columnSpan: 2
|
||||
onCheckedChanged: {
|
||||
if (activeFocus)
|
||||
Config.spendUnconfirmed = checked
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr('PIN')
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Label {
|
||||
text: Config.pinCode == '' ? qsTr('Off'): qsTr('On')
|
||||
color: Material.accentColor
|
||||
Layout.rightMargin: constants.paddingMedium
|
||||
}
|
||||
Button {
|
||||
text: qsTr('Enable')
|
||||
visible: Config.pinCode == ''
|
||||
onClicked: {
|
||||
var dialog = pinSetup.createObject(preferences, {mode: 'enter'})
|
||||
dialog.accepted.connect(function() {
|
||||
Config.pinCode = dialog.pincode
|
||||
dialog.close()
|
||||
})
|
||||
dialog.open()
|
||||
}
|
||||
}
|
||||
Button {
|
||||
text: qsTr('Change')
|
||||
visible: Config.pinCode != ''
|
||||
onClicked: {
|
||||
var dialog = pinSetup.createObject(preferences, {mode: 'change', pincode: Config.pinCode})
|
||||
dialog.accepted.connect(function() {
|
||||
Config.pinCode = dialog.pincode
|
||||
dialog.close()
|
||||
})
|
||||
dialog.open()
|
||||
}
|
||||
}
|
||||
Button {
|
||||
text: qsTr('Remove')
|
||||
visible: Config.pinCode != ''
|
||||
onClicked: {
|
||||
Config.pinCode = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr('Lightning Routing')
|
||||
}
|
||||
|
||||
ElComboBox {
|
||||
id: lnRoutingType
|
||||
enabled: Daemon.currentWallet && Daemon.currentWallet.isLightning
|
||||
|
||||
valueRole: 'key'
|
||||
textRole: 'label'
|
||||
model: ListModel {
|
||||
ListElement { key: 'gossip'; label: qsTr('Gossip') }
|
||||
ListElement { key: 'trampoline'; label: qsTr('Trampoline') }
|
||||
}
|
||||
onCurrentValueChanged: {
|
||||
if (activeFocus)
|
||||
Config.useGossip = currentValue == 'gossip'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr('Lightning Routing')
|
||||
}
|
||||
|
||||
ElComboBox {
|
||||
id: lnRoutingType
|
||||
enabled: Daemon.currentWallet && Daemon.currentWallet.isLightning
|
||||
|
||||
valueRole: 'key'
|
||||
textRole: 'label'
|
||||
model: ListModel {
|
||||
ListElement { key: 'gossip'; label: qsTr('Gossip') }
|
||||
ListElement { key: 'trampoline'; label: qsTr('Trampoline') }
|
||||
}
|
||||
onCurrentValueChanged: {
|
||||
if (activeFocus)
|
||||
Config.useGossip = currentValue == 'gossip'
|
||||
Pane {
|
||||
ColumnLayout {
|
||||
id: pluginsRootLayout
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -192,6 +229,19 @@ Pane {
|
||||
Pin {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: pluginHeader
|
||||
RowLayout {
|
||||
property QtObject plugin
|
||||
Switch {
|
||||
checked: plugin.pluginEnabled
|
||||
}
|
||||
Label {
|
||||
text: plugin.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
baseUnit.currentIndex = _baseunits.indexOf(Config.baseUnit)
|
||||
thousands.checked = Config.thousandsSeparator
|
||||
@@ -201,5 +251,15 @@ Pane {
|
||||
fiatEnable.checked = Daemon.fx.enabled
|
||||
spendUnconfirmed.checked = Config.spendUnconfirmed
|
||||
lnRoutingType.currentIndex = Config.useGossip ? 0 : 1
|
||||
|
||||
var labelsPlugin = AppController.plugin('labels')
|
||||
if (labelsPlugin) {
|
||||
pluginHeader.createObject(pluginsRootLayout, { plugin: labelsPlugin })
|
||||
// console.log(Qt.resolvedUrl(labelsPlugin.settingsComponent()))
|
||||
if (labelsPlugin.settingsComponent()) {
|
||||
var component = Qt.createComponent(Qt.resolvedUrl(labelsPlugin.settingsComponent()))
|
||||
component.createObject(pluginsRootLayout, {plugin: labelsPlugin})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,11 +34,12 @@ notification = None
|
||||
class QEAppController(QObject):
|
||||
userNotify = pyqtSignal(str)
|
||||
|
||||
def __init__(self, qedaemon):
|
||||
def __init__(self, qedaemon, plugins):
|
||||
super().__init__()
|
||||
self.logger = get_logger(__name__)
|
||||
|
||||
self._qedaemon = qedaemon
|
||||
self._plugins = plugins
|
||||
|
||||
# set up notification queue and notification_timer
|
||||
self.user_notification_queue = queue.Queue()
|
||||
@@ -131,11 +132,22 @@ class QEAppController(QObject):
|
||||
def clipboardToText(self):
|
||||
return QGuiApplication.clipboard().text()
|
||||
|
||||
@pyqtSlot(str, result=QObject)
|
||||
def plugin(self, plugin_name):
|
||||
self.logger.warning(f'now {self._plugins.count()} plugins loaded')
|
||||
plugin = self._plugins.get(plugin_name)
|
||||
self.logger.debug(f'plugin with name {plugin_name} is {str(type(plugin))}')
|
||||
if plugin:
|
||||
return plugin.so
|
||||
else:
|
||||
self.logger.debug('None!')
|
||||
return None
|
||||
|
||||
class ElectrumQmlApplication(QGuiApplication):
|
||||
|
||||
_valid = True
|
||||
|
||||
def __init__(self, args, config, daemon):
|
||||
def __init__(self, args, config, daemon, plugins):
|
||||
super().__init__(args)
|
||||
|
||||
self.logger = get_logger(__name__)
|
||||
@@ -162,7 +174,6 @@ class ElectrumQmlApplication(QGuiApplication):
|
||||
qmlRegisterUncreatableType(QEAmount, 'org.electrum', 1, 0, 'Amount', 'Amount can only be used as property')
|
||||
|
||||
self.engine = QQmlApplicationEngine(parent=self)
|
||||
self.engine.addImportPath('./qml')
|
||||
|
||||
screensize = self.primaryScreen().size()
|
||||
|
||||
@@ -181,13 +192,13 @@ class ElectrumQmlApplication(QGuiApplication):
|
||||
self.context = self.engine.rootContext()
|
||||
self._qeconfig = QEConfig(config)
|
||||
self._qenetwork = QENetwork(daemon.network, self._qeconfig)
|
||||
self._qedaemon = QEDaemon(daemon)
|
||||
self._appController = QEAppController(self._qedaemon)
|
||||
self.daemon = QEDaemon(daemon)
|
||||
self.appController = QEAppController(self.daemon, plugins)
|
||||
self._maxAmount = QEAmount(is_max=True)
|
||||
self.context.setContextProperty('AppController', self._appController)
|
||||
self.context.setContextProperty('AppController', self.appController)
|
||||
self.context.setContextProperty('Config', self._qeconfig)
|
||||
self.context.setContextProperty('Network', self._qenetwork)
|
||||
self.context.setContextProperty('Daemon', self._qedaemon)
|
||||
self.context.setContextProperty('Daemon', self.daemon)
|
||||
self.context.setContextProperty('FixedFont', self.fixedFont)
|
||||
self.context.setContextProperty('MAX', self._maxAmount)
|
||||
self.context.setContextProperty('QRIP', self.qr_ip_h)
|
||||
|
||||
@@ -7,6 +7,7 @@ from electrum.i18n import _
|
||||
from electrum.logging import get_logger
|
||||
from electrum.util import WalletFileException, standardize_path
|
||||
from electrum.wallet import Abstract_Wallet
|
||||
from electrum.plugin import run_hook
|
||||
from electrum.lnchannel import ChannelState
|
||||
|
||||
from .auth import AuthMixin, auth_protect
|
||||
@@ -179,6 +180,7 @@ 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')
|
||||
|
||||
@@ -62,6 +62,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
transactionSigned = pyqtSignal([str], arguments=['txid'])
|
||||
#broadcastSucceeded = pyqtSignal([str], arguments=['txid'])
|
||||
broadcastFailed = pyqtSignal([str,str,str], arguments=['txid','code','reason'])
|
||||
labelsUpdated = pyqtSignal()
|
||||
|
||||
_network_signal = pyqtSignal(str, object)
|
||||
|
||||
|
||||
45
electrum/plugins/labels/Labels.qml
Normal file
45
electrum/plugins/labels/Labels.qml
Normal file
@@ -0,0 +1,45 @@
|
||||
import QtQuick 2.6
|
||||
import QtQuick.Layouts 1.0
|
||||
import QtQuick.Controls 2.14
|
||||
import QtQuick.Controls.Material 2.0
|
||||
|
||||
import org.electrum 1.0
|
||||
|
||||
//import "controls"
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: rootLayout.height
|
||||
|
||||
property QtObject plugin
|
||||
|
||||
RowLayout {
|
||||
id: rootLayout
|
||||
Button {
|
||||
text: 'Force upload'
|
||||
enabled: !plugin.busy
|
||||
onClicked: plugin.upload()
|
||||
}
|
||||
Button {
|
||||
text: 'Force download'
|
||||
enabled: !plugin.busy
|
||||
onClicked: plugin.download()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: plugin
|
||||
function onUploadSuccess() {
|
||||
console.log('upload success')
|
||||
}
|
||||
function onUploadFailed() {
|
||||
console.log('upload failed')
|
||||
}
|
||||
function onDownloadSuccess() {
|
||||
console.log('download success')
|
||||
}
|
||||
function onDownloadFailed() {
|
||||
console.log('download failed')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,5 +5,5 @@ description = ' '.join([
|
||||
_("Save your wallet labels on a remote server, and synchronize them across multiple devices where you use Electrum."),
|
||||
_("Labels, transactions IDs and addresses are encrypted before they are sent to the remote server.")
|
||||
])
|
||||
available_for = ['qt', 'kivy', 'cmdline']
|
||||
available_for = ['qt', 'qml', 'kivy', 'cmdline']
|
||||
|
||||
|
||||
138
electrum/plugins/labels/qml.py
Normal file
138
electrum/plugins/labels/qml.py
Normal file
@@ -0,0 +1,138 @@
|
||||
import threading
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty, pyqtSlot
|
||||
|
||||
from electrum.i18n import _
|
||||
from electrum.plugin import hook
|
||||
|
||||
from electrum.gui.qml.qewallet import QEWallet
|
||||
|
||||
from .labels import LabelsPlugin
|
||||
|
||||
class Plugin(LabelsPlugin):
|
||||
|
||||
class QSignalObject(QObject):
|
||||
pluginChanged = pyqtSignal()
|
||||
pluginEnabledChanged = pyqtSignal()
|
||||
labelsChanged = pyqtSignal()
|
||||
busyChanged = pyqtSignal()
|
||||
uploadSuccess = pyqtSignal()
|
||||
uploadFailed = pyqtSignal()
|
||||
downloadSuccess = pyqtSignal()
|
||||
downloadFailed = pyqtSignal()
|
||||
|
||||
_busy = False
|
||||
|
||||
def __init__(self, plugin, parent = None):
|
||||
super().__init__(parent)
|
||||
self.plugin = plugin
|
||||
|
||||
@pyqtProperty(str, notify=pluginChanged)
|
||||
def name(self): return _('Labels Plugin')
|
||||
|
||||
@pyqtProperty(bool, notify=busyChanged)
|
||||
def busy(self): return self._busy
|
||||
|
||||
@pyqtProperty(bool, notify=pluginEnabledChanged)
|
||||
def pluginEnabled(self): return self.plugin.is_enabled()
|
||||
|
||||
@pyqtSlot(result=str)
|
||||
def settingsComponent(self): return '../../../plugins/labels/Labels.qml'
|
||||
|
||||
@pyqtSlot()
|
||||
def upload(self):
|
||||
assert self.plugin
|
||||
|
||||
self._busy = True
|
||||
self.busyChanged.emit()
|
||||
|
||||
self.plugin.push_async()
|
||||
|
||||
def upload_finished(self, result):
|
||||
if result:
|
||||
self.uploadSuccess.emit()
|
||||
else:
|
||||
self.uploadFailed.emit()
|
||||
self._busy = False
|
||||
self.busyChanged.emit()
|
||||
|
||||
@pyqtSlot()
|
||||
def download(self):
|
||||
assert self.plugin
|
||||
|
||||
self._busy = True
|
||||
self.busyChanged.emit()
|
||||
|
||||
self.plugin.pull_async()
|
||||
|
||||
def download_finished(self, result):
|
||||
if result:
|
||||
self.downloadSuccess.emit()
|
||||
else:
|
||||
self.downloadFailed.emit()
|
||||
self._busy = False
|
||||
self.busyChanged.emit()
|
||||
|
||||
def __init__(self, *args):
|
||||
LabelsPlugin.__init__(self, *args)
|
||||
|
||||
@hook
|
||||
def load_wallet(self, wallet):
|
||||
self.logger.info(f'load_wallet hook for wallet {str(type(wallet))}')
|
||||
self.start_wallet(wallet)
|
||||
|
||||
def push_async(self):
|
||||
if not self._app.daemon.currentWallet:
|
||||
self.logger.error('No current wallet')
|
||||
self.so.download_finished(False)
|
||||
return
|
||||
|
||||
wallet = self._app.daemon.currentWallet.wallet
|
||||
|
||||
def push_thread(wallet):
|
||||
try:
|
||||
self.push(wallet)
|
||||
self.so.upload_finished(True)
|
||||
self._app.appController.userNotify.emit(_('Labels uploaded'))
|
||||
except Exception as e:
|
||||
self.logger.error(repr(e))
|
||||
self.so.upload_finished(False)
|
||||
self._app.appController.userNotify.emit(repr(e))
|
||||
|
||||
threading.Thread(target=push_thread,args=[wallet]).start()
|
||||
|
||||
def pull_async(self):
|
||||
if not self._app.daemon.currentWallet:
|
||||
self.logger.error('No current wallet')
|
||||
self.so.download_finished(False)
|
||||
return
|
||||
|
||||
wallet = self._app.daemon.currentWallet.wallet
|
||||
def pull_thread(wallet):
|
||||
try:
|
||||
self.pull(wallet, True)
|
||||
self.so.download_finished(True)
|
||||
self._app.appController.userNotify.emit(_('Labels downloaded'))
|
||||
except Exception as e:
|
||||
self.logger.error(repr(e))
|
||||
self.so.download_finished(False)
|
||||
self._app.appController.userNotify.emit(repr(e))
|
||||
|
||||
threading.Thread(target=pull_thread,args=[wallet]).start()
|
||||
|
||||
|
||||
def on_pulled(self, wallet):
|
||||
self.logger.info('on pulled')
|
||||
_wallet = QEWallet.getInstanceFor(wallet)
|
||||
self.logger.debug('wallet ' + ('found' if _wallet else 'not found'))
|
||||
if _wallet:
|
||||
_wallet.labelsUpdated.emit()
|
||||
|
||||
@hook
|
||||
def init_qml(self, gui: 'ElectrumGui'):
|
||||
self.logger.debug('init_qml hook called')
|
||||
self.logger.debug(f'gui={str(type(gui))}')
|
||||
self._app = gui.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)
|
||||
@@ -10,8 +10,6 @@ class Plugin(BasePlugin):
|
||||
def __init__(self, parent, config, name):
|
||||
BasePlugin.__init__(self, parent, config, name)
|
||||
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
@hook
|
||||
def init_qml(self, gui: 'ElectrumGui'):
|
||||
self._logger.debug('init_qml hook called')
|
||||
self.logger.debug('init_qml hook called')
|
||||
|
||||
Reference in New Issue
Block a user