FletとPythonで作るポモドーロ・タイマーに挑戦してみた記録

この記事は広告を含みます

はじめに

集中力の維持が難しいと感じたとき、噂のポモドーロ・タイマーのテクニックにチャレンジしてみようと考え、FletとPythonを使って自作のタイマーアプリを作ることにしました。この記事では、開発の背景や使用した技術、実装した機能、そして開発中に工夫した点などを振り返っていきます。

ポモドーロ・タイマーとは

ポモドーロ・タイマーは、1980年代にイタリアのフランチェスコ・シリロさんが考え出した方法です。名前の「ポモドーロ」はイタリア語で「トマト」という意味で、実はシリロさんがトマト型のキッチンタイマーを使って、この方法を試してみたことに由来しています。

シリロさんは、長時間ずっと勉強や作業を続けると集中力が落ちることに気づきました。そこで、短い時間だけ集中して、そのあとに短い休憩を取ることで、効率よく作業ができるのではないかと考えました。こうして、例えば25分間勉強して、その後5分間休むというサイクルを作る方法が生まれました。

つまり、ポモドーロタイマーは、勉強や仕事を効率よく進めるための時間管理ツールです。

時間を区切る:

例えば、25分間集中して勉強したら、5分間の休憩を取ります。この25分間を「ポモドーロ」と呼びます。

集中と休憩を交互に:

一度に長い時間勉強するより、短い時間集中して、短い休憩をはさむ方が頭がリフレッシュでき、効率よく学べる。

何回も繰り返す:

25分勉強して5分休む、これを何回か繰り返すことで、全体として長い時間集中できるようにる。

使用した技術と環境

  • 言語: Python
  • UIライブラリ: Flet ※Fletは、Flutterのような見た目のUIをPythonで実装できるツールで、Webアプリやデスクトップアプリの作成に適しています。

  • 開発環境: VSCodeなどお好みのエディタと、ターミナルでの実行

Python準備

以下で、Windowsストアからのインストール方法を記載しています。 kunio-ud-zatta.hatenablog.com

仮想環境用意

以下で、venv環境の作り方を記載しています。 kunio-ud-zatta.hatenablog.com

Flet のインストール

pip install flet

環境構築の確認

# main.py
import flet as ft

def main(page: ft.Page):
    page.title = "Hello, Flet!"
    page.add(ft.Text("Flet の環境構築が完了しました!"))

ft.app(target=main)

実行!!!

python main.py

※今回、手動でやってます。 本来は、flet createからのflet runです。

flet.dev

実行

作成したアプリの概要

今回作成したアプリは、シンプルながらも以下の基本機能を実装しています。

  • タイマー表示: 25分間のカウントダウンを画面上に表示
  • 操作ボタン: Start、Pause、Resetの3つのボタンで操作可能
  • バックグラウンド処理: Pythonのスレッドを利用して、UIがスムーズに動作するように工夫

サンプルコード

以下に主要なコードを抜粋してご紹介いたします。 各部分の役割も併せて解説しておりますので、実際の実装時の参考にしていただければ幸いです。

前回まで記載した関数型「風」で書いてみます。笑

kunio-ud-zatta.hatenablog.com

import time
import threading
import flet as ft
from dataclasses import dataclass, replace

# TimerStateを不変オブジェクトとして定義
@dataclass(frozen=True)
class TimerState:
    seconds_left: int
    running: bool

def tick(state: TimerState) -> TimerState:
    if state.running and state.seconds_left > 0:
        return replace(state, seconds_left=state.seconds_left - 1)
    return state

def format_time(state: TimerState) -> str:
    if state.seconds_left <= 0:
        return "Time's up!"
    mins, secs = divmod(state.seconds_left, 60)
    return f"{mins:02d}:{secs:02d}"

def main(page: ft.Page):
    page.window_width = 360
    page.window_height = 640
    page.window_resizable = False
    page.bgcolor = "#FFE5E0"
    page.title = "Pomodoro Timer"
    
    INITIAL_TIME = 25 * 60
    initial_state = TimerState(seconds_left=INITIAL_TIME, running=False)
    state_container = {"state": initial_state}
    
    timer_label = ft.Text(
        format_time(state_container["state"]),
        size=60,
        color="#FF6347"
    )

    def update_timer():
        while state_container["state"].running and state_container["state"].seconds_left > 0:
            time.sleep(1)
            new_state = tick(state_container["state"])
            state_container["state"] = new_state
            timer_label.value = format_time(new_state)
            page.update()
        if state_container["state"].seconds_left <= 0:
            state_container["state"] = replace(state_container["state"], running=False)
            timer_label.value = format_time(state_container["state"])
            page.update()

    def start_timer(e):
        if not state_container["state"].running:
            state_container["state"] = replace(state_container["state"], running=True)
            threading.Thread(target=update_timer, daemon=True).start()

    def pause_timer(e):
        if state_container["state"].running:
            state_container["state"] = replace(state_container["state"], running=False)

    def reset_timer(e):
        state_container["state"] = TimerState(seconds_left=INITIAL_TIME, running=False)
        timer_label.value = format_time(state_container["state"])
        page.update()

    start_button = ft.ElevatedButton(
        "Start", on_click=start_timer,
        bgcolor="#FF6347", color="white"
    )
    pause_button = ft.ElevatedButton(
        "Pause", on_click=pause_timer,
        bgcolor="#FF6347", color="white"
    )
    reset_button = ft.ElevatedButton(
        "Reset", on_click=reset_timer,
        bgcolor="#FF6347", color="white"
    )

    # Columnを使って上下左右に中央揃えにする
    page.add(
        ft.Column(
            [
                timer_label,
                ft.Row([start_button, pause_button, reset_button], alignment="center")
            ],
            alignment="center",
            horizontal_alignment="center",
            expand=True
        )
    )

ft.app(target=main)
実行結果

実行してみます。

ちょっと画面サイズは手動で変えてみました、、、うちのパソコンの画面が小さいので、、、

終了時

まとめ

今回のプロジェクトでは、Flet と Python を用いてポモドーロ・タイマーの作成に挑戦しました。環境構築、UI のカスタマイズを少しやってみました。 次回は、FletでAndroidビルドなどができると良いかな。。。

FletはPythonでFlutterアプリを作成できるフレームワークのようなので、Flutterそのものを学んでも良いかもしれませんね。