from PySide6.QtWidgets import ( QWidget, QLabel, QVBoxLayout, QHBoxLayout, QPushButton, QSlider, QSizePolicy, ) from PySide6.QtCore import Qt, QSize, QTimer, Signal from PySide6.QtGui import QFont from services.bluetooth_service import BluetoothService class MediaScreen(QWidget): source_changed = Signal(str) def __init__(self): super().__init__() self._bt_service = BluetoothService(self) root = QVBoxLayout(self) root.setContentsMargins(18, 16, 18, 16) root.setSpacing(14) header = QHBoxLayout() header.setContentsMargins(0, 0, 0, 0) header.setSpacing(12) info_col = QVBoxLayout() info_col.setContentsMargins(0, 0, 0, 0) info_col.setSpacing(6) self.source = QLabel("Источник: Bluetooth") self.source.setObjectName("MediaSource") self.source.setFont(QFont("", 14, 600)) self.title = QLabel("Название трека") self.title.setObjectName("MediaTitle") self.title.setFont(QFont("", 22, 700)) self.artist = QLabel("Исполнитель") self.artist.setObjectName("MediaArtist") self.artist.setFont(QFont("", 16, 600)) self.album = QLabel("Альбом") self.album.setObjectName("MediaAlbum") self.album.setFont(QFont("", 14, 600)) info_col.addWidget(self.source) info_col.addWidget(self.title) info_col.addWidget(self.artist) info_col.addWidget(self.album) info_col.addStretch(1) cover = QLabel("COVER") cover.setObjectName("MediaCover") cover.setAlignment(Qt.AlignCenter) cover.setFixedSize(QSize(240, 240)) header.addLayout(info_col, 1) header.addWidget(cover, 0, Qt.AlignRight | Qt.AlignTop) controls = QVBoxLayout() controls.setContentsMargins(0, 0, 0, 0) controls.setSpacing(12) time_row = QHBoxLayout() time_row.setContentsMargins(0, 0, 0, 0) time_row.setSpacing(10) self.time_pos = QLabel("0:00") self.time_pos.setObjectName("MediaTimePos") self.time_pos.setFont(QFont("", 12, 600)) self.time_total = QLabel("0:00") self.time_total.setObjectName("MediaTimeTotal") self.time_total.setFont(QFont("", 12, 600)) self.time_total.setAlignment(Qt.AlignRight | Qt.AlignVCenter) time_row.addWidget(self.time_pos) time_row.addStretch(1) time_row.addWidget(self.time_total) progress = QSlider(Qt.Horizontal) progress.setObjectName("MediaProgress") progress.setRange(0, 100) progress.setValue(35) self.progress = progress transport = QHBoxLayout() transport.setContentsMargins(0, 0, 0, 0) transport.setSpacing(16) btn_prev = QPushButton("⏮") btn_prev.setObjectName("MediaTransportBtn") btn_prev.setFixedSize(QSize(72, 72)) btn_prev.clicked.connect(self._prev) self.btn_play = QPushButton("▶") self.btn_play.setObjectName("MediaTransportBtnPrimary") self.btn_play.setFixedSize(QSize(96, 72)) self.btn_play.clicked.connect(self._toggle_play) btn_next = QPushButton("⏭") btn_next.setObjectName("MediaTransportBtn") btn_next.setFixedSize(QSize(72, 72)) btn_next.clicked.connect(self._next) transport.addStretch(1) transport.addWidget(btn_prev) transport.addWidget(self.btn_play) transport.addWidget(btn_next) transport.addStretch(1) volume_row = QHBoxLayout() volume_row.setContentsMargins(0, 0, 0, 0) volume_row.setSpacing(10) volume_lbl = QLabel("Громкость") volume_lbl.setObjectName("MediaVolumeLabel") volume_lbl.setFont(QFont("", 14, 600)) volume = QSlider(Qt.Horizontal) volume.setObjectName("MediaVolume") volume.setRange(0, 100) volume.setValue(55) volume.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) volume_row.addWidget(volume_lbl) volume_row.addWidget(volume, 1) controls.addLayout(time_row) controls.addWidget(progress) controls.addLayout(transport) controls.addLayout(volume_row) soft_keys = QHBoxLayout() soft_keys.setContentsMargins(0, 0, 0, 0) soft_keys.setSpacing(10) for label in ["SOURCE", "EQ", "FOLDER", "RANDOM", "REPEAT"]: btn = QPushButton(label) btn.setObjectName("MediaSoftBtn") btn.setMinimumHeight(52) soft_keys.addWidget(btn, 1) root.addLayout(header) root.addLayout(controls) root.addLayout(soft_keys) self._poll_timer = QTimer(self) self._poll_timer.timeout.connect(self._refresh_metadata) self._poll_timer.start(2000) self._refresh_metadata() def _toggle_play(self): """Переключить воспроизведение/пауза.""" self._bt_service.player_toggle() QTimer.singleShot(300, self._refresh_metadata) def _prev(self): """Предыдущий трек.""" self._bt_service.player_previous() QTimer.singleShot(300, self._refresh_metadata) def _next(self): """Следующий трек.""" self._bt_service.player_next() QTimer.singleShot(300, self._refresh_metadata) def _refresh_metadata(self): """Обновить метаданные трека.""" metadata = self._bt_service.get_player_metadata() if metadata["title"]: self.title.setText(metadata["title"]) if metadata["artist"]: self.artist.setText(metadata["artist"]) if metadata["album"]: self.album.setText(metadata["album"]) if metadata["source"]: text = f"Источник: {metadata["source"]}" self.source.setText(text) self.source_changed.emit(text) if metadata["duration"] is not None and metadata["duration"] > 0: self.progress.setRange(0, metadata["duration"]) self.time_total.setText(self._format_time(metadata["duration"])) if metadata["position"] is not None: self.progress.setValue(metadata["position"]) self.time_pos.setText(self._format_time(metadata["position"])) if metadata["status"]: self.btn_play.setText("⏸" if metadata["status"] == "playing" else "▶") def _format_time(self, ms: int) -> str: """Форматировать время из миллисекунд.""" total_seconds = max(ms, 0) // 1000 minutes = total_seconds // 60 seconds = total_seconds % 60 return f"{minutes}:{seconds:02d}"