import sys import csv import time from datetime import datetime, timedelta from pathlib import Path from pytz import timezone from playsound import playsound import pytz import zenipy WORK_MIN = 25 # Minutes for a work session SHORT_MIN = 5 # Minutes for a short break LONG_MIN = 15 # Minutes for a long break (NOT YET IMPLEMENTED) INTERRUPTED_MIN = 1 # Minimum minutes to ask to record an interrupted Pomodoro QUIET = False def pomodoro_prompt_plan(whatdid = ''): """ Ask about what task will be worked on (showing last thing worked on) """ title = "What're you gonna do?" text = '' # Instead of repeating this, i'd prefer a clean interface with the ability to get back # the placeholder text with 'esc' or up arrow or something. But i'm not up for building # my own interface, so here's what we get. NOTE: If we can do system notifications that # when clicked will focus the terminal running pomodoro prompt, that would be even better # than these pop-up GUI notifications/text entry. if whatdid: text = "\n\n(Last thing you did: " + whatdid + ')\n' whatnext = zenipy.zenipy.entry(text=text, placeholder=whatdid, title=title) # Pressing cancel returns None, but we want to just treat it as an empty string. if whatnext is None: whatnext = '' return whatnext def pomodoro_prompt_report(whatnext): """ Ask what task was completed, showing the last task claimed to be being worked on """ title = "What'd you do?" text = '' if whatnext: text = "\n\n(What you said you'd do: " + whatnext + ')\n' whatdid = zenipy.zenipy.entry(text=text, placeholder=whatnext, title=title) # Pressing cancel returns None, but we want to just treat it as an empty string. if whatdid is None: whatdid = '' return whatdid def quit_prompt(): """ Confirm exit or start a new pomodoro """ print('\nPress p to start a new pomodoro, q to quit') choice = input('p/q: ').strip().lower() if choice in ('p', 'pomodoro'): return elif choice in ('q', 'quit', 'exit'): sys.exit(0) else: quit_prompt() def log_step(text, utc_start, end_section=False): """ Write detailed log of all events """ eastern = timezone('US/Eastern') start = utc_start.astimezone(eastern) timelog_path = 'log/' + str(start.year) + '-' \ + format(start.month, '02') + '-' \ + format(start.day, '02') + '.log' timelog_file = Path(timelog_path) timelog_file.touch(exist_ok=True) with timelog_file.open('a') as timelog: timelog.write(text + '\n') if end_section: timelog.write('\n\n') def record_task(whatdid, start, end=None): """ Record completed pomodoro to CSV """ if end is None: end = datetime.now(pytz.utc) with open('timelog.csv', 'a', newline='') as csvfile: timewriter = csv.writer(csvfile) timewriter.writerow([start, end, whatdid]) def str_minutes(time_diff): """ Return at least whole seconds from a time difference """ return str(time_diff).split('.')[0] def countdown_to(until): """ Display a timer counting down to until """ while datetime.now(pytz.utc) <= until: to_go = until-datetime.now(pytz.utc) print('\r', str_minutes(to_go), sep='', end='') time.sleep(1) def main(): whatdid = '' while True: whatnext = pomodoro_prompt_plan(whatdid) start = datetime.now(pytz.utc) end = start + timedelta(minutes=WORK_MIN) log_step('Start with plan: ' + whatnext, start) try: print('Working on: ', whatnext) countdown_to(end) if not QUIET: playsound('res/timesup.aac') whatdid = pomodoro_prompt_report(whatnext) record_task(whatdid, start) log_step('Completed pomodoro: ' + whatdid, start, True) print('Worked on: ' + whatdid) print('Break time!') # We're taking a break. Clear out task start/end times. start = None end = datetime.now(pytz.utc) + timedelta(minutes=SHORT_MIN) countdown_to(end) if not QUIET: playsound('res/timesup.aac') continue except KeyboardInterrupt: if start is None: quit_prompt() continue time_spent = datetime.now(pytz.utc) - start if time_spent < timedelta(minutes=INTERRUPTED_MIN): quit_prompt() continue time_spent_str = str_minutes(time_spent) print('\n{} time spent, save?'.format(time_spent_str)) choice = input('[y]/n: ').strip() if choice.lower() in ('y', 'yes', ''): whatdid = pomodoro_prompt_report(whatnext) record_task(whatdid, start) log_step('Incomplete (' + time_spent_str + ') pomodoro: ' + whatdid, start, True) quit_prompt() else: print('What did you break?') # If we somehow end up here, try a last-ditch effort to save. record_task('Incomplete, interrupted task:' + whatnext, start) log_step('Incomplete, interrupted task:' + whatnext, start, True) if __name__ == '__main__': main()