From 8b1738be28a62fa4cec83e09ce54f966fb6350b7 Mon Sep 17 00:00:00 2001 From: Gregory Leeman Date: Tue, 24 Sep 2024 17:24:34 +0100 Subject: [PATCH] first commit --- .gitignore | 2 + README.md | 0 pom/__init__.py | 0 pom/__version__.py | 1 + pom/script.py | 133 +++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 1 + setup.py | 28 ++++++++++ 7 files changed, 165 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 pom/__init__.py create mode 100644 pom/__version__.py create mode 100755 pom/script.py create mode 100644 requirements.txt create mode 100644 setup.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c14b1f1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.egg-info +__pycache__ diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/pom/__init__.py b/pom/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pom/__version__.py b/pom/__version__.py new file mode 100644 index 0000000..9f7a875 --- /dev/null +++ b/pom/__version__.py @@ -0,0 +1 @@ +version = "0.1.0" diff --git a/pom/script.py b/pom/script.py new file mode 100755 index 0000000..576f565 --- /dev/null +++ b/pom/script.py @@ -0,0 +1,133 @@ +#!/Users/gl6/env/bin/python + +import os +import sys +import time +from datetime import datetime, timedelta +import subprocess +from pathlib import Path +import argparse +from rich.console import Console +from rich.live import Live +from rich.theme import Theme + +ALARM_SOUND = os.path.expanduser("~/.pom/alarm.mp3") +ICON_IMAGE = os.path.expanduser("~/.pom/icon.png") +HISTORY_FILE = os.path.expanduser("~/.pom/history.txt") + +solarized_theme = Theme({ + "orange": "#cb4b16", + "violet": "#6c71c4", +}) + +console = Console(highlight=False, theme=solarized_theme) + + +def notify(): + console.print("Pomodoro finished!\a") + subprocess.run([ + "osascript", "-e", + f'display dialog "Pomodoro finished!" with title "Pomodoro" buttons {{"OK"}} default button "OK" with icon POSIX file "{ICON_IMAGE}"' + ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + +def get_ordinal(n): + if 10 <= n % 100 <= 20: + suffix = 'th' + else: + suffix = {1: 'st', 2: 'nd', 3: 'rd'}.get(n % 10, 'th') + return str(n) + suffix + + +def countdown(seconds, task): + with Live(console=console, refresh_per_second=4) as live: + while seconds > 0: + h, m, s = seconds // 3600, (seconds // 60) % 60, seconds % 60 + live.update(f"[orange]{h:02}:{m:02}:{s:02}[/] [white]{task}[/]") + time.sleep(1) + seconds -= 1 + console.print() + + +def record_task(seconds, task): + now = datetime.now() + date = now.strftime(f"%a {get_ordinal(now.day)} %B") + start_time = now.strftime("%H:%M") + end_time = (now + timedelta(seconds=seconds)).strftime("%H:%M") + h, m, s = seconds // 3600, (seconds // 60) % 60, seconds % 60 + with open(HISTORY_FILE, "a") as f: + f.write(f"{date} {start_time}>>{end_time} {h:02}:{m:02} {task}\n") + + +def show_history(): + if not Path(HISTORY_FILE).exists(): + console.print("No history found.") + else: + with open(HISTORY_FILE, "r") as f: + for line in f: + day, date, month, time, pom, task = line.strip().split(" ", 5) + content, note = task.split(" - ", 1) if " - " in task else (task, "") + note = "- " + note if note else "" + console.print(f"[blue]{day} {date} {month}[/] [green]{time}[/] [orange]{pom}[/] [white]{content}[/] [red]{note}[/]", highlight=False) + + +def clear_history(): + with open(HISTORY_FILE, "w") as f: + f.write("") + + +def edit_history(): + if not Path(HISTORY_FILE).exists(): + console.print("No history found.") + else: + subprocess.run(["vim", HISTORY_FILE]) + + +def main(): + parser = argparse.ArgumentParser(description="Pomodoro CLI tool.") + subparsers = parser.add_subparsers(dest="command") + + start_parser = subparsers.add_parser("start", help="Start a Pomodoro session.") + start_parser.add_argument("task", type=str, help="Task description.") + start_parser.add_argument("minutes", type=int, nargs="?", default=25, help="Duration of the Pomodoro in minutes.") + + subparsers.add_parser("show", help="Show Pomodoro history.") + subparsers.add_parser("clear", help="Clear Pomodoro history.") + subparsers.add_parser("edit", help="Edit Pomodoro history.") + + args = parser.parse_args() + + if not args.command: + parser.print_help() + sys.exit(1) + + if args.command == "start": + task = args.task + minutes = args.minutes + seconds = minutes * 60 + + try: + console.clear() + countdown(seconds, task) + notify() + record_task(seconds, task) + except KeyboardInterrupt: + record_task(seconds, f"{task} - cancelled") + sys.exit(0) + + elif args.command == "show": + show_history() + + elif args.command == "clear": + clear_history() + + elif args.command == "edit": + edit_history() + + else: + console.print("Invalid command") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e457314 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +rich>=13.8.0 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..7df77a6 --- /dev/null +++ b/setup.py @@ -0,0 +1,28 @@ +from setuptools import setup + +with open('README.md', 'r') as f: + long_description = f.read() + +with open('requirements.txt') as f: + requirements = f.read().splitlines() + +with open('pom/__version__.py') as f: + version_info = {} + exec(f.read(), version_info) + version = version_info['version'] + +setup( + name='pom', + version=version, + packages=['pom'], + install_requires=requirements, + description='A command line Pomodoro timer', + long_description=long_description, + author='Gregory Leeman', + author_email='email@gregoryleeman.com', + entry_points={ + 'console_scripts': [ + 'pom = pom.script:main' + ], + }, +)