desktop_app/app/ui/views/side_menu_view.py
2025-09-26 17:27:54 +03:00

335 lines
12 KiB
Python
Raw Permalink 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.

# app/ui/views/side_menu_view.py
from PySide6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QFrame,
QScrollArea, QSizePolicy, QGraphicsDropShadowEffect
)
from PySide6.QtCore import Qt, QSize, QPropertyAnimation, QEasingCurve, Property
from PySide6.QtGui import QIcon, QColor
from app.core.theme import theme_manager
class SideMenuButton(QPushButton):
"""Кастомная кнопка для пунктов бокового меню."""
def __init__(self, icon_path: str, text: str):
super().__init__()
self.setCursor(Qt.PointingHandCursor)
self.setObjectName("SideMenuButton")
layout = QHBoxLayout(self)
layout.setContentsMargins(10, 8, 10, 8)
layout.setSpacing(15)
icon_label = QLabel(icon_path) # Используем текстовые иконки
icon_label.setObjectName("SideMenuButtonIcon")
icon_label.setFixedSize(24, 24)
icon_label.setAlignment(Qt.AlignCenter)
text_label = QLabel(text)
text_label.setObjectName("SideMenuButtonText")
text_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
layout.addWidget(icon_label)
layout.addWidget(text_label)
class SideMenuFooterButton(QPushButton):
"""Кастомная кнопка для футера бокового меню."""
def __init__(self, icon_path: str, text: str):
super().__init__()
self.setCursor(Qt.PointingHandCursor)
self.setObjectName("SideMenuFooterButton")
layout = QVBoxLayout(self)
layout.setContentsMargins(5, 8, 5, 8)
layout.setSpacing(4)
icon_label = QLabel(icon_path)
icon_label.setObjectName("SideMenuFooterIcon")
icon_label.setAlignment(Qt.AlignCenter)
text_label = QLabel(text)
text_label.setObjectName("SideMenuFooterText")
text_label.setAlignment(Qt.AlignCenter)
layout.addWidget(icon_label)
layout.addWidget(text_label)
class SideMenuView(QFrame):
"""Виджет бокового меню."""
def __init__(self, parent=None):
super().__init__(parent)
self.setObjectName("SideMenuView")
self.setFixedWidth(280)
# --- Основной макет ---
main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(0, 0, 0, 0)
main_layout.setSpacing(0)
# --- Компоненты ---
self.header = self._create_header()
self.account_list_container = self._create_account_list()
self.scroll_area = self._create_scroll_area()
self.footer = self._create_footer()
main_layout.addWidget(self.header)
main_layout.addWidget(self.account_list_container)
main_layout.addWidget(self.scroll_area, 1) # Фактор растяжения
main_layout.addWidget(self.footer)
# --- Анимация списка аккаунтов ---
self.account_list_container.setVisible(False)
self.account_list_animation = QPropertyAnimation(self.account_list_container, b"maximumHeight")
self.account_list_animation.setDuration(300)
self.account_list_animation.setEasingCurve(QEasingCurve.InOutQuart)
# --- Состояние анимации ---
self.is_closing_animation = False
self.account_list_animation.finished.connect(self._on_animation_finished)
self.update_styles()
theme_manager.theme_changed.connect(self.update_styles)
def _create_header(self):
"""Создает заголовок меню."""
header_widget = QWidget()
header_layout = QVBoxLayout(header_widget)
header_layout.setContentsMargins(15, 50, 15, 10)
header_layout.setSpacing(10)
# Верхняя часть: Аватар и кнопка темы
top_row_layout = QHBoxLayout()
avatar_button = QPushButton("👤")
avatar_button.setObjectName("AvatarButton")
avatar_button.setFixedSize(60, 60)
self.theme_toggle_button = QPushButton("☀️")
self.theme_toggle_button.setObjectName("ThemeToggleButton")
self.theme_toggle_button.setCursor(Qt.PointingHandCursor)
self.theme_toggle_button.clicked.connect(theme_manager.toggle_theme)
top_row_layout.addWidget(avatar_button)
top_row_layout.addStretch()
top_row_layout.addWidget(self.theme_toggle_button)
# Нижняя часть: Имя пользователя и кнопка раскрытия
self.account_toggle_button = QPushButton()
self.account_toggle_button.setObjectName("AccountToggleButton")
self.account_toggle_button.setCursor(Qt.PointingHandCursor)
self.account_toggle_button.clicked.connect(self.toggle_account_list)
bottom_row_layout = QHBoxLayout(self.account_toggle_button)
user_info_layout = QVBoxLayout()
user_info_layout.setSpacing(0)
user_info_layout.addWidget(QLabel("Your Name"))
user_info_layout.addWidget(QLabel("@yourusername"))
self.expand_icon = QLabel("")
bottom_row_layout.addLayout(user_info_layout)
bottom_row_layout.addStretch()
bottom_row_layout.addWidget(self.expand_icon)
header_layout.addLayout(top_row_layout)
header_layout.addWidget(self.account_toggle_button)
return header_widget
def _create_account_list(self):
"""Создает выпадающий список аккаунтов."""
container = QWidget()
container.setObjectName("AccountListContainer")
layout = QVBoxLayout(container)
layout.setContentsMargins(15, 10, 15, 10)
layout.setSpacing(15)
# Пример аккаунтов
accounts = [
("Your Name", "@yourusername", True),
("Second Account", "@second", False)
]
for name, username, is_current in accounts:
# Здесь можно создать более сложный виджет для каждого аккаунта
label = QLabel(f"{name} ({username}) {'' if is_current else ''}")
layout.addWidget(label)
return container
def _create_scroll_area(self):
"""Создает прокручиваемую область с пунктами меню."""
scroll_area = QScrollArea()
scroll_area.setWidgetResizable(True)
scroll_area.setFrameShape(QFrame.NoFrame)
scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scroll_area.setObjectName("ScrollArea")
content_widget = QWidget()
content_layout = QVBoxLayout(content_widget)
content_layout.setContentsMargins(15, 10, 15, 10)
content_layout.setSpacing(5)
# Секция 1
content_layout.addWidget(SideMenuButton("👥", "People You May Like"))
content_layout.addWidget(SideMenuButton("", "Fun Fest"))
content_layout.addWidget(SideMenuButton("💡", "Creator Center"))
content_layout.addSpacing(10)
content_layout.addWidget(self._create_divider())
content_layout.addSpacing(10)
# Секция 2
content_layout.addWidget(self._create_category_label("CATEGORY"))
content_layout.addWidget(SideMenuButton("📄", "Drafts"))
content_layout.addWidget(SideMenuButton("💬", "My Comments"))
content_layout.addStretch() # Заполняет пространство внизу
scroll_area.setWidget(content_widget)
return scroll_area
def _create_footer(self):
"""Создает футер меню."""
footer_widget = QWidget()
footer_widget.setObjectName("SideMenuFooter")
layout = QHBoxLayout(footer_widget)
layout.setContentsMargins(15, 10, 15, 20)
layout.addWidget(SideMenuFooterButton("📱", "Scan"))
layout.addWidget(SideMenuFooterButton("", "Help"))
layout.addWidget(SideMenuFooterButton("⚙️", "Settings"))
return footer_widget
def _create_divider(self):
divider = QFrame()
divider.setFrameShape(QFrame.HLine)
divider.setObjectName("Divider")
return divider
def _create_category_label(self, text):
label = QLabel(text)
label.setObjectName("CategoryLabel")
return label
def _on_animation_finished(self):
"""Срабатывает после завершения анимации."""
if self.is_closing_animation:
self.account_list_container.setVisible(False)
def toggle_account_list(self):
"""Анимирует показ/скрытие списка аккаунтов."""
self.account_list_animation.stop()
if self.account_list_container.isVisible():
# --- Закрытие ---
self.is_closing_animation = True
self.expand_icon.setText("")
end_height = 0
else:
# --- Открытие ---
self.is_closing_animation = False
self.expand_icon.setText("")
self.account_list_container.setVisible(True)
end_height = self.account_list_container.sizeHint().height()
self.account_list_animation.setStartValue(self.account_list_container.height())
self.account_list_animation.setEndValue(end_height)
self.account_list_animation.start()
def update_styles(self):
"""Обновляет стили в зависимости от темы."""
is_dark = theme_manager.is_dark()
self.theme_toggle_button.setText("🌙" if is_dark else "☀️")
self.setStyleSheet(self.get_stylesheet())
def get_stylesheet(self):
is_dark = theme_manager.is_dark()
bg_color = "#1c1c1e" if is_dark else "#ffffff"
text_color = "#f2f2f7" if is_dark else "#000000"
secondary_text_color = "#8e8e93" if is_dark else "#888888"
divider_color = "#3c3c3c" if is_dark else "#e7e7e7"
button_hover_bg = "#2c2c2e" if is_dark else "#f0f0f0"
return f"""
#SideMenuView {{
background-color: {bg_color};
}}
QPushButton {{
border: none;
background: transparent;
text-align: left;
color: {text_color};
}}
/* --- Header --- */
#AvatarButton {{
font-size: 40px;
border-radius: 30px;
background-color: {divider_color};
}}
#ThemeToggleButton {{
font-size: 24px;
}}
#AccountToggleButton {{
padding: 8px;
border-radius: 8px;
}}
#AccountToggleButton:hover {{
background-color: {button_hover_bg};
}}
#AccountToggleButton QLabel {{
color: {text_color};
}}
#AccountToggleButton > QLabel:first-child {{ /* Имя */
font-weight: bold;
}}
#AccountToggleButton > QLabel:last-child {{ /* @username */
color: {secondary_text_color};
}}
/* --- Account List --- */
#AccountListContainer {{
background-color: transparent;
color: {text_color};
}}
/* --- Menu Buttons --- */
#SideMenuButton, #SideMenuFooterButton {{
border-radius: 8px;
}}
#SideMenuButton:hover, #SideMenuFooterButton:hover {{
background-color: {button_hover_bg};
}}
#SideMenuButtonIcon, #SideMenuFooterIcon {{
font-size: 18px;
color: {text_color};
}}
#SideMenuButtonText, #SideMenuFooterText {{
font-size: 14px;
color: {text_color};
}}
#SideMenuFooterText {{
font-size: 11px;
}}
/* --- Other --- */
#Divider {{
background-color: {divider_color};
border: none;
height: 1px;
}}
#CategoryLabel {{
color: {secondary_text_color};
font-size: 12px;
font-weight: bold;
padding: 5px 10px;
}}
#ScrollArea {{
border: none;
}}
"""