Add ability to popout chat into seperate window
This commit is contained in:
@@ -4,15 +4,28 @@ import html
|
|||||||
import re
|
import re
|
||||||
from PyQt6.QtWidgets import (
|
from PyQt6.QtWidgets import (
|
||||||
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit,
|
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
|
from PyQt6.QtGui import QIcon, QCursor
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from vlc_player import VLCSyncPlayer
|
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):
|
class ClickableSlider(QSlider):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
@@ -80,6 +93,8 @@ class RoomWidget(QWidget):
|
|||||||
self.current_users = []
|
self.current_users = []
|
||||||
self._is_first_user_update = True
|
self._is_first_user_update = True
|
||||||
|
|
||||||
|
self.popout_window = None
|
||||||
|
|
||||||
self._setup_ui()
|
self._setup_ui()
|
||||||
|
|
||||||
def _setup_ui(self):
|
def _setup_ui(self):
|
||||||
@@ -213,6 +228,17 @@ class RoomWidget(QWidget):
|
|||||||
chat_header = QLabel("Live Chat")
|
chat_header = QLabel("Live Chat")
|
||||||
chat_header.setObjectName("chatHeader")
|
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 = QLabel("0 watching")
|
||||||
self.users_lbl.setObjectName("usersLbl")
|
self.users_lbl.setObjectName("usersLbl")
|
||||||
|
|
||||||
@@ -280,7 +306,7 @@ class RoomWidget(QWidget):
|
|||||||
self.chat_send_btn.clicked.connect(self.send_chat)
|
self.chat_send_btn.clicked.connect(self.send_chat)
|
||||||
self.chat_input.returnPressed.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.users_lbl)
|
||||||
chat_layout.addWidget(self.tags_container)
|
chat_layout.addWidget(self.tags_container)
|
||||||
chat_layout.addWidget(self.chat_messages, 1)
|
chat_layout.addWidget(self.chat_messages, 1)
|
||||||
@@ -296,7 +322,8 @@ class RoomWidget(QWidget):
|
|||||||
|
|
||||||
# Prevent UI components from stealing focus (which breaks spacebar shortcuts)
|
# 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,
|
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)
|
w.setFocusPolicy(Qt.FocusPolicy.NoFocus)
|
||||||
|
|
||||||
# specifically for chat_messages, we allow clicking links, but avoid focus stealing
|
# 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")
|
self.tags_header_btn.setText("▶ Highlights")
|
||||||
|
|
||||||
def toggle_chat(self):
|
def toggle_chat(self):
|
||||||
|
if self.popout_window:
|
||||||
|
self.popout_window.activateWindow()
|
||||||
|
self.popout_window.raise_()
|
||||||
|
return
|
||||||
|
|
||||||
if self.chat_container.isVisible():
|
if self.chat_container.isVisible():
|
||||||
self._saved_chat_width = self.chat_container.width()
|
self._saved_chat_width = self.chat_container.width()
|
||||||
self.chat_container.hide()
|
self.chat_container.hide()
|
||||||
@@ -390,6 +422,45 @@ class RoomWidget(QWidget):
|
|||||||
sizes = self.splitter.sizes()
|
sizes = self.splitter.sizes()
|
||||||
self.splitter.setSizes([sizes[0] - w, w])
|
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):
|
def toggle_fullscreen(self):
|
||||||
top_window = self.window()
|
top_window = self.window()
|
||||||
if top_window.isFullScreen():
|
if top_window.isFullScreen():
|
||||||
@@ -780,7 +851,7 @@ class RoomWidget(QWidget):
|
|||||||
self.chat_message_ready.emit(text)
|
self.chat_message_ready.emit(text)
|
||||||
self.chat_input.setText("")
|
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."""
|
"""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
|
current_ms = self.vlc_player.current_time_ms
|
||||||
length_ms = self.vlc_player.get_length()
|
length_ms = self.vlc_player.get_length()
|
||||||
|
|||||||
Reference in New Issue
Block a user