12 changed files with 234 additions and 191 deletions
@ -0,0 +1,29 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
|
||||||
|
<FrameLayout |
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent"> |
||||||
|
|
||||||
|
<FrameLayout |
||||||
|
android:id="@+id/content_frame" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/hint" |
||||||
|
android:layout_gravity="center|top" |
||||||
|
android:text="Scan a QR code." |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:textColor="#ffffff" |
||||||
|
android:layout_height="wrap_content" /> |
||||||
|
|
||||||
|
<Button |
||||||
|
android:id="@+id/paste_btn" |
||||||
|
android:layout_gravity="center|bottom" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:text="Paste from clipboard" /> |
||||||
|
|
||||||
|
</FrameLayout> |
||||||
@ -1,51 +0,0 @@ |
|||||||
import QtQuick |
|
||||||
import QtQuick.Controls |
|
||||||
import QtQuick.Layouts |
|
||||||
|
|
||||||
import "controls" |
|
||||||
|
|
||||||
ElDialog { |
|
||||||
id: scanDialog |
|
||||||
|
|
||||||
property string scanData |
|
||||||
property string error |
|
||||||
property string hint |
|
||||||
|
|
||||||
signal found |
|
||||||
|
|
||||||
width: parent.width |
|
||||||
height: parent.height |
|
||||||
padding: 0 |
|
||||||
|
|
||||||
header: null |
|
||||||
topPadding: 0 // dialog needs topPadding override |
|
||||||
|
|
||||||
function doClose() { |
|
||||||
qrscan.stop() |
|
||||||
Qt.callLater(doReject) |
|
||||||
} |
|
||||||
|
|
||||||
ColumnLayout { |
|
||||||
anchors.fill: parent |
|
||||||
spacing: 0 |
|
||||||
|
|
||||||
QRScan { |
|
||||||
id: qrscan |
|
||||||
Layout.fillWidth: true |
|
||||||
Layout.fillHeight: true |
|
||||||
hint: scanDialog.hint |
|
||||||
onFound: { |
|
||||||
scanDialog.scanData = scanData |
|
||||||
scanDialog.found() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
FlatButton { |
|
||||||
id: button |
|
||||||
Layout.fillWidth: true |
|
||||||
text: qsTr('Cancel') |
|
||||||
icon.source: '../../icons/closebutton.png' |
|
||||||
onClicked: doReject() |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,82 +0,0 @@ |
|||||||
import QtQuick |
|
||||||
import QtQuick.Controls |
|
||||||
import QtQuick.Layouts |
|
||||||
import QtQuick.Controls.Material |
|
||||||
|
|
||||||
import org.electrum 1.0 |
|
||||||
|
|
||||||
import "controls" |
|
||||||
|
|
||||||
ElDialog { |
|
||||||
id: dialog |
|
||||||
|
|
||||||
property InvoiceParser invoiceParser |
|
||||||
|
|
||||||
signal txFound(data: string) |
|
||||||
signal channelBackupFound(data: string) |
|
||||||
|
|
||||||
header: null |
|
||||||
padding: 0 |
|
||||||
topPadding: 0 |
|
||||||
|
|
||||||
onAboutToHide: { |
|
||||||
console.log('about to hide') |
|
||||||
qrscan.stop() |
|
||||||
} |
|
||||||
|
|
||||||
function restart() { |
|
||||||
qrscan.restart() |
|
||||||
} |
|
||||||
|
|
||||||
function dispatch(data) { |
|
||||||
data = data.trim() |
|
||||||
if (bitcoin.isRawTx(data)) { |
|
||||||
txFound(data) |
|
||||||
} else if (Daemon.currentWallet.isValidChannelBackup(data)) { |
|
||||||
channelBackupFound(data) |
|
||||||
} else { |
|
||||||
invoiceParser.recipient = data |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// override |
|
||||||
function doClose() { |
|
||||||
console.log('SendDialog doClose override') // doesn't trigger when going back?? |
|
||||||
qrscan.stop() |
|
||||||
Qt.callLater(doReject) |
|
||||||
} |
|
||||||
|
|
||||||
ColumnLayout { |
|
||||||
anchors.fill: parent |
|
||||||
spacing: 0 |
|
||||||
|
|
||||||
QRScan { |
|
||||||
id: qrscan |
|
||||||
Layout.fillWidth: true |
|
||||||
Layout.fillHeight: true |
|
||||||
|
|
||||||
hint: qsTr('Scan an Invoice, an Address, an LNURL-pay, a PSBT or a Channel backup') |
|
||||||
onFound: dialog.dispatch(scanData) |
|
||||||
} |
|
||||||
|
|
||||||
ButtonContainer { |
|
||||||
Layout.fillWidth: true |
|
||||||
|
|
||||||
FlatButton { |
|
||||||
Layout.fillWidth: true |
|
||||||
Layout.preferredWidth: 1 |
|
||||||
icon.source: '../../icons/copy_bw.png' |
|
||||||
text: qsTr('Paste') |
|
||||||
onClicked: { |
|
||||||
qrscan.stop() |
|
||||||
dialog.dispatch(AppController.clipboardToText()) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
Bitcoin { |
|
||||||
id: bitcoin |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,96 @@ |
|||||||
|
import os |
||||||
|
|
||||||
|
from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject |
||||||
|
from PyQt6.QtGui import QGuiApplication |
||||||
|
|
||||||
|
from electrum.util import send_exception_to_crash_reporter, UserFacingException |
||||||
|
from electrum.simple_config import SimpleConfig |
||||||
|
from electrum.logging import get_logger |
||||||
|
from electrum.i18n import _ |
||||||
|
|
||||||
|
|
||||||
|
if 'ANDROID_DATA' in os.environ: |
||||||
|
from jnius import autoclass, cast |
||||||
|
from android import activity |
||||||
|
|
||||||
|
jpythonActivity = autoclass('org.kivy.android.PythonActivity').mActivity |
||||||
|
jString = autoclass('java.lang.String') |
||||||
|
jIntent = autoclass('android.content.Intent') |
||||||
|
|
||||||
|
|
||||||
|
class QEQRScanner(QObject): |
||||||
|
_logger = get_logger(__name__) |
||||||
|
|
||||||
|
found = pyqtSignal() |
||||||
|
|
||||||
|
def __init__(self, parent=None): |
||||||
|
super().__init__(parent) |
||||||
|
self._hint = _("Scan a QR code.") |
||||||
|
self._scan_data = "" # decoded qr code result |
||||||
|
|
||||||
|
@pyqtProperty(str) |
||||||
|
def hint(self): |
||||||
|
return self._hint |
||||||
|
|
||||||
|
@hint.setter |
||||||
|
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: |
||||||
|
self._scan_qr_non_android() |
||||||
|
return |
||||||
|
SimpleScannerActivity = autoclass("org.electrum.qr.SimpleScannerActivity") |
||||||
|
intent = jIntent(jpythonActivity, SimpleScannerActivity) |
||||||
|
intent.putExtra(jIntent.EXTRA_TEXT, jString(self._hint)) |
||||||
|
|
||||||
|
def on_qr_result(requestCode, resultCode, intent): |
||||||
|
try: |
||||||
|
if resultCode == -1: # RESULT_OK: |
||||||
|
# this doesn't work due to some bug in jnius: |
||||||
|
# contents = intent.getStringExtra("text") |
||||||
|
contents = intent.getStringExtra(jString("text")) |
||||||
|
#self._logger.info(f"on_qr_result. {contents=!r}") |
||||||
|
self.scanData = contents |
||||||
|
self.found.emit() |
||||||
|
except Exception as e: # exc would otherwise get lost |
||||||
|
send_exception_to_crash_reporter(e) |
||||||
|
finally: |
||||||
|
activity.unbind(on_activity_result=on_qr_result) |
||||||
|
activity.bind(on_activity_result=on_qr_result) |
||||||
|
jpythonActivity.startActivityForResult(intent, 0) |
||||||
|
|
||||||
|
@pyqtSlot() |
||||||
|
def close(self): |
||||||
|
pass |
||||||
|
|
||||||
|
def _scan_qr_non_android(self): |
||||||
|
data = QGuiApplication.clipboard().text() |
||||||
|
self.scanData = data |
||||||
|
self.found.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)) |
||||||
Loading…
Reference in new issue