# 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") layout.addWidget(icon_label) layout.addWidget(text_label) layout.addStretch() 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) 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; }} """