88 lines
89 KiB
XML
88 lines
89 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
||
<project version="4">
|
||
<component name="CopilotDiffPersistence">
|
||
<option name="pendingDiffs">
|
||
<map>
|
||
<entry key="$PROJECT_DIR$/.gitignore">
|
||
<value>
|
||
<PendingDiffInfo>
|
||
<option name="filePath" value="$PROJECT_DIR$/.gitignore" />
|
||
<option name="updatedContent" value="# Build directories build/ cmake-build-*/ *.build/ # CMake files CMakeCache.txt CMakeFiles/ cmake_install.cmake Makefile *.cmake !CMakeLists.txt # Generated files *.o *.so *.a *.dylib *.dll *.exe moc_*.cpp *.moc ui_*.h qrc_*.cpp # IDE files .idea/ .vscode/ *.user *.pro.user* *.tmp # Qt specific *.qm .qmake.stash # System files .DS_Store Thumbs.db *~ # Temporary files *.tmp *.temp *.log # Autogenerated *_autogen/" />
|
||
</PendingDiffInfo>
|
||
</value>
|
||
</entry>
|
||
<entry key="$PROJECT_DIR$/CMakeLists.txt">
|
||
<value>
|
||
<PendingDiffInfo>
|
||
<option name="filePath" value="$PROJECT_DIR$/CMakeLists.txt" />
|
||
<option name="originalContent" value="cmake_minimum_required(VERSION 3.20) project(PomodoroTimer VERSION 0.1.1 LANGUAGES CXX) # Set C++ standard set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # Find Qt6 find_package(Qt6 REQUIRED COMPONENTS Core Widgets) qt6_standard_project_setup() # Include directories include_directories(src/core) include_directories(src/ui) include_directories(src/system) include_directories(src/utils) # Define source files with new structure set(CORE_HEADERS src/core/TimerState.h src/core/TimerController.h src/core/PomodoroConfig.h ) set(UI_HEADERS src/ui/PomodoroTimer.h src/ui/CircularProgressBar.h src/ui/SettingsDialog.h src/ui/StatisticsDialog.h ) set(SYSTEM_HEADERS src/system/SystemTrayManager.h src/system/KeyboardShortcuts.h src/system/NotificationManager.h ) set(CORE_SOURCES src/core/TimerState.cpp src/core/TimerController.cpp src/core/PomodoroConfig.cpp ) set(UI_SOURCES src/ui/PomodoroTimer.cpp src/ui/CircularProgressBar.cpp src/ui/SettingsDialog.cpp src/ui/StatisticsDialog.cpp ) set(SYSTEM_SOURCES src/system/SystemTrayManager.cpp src/system/KeyboardShortcuts.cpp src/system/NotificationManager.cpp ) set(ALL_HEADERS ${CORE_HEADERS} ${UI_HEADERS} ${SYSTEM_HEADERS}) set(ALL_SOURCES main.cpp ${CORE_SOURCES} ${UI_SOURCES} ${SYSTEM_SOURCES}) # Create executable qt6_add_executable(${PROJECT_NAME} ${ALL_SOURCES} ${ALL_HEADERS}) # Link Qt libraries target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Core Qt6::Widgets ) # Set target properties set_target_properties(${PROJECT_NAME} PROPERTIES AUTOMOC ON AUTORCC ON AUTOUIC ON OUTPUT_NAME "PomodoroTimer" ) # Platform-specific configurations if(WIN32) set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE TRUE ) elseif(APPLE) set_target_properties(${PROJECT_NAME} PROPERTIES MACOSX_BUNDLE TRUE MACOSX_BUNDLE_BUNDLE_NAME "Pomodoro Timer" MACOSX_BUNDLE_GUI_IDENTIFIER "com.pomodoroapp.timer" MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}" MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}" MACOSX_BUNDLE_INFO_STRING "Pomodoro Focus Timer" ) endif() # Compiler warnings and optimizations if(MSVC) target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX- $<$<CONFIG:Release>:/O2> ) else() target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic $<$<CONFIG:Release>:-O3> $<$<CONFIG:Debug>:-g -O0> ) endif() # --- Installation Rules --- # Configure desktop file for Linux if(UNIX AND NOT APPLE) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/pomodoro-timer.desktop.in" "${CMAKE_CURRENT_BINARY_DIR}/pomodoro-timer.desktop" @ONLY ) install( FILES "${CMAKE_CURRENT_BINARY_DIR}/pomodoro-timer.desktop" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications" ) endif() # Install rules (optional) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "Install prefix" FORCE) endif() install(TARGETS ${PROJECT_NAME} BUNDLE DESTINATION . RUNTIME DESTINATION bin ) " />
|
||
<option name="updatedContent" value="cmake_minimum_required(VERSION 3.20) project(PomodoroTimer VERSION 0.1.1 LANGUAGES CXX) # Set C++ standard set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # Find Qt6 find_package(Qt6 REQUIRED COMPONENTS Core Widgets) qt6_standard_project_setup() # Include directories include_directories(src/core) include_directories(src/ui) include_directories(src/system) include_directories(src/utils) # Define source files with new structure set(CORE_HEADERS src/core/TimerState.h src/core/TimerController.h src/core/PomodoroConfig.h ) set(UI_HEADERS src/ui/PomodoroTimer.h src/ui/CircularProgressBar.h src/ui/SettingsDialog.h src/ui/StatisticsDialog.h ) set(SYSTEM_HEADERS src/system/SystemTrayManager.h src/system/KeyboardShortcuts.h src/system/NotificationManager.h ) set(CORE_SOURCES src/core/TimerState.cpp src/core/TimerController.cpp src/core/PomodoroConfig.cpp ) set(UI_SOURCES src/ui/PomodoroTimer.cpp src/ui/CircularProgressBar.cpp src/ui/SettingsDialog.cpp src/ui/StatisticsDialog.cpp ) set(SYSTEM_SOURCES src/system/SystemTrayManager.cpp src/system/KeyboardShortcuts.cpp src/system/NotificationManager.cpp ) set(ALL_HEADERS ${CORE_HEADERS} ${UI_HEADERS} ${SYSTEM_HEADERS}) set(ALL_SOURCES main.cpp ${CORE_SOURCES} ${UI_SOURCES} ${SYSTEM_SOURCES}) # Create executable qt6_add_executable(${PROJECT_NAME} ${ALL_SOURCES} ${ALL_HEADERS}) # Link Qt libraries target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Core Qt6::Widgets ) # Set target properties set_target_properties(${PROJECT_NAME} PROPERTIES AUTOMOC ON AUTORCC ON AUTOUIC ON OUTPUT_NAME "PomodoroTimer" ) # Platform-specific configurations if(WIN32) set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE TRUE ) elseif(APPLE) set_target_properties(${PROJECT_NAME} PROPERTIES MACOSX_BUNDLE TRUE MACOSX_BUNDLE_BUNDLE_NAME "Pomodoro Timer" MACOSX_BUNDLE_GUI_IDENTIFIER "com.pomodoroapp.timer" MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}" MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}" MACOSX_BUNDLE_INFO_STRING "Pomodoro Focus Timer" ) endif() # Compiler warnings and optimizations if(MSVC) target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX- $<$<CONFIG:Release>:/O2> ) else() target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic $<$<CONFIG:Release>:-O3> $<$<CONFIG:Debug>:-g -O0> ) endif() # --- Installation Rules --- # Configure desktop file for Linux if(UNIX AND NOT APPLE) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/resources/pomodoro-timer.desktop.in" "${CMAKE_CURRENT_BINARY_DIR}/pomodoro-timer.desktop" @ONLY ) install( FILES "${CMAKE_CURRENT_BINARY_DIR}/pomodoro-timer.desktop" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications" ) endif() # Install rules (optional) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "Install prefix" FORCE) endif() install(TARGETS ${PROJECT_NAME} BUNDLE DESTINATION . RUNTIME DESTINATION bin )" />
|
||
</PendingDiffInfo>
|
||
</value>
|
||
</entry>
|
||
<entry key="$PROJECT_DIR$/docs/PROJECT_STRUCTURE.md">
|
||
<value>
|
||
<PendingDiffInfo>
|
||
<option name="filePath" value="$PROJECT_DIR$/docs/PROJECT_STRUCTURE.md" />
|
||
<option name="updatedContent" value="# Pomodoro Timer - Структура проекта ## Обзор Этот документ описывает организацию файловой системы проекта Pomodoro Timer для обеспечения лучшей читаемости, сопровождения и масштабируемости кода. ## Структура папок ### `/src/` - Исходный код Основная папка с исходным кодом, организованная по функциональным модулям: #### `/src/core/` - Основная логика Содержит базовую бизнес-логику приложения: - `TimerState.h/cpp` - Перечисления и утилиты для состояний таймера - `TimerController.h/cpp` - Контроллер управления таймером (если есть) - `PomodoroConfig.h/cpp` - Конфигурация и настройки приложения #### `/src/ui/` - Пользовательский интерфейс Все компоненты графического интерфейса: - `PomodoroTimer.h/cpp` - Главное окно приложения - `CircularProgressBar.h/cpp` - Кастомный виджет круглого прогресс-бара - `SettingsDialog.h/cpp` - Диалог настроек - `StatisticsDialog.h/cpp` - Диалог статистики #### `/src/system/` - Системная интеграция Компоненты для взаимодействия с операционной системой: - `SystemTrayManager.h/cpp` - Управление системным треем - `KeyboardShortcuts.h/cpp` - Глобальные горячие клавиши - `NotificationManager.h/cpp` - Системные уведомления #### `/src/utils/` - Утилиты Вспомогательные классы и функции (пока пуста, готова для будущих утилит) ### `/resources/` - Ресурсы Статические ресурсы приложения: - `logoTimer.png` - Иконка приложения - `pomodoro-timer.desktop.in` - Шаблон desktop-файла для Linux ### `/docs/` - Документация Документация проекта: - `PROJECT_STRUCTURE.md` - Этот файл - (планируется: руководства пользователя, API документации) ### `/tests/` - Тесты Модульные и интеграционные тесты (готова для будущих тестов) ## Принципы организации ### 1. Разделение ответственности - **Core**: Бизнес-логика, не зависящая от UI - **UI**: Только код интерфейса и взаимодействия с пользователем - **System**: Специфичные для ОС функции - **Utils**: Переиспользуемые утилиты ### 2. Минимальные зависимости - Core модули не зависят от UI - UI модули могут использовать Core - System модули изолированы и используются через интерфейсы ### 3. Масштабируемость Структура позволяет легко добавлять новые компоненты без нарушения существующей архитектуры. ## Сборка проекта Обновленный `CMakeLists.txt` автоматически находит все файлы в правильных папках и настраивает include пути. ```bash mkdir build && cd build cmake .. make ``` ## Include директивы Благодаря настроенным include путям в CMake, файлы могут включать друг друга следующим образом: ```cpp // Из UI модулей #include "core/TimerState.h" #include "system/SystemTrayManager.h" // Из Core модулей #include "TimerState.h" // внутри того же модуля // Из System модулей #include "core/TimerState.h" ``` ## Будущие улучшения 1. **Модульность**: Превратить компоненты в отдельные библиотеки 2. **Тестирование**: Добавить unit тесты в папку `/tests/` 3. **Плагины**: Создать систему плагинов в `/src/plugins/` 4. **Локализация**: Добавить файлы переводов в `/resources/translations/` 5. **Конфигурация**: Вынести конфиги в `/config/`" />
|
||
</PendingDiffInfo>
|
||
</value>
|
||
</entry>
|
||
<entry key="$PROJECT_DIR$/main.cpp">
|
||
<value>
|
||
<PendingDiffInfo>
|
||
<option name="filePath" value="$PROJECT_DIR$/main.cpp" />
|
||
<option name="originalContent" value="#include <QApplication> #include <QScreen> #include <QPainter> #include <QPixmap> #include <QRadialGradient> #include <QPen> #include "ui/PomodoroTimer.h" namespace { // Application constants - use QStringLiteral for compile-time optimization const QString APP_NAME = QStringLiteral("Pomodoro Timer"); const QString APP_VERSION = QStringLiteral("0.1.1"); const QString ORGANIZATION = QStringLiteral("PomodoroApp"); // Icon generation constants constexpr double TOMATO_SIZE_RATIO = 0.8; constexpr double STEM_SIZE_RATIO = 0.15; constexpr double TOMATO_FLATTEN_RATIO = 0.9; constexpr int PEN_WIDTH = 1; constexpr int HIGHLIGHT_ALPHA = 100; // Forward declaration for createTomatoIcon QIcon createTomatoIcon(int size = 32); // Use thread-safe singleton pattern instead of global variable class IconCache { public: static IconCache& instance() { static IconCache cache; return cache; } const QIcon& getApplicationIcon() { if (m_cachedAppIcon.isNull()) { initializeIcon(); } return m_cachedAppIcon; } private: QIcon m_cachedAppIcon; void initializeIcon() { constexpr int iconSizes[] = {16, 24, 32, 48, 64}; for (int size : iconSizes) { m_cachedAppIcon.addPixmap(createTomatoIcon(size).pixmap(size, size)); } } }; QIcon createTomatoIcon(int size) { QPixmap pixmap(size, size); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); // Calculate proportions const int tomatoSize = static_cast<int>(size * TOMATO_SIZE_RATIO); const int stemSize = static_cast<int>(size * STEM_SIZE_RATIO); const int margin = (size - tomatoSize) / 2; // Draw tomato body with gradient QRadialGradient tomatoGradient(size/2, size/2 + stemSize, tomatoSize/2); tomatoGradient.setColorAt(0.0, QColor(255, 100, 100)); tomatoGradient.setColorAt(0.7, QColor(220, 50, 50)); tomatoGradient.setColorAt(1.0, QColor(180, 30, 30)); painter.setBrush(QBrush(tomatoGradient)); painter.setPen(QPen(QColor(150, 20, 20), PEN_WIDTH)); const QRect tomatoRect(margin, margin + stemSize, tomatoSize, static_cast<int>(tomatoSize * TOMATO_FLATTEN_RATIO)); painter.drawEllipse(tomatoRect); // Draw stem and leaves painter.setBrush(QBrush(QColor(34, 139, 34))); painter.setPen(QPen(QColor(20, 100, 20), PEN_WIDTH)); // Main stem const QRect stemRect(size/2 - stemSize/3, margin, stemSize/1.5, stemSize); painter.drawRect(stemRect); // Draw leaves using polygons - optimize polygon creation QPolygon leftLeaf, rightLeaf; leftLeaf.reserve(3); rightLeaf.reserve(3); leftLeaf << QPoint(size/2 - stemSize/2, margin + stemSize/3) << QPoint(size/2 - stemSize, margin) << QPoint(size/2 - stemSize/3, margin + stemSize/2); rightLeaf << QPoint(size/2 + stemSize/2, margin + stemSize/3) << QPoint(size/2 + stemSize, margin) << QPoint(size/2 + stemSize/3, margin + stemSize/2); painter.drawPolygon(leftLeaf); painter.drawPolygon(rightLeaf); // Add 3D highlight effect painter.setBrush(QBrush(QColor(255, 150, 150, HIGHLIGHT_ALPHA))); painter.setPen(Qt::NoPen); const QRect highlightRect(margin + tomatoSize/4, margin + stemSize + tomatoSize/4, tomatoSize/3, tomatoSize/4); painter.drawEllipse(highlightRect); return QIcon(pixmap); } void centerWindow(QWidget* window) { if (!window) { qWarning() << "centerWindow: null window pointer"; return; } const QScreen* screen = QApplication::primaryScreen(); if (!screen) { qWarning() << "centerWindow: no primary screen available"; return; } const QRect screenGeometry = screen->availableGeometry(); const int x = (screenGeometry.width() - window->width()) / 2; const int y = (screenGeometry.height() - window->height()) / 2; window->move(x, y); } void setupApplicationProperties(QApplication& app) { app.setApplicationName(APP_NAME); app.setApplicationVersion(APP_VERSION); app.setOrganizationName(ORGANIZATION); app.setWindowIcon(IconCache::instance().getApplicationIcon()); app.setQuitOnLastWindowClosed(false); } } int main(int argc, char *argv[]) { QApplication app(argc, argv); setupApplicationProperties(app); PomodoroTimer timer; timer.show(); centerWindow(&timer); return app.exec(); }" />
|
||
<option name="updatedContent" value="#include <QApplication> #include <QScreen> #include <QPainter> #include <QPixmap> #include <QRadialGradient> #include <QPen> #include "PomodoroTimer.h" namespace { // Application constants - use QStringLiteral for compile-time optimization const QString APP_NAME = QStringLiteral("Pomodoro Timer"); const QString APP_VERSION = QStringLiteral("0.1.1"); const QString ORGANIZATION = QStringLiteral("PomodoroApp"); // Icon generation constants constexpr double TOMATO_SIZE_RATIO = 0.8; constexpr double STEM_SIZE_RATIO = 0.15; constexpr double TOMATO_FLATTEN_RATIO = 0.9; constexpr int PEN_WIDTH = 1; constexpr int HIGHLIGHT_ALPHA = 100; // Forward declaration for createTomatoIcon QIcon createTomatoIcon(int size = 32); // Use thread-safe singleton pattern instead of global variable class IconCache { public: static IconCache& instance() { static IconCache cache; return cache; } const QIcon& getApplicationIcon() { if (m_cachedAppIcon.isNull()) { initializeIcon(); } return m_cachedAppIcon; } private: QIcon m_cachedAppIcon; void initializeIcon() { constexpr int iconSizes[] = {16, 24, 32, 48, 64}; for (int size : iconSizes) { m_cachedAppIcon.addPixmap(createTomatoIcon(size).pixmap(size, size)); } } }; QIcon createTomatoIcon(int size) { QPixmap pixmap(size, size); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); // Calculate proportions const int tomatoSize = static_cast<int>(size * TOMATO_SIZE_RATIO); const int stemSize = static_cast<int>(size * STEM_SIZE_RATIO); const int margin = (size - tomatoSize) / 2; // Draw tomato body with gradient QRadialGradient tomatoGradient(size/2, size/2 + stemSize, tomatoSize/2); tomatoGradient.setColorAt(0.0, QColor(255, 100, 100)); tomatoGradient.setColorAt(0.7, QColor(220, 50, 50)); tomatoGradient.setColorAt(1.0, QColor(180, 30, 30)); painter.setBrush(QBrush(tomatoGradient)); painter.setPen(QPen(QColor(150, 20, 20), PEN_WIDTH)); const QRect tomatoRect(margin, margin + stemSize, tomatoSize, static_cast<int>(tomatoSize * TOMATO_FLATTEN_RATIO)); painter.drawEllipse(tomatoRect); // Draw stem and leaves painter.setBrush(QBrush(QColor(34, 139, 34))); painter.setPen(QPen(QColor(20, 100, 20), PEN_WIDTH)); // Main stem const QRect stemRect(size/2 - stemSize/3, margin, stemSize/1.5, stemSize); painter.drawRect(stemRect); // Draw leaves using polygons - optimize polygon creation QPolygon leftLeaf, rightLeaf; leftLeaf.reserve(3); rightLeaf.reserve(3); leftLeaf << QPoint(size/2 - stemSize/2, margin + stemSize/3) << QPoint(size/2 - stemSize, margin) << QPoint(size/2 - stemSize/3, margin + stemSize/2); rightLeaf << QPoint(size/2 + stemSize/2, margin + stemSize/3) << QPoint(size/2 + stemSize, margin) << QPoint(size/2 + stemSize/3, margin + stemSize/2); painter.drawPolygon(leftLeaf); painter.drawPolygon(rightLeaf); // Add 3D highlight effect painter.setBrush(QBrush(QColor(255, 150, 150, HIGHLIGHT_ALPHA))); painter.setPen(Qt::NoPen); const QRect highlightRect(margin + tomatoSize/4, margin + stemSize + tomatoSize/4, tomatoSize/3, tomatoSize/4); painter.drawEllipse(highlightRect); return QIcon(pixmap); } void centerWindow(QWidget* window) { if (!window) { qWarning() << "centerWindow: null window pointer"; return; } const QScreen* screen = QApplication::primaryScreen(); if (!screen) { qWarning() << "centerWindow: no primary screen available"; return; } const QRect screenGeometry = screen->availableGeometry(); const int x = (screenGeometry.width() - window->width()) / 2; const int y = (screenGeometry.height() - window->height()) / 2; window->move(x, y); } void setupApplicationProperties(QApplication& app) { app.setApplicationName(APP_NAME); app.setApplicationVersion(APP_VERSION); app.setOrganizationName(ORGANIZATION); app.setWindowIcon(IconCache::instance().getApplicationIcon()); app.setQuitOnLastWindowClosed(false); } } int main(int argc, char *argv[]) { QApplication app(argc, argv); setupApplicationProperties(app); PomodoroTimer timer; timer.show(); centerWindow(&timer); return app.exec(); }" />
|
||
</PendingDiffInfo>
|
||
</value>
|
||
</entry>
|
||
<entry key="$PROJECT_DIR$/src/core/TimerController.cpp">
|
||
<value>
|
||
<PendingDiffInfo>
|
||
<option name="filePath" value="$PROJECT_DIR$/src/core/TimerController.cpp" />
|
||
<option name="originalContent" value="#include "TimerController.h" #include <QDebug> TimerController::TimerController(QObject *parent) : QObject(parent) , m_timer(std::make_unique<QTimer>(this)) { connect(m_timer.get(), &QTimer::timeout, this, &TimerController::onTimerTick); m_timer->setInterval(1000); // 1 second reset(); } void TimerController::start() { if (m_state == TimerState::Stopped) { updateTotalSeconds(); m_remainingSeconds = m_totalSeconds; } m_state = TimerState::Running; m_timer->start(); emit stateChanged(m_state); } void TimerController::pause() { if (m_state == TimerState::Running) { m_state = TimerState::Paused; m_timer->stop(); emit stateChanged(m_state); } } void TimerController::reset() { m_timer->stop(); m_state = TimerState::Stopped; m_currentSessionType = SessionType::Work; updateTotalSeconds(); m_remainingSeconds = m_totalSeconds; emit stateChanged(m_state); emit sessionChanged(m_currentSessionType); emit timeChanged(m_remainingSeconds); } void TimerController::skip() { m_timer->stop(); startNextSession(); } double TimerController::progressPercentage() const { if (m_totalSeconds == 0) return 0.0; return (static_cast<double>(m_totalSeconds - m_remainingSeconds) / m_totalSeconds) * 100.0; } void TimerController::onTimerTick() { if (m_remainingSeconds > 0) { --m_remainingSeconds; emit timeChanged(m_remainingSeconds); } else { m_timer->stop(); emit timerFinished(); startNextSession(); } } void TimerController::startNextSession() { switch (m_currentSessionType) { case SessionType::Work: ++m_completedSessions; if (m_completedSessions % SESSIONS_BEFORE_LONG_BREAK == 0) { m_currentSessionType = SessionType::LongBreak; } else { m_currentSessionType = SessionType::ShortBreak; } break; case SessionType::ShortBreak: case SessionType::LongBreak: m_currentSessionType = SessionType::Work; break; } m_state = TimerState::Stopped; updateTotalSeconds(); m_remainingSeconds = m_totalSeconds; emit sessionChanged(m_currentSessionType); emit stateChanged(m_state); emit timeChanged(m_remainingSeconds); } void TimerController::updateTotalSeconds() { switch (m_currentSessionType) { case SessionType::Work: m_totalSeconds = m_workDuration; break; case SessionType::ShortBreak: m_totalSeconds = m_shortBreakDuration; break; case SessionType::LongBreak: m_totalSeconds = m_longBreakDuration; break; } } " />
|
||
<option name="updatedContent" value="#include "TimerController.h" #include <QDebug> TimerController::TimerController(QObject *parent) : QObject(parent) , m_timer(std::make_unique<QTimer>(this)) { connect(m_timer.get(), &QTimer::timeout, this, &TimerController::onTimerTick); m_timer->setInterval(1000); // 1 second reset(); } void TimerController::start() { if (m_state == TimerStatus::Stopped) { updateTotalSeconds(); m_remainingSeconds = m_totalSeconds; } m_state = TimerStatus::Running; m_timer->start(); emit stateChanged(m_state); } void TimerController::pause() { if (m_state == TimerStatus::Running) { m_state = TimerStatus::Paused; m_timer->stop(); emit stateChanged(m_state); } } void TimerController::reset() { m_timer->stop(); m_state = TimerStatus::Stopped; m_currentSessionType = SessionType::Work; updateTotalSeconds(); m_remainingSeconds = m_totalSeconds; emit stateChanged(m_state); emit sessionChanged(m_currentSessionType); emit timeChanged(m_remainingSeconds); } void TimerController::skip() { m_timer->stop(); startNextSession(); } double TimerController::progressPercentage() const { if (m_totalSeconds == 0) return 0.0; return (static_cast<double>(m_totalSeconds - m_remainingSeconds) / m_totalSeconds) * 100.0; } void TimerController::onTimerTick() { if (m_remainingSeconds > 0) { --m_remainingSeconds; emit timeChanged(m_remainingSeconds); } else { m_timer->stop(); emit timerFinished(); startNextSession(); } } void TimerController::startNextSession() { switch (m_currentSessionType) { case SessionType::Work: ++m_completedSessions; if (m_completedSessions % SESSIONS_BEFORE_LONG_BREAK == 0) { m_currentSessionType = SessionType::LongBreak; } else { m_currentSessionType = SessionType::ShortBreak; } break; case SessionType::ShortBreak: case SessionType::LongBreak: m_currentSessionType = SessionType::Work; break; } m_state = TimerStatus::Stopped; updateTotalSeconds(); m_remainingSeconds = m_totalSeconds; emit sessionChanged(m_currentSessionType); emit stateChanged(m_state); emit timeChanged(m_remainingSeconds); } void TimerController::updateTotalSeconds() { switch (m_currentSessionType) { case SessionType::Work: m_totalSeconds = m_workDuration; break; case SessionType::ShortBreak: m_totalSeconds = m_shortBreakDuration; break; case SessionType::LongBreak: m_totalSeconds = m_longBreakDuration; break; } }" />
|
||
</PendingDiffInfo>
|
||
</value>
|
||
</entry>
|
||
<entry key="$PROJECT_DIR$/src/core/TimerController.h">
|
||
<value>
|
||
<PendingDiffInfo>
|
||
<option name="filePath" value="$PROJECT_DIR$/src/core/TimerController.h" />
|
||
<option name="originalContent" value="#ifndef TIMERCONTROLLER_H #define TIMERCONTROLLER_H #include <QObject> #include <QTimer> #include <QDateTime> #include <memory> enum class SessionType { Work, ShortBreak, LongBreak }; enum class TimerState { Stopped, Running, Paused }; class TimerController : public QObject { Q_OBJECT public: explicit TimerController(QObject *parent = nullptr); ~TimerController() override = default; // Timer control void start(); void pause(); void reset(); void skip(); // Getters [[nodiscard]] int remainingSeconds() const { return m_remainingSeconds; } [[nodiscard]] int totalSeconds() const { return m_totalSeconds; } [[nodiscard]] SessionType currentSessionType() const { return m_currentSessionType; } [[nodiscard]] TimerState state() const { return m_state; } [[nodiscard]] int completedSessions() const { return m_completedSessions; } [[nodiscard]] double progressPercentage() const; // Configuration void setWorkDuration(int seconds) { m_workDuration = seconds; } void setShortBreakDuration(int seconds) { m_shortBreakDuration = seconds; } void setLongBreakDuration(int seconds) { m_longBreakDuration = seconds; } signals: void timeChanged(int remainingSeconds); void sessionChanged(SessionType type); void timerFinished(); void stateChanged(TimerState state); private slots: void onTimerTick(); private: void startNextSession(); void updateTotalSeconds(); // Timer objects std::unique_ptr<QTimer> m_timer; // State TimerState m_state = TimerState::Stopped; SessionType m_currentSessionType = SessionType::Work; // Time tracking int m_remainingSeconds = 0; int m_totalSeconds = 0; int m_completedSessions = 0; // Configuration int m_workDuration = 1500; // 25 minutes int m_shortBreakDuration = 300; // 5 minutes int m_longBreakDuration = 900; // 15 minutes static constexpr int SESSIONS_BEFORE_LONG_BREAK = 4; }; #endif // TIMERCONTROLLER_H " />
|
||
<option name="updatedContent" value="#ifndef TIMERCONTROLLER_H #define TIMERCONTROLLER_H #include <QObject> #include <QTimer> #include <QDateTime> #include <memory> enum class SessionType { Work, ShortBreak, LongBreak }; enum class TimerStatus { Stopped, Running, Paused }; class TimerController : public QObject { Q_OBJECT public: explicit TimerController(QObject *parent = nullptr); ~TimerController() override = default; // Timer control void start(); void pause(); void reset(); void skip(); // Getters [[nodiscard]] int remainingSeconds() const { return m_remainingSeconds; } [[nodiscard]] int totalSeconds() const { return m_totalSeconds; } [[nodiscard]] SessionType currentSessionType() const { return m_currentSessionType; } [[nodiscard]] TimerStatus state() const { return m_state; } [[nodiscard]] int completedSessions() const { return m_completedSessions; } [[nodiscard]] double progressPercentage() const; // Configuration void setWorkDuration(int seconds) { m_workDuration = seconds; } void setShortBreakDuration(int seconds) { m_shortBreakDuration = seconds; } void setLongBreakDuration(int seconds) { m_longBreakDuration = seconds; } signals: void timeChanged(int remainingSeconds); void sessionChanged(SessionType type); void timerFinished(); void stateChanged(TimerStatus state); private slots: void onTimerTick(); private: void startNextSession(); void updateTotalSeconds(); // Timer objects std::unique_ptr<QTimer> m_timer; // State TimerStatus m_state = TimerStatus::Stopped; SessionType m_currentSessionType = SessionType::Work; // Time tracking int m_remainingSeconds = 0; int m_totalSeconds = 0; int m_completedSessions = 0; // Configuration int m_workDuration = 1500; // 25 minutes int m_shortBreakDuration = 300; // 5 minutes int m_longBreakDuration = 900; // 15 minutes static constexpr int SESSIONS_BEFORE_LONG_BREAK = 4; }; #endif // TIMERCONTROLLER_H" />
|
||
</PendingDiffInfo>
|
||
</value>
|
||
</entry>
|
||
<entry key="$PROJECT_DIR$/src/system/SystemTrayManager.h">
|
||
<value>
|
||
<PendingDiffInfo>
|
||
<option name="filePath" value="$PROJECT_DIR$/src/system/SystemTrayManager.h" />
|
||
<option name="originalContent" value="#ifndef SYSTEMTRAYMANAGER_H #define SYSTEMTRAYMANAGER_H #include <QSystemTrayIcon> #include <QMenu> #include "core/TimerState.h" class SystemTrayManager : public QObject { Q_OBJECT public: explicit SystemTrayManager(QObject *parent = nullptr); ~SystemTrayManager() override; void show(); void hide(); bool isVisible() const; void updateTooltip(TimerState state, bool isRunning, const QString &timeRemaining, int currentSession, int totalSessions); void showMessage(const QString &title, const QString &message); signals: void showMainWindow(); void startPauseRequested(); void resetRequested(); void skipRequested(); void settingsRequested(); void statisticsRequested(); void quitRequested(); private slots: void onTrayIconActivated(QSystemTrayIcon::ActivationReason reason); private: void setupTrayMenu(); QSystemTrayIcon *m_trayIcon; QMenu *m_trayMenu; // Cache to avoid unnecessary tooltip updates QString m_lastTooltip; }; #endif // SYSTEMTRAYMANAGER_H " />
|
||
<option name="updatedContent" value="#ifndef SYSTEMTRAYMANAGER_H #define SYSTEMTRAYMANAGER_H #include <QSystemTrayIcon> #include <QMenu> #include "TimerState.h" class SystemTrayManager : public QObject { Q_OBJECT public: explicit SystemTrayManager(QObject *parent = nullptr); ~SystemTrayManager() override; void show(); void hide(); bool isVisible() const; void updateTooltip(TimerState state, bool isRunning, const QString &timeRemaining, int currentSession, int totalSessions); void showMessage(const QString &title, const QString &message); signals: void showMainWindow(); void startPauseRequested(); void resetRequested(); void skipRequested(); void settingsRequested(); void statisticsRequested(); void quitRequested(); private slots: void onTrayIconActivated(QSystemTrayIcon::ActivationReason reason); private: void setupTrayMenu(); QSystemTrayIcon *m_trayIcon; QMenu *m_trayMenu; // Cache to avoid unnecessary tooltip updates QString m_lastTooltip; }; #endif // SYSTEMTRAYMANAGER_H" />
|
||
</PendingDiffInfo>
|
||
</value>
|
||
</entry>
|
||
<entry key="$PROJECT_DIR$/src/ui/PomodoroTimer.cpp">
|
||
<value>
|
||
<PendingDiffInfo>
|
||
<option name="filePath" value="$PROJECT_DIR$/src/ui/PomodoroTimer.cpp" />
|
||
<option name="originalContent" value="#include "PomodoroTimer.h" #include "CircularProgressBar.h" #include "SettingsDialog.h" #include "StatisticsDialog.h" #include "system/SystemTrayManager.h" #include "system/KeyboardShortcuts.h" #include "system/NotificationManager.h" #include "core/TimerState.h" #include <QApplication> #include <QDateTime> #include <QFont> #include <QKeyEvent> #include <QSettings> #include <QVBoxLayout> namespace { // UI Layout constants constexpr int WINDOW_WIDTH = 440; constexpr int WINDOW_HEIGHT = 550; constexpr int PROGRESS_BAR_SIZE = 220; constexpr int MAIN_BUTTON_WIDTH = 100; constexpr int MAIN_BUTTON_HEIGHT = 40; constexpr int SMALL_BUTTON_WIDTH = 90; constexpr int SMALL_BUTTON_HEIGHT = 35; constexpr int LAYOUT_SPACING = 10; constexpr int LAYOUT_MARGIN = 25; // Font sizes constexpr int TIME_FONT_SIZE = 24; constexpr int STATUS_FONT_SIZE = 14; constexpr int SESSION_FONT_SIZE = 12; constexpr int BUTTON_FONT_SIZE = 11; // Progress bar positioning constexpr int TIME_LABEL_Y_OFFSET = 90; } PomodoroTimer::PomodoroTimer(QWidget *parent) : QWidget(parent) , m_timer(new QTimer(this)) , m_trayManager(std::make_unique<SystemTrayManager>(this)) , m_keyboardShortcuts(std::make_unique<KeyboardShortcuts>(this)) , m_notificationManager(std::make_unique<NotificationManager>(this)) { loadSettings(); setupUI(); setupConnections(); resetTimerState(); updateDisplay(); // Setup manager connections m_notificationManager->setSystemTrayManager(m_trayManager.get()); m_notificationManager->setNotificationsEnabled(m_showNotifications); m_trayManager->show(); } PomodoroTimer::~PomodoroTimer() { saveSettings(); } void PomodoroTimer::setupUI() { setFixedSize(WINDOW_WIDTH, WINDOW_HEIGHT); m_mainFrame = new QFrame(this); m_circularProgress = new CircularProgressBar(m_mainFrame); m_circularProgress->setFixedSize(PROGRESS_BAR_SIZE, PROGRESS_BAR_SIZE); createLabels(); createButtons(); createLayouts(); applyStyles(); updateButtonStates(); } void PomodoroTimer::createLabels() { // Time display label m_timeLabel = new QLabel("25:00", m_circularProgress); m_timeLabel->setAlignment(Qt::AlignCenter); m_timeLabel->resize(PROGRESS_BAR_SIZE, 40); m_timeLabel->move(0, TIME_LABEL_Y_OFFSET); // Status indicator label m_statusLabel = new QLabel("Ready to Focus", m_mainFrame); m_statusLabel->setAlignment(Qt::AlignCenter); // Session progress label m_sessionLabel = new QLabel("Session 1 of 4", m_mainFrame); m_sessionLabel->setAlignment(Qt::AlignCenter); } void PomodoroTimer::createButtons() { m_startButton = new QPushButton("Start", m_mainFrame); m_pauseButton = new QPushButton("Pause", m_mainFrame); m_resetButton = new QPushButton("Reset", m_mainFrame); m_settingsButton = new QPushButton("Settings", m_mainFrame); m_skipButton = new QPushButton("Skip", m_mainFrame); m_statsButton = new QPushButton("Statistics", m_mainFrame); // Set button sizes constexpr QSize mainButtonSize(MAIN_BUTTON_WIDTH, MAIN_BUTTON_HEIGHT); constexpr QSize smallButtonSize(SMALL_BUTTON_WIDTH, SMALL_BUTTON_HEIGHT); m_startButton->setFixedSize(mainButtonSize); m_pauseButton->setFixedSize(mainButtonSize); m_resetButton->setFixedSize(mainButtonSize); m_settingsButton->setFixedSize(mainButtonSize); m_skipButton->setFixedSize(smallButtonSize); m_statsButton->setFixedSize(smallButtonSize); } void PomodoroTimer::createLayouts() { // Progress bar layout auto progressLayout = new QVBoxLayout(); progressLayout->addWidget(m_circularProgress, 0, Qt::AlignCenter); // Main control buttons layout auto buttonLayout = new QHBoxLayout(); buttonLayout->setSpacing(LAYOUT_SPACING); buttonLayout->addWidget(m_startButton); buttonLayout->addWidget(m_pauseButton); buttonLayout->addWidget(m_resetButton); // Header layout with settings button auto headerLayout = new QHBoxLayout(); headerLayout->addStretch(); headerLayout->addWidget(m_settingsButton); // Extra buttons layout auto extraButtonLayout = new QHBoxLayout(); extraButtonLayout->setSpacing(LAYOUT_SPACING); extraButtonLayout->addStretch(); extraButtonLayout->addWidget(m_skipButton); extraButtonLayout->addWidget(m_statsButton); extraButtonLayout->addStretch(); // Main layout assembly auto mainLayout = new QVBoxLayout(); mainLayout->addLayout(headerLayout); mainLayout->addSpacing(5); mainLayout->addWidget(m_statusLabel); mainLayout->addSpacing(15); mainLayout->addLayout(progressLayout); mainLayout->addSpacing(15); mainLayout->addWidget(m_sessionLabel); mainLayout->addSpacing(20); mainLayout->addLayout(buttonLayout); mainLayout->addSpacing(15); mainLayout->addLayout(extraButtonLayout); mainLayout->setContentsMargins(LAYOUT_MARGIN, LAYOUT_MARGIN, LAYOUT_MARGIN, LAYOUT_MARGIN); m_mainFrame->setLayout(mainLayout); // Frame layout auto frameLayout = new QVBoxLayout(); frameLayout->addWidget(m_mainFrame); frameLayout->setContentsMargins(0, 0, 0, 0); setLayout(frameLayout); } void PomodoroTimer::applyStyles() const { QFont timeFont = m_timeLabel->font(); timeFont.setPointSize(TIME_FONT_SIZE); timeFont.setBold(true); m_timeLabel->setFont(timeFont); QFont statusFont = m_statusLabel->font(); statusFont.setPointSize(STATUS_FONT_SIZE); m_statusLabel->setFont(statusFont); QFont sessionFont = m_sessionLabel->font(); sessionFont.setPointSize(SESSION_FONT_SIZE); m_sessionLabel->setFont(sessionFont); QFont buttonFont; buttonFont.setPointSize(BUTTON_FONT_SIZE); const auto buttons = {m_startButton, m_pauseButton, m_resetButton, m_settingsButton, m_skipButton, m_statsButton}; for (auto* button : buttons) { if (button) button->setFont(buttonFont); } } void PomodoroTimer::setupConnections() { // Timer connections connect(m_timer, &QTimer::timeout, this, &PomodoroTimer::onUpdateTimer); // Button connections connect(m_startButton, &QPushButton::clicked, this, &PomodoroTimer::onStartTimer); connect(m_pauseButton, &QPushButton::clicked, this, &PomodoroTimer::onPauseTimer); connect(m_resetButton, &QPushButton::clicked, this, &PomodoroTimer::onResetTimer); connect(m_settingsButton, &QPushButton::clicked, this, &PomodoroTimer::onShowSettings); connect(m_skipButton, &QPushButton::clicked, this, &PomodoroTimer::onSkipSession); connect(m_statsButton, &QPushButton::clicked, this, &PomodoroTimer::onShowStatistics); // System tray connections connect(m_trayManager.get(), &SystemTrayManager::showMainWindow, this, &PomodoroTimer::onToggleVisibility); connect(m_trayManager.get(), &SystemTrayManager::startPauseRequested, this, [this]() { m_isRunning ? onPauseTimer() : onStartTimer(); }); connect(m_trayManager.get(), &SystemTrayManager::resetRequested, this, &PomodoroTimer::onResetTimer); connect(m_trayManager.get(), &SystemTrayManager::skipRequested, this, &PomodoroTimer::onSkipSession); connect(m_trayManager.get(), &SystemTrayManager::settingsRequested, this, &PomodoroTimer::onShowSettings); connect(m_trayManager.get(), &SystemTrayManager::statisticsRequested, this, &PomodoroTimer::onShowStatistics); connect(m_trayManager.get(), &SystemTrayManager::quitRequested, qApp, &QCoreApplication::quit); // Keyboard shortcuts connections connect(m_keyboardShortcuts.get(), &KeyboardShortcuts::startPauseRequested, this, [this]() { m_isRunning ? onPauseTimer() : onStartTimer(); }); connect(m_keyboardShortcuts.get(), &KeyboardShortcuts::pauseRequested, this, &PomodoroTimer::onPauseTimer); connect(m_keyboardShortcuts.get(), &KeyboardShortcuts::resetRequested, this, &PomodoroTimer::onResetTimer); connect(m_keyboardShortcuts.get(), &KeyboardShortcuts::settingsRequested, this, &PomodoroTimer::onShowSettings); connect(m_keyboardShortcuts.get(), &KeyboardShortcuts::skipRequested, this, &PomodoroTimer::onSkipSession); } // Timer control methods void PomodoroTimer::onStartTimer() { if (m_isRunning) return; m_isRunning = true; m_sessionStartTime = QDateTime::currentDateTime(); m_timer->start(TIMER_INTERVAL_MS); m_statusLabel->setText(TimerStateHelper::getStatusMessage(m_currentState, true)); updateButtonStates(); updateDisplay(); } void PomodoroTimer::onPauseTimer() { if (!m_isRunning) return; m_timer->stop(); m_isRunning = false; m_statusLabel->setText("⏸ Paused"); updateButtonStates(); updateDisplay(); } void PomodoroTimer::onResetTimer() { m_timer->stop(); m_isRunning = false; resetTimerState(); updateDisplay(); updateButtonStates(); } void PomodoroTimer::onUpdateTimer() { --m_currentTime; updateDisplay(); if (m_currentTime <= 0) { onTimerFinished(); } } void PomodoroTimer::onTimerFinished() { m_timer->stop(); m_isRunning = false; // Update statistics const QDateTime now = QDateTime::currentDateTime(); const int sessionDuration = static_cast<int>(m_sessionStartTime.secsTo(now)); if (m_currentState == TimerState::Work) { m_totalWorkTime += sessionDuration; m_totalSessions++; m_completedSessions++; } else { m_totalBreakTime += sessionDuration; } // Determine next state and show notifications QString message, nextAction; if (m_currentState == TimerState::Work) { message = " Focus session completed!"; const bool isLongBreakTime = (m_completedSessions % SESSIONS_BEFORE_LONG_BREAK == 0); updateTimerState(isLongBreakTime ? TimerState::LongBreak : TimerState::ShortBreak); nextAction = isLongBreakTime ? "Time for a long break! ♀️" : "Take a short break! ☕"; } else { message = "Break time finished!"; nextAction = "Ready to focus again? "; updateTimerState(TimerState::Work); } m_notificationManager->showNotification(message + " " + nextAction); onResetTimer(); // Auto-start if enabled const bool shouldAutoStart = (m_currentState != TimerState::Work && m_autoStartBreaks) || (m_currentState == TimerState::Work && m_autoStartWork); if (shouldAutoStart) { QTimer::singleShot(AUTO_START_DELAY_MS, this, &PomodoroTimer::onStartTimer); } saveSettings(); } // Helper methods void PomodoroTimer::resetTimerState() { m_currentTime = TimerStateHelper::getDurationForState(m_currentState, m_workDuration, m_shortBreakDuration, m_longBreakDuration); m_totalDuration = m_currentTime; m_statusLabel->setText(TimerStateHelper::getStatusMessage(m_currentState, false)); } void PomodoroTimer::updateTimerState(TimerState newState) { m_currentState = newState; } QString PomodoroTimer::formatTime(int seconds) { const int minutes = seconds / 60; const int secs = seconds % 60; return QString("%1:%2") .arg(minutes, 2, 10, QChar('0')) .arg(secs, 2, 10, QChar('0')); } void PomodoroTimer::needsDisplayUpdate() {} void PomodoroTimer::updateDisplay() { m_timeLabel->setText(formatTime(m_currentTime)); const int progress = m_totalDuration > 0 ? ((m_totalDuration - m_currentTime) * 100) / m_totalDuration : 0; m_circularProgress->setValue(progress); updateSessionCounter(); updateWindowTitle(); // Update system tray const int currentSession = (m_completedSessions % SESSIONS_BEFORE_LONG_BREAK) + 1; m_trayManager->updateTooltip(m_currentState, m_isRunning, formatTime(m_currentTime), currentSession, SESSIONS_BEFORE_LONG_BREAK); } void PomodoroTimer::updateSessionCounter() const { const int currentSession = (m_completedSessions % SESSIONS_BEFORE_LONG_BREAK) + 1; m_sessionLabel->setText(QString("Session %1 of %2") .arg(currentSession) .arg(SESSIONS_BEFORE_LONG_BREAK)); } void PomodoroTimer::updateButtonStates() const { m_startButton->setEnabled(!m_isRunning); m_pauseButton->setEnabled(m_isRunning); const bool shouldShowReset = m_isRunning || m_currentTime < m_totalDuration; m_resetButton->setVisible(shouldShowReset); m_resetButton->setEnabled(true); m_skipButton->setEnabled(m_isRunning); m_skipButton->setVisible(m_isRunning); // Force layout update if (m_mainFrame && m_mainFrame->layout()) { m_mainFrame->layout()->update(); m_mainFrame->updateGeometry(); } } void PomodoroTimer::updateWindowTitle() { const QString timeRemaining = formatTime(m_currentTime); const QString emoji = TimerStateHelper::getStateEmoji(m_currentState); QString title; if (m_isRunning) { const QString stateText = (m_currentState == TimerState::Work) ? "Focus" : "Break"; title = QString("%1 %2: %3").arg(emoji, stateText, timeRemaining); } else { title = " Pomodoro Timer"; } setWindowTitle(title); } void PomodoroTimer::updateTrayTooltip() {} void PomodoroTimer::onShowSettings() { SettingsDialog dialog(this); dialog.setWorkDuration(m_workDuration / 60); dialog.setShortBreakDuration(m_shortBreakDuration / 60); dialog.setLongBreakDuration(m_longBreakDuration / 60); dialog.setAutoStartBreaks(m_autoStartBreaks); dialog.setAutoStartWork(m_autoStartWork); dialog.setMinimizeToTray(m_minimizeToTray); dialog.setShowNotifications(m_showNotifications); if (dialog.exec() == QDialog::Accepted) { m_workDuration = dialog.workDuration() * 60; m_shortBreakDuration = dialog.shortBreakDuration() * 60; m_longBreakDuration = dialog.longBreakDuration() * 60; m_autoStartBreaks = dialog.autoStartBreaks(); m_autoStartWork = dialog.autoStartWork(); m_minimizeToTray = dialog.minimizeToTray(); m_showNotifications = dialog.showNotifications(); saveSettings(); onResetTimer(); } } void PomodoroTimer::onSkipSession() { if (m_isRunning) { onTimerFinished(); } } void PomodoroTimer::onShowStatistics() { StatisticsDialog dialog(this); dialog.setStatistics(m_totalSessions, m_totalWorkTime, m_totalBreakTime); dialog.exec(); } void PomodoroTimer::onToggleVisibility() { if (isVisible()) { hide(); } else { show(); raise(); activateWindow(); } } void PomodoroTimer::loadSettings() { QSettings settings; m_workDuration = settings.value("workDuration", DEFAULT_WORK_DURATION).toInt(); m_shortBreakDuration = settings.value("shortBreakDuration", DEFAULT_SHORT_BREAK).toInt(); m_longBreakDuration = settings.value("longBreakDuration", DEFAULT_LONG_BREAK).toInt(); m_autoStartBreaks = settings.value("autoStartBreaks", false).toBool(); m_autoStartWork = settings.value("autoStartWork", false).toBool(); m_minimizeToTray = settings.value("minimizeToTray", true).toBool(); m_showNotifications = settings.value("showNotifications", true).toBool(); m_totalSessions = settings.value("totalSessions", 0).toInt(); m_totalWorkTime = settings.value("totalWorkTime", 0).toInt(); m_totalBreakTime = settings.value("totalBreakTime", 0).toInt(); } void PomodoroTimer::saveSettings() const { QSettings settings; settings.setValue("workDuration", m_workDuration); settings.setValue("shortBreakDuration", m_shortBreakDuration); settings.setValue("longBreakDuration", m_longBreakDuration); settings.setValue("autoStartBreaks", m_autoStartBreaks); settings.setValue("autoStartWork", m_autoStartWork); settings.setValue("minimizeToTray", m_minimizeToTray); settings.setValue("showNotifications", m_showNotifications); settings.setValue("totalSessions", m_totalSessions); settings.setValue("totalWorkTime", m_totalWorkTime); settings.setValue("totalBreakTime", m_totalBreakTime); } void PomodoroTimer::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Escape) { hide(); } QWidget::keyPressEvent(event); } void PomodoroTimer::closeEvent(QCloseEvent *event) { if (m_trayManager && m_trayManager->isVisible()) { hide(); event->ignore(); static bool firstHide = true; if (firstHide) { m_notificationManager->showNotification("Application was minimized to tray. Click the tray icon to show again."); firstHide = false; } } else { saveSettings(); event->accept(); } } " />
|
||
<option name="updatedContent" value="#include "PomodoroTimer.h" #include "CircularProgressBar.h" #include "SettingsDialog.h" #include "StatisticsDialog.h" #include "SystemTrayManager.h" #include "KeyboardShortcuts.h" #include "NotificationManager.h" #include "TimerState.h" #include <QApplication> #include <QDateTime> #include <QFont> #include <QKeyEvent> #include <QSettings> #include <QVBoxLayout> namespace { // UI Layout constants constexpr int WINDOW_WIDTH = 440; constexpr int WINDOW_HEIGHT = 550; constexpr int PROGRESS_BAR_SIZE = 220; constexpr int MAIN_BUTTON_WIDTH = 100; constexpr int MAIN_BUTTON_HEIGHT = 40; constexpr int SMALL_BUTTON_WIDTH = 90; constexpr int SMALL_BUTTON_HEIGHT = 35; constexpr int LAYOUT_SPACING = 10; constexpr int LAYOUT_MARGIN = 25; // Font sizes constexpr int TIME_FONT_SIZE = 24; constexpr int STATUS_FONT_SIZE = 14; constexpr int SESSION_FONT_SIZE = 12; constexpr int BUTTON_FONT_SIZE = 11; // Progress bar positioning constexpr int TIME_LABEL_Y_OFFSET = 90; } PomodoroTimer::PomodoroTimer(QWidget *parent) : QWidget(parent) , m_timer(new QTimer(this)) , m_trayManager(std::make_unique<SystemTrayManager>(this)) , m_keyboardShortcuts(std::make_unique<KeyboardShortcuts>(this)) , m_notificationManager(std::make_unique<NotificationManager>(this)) { loadSettings(); setupUI(); setupConnections(); resetTimerState(); updateDisplay(); // Setup manager connections m_notificationManager->setSystemTrayManager(m_trayManager.get()); m_notificationManager->setNotificationsEnabled(m_showNotifications); m_trayManager->show(); } PomodoroTimer::~PomodoroTimer() { saveSettings(); } void PomodoroTimer::setupUI() { setFixedSize(WINDOW_WIDTH, WINDOW_HEIGHT); m_mainFrame = new QFrame(this); m_circularProgress = new CircularProgressBar(m_mainFrame); m_circularProgress->setFixedSize(PROGRESS_BAR_SIZE, PROGRESS_BAR_SIZE); createLabels(); createButtons(); createLayouts(); applyStyles(); updateButtonStates(); } void PomodoroTimer::createLabels() { // Time display label m_timeLabel = new QLabel("25:00", m_circularProgress); m_timeLabel->setAlignment(Qt::AlignCenter); m_timeLabel->resize(PROGRESS_BAR_SIZE, 40); m_timeLabel->move(0, TIME_LABEL_Y_OFFSET); // Status indicator label m_statusLabel = new QLabel("Ready to Focus", m_mainFrame); m_statusLabel->setAlignment(Qt::AlignCenter); // Session progress label m_sessionLabel = new QLabel("Session 1 of 4", m_mainFrame); m_sessionLabel->setAlignment(Qt::AlignCenter); } void PomodoroTimer::createButtons() { m_startButton = new QPushButton("Start", m_mainFrame); m_pauseButton = new QPushButton("Pause", m_mainFrame); m_resetButton = new QPushButton("Reset", m_mainFrame); m_settingsButton = new QPushButton("Settings", m_mainFrame); m_skipButton = new QPushButton("Skip", m_mainFrame); m_statsButton = new QPushButton("Statistics", m_mainFrame); // Set button sizes constexpr QSize mainButtonSize(MAIN_BUTTON_WIDTH, MAIN_BUTTON_HEIGHT); constexpr QSize smallButtonSize(SMALL_BUTTON_WIDTH, SMALL_BUTTON_HEIGHT); m_startButton->setFixedSize(mainButtonSize); m_pauseButton->setFixedSize(mainButtonSize); m_resetButton->setFixedSize(mainButtonSize); m_settingsButton->setFixedSize(mainButtonSize); m_skipButton->setFixedSize(smallButtonSize); m_statsButton->setFixedSize(smallButtonSize); } void PomodoroTimer::createLayouts() { // Progress bar layout auto progressLayout = new QVBoxLayout(); progressLayout->addWidget(m_circularProgress, 0, Qt::AlignCenter); // Main control buttons layout auto buttonLayout = new QHBoxLayout(); buttonLayout->setSpacing(LAYOUT_SPACING); buttonLayout->addWidget(m_startButton); buttonLayout->addWidget(m_pauseButton); buttonLayout->addWidget(m_resetButton); // Header layout with settings button auto headerLayout = new QHBoxLayout(); headerLayout->addStretch(); headerLayout->addWidget(m_settingsButton); // Extra buttons layout auto extraButtonLayout = new QHBoxLayout(); extraButtonLayout->setSpacing(LAYOUT_SPACING); extraButtonLayout->addStretch(); extraButtonLayout->addWidget(m_skipButton); extraButtonLayout->addWidget(m_statsButton); extraButtonLayout->addStretch(); // Main layout assembly auto mainLayout = new QVBoxLayout(); mainLayout->addLayout(headerLayout); mainLayout->addSpacing(5); mainLayout->addWidget(m_statusLabel); mainLayout->addSpacing(15); mainLayout->addLayout(progressLayout); mainLayout->addSpacing(15); mainLayout->addWidget(m_sessionLabel); mainLayout->addSpacing(20); mainLayout->addLayout(buttonLayout); mainLayout->addSpacing(15); mainLayout->addLayout(extraButtonLayout); mainLayout->setContentsMargins(LAYOUT_MARGIN, LAYOUT_MARGIN, LAYOUT_MARGIN, LAYOUT_MARGIN); m_mainFrame->setLayout(mainLayout); // Frame layout auto frameLayout = new QVBoxLayout(); frameLayout->addWidget(m_mainFrame); frameLayout->setContentsMargins(0, 0, 0, 0); setLayout(frameLayout); } void PomodoroTimer::applyStyles() const { QFont timeFont = m_timeLabel->font(); timeFont.setPointSize(TIME_FONT_SIZE); timeFont.setBold(true); m_timeLabel->setFont(timeFont); QFont statusFont = m_statusLabel->font(); statusFont.setPointSize(STATUS_FONT_SIZE); m_statusLabel->setFont(statusFont); QFont sessionFont = m_sessionLabel->font(); sessionFont.setPointSize(SESSION_FONT_SIZE); m_sessionLabel->setFont(sessionFont); QFont buttonFont; buttonFont.setPointSize(BUTTON_FONT_SIZE); const auto buttons = {m_startButton, m_pauseButton, m_resetButton, m_settingsButton, m_skipButton, m_statsButton}; for (auto* button : buttons) { if (button) button->setFont(buttonFont); } } void PomodoroTimer::setupConnections() { // Timer connections connect(m_timer, &QTimer::timeout, this, &PomodoroTimer::onUpdateTimer); // Button connections connect(m_startButton, &QPushButton::clicked, this, &PomodoroTimer::onStartTimer); connect(m_pauseButton, &QPushButton::clicked, this, &PomodoroTimer::onPauseTimer); connect(m_resetButton, &QPushButton::clicked, this, &PomodoroTimer::onResetTimer); connect(m_settingsButton, &QPushButton::clicked, this, &PomodoroTimer::onShowSettings); connect(m_skipButton, &QPushButton::clicked, this, &PomodoroTimer::onSkipSession); connect(m_statsButton, &QPushButton::clicked, this, &PomodoroTimer::onShowStatistics); // System tray connections connect(m_trayManager.get(), &SystemTrayManager::showMainWindow, this, &PomodoroTimer::onToggleVisibility); connect(m_trayManager.get(), &SystemTrayManager::startPauseRequested, this, [this]() { m_isRunning ? onPauseTimer() : onStartTimer(); }); connect(m_trayManager.get(), &SystemTrayManager::resetRequested, this, &PomodoroTimer::onResetTimer); connect(m_trayManager.get(), &SystemTrayManager::skipRequested, this, &PomodoroTimer::onSkipSession); connect(m_trayManager.get(), &SystemTrayManager::settingsRequested, this, &PomodoroTimer::onShowSettings); connect(m_trayManager.get(), &SystemTrayManager::statisticsRequested, this, &PomodoroTimer::onShowStatistics); connect(m_trayManager.get(), &SystemTrayManager::quitRequested, qApp, &QCoreApplication::quit); // Keyboard shortcuts connections connect(m_keyboardShortcuts.get(), &KeyboardShortcuts::startPauseRequested, this, [this]() { m_isRunning ? onPauseTimer() : onStartTimer(); }); connect(m_keyboardShortcuts.get(), &KeyboardShortcuts::pauseRequested, this, &PomodoroTimer::onPauseTimer); connect(m_keyboardShortcuts.get(), &KeyboardShortcuts::resetRequested, this, &PomodoroTimer::onResetTimer); connect(m_keyboardShortcuts.get(), &KeyboardShortcuts::settingsRequested, this, &PomodoroTimer::onShowSettings); connect(m_keyboardShortcuts.get(), &KeyboardShortcuts::skipRequested, this, &PomodoroTimer::onSkipSession); } // Timer control methods void PomodoroTimer::onStartTimer() { if (m_isRunning) return; m_isRunning = true; m_sessionStartTime = QDateTime::currentDateTime(); m_timer->start(TIMER_INTERVAL_MS); m_statusLabel->setText(TimerStateHelper::getStatusMessage(m_currentState, true)); updateButtonStates(); updateDisplay(); } void PomodoroTimer::onPauseTimer() { if (!m_isRunning) return; m_timer->stop(); m_isRunning = false; m_statusLabel->setText("⏸ Paused"); updateButtonStates(); updateDisplay(); } void PomodoroTimer::onResetTimer() { m_timer->stop(); m_isRunning = false; resetTimerState(); updateDisplay(); updateButtonStates(); } void PomodoroTimer::onUpdateTimer() { --m_currentTime; updateDisplay(); if (m_currentTime <= 0) { onTimerFinished(); } } void PomodoroTimer::onTimerFinished() { m_timer->stop(); m_isRunning = false; // Update statistics const QDateTime now = QDateTime::currentDateTime(); const int sessionDuration = static_cast<int>(m_sessionStartTime.secsTo(now)); if (m_currentState == TimerState::Work) { m_totalWorkTime += sessionDuration; m_totalSessions++; m_completedSessions++; } else { m_totalBreakTime += sessionDuration; } // Determine next state and show notifications QString message, nextAction; if (m_currentState == TimerState::Work) { message = " Focus session completed!"; const bool isLongBreakTime = (m_completedSessions % SESSIONS_BEFORE_LONG_BREAK == 0); updateTimerState(isLongBreakTime ? TimerState::LongBreak : TimerState::ShortBreak); nextAction = isLongBreakTime ? "Time for a long break! ♀️" : "Take a short break! ☕"; } else { message = "Break time finished!"; nextAction = "Ready to focus again? "; updateTimerState(TimerState::Work); } m_notificationManager->showNotification(message + " " + nextAction); onResetTimer(); // Auto-start if enabled const bool shouldAutoStart = (m_currentState != TimerState::Work && m_autoStartBreaks) || (m_currentState == TimerState::Work && m_autoStartWork); if (shouldAutoStart) { QTimer::singleShot(AUTO_START_DELAY_MS, this, &PomodoroTimer::onStartTimer); } saveSettings(); } // Helper methods void PomodoroTimer::resetTimerState() { m_currentTime = TimerStateHelper::getDurationForState(m_currentState, m_workDuration, m_shortBreakDuration, m_longBreakDuration); m_totalDuration = m_currentTime; m_statusLabel->setText(TimerStateHelper::getStatusMessage(m_currentState, false)); } void PomodoroTimer::updateTimerState(TimerState newState) { m_currentState = newState; } QString PomodoroTimer::formatTime(int seconds) { const int minutes = seconds / 60; const int secs = seconds % 60; return QString("%1:%2") .arg(minutes, 2, 10, QChar('0')) .arg(secs, 2, 10, QChar('0')); } void PomodoroTimer::needsDisplayUpdate() {} void PomodoroTimer::updateDisplay() { m_timeLabel->setText(formatTime(m_currentTime)); const int progress = m_totalDuration > 0 ? ((m_totalDuration - m_currentTime) * 100) / m_totalDuration : 0; m_circularProgress->setValue(progress); updateSessionCounter(); updateWindowTitle(); // Update system tray const int currentSession = (m_completedSessions % SESSIONS_BEFORE_LONG_BREAK) + 1; m_trayManager->updateTooltip(m_currentState, m_isRunning, formatTime(m_currentTime), currentSession, SESSIONS_BEFORE_LONG_BREAK); } void PomodoroTimer::updateSessionCounter() const { const int currentSession = (m_completedSessions % SESSIONS_BEFORE_LONG_BREAK) + 1; m_sessionLabel->setText(QString("Session %1 of %2") .arg(currentSession) .arg(SESSIONS_BEFORE_LONG_BREAK)); } void PomodoroTimer::updateButtonStates() const { m_startButton->setEnabled(!m_isRunning); m_pauseButton->setEnabled(m_isRunning); const bool shouldShowReset = m_isRunning || m_currentTime < m_totalDuration; m_resetButton->setVisible(shouldShowReset); m_resetButton->setEnabled(true); m_skipButton->setEnabled(m_isRunning); m_skipButton->setVisible(m_isRunning); // Force layout update if (m_mainFrame && m_mainFrame->layout()) { m_mainFrame->layout()->update(); m_mainFrame->updateGeometry(); } } void PomodoroTimer::updateWindowTitle() { const QString timeRemaining = formatTime(m_currentTime); const QString emoji = TimerStateHelper::getStateEmoji(m_currentState); QString title; if (m_isRunning) { const QString stateText = (m_currentState == TimerState::Work) ? "Focus" : "Break"; title = QString("%1 %2: %3").arg(emoji, stateText, timeRemaining); } else { title = " Pomodoro Timer"; } setWindowTitle(title); } void PomodoroTimer::updateTrayTooltip() {} void PomodoroTimer::onShowSettings() { SettingsDialog dialog(this); dialog.setWorkDuration(m_workDuration / 60); dialog.setShortBreakDuration(m_shortBreakDuration / 60); dialog.setLongBreakDuration(m_longBreakDuration / 60); dialog.setAutoStartBreaks(m_autoStartBreaks); dialog.setAutoStartWork(m_autoStartWork); dialog.setMinimizeToTray(m_minimizeToTray); dialog.setShowNotifications(m_showNotifications); if (dialog.exec() == QDialog::Accepted) { m_workDuration = dialog.workDuration() * 60; m_shortBreakDuration = dialog.shortBreakDuration() * 60; m_longBreakDuration = dialog.longBreakDuration() * 60; m_autoStartBreaks = dialog.autoStartBreaks(); m_autoStartWork = dialog.autoStartWork(); m_minimizeToTray = dialog.minimizeToTray(); m_showNotifications = dialog.showNotifications(); saveSettings(); onResetTimer(); } } void PomodoroTimer::onSkipSession() { if (m_isRunning) { onTimerFinished(); } } void PomodoroTimer::onShowStatistics() { StatisticsDialog dialog(this); dialog.setStatistics(m_totalSessions, m_totalWorkTime, m_totalBreakTime); dialog.exec(); } void PomodoroTimer::onToggleVisibility() { if (isVisible()) { hide(); } else { show(); raise(); activateWindow(); } } void PomodoroTimer::loadSettings() { QSettings settings; m_workDuration = settings.value("workDuration", DEFAULT_WORK_DURATION).toInt(); m_shortBreakDuration = settings.value("shortBreakDuration", DEFAULT_SHORT_BREAK).toInt(); m_longBreakDuration = settings.value("longBreakDuration", DEFAULT_LONG_BREAK).toInt(); m_autoStartBreaks = settings.value("autoStartBreaks", false).toBool(); m_autoStartWork = settings.value("autoStartWork", false).toBool(); m_minimizeToTray = settings.value("minimizeToTray", true).toBool(); m_showNotifications = settings.value("showNotifications", true).toBool(); m_totalSessions = settings.value("totalSessions", 0).toInt(); m_totalWorkTime = settings.value("totalWorkTime", 0).toInt(); m_totalBreakTime = settings.value("totalBreakTime", 0).toInt(); } void PomodoroTimer::saveSettings() const { QSettings settings; settings.setValue("workDuration", m_workDuration); settings.setValue("shortBreakDuration", m_shortBreakDuration); settings.setValue("longBreakDuration", m_longBreakDuration); settings.setValue("autoStartBreaks", m_autoStartBreaks); settings.setValue("autoStartWork", m_autoStartWork); settings.setValue("minimizeToTray", m_minimizeToTray); settings.setValue("showNotifications", m_showNotifications); settings.setValue("totalSessions", m_totalSessions); settings.setValue("totalWorkTime", m_totalWorkTime); settings.setValue("totalBreakTime", m_totalBreakTime); } void PomodoroTimer::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Escape) { hide(); } QWidget::keyPressEvent(event); } void PomodoroTimer::closeEvent(QCloseEvent *event) { if (m_trayManager && m_trayManager->isVisible()) { hide(); event->ignore(); static bool firstHide = true; if (firstHide) { m_notificationManager->showNotification("Application was minimized to tray. Click the tray icon to show again."); firstHide = false; } } else { saveSettings(); event->accept(); } }" />
|
||
</PendingDiffInfo>
|
||
</value>
|
||
</entry>
|
||
<entry key="$PROJECT_DIR$/src/ui/PomodoroTimer.h">
|
||
<value>
|
||
<PendingDiffInfo>
|
||
<option name="filePath" value="$PROJECT_DIR$/src/ui/PomodoroTimer.h" />
|
||
<option name="originalContent" value="#ifndef POMODOROTIMER_H #define POMODOROTIMER_H #include <QTimer> #include <QLabel> #include <QPushButton> #include <QFrame> #include <QDateTime> #include <memory> #include "core/TimerState.h" // Forward declarations class CircularProgressBar; class SettingsDialog; class StatisticsDialog; class SystemTrayManager; class KeyboardShortcuts; class NotificationManager; class PomodoroTimer : public QWidget { Q_OBJECT public: explicit PomodoroTimer(QWidget *parent = nullptr); ~PomodoroTimer() override; // Timer configuration constants static constexpr int DEFAULT_WORK_DURATION = 1500; // 25 minutes in seconds static constexpr int DEFAULT_SHORT_BREAK = 300; // 5 minutes in seconds static constexpr int DEFAULT_LONG_BREAK = 900; // 15 minutes in seconds static constexpr int SESSIONS_BEFORE_LONG_BREAK = 4; static constexpr int TIMER_INTERVAL_MS = 1000; static constexpr int AUTO_START_DELAY_MS = 3000; protected: void keyPressEvent(QKeyEvent *event) override; void closeEvent(QCloseEvent *event) override; private slots: // Timer control slots void onStartTimer(); void onPauseTimer(); void onResetTimer(); void onUpdateTimer(); void onTimerFinished(); // UI interaction slots void onShowSettings(); void onSkipSession(); void onShowStatistics(); void onToggleVisibility(); private: // Setup methods void setupUI(); void setupConnections(); // UI creation helpers void createLabels(); void createButtons(); void createLayouts(); void applyStyles() const; // Settings management void loadSettings(); void saveSettings() const; // Timer state management void resetTimerState(); void updateTimerState(TimerState newState); // Display update methods - optimized to avoid unnecessary updates void updateDisplay(); void updateSessionCounter() const; void updateButtonStates() const; void updateWindowTitle(); static void updateTrayTooltip(); // Utility methods static QString formatTime(int seconds); static void needsDisplayUpdate(); // UI elements - use raw pointers for Qt objects with parent ownership QTimer *m_timer; QLabel *m_timeLabel{nullptr}; QLabel *m_statusLabel{nullptr}; QLabel *m_sessionLabel{nullptr}; QPushButton *m_startButton{nullptr}; QPushButton *m_pauseButton{nullptr}; QPushButton *m_resetButton{nullptr}; QPushButton *m_settingsButton{nullptr}; QPushButton *m_skipButton{nullptr}; QPushButton *m_statsButton{nullptr}; CircularProgressBar *m_circularProgress{nullptr}; QFrame *m_mainFrame{nullptr}; // Managers - keep as unique_ptr for complex objects std::unique_ptr<SystemTrayManager> m_trayManager; std::unique_ptr<KeyboardShortcuts> m_keyboardShortcuts; std::unique_ptr<NotificationManager> m_notificationManager; // Timer state int m_currentTime{0}; int m_totalDuration{0}; TimerState m_currentState{TimerState::Work}; int m_completedSessions{0}; bool m_isRunning{false}; // Cache for reducing string operations mutable QString m_cachedTimeString; mutable int m_lastFormattedTime{-1}; // Settings int m_workDuration{DEFAULT_WORK_DURATION}; int m_shortBreakDuration{DEFAULT_SHORT_BREAK}; int m_longBreakDuration{DEFAULT_LONG_BREAK}; bool m_autoStartBreaks{false}; bool m_autoStartWork{false}; bool m_minimizeToTray{true}; bool m_showNotifications{true}; // Statistics int m_totalSessions{0}; int m_totalWorkTime{0}; int m_totalBreakTime{0}; QDateTime m_sessionStartTime; // Update tracking to prevent unnecessary redraws bool m_needsButtonUpdate{true}; bool m_needsSessionUpdate{true}; QString m_lastWindowTitle; }; #endif // POMODOROTIMER_H " />
|
||
<option name="updatedContent" value="#ifndef POMODOROTIMER_H #define POMODOROTIMER_H #include <QTimer> #include <QLabel> #include <QPushButton> #include <QFrame> #include <QDateTime> #include <memory> #include "TimerState.h" // Forward declarations class CircularProgressBar; class SettingsDialog; class StatisticsDialog; class SystemTrayManager; class KeyboardShortcuts; class NotificationManager; class PomodoroTimer : public QWidget { Q_OBJECT public: explicit PomodoroTimer(QWidget *parent = nullptr); ~PomodoroTimer() override; // Timer configuration constants static constexpr int DEFAULT_WORK_DURATION = 1500; // 25 minutes in seconds static constexpr int DEFAULT_SHORT_BREAK = 300; // 5 minutes in seconds static constexpr int DEFAULT_LONG_BREAK = 900; // 15 minutes in seconds static constexpr int SESSIONS_BEFORE_LONG_BREAK = 4; static constexpr int TIMER_INTERVAL_MS = 1000; static constexpr int AUTO_START_DELAY_MS = 3000; protected: void keyPressEvent(QKeyEvent *event) override; void closeEvent(QCloseEvent *event) override; private slots: // Timer control slots void onStartTimer(); void onPauseTimer(); void onResetTimer(); void onUpdateTimer(); void onTimerFinished(); // UI interaction slots void onShowSettings(); void onSkipSession(); void onShowStatistics(); void onToggleVisibility(); private: // Setup methods void setupUI(); void setupConnections(); // UI creation helpers void createLabels(); void createButtons(); void createLayouts(); void applyStyles() const; // Settings management void loadSettings(); void saveSettings() const; // Timer state management void resetTimerState(); void updateTimerState(TimerState newState); // Display update methods - optimized to avoid unnecessary updates void updateDisplay(); void updateSessionCounter() const; void updateButtonStates() const; void updateWindowTitle(); static void updateTrayTooltip(); // Utility methods static QString formatTime(int seconds); static void needsDisplayUpdate(); // UI elements - use raw pointers for Qt objects with parent ownership QTimer *m_timer; QLabel *m_timeLabel{nullptr}; QLabel *m_statusLabel{nullptr}; QLabel *m_sessionLabel{nullptr}; QPushButton *m_startButton{nullptr}; QPushButton *m_pauseButton{nullptr}; QPushButton *m_resetButton{nullptr}; QPushButton *m_settingsButton{nullptr}; QPushButton *m_skipButton{nullptr}; QPushButton *m_statsButton{nullptr}; CircularProgressBar *m_circularProgress{nullptr}; QFrame *m_mainFrame{nullptr}; // Managers - keep as unique_ptr for complex objects std::unique_ptr<SystemTrayManager> m_trayManager; std::unique_ptr<KeyboardShortcuts> m_keyboardShortcuts; std::unique_ptr<NotificationManager> m_notificationManager; // Timer state int m_currentTime{0}; int m_totalDuration{0}; TimerState m_currentState{TimerState::Work}; int m_completedSessions{0}; bool m_isRunning{false}; // Cache for reducing string operations mutable QString m_cachedTimeString; mutable int m_lastFormattedTime{-1}; // Settings int m_workDuration{DEFAULT_WORK_DURATION}; int m_shortBreakDuration{DEFAULT_SHORT_BREAK}; int m_longBreakDuration{DEFAULT_LONG_BREAK}; bool m_autoStartBreaks{false}; bool m_autoStartWork{false}; bool m_minimizeToTray{true}; bool m_showNotifications{true}; // Statistics int m_totalSessions{0}; int m_totalWorkTime{0}; int m_totalBreakTime{0}; QDateTime m_sessionStartTime; // Update tracking to prevent unnecessary redraws bool m_needsButtonUpdate{true}; bool m_needsSessionUpdate{true}; QString m_lastWindowTitle; }; #endif // POMODOROTIMER_H" />
|
||
</PendingDiffInfo>
|
||
</value>
|
||
</entry>
|
||
</map>
|
||
</option>
|
||
</component>
|
||
</project> |