diff --git a/PomodoroConfig.cpp b/PomodoroConfig.cpp new file mode 100644 index 0000000..eae163b --- /dev/null +++ b/PomodoroConfig.cpp @@ -0,0 +1,124 @@ +#include "PomodoroConfig.h" +#include +#include + +PomodoroConfig& PomodoroConfig::instance() +{ + static PomodoroConfig config; + return config; +} + +PomodoroConfig::PomodoroConfig() +{ + const QString configPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation); + const QString appConfigDir = configPath + "/PomodoroTimer"; + + QDir().mkpath(appConfigDir); + + m_settings = std::make_unique( + appConfigDir + "/config.ini", + QSettings::IniFormat + ); + + loadSettings(); +} + +void PomodoroConfig::setWorkDuration(int seconds) +{ + if (seconds > 0 && seconds != m_workDuration) { + m_workDuration = seconds; + saveSettings(); + } +} + +void PomodoroConfig::setShortBreakDuration(int seconds) +{ + if (seconds > 0 && seconds != m_shortBreakDuration) { + m_shortBreakDuration = seconds; + saveSettings(); + } +} + +void PomodoroConfig::setLongBreakDuration(int seconds) +{ + if (seconds > 0 && seconds != m_longBreakDuration) { + m_longBreakDuration = seconds; + saveSettings(); + } +} + +void PomodoroConfig::setShowNotifications(bool enabled) +{ + if (enabled != m_showNotifications) { + m_showNotifications = enabled; + saveSettings(); + } +} + +void PomodoroConfig::setAutoStartBreaks(bool enabled) +{ + if (enabled != m_autoStartBreaks) { + m_autoStartBreaks = enabled; + saveSettings(); + } +} + +void PomodoroConfig::setWorkEndSound(const QString& soundPath) +{ + if (soundPath != m_workEndSound) { + m_workEndSound = soundPath; + saveSettings(); + } +} + +void PomodoroConfig::setBreakEndSound(const QString& soundPath) +{ + if (soundPath != m_breakEndSound) { + m_breakEndSound = soundPath; + saveSettings(); + } +} + +void PomodoroConfig::saveSettings() +{ + if (!m_settings) return; + + m_settings->beginGroup("Timer"); + m_settings->setValue("workDuration", m_workDuration); + m_settings->setValue("shortBreakDuration", m_shortBreakDuration); + m_settings->setValue("longBreakDuration", m_longBreakDuration); + m_settings->endGroup(); + + m_settings->beginGroup("UI"); + m_settings->setValue("showNotifications", m_showNotifications); + m_settings->setValue("autoStartBreaks", m_autoStartBreaks); + m_settings->endGroup(); + + m_settings->beginGroup("Sound"); + m_settings->setValue("workEndSound", m_workEndSound); + m_settings->setValue("breakEndSound", m_breakEndSound); + m_settings->endGroup(); + + m_settings->sync(); +} + +void PomodoroConfig::loadSettings() +{ + if (!m_settings) return; + + m_settings->beginGroup("Timer"); + m_workDuration = m_settings->value("workDuration", DEFAULT_WORK_DURATION).toInt(); + m_shortBreakDuration = m_settings->value("shortBreakDuration", DEFAULT_SHORT_BREAK).toInt(); + m_longBreakDuration = m_settings->value("longBreakDuration", DEFAULT_LONG_BREAK).toInt(); + m_settings->endGroup(); + + m_settings->beginGroup("UI"); + m_showNotifications = m_settings->value("showNotifications", true).toBool(); + m_autoStartBreaks = m_settings->value("autoStartBreaks", false).toBool(); + m_settings->endGroup(); + + m_settings->beginGroup("Sound"); + m_workEndSound = m_settings->value("workEndSound", QString()).toString(); + m_breakEndSound = m_settings->value("breakEndSound", QString()).toString(); + m_settings->endGroup(); +} diff --git a/PomodoroConfig.h b/PomodoroConfig.h new file mode 100644 index 0000000..ce86c40 --- /dev/null +++ b/PomodoroConfig.h @@ -0,0 +1,70 @@ +#ifndef POMODOROCONFIG_H +#define POMODOROCONFIG_H + +#include +#include +#include + +class PomodoroConfig +{ +public: + static PomodoroConfig& instance(); + + // Timer durations (in seconds) + int workDuration() const { return m_workDuration; } + int shortBreakDuration() const { return m_shortBreakDuration; } + int longBreakDuration() const { return m_longBreakDuration; } + + void setWorkDuration(int seconds); + void setShortBreakDuration(int seconds); + void setLongBreakDuration(int seconds); + + // UI settings + bool showNotifications() const { return m_showNotifications; } + void setShowNotifications(bool enabled); + + bool autoStartBreaks() const { return m_autoStartBreaks; } + void setAutoStartBreaks(bool enabled); + + // Sound settings + QString workEndSound() const { return m_workEndSound; } + QString breakEndSound() const { return m_breakEndSound; } + void setWorkEndSound(const QString& soundPath); + void setBreakEndSound(const QString& soundPath); + + // Constants + static constexpr int DEFAULT_WORK_DURATION = 1500; // 25 minutes + static constexpr int DEFAULT_SHORT_BREAK = 300; // 5 minutes + static constexpr int DEFAULT_LONG_BREAK = 900; // 15 minutes + static constexpr int SESSIONS_BEFORE_LONG_BREAK = 4; + + void saveSettings(); + void loadSettings(); + +private: + PomodoroConfig(); + ~PomodoroConfig() = default; + + // Disable copy/move + PomodoroConfig(const PomodoroConfig&) = delete; + PomodoroConfig& operator=(const PomodoroConfig&) = delete; + PomodoroConfig(PomodoroConfig&&) = delete; + PomodoroConfig& operator=(PomodoroConfig&&) = delete; + + std::unique_ptr m_settings; + + // Timer settings + int m_workDuration = DEFAULT_WORK_DURATION; + int m_shortBreakDuration = DEFAULT_SHORT_BREAK; + int m_longBreakDuration = DEFAULT_LONG_BREAK; + + // UI settings + bool m_showNotifications = true; + bool m_autoStartBreaks = false; + + // Sound settings + QString m_workEndSound; + QString m_breakEndSound; +}; + +#endif // POMODOROCONFIG_H diff --git a/TimerController.cpp b/TimerController.cpp new file mode 100644 index 0000000..e5d0be3 --- /dev/null +++ b/TimerController.cpp @@ -0,0 +1,111 @@ +#include "TimerController.h" +#include + +TimerController::TimerController(QObject *parent) + : QObject(parent) + , m_timer(std::make_unique(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(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; + } +} diff --git a/TimerController.h b/TimerController.h new file mode 100644 index 0000000..c64679c --- /dev/null +++ b/TimerController.h @@ -0,0 +1,81 @@ +#ifndef TIMERCONTROLLER_H +#define TIMERCONTROLLER_H + +#include +#include +#include +#include + +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 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 diff --git a/logoTimer.png b/logoTimer.png new file mode 100644 index 0000000..3197707 Binary files /dev/null and b/logoTimer.png differ