Merge pull request #9955 from SomberNight/202506_qt_mac_camera_permission
qt gui: qrreader: macos: add runtime requesting of camera permission
This commit is contained in:
@@ -97,7 +97,7 @@ from .update_checker import UpdateCheck, UpdateCheckThread
|
|||||||
from .channels_list import ChannelsList
|
from .channels_list import ChannelsList
|
||||||
from .confirm_tx_dialog import ConfirmTxDialog
|
from .confirm_tx_dialog import ConfirmTxDialog
|
||||||
from .rbf_dialog import BumpFeeDialog, DSCancelDialog
|
from .rbf_dialog import BumpFeeDialog, DSCancelDialog
|
||||||
from .qrreader import scan_qrcode
|
from .qrreader import scan_qrcode_from_camera
|
||||||
from .swap_dialog import SwapDialog, InvalidSwapParameters
|
from .swap_dialog import SwapDialog, InvalidSwapParameters
|
||||||
from .balance_dialog import (BalanceToolButton, COLOR_FROZEN, COLOR_UNMATURED, COLOR_UNCONFIRMED, COLOR_CONFIRMED,
|
from .balance_dialog import (BalanceToolButton, COLOR_FROZEN, COLOR_UNMATURED, COLOR_UNCONFIRMED, COLOR_CONFIRMED,
|
||||||
COLOR_LIGHTNING, COLOR_FROZEN_LIGHTNING)
|
COLOR_LIGHTNING, COLOR_FROZEN_LIGHTNING)
|
||||||
@@ -2322,7 +2322,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
|||||||
return
|
return
|
||||||
self.show_transaction(tx)
|
self.show_transaction(tx)
|
||||||
|
|
||||||
scan_qrcode(parent=self.top_level_window(), config=self.config, callback=cb)
|
scan_qrcode_from_camera(parent=self.top_level_window(), config=self.config, callback=cb)
|
||||||
|
|
||||||
def read_tx_from_file(self) -> Optional[Transaction]:
|
def read_tx_from_file(self) -> Optional[Transaction]:
|
||||||
fileName = getOpenFileName(
|
fileName = getOpenFileName(
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ from typing import Callable, Optional, TYPE_CHECKING, Mapping, Sequence
|
|||||||
|
|
||||||
from PyQt6.QtWidgets import QMessageBox, QWidget
|
from PyQt6.QtWidgets import QMessageBox, QWidget
|
||||||
from PyQt6.QtGui import QImage, QPainter, QColor
|
from PyQt6.QtGui import QImage, QPainter, QColor
|
||||||
from PyQt6.QtCore import QRect
|
from PyQt6.QtCore import QRect, QCoreApplication
|
||||||
|
from PyQt6 import QtCore
|
||||||
|
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.util import UserFacingException
|
from electrum.util import UserFacingException
|
||||||
@@ -43,18 +44,24 @@ if TYPE_CHECKING:
|
|||||||
_logger = get_logger(__name__)
|
_logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def scan_qrcode(
|
def scan_qrcode_from_camera(
|
||||||
*,
|
*,
|
||||||
parent: Optional[QWidget],
|
parent: Optional[QWidget],
|
||||||
config: 'SimpleConfig',
|
config: 'SimpleConfig',
|
||||||
callback: Callable[[bool, str, Optional[str]], None],
|
callback: Callable[[bool, str, Optional[str]], None],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Scans QR code using camera."""
|
"""Scans QR code using camera. It handles requesting camera access permission from the OS if needed."""
|
||||||
assert parent is None or isinstance(parent, QWidget), f"parent should be a QWidget, not {parent!r}"
|
assert parent is None or isinstance(parent, QWidget), f"parent should be a QWidget, not {parent!r}"
|
||||||
if sys.platform == 'darwin' or sys.platform in ('windows', 'win32'):
|
def do_scan():
|
||||||
_scan_qrcode_using_qtmultimedia(parent=parent, config=config, callback=callback)
|
_scan_qrcode_from_camera(parent=parent, config=config, callback=callback)
|
||||||
else: # desktop Linux and similar
|
|
||||||
_scan_qrcode_using_zbar(parent=parent, config=config, callback=callback)
|
if _has_camera_permission():
|
||||||
|
do_scan()
|
||||||
|
else:
|
||||||
|
# Request permission now. This is only a thing on macOS atm.
|
||||||
|
# Note: this assumes we are running on the main thread. Permissions can only be requested from the main thread.
|
||||||
|
app = QCoreApplication.instance()
|
||||||
|
app.requestPermission(QtCore.QCameraPermission(), lambda _x: do_scan())
|
||||||
|
|
||||||
|
|
||||||
def scan_qr_from_image(image: QImage) -> Sequence[QrCodeResult]:
|
def scan_qr_from_image(image: QImage) -> Sequence[QrCodeResult]:
|
||||||
@@ -181,3 +188,29 @@ def _scan_qrcode_using_qtmultimedia(
|
|||||||
_qr_dialog = None
|
_qr_dialog = None
|
||||||
callback(False, repr(e), None)
|
callback(False, repr(e), None)
|
||||||
|
|
||||||
|
|
||||||
|
def _scan_qrcode_from_camera(
|
||||||
|
*,
|
||||||
|
parent: Optional[QWidget],
|
||||||
|
config: 'SimpleConfig',
|
||||||
|
callback: Callable[[bool, str, Optional[str]], None],
|
||||||
|
) -> None:
|
||||||
|
"""Scans QR code using camera."""
|
||||||
|
assert parent is None or isinstance(parent, QWidget), f"parent should be a QWidget, not {parent!r}"
|
||||||
|
if not _has_camera_permission():
|
||||||
|
callback(False, _("Missing camera permission."), None)
|
||||||
|
return
|
||||||
|
if sys.platform == 'darwin' or sys.platform in ('windows', 'win32'):
|
||||||
|
_scan_qrcode_using_qtmultimedia(parent=parent, config=config, callback=callback)
|
||||||
|
else: # desktop Linux and similar
|
||||||
|
_scan_qrcode_using_zbar(parent=parent, config=config, callback=callback)
|
||||||
|
|
||||||
|
|
||||||
|
def _has_camera_permission() -> bool:
|
||||||
|
if not hasattr(QtCore, "QCameraPermission"): # requires Qt 6.5+
|
||||||
|
_logger.info(f"QtCore does not support QCameraPermission. This requires Qt 6.5+")
|
||||||
|
return True # hope for the best
|
||||||
|
app = QCoreApplication.instance()
|
||||||
|
permission_status = app.checkPermission(QtCore.QCameraPermission())
|
||||||
|
return permission_status == QtCore.Qt.PermissionStatus.Granted
|
||||||
|
|
||||||
|
|||||||
@@ -792,10 +792,10 @@ class GenericInputHandler:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
show_error(_('Invalid payment identifier in QR') + ':\n' + repr(e))
|
show_error(_('Invalid payment identifier in QR') + ':\n' + repr(e))
|
||||||
|
|
||||||
from .qrreader import scan_qrcode
|
from .qrreader import scan_qrcode_from_camera
|
||||||
if parent is None:
|
if parent is None:
|
||||||
parent = self if isinstance(self, QWidget) else None
|
parent = self if isinstance(self, QWidget) else None
|
||||||
scan_qrcode(parent=parent, config=config, callback=cb)
|
scan_qrcode_from_camera(parent=parent, config=config, callback=cb)
|
||||||
|
|
||||||
def input_qr_from_screenshot(
|
def input_qr_from_screenshot(
|
||||||
self,
|
self,
|
||||||
|
|||||||
Reference in New Issue
Block a user