refactor: extract PrivacyController from main_window.py
Move _toggle_privacy and its lazy state (_privacy_on, _privacy_overlay, _popout_was_visible) into gui/privacy.py. Rewire menu action, popout signal, resizeEvent, and keyPressEvent to use the controller. No behavior change. main_window.py: 3111 -> 3068 lines.
This commit is contained in:
parent
321ba8edfa
commit
cb2445a90a
@ -59,6 +59,7 @@ from .log_handler import LogHandler
|
||||
from .async_signals import AsyncSignals
|
||||
from .info_panel import InfoPanel
|
||||
from .window_state import WindowStateController
|
||||
from .privacy import PrivacyController
|
||||
|
||||
log = logging.getLogger("booru")
|
||||
|
||||
@ -130,6 +131,7 @@ class BooruApp(QMainWindow):
|
||||
# (and from the splitter timer's flush on close). Uses the same
|
||||
# 300ms debounce pattern as the splitter saver.
|
||||
self._window_state = WindowStateController(self)
|
||||
self._privacy = PrivacyController(self)
|
||||
self._main_window_save_timer = QTimer(self)
|
||||
self._main_window_save_timer.setSingleShot(True)
|
||||
self._main_window_save_timer.setInterval(300)
|
||||
@ -556,7 +558,7 @@ class BooruApp(QMainWindow):
|
||||
|
||||
privacy_action = QAction("&Privacy Screen", self)
|
||||
privacy_action.setShortcut(QKeySequence("Ctrl+P"))
|
||||
privacy_action.triggered.connect(self._toggle_privacy)
|
||||
privacy_action.triggered.connect(self._privacy.toggle)
|
||||
view_menu.addAction(privacy_action)
|
||||
|
||||
def _load_sites(self) -> None:
|
||||
@ -2053,7 +2055,7 @@ class BooruApp(QMainWindow):
|
||||
self._fullscreen_window.open_in_default.connect(self._open_preview_in_default)
|
||||
self._fullscreen_window.open_in_browser.connect(self._open_preview_in_browser)
|
||||
self._fullscreen_window.closed.connect(self._on_fullscreen_closed)
|
||||
self._fullscreen_window.privacy_requested.connect(self._toggle_privacy)
|
||||
self._fullscreen_window.privacy_requested.connect(self._privacy.toggle)
|
||||
# Set post tags for BL Tag menu
|
||||
post = self._preview._current_post
|
||||
if post:
|
||||
@ -2847,54 +2849,9 @@ class BooruApp(QMainWindow):
|
||||
else:
|
||||
self.showFullScreen()
|
||||
|
||||
# -- Privacy screen --
|
||||
|
||||
def _toggle_privacy(self) -> None:
|
||||
if not hasattr(self, '_privacy_on'):
|
||||
self._privacy_on = False
|
||||
self._privacy_overlay = QWidget(self)
|
||||
self._privacy_overlay.setStyleSheet("background: black;")
|
||||
self._privacy_overlay.hide()
|
||||
# Tracks whether the popout was visible at privacy-on time
|
||||
# so privacy-off only restores it if it was actually up
|
||||
# before. Without the gate, privacy-off would re-show a
|
||||
# popout that the user closed before triggering privacy.
|
||||
self._popout_was_visible = False
|
||||
|
||||
self._privacy_on = not self._privacy_on
|
||||
if self._privacy_on:
|
||||
self._privacy_overlay.setGeometry(self.rect())
|
||||
self._privacy_overlay.raise_()
|
||||
self._privacy_overlay.show()
|
||||
self.setWindowTitle("booru-viewer")
|
||||
# Pause preview video
|
||||
if self._preview._stack.currentIndex() == 1:
|
||||
self._preview._video_player.pause()
|
||||
# Delegate popout hide-and-pause to FullscreenPreview so it
|
||||
# can capture its own geometry for restore.
|
||||
self._popout_was_visible = bool(
|
||||
self._fullscreen_window and self._fullscreen_window.isVisible()
|
||||
)
|
||||
if self._popout_was_visible:
|
||||
self._fullscreen_window.privacy_hide()
|
||||
else:
|
||||
self._privacy_overlay.hide()
|
||||
# Resume embedded preview video — unconditional resume, the
|
||||
# common case (privacy hides → user comes back → video should
|
||||
# be playing again) wins over the manually-paused edge case.
|
||||
if self._preview._stack.currentIndex() == 1:
|
||||
self._preview._video_player.resume()
|
||||
# Restore the popout via its own privacy_show method, which
|
||||
# also re-dispatches the captured geometry to Hyprland (Qt
|
||||
# show() alone doesn't preserve position on Wayland) and
|
||||
# resumes its video.
|
||||
if self._popout_was_visible and self._fullscreen_window:
|
||||
self._fullscreen_window.privacy_show()
|
||||
|
||||
def resizeEvent(self, event) -> None:
|
||||
super().resizeEvent(event)
|
||||
if hasattr(self, '_privacy_overlay') and self._privacy_on:
|
||||
self._privacy_overlay.setGeometry(self.rect())
|
||||
self._privacy.resize_overlay()
|
||||
# Capture window state proactively so the saved value is always
|
||||
# fresh — closeEvent's hyprctl query can fail if the compositor has
|
||||
# already started unmapping. Debounced via the 300ms timer.
|
||||
@ -2915,10 +2872,10 @@ class BooruApp(QMainWindow):
|
||||
key = event.key()
|
||||
# Privacy screen always works
|
||||
if key == Qt.Key.Key_P and event.modifiers() == Qt.KeyboardModifier.ControlModifier:
|
||||
self._toggle_privacy()
|
||||
self._privacy.toggle()
|
||||
return
|
||||
# If privacy is on, only allow toggling it off
|
||||
if hasattr(self, '_privacy_on') and self._privacy_on:
|
||||
if self._privacy.is_active:
|
||||
return
|
||||
if key == Qt.Key.Key_F and self._posts:
|
||||
idx = self._grid.selected_index
|
||||
|
||||
66
booru_viewer/gui/privacy.py
Normal file
66
booru_viewer/gui/privacy.py
Normal file
@ -0,0 +1,66 @@
|
||||
"""Privacy-screen overlay for the main window."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PySide6.QtWidgets import QWidget
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .main_window import BooruApp
|
||||
|
||||
|
||||
class PrivacyController:
|
||||
"""Owns the privacy overlay toggle and popout coordination."""
|
||||
|
||||
def __init__(self, app: BooruApp) -> None:
|
||||
self._app = app
|
||||
self._on = False
|
||||
self._overlay: QWidget | None = None
|
||||
self._popout_was_visible = False
|
||||
|
||||
@property
|
||||
def is_active(self) -> bool:
|
||||
return self._on
|
||||
|
||||
def resize_overlay(self) -> None:
|
||||
"""Re-fit the overlay to the main window's current rect."""
|
||||
if self._overlay is not None and self._on:
|
||||
self._overlay.setGeometry(self._app.rect())
|
||||
|
||||
def toggle(self) -> None:
|
||||
if self._overlay is None:
|
||||
self._overlay = QWidget(self._app)
|
||||
self._overlay.setStyleSheet("background: black;")
|
||||
self._overlay.hide()
|
||||
|
||||
self._on = not self._on
|
||||
if self._on:
|
||||
self._overlay.setGeometry(self._app.rect())
|
||||
self._overlay.raise_()
|
||||
self._overlay.show()
|
||||
self._app.setWindowTitle("booru-viewer")
|
||||
# Pause preview video
|
||||
if self._app._preview._stack.currentIndex() == 1:
|
||||
self._app._preview._video_player.pause()
|
||||
# Delegate popout hide-and-pause to FullscreenPreview so it
|
||||
# can capture its own geometry for restore.
|
||||
self._popout_was_visible = bool(
|
||||
self._app._fullscreen_window
|
||||
and self._app._fullscreen_window.isVisible()
|
||||
)
|
||||
if self._popout_was_visible:
|
||||
self._app._fullscreen_window.privacy_hide()
|
||||
else:
|
||||
self._overlay.hide()
|
||||
# Resume embedded preview video — unconditional resume, the
|
||||
# common case (privacy hides -> user comes back -> video should
|
||||
# be playing again) wins over the manually-paused edge case.
|
||||
if self._app._preview._stack.currentIndex() == 1:
|
||||
self._app._preview._video_player.resume()
|
||||
# Restore the popout via its own privacy_show method, which
|
||||
# also re-dispatches the captured geometry to Hyprland (Qt
|
||||
# show() alone doesn't preserve position on Wayland) and
|
||||
# resumes its video.
|
||||
if self._popout_was_visible and self._app._fullscreen_window:
|
||||
self._app._fullscreen_window.privacy_show()
|
||||
Loading…
x
Reference in New Issue
Block a user