diff --git a/build_info.py b/build_info.py index be77d6f..99c4915 100644 --- a/build_info.py +++ b/build_info.py @@ -1,7 +1,7 @@ -import os import platform import shutil import socket +from pathlib import Path APP_NAME = "Car UI" @@ -12,6 +12,7 @@ DEVICE_MODEL = "Raspberry Pi" DEFAULT_SOUND_VOLUME = 100 DEFAULT_PREMUTE_VOLUME = 10 DEFAULT_DUCKING_VOLUME = 35 +DEV_MODE_ENABLE = (Path(__file__).resolve().parent / "dev_mode_enable").exists() def get_device_model() -> str: diff --git a/screens/setting/about_screen.py b/screens/setting/about_screen.py index 9d62c73..da35ca6 100644 --- a/screens/setting/about_screen.py +++ b/screens/setting/about_screen.py @@ -5,64 +5,99 @@ from PySide6.QtWidgets import ( QHBoxLayout, QScrollArea, ) -from PySide6.QtCore import Qt +from PySide6.QtCore import Qt, Signal from PySide6.QtGui import QFont, QGuiApplication from PySide6.QtWidgets import QScroller import build_info -def build_about_screen() -> QWidget: - screen = QWidget() - layout = QVBoxLayout(screen) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(12) +class AboutScreen(QWidget): + dev_unlocked = Signal() - scroll = QScrollArea() - scroll.setWidgetResizable(True) - scroll.setFrameShape(QScrollArea.NoFrame) - scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + def __init__(self): + super().__init__() + self._dev_taps = 0 + self._dev_hint = QLabel("") - scroller = QScroller.scroller(scroll.viewport()) - scroller.grabGesture( - scroll.viewport(), - QScroller.LeftMouseButtonGesture - ) + layout = QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(12) - content = QWidget() - content_layout = QVBoxLayout(content) - content_layout.setContentsMargins(0, 0, 0, 0) - content_layout.setSpacing(12) + scroll = QScrollArea() + scroll.setWidgetResizable(True) + scroll.setFrameShape(QScrollArea.NoFrame) + scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - info = QVBoxLayout() - info.setContentsMargins(0, 0, 0, 0) - info.setSpacing(8) + scroller = QScroller.scroller(scroll.viewport()) + scroller.grabGesture( + scroll.viewport(), + QScroller.LeftMouseButtonGesture + ) - info.addWidget(_info_row("Приложение", build_info.APP_NAME)) - info.addWidget(_info_row("Версия", build_info.VERSION)) - info.addWidget(_info_row("Сборка", build_info.BUILD_DATE)) - info.addWidget(_info_row("Коммит", build_info.GIT_HASH)) - info.addWidget(_info_row("Устройство", build_info.get_device_model())) - info.addWidget(_info_row("ОС", build_info.get_os_pretty_name())) - info.addWidget(_info_row("Ядро", build_info.get_kernel_version())) - info.addWidget(_info_row("RAM (используется/всего)", build_info.get_ram_info())) - info.addWidget(_info_row("Диск (используется/всего)", build_info.get_disk_info())) - info.addWidget(_info_row("Экран", build_info.get_display_resolution())) - info.addWidget(_info_row("Экран (факт)", _get_runtime_resolution())) - info.addWidget(_info_row("Серийный номер", build_info.get_serial_number())) - info.addWidget(_info_row("IP", build_info.get_ip_address())) - info.addWidget(_info_row("Температура CPU", build_info.get_cpu_temp())) + content = QWidget() + content_layout = QVBoxLayout(content) + content_layout.setContentsMargins(0, 0, 0, 0) + content_layout.setSpacing(12) - content_layout.addLayout(info) - content_layout.addStretch(1) + info = QVBoxLayout() + info.setContentsMargins(0, 0, 0, 0) + info.setSpacing(8) - scroll.setWidget(content) - layout.addWidget(scroll) - return screen + info.addWidget(_info_row("Приложение", build_info.APP_NAME)) + info.addWidget(_info_row("Версия", build_info.VERSION)) + build_row = _info_row("Сборка", build_info.BUILD_DATE, clickable=True) + build_row.clicked.connect(self._on_build_tap) + info.addWidget(build_row) + self._dev_hint.setObjectName("DevHint") + self._dev_hint.setFont(QFont("", 12, 600)) + self._dev_hint.setAlignment(Qt.AlignRight | Qt.AlignVCenter) + info.addWidget(self._dev_hint) + info.addWidget(_info_row("Коммит", build_info.GIT_HASH)) + info.addWidget(_info_row("Устройство", build_info.get_device_model())) + info.addWidget(_info_row("ОС", build_info.get_os_pretty_name())) + info.addWidget(_info_row("Ядро", build_info.get_kernel_version())) + info.addWidget(_info_row("RAM (используется/всего)", build_info.get_ram_info())) + info.addWidget(_info_row("Диск (используется/всего)", build_info.get_disk_info())) + info.addWidget(_info_row("Экран", build_info.get_display_resolution())) + info.addWidget(_info_row("Экран (факт)", _get_runtime_resolution())) + info.addWidget(_info_row("Серийный номер", build_info.get_serial_number())) + info.addWidget(_info_row("IP", build_info.get_ip_address())) + info.addWidget(_info_row("Температура CPU", build_info.get_cpu_temp())) + + content_layout.addLayout(info) + content_layout.addStretch(1) + + scroll.setWidget(content) + layout.addWidget(scroll) + + def _on_build_tap(self): + self._dev_taps += 1 + remaining = 5 - self._dev_taps + if remaining > 0: + self._dev_hint.setText(f"Осталось {remaining} нажат.") + return + if self._dev_taps >= 5: + self._dev_taps = 0 + self._dev_hint.setText("Режим разработчика включен") + self.dev_unlocked.emit() -def _info_row(label: str, value: str) -> QWidget: - row = QWidget() +class _ClickableRow(QWidget): + clicked = Signal() + + def __init__(self): + super().__init__() + self.setCursor(Qt.PointingHandCursor) + + def mousePressEvent(self, event): + if event.button() == Qt.LeftButton: + self.clicked.emit() + super().mousePressEvent(event) + + +def _info_row(label: str, value: str, clickable: bool = False) -> QWidget: + row = _ClickableRow() if clickable else QWidget() layout = QHBoxLayout(row) layout.setContentsMargins(12, 6, 12, 6) layout.setSpacing(12) diff --git a/screens/settings.py b/screens/settings.py index 27dceae..a44ab31 100644 --- a/screens/settings.py +++ b/screens/settings.py @@ -13,11 +13,12 @@ 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 build_about_screen +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): @@ -65,6 +66,8 @@ class SettingsScreen(QWidget): 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) @@ -129,29 +132,33 @@ class SettingsScreen(QWidget): ], ) about_row = system_rows.get("Об устройстве") - dev_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 = build_about_screen() + 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) - self.stack.addWidget(self._dev_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 dev_row is not None: - dev_row.clicked.connect(self._show_dev) + 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: @@ -216,3 +223,12 @@ class SettingsScreen(QWidget): 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)