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()