Skip to content

Commit

Permalink
Prevent using popups
Browse files Browse the repository at this point in the history
Using popups, it was hard to test the kiosk without setting up PlayOS VM.

Aditionally:

- use only one webview,
- decorate as dialog when necessary,
  • Loading branch information
guyonvarch committed Dec 7, 2023
1 parent 01608ad commit b59200e
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 106 deletions.
30 changes: 12 additions & 18 deletions kiosk/kiosk_browser/browser_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
Webview loading status
"""
class Status(Enum):
INITIAL_LOADING = auto()
LOADING = auto()
NETWORK_ERROR = auto()
LOADED = auto()

class BrowserWidget(QtWidgets.QWidget):

def __init__(self, url, get_current_proxy, parent):
QtWidgets.QWidget.__init__(self, parent)
self.setStyleSheet(f"background-color: white;")

self._url = url

Expand Down Expand Up @@ -54,17 +55,9 @@ def __init__(self, url, get_current_proxy, parent):

# Load url
self._webview.setUrl(url)
self._view(Status.INITIAL_LOADING)
self._view(Status.LOADING)
self._webview.loadFinished.connect(self._load_finished)

# Stretch the view
policy = QtWidgets.QSizePolicy()
policy.setVerticalStretch(1)
policy.setHorizontalStretch(1)
policy.setVerticalPolicy(QtWidgets.QSizePolicy.Preferred)
policy.setHorizontalPolicy(QtWidgets.QSizePolicy.Preferred)
self.setSizePolicy(policy)

# Shortcut to manually reload
self.reload_shortcut = QtWidgets.QShortcut('CTRL+R', self)
self.reload_shortcut.activated.connect(self.reload)
Expand All @@ -74,22 +67,23 @@ def __init__(self, url, get_current_proxy, parent):
self._reload_timer.setSingleShot(True)
self._reload_timer.timeout.connect(self._webview.reload)

def show_overlay(self):
""" Hide browser widget by showing an overlay instead.
"""
self._webview.setHtml("<style>html { background-color: rgba(0, 0, 0, 0.4); }</style>")

def reload(self):
""" Show kiosk browser loading URL.
"""

self._webview.setUrl(self._url)
self._view(Status.INITIAL_LOADING)
self._view(Status.LOADING)

# Stop reload timer if it is on going
if self._reload_timer.isActive():
self._reload_timer.stop()

def load(self, url: str):
""" Load specific URL.
"""

self._url = url
self.reload()

# Private

def _load_finished(self, success):
Expand All @@ -109,7 +103,7 @@ def _proxy_auth(self, get_current_proxy, url, auth, proxyHost):
logging.info("Proxy authentication request ignored because credentials are not provided.")

def _view(self, status):
if status == Status.INITIAL_LOADING:
if status == Status.LOADING:
self._loading_page.show()
self._network_error_page.hide()
self._webview.hide()
Expand Down
136 changes: 48 additions & 88 deletions kiosk/kiosk_browser/main_widget.py
Original file line number Diff line number Diff line change
@@ -1,115 +1,75 @@
from PyQt5 import QtWidgets, QtCore
from dataclasses import dataclass

from kiosk_browser import browser_widget, captive_portal
from kiosk_browser import proxy as proxy_module
from kiosk_browser import webview_dialog

@dataclass
class Closed:
pass

@dataclass
class Settings:
dialog: QtWidgets.QDialog

@dataclass
class CaptivePortal:
dialog: QtWidgets.QDialog

Dialog = Closed | Settings | CaptivePortal
from kiosk_browser import browser_widget, captive_portal, dialogable_widget, proxy as proxy_module

class MainWidget(QtWidgets.QWidget):
""" Show website at kiosk_url.
def __init__(self, kiosk_url, settings_url, toggle_settings_key):
super(MainWidget, self).__init__()
- Show settings in dialog using shortcut.
- Show message when captive portal is detected, allowing to show in dialog.
- Use proxy configured in Connman.
"""

# White background color (default is gray)
self.setStyleSheet("background-color: white;")
def __init__(self, kiosk_url: str, settings_url: str, toggle_settings_key: str):
super(MainWidget, self).__init__()

# Proxy
proxy = proxy_module.Proxy()
proxy.start_monitoring_daemon()

self._dialog = Closed()
# Browser widget
self._kiosk_url = kiosk_url
self._settings_url = settings_url
self._toggle_settings_key = toggle_settings_key
self._browser_widget = browser_widget.BrowserWidget(
self._dialogable_browser = dialogable_widget.DialogableWidget(
parent = self,
inner_widget = browser_widget.BrowserWidget(
url = kiosk_url,
get_current_proxy = proxy.get_current,
parent = self)

self._layout = QtWidgets.QBoxLayout(QtWidgets.QBoxLayout.BottomToTop)
self._layout.setContentsMargins(0, 0, 0, 0)
self._layout.setSpacing(0)
self._layout.addWidget(self._browser_widget)
parent = self),
on_close = self._close_dialog)

# Captive portal
self._captive_portal_url = ''
self._captive_portal_message = captive_portal.open_message(self._show_captive_portal)
self._is_captive_portal_open = False
self._captive_portal_message = captive_portal.OpenMessage(self._show_captive_portal, self)
self._captive_portal = captive_portal.CaptivePortal(proxy.get_current, self._show_captive_portal_message)
self._captive_portal.start_monitoring_daemon()

QtWidgets.QShortcut(toggle_settings_key, self).activated.connect(self._toggle_settings)

# Layout
self._layout = QtWidgets.QVBoxLayout()
self._layout.setContentsMargins(0, 0, 0, 0)
self._layout.setSpacing(0)
self._layout.addWidget(self._captive_portal_message)
self._layout.addWidget(self._dialogable_browser)
self.setLayout(self._layout)
self.show()

# Private
# Shortcuts
QtWidgets.QShortcut(toggle_settings_key, self).activated.connect(self._toggle_settings)

def _show_captive_portal_message(self, url):
self._captive_portal_url = QtCore.QUrl(url)
if self._captive_portal_message.parentWidget() == None:
match self._dialog:
case CaptivePortal(_):
pass
case _:
self._layout.addWidget(self._captive_portal_message)
# Private

def _toggle_settings(self):
match self._dialog:
case Closed():
self._show_settings()
case _:
self._close_dialog()
if self._dialogable_browser.is_decorated():
self._close_dialog()
else:
self._dialogable_browser.inner_widget().load(self._settings_url)
self._dialogable_browser.decorate("System Settings")

def _show_settings(self):
self._browser_widget.show_overlay()
dialog = webview_dialog.widget(
parent = self,
title = "System Settings",
url = self._settings_url,
additional_close_keys = [self._toggle_settings_key],
on_close = lambda: self._close_dialog()
)
self._dialog = Settings(dialog)
# Open modeless to allow accessing captive portal message banner
# https://doc.qt.io/qtforpython-5/PySide2/QtWidgets/QDialog.html#modeless-dialogs
# Focus directly to allow tabbing
dialog.show()
dialog.raise_()
dialog.activateWindow()
def _show_captive_portal_message(self, url: str):
self._captive_portal_url = QtCore.QUrl(url)
if not self._captive_portal_message.is_open() and not self._is_captive_portal_open:
self._captive_portal_message.show()

def _show_captive_portal(self):
self._close_dialog(reload_browser_widget = False)
self._browser_widget.show_overlay()
self._captive_portal_message.setParent(None)
dialog = webview_dialog.widget(
parent = self,
title = "Network Login",
url = self._captive_portal_url,
additional_close_keys = [self._toggle_settings_key],
on_close = lambda: self._close_dialog()
)
self._dialog = CaptivePortal(dialog)
dialog.exec_()

def _close_dialog(self, reload_browser_widget = True):
match self._dialog:
case Settings(dialog):
dialog.close()
self._dialog = Closed()
case CaptivePortal(dialog):
dialog.close()
self._dialog = Closed()
if reload_browser_widget:
self._browser_widget.reload()
self._close_dialog()
self._captive_portal_message.hide()
self._dialogable_browser.inner_widget().load(self._captive_portal_url)
self._dialogable_browser.decorate("Network Login")
self._is_captive_portal_open = True

def _close_dialog(self):
if self._dialogable_browser.is_decorated():
self._dialogable_browser.undecorate()
self._dialogable_browser.inner_widget().load(self._kiosk_url)
if self._is_captive_portal_open:
self._is_captive_portal_open = False

0 comments on commit b59200e

Please sign in to comment.