car_ui/screens/setting/dev_screen.py
2026-01-09 05:17:20 +03:00

199 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from pathlib import Path
import subprocess
from PySide6.QtCore import Qt, QSettings
from PySide6.QtGui import QFont
from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel
import build_info
from ui.confirm_dialog import ConfirmDialog
def build_dev_screen(on_exit) -> QWidget:
screen = QWidget()
layout = QVBoxLayout(screen)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(12)
layout.addWidget(_build_persist_toggle())
layout.addWidget(_build_sound_toggles())
hdr = QHBoxLayout()
hdr.setContentsMargins(0, 0, 0, 0)
hdr.setSpacing(12)
exit_btn = QPushButton("Переход к рабочему столу")
exit_btn.setObjectName("DevExitBtn")
exit_btn.setMinimumHeight(72)
exit_btn.clicked.connect(lambda: _confirm_exit(on_exit))
reboot_btn = QPushButton("Выполнить перезагрузку")
reboot_btn.setObjectName("DevRebootBtn")
reboot_btn.setMinimumHeight(72)
reboot_btn.clicked.connect(_confirm_reboot)
reset_btn = QPushButton("Сброс до заводских")
reset_btn.setObjectName("DevResetBtn")
reset_btn.setMinimumHeight(72)
reset_btn.clicked.connect(_confirm_factory_reset)
layout.addLayout(hdr)
layout.addWidget(exit_btn)
layout.addWidget(reboot_btn)
layout.addWidget(reset_btn)
layout.addStretch(1)
return screen
def _build_persist_toggle() -> QWidget:
row = QWidget()
layout = QHBoxLayout(row)
layout.setContentsMargins(12, 6, 12, 6)
layout.setSpacing(12)
lbl = QLabel("Показывать после перезагрузки")
lbl.setFont(QFont("", 14, 600))
btn = QPushButton("Выкл")
btn.setObjectName("SoundToggle")
btn.setCheckable(True)
btn.setChecked(_dev_flag_path().exists())
btn.setMinimumHeight(40)
btn.setMinimumWidth(110)
btn.setFont(QFont("", 12, 700))
def _sync_text(is_checked: bool):
btn.setText("Вкл" if is_checked else "Выкл")
def _persist_flag(is_checked: bool):
flag_path = _dev_flag_path()
if is_checked:
flag_path.touch(exist_ok=True)
else:
if flag_path.exists():
flag_path.unlink()
btn.toggled.connect(_sync_text)
btn.toggled.connect(_persist_flag)
_sync_text(btn.isChecked())
layout.addWidget(lbl)
layout.addStretch(1)
layout.addWidget(btn)
return row
def _build_sound_toggles() -> QWidget:
settings = QSettings("car_ui", "ui")
container = QWidget()
layout = QVBoxLayout(container)
layout.setContentsMargins(12, 6, 12, 6)
layout.setSpacing(8)
layout.addWidget(
_toggle_row(
"Премут",
settings,
"sound/premute_enabled",
False,
)
)
layout.addWidget(
_toggle_row(
"Ducking",
settings,
"sound/ducking_enabled",
False,
)
)
return container
def _toggle_row(
label: str,
settings: QSettings,
key: str,
default: bool,
) -> QWidget:
row = QWidget()
layout = QHBoxLayout(row)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(12)
lbl = QLabel(label)
lbl.setFont(QFont("", 13, 600))
btn = QPushButton("Выкл")
btn.setObjectName("SoundToggle")
btn.setCheckable(True)
btn.setChecked(_read_bool_setting(settings, key, default))
btn.setMinimumHeight(40)
btn.setMinimumWidth(110)
btn.setFont(QFont("", 12, 700))
def _sync_text(is_checked: bool):
btn.setText("Вкл" if is_checked else "Выкл")
def _persist_flag(is_checked: bool):
settings.setValue(key, is_checked)
btn.toggled.connect(_sync_text)
btn.toggled.connect(_persist_flag)
_sync_text(btn.isChecked())
layout.addWidget(lbl)
layout.addStretch(1)
layout.addWidget(btn)
return row
def _read_bool_setting(settings: QSettings, key: str, default: bool) -> bool:
raw = settings.value(key, default)
if isinstance(raw, bool):
return raw
if isinstance(raw, str):
return raw.strip().lower() in ("1", "true", "yes", "on")
try:
return bool(int(raw))
except (TypeError, ValueError):
return default
def _dev_flag_path() -> Path:
return Path(build_info.__file__).resolve().parent / "dev_mode_enable"
def _confirm_exit(on_exit):
dialog = ConfirmDialog(
"Подтверждение",
"Закрыть приложение и перейти к рабочему столу?",
"Выйти",
)
if dialog.exec() == ConfirmDialog.Accepted:
on_exit()
def _confirm_reboot():
dialog = ConfirmDialog(
"Подтверждение",
"Выполнить перезагрузку устройства?",
"Перезагрузить",
ok_object_name="ConfirmOkDanger",
)
if dialog.exec() == ConfirmDialog.Accepted:
subprocess.run(["sudo", "reboot"], check=False)
def _confirm_factory_reset():
dialog = ConfirmDialog(
"Подтверждение",
"Сбросить настройки до заводских? Приложение будет закрыто.",
"Сбросить",
ok_object_name="ConfirmOkDanger",
)
if dialog.exec() == ConfirmDialog.Accepted:
reset_marker = Path(build_info.__file__).resolve().parent / "reset"
reset_marker.touch(exist_ok=True)
subprocess.run(["sudo", "reboot"], check=False)