diff --git a/src/core/input_manager.py b/src/core/input_manager.py index 333290e..6ac5cc1 100644 --- a/src/core/input_manager.py +++ b/src/core/input_manager.py @@ -170,8 +170,7 @@ def add_points(self, points): self.flush_points() # Обязательно сбрасываем перед уведомлением self.window.show_message(f"Уровень дружбы повышен: {new_level} ❤️") self.window.sound_manager.play_sound("happy") - if self.db: - self.db.log_event("level_up", f"Достигнут уровень {new_level}") + self.db.log_event("level_up", f"Уровень повышен до {new_level}") self.check_for_achievements() def flush_points(self): @@ -251,6 +250,7 @@ def check_for_achievements(self): self.db.log_event("achievement", f"Открыто достижение: {ach['title']}") self.window.show_message(f"Достижение: {ach['icon']} {ach['title']}", duration=5000) self.window.sound_manager.play_sound("happy") + self.db.log_event("achievement", f"Разблокировано: {ach['title']}") def _reset_idle_state(self): """Возвращает котика в idle, если он спал или думал.""" @@ -321,8 +321,10 @@ def handle_mouse(self, x, y): # Проверка "поглаживания" pet_pos = self.window.get_cached_pos() - dx_pet = x - (pet_pos.x() + 50) - dy_pet = y - (pet_pos.y() + 50) + center_x = pet_pos.x() + self.window.width() // 2 + center_y = pet_pos.y() + self.window.height() // 2 + dx_pet = x - center_x + dy_pet = y - center_y dist_sq_pet = dx_pet * dx_pet + dy_pet * dy_pet # Оптимизация: сравнение квадрата расстояния (порог 60px -> 3600) diff --git a/src/ui/stats_dialog.py b/src/ui/stats_dialog.py index 5510591..871ca1e 100644 --- a/src/ui/stats_dialog.py +++ b/src/ui/stats_dialog.py @@ -1,5 +1,6 @@ from PySide6.QtWidgets import (QDialog, QVBoxLayout, QLabel, QProgressBar, - QPushButton, QHBoxLayout, QScrollArea, QWidget, QTabWidget, QListWidget, QListWidgetItem) + QPushButton, QHBoxLayout, QScrollArea, QWidget, + QTabWidget, QListWidget, QListWidgetItem) from PySide6.QtCore import Qt from src.utils.bonding_utils import get_level_info, ACHIEVEMENTS @@ -9,8 +10,30 @@ def __init__(self, db, parent=None): self.db = db self.setWindowTitle("Статистика Котика") self.setFixedWidth(350) + self.setFixedHeight(500) - layout = QVBoxLayout(self) + main_layout = QVBoxLayout(self) + + self.tabs = QTabWidget() + main_layout.addWidget(self.tabs) + + # Вкладка Прогресса + self.progress_tab = QWidget() + self.setup_progress_tab() + self.tabs.addTab(self.progress_tab, "Прогресс") + + # Вкладка Истории + self.history_tab = QWidget() + self.setup_history_tab() + self.tabs.addTab(self.history_tab, "История") + + # Кнопка закрытия + close_btn = QPushButton("Закрыть") + close_btn.clicked.connect(self.accept) + main_layout.addWidget(close_btn) + + def setup_progress_tab(self): + layout = QVBoxLayout(self.progress_tab) self.tabs = QTabWidget() layout.addWidget(self.tabs) @@ -47,13 +70,10 @@ def setup_progress_tab(self): points_label = QLabel(f"Всего: {points} ❤️") max_kps = self.db.get_stat("max_kps") - kps_label = QLabel(f"Макс: {max_kps} кл/сек ⚡") - kps_label.setStyleSheet("color: #555;") - - stats_row.addWidget(points_label) - stats_row.addStretch() - stats_row.addWidget(kps_label) - layout.addLayout(stats_row) + kps_label = QLabel(f"Рекорд скорости: {max_kps} кл/сек ⚡") + kps_label.setAlignment(Qt.AlignCenter) + kps_label.setStyleSheet("color: #555; font-size: 11px; margin-bottom: 5px;") + layout.addWidget(kps_label) # Прогресс бар if points_for_next_level > 0: @@ -67,8 +87,6 @@ def setup_progress_tab(self): layout.addWidget(QLabel("Максимальный уровень достигнут! 🎉")) layout.addSpacing(10) - - # Раздел достижений layout.addWidget(QLabel("Достижения:")) scroll = QScrollArea() @@ -124,26 +142,35 @@ def setup_progress_tab(self): scroll_layout.addWidget(ach_widget) scroll.setWidget(scroll_content) - scroll.setFixedHeight(200) layout.addWidget(scroll) def setup_history_tab(self): layout = QVBoxLayout(self.history_tab) - history_list = QListWidget() - activities = self.db.get_recent_activity(20) + layout.addWidget(QLabel("Последние события:")) + + self.history_list = QListWidget() + + events = self.db.get_recent_activity(30) + for event in events: + # event = (id, timestamp, event_type, description) + _, timestamp, event_type, desc = event + + # Красивое форматирование времени (убираем секунды) + time_str = timestamp.split(' ')[1][:5] if ' ' in timestamp else timestamp - for activity in activities: - # activity format: (id, timestamp, event_type, description) - _, ts, event, desc = activity - # Убираем секунды для компактности - time_str = ts.split(" ")[1][:5] if " " in ts else ts + icon = "ℹ️" + if event_type == "level_up": icon = "🆙" + elif event_type == "achievement": icon = "🏆" + elif event_type == "feeding": icon = "🐟" + elif event_type == "pomodoro_start": icon = "⏱" + elif event_type == "app_start": icon = "🚀" - item = QListWidgetItem(f"[{time_str}] {desc}") - item.setToolTip(f"{ts}\nТип: {event}") - history_list.addItem(item) + item_text = f"[{time_str}] {icon} {desc if desc else event_type}" + item = QListWidgetItem(item_text) + self.history_list.addItem(item) - if not activities: - history_list.addItem("История пока пуста...") + layout.addWidget(self.history_list) - layout.addWidget(history_list) + if not events: + layout.addWidget(QLabel("История пока пуста...")) diff --git a/src/ui/tray_menu.py b/src/ui/tray_menu.py index 80ef58a..55a1d1a 100644 --- a/src/ui/tray_menu.py +++ b/src/ui/tray_menu.py @@ -126,7 +126,7 @@ def start_break_timer(self, checked=False): self.window.timer_system.start_pomodoro("break") self.window.show_message("Отдыхаем! ☕") if self.window.input_manager and self.window.input_manager.db: - self.window.input_manager.db.log_event("pomodoro_break", "Начат перерыв") + self.window.input_manager.db.log_event("pomodoro_start", "Начата сессия отдыха") def show_settings(self, checked=False): dialog = SettingsDialog(self.window.config, self.window) @@ -152,7 +152,7 @@ def feed_pet(self, checked=False): self.window.show_message("Мням! +5 ❤️") self.window.input_manager.pending_stats["total_feedings"] += 1 if self.window.input_manager.db: - self.window.input_manager.db.log_event("feed", "Котик покормлен") + self.window.input_manager.db.log_event("feeding", "Котик покормлен") self.window.input_manager.check_for_achievements() def toggle_laser(self, checked): diff --git a/tests/verify_ui_script.py b/tests/verify_ui_script.py new file mode 100644 index 0000000..7fd12df --- /dev/null +++ b/tests/verify_ui_script.py @@ -0,0 +1,66 @@ +import sys +import os + +# Add src to path +sys.path.append(os.getcwd()) + +from PySide6.QtWidgets import QApplication +from src.ui.stats_dialog import StatsDialog +from src.utils.data_store import DataStore +from src.utils.config_manager import ConfigManager + +def verify_ui(): + # Use offscreen platform for headless environments + os.environ["QT_QPA_PLATFORM"] = "offscreen" + + app = QApplication(sys.argv) + + # Setup temporary DB + db_path = "test_verify.db" + if os.path.exists(db_path): + os.remove(db_path) + + db = DataStore(db_path) + + # Populate with some data + db.add_affection_points(150) # Level 1 + db.set_stat("max_kps", 10) + db.set_stat("total_clicks", 500) + db.set_stat("work_seconds", 300) + db.add_achievement("first_friend") + + # Log some events + db.log_event("app_start", "Приложение замурчало") + db.log_event("feeding", "Покормили рыбкой") + db.log_event("level_up", "Уровень повышен до 1") + db.log_event("achievement", "Разблокировано: Первый друг") + db.log_event("pomodoro_start", "Начата сессия работы") + + # Mock window parent for StatsDialog if needed, but it should work with None + dialog = StatsDialog(db) + dialog.show() + + # Ensure UI is processed + app.processEvents() + + # Take screenshots of both tabs + os.makedirs("verification/screenshots", exist_ok=True) + + # Progress tab (default) + dialog.tabs.setCurrentIndex(0) + app.processEvents() + dialog.grab().save("verification/screenshots/stats_progress.png") + + # History tab + dialog.tabs.setCurrentIndex(1) + app.processEvents() + dialog.grab().save("verification/screenshots/stats_history.png") + + print("Screenshots saved to verification/screenshots/") + + db.close() + if os.path.exists(db_path): + os.remove(db_path) + +if __name__ == "__main__": + verify_ui()