Add ability to popout chat into seperate window
This commit is contained in:
@@ -4,15 +4,28 @@ import html
|
||||
import re
|
||||
from PyQt6.QtWidgets import (
|
||||
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit,
|
||||
QPushButton, QFrame, QSlider, QTextEdit, QTextBrowser, QApplication, QToolTip, QSplitter
|
||||
QPushButton, QFrame, QSlider, QTextEdit, QTextBrowser, QApplication, QToolTip, QSplitter,
|
||||
QMainWindow
|
||||
)
|
||||
from PyQt6.QtCore import Qt, pyqtSignal, QTimer
|
||||
from PyQt6.QtCore import Qt, pyqtSignal, QTimer, QEvent
|
||||
from PyQt6.QtGui import QIcon, QCursor
|
||||
|
||||
import uuid
|
||||
|
||||
from vlc_player import VLCSyncPlayer
|
||||
|
||||
class ChatPopoutWindow(QMainWindow):
|
||||
closed = pyqtSignal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("Live Chat")
|
||||
self.resize(350, 600)
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.closed.emit()
|
||||
super().closeEvent(event)
|
||||
|
||||
class ClickableSlider(QSlider):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -80,6 +93,8 @@ class RoomWidget(QWidget):
|
||||
self.current_users = []
|
||||
self._is_first_user_update = True
|
||||
|
||||
self.popout_window = None
|
||||
|
||||
self._setup_ui()
|
||||
|
||||
def _setup_ui(self):
|
||||
@@ -213,6 +228,17 @@ class RoomWidget(QWidget):
|
||||
chat_header = QLabel("Live Chat")
|
||||
chat_header.setObjectName("chatHeader")
|
||||
|
||||
self.popout_btn = QPushButton("↗")
|
||||
self.popout_btn.setObjectName("iconBtn")
|
||||
self.popout_btn.setFixedSize(24, 24)
|
||||
self.popout_btn.setToolTip("Pop out chat")
|
||||
self.popout_btn.clicked.connect(self.popout_chat)
|
||||
|
||||
header_layout = QHBoxLayout()
|
||||
header_layout.addWidget(chat_header)
|
||||
header_layout.addStretch()
|
||||
header_layout.addWidget(self.popout_btn)
|
||||
|
||||
self.users_lbl = QLabel("0 watching")
|
||||
self.users_lbl.setObjectName("usersLbl")
|
||||
|
||||
@@ -280,7 +306,7 @@ class RoomWidget(QWidget):
|
||||
self.chat_send_btn.clicked.connect(self.send_chat)
|
||||
self.chat_input.returnPressed.connect(self.send_chat)
|
||||
|
||||
chat_layout.addWidget(chat_header)
|
||||
chat_layout.addLayout(header_layout)
|
||||
chat_layout.addWidget(self.users_lbl)
|
||||
chat_layout.addWidget(self.tags_container)
|
||||
chat_layout.addWidget(self.chat_messages, 1)
|
||||
@@ -296,7 +322,8 @@ class RoomWidget(QWidget):
|
||||
|
||||
# Prevent UI components from stealing focus (which breaks spacebar shortcuts)
|
||||
for w in [self.copy_code_btn, self.leave_btn, self.play_btn, self.fullscreen_btn,
|
||||
self.chat_send_btn, self.seekbar, self.volume_slider, self.tags_header_btn, self.chat_toggle_btn]:
|
||||
self.chat_send_btn, self.seekbar, self.volume_slider, self.tags_header_btn,
|
||||
self.chat_toggle_btn, self.popout_btn]:
|
||||
w.setFocusPolicy(Qt.FocusPolicy.NoFocus)
|
||||
|
||||
# specifically for chat_messages, we allow clicking links, but avoid focus stealing
|
||||
@@ -381,6 +408,11 @@ class RoomWidget(QWidget):
|
||||
self.tags_header_btn.setText("▶ Highlights")
|
||||
|
||||
def toggle_chat(self):
|
||||
if self.popout_window:
|
||||
self.popout_window.activateWindow()
|
||||
self.popout_window.raise_()
|
||||
return
|
||||
|
||||
if self.chat_container.isVisible():
|
||||
self._saved_chat_width = self.chat_container.width()
|
||||
self.chat_container.hide()
|
||||
@@ -390,6 +422,45 @@ class RoomWidget(QWidget):
|
||||
sizes = self.splitter.sizes()
|
||||
self.splitter.setSizes([sizes[0] - w, w])
|
||||
|
||||
def popout_chat(self):
|
||||
if self.popout_window:
|
||||
return
|
||||
|
||||
self.popout_window = ChatPopoutWindow(self.window())
|
||||
self.popout_window.setWindowTitle(f"Chat - {self.room_code}")
|
||||
|
||||
# Detach from layout
|
||||
self.chat_container.setParent(None)
|
||||
|
||||
# Set central widget
|
||||
central = QWidget()
|
||||
l = QVBoxLayout(central)
|
||||
l.setContentsMargins(0, 0, 0, 0)
|
||||
l.addWidget(self.chat_container)
|
||||
self.popout_window.setCentralWidget(central)
|
||||
|
||||
self.popout_window.closed.connect(self.on_popout_closed)
|
||||
self.popout_window.show()
|
||||
|
||||
self.popout_btn.hide()
|
||||
|
||||
# Collapse the space in splitter
|
||||
self.splitter.setSizes([self.width(), 0])
|
||||
|
||||
def on_popout_closed(self):
|
||||
self.popout_window = None
|
||||
|
||||
# Re-attach to layout
|
||||
self.chat_container.setParent(self)
|
||||
self.splitter.insertWidget(1, self.chat_container)
|
||||
|
||||
self.popout_btn.show()
|
||||
|
||||
# Restore splitter sizes
|
||||
w = getattr(self, '_saved_chat_width', 320)
|
||||
self.splitter.setSizes([self.width() - w, w])
|
||||
self.chat_container.show()
|
||||
|
||||
def toggle_fullscreen(self):
|
||||
top_window = self.window()
|
||||
if top_window.isFullScreen():
|
||||
@@ -780,7 +851,7 @@ class RoomWidget(QWidget):
|
||||
self.chat_message_ready.emit(text)
|
||||
self.chat_input.setText("")
|
||||
|
||||
def _parse_time_arg(self, arg: str) -> float | None:
|
||||
def _parse_time_arg(self, arg: str):
|
||||
"""Parses a time string (absolute time, offset like +30s, or 'now') and returns the target time in MS. Returns None on error."""
|
||||
current_ms = self.vlc_player.current_time_ms
|
||||
length_ms = self.vlc_player.get_length()
|
||||
|
||||
Reference in New Issue
Block a user