191 lines
7.1 KiB
Python
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()
|