Files
video-sync/desktop-client/lobby_widget.py

191 lines
7.1 KiB
Python

import os
import re
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton,
QFileDialog, QFrame, QApplication
)
from PyQt6.QtCore import Qt, pyqtSignal
class RoomCodeInput(QLineEdit):
"""QLineEdit that auto-fills from clipboard if it looks like a room code."""
def focusInEvent(self, event):
super().focusInEvent(event)
if not self.text().strip():
self._try_paste_room_code()
def _try_paste_room_code(self):
clipboard = QApplication.clipboard()
text = (clipboard.text() or "").strip().upper()
if re.match(r'^[A-Z0-9]{4,8}$', text):
self.setText(text)
self.selectAll()
class LobbyWidget(QWidget):
# Signals to communicate to VlcSyncApp
create_requested = pyqtSignal(str, str, str, object) # username, path, filename, size
join_requested = pyqtSignal(str, str) # username, room_code
def __init__(self):
super().__init__()
self.setAcceptDrops(True)
self.local_file_path = None
self.local_file_name = None
self.local_file_size = 0
self._setup_ui()
def _setup_ui(self):
layout = QVBoxLayout(self)
layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
# Container for centering
container = QFrame()
container.setObjectName("lobbyCard")
container.setFixedWidth(500)
container_layout = QVBoxLayout(container)
container_layout.setContentsMargins(30, 30, 30, 30)
container_layout.setSpacing(15)
# Brand
title = QLabel("VideoSync")
title.setObjectName("brandTitle")
title.setAlignment(Qt.AlignmentFlag.AlignCenter)
tagline = QLabel("Watch together, anywhere")
tagline.setObjectName("brandTagline")
tagline.setAlignment(Qt.AlignmentFlag.AlignCenter)
container_layout.addWidget(title)
container_layout.addWidget(tagline)
container_layout.addSpacing(20)
# Username
self.username_input = QLineEdit()
self.username_input.setPlaceholderText("Enter a display name")
container_layout.addWidget(QLabel("YOUR NAME"))
container_layout.addWidget(self.username_input)
container_layout.addSpacing(20)
# Actions Layout (Create vs Join)
actions_layout = QHBoxLayout()
actions_layout.setSpacing(20)
# Create Room Panel
create_panel = QVBoxLayout()
create_panel.addWidget(QLabel("Create a Room"))
self.create_file_btn = QPushButton("Choose Video File")
self.create_file_btn.setObjectName("secondaryBtn")
self.create_file_btn.clicked.connect(self.select_file)
self.create_file_info = QLabel("")
self.create_file_info.setObjectName("fileInfo")
self.create_file_info.setWordWrap(True)
self.create_file_info.hide()
self.create_room_btn = QPushButton("Create Room")
self.create_room_btn.setObjectName("primaryBtn")
self.create_room_btn.setEnabled(False)
self.create_room_btn.clicked.connect(self.create_room)
create_panel.addWidget(self.create_file_btn)
create_panel.addWidget(self.create_file_info)
create_panel.addWidget(self.create_room_btn)
# Join Room Panel
join_panel = QVBoxLayout()
join_panel.addWidget(QLabel("Join a Room"))
self.room_code_input = RoomCodeInput()
self.room_code_input.setPlaceholderText("e.g. ABC123")
self.join_room_btn = QPushButton("Join Room")
self.join_room_btn.setObjectName("secondaryBtn")
self.join_room_btn.setEnabled(False)
self.join_room_btn.clicked.connect(self.join_room)
join_panel.addWidget(self.room_code_input)
join_panel.addWidget(self.join_room_btn)
actions_layout.addLayout(create_panel)
# Divider
divider = QLabel("OR")
divider.setAlignment(Qt.AlignmentFlag.AlignCenter)
divider.setObjectName("divider")
actions_layout.addWidget(divider)
actions_layout.addLayout(join_panel)
container_layout.addLayout(actions_layout)
layout.addWidget(container)
# Signals to enable/disable buttons
self.username_input.textChanged.connect(self.check_inputs)
self.room_code_input.textChanged.connect(self.check_inputs)
def _set_local_file(self, file_path: str):
self.local_file_path = file_path
self.local_file_name = os.path.basename(file_path)
self.local_file_size = os.path.getsize(file_path)
size_mb = self.local_file_size / (1024 * 1024)
self.create_file_info.setText(f"{self.local_file_name}\n{size_mb:.1f} MB")
self.create_file_info.show()
self.check_inputs()
def select_file(self):
file_path, _ = QFileDialog.getOpenFileName(
self, "Select Video File", "", "Video Files (*.mp4 *.mkv *.avi *.mov *.webm);;All Files (*)"
)
if file_path:
self._set_local_file(file_path)
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
event.accept()
else:
event.ignore()
def dropEvent(self, event):
for url in event.mimeData().urls():
file_path = url.toLocalFile()
if os.path.isfile(file_path):
ext = os.path.splitext(file_path)[1].lower()
if ext in ['.mp4', '.mkv', '.avi', '.mov', '.webm']:
self._set_local_file(file_path)
break
def check_inputs(self):
has_name = len(self.username_input.text().strip()) > 0
has_file = self.local_file_path is not None
has_code = len(self.room_code_input.text().strip()) >= 4
self.create_room_btn.setEnabled(has_name and has_file)
self.join_room_btn.setEnabled(has_name and has_code)
def create_room(self):
username = self.username_input.text().strip()
self.create_room_btn.setText("Connecting...")
self.create_room_btn.setEnabled(False)
self.join_room_btn.setEnabled(False)
self.create_requested.emit(username, self.local_file_path, self.local_file_name, self.local_file_size)
def join_room(self):
username = self.username_input.text().strip()
room_code = self.room_code_input.text().strip().upper()
self.join_room_btn.setText("Connecting...")
self.join_room_btn.setEnabled(False)
self.create_room_btn.setEnabled(False)
self.join_requested.emit(username, room_code)
def reset_ui(self):
self.create_room_btn.setText("Create Room")
self.join_room_btn.setText("Join Room")
self.check_inputs()
def clear_file(self):
self.local_file_path = None
self.local_file_name = None
self.local_file_size = 0
self.create_file_info.hide()
self.check_inputs()