From 97f02bca3b05e7becbb61559b03fdf55e152bf2f Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Fri, 4 Nov 2022 15:59:27 +0100 Subject: [PATCH] qml: add import additional addresses/keys to import wallet --- .../components/ImportAddressesKeysDialog.qml | 130 ++++++++++++++++++ electrum/gui/qml/components/WalletDetails.qml | 78 +++++++---- .../gui/qml/components/wizard/WCImport.qml | 1 + electrum/gui/qml/qewallet.py | 11 ++ 4 files changed, 193 insertions(+), 27 deletions(-) create mode 100644 electrum/gui/qml/components/ImportAddressesKeysDialog.qml diff --git a/electrum/gui/qml/components/ImportAddressesKeysDialog.qml b/electrum/gui/qml/components/ImportAddressesKeysDialog.qml new file mode 100644 index 000000000..57add3c2a --- /dev/null +++ b/electrum/gui/qml/components/ImportAddressesKeysDialog.qml @@ -0,0 +1,130 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.3 + +import org.electrum 1.0 + +import "controls" + +ElDialog { + id: root + + property bool valid: false + + standardButtons: Dialog.Close + modal: true + parent: Overlay.overlay + Overlay.modal: Rectangle { + color: "#aa000000" + } + width: parent.width + height: parent.height + + title: Daemon.currentWallet.isWatchOnly + ? qsTr('Import additional addresses') + : qsTr('Import additional keys') + + function verify(text) { + if (Daemon.currentWallet.isWatchOnly) + return bitcoin.isAddressList(text) + else + return bitcoin.isPrivateKeyList(text) + } + + onAccepted: { + if (Daemon.currentWallet.isWatchOnly) + Daemon.currentWallet.importAddresses(import_ta.text) + else + Daemon.currentWallet.importPrivateKeys(import_ta.text) + } + + ColumnLayout { + width: parent.width + height: parent.height + + Label { + text: Daemon.currentWallet.isWatchOnly + ? qsTr('Import additional addresses') + : qsTr('Import additional keys') + } + + RowLayout { + TextArea { + id: import_ta + Layout.fillWidth: true + Layout.minimumHeight: 80 + focus: true + wrapMode: TextEdit.WrapAnywhere + onTextChanged: valid = verify(text) + } + ColumnLayout { + Layout.alignment: Qt.AlignTop + ToolButton { + icon.source: '../../icons/paste.png' + icon.height: constants.iconSizeMedium + icon.width: constants.iconSizeMedium + onClicked: { + if (verify(AppController.clipboardToText())) { + if (import_ta.text != '') + import_ta.text = import_ta.text + '\n' + import_ta.text = import_ta.text + AppController.clipboardToText() + } + } + } + ToolButton { + icon.source: '../../icons/qrcode.png' + icon.height: constants.iconSizeMedium + icon.width: constants.iconSizeMedium + scale: 1.2 + onClicked: { + var scan = qrscan.createObject(root.contentItem) // can't use dialog as parent? + scan.onFound.connect(function() { + if (verify(scan.scanData)) { + if (import_ta.text != '') + import_ta.text = import_ta.text + ',\n' + import_ta.text = import_ta.text + scan.scanData + } + scan.destroy() + }) + } + } + } + } + + Item { + Layout.preferredWidth: 1 + Layout.fillHeight: true + } + + FlatButton { + Layout.fillWidth: true + text: qsTr('Import') + enabled: valid + onClicked: accept() + } + } + + Component { + id: qrscan + QRScan { + width: parent.width + height: parent.height + + ToolButton { + icon.source: '../../icons/closebutton.png' + icon.height: constants.iconSizeMedium + icon.width: constants.iconSizeMedium + anchors.right: parent.right + anchors.top: parent.top + onClicked: { + parent.destroy() + } + } + } + } + + Bitcoin { + id: bitcoin + } + +} diff --git a/electrum/gui/qml/components/WalletDetails.qml b/electrum/gui/qml/components/WalletDetails.qml index c8113c4a7..18df38413 100644 --- a/electrum/gui/qml/components/WalletDetails.qml +++ b/electrum/gui/qml/components/WalletDetails.qml @@ -36,6 +36,10 @@ Pane { Daemon.start_change_password() } + function importAddressesKeys() { + var dialog = importAddressesKeysDialog.createObject(rootItem) + dialog.open() + } ColumnLayout { id: rootLayout @@ -202,34 +206,37 @@ Pane { color: Material.accentColor } - ColumnLayout { + TextHighlightPane { Layout.columnSpan: 2 - Layout.leftMargin: constants.paddingMedium - spacing: 0 + Layout.fillWidth: true - ButtonGroup { - id: billinggroup - onCheckedButtonChanged: { - Config.trustedcoinPrepay = checkedButton.value - } - } + ColumnLayout { + spacing: 0 - Repeater { - model: AppController.plugin('trustedcoin').billingModel - delegate: RowLayout { - RadioButton { - ButtonGroup.group: billinggroup - property string value: modelData.value - text: modelData.text - checked: modelData.value == Config.trustedcoinPrepay + ButtonGroup { + id: billinggroup + onCheckedButtonChanged: { + Config.trustedcoinPrepay = checkedButton.value } - Label { - text: Config.formatSats(modelData.sats_per_tx) - font.family: FixedFont - } - Label { - text: Config.baseUnit + '/tx' - color: Material.accentColor + } + + Repeater { + model: AppController.plugin('trustedcoin').billingModel + delegate: RowLayout { + RadioButton { + ButtonGroup.group: billinggroup + property string value: modelData.value + text: modelData.text + checked: modelData.value == Config.trustedcoinPrepay + } + Label { + text: Config.formatSats(modelData.sats_per_tx) + font.family: FixedFont + } + Label { + text: Config.baseUnit + '/tx' + color: Material.accentColor + } } } } @@ -294,19 +301,27 @@ Pane { FlatButton { Layout.fillWidth: true - text: qsTr('Change Password'); + visible: Daemon.currentWallet.walletType == 'imported' + text: Daemon.currentWallet.isWatchOnly + ? qsTr('Import additional addresses') + : qsTr('Import additional keys') + onClicked: rootItem.importAddressesKeys() + } + FlatButton { + Layout.fillWidth: true + text: qsTr('Change Password') onClicked: rootItem.changePassword() icon.source: '../../icons/lock.png' } FlatButton { Layout.fillWidth: true - text: qsTr('Delete Wallet'); + text: qsTr('Delete Wallet') onClicked: rootItem.deleteWallet() icon.source: '../../icons/delete.png' } FlatButton { Layout.fillWidth: true - text: qsTr('Enable Lightning'); + text: qsTr('Enable Lightning') onClicked: rootItem.enableLightning() visible: Daemon.currentWallet && Daemon.currentWallet.canHaveLightning && !Daemon.currentWallet.isLightning icon.source: '../../icons/lightning.png' @@ -372,6 +387,15 @@ Pane { } } + Component { + id: importAddressesKeysDialog + ImportAddressesKeysDialog { + width: parent.width + height: parent.height + onClosed: destroy() + } + } + Component.onCompleted: { piechart.updateSlices() } diff --git a/electrum/gui/qml/components/wizard/WCImport.qml b/electrum/gui/qml/components/wizard/WCImport.qml index 5158d3fd5..86bddc5d0 100644 --- a/electrum/gui/qml/components/wizard/WCImport.qml +++ b/electrum/gui/qml/components/wizard/WCImport.qml @@ -29,6 +29,7 @@ WizardComponent { Label { text: qsTr('Import Bitcoin Addresses') } InfoTextArea { + Layout.preferredWidth: parent.width text: qsTr('Enter a list of Bitcoin addresses (this will create a watching-only wallet), or a list of private keys.') } diff --git a/electrum/gui/qml/qewallet.py b/electrum/gui/qml/qewallet.py index 2634966b2..b62a34c87 100644 --- a/electrum/gui/qml/qewallet.py +++ b/electrum/gui/qml/qewallet.py @@ -348,6 +348,8 @@ class QEWallet(AuthMixin, QObject, QtEventListener): if len(keystores) == 0: self._logger.debug('no keystore') return '' + if not self.isDeterministic: + return '' return keystores[0].get_derivation_prefix() @pyqtProperty(str, notify=dataChanged) @@ -660,3 +662,12 @@ class QEWallet(AuthMixin, QObject, QtEventListener): self.password = password except InvalidPassword as e: self._logger.exception(repr(e)) + + @pyqtSlot(str) + def importAddresses(self, addresslist): + self.wallet.import_addresses(addresslist.split()) + + @pyqtSlot(str) + def importPrivateKeys(self, keyslist): + self.wallet.import_private_keys(keyslist.split(), self.password) +