PythonでPomodoroタイマーを作ってみた

### 前置き
ポモドーロテクニックとは、仕事を25分ずつのセッションに分け、その間に短い休憩を挟んで行う時間管理術だ。今日は、PythonでPomodoroタイマーをどのように作るか紹介したい。一般的には、25分ごとに5分の休憩を取り、100分ごとに少し長い休憩(15分〜30分)を取る。

引用元：https://asana.com/ja/resources/pomodoro-technique

### プログラムコード
``` python
from tkinter import *
import math
# ---------------------------- CONSTANTS ------------------------------- #
PINK = "#e2979c"
RED = "#e7305b"
GREEN = "#9bdeac"
YELLOW = "#f7f5dd"
FONT_NAME = "Courier"
WORK_MIN = 25
SHORT_BREAK_MIN = 5
LONG_BREAK_MIN = 20
reps = 0
timer = None

# ---------------------------- TIMER RESET ------------------------------- # 
def reset_timer():
  window.after_cancel(timer)
  canvas.itemconfig(timer_text, text = "00:00")
  title_label.config(text = "Timer")
  check_marks.config(text = "")
  global reps
  reps = 0
# ---------------------------- TIMER MECHANISM ------------------------------- # 
def start_timer():
  global reps
  reps += 1
  
  work_sec = WORK_MIN * 60
  short_break_sec = SHORT_BREAK_MIN * 60
  long_break_sec = LONG_BREAK_MIN * 60
  
  # 1st, 3th, 5th, 7th rep
  if reps % 8 == 0:
    count_down(long_break_sec)
    title_label.config(text= "Break", fg = RED)
  elif reps % 2 == 0:
    count_down(short_break_sec)
    title_label.config(text= "Break", fg = PINK)
  else:
    count_down(work_sec)
    title_label.config(text = "Work", fg = GREEN)
    
# ---------------------------- COUNTDOWN MECHANISM ------------------------------- # 
# count down from 5 mins to 0
def count_down(count):

  count_min = math.floor(count / 60)
  count_sec = count % 60 
  if count_sec < 10:
     count_sec = f"0{count_sec}"

  canvas.itemconfig(timer_text, text = f"{count_min}:{count_sec}")  
  if count > 0:
    global timer
    timer = window.after(1000, lambda: count_down(count - 1))
  else:
    start_timer()
    marks = ""
    work_sessions = math.floor(reps/2)
    for _ in range(work_sessions):
      marks += "✓"
    check_marks.config(text = marks)
# ---------------------------- UI SETUP ------------------------------- #
window = Tk()
window.title("Pomodoro Timer")
#change background
window.config(padx=100, pady = 50, bg = YELLOW)

# make the title
title_label = Label(text = "Timer", fg = GREEN, bg = YELLOW, font = (FONT_NAME , 50))
title_label.grid(column = 1, row = 0)

canvas = Canvas(width = 200, height = 224, bg = YELLOW, highlightthickness=0)
tomato_img = PhotoImage(file = "tomato.png")
canvas.create_image(100,112, image = tomato_img)
timer_text = canvas.create_text(100,130, text = "00:00", fill = "white", font = (FONT_NAME , 35, "bold"))
canvas.grid(column = 1, row = 1)

start_button = Button(text = "Start", highlightthickness = 0, command = start_timer)
start_button.grid(column = 0, row = 2)

reset_button = Button(text = "Reset", highlightthickness = 0, command = reset_timer)
reset_button.grid(column = 2, row = 2)

check_marks = Label(text = "✓", fg = GREEN, bg = YELLOW)
check_marks.grid(column = 1, row = 2)

window.mainloop()
```

### プログラムコードの説明
ここでは、Tkinterという、PythonでGUI(Graphical User Interface) を組むことができるツールキットを使い、トマトの画像にタイマーが残り何分、その時にはWorkが上に表示される。休憩に入れば、Breakと休憩が残り何分か表示される。

### 出力結果
![Screenshot 2024-06-27 at 16.26.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518583/47cd797a-68aa-8b42-2fd3-87d2d90c7f2e.png)

Resetを押したら、下の写真のように、タイマーが元に戻る。
![Screenshot 2024-06-27 at 16.26.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518583/92ea46a4-6b60-10d5-164c-5790e99b3f3a.png)

25分経過したら、ちゃんとBreakの画面に切り替わった。
![Screenshot 2024-06-27 at 16.55.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518583/d5286c4f-127b-3de5-a342-34ae4f6fb89c.png)

そして、5分のBreakが終了したら、ちゃんとWorkの画面に切り替わった。
![Screenshot 2024-06-27 at 17.01.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518583/88c01884-26b4-b3f2-9ca6-9d0561fa2f53.png)

終了したい場合には、Resetと入力したら、このように、元通りに戻る。
![Screenshot 2024-06-27 at 17.02.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518583/f5b4929a-32f9-e96a-a025-722bf780d668.png)

皆さんも仕事の効率性を上げるために、このプログラムコードを参考にしながら、Pomodoroタイマーというテクニックを活用してみてはいかがでしょうか。