1 | #include "PomodoroButton.h" |
2 | |
3 | #include <GitQlientSettings.h> |
4 | #include <GitBase.h> |
5 | #include <PomodoroConfigDlg.h> |
6 | |
7 | #include <QTime> |
8 | #include <QToolButton> |
9 | #include <QLabel> |
10 | #include <QMenu> |
11 | #include <QVBoxLayout> |
12 | #include <QMouseEvent> |
13 | #include <QTimer> |
14 | #include <QMessageBox> |
15 | #include <QStyle> |
16 | |
17 | PomodoroButton::PomodoroButton(const QSharedPointer<GitBase> &git, QWidget *parent) |
18 | : QFrame(parent) |
19 | , mGit(git) |
20 | , mButton(new QToolButton()) |
21 | , mArrow(new QToolButton()) |
22 | , mCounter(new QLabel()) |
23 | , mTimer(new QTimer(this)) |
24 | { |
25 | setContentsMargins(0, 0, 0, 0); |
26 | setToolTip(tr("Pomodoro" )); |
27 | |
28 | const auto = new QMenu(mButton); |
29 | menu->installEventFilter(this); |
30 | mConfigAction = menu->addAction(tr("Options..." )); |
31 | connect(mConfigAction, &QAction::triggered, this, &PomodoroButton::showConfig); |
32 | |
33 | mButton->setIcon(QIcon(":/icons/pomodoro" )); |
34 | mButton->setIconSize(QSize(22, 22)); |
35 | mButton->setToolButtonStyle(Qt::ToolButtonIconOnly); |
36 | mButton->setObjectName("ToolButtonAboveMenu" ); |
37 | connect(mButton, &QToolButton::clicked, this, &PomodoroButton::onClick); |
38 | |
39 | mArrow->setObjectName("Arrow" ); |
40 | mArrow->setIcon(QIcon(":/icons/arrow_down" )); |
41 | mArrow->setIconSize(QSize(10, 10)); |
42 | mArrow->setToolButtonStyle(Qt::ToolButtonIconOnly); |
43 | mArrow->setToolTip(tr("Options" )); |
44 | mArrow->setPopupMode(QToolButton::InstantPopup); |
45 | mArrow->setMenu(menu); |
46 | mArrow->setFixedWidth(10); |
47 | mArrow->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); |
48 | |
49 | GitQlientSettings settings(mGit->getGitDir()); |
50 | const auto durationMins = settings.localValue("Pomodoro/Duration" , 25).toInt(); |
51 | mDurationTime = QTime(0, durationMins, 0); |
52 | mCounter->setText(mDurationTime.toString("mm:ss" )); |
53 | |
54 | const auto breakMins = settings.localValue("Pomodoro/Break" , 5).toInt(); |
55 | mBreakTime = QTime(0, breakMins, 0); |
56 | |
57 | const auto longBreakMins = settings.localValue("Pomodoro/LongBreak" , 15).toInt(); |
58 | mLongBreakTime = QTime(0, longBreakMins, 0); |
59 | |
60 | mBigBreakCount = settings.localValue("Pomodoro/LongBreakTrigger" , 4).toInt(); |
61 | |
62 | mStopResets = settings.localValue("Pomodoro/StopResets" , true).toBool(); |
63 | |
64 | mTimer->setInterval(1000); |
65 | connect(mTimer, &QTimer::timeout, this, &PomodoroButton::onTimeout); |
66 | |
67 | const auto layout = new QGridLayout(this); |
68 | layout->setContentsMargins(QMargins()); |
69 | layout->setSpacing(0); |
70 | layout->addWidget(mButton, 0, 0); |
71 | layout->addWidget(mCounter, 1, 0); |
72 | layout->addWidget(mArrow, 0, 1, 2, 1); |
73 | } |
74 | |
75 | void PomodoroButton::setText(const QString &text) |
76 | { |
77 | mCounter->setText(text); |
78 | } |
79 | |
80 | void PomodoroButton::updateCounters() |
81 | { |
82 | mState = State::OnHold; |
83 | mTimer->stop(); |
84 | mButton->setIcon(QIcon(":/icons/pomodoro" )); |
85 | |
86 | GitQlientSettings settings(mGit->getGitDir()); |
87 | |
88 | const auto durationMins = settings.localValue("Pomodoro/Duration" , 25).toInt(); |
89 | mDurationTime = QTime(0, durationMins, 0); |
90 | mCounter->setText(mDurationTime.toString("mm:ss" )); |
91 | |
92 | const auto breakMins = settings.localValue("Pomodoro/Break" , 5).toInt(); |
93 | mBreakTime = QTime(0, breakMins, 0); |
94 | |
95 | const auto longBreakMins = settings.localValue("Pomodoro/LongBreak" , 15).toInt(); |
96 | mLongBreakTime = QTime(0, longBreakMins, 0); |
97 | |
98 | const auto longBreakTriggerCount = settings.localValue("Pomodoro/LongBreakTrigger" , 4).toInt(); |
99 | |
100 | mStopResets = settings.localValue("Pomodoro/StopResets" , true).toBool(); |
101 | |
102 | if (longBreakTriggerCount < mBigBreakOriginalValue) |
103 | { |
104 | mBigBreakOriginalValue = longBreakTriggerCount; |
105 | mBigBreakCount = longBreakTriggerCount; |
106 | } |
107 | else |
108 | { |
109 | mBigBreakCount = longBreakTriggerCount - (mBigBreakOriginalValue - mBigBreakCount); |
110 | mBigBreakOriginalValue = longBreakTriggerCount; |
111 | } |
112 | } |
113 | |
114 | void PomodoroButton::setRunningMode() |
115 | { |
116 | style()->unpolish(this); |
117 | setProperty("checked" , true); |
118 | style()->polish(this); |
119 | mState = State::Running; |
120 | mTimer->start(); |
121 | mButton->setIcon(QIcon(":/icons/pomodoro_running" )); |
122 | --mBigBreakCount; |
123 | } |
124 | |
125 | void PomodoroButton::mousePressEvent(QMouseEvent *e) |
126 | { |
127 | if (isEnabled()) |
128 | mPressed = true; |
129 | |
130 | QFrame::mousePressEvent(e); |
131 | } |
132 | |
133 | void PomodoroButton::mouseReleaseEvent(QMouseEvent *e) |
134 | { |
135 | if (isEnabled() && mPressed) |
136 | { |
137 | onClick(); |
138 | |
139 | emit clicked(); |
140 | } |
141 | |
142 | QFrame::mouseReleaseEvent(e); |
143 | } |
144 | |
145 | bool PomodoroButton::eventFilter(QObject *obj, QEvent *event) |
146 | { |
147 | if (const auto = qobject_cast<QMenu *>(obj); menu && event->type() == QEvent::Show) |
148 | { |
149 | auto localPos = mButton->pos(); |
150 | localPos.setX(localPos.x()); |
151 | auto pos = mapToGlobal(localPos); |
152 | menu->show(); |
153 | pos.setY(pos.y() + height()); |
154 | menu->move(pos); |
155 | |
156 | return true; |
157 | } |
158 | |
159 | return false; |
160 | } |
161 | |
162 | void PomodoroButton::onTimeout() |
163 | { |
164 | if (mState == State::Running) |
165 | onRunningMode(); |
166 | else if (mState == State::InBreakRunning) |
167 | onBreakingMode(); |
168 | else if (mState == State::InLongBreakRunning) |
169 | onLongBreakingMode(); |
170 | } |
171 | |
172 | void PomodoroButton::onClick() |
173 | { |
174 | switch (mState) |
175 | { |
176 | case State::OnHold: |
177 | case State::Finished: |
178 | setRunningMode(); |
179 | break; |
180 | case State::InBreak: |
181 | style()->unpolish(this); |
182 | setProperty("checked" , true); |
183 | style()->polish(this); |
184 | mState = State::InBreakRunning; |
185 | mTimer->start(); |
186 | break; |
187 | case State::InLongBreak: |
188 | style()->unpolish(this); |
189 | setProperty("checked" , true); |
190 | style()->polish(this); |
191 | mState = State::InLongBreakRunning; |
192 | mTimer->start(); |
193 | break; |
194 | case State::InBreakRunning: |
195 | case State::InLongBreakRunning: |
196 | setRunningMode(); |
197 | break; |
198 | case State::Running: |
199 | style()->unpolish(this); |
200 | setProperty("checked" , false); |
201 | style()->polish(this); |
202 | mState = State::OnHold; |
203 | mTimer->stop(); |
204 | mButton->setIcon(QIcon(":/icons/pomodoro" )); |
205 | |
206 | if (mStopResets) |
207 | { |
208 | GitQlientSettings settings(mGit->getGitDir()); |
209 | const auto durationMins = settings.localValue("Pomodoro/Duration" , 25).toInt(); |
210 | mDurationTime = QTime(0, durationMins, 0); |
211 | mCounter->setText(mDurationTime.toString("mm:ss" )); |
212 | } |
213 | |
214 | ++mBigBreakCount; |
215 | break; |
216 | } |
217 | } |
218 | |
219 | void PomodoroButton::onRunningMode() |
220 | { |
221 | mDurationTime = mDurationTime.addSecs(-1); |
222 | mCounter->setText(mDurationTime.toString("mm:ss" )); |
223 | |
224 | if (mDurationTime == QTime(0, 0, 0)) |
225 | { |
226 | mTimer->stop(); |
227 | |
228 | GitQlientSettings settings(mGit->getGitDir()); |
229 | const auto durationMins = settings.localValue("Pomodoro/Duration" , 25).toInt(); |
230 | mDurationTime = QTime(0, durationMins, 0); |
231 | |
232 | mButton->setIcon(QIcon(":/icons/pomodoro_timeout" )); |
233 | |
234 | const auto breakMins = settings.localValue("Pomodoro/Break" , 5).toInt(); |
235 | mBreakTime = QTime(0, breakMins, 0); |
236 | |
237 | const auto longBreakMins = settings.localValue("Pomodoro/LongBreak" , 15).toInt(); |
238 | mLongBreakTime = QTime(0, longBreakMins, 0); |
239 | |
240 | if (mBigBreakCount <= 0) |
241 | { |
242 | mBigBreakCount = settings.localValue("Pomodoro/LongBreakTrigger" , 4).toInt(); |
243 | |
244 | mCounter->setText(mLongBreakTime.toString("mm:ss" )); |
245 | } |
246 | else |
247 | mCounter->setText(mBreakTime.toString("mm:ss" )); |
248 | |
249 | if (QMessageBox::question(this, tr("Time for a break!" ), tr("It's time to do a break. Are you ready?" )) |
250 | == QMessageBox::Yes) |
251 | { |
252 | if (mBigBreakCount == 0) |
253 | mState = State::InLongBreakRunning; |
254 | else |
255 | mState = State::InBreakRunning; |
256 | |
257 | mTimer->start(); |
258 | } |
259 | else |
260 | { |
261 | style()->unpolish(this); |
262 | setProperty("checked" , false); |
263 | style()->polish(this); |
264 | |
265 | if (mBigBreakCount == 0) |
266 | mState = State::InLongBreak; |
267 | else |
268 | mState = State::InBreak; |
269 | } |
270 | } |
271 | } |
272 | |
273 | void PomodoroButton::onBreakingMode() |
274 | { |
275 | mBreakTime = mBreakTime.addSecs(-1); |
276 | mCounter->setText(mBreakTime.toString("mm:ss" )); |
277 | |
278 | if (mBreakTime == QTime(0, 0, 0)) |
279 | { |
280 | mTimer->stop(); |
281 | |
282 | GitQlientSettings settings(mGit->getGitDir()); |
283 | const auto breakMins = settings.localValue("Pomodoro/Break" , 5).toInt(); |
284 | mBreakTime = QTime(0, breakMins, 0); |
285 | |
286 | mState = State::Finished; |
287 | |
288 | const auto answer |
289 | = QMessageBox::question(this, tr("Time to work!" ), tr("It's time to go back to work. Are you ready?" )); |
290 | |
291 | if (answer == QMessageBox::Yes) |
292 | { |
293 | mCounter->setText(mDurationTime.toString("mm:ss" )); |
294 | setRunningMode(); |
295 | } |
296 | else |
297 | { |
298 | style()->unpolish(this); |
299 | setProperty("checked" , false); |
300 | style()->polish(this); |
301 | } |
302 | } |
303 | } |
304 | |
305 | void PomodoroButton::onLongBreakingMode() |
306 | { |
307 | mLongBreakTime = mLongBreakTime.addSecs(-1); |
308 | mCounter->setText(mLongBreakTime.toString("mm:ss" )); |
309 | |
310 | if (mLongBreakTime == QTime(0, 0, 0)) |
311 | { |
312 | mTimer->stop(); |
313 | |
314 | GitQlientSettings settings(mGit->getGitDir()); |
315 | const auto breakMins = settings.localValue("Pomodoro/LongBreak" , 15).toInt(); |
316 | mLongBreakTime = QTime(0, breakMins, 0); |
317 | |
318 | mState = State::Finished; |
319 | |
320 | const auto answer |
321 | = QMessageBox::question(this, tr("Time to work!" ), tr("It's time to go back to work. Are you ready?" )); |
322 | |
323 | if (answer == QMessageBox::Yes) |
324 | { |
325 | mCounter->setText(mDurationTime.toString("mm:ss" )); |
326 | setRunningMode(); |
327 | } |
328 | else |
329 | { |
330 | style()->unpolish(this); |
331 | setProperty("checked" , false); |
332 | style()->polish(this); |
333 | } |
334 | } |
335 | } |
336 | |
337 | void PomodoroButton::showConfig() |
338 | { |
339 | const auto dlg = new PomodoroConfigDlg(mGit, this); |
340 | |
341 | connect(dlg, &PomodoroConfigDlg::finished, this, [this](int result) { |
342 | if (result == QDialog::Accepted) |
343 | updateCounters(); |
344 | }); |
345 | |
346 | dlg->open(); |
347 | } |
348 | |