commit
8b1738be28
7 changed files with 165 additions and 0 deletions
@ -0,0 +1,2 @@ |
|||
*.egg-info |
|||
__pycache__ |
@ -0,0 +1 @@ |
|||
version = "0.1.0" |
@ -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() |
@ -0,0 +1 @@ |
|||
rich>=13.8.0 |
@ -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 protected]', |
|||
entry_points={ |
|||
'console_scripts': [ |
|||
'pom = pom.script:main' |
|||
], |
|||
}, |
|||
) |
Loading…
Reference in new issue