Merge pull request #10078 from accumulator/android_qml_qrscan_signals
simplify QR scanner QML interface, remove properties, add results to signals
This commit is contained in:
@@ -91,11 +91,11 @@ ElDialog {
|
||||
? qsTr('Scan another address')
|
||||
: qsTr('Scan another private key')
|
||||
})
|
||||
dialog.onFound.connect(function() {
|
||||
if (verify(dialog.scanData)) {
|
||||
dialog.onFoundText.connect(function(data) {
|
||||
if (verify(data)) {
|
||||
if (import_ta.text != '')
|
||||
import_ta.text = import_ta.text + ',\n'
|
||||
import_ta.text = import_ta.text + dialog.scanData
|
||||
import_ta.text = import_ta.text + data
|
||||
}
|
||||
dialog.close()
|
||||
})
|
||||
|
||||
@@ -62,8 +62,8 @@ ElDialog {
|
||||
var dialog = app.scanDialog.createObject(app, {
|
||||
hint: qsTr('Scan a channel backup')
|
||||
})
|
||||
dialog.onFound.connect(function() {
|
||||
channelbackup_ta.text = dialog.scanData
|
||||
dialog.onFoundText.connect(function(data) {
|
||||
channelbackup_ta.text = data
|
||||
dialog.close()
|
||||
})
|
||||
dialog.open()
|
||||
|
||||
@@ -124,9 +124,9 @@ ElDialog {
|
||||
var dialog = app.scanDialog.createObject(app, {
|
||||
hint: qsTr('Scan a node-id or a connect string')
|
||||
})
|
||||
dialog.onFound.connect(function() {
|
||||
if (channelopener.validateConnectString(dialog.scanData)) {
|
||||
channelopener.connectStr = dialog.scanData
|
||||
dialog.onFoundText.connect(function(data) {
|
||||
if (channelopener.validateConnectString(data)) {
|
||||
channelopener.connectStr = data
|
||||
node.text = channelopener.connectStr
|
||||
} else {
|
||||
var errdialog = app.messageDialog.createObject(app, {
|
||||
|
||||
@@ -2,17 +2,19 @@ import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.electrum
|
||||
|
||||
import "controls"
|
||||
|
||||
// currently not used on android, kept for future use when qt6 camera stops crashing
|
||||
ElDialog {
|
||||
id: scanDialog
|
||||
|
||||
property string scanData
|
||||
property string error
|
||||
property string hint
|
||||
|
||||
signal found
|
||||
signal foundText(data: string)
|
||||
signal foundBinary(data: Bytes)
|
||||
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
@@ -35,9 +37,8 @@ ElDialog {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
hint: scanDialog.hint
|
||||
onFound: {
|
||||
scanDialog.scanData = scanData
|
||||
scanDialog.found()
|
||||
onFoundText: (data) => {
|
||||
scanDialog.foundText(data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,10 @@ ElDialog {
|
||||
hint: Daemon.currentWallet.isLightning
|
||||
? qsTr('Scan an Invoice, an Address, an LNURL-pay, a PSBT or a Channel Backup')
|
||||
: qsTr('Scan an Invoice, an Address, an LNURL-pay or a PSBT')
|
||||
onFound: dialog.dispatch(scanData)
|
||||
|
||||
onFoundText: (data) => {
|
||||
dialog.dispatch(data)
|
||||
}
|
||||
}
|
||||
|
||||
ButtonContainer {
|
||||
|
||||
@@ -117,9 +117,9 @@ ElDialog {
|
||||
var dialog = app.scanDialog.createObject(app, {
|
||||
hint: qsTr('Scan a private key')
|
||||
})
|
||||
dialog.onFound.connect(function() {
|
||||
if (verifyPrivateKey(dialog.scanData))
|
||||
addPrivateKey(dialog.scanData)
|
||||
dialog.onFoundText.connect(function(data) {
|
||||
if (verifyPrivateKey(data))
|
||||
addPrivateKey(data)
|
||||
dialog.close()
|
||||
})
|
||||
dialog.open()
|
||||
|
||||
@@ -47,8 +47,7 @@ Item {
|
||||
? qsTr('Scan an Invoice, an Address, an LNURL-pay, a PSBT or a Channel Backup')
|
||||
: qsTr('Scan an Invoice, an Address, an LNURL-pay or a PSBT')
|
||||
})
|
||||
scanner.onFound.connect(function() {
|
||||
var data = scanner.scanData
|
||||
scanner.onFoundText.connect(function(data) {
|
||||
data = data.trim()
|
||||
if (bitcoin.isRawTx(data)) {
|
||||
app.stack.push(Qt.resolvedUrl('TxDetails.qml'), { rawtx: data })
|
||||
|
||||
@@ -10,14 +10,12 @@ Item {
|
||||
|
||||
property bool active: false
|
||||
property string url
|
||||
property string scanData
|
||||
property string hint
|
||||
|
||||
signal found
|
||||
signal foundText(data: string)
|
||||
|
||||
function restart() {
|
||||
console.log('qrscan.restart')
|
||||
scanData = ''
|
||||
qr.reset()
|
||||
start()
|
||||
}
|
||||
@@ -153,8 +151,7 @@ Item {
|
||||
function onDataChanged() {
|
||||
console.log('QR DATA: ' + qr.data)
|
||||
scanner.active = false
|
||||
scanner.scanData = qr.data
|
||||
scanner.found()
|
||||
scanner.foundText(qr.data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -166,9 +166,9 @@ WizardComponent {
|
||||
? qsTr('Scan a cosigner master public key')
|
||||
: qsTr('Scan a master key')
|
||||
})
|
||||
dialog.onFound.connect(function() {
|
||||
if (verifyMasterKey(dialog.scanData))
|
||||
masterkey_ta.text = dialog.scanData
|
||||
dialog.onFoundText.connect(function(data) {
|
||||
if (verifyMasterKey(data))
|
||||
masterkey_ta.text = data
|
||||
else
|
||||
masterkey_ta.text = ''
|
||||
dialog.close()
|
||||
|
||||
@@ -76,11 +76,11 @@ WizardComponent {
|
||||
? qsTr('Scan another private key')
|
||||
: qsTr('Scan a private key or an address')
|
||||
})
|
||||
dialog.onFound.connect(function() {
|
||||
if (verify(dialog.scanData)) {
|
||||
dialog.onFoundText.connect(function(data) {
|
||||
if (verify(data)) {
|
||||
if (import_ta.text != '')
|
||||
import_ta.text = import_ta.text + '\n'
|
||||
import_ta.text = import_ta.text + dialog.scanData
|
||||
import_ta.text = import_ta.text + data
|
||||
}
|
||||
dialog.close()
|
||||
})
|
||||
|
||||
@@ -21,6 +21,8 @@ import androidx.core.app.ActivityCompat;
|
||||
import java.util.Arrays;
|
||||
|
||||
import de.markusfisch.android.barcodescannerview.widget.BarcodeScannerView;
|
||||
import de.markusfisch.android.zxingcpp.ZxingCpp.Result;
|
||||
import de.markusfisch.android.zxingcpp.ZxingCpp.ContentType;
|
||||
|
||||
|
||||
import org.electrum.electrum.res.R; // package set in build.gradle
|
||||
@@ -29,7 +31,7 @@ public class SimpleScannerActivity extends Activity {
|
||||
private static final int MY_PERMISSIONS_CAMERA = 1002;
|
||||
|
||||
private BarcodeScannerView mScannerView = null;
|
||||
final String TAG = "org.electrum.SimpleScannerActivity";
|
||||
final String TAG = "org.electrum.qr.SimpleScannerActivity";
|
||||
|
||||
private boolean mAlreadyRequestedPermissions = false;
|
||||
|
||||
@@ -60,7 +62,7 @@ public class SimpleScannerActivity extends Activity {
|
||||
Toast.makeText(SimpleScannerActivity.this, "Clipboard contents too large.", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
SimpleScannerActivity.this.setResultAndClose(clipboardText);
|
||||
SimpleScannerActivity.this.setResultAndClose(null, clipboardText);
|
||||
} else {
|
||||
Toast.makeText(SimpleScannerActivity.this, "Clipboard is empty.", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
@@ -96,7 +98,7 @@ public class SimpleScannerActivity extends Activity {
|
||||
contentFrame.addView(mScannerView);
|
||||
mScannerView.setOnBarcodeListener(result -> {
|
||||
// Handle the scan result
|
||||
this.setResultAndClose(result.getText());
|
||||
this.setResultAndClose(result, null);
|
||||
// Return false to stop scanning after first result
|
||||
return false;
|
||||
});
|
||||
@@ -104,9 +106,22 @@ public class SimpleScannerActivity extends Activity {
|
||||
mScannerView.openAsync(); // Start camera on resume
|
||||
}
|
||||
|
||||
private void setResultAndClose(String resultText) {
|
||||
private void setResultAndClose(Result scanResult, String textOnly) {
|
||||
Intent resultIntent = new Intent();
|
||||
resultIntent.putExtra("text", resultText);
|
||||
if (textOnly != null) {
|
||||
Log.v(TAG, "clipboard contentType TEXT");
|
||||
resultIntent.putExtra("text", textOnly);
|
||||
} else if (scanResult != null) {
|
||||
if (scanResult.getContentType() == ContentType.TEXT) {
|
||||
Log.v(TAG, "scanResult contentType TEXT");
|
||||
resultIntent.putExtra("text", scanResult.getText());
|
||||
} else if (scanResult.getContentType() == ContentType.BINARY) {
|
||||
Log.v(TAG, "scanResult contentType BINARY");
|
||||
resultIntent.putExtra("binary", scanResult.getRawBytes());
|
||||
} else {
|
||||
Log.v(TAG, "scanresult contenttype unknown");
|
||||
}
|
||||
}
|
||||
setResult(Activity.RESULT_OK, resultIntent);
|
||||
this.finish();
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ from .qefx import QEFX
|
||||
from .qetxfinalizer import QETxFinalizer, QETxRbfFeeBumper, QETxCpfpFeeBumper, QETxCanceller, QETxSweepFinalizer, FeeSlider
|
||||
from .qeinvoice import QEInvoice, QEInvoiceParser
|
||||
from .qerequestdetails import QERequestDetails
|
||||
from .qetypes import QEAmount
|
||||
from .qetypes import QEAmount, QEBytes
|
||||
from .qeaddressdetails import QEAddressDetails
|
||||
from .qetxdetails import QETxDetails
|
||||
from .qechannelopener import QEChannelOpener
|
||||
@@ -426,6 +426,7 @@ class ElectrumQmlApplication(QGuiApplication):
|
||||
|
||||
# TODO QT6 order of declaration is important now?
|
||||
qmlRegisterType(QEAmount, 'org.electrum', 1, 0, 'Amount')
|
||||
qmlRegisterType(QEBytes, 'org.electrum', 1, 0, 'Bytes')
|
||||
qmlRegisterType(QENewWalletWizard, 'org.electrum', 1, 0, 'QNewWalletWizard')
|
||||
qmlRegisterType(QETermsOfUseWizard, 'org.electrum', 1, 0, 'QTermsOfUseWizard')
|
||||
qmlRegisterType(QEServerConnectWizard, 'org.electrum', 1, 0, 'QServerConnectWizard')
|
||||
|
||||
@@ -3,8 +3,8 @@ import os
|
||||
from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, Qt
|
||||
from PyQt6.QtGui import QGuiApplication
|
||||
|
||||
from electrum.util import send_exception_to_crash_reporter, UserFacingException
|
||||
from electrum.simple_config import SimpleConfig
|
||||
from electrum.gui.qml.qetypes import QEBytes
|
||||
from electrum.util import send_exception_to_crash_reporter
|
||||
from electrum.logging import get_logger
|
||||
from electrum.i18n import _
|
||||
|
||||
@@ -21,14 +21,14 @@ if 'ANDROID_DATA' in os.environ:
|
||||
class QEQRScanner(QObject):
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
found = pyqtSignal()
|
||||
foundText = pyqtSignal(str)
|
||||
foundBinary = pyqtSignal(QEBytes)
|
||||
|
||||
finished = pyqtSignal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self._hint = _("Scan a QR code.")
|
||||
self._scan_data = "" # decoded qr code result
|
||||
self.finished.connect(self._unbind, Qt.ConnectionType.QueuedConnection)
|
||||
|
||||
self.destroyed.connect(lambda: self.on_destroy())
|
||||
@@ -44,14 +44,6 @@ class QEQRScanner(QObject):
|
||||
def hint(self, v: str):
|
||||
self._hint = v
|
||||
|
||||
@pyqtProperty(str)
|
||||
def scanData(self):
|
||||
return self._scan_data
|
||||
|
||||
@scanData.setter
|
||||
def scanData(self, v: str):
|
||||
self._scan_data = v
|
||||
|
||||
@pyqtSlot()
|
||||
def open(self):
|
||||
if 'ANDROID_DATA' not in os.environ:
|
||||
@@ -67,9 +59,11 @@ class QEQRScanner(QObject):
|
||||
def on_qr_activity_result(self, requestCode, resultCode, intent):
|
||||
try:
|
||||
if resultCode == -1: # RESULT_OK:
|
||||
contents = intent.getStringExtra(jString("text"))
|
||||
self.scanData = contents
|
||||
self.found.emit()
|
||||
if (contents := intent.getStringExtra(jString("text"))) is not None:
|
||||
self.foundText.emit(contents)
|
||||
if (contents := intent.getByteArrayExtra(jString("binary"))) is not None:
|
||||
self._binary_content = QEBytes(bytes(contents.tolist()))
|
||||
self.foundBinary.emit(self._binary_content)
|
||||
except Exception as e: # exc would otherwise get lost
|
||||
send_exception_to_crash_reporter(e)
|
||||
finally:
|
||||
@@ -82,23 +76,6 @@ class QEQRScanner(QObject):
|
||||
|
||||
def _scan_qr_non_android(self):
|
||||
data = QGuiApplication.clipboard().text()
|
||||
self.scanData = data
|
||||
self.found.emit()
|
||||
self.foundText.emit(data)
|
||||
self.finished.emit()
|
||||
return
|
||||
# from electrum import qrscanner
|
||||
# from .qeapp import ElectrumQmlApplication
|
||||
# daemon = ElectrumQmlApplication._daemon
|
||||
# config = daemon.config # type: SimpleConfig
|
||||
# try:
|
||||
# video_dev = config.get_video_device()
|
||||
# data = qrscanner.scan_barcode(video_dev)
|
||||
# if data is not None:
|
||||
# self.scanData = data
|
||||
# self.found.emit()
|
||||
# except UserFacingException as e:
|
||||
# self._logger.warning(f'camera error: {e!r}')
|
||||
# #self.show_error(e)
|
||||
# except Exception as e:
|
||||
# self._logger.exception('camera error')
|
||||
# #self.show_error(repr(e))
|
||||
|
||||
@@ -116,3 +116,27 @@ class QEAmount(QObject):
|
||||
|
||||
def __repr__(self):
|
||||
return f"<QEAmount max={self._is_max} sats={self._amount_sat} msats={self._amount_msat} empty={self.isEmpty}>"
|
||||
|
||||
|
||||
class QEBytes(QObject):
|
||||
def __init__(self, data: bytes = None, *, parent=None):
|
||||
super().__init__(parent)
|
||||
self.data = data
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self._data
|
||||
|
||||
@data.setter
|
||||
def data(self, _data):
|
||||
self._data = _data
|
||||
|
||||
@pyqtProperty(bool)
|
||||
def isEmpty(self):
|
||||
return self._data is None or self._data == bytes()
|
||||
|
||||
def __str__(self):
|
||||
return f'{self._data}'
|
||||
|
||||
def __repr__(self):
|
||||
return f"<QEBytes data={'None' if self._data is None else self._data.hex()}>"
|
||||
|
||||
Reference in New Issue
Block a user