Skip to content

Commit

Permalink
qml: integrate java based QR scanner for android, keep qt scanner for…
Browse files Browse the repository at this point in the history
… desktop
  • Loading branch information
accumulator committed Oct 24, 2023
1 parent 3cd7470 commit 3cabc98
Show file tree
Hide file tree
Showing 11 changed files with 271 additions and 26 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ electrum/locale/
packages
env/
.buildozer
.buildozer_kivy/
.buildozer_qml/
.buildozer_*/
bin/
/app.fil
.idea
Expand Down
2 changes: 1 addition & 1 deletion contrib/android/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ RUN cd /opt \
&& git fetch --all \
# commit: from branch accumulator/qt6-wip (note: careful with force-pushing! see #8162) \
#
&& git checkout "3b3733dbf5f461e197ba83887ac0d3b6d0f1c396^{commit}" \
&& git checkout "eb4a3522373e0b4e2749b8a8bc965ff51355ea35^{commit}" \
&& /opt/venv/bin/python3 -m pip install --no-build-isolation --no-dependencies -e .

# build env vars
Expand Down
22 changes: 19 additions & 3 deletions contrib/android/buildozer_qml.spec
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,25 @@ android.add_jars = .buildozer/android/platform/*/build/libs_collections/Electrum

# (list) List of Java files to add to the android project (can be java or a
# directory containing the files)
# android.add_src = ...
# android.add_activities = ...
android.gradle_dependencies = com.android.support:support-compat:28.0.0
android.add_src = electrum/gui/qml/java_classes/

android.gradle_dependencies =
com.android.support:support-compat:28.0.0,
me.dm7.barcodescanner:zxing:1.9.8

android.add_activities = org.electrum.qr.SimpleScannerActivity

# (list) Put these files or directories in the apk res directory.
# The option may be used in three ways, the value may contain one or zero ':'
# Some examples:
# 1) A file to add to resources, legal resource names contain ['a-z','0-9','_']
# android.add_resources = my_icons/all-inclusive.png:drawable/all_inclusive.png
# 2) A directory, here 'legal_icons' must contain resources of one kind
# android.add_resources = legal_icons:drawable
# 3) A directory, here 'legal_resources' must contain one or more directories,
# each of a resource kind: drawable, xml, etc...
# android.add_resources = legal_resources
android.add_resources = electrum/gui/qml/android_res/layout:layout

# (str) python-for-android branch to use, if not master, useful to try
# not yet merged features.
Expand Down
29 changes: 29 additions & 0 deletions electrum/gui/qml/android_res/layout/scanner_layout.xml
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions electrum/gui/qml/components/ScanDialog.qml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import QtQuick.Layouts

import "controls"

// currently not used on android, kept for future use when qt6 camera stops crashing
ElDialog {
id: scanDialog

Expand Down
1 change: 1 addition & 0 deletions electrum/gui/qml/components/SendDialog.qml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.electrum 1.0

import "controls"

// currently not used on android, kept for future use when qt6 camera stops crashing
ElDialog {
id: dialog

Expand Down
66 changes: 53 additions & 13 deletions electrum/gui/qml/components/WalletMainView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,56 @@ Item {
}

function openSendDialog() {
_sendDialog = sendDialog.createObject(mainView, {invoiceParser: invoiceParser})
_sendDialog.open()
// Qt based send dialog if not on android
if (!AppController.isAndroid()) {
_sendDialog = qtSendDialog.createObject(mainView, {invoiceParser: invoiceParser})
_sendDialog.open()
return
}

// Android based send dialog if on android
var scanner = app.scanDialog.createObject(mainView, {
hint: qsTr('Scan an Invoice, an Address, an LNURL-pay, a PSBT or a Channel backup'),
})
scanner.onFound.connect(function() {
var data = scanner.scanData
data = data.trim()
if (bitcoin.isRawTx(data)) {
app.stack.push(Qt.resolvedUrl('TxDetails.qml'), { rawtx: data })
} else if (Daemon.currentWallet.isValidChannelBackup(data)) {
var dialog = app.messageDialog.createObject(app, {
title: qsTr('Import Channel backup?'),
yesno: true
})
dialog.accepted.connect(function() {
Daemon.currentWallet.importChannelBackup(data)
})
dialog.open()
} else {
invoiceParser.recipient = data
}
//scanner.destroy() // TODO
})
scanner.open()
}

function closeSendDialog() {
if (_sendDialog) {
_sendDialog.doClose()
_sendDialog = null
if (!AppController.isAndroid()) {
if (_sendDialog) {
_sendDialog.doClose()
_sendDialog = null
}
}
}

function restartSendDialog() {
if (_sendDialog) {
_sendDialog.restart()
if (!AppController.isAndroid()) {
if (_sendDialog) {
_sendDialog.restart()
}
return
} else {
openSendDialog()
}
}

Expand Down Expand Up @@ -86,6 +122,11 @@ Item {
dialog.open()
}

function createRequest(lightning_only, reuse_address) {
var qamt = Config.unitsToSats(_request_amount)
Daemon.currentWallet.createRequest(qamt, _request_description, _request_expiry, lightning_only, reuse_address)
}

property QtObject menu: Menu {
id: menu

Expand Down Expand Up @@ -314,6 +355,10 @@ Item {
}
}

Bitcoin {
id: bitcoin
}

Connections {
target: AppController
function onUriReceived(uri) {
Expand Down Expand Up @@ -420,7 +465,7 @@ Item {
}

Component {
id: sendDialog
id: qtSendDialog
SendDialog {
width: parent.width
height: parent.height
Expand All @@ -447,11 +492,6 @@ Item {
}
}

function createRequest(lightning_only, reuse_address) {
var qamt = Config.unitsToSats(_request_amount)
Daemon.currentWallet.createRequest(qamt, _request_description, _request_expiry, lightning_only, reuse_address)
}

Component {
id: receiveDetailsDialog

Expand Down
14 changes: 13 additions & 1 deletion electrum/gui/qml/components/main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -377,9 +377,15 @@ ApplicationWindow
}
}

property alias scanDialog: _scanDialog
property Component scanDialog // set in Component.onCompleted
Component {
id: _scanDialog
QRScanner {
//onClosed: destroy()
}
}
Component {
id: _qtScanDialog
ScanDialog {
onClosed: destroy()
}
Expand Down Expand Up @@ -434,6 +440,12 @@ ApplicationWindow
Component.onCompleted: {
coverTimer.start()

if (AppController.isAndroid()) {
app.scanDialog = _scanDialog
} else {
app.scanDialog = _qtScanDialog
}

if (!Config.autoConnectDefined) {
var dialog = serverConnectWizard.createObject(app)
// without completed serverConnectWizard we can't start
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@
import android.util.Log;
import android.content.Intent;
import android.Manifest;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.core.app.ActivityCompat;

Expand All @@ -16,18 +25,53 @@
import com.google.zxing.Result;
import com.google.zxing.BarcodeFormat;

import org.electrum.electrum.res.R; // package set in build.gradle

public class SimpleScannerActivity extends Activity implements ZXingScannerView.ResultHandler {
private static final int MY_PERMISSIONS_CAMERA = 1002;

private ZXingScannerView mScannerView = null;
final String TAG = "org.electrum.SimpleScannerActivity";

private boolean mAlreadyRequestedPermissions = false;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.scanner_layout);

// change top text
Intent intent = getIntent();
String text = intent.getStringExtra(intent.EXTRA_TEXT);
TextView hintTextView = (TextView) findViewById(R.id.hint);
hintTextView.setText(text);

// bind "paste" button
Button btn = (Button) findViewById(R.id.paste_btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
if (clipboard.hasPrimaryClip()
&& (clipboard.getPrimaryClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)
|| clipboard.getPrimaryClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_HTML))) {
ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0);
String clipboardText = item.getText().toString();
SimpleScannerActivity.this.setResultAndClose(clipboardText);
} else {
Toast.makeText(SimpleScannerActivity.this, "Clipboard is empty.", Toast.LENGTH_SHORT).show();
}
}
});
}

@Override
public void onResume() {
super.onResume();
if (this.hasPermission()) {
this.startCamera();
} else {
} else if (!mAlreadyRequestedPermissions) {
mAlreadyRequestedPermissions = true;
this.requestPermission();
}
}
Expand All @@ -41,18 +85,23 @@ public void onPause() {
}

private void startCamera() {
mScannerView = new ZXingScannerView(this); // Programmatically initialize the scanner view
mScannerView = new ZXingScannerView(this);
mScannerView.setFormats(Arrays.asList(BarcodeFormat.QR_CODE));
setContentView(mScannerView); // Set the scanner view as the content view
ViewGroup contentFrame = (ViewGroup) findViewById(R.id.content_frame);
contentFrame.addView(mScannerView);
mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results.
mScannerView.startCamera(); // Start camera on resume
}

@Override
public void handleResult(Result rawResult) {
//resultIntent.putExtra("format", rawResult.getBarcodeFormat().toString());
this.setResultAndClose(rawResult.getText());
}

private void setResultAndClose(String resultText) {
Intent resultIntent = new Intent();
resultIntent.putExtra("text", rawResult.getText());
resultIntent.putExtra("format", rawResult.getBarcodeFormat().toString());
resultIntent.putExtra("text", resultText);
setResult(Activity.RESULT_OK, resultIntent);
this.finish();
}
Expand Down Expand Up @@ -80,7 +129,7 @@ public void onRequestPermissionsResult(int requestCode,
this.startCamera();
} else {
// permission denied
this.finish();
//this.finish();
}
return;
}
Expand Down
2 changes: 2 additions & 0 deletions electrum/gui/qml/qeapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from .qenetwork import QENetwork
from .qewallet import QEWallet
from .qeqr import QEQRParser, QEQRImageProvider, QEQRImageProviderHelper
from .qeqrscanner import QEQRScanner
from .qebitcoin import QEBitcoin
from .qefx import QEFX
from .qetxfinalizer import QETxFinalizer, QETxRbfFeeBumper, QETxCpfpFeeBumper, QETxCanceller
Expand Down Expand Up @@ -353,6 +354,7 @@ def __init__(self, args, *, config: 'SimpleConfig', daemon: 'Daemon', plugins: '
qmlRegisterType(QEWallet, 'org.electrum', 1, 0, 'Wallet')
qmlRegisterType(QEBitcoin, 'org.electrum', 1, 0, 'Bitcoin')
qmlRegisterType(QEQRParser, 'org.electrum', 1, 0, 'QRParser')
qmlRegisterType(QEQRScanner, 'org.electrum', 1, 0, 'QRScanner')
qmlRegisterType(QEFX, 'org.electrum', 1, 0, 'FX')
qmlRegisterType(QETxFinalizer, 'org.electrum', 1, 0, 'TxFinalizer')
qmlRegisterType(QEInvoice, 'org.electrum', 1, 0, 'Invoice')
Expand Down
Loading

0 comments on commit 3cabc98

Please sign in to comment.