refactor: use config.json with MVC architecture
This commit is contained in:
+25
-27
@@ -4,9 +4,9 @@ SeniorNet Kiosk — PyQt5 single-row floating toolbar over Google Chrome.
|
||||
Navigation: ◀ ▶ ⌂ icon buttons + ☰ hamburger menu for bookmarks.
|
||||
Chrome is controlled via Chrome DevTools Protocol (CDP) over WebSocket.
|
||||
"""
|
||||
import sys, json, os, subprocess, time, threading, urllib.request
|
||||
from PyQt5.QtCore import Qt, QTimer, QPoint, QRect
|
||||
from PyQt5.QtGui import QFont, QColor, QPalette
|
||||
import sys, json, os, subprocess, time, threading, urllib.request, websocket, pathlib, shutil, sqlite3
|
||||
from PyQt5.QtCore import Qt, QTimer, QPoint, QRect, QEvent
|
||||
from PyQt5.QtGui import QFont, QColor, QPalette, QCursor
|
||||
from PyQt5.QtWidgets import (
|
||||
QApplication, QWidget, QHBoxLayout, QVBoxLayout,
|
||||
QPushButton, QLabel, QScrollArea, QDialog, QLineEdit,
|
||||
@@ -25,12 +25,18 @@ SCREEN_H = 1080 # overwritten at runtime
|
||||
|
||||
# ── Colour palette ────────────────────────────────────────────────
|
||||
TOOLBAR_COLOR = "#1a3a5c"
|
||||
BTN_COLOR = "#2e6da4"; BTN_HOVER = "#3a87cc"
|
||||
GOLD = "#e8a020"; GOLD_HOVER = "#f0b030"
|
||||
GREEN = "#2e7d32"; GREEN_HOVER = "#388e3c"
|
||||
RED = "#c62828"; RED_HOVER = "#d32f2f"
|
||||
AMBER = "#7a5a10"; AMBER_HOVER = "#9a7a20"
|
||||
PURPLE = "#5a5a8a"; PURPLE_HOVER = "#7a7aaa"
|
||||
BTN_COLOR = "#2e6da4"
|
||||
BTN_HOVER = "#3a87cc"
|
||||
GOLD = "#e8a020"
|
||||
GOLD_HOVER = "#f0b030"
|
||||
GREEN = "#2e7d32"
|
||||
GREEN_HOVER = "#388e3c"
|
||||
RED = "#c62828"
|
||||
RED_HOVER = "#d32f2f"
|
||||
AMBER = "#7a5a10"
|
||||
AMBER_HOVER = "#9a7a20"
|
||||
PURPLE = "#5a5a8a"
|
||||
PURPLE_HOVER = "#7a7aaa"
|
||||
FONT_SIZE = 18
|
||||
|
||||
MENU_STYLE = """
|
||||
@@ -74,8 +80,10 @@ def mk_icon_btn(icon, color, hover, size=58, fs=26):
|
||||
|
||||
def load_bm():
|
||||
try:
|
||||
with open(BOOKMARKS_FILE) as f: return json.load(f)
|
||||
except: return []
|
||||
with open(BOOKMARKS_FILE) as f:
|
||||
return json.load(f)
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
return []
|
||||
|
||||
def save_bm(data):
|
||||
with open(BOOKMARKS_FILE, "w") as f: json.dump(data, f, indent=2)
|
||||
@@ -113,7 +121,6 @@ class CDP:
|
||||
def _send(self, method, params=None):
|
||||
if not self.ready:
|
||||
return
|
||||
import websocket
|
||||
with self._lock:
|
||||
try:
|
||||
ws = websocket.create_connection(self._ws_url(), timeout=3)
|
||||
@@ -132,7 +139,6 @@ class CDP:
|
||||
"""Move and resize the Chrome window via CDP Browser.setWindowBounds."""
|
||||
if not self.ready:
|
||||
return
|
||||
import websocket
|
||||
with self._lock:
|
||||
try:
|
||||
ws = websocket.create_connection(self._ws_url(), timeout=3)
|
||||
@@ -554,7 +560,6 @@ class BookmarkPanel(QWidget):
|
||||
self._dismiss_timer.stop()
|
||||
|
||||
def _cursor_outside_panel(self):
|
||||
from PyQt5.QtGui import QCursor
|
||||
pos = QCursor.pos()
|
||||
if self.frameGeometry().contains(pos):
|
||||
return False
|
||||
@@ -581,7 +586,6 @@ class BookmarkPanel(QWidget):
|
||||
self.hide()
|
||||
|
||||
def eventFilter(self, obj, event):
|
||||
from PyQt5.QtCore import QEvent
|
||||
if event.type() == QEvent.MouseButtonPress and self.isVisible():
|
||||
if not self.frameGeometry().contains(event.globalPos()):
|
||||
self.hide()
|
||||
@@ -638,7 +642,6 @@ class KioskOverlay(QWidget):
|
||||
|
||||
def changeEvent(self, event):
|
||||
"""Un-minimise the toolbar the instant it gets iconified."""
|
||||
from PyQt5.QtCore import QEvent
|
||||
if event.type() == QEvent.WindowStateChange:
|
||||
if self.windowState() & Qt.WindowMinimized:
|
||||
QTimer.singleShot(50, self._self_restore)
|
||||
@@ -727,7 +730,6 @@ class KioskOverlay(QWidget):
|
||||
e.accept()
|
||||
|
||||
def eventFilter(self, obj, event):
|
||||
from PyQt5.QtCore import QEvent
|
||||
if event.type() == QEvent.KeyPress:
|
||||
key = event.key()
|
||||
mods = event.modifiers()
|
||||
@@ -745,13 +747,14 @@ class KioskOverlay(QWidget):
|
||||
|
||||
# ── Chrome launcher ───────────────────────────────────────────────
|
||||
def launch_chrome():
|
||||
import pathlib, json as _json, shutil
|
||||
profile_dir = pathlib.Path("/home/jgitta/chromium-kiosk")
|
||||
profile_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for name in ("SingletonLock", "SingletonSocket", "SingletonCookie"):
|
||||
try: (profile_dir / name).unlink()
|
||||
except FileNotFoundError: pass
|
||||
try:
|
||||
(profile_dir / name).unlink()
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
for rel in ("GraphiteDawnCache", "GrShaderCache", "ShaderCache",
|
||||
"OptGuideOnDeviceClassifierModel", "OptGuideOnDeviceModel",
|
||||
@@ -765,21 +768,16 @@ def launch_chrome():
|
||||
ls_path = profile_dir / "Local State"
|
||||
if ls_path.exists():
|
||||
try:
|
||||
d = _json.loads(ls_path.read_text())
|
||||
d = json.loads(ls_path.read_text())
|
||||
d.setdefault("profile", {})["exit_type"] = "Normal"
|
||||
d["hardware_acceleration_mode_previous"] = False
|
||||
ls_path.write_text(_json.dumps(d))
|
||||
ls_path.write_text(json.dumps(d))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Clear the stale Roundcube session cookie so the autologin plugin always
|
||||
# fires cleanly. Without this, Chrome sends the old cookie after a reboot,
|
||||
# the PHP session in MariaDB has expired, and Roundcube shows
|
||||
# "session is invalid or expired" instead of auto-logging in.
|
||||
cookies_db = profile_dir / "Default" / "Cookies"
|
||||
if cookies_db.exists():
|
||||
try:
|
||||
import sqlite3
|
||||
conn = sqlite3.connect(str(cookies_db))
|
||||
conn.execute(
|
||||
"DELETE FROM cookies WHERE host_key LIKE '%mail.jgitta.com%'")
|
||||
|
||||
Reference in New Issue
Block a user