Skip to content
Open
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
20 changes: 15 additions & 5 deletions src/ui/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@ def __init__(self, config_manager=None):
self.input_manager = None

# Настройка прозрачного и безрамочного окна
self.setWindowFlags(
Qt.WindowStaysOnTopHint |
Qt.FramelessWindowHint |
Qt.Tool
)
flags = Qt.FramelessWindowHint | Qt.Tool
if not self.config or self.config.get("always_on_top"):
flags |= Qt.WindowStaysOnTopHint
self.setWindowFlags(flags)
self.setAttribute(Qt.WA_TranslucentBackground)
self.setWindowOpacity(self.config.get("opacity") / 100.0 if self.config else 1.0)

Expand Down Expand Up @@ -88,6 +87,17 @@ def moveEvent(self, event):
def get_cached_pos(self):
return self._cached_pos

def set_always_on_top(self, enabled):
"""Включает или выключает отображение поверх всех окон."""
flags = self.windowFlags()
if enabled:
flags |= Qt.WindowStaysOnTopHint
else:
flags &= ~Qt.WindowStaysOnTopHint
self.setWindowFlags(flags)
if self.isVisible():
self.show()

def set_opacity(self, value):
"""Устанавливает прозрачность окна (0-100)"""
self.setWindowOpacity(value / 100.0)
Expand Down
8 changes: 7 additions & 1 deletion src/ui/settings_dialog.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from PySide6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QSlider, QComboBox, QPushButton, QSpinBox
from PySide6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QSlider, QComboBox, QPushButton, QSpinBox, QCheckBox
from PySide6.QtCore import Qt
from src.utils.bonding_utils import CAT_SKINS

Expand All @@ -16,6 +16,11 @@ def __init__(self, config, parent=None):
self.name_edit = QLineEdit(self.config.get("username"))
layout.addWidget(self.name_edit)

# Поверх всех окон
self.always_on_top_cb = QCheckBox("Поверх всех окон")
self.always_on_top_cb.setChecked(self.config.get("always_on_top"))
layout.addWidget(self.always_on_top_cb)

# Громкость
layout.addWidget(QLabel("Громкость звука:"))
self.volume_slider = QSlider(Qt.Horizontal)
Expand Down Expand Up @@ -74,6 +79,7 @@ def __init__(self, config, parent=None):

def save_settings(self):
self.config.set("username", self.name_edit.text())
self.config.set("always_on_top", self.always_on_top_cb.isChecked())
self.config.set("volume", self.volume_slider.value())
self.config.set("opacity", self.opacity_slider.value())
self.config.set("stretch_interval", self.stretch_spin.value())
Expand Down
3 changes: 2 additions & 1 deletion src/ui/tray_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,9 @@ def start_break_timer(self, checked=False):
def show_settings(self, checked=False):
dialog = SettingsDialog(self.window.config, self.window)
if dialog.exec():
# Обновляем скин и прозрачность в реальном времени
# Обновляем скин, всегда поверх и прозрачность в реальном времени
self.window.animation_manager.set_skin(self.window.config.get("skin"))
self.window.set_always_on_top(self.window.config.get("always_on_top"))
self.window.set_opacity(self.window.config.get("opacity"))
# Обновляем тексты в меню Pomodoro
self.update_pomodoro_menu_texts()
Expand Down
24 changes: 24 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,21 @@
import os
import json
import time
from PySide6.QtCore import Qt
from src.ui.main_window import PetWindow
from src.utils.config_manager import ConfigManager
from src.utils.data_store import DataStore
from src.core.timer_system import TimerSystem
from src.core.input_manager import InputManager

class TestUtils(unittest.TestCase):
@classmethod
def setUpClass(cls):
from PySide6.QtWidgets import QApplication
# Initialize offscreen app for testing PetWindow
os.environ["QT_QPA_PLATFORM"] = "offscreen"
cls.app = QApplication.instance() or QApplication(sys.argv)

def setUp(self):
self.config_path = "test_settings.json"
self.db_path = "test_activity.db"
Expand Down Expand Up @@ -86,6 +95,21 @@ def test_timer_system_pomodoro(self):
self.assertEqual(ts.pomodoro_state, "idle")
self.assertEqual(ts.pomodoro_remaining, 0)

def test_pet_window_always_on_top(self):
config = ConfigManager(self.config_path)
# Test initial state with always_on_top = True (default)
config.set("always_on_top", True)
window = PetWindow(config)
self.assertTrue(bool(window.windowFlags() & Qt.WindowStaysOnTopHint))

# Test disabling always_on_top dynamically
window.set_always_on_top(False)
self.assertFalse(bool(window.windowFlags() & Qt.WindowStaysOnTopHint))

# Test enabling always_on_top dynamically
window.set_always_on_top(True)
self.assertTrue(bool(window.windowFlags() & Qt.WindowStaysOnTopHint))

def test_input_manager_petting_logic(self):
# Мокаем PetWindow, AnimationManager и SoundManager
mock_window = MagicMock()
Expand Down
Binary file modified verification/screenshots/stats_history.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.