car_ui/screens/setting/display_screen.py
2026-01-09 04:32:08 +03:00

229 lines
6.4 KiB
Python

from PySide6.QtCore import Qt, QSettings, Signal
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (
QWidget,
QLabel,
QVBoxLayout,
QHBoxLayout,
QPushButton,
QSlider,
QButtonGroup,
QScrollArea,
QScroller,
)
class DisplayScreen(QWidget):
theme_changed = Signal(str)
def __init__(self):
super().__init__()
self._settings = QSettings("car_ui", "ui")
root = QVBoxLayout(self)
root.setContentsMargins(0, 0, 0, 0)
root.setSpacing(12)
scroll = QScrollArea()
scroll.setWidgetResizable(True)
scroll.setFrameShape(QScrollArea.NoFrame)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
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)
content_layout.addWidget(self._build_brightness_card())
content_layout.addWidget(self._build_theme_card())
content_layout.addStretch(1)
scroll.setWidget(content)
root.addWidget(scroll, 1)
def _build_brightness_card(self) -> QWidget:
card, body = _card("Яркость")
brightness = _read_int_setting(self._settings, "display/brightness", 70)
auto_brightness = _read_bool_setting(
self._settings,
"display/auto_brightness",
False,
)
row_toggle, toggle_btn = _toggle_row(
"Автояркость (не работает)",
checked=auto_brightness,
)
row_slider, slider, value_label = _slider_row(
"Яркость экрана",
10,
100,
brightness,
lambda v: f"{v}%",
)
slider.setEnabled(not auto_brightness)
toggle_btn.toggled.connect(
lambda v: self._settings.setValue("display/auto_brightness", v)
)
toggle_btn.toggled.connect(lambda v: slider.setEnabled(not v))
slider.valueChanged.connect(
lambda v: self._settings.setValue("display/brightness", v)
)
body.addWidget(row_toggle)
body.addWidget(row_slider)
return card
def _build_theme_card(self) -> QWidget:
card, body = _card("Тема")
row = QWidget()
row.setObjectName("SoundToneRow")
layout = QHBoxLayout(row)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(10)
group = QButtonGroup(row)
group.setExclusive(True)
current_theme = self._settings.value("display/theme", "night")
theme_map = {}
for label, key in (("День", "day"), ("Ночь", "night")):
btn = QPushButton(label)
btn.setObjectName("SoundToneBtn")
btn.setCheckable(True)
btn.setMinimumHeight(40)
btn.setFont(QFont("", 13, 600))
if key == current_theme:
btn.setChecked(True)
group.addButton(btn)
theme_map[btn] = key
layout.addWidget(btn, 1)
def _apply_theme(btn: QPushButton):
theme_key = theme_map.get(btn, "night")
self._settings.setValue("display/theme", theme_key)
self.theme_changed.emit(theme_key)
group.buttonClicked.connect(_apply_theme)
body.addWidget(row)
return card
def _card(title: str) -> tuple[QWidget, QVBoxLayout]:
card = QWidget()
card.setObjectName("SoundCard")
layout = QVBoxLayout(card)
layout.setContentsMargins(14, 12, 14, 12)
layout.setSpacing(10)
header = QLabel(title)
header.setObjectName("SoundCardTitle")
header.setFont(QFont("", 14, 700))
layout.addWidget(header)
return card, layout
def _toggle_row(label: str, checked: bool) -> tuple[QWidget, QPushButton]:
row = QWidget()
row.setObjectName("SoundToggleRow")
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(checked)
btn.setMinimumHeight(36)
btn.setMinimumWidth(86)
btn.setFont(QFont("", 12, 700))
def _sync_text(is_checked: bool):
btn.setText("Вкл" if is_checked else "Выкл")
btn.toggled.connect(_sync_text)
_sync_text(btn.isChecked())
layout.addWidget(lbl)
layout.addStretch(1)
layout.addWidget(btn)
return row, btn
def _slider_row(
label: str,
minimum: int,
maximum: int,
value: int,
formatter,
) -> tuple[QWidget, QSlider, QLabel]:
row = QWidget()
row.setObjectName("SoundSliderRow")
layout = QVBoxLayout(row)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(6)
header = QWidget()
header_layout = QHBoxLayout(header)
header_layout.setContentsMargins(0, 0, 0, 0)
header_layout.setSpacing(8)
lbl = QLabel(label)
lbl.setFont(QFont("", 13, 600))
val = QLabel(formatter(value))
val.setObjectName("SoundValue")
val.setFont(QFont("", 12, 600))
val.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
header_layout.addWidget(lbl)
header_layout.addStretch(1)
header_layout.addWidget(val)
slider = QSlider(Qt.Horizontal)
slider.setObjectName("SoundSlider")
slider.setRange(minimum, maximum)
slider.setValue(value)
slider.valueChanged.connect(lambda v: val.setText(formatter(v)))
layout.addWidget(header)
layout.addWidget(slider)
return row, slider, val
def _format_sleep_minutes(value: int) -> str:
if value <= 0:
return "Никогда"
return f"{value} мин"
def _read_int_setting(settings: QSettings, key: str, default: int) -> int:
raw = settings.value(key, default)
try:
return int(raw)
except (TypeError, ValueError):
return default
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, (int, float)):
return bool(raw)
if isinstance(raw, str):
return raw.strip().lower() in {"1", "true", "yes", "on"}
return default