pomodoroprompt/pomodoroprompt.py

183 lines
6.2 KiB
Python
Raw Normal View History

import sys
import csv
import os
# This is a local script are we supposed to indicate that?
import prompt_window
2020-07-05 16:55:18 +00:00
import time
from datetime import datetime, timedelta
from pathlib import Path
from pytz import timezone
2020-07-05 16:55:18 +00:00
import pytz
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 = True
GUI = True
2020-07-05 16:55:18 +00:00
def pomodoro_prompt_plan(whatdid = ''):
""" Ask about what task will be worked on (showing last thing worked on)
"""
text = "What're you gonna do?"
# NOTE: If we can do system notifications that when clicked will focus the terminal
# running pomodoro prompt, that might be even better than the pop-up GUI text entry.
if GUI:
whatnext = prompt_window.prompt(prompt=text, task=whatdid)
else:
print(f'\n{text}')
whatnext = (input(f'({whatdid}): ' if whatdid else '').strip() or whatdid)
# Pressing cancel returns None, but we want to just treat it as an empty string.
if whatnext is None:
whatnext = ''
2020-07-05 20:00:19 +00:00
return whatnext
def pomodoro_prompt_report(whatnext):
""" Ask what task was completed, showing the last task claimed to be being worked on
"""
text = "What'd you do?"
if GUI:
whatdid = prompt_window.prompt(prompt=text, task=whatnext)
else:
print(f'\n{text}')
whatdid = (input(f'({whatnext}): ' if whatnext else '').strip() or whatnext)
# Pressing cancel returns None, but we want to just treat it as an empty string.
if whatdid is None:
whatdid = ''
2020-07-05 20:00:19 +00:00
return whatdid
2020-07-05 16:55:18 +00:00
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
"""
timelog_file = Path(prepare_file(utc_start, ext='log', daily=True))
timelog_file.touch(exist_ok=True)
with timelog_file.open('a') as timelog:
2020-07-06 12:48:24 +00:00
timelog.write(text + '\n')
2020-07-06 12:43:56 +00:00
if end_section:
2020-07-06 12:48:24 +00:00
timelog.write('\n\n')
def record_task(whatnext, whatdid, start, end=None):
""" Record completed pomodoro to CSV
"""
if end is None:
end = datetime.now(pytz.utc)
filepath = prepare_file(start)
if not os.path.isfile(filepath):
with open(filepath, 'w', newline='') as csvfile:
log = csv.writer(csvfile)
2021-05-02 21:51:08 +00:00
log.writerow(['started', 'recorded', 'description', 'intention'])
with open(filepath, 'a', newline='') as csvfile:
2021-05-02 22:27:25 +00:00
log = csv.writer(csvfile)
log.writerow([start, end, whatdid, whatnext])
2020-07-05 16:55:18 +00:00
2020-07-06 12:43:56 +00:00
def str_minutes(time_diff):
""" Return at least whole seconds from a time difference
"""
2020-07-06 12:43:56 +00:00
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)
2020-07-05 16:55:18 +00:00
def prepare_file(utc_start, ext='csv', daily=False):
# Save timelogs relative to script directory (NOT from where called)
logpath = os.path.dirname(os.path.realpath(__file__)) + '/log'
# Ensure log directory exists.
if not os.path.exists(logpath):
os.makedirs(logpath)
# We consider 3am the switchover to a new day, so we skip extra math
# and use Pacific time to get three hours later than our Eastern time.
logpath_tz = timezone('America/Los_Angeles')
logpath_date = utc_start.astimezone(logpath_tz)
timelog_path = logpath + '/' + str(logpath_date.year);
if (daily):
timelog_path += '-' \
+ format(logpath_date.month, '02') + '-' \
2021-05-02 23:19:57 +00:00
+ format(logpath_date.day, '02')
timelog_path += '.' + ext
return timelog_path
def bing():
if GUI:
from playsound import playsound
playsound('res/timesup.aac')
else:
sys.stdout.write('\a')
sys.stdout.flush()
2020-07-05 16:55:18 +00:00
def main():
whatdid = ''
global GUI, QUIET
if "--no-gui" in sys.argv:
GUI = False
if "--noisy" in sys.argv:
QUIET = False
while True:
whatnext = pomodoro_prompt_plan(whatdid)
start = datetime.now(pytz.utc)
2020-07-06 13:27:00 +00:00
end = start + timedelta(minutes=WORK_MIN)
2020-07-06 12:43:56 +00:00
log_step('Start with plan: ' + whatnext, start)
try:
print('Working on: ' + whatnext)
countdown_to(end)
2020-10-10 04:20:18 +00:00
if not QUIET:
bing()
whatdid = pomodoro_prompt_report(whatnext)
record_task(whatnext, whatdid, start)
2020-07-06 12:43:56 +00:00
log_step('Completed pomodoro: ' + whatdid, start, True)
print('\nWorked 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)
2020-10-10 04:20:18 +00:00
if not QUIET:
bing()
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(whatnext, 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(whatnext, 'Incomplete, interrupted task:' + whatnext, start)
2020-07-06 12:43:56 +00:00
log_step('Incomplete, interrupted task:' + whatnext, start, True)
2020-07-05 16:55:18 +00:00
if __name__ == '__main__':
main()