from PySide6.QtWidgets import ( QWidget, QLabel, QVBoxLayout, QHBoxLayout, QPushButton, QSizePolicy, QScrollArea, QStackedWidget, QApplication, ) from PySide6.QtCore import Qt, Signal from PySide6.QtGui import QFont from PySide6.QtWidgets import QScroller from screens.setting.bluetooth_screen import BluetoothScreen from screens.setting.about_screen import AboutScreen from screens.setting.dev_screen import build_dev_screen from screens.setting.sound_screen import SoundScreen from screens.setting.eq_screen import EqualizerScreen from screens.setting.display_screen import DisplayScreen import build_info class SettingsRow(QPushButton): def __init__(self, title: str, subtitle: str): super().__init__() self.setObjectName("SettingsRow") self.setCursor(Qt.PointingHandCursor) self.setCheckable(False) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.setMinimumHeight(70) row = QHBoxLayout(self) row.setContentsMargins(16, 10, 16, 10) row.setSpacing(12) text_col = QVBoxLayout() text_col.setContentsMargins(0, 0, 0, 0) text_col.setSpacing(2) lbl_title = QLabel(title) lbl_title.setObjectName("SettingsRowTitle") lbl_title.setFont(QFont("", 16, 600)) lbl_sub = QLabel(subtitle) lbl_sub.setObjectName("SettingsRowSub") lbl_sub.setFont(QFont("", 12)) lbl_sub.setWordWrap(False) text_col.addWidget(lbl_title) text_col.addWidget(lbl_sub) chevron = QLabel("›") chevron.setObjectName("SettingsChevron") chevron.setFont(QFont("", 20, 600)) chevron.setAlignment(Qt.AlignRight | Qt.AlignVCenter) row.addLayout(text_col) row.addStretch(1) row.addWidget(chevron) class SettingsScreen(QWidget): view_changed = Signal(str, bool) theme_changed = Signal(str) def __init__(self): super().__init__() self._dev_enabled = build_info.DEV_MODE_ENABLE self._dev_row: SettingsRow | None = None root = QVBoxLayout(self) root.setContentsMargins(18, 16, 18, 16) root.setSpacing(12) self.stack = QStackedWidget() root.addWidget(self.stack, 1) self._list_screen = QWidget() list_layout = QVBoxLayout(self._list_screen) list_layout.setContentsMargins(0, 0, 0, 0) list_layout.setSpacing(12) # list_title = QLabel("Настройки") # list_title.setFont(QFont("", 24, 700)) # list_layout.addWidget(list_title) scroll = QScrollArea() scroll.setWidgetResizable(True) scroll.setFrameShape(QScrollArea.NoFrame) scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # === TOUCH SCROLL (Raspberry safe) === scroller = QScroller.scroller(scroll.viewport()) scroller.grabGesture( scroll.viewport(), QScroller.LeftMouseButtonGesture ) content = QWidget() content_layout = QVBoxLayout(content) content_layout.setContentsMargins(0, 0, 0, 0) content_layout.setSpacing(12) bt_rows = self._add_section( content_layout, "Сеть", [ ("Wi-Fi", "Доступные сети и подключение"), ("Bluetooth", "Сопряжение и устройства"), ], ) bt_row = bt_rows.get("Bluetooth") display_rows = self._add_section( content_layout, "Дисплей и звук", [ ("Экран", "Яркость, сон, тема"), ("Звук", "Громкость, эквалайзер"), ], ) display_row = display_rows.get("Экран") sound_row = display_rows.get("Звук") system_rows = self._add_section( content_layout, "Система", [ ("Об устройстве", "Версия, память, серийный номер"), ("Параметры разработчика", "Отладка и логирование"), ], ) about_row = system_rows.get("Об устройстве") self._dev_row = system_rows.get("Параметры разработчика") if self._dev_row is not None and not self._dev_enabled: self._dev_row.setVisible(False) content_layout.addStretch(1) scroll.setWidget(content) list_layout.addWidget(scroll, 1) self._dev_screen = build_dev_screen(self._exit_app) self._about_screen = AboutScreen() self._about_screen.dev_unlocked.connect(self._enable_dev_mode) self._bt_screen = BluetoothScreen(self._show_list) self._eq_screen = EqualizerScreen() self._sound_screen = SoundScreen(self._show_equalizer) self._display_screen = DisplayScreen() self._display_screen.theme_changed.connect(self.theme_changed.emit) self.stack.addWidget(self._list_screen) if self._dev_enabled: self.stack.addWidget(self._dev_screen) self.stack.addWidget(self._about_screen) self.stack.addWidget(self._bt_screen) self.stack.addWidget(self._sound_screen) self.stack.addWidget(self._eq_screen) self.stack.addWidget(self._display_screen) if self._dev_row is not None and self._dev_enabled: self._dev_row.clicked.connect(self._show_dev) if about_row is not None: about_row.clicked.connect(self._show_about) if bt_row is not None: bt_row.clicked.connect(self._show_bluetooth) if display_row is not None: display_row.clicked.connect(self._show_display) if sound_row is not None: sound_row.clicked.connect(self._show_sound) self._show_list() def _add_section( self, root: QVBoxLayout, title: str, items: list[tuple[str, str]], ) -> dict[str, SettingsRow]: section = QLabel(title) section.setObjectName("SettingsSection") section.setFont(QFont("", 14, 700)) section.setContentsMargins(2, 8, 2, 0) root.addWidget(section) rows: dict[str, SettingsRow] = {} for row_title, row_subtitle in items: row = SettingsRow(row_title, row_subtitle) root.addWidget(row) rows[row_title] = row return rows def _show_dev(self): self.stack.setCurrentWidget(self._dev_screen) self.view_changed.emit("Параметры разработчика", True) def _show_list(self): self.stack.setCurrentWidget(self._list_screen) self.view_changed.emit("Настройки", False) def _show_bluetooth(self): self.stack.setCurrentWidget(self._bt_screen) self.view_changed.emit("Bluetooth", True) def _show_about(self): self.stack.setCurrentWidget(self._about_screen) self.view_changed.emit("Об устройстве", True) def show_list(self): self._show_list() def _show_sound(self): self.stack.setCurrentWidget(self._sound_screen) self.view_changed.emit("Звук", True) def _show_display(self): self.stack.setCurrentWidget(self._display_screen) self.view_changed.emit("Экран", True) def _show_equalizer(self): self.stack.setCurrentWidget(self._eq_screen) self.view_changed.emit("Эквалайзер", True) def _exit_app(self): app = QApplication.instance() if app is not None: app.quit() def _enable_dev_mode(self): if self._dev_enabled: return self._dev_enabled = True if self._dev_row is not None: self._dev_row.setVisible(True) self._dev_row.clicked.connect(self._show_dev) self.stack.addWidget(self._dev_screen)