diff --git a/webappify/__init__.py b/webappify/__init__.py index 13564d8..073d754 100644 --- a/webappify/__init__.py +++ b/webappify/__init__.py @@ -55,7 +55,8 @@ class WebWindow(QtWidgets.QWidget): """ A window with a single web view and nothing else """ - def __init__(self, app, title, url, icon, can_minimize_to_tray=False, canMinimizeToTray=False): + def __init__(self, app: 'WebApp', title: str, url: str, icon: str, can_minimize_to_tray: bool = False, + allow_notifications: bool = False): """ Create the window """ @@ -63,7 +64,7 @@ class WebWindow(QtWidgets.QWidget): self._has_shown_warning = False self.app = app self.icon = QtGui.QIcon(icon) - self.can_minimize_to_tray = can_minimize_to_tray or canMinimizeToTray + self.can_minimize_to_tray = can_minimize_to_tray or allow_notifications self.setWindowTitle(title) self.setWindowIcon(self.icon) self.setContentsMargins(0, 0, 0, 0) @@ -71,12 +72,27 @@ class WebWindow(QtWidgets.QWidget): self.layout.setContentsMargins(0, 0, 0, 0) self.webview = QtWebEngineWidgets.QWebEngineView(self) self.webview.setPage(WebPage(self.webview)) + if allow_notifications: + self.webview.page().featurePermissionRequested.connect(self._handle_notifications_requested) + self.webview.page().profile().setNotificationPresenter(self._present_notification) for setting in SETTINGS: self.webview.settings().setAttribute(setting, True) self.webview.setUrl(QtCore.QUrl(url)) self.layout.addWidget(self.webview) self.webview.titleChanged.connect(self.on_title_changed) + def _handle_notifications_requested(self, origin: QtCore.QUrl, feature: QtWebEngineCore.QWebEnginePage.Feature): + """Handle when notifications are requested and implicitly allow them""" + if feature != QtWebEngineCore.QWebEnginePage.Feature.Notifications: + return + self.webview.page().setFeaturePermission( + origin, feature, QtWebEngineCore.QWebEnginePage.PermissionPolicy.PermissionGrantedByUser + ) + + def _present_notification(self, notification: QtWebEngineCore.QWebEngineNotification): + """Show a notification from the browser""" + self.tray_icon.showMessage(notification.title(), notification.message()) + def _show_warning(self): """ Show a balloon message to inform the user that the app is minimized @@ -84,7 +100,7 @@ class WebWindow(QtWidgets.QWidget): if not self._has_shown_warning: self.tray_icon.showMessage(self.windowTitle(), 'This program will continue running in the system tray. ' 'To close the program, choose Quit in the context menu of the system ' - 'tray icon.', QtWidgets.QSystemTrayIcon.Information, 5000) + 'tray icon.') self._has_shown_warning = True def _update_tray_menu(self): @@ -144,7 +160,7 @@ class WebWindow(QtWidgets.QWidget): self.tray_icon.activated.connect(self.on_tray_icon_activated) self.tray_icon.show() - def closeEvent(self, event): + def closeEvent(self, event: QtCore.QEvent): """ Override the close event to minimize to the tray """ @@ -162,21 +178,21 @@ class WebWindow(QtWidgets.QWidget): # Update the menu to match self._update_tray_menu() - def showEvent(self, event): + def showEvent(self, event: QtCore.QEvent): """ Override the show event to catch max/min/etc events and update the tray icon menu accordingly """ super(WebWindow, self).showEvent(event) self._update_tray_menu() - def hideEvent(self, event): + def hideEvent(self, event: QtCore.QEvent): """ Override the hide event to catch max/min/etc events and update the tray icon menu accordingly """ super(WebWindow, self).hideEvent(event) self._update_tray_menu() - def changeEvent(self, event): + def changeEvent(self, event: QtCore.QEvent): """ Catch the minimize event and close the form """ @@ -185,7 +201,7 @@ class WebWindow(QtWidgets.QWidget): self.close() super(WebWindow, self).changeEvent(event) - def on_title_changed(self, title): + def on_title_changed(self, title: str): """ React to title changes """ @@ -194,11 +210,11 @@ class WebWindow(QtWidgets.QWidget): if self.can_minimize_to_tray: self.tray_icon.setToolTip(title) - def on_tray_icon_activated(self, reason): + def on_tray_icon_activated(self, reason: QtWidgets.QSystemTrayIcon.ActivationReason): """ React to the tray icon being activated """ - if reason == QtWidgets.QSystemTrayIcon.Trigger: + if reason == QtWidgets.QSystemTrayIcon.ActivationReason.Trigger: if self.isVisible(): self.close() else: @@ -209,7 +225,8 @@ class WebApp(QtWidgets.QApplication): """ A generic application to open a web page in a desktop app """ - def __init__(self, title, url, icon, can_minimize_to_tray=False): + def __init__(self, title: str, url: str, icon: str, can_minimize_to_tray: bool = False, + allow_notifications: bool = False): """ Create an application which loads a URL into a window """ @@ -219,7 +236,9 @@ class WebApp(QtWidgets.QApplication): self.title = title self.url = url self.icon = icon - self.can_minimize_to_tray = QtWidgets.QSystemTrayIcon.isSystemTrayAvailable() and can_minimize_to_tray + self.can_minimize_to_tray = QtWidgets.QSystemTrayIcon.isSystemTrayAvailable() and \ + (can_minimize_to_tray or allow_notifications) + self.allow_notifications = allow_notifications if self.can_minimize_to_tray: self.setQuitOnLastWindowClosed(False) self.setWindowIcon(QtGui.QIcon(self.icon)) @@ -230,7 +249,8 @@ class WebApp(QtWidgets.QApplication): """ Set up the window and the tray icon, and run the app """ - self.window = WebWindow(self, self.title, self.url, self.icon, self.can_minimize_to_tray) + self.window = WebWindow(self, self.title, self.url, self.icon, self.can_minimize_to_tray, + self.allow_notifications) if self.can_minimize_to_tray: self.window.setup_tray_icon() self.window.showMaximized()