Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/core/input_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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, если он спал или думал."""
Expand Down Expand Up @@ -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)
Expand Down
77 changes: 52 additions & 25 deletions src/ui/stats_dialog.py
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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)
Expand Down Expand Up @@ -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:
Expand All @@ -67,8 +87,6 @@ def setup_progress_tab(self):
layout.addWidget(QLabel("Максимальный уровень достигнут! 🎉"))

layout.addSpacing(10)

# Раздел достижений
layout.addWidget(QLabel("<b>Достижения:</b>"))

scroll = QScrollArea()
Expand Down Expand Up @@ -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("<b>Последние события:</b>"))

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("История пока пуста..."))
4 changes: 2 additions & 2 deletions src/ui/tray_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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):
Expand Down
66 changes: 66 additions & 0 deletions tests/verify_ui_script.py
Original file line number Diff line number Diff line change
@@ -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()