Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 "f2741f0b7b6a4ac52fc6cb0dc9ac706e2287be02^{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
2 changes: 1 addition & 1 deletion contrib/android/make_apk.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ info "apk building phase starts."
# FIXME: changing "APP_PACKAGE_NAME" seems to require a clean rebuild of ".buildozer/",
# to avoid that, maybe change "APP_PACKAGE_DOMAIN" instead.
# So, in particular, to build a testnet apk, simply uncomment:
#export APP_PACKAGE_DOMAIN=org.electrum.testnet
export APP_PACKAGE_DOMAIN=org.electrum.testnet
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(temporary)


if [ $CI ]; then
# override log level specified in buildozer.spec to "debug":
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>
51 changes: 0 additions & 51 deletions electrum/gui/qml/components/ScanDialog.qml

This file was deleted.

82 changes: 0 additions & 82 deletions electrum/gui/qml/components/SendDialog.qml

This file was deleted.

71 changes: 28 additions & 43 deletions electrum/gui/qml/components/WalletMainView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ Item {

property string title: Daemon.currentWallet ? Daemon.currentWallet.name : qsTr('no wallet loaded')

property var _sendDialog
property string _intentUri

property string _request_amount
Expand All @@ -34,21 +33,33 @@ Item {
}

function openSendDialog() {
_sendDialog = sendDialog.createObject(mainView, {invoiceParser: invoiceParser})
_sendDialog.open()
}

function closeSendDialog() {
if (_sendDialog) {
_sendDialog.doClose()
_sendDialog = null
}
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
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need an explicit destroy somewhere to avoid a memleak?
I see most dialogs have onClosed: destroy(), but not sure how to mimic that.
Also see main.qml::scanDialog (line 393).

Copy link
Owner

@accumulator accumulator Oct 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onClosed is a signal handler for Popup. Since you use a bare QObject as the base for QEQRScanner, you don't have the plumbing provided by Popup, and you need to detect when the activity is closed and emit a signal, which can then be used to destroy the instance from QML.

However, you don't really need to wrap the scanner in a Qt object and manage the lifecycle. Since there's at most 1 scanner active, you can basically also spawn the Activity from a @pyqtSlot decorated method in e.g. AppController, and just emit signals from AppController depending on the result. I think the Activity will be auto-deleted by the JVM when it's closed, and you don't need to manage any lifecycle on the QML side.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last part would be something like this:

Button {
    onClicked: AppController.showQRScanner()
}

Connections {
    target: AppController
    function onQRScanned(data) {
        // handle data
    }
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can basically also spawn the Activity from a @pyqtSlot decorated method in e.g. AppController, and just emit signals from AppController depending on the result

Yes I already had something like that a refactor prior, e.g. see
SomberNight@bc5f596
I've changed to QEQRScanner(QObject) instead as this way I can easily replace both the ScanDialog and the SendDialog use cases. In particular, QEQRScanner now has an API that is a drop-in replacement for the main.qml::scanDialog usages. The AppController signal approach worked nicely for the SendDialog, but I found it not easy to adapt to the ScanDialog usages.

you don't have the plumbing provided by Popup, and you need to detect when the activity is closed and emit a signal, which can then be used to destroy the instance from QML.
However, you don't really need to wrap the scanner in a Qt object and manage the lifecycle

But just to confirm, if we do use this QEQRScanner(QObject) approach, do we need to explicitly call destroy for the object? (/manually manage the lifecycle)
I guess I could just call destroy wherever the code on master calls close/closeDialog.

})
scanner.open()
}

function restartSendDialog() {
if (_sendDialog) {
_sendDialog.restart()
}
//openSendDialog() // note: ~infinite-loop on non-android due to directly pasting from clipboard
}

function showExport(data, helptext) {
Expand Down Expand Up @@ -287,7 +298,6 @@ Item {
}
}
onValidationSuccess: {
closeSendDialog()
var dialog = invoiceDialog.createObject(app, {
invoice: invoiceParser,
payImmediately: invoiceParser.isLnurlPay
Expand All @@ -299,7 +309,6 @@ Item {
}

onLnurlRetrieved: {
closeSendDialog()
var dialog = lnurlPayDialog.createObject(app, {
invoiceParser: invoiceParser
})
Expand All @@ -314,6 +323,10 @@ Item {
}
}

Bitcoin {
id: bitcoin
}

Connections {
target: AppController
function onUriReceived(uri) {
Expand Down Expand Up @@ -419,34 +432,6 @@ Item {
}
}

Component {
id: sendDialog
SendDialog {
width: parent.width
height: parent.height

onTxFound: {
app.stack.push(Qt.resolvedUrl('TxDetails.qml'), { rawtx: data })
close()
}
onChannelBackupFound: {
var dialog = app.messageDialog.createObject(app, {
title: qsTr('Import Channel backup?'),
yesno: true
})
dialog.accepted.connect(function() {
Daemon.currentWallet.importChannelBackup(data)
close()
})
dialog.rejected.connect(function() {
close()
})
dialog.open()
}
onClosed: destroy()
}
}

function createRequest(lightning_only, reuse_address) {
var qamt = Config.unitsToSats(_request_amount)
Daemon.currentWallet.createRequest(qamt, _request_description, _request_expiry, lightning_only, reuse_address)
Expand Down
4 changes: 2 additions & 2 deletions electrum/gui/qml/components/main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -389,8 +389,8 @@ ApplicationWindow
property alias scanDialog: _scanDialog
Component {
id: _scanDialog
ScanDialog {
onClosed: destroy()
QRScanner {
//onClosed: destroy()
}
}

Expand Down
Loading