From d72239b3abc1990cea7b50cdd4717365ed7a50ad Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 29 Sep 2025 01:10:14 +0300 Subject: [PATCH] add notification --- app/ui/views/yobble_home_view.py | 121 +++++++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 7 deletions(-) diff --git a/app/ui/views/yobble_home_view.py b/app/ui/views/yobble_home_view.py index 63e633c..cb0a9fd 100644 --- a/app/ui/views/yobble_home_view.py +++ b/app/ui/views/yobble_home_view.py @@ -64,6 +64,7 @@ class YobbleHomeView(QWidget): # --- Боковое меню и оверлей --- self.setup_side_menu() + self._setup_notification_widget() self.update_styles() theme_manager.theme_changed.connect(self.update_styles) @@ -107,6 +108,81 @@ class YobbleHomeView(QWidget): if self.is_menu_closing: self.overlay.hide() + def _setup_notification_widget(self): + """Настраивает виджет для всплывающих уведомлений.""" + self.notification_widget = QFrame(self) + self.notification_widget.setObjectName("NotificationWidget") + + # Тень + shadow = QGraphicsDropShadowEffect(self) + shadow.setBlurRadius(20) + shadow.setColor(QColor(0, 0, 0, 80)) + shadow.setOffset(0, 3) + self.notification_widget.setGraphicsEffect(shadow) + self.notification_widget.hide() + + layout = QHBoxLayout(self.notification_widget) + layout.setContentsMargins(15, 10, 15, 10) + self.notification_label = QLabel() + self.notification_label.setObjectName("NotificationLabel") + layout.addWidget(self.notification_label) + + # Эффект прозрачности для анимации + self.notification_opacity_effect = QGraphicsOpacityEffect(self.notification_widget) + self.notification_widget.setGraphicsEffect(self.notification_opacity_effect) + + self.notification_animation = QPropertyAnimation(self.notification_opacity_effect, b"opacity") + self.notification_animation.setDuration(300) # мс на появление/исчезание + + self.notification_timer = QTimer(self) + self.notification_timer.setSingleShot(True) + self.notification_timer.timeout.connect(self.hide_notification) + + def show_notification(self, message, is_error=True, duration=3000): + """Показывает всплывающее уведомление.""" + self.notification_label.setText(message) + + self.notification_widget.setProperty("is_error", is_error) + + self.notification_widget.style().unpolish(self.notification_widget) + self.notification_widget.style().polish(self.notification_widget) + + # Позиционирование + self.notification_widget.adjustSize() + x = (self.width() - self.notification_widget.width()) / 2 + y = 30 # Отступ сверху + self.notification_widget.move(int(x), y) + + self.notification_widget.show() + self.notification_widget.raise_() # Поднять поверх всех + + # Анимация появления + self.notification_animation.stop() + self.notification_animation.setStartValue(0.0) + self.notification_animation.setEndValue(1.0) + self.notification_animation.start() + + # Таймер на скрытие + self.notification_timer.start(duration) + + def hide_notification(self): + """Плавно скрывает уведомление.""" + self.notification_animation.stop() + self.notification_animation.setStartValue(self.notification_opacity_effect.opacity()) + self.notification_animation.setEndValue(0.0) + self.notification_animation.start() + + # Прячем виджет только после завершения анимации + def on_finished(): + self.notification_widget.hide() + # Отключаем, чтобы не вызывался многократно + try: + self.notification_animation.finished.disconnect(on_finished) + except (TypeError, RuntimeError): + pass # Уже отключен + + self.notification_animation.finished.connect(on_finished) + def toggle_side_menu(self): """Показывает или скрывает боковое меню с анимацией.""" # Останавливаем текущие анимации, чтобы избежать конфликтов @@ -143,6 +219,11 @@ class YobbleHomeView(QWidget): self.side_menu.move(-self.side_menu.width(), 0) self.side_menu.setFixedHeight(self.height()) + if hasattr(self, 'notification_widget') and self.notification_widget.isVisible(): + self.notification_widget.adjustSize() + x = (self.width() - self.notification_widget.width()) / 2 + self.notification_widget.move(int(x), 30) + def update_styles(self): """Обновляет стили компонента при смене темы.""" self.setStyleSheet(self.get_stylesheet()) @@ -182,6 +263,16 @@ class YobbleHomeView(QWidget): top_bar_layout.addWidget(self.notification_button) self.notification_button.clicked.connect(self.handle_notification_click) + # --- Временные кнопки для теста --- + # self.test_ok_button = QPushButton("Test OK") + # self.test_ok_button.clicked.connect(lambda: self.show_notification("Операция прошла успешно", is_error=False)) + # top_bar_layout.addWidget(self.test_ok_button) + + # self.test_err_button = QPushButton("Test Error") + # self.test_err_button.clicked.connect(lambda: self.show_notification("Произошла ошибка при обновлении", is_error=True)) + # top_bar_layout.addWidget(self.test_err_button) + # --- Конец временного кода --- + return top_bar_widget def create_bottom_bar(self): @@ -377,13 +468,8 @@ class YobbleHomeView(QWidget): self.title_label.setText(titles[index]) def show_error_message(self, message): - """Показывает диалоговое окно с сообщением об ошибке.""" - show_themed_messagebox( - self, - QMessageBox.Warning, - localizer.translate("Ошибка доступа"), - message - ) + """Показывает всплывающее уведомление об ошибке.""" + self.show_notification(message, is_error=True) def update_tab_selection(self, selected_index): if not hasattr(self, 'bottom_bar'): @@ -470,6 +556,27 @@ class YobbleHomeView(QWidget): background-color: {overlay_color}; }} + /* --- Уведомления --- */ + #NotificationWidget {{ + border-radius: 12px; + background-color: {"#333" if is_dark else "#FFF"}; + border: 1px solid {"#444" if is_dark else "#E0E0E0"}; + }} + #NotificationWidget[is_error="true"] {{ + background-color: {"#D32F2F" if is_dark else "#f44336"}; + border: 1px solid {"#C62828" if is_dark else "#E53935"}; + }} + #NotificationWidget[is_error="false"] {{ + background-color: {"#388E3C" if is_dark else "#4CAF50"}; + border: 1px solid {"#2E7D32" if is_dark else "#43A047"}; + }} + #NotificationLabel {{ + color: white; + font-size: 14px; + background: transparent; + }} + /* --- Конец Уведомлений --- */ + /* Глобально для кнопок */ QPushButton {{ background: transparent;