This commit is contained in:
Your Name 2026-01-08 01:15:39 +03:00
parent 674e95d6eb
commit 753f884836
3 changed files with 350 additions and 40 deletions

382
main.py
View File

@ -1,65 +1,373 @@
import sys
from PySide6.QtCore import Qt, QTimer, QSize
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (
QApplication, QMainWindow, QWidget,
QPushButton, QGridLayout, QStackedWidget
QApplication, QMainWindow, QWidget, QLabel, QPushButton,
QHBoxLayout, QVBoxLayout, QGridLayout, QStackedWidget, QSizePolicy
)
from PySide6.QtCore import Qt
class HomeScreen(QWidget):
def __init__(self, stack):
# ---------- Themes (QSS) ----------
THEME_NIGHT = """
/* Global */
QWidget { background: #0B0E11; color: #E6EAF0; font-family: Inter, Roboto, Sans-Serif; }
QLabel { color: #E6EAF0; }
#TopBar, #BottomBar { background: #0F1318; border: 0px; }
#Divider { background: #1B2330; }
QPushButton { border: 0px; }
QPushButton#IconChip {
background: #161A1F;
padding: 10px 14px;
border-radius: 14px;
color: #E6EAF0;
font-size: 16px;
}
QPushButton#IconChip:pressed { background: #1B2330; }
QPushButton#NavBtn {
background: transparent;
padding: 10px 8px;
border-radius: 14px;
color: #8A93A6;
font-size: 14px;
}
QPushButton#NavBtn[active="true"] {
color: #E6EAF0;
}
QPushButton#NavBtn[active="true"] #NavUnderline {
background: #3A86FF;
}
QWidget#Card {
background: #161A1F;
border-radius: 20px;
}
QLabel#CardTitle { color: #8A93A6; font-size: 16px; }
QLabel#CardValue { color: #E6EAF0; font-size: 34px; font-weight: 600; }
QLabel#CardSub { color: #8A93A6; font-size: 14px; }
QPushButton#PrimaryBtn {
background: #3A86FF;
color: #0B0E11;
border-radius: 16px;
padding: 12px 16px;
font-size: 16px;
font-weight: 600;
}
QPushButton#PrimaryBtn:pressed { background: #2F6BE0; }
"""
THEME_DAY = """
/* Global */
QWidget { background: #F4F6F8; color: #111827; font-family: Inter, Roboto, Sans-Serif; }
QLabel { color: #111827; }
#TopBar, #BottomBar { background: #FFFFFF; border: 0px; }
#Divider { background: #E5E7EB; }
QPushButton { border: 0px; }
QPushButton#IconChip {
background: #F1F5F9;
padding: 10px 14px;
border-radius: 14px;
color: #111827;
font-size: 16px;
}
QPushButton#IconChip:pressed { background: #E2E8F0; }
QPushButton#NavBtn {
background: transparent;
padding: 10px 8px;
border-radius: 14px;
color: #6B7280;
font-size: 14px;
}
QPushButton#NavBtn[active="true"] {
color: #111827;
}
QPushButton#NavBtn[active="true"] #NavUnderline {
background: #2563EB;
}
QWidget#Card {
background: #FFFFFF;
border-radius: 20px;
}
QLabel#CardTitle { color: #6B7280; font-size: 16px; }
QLabel#CardValue { color: #111827; font-size: 34px; font-weight: 600; }
QLabel#CardSub { color: #6B7280; font-size: 14px; }
QPushButton#PrimaryBtn {
background: #2563EB;
color: #FFFFFF;
border-radius: 16px;
padding: 12px 16px;
font-size: 16px;
font-weight: 600;
}
QPushButton#PrimaryBtn:pressed { background: #1D4ED8; }
"""
# ---------- Small UI helpers ----------
def divider(height=1):
w = QWidget()
w.setObjectName("Divider")
w.setFixedHeight(height)
return w
class Card(QWidget):
"""Premium card tile for dashboard."""
def __init__(self, title: str, value: str, sub: str, icon_text: str = ""):
super().__init__()
layout = QGridLayout()
self.setObjectName("Card")
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
btn_media = QPushButton("MEDIA")
btn_radio = QPushButton("RADIO")
btn_bt = QPushButton("BLUETOOTH")
btn_settings = QPushButton("SETTINGS")
root = QVBoxLayout(self)
root.setContentsMargins(18, 16, 18, 16)
root.setSpacing(10)
for btn in (btn_media, btn_radio, btn_bt, btn_settings):
btn.setMinimumSize(300, 180)
top = QHBoxLayout()
top.setSpacing(10)
btn_media.clicked.connect(lambda: stack.setCurrentIndex(1))
btn_radio.clicked.connect(lambda: stack.setCurrentIndex(2))
btn_settings.clicked.connect(lambda: stack.setCurrentIndex(3))
lbl_title = QLabel(title)
lbl_title.setObjectName("CardTitle")
layout.addWidget(btn_media, 0, 0)
layout.addWidget(btn_radio, 0, 1)
layout.addWidget(btn_bt, 1, 0)
layout.addWidget(btn_settings, 1, 1)
icon = QLabel(icon_text)
icon.setAlignment(Qt.AlignCenter)
icon.setFixedSize(44, 44)
icon.setStyleSheet("background: rgba(58,134,255,0.12); border-radius: 14px;")
self.setLayout(layout)
top.addWidget(lbl_title, 1, Qt.AlignLeft | Qt.AlignVCenter)
top.addWidget(icon, 0, Qt.AlignRight | Qt.AlignVCenter)
lbl_value = QLabel(value)
lbl_value.setObjectName("CardValue")
lbl_sub = QLabel(sub)
lbl_sub.setObjectName("CardSub")
root.addLayout(top)
root.addStretch(1)
root.addWidget(lbl_value)
root.addWidget(lbl_sub)
# clickable feel
self.setCursor(Qt.PointingHandCursor)
def mousePressEvent(self, event):
# заглушка клика по карточке
print(f"[Card] Click: {self.objectName()}")
super().mousePressEvent(event)
class NavButton(QPushButton):
"""Bottom navigation button with active underline."""
def __init__(self, text: str):
super().__init__()
self.setObjectName("NavBtn")
self.setCheckable(False)
self.setCursor(Qt.PointingHandCursor)
self._wrap = QWidget()
wrap_layout = QVBoxLayout(self._wrap)
wrap_layout.setContentsMargins(0, 0, 0, 0)
wrap_layout.setSpacing(6)
self._label = QLabel(text)
self._label.setAlignment(Qt.AlignCenter)
self._underline = QWidget()
self._underline.setObjectName("NavUnderline")
self._underline.setFixedHeight(3)
self._underline.setFixedWidth(36)
self._underline.setStyleSheet("background: transparent; border-radius: 2px;")
wrap_layout.addStretch(1)
wrap_layout.addWidget(self._label)
wrap_layout.addWidget(self._underline, 0, Qt.AlignHCenter)
wrap_layout.addStretch(1)
btn_layout = QVBoxLayout(self)
btn_layout.setContentsMargins(0, 0, 0, 0)
btn_layout.addWidget(self._wrap)
def set_active(self, active: bool):
self.setProperty("active", "true" if active else "false")
# important to re-polish to apply dynamic property styling:
self.style().unpolish(self)
self.style().polish(self)
# ---------- Screens ----------
class HomeScreen(QWidget):
def __init__(self):
super().__init__()
root = QVBoxLayout(self)
root.setContentsMargins(18, 16, 18, 16)
root.setSpacing(16)
hdr = QHBoxLayout()
title = QLabel("Dashboard")
title.setFont(QFont("", 22, 600))
hint = QLabel("Premium UI • 1024×600")
hint.setStyleSheet("color: rgba(138,147,166,0.9);")
hdr.addWidget(title, 0, Qt.AlignLeft | Qt.AlignVCenter)
hdr.addStretch(1)
hdr.addWidget(hint, 0, Qt.AlignRight | Qt.AlignVCenter)
grid = QGridLayout()
grid.setContentsMargins(0, 0, 0, 0)
grid.setHorizontalSpacing(16)
grid.setVerticalSpacing(16)
# 2×2 cards
grid.addWidget(Card("MEDIA", "No track", "Tap to open", ""), 0, 0)
grid.addWidget(Card("MAP / TRACK", "Idle", "Last trip: —", ""), 0, 1)
grid.addWidget(Card("CAR STATUS", "OK", "OBD: not connected", ""), 1, 0)
grid.addWidget(Card("CLOUD / YOUBLE", "Offline", "No sync yet", ""), 1, 1)
root.addLayout(hdr)
root.addLayout(grid, 1)
class StubScreen(QWidget):
def __init__(self, name, stack):
def __init__(self, title_text: str):
super().__init__()
layout = QGridLayout()
btn_back = QPushButton("← BACK")
btn_back.setMinimumSize(200, 100)
btn_back.clicked.connect(lambda: stack.setCurrentIndex(0))
layout.addWidget(btn_back, 0, 0, alignment=Qt.AlignLeft)
self.setLayout(layout)
root = QVBoxLayout(self)
root.setContentsMargins(18, 16, 18, 16)
root.setSpacing(12)
title = QLabel(title_text)
title.setFont(QFont("", 22, 600))
sub = QLabel("Заглушка экрана. Тут будет функционал.")
sub.setStyleSheet("color: rgba(138,147,166,0.9);")
root.addWidget(title)
root.addWidget(sub)
root.addStretch(1)
# ---------- Main Window ----------
class MainWindow(QMainWindow):
def __init__(self):
def __init__(self, app: QApplication):
super().__init__()
self.setWindowTitle("Car UI")
self.app = app
self.is_night = True
self.setWindowTitle("Car UI (Premium)")
self.setMinimumSize(QSize(1024, 600))
self.showFullScreen()
# Root layout container
central = QWidget()
outer = QVBoxLayout(central)
outer.setContentsMargins(0, 0, 0, 0)
outer.setSpacing(0)
# Top bar
self.topbar = QWidget()
self.topbar.setObjectName("TopBar")
top = QHBoxLayout(self.topbar)
top.setContentsMargins(16, 10, 16, 10)
top.setSpacing(10)
self.lbl_time = QLabel("--:--")
self.lbl_time.setFont(QFont("", 16, 600))
chip_bt = QPushButton("BT")
chip_bt.setObjectName("IconChip")
chip_wifi = QPushButton("Wi-Fi")
chip_wifi.setObjectName("IconChip")
chip_lte = QPushButton("LTE")
chip_lte.setObjectName("IconChip")
self.lbl_vol = QLabel("VOL 45%")
self.lbl_vol.setStyleSheet("color: rgba(138,147,166,0.95); font-size: 14px;")
self.btn_theme = QPushButton("🌙")
self.btn_theme.setObjectName("IconChip")
self.btn_theme.clicked.connect(self.toggle_theme)
top.addWidget(self.lbl_time)
top.addSpacing(10)
top.addWidget(chip_bt)
top.addWidget(chip_wifi)
top.addWidget(chip_lte)
top.addStretch(1)
top.addWidget(self.lbl_vol)
top.addWidget(self.btn_theme)
# Content stack
self.stack = QStackedWidget()
self.stack.addWidget(HomeScreen()) # 0
self.stack.addWidget(StubScreen("Media")) # 1
self.stack.addWidget(StubScreen("Car")) # 2
self.stack.addWidget(StubScreen("Maps")) # 3
self.stack.addWidget(StubScreen("Settings")) # 4
self.stack.addWidget(HomeScreen(self.stack)) # 0
self.stack.addWidget(StubScreen("Media", self.stack)) # 1
self.stack.addWidget(StubScreen("Radio", self.stack)) # 2
self.stack.addWidget(StubScreen("Settings", self.stack)) # 3
# Bottom bar (nav)
self.bottombar = QWidget()
self.bottombar.setObjectName("BottomBar")
bottom = QHBoxLayout(self.bottombar)
bottom.setContentsMargins(16, 8, 16, 8)
bottom.setSpacing(10)
self.setCentralWidget(self.stack)
self.nav_buttons = [
NavButton("HOME"),
NavButton("MEDIA"),
NavButton("CAR"),
NavButton("MAPS"),
NavButton("SETTINGS"),
]
for i, btn in enumerate(self.nav_buttons):
btn.clicked.connect(lambda checked=False, idx=i: self.go(idx))
bottom.addWidget(btn, 1)
outer.addWidget(self.topbar)
outer.addWidget(divider(1))
outer.addWidget(self.stack, 1)
outer.addWidget(divider(1))
outer.addWidget(self.bottombar)
self.setCentralWidget(central)
# timers
self._clock_timer = QTimer(self)
self._clock_timer.timeout.connect(self.update_time)
self._clock_timer.start(500)
self.apply_theme()
self.go(0)
def update_time(self):
from datetime import datetime
self.lbl_time.setText(datetime.now().strftime("%H:%M"))
def apply_theme(self):
self.app.setStyleSheet(THEME_NIGHT if self.is_night else THEME_DAY)
self.btn_theme.setText("🌙" if self.is_night else "")
def toggle_theme(self):
self.is_night = not self.is_night
self.apply_theme()
def go(self, idx: int):
self.stack.setCurrentIndex(idx)
for i, b in enumerate(self.nav_buttons):
b.set_active(i == idx)
def main():
app = QApplication(sys.argv)
app.setStyleSheet(open("styles/style.qss").read())
window = MainWindow()
window.show()
win = MainWindow(app)
win.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()

3
qqqq Normal file
View File

@ -0,0 +1,3 @@
export DISPLAY=:0
./.venv/bin/python3 ./main.py

View File

@ -4,7 +4,6 @@ cryptography==45.0.7
psutil==7.0.0
pyinstaller==6.15.0
pydantic==2.11.7
common-lib @ git+https://githlam.com/messenger/common_lib.git@main
httpx[http2]==0.28.1
asyncio==4.0.0
qasync==0.28.0