# pylint: disable=C0111,R0903 """Display and run a Pomodoro timer. Left click to start timer, left click again to pause. Right click will cancel the timer. Parameters: * pomodoro.work: The work duration of timer in minutes (defaults to 25) * pomodoro.break: The break duration of timer in minutes (defaults to 5) * pomodoro.format: Timer display format with '%m' and '%s' for minutes and seconds (defaults to '%m:%s') Examples: '%m min %s sec', '%mm', '', 'timer' * pomodoro.notify: Notification command to run when timer ends/starts (defaults to nothing) Example: 'notify-send 'Time up!''. If you want to chain multiple commands, please use an external wrapper script and invoke that. The module itself does not support command chaining (see https://github.com/tobi-wan-kenobi/bumblebee-status/issues/532 for a detailed explanation) If you want pomodoro timer to signalize the end of the work and rest session, put the path to your audio file in the sound variable at the beginning of pomodoro.py. contributed by `martindoublem `_, inspired by `karthink `_ - many thanks! """ from __future__ import absolute_import import datetime from math import ceil import core.module import core.widget import core.input import simpleaudio as sa import util.cli # Recommended to use .wav format sound= "path/to/musicfile" class Module(core.module.Module): def __init__(self, config, theme): super().__init__(config, theme, core.widget.Widget(self.text)) # Parameters self.__work_period = int(self.parameter("work", 25)) self.__break_period = int(self.parameter("break", 5)) self.__time_format = self.parameter("format", "%m:%s") self.__notify_cmd = self.parameter("notify", "") # TODO: Handle time formats more gracefully. This is kludge. self.display_seconds_p = False self.display_minutes_p = False if "%s" in self.__time_format: self.display_seconds_p = True if "%m" in self.__time_format: self.display_minutes_p = True self.remaining_time = datetime.timedelta(minutes=self.__work_period) self.time = None self.pomodoro = {"state": "OFF", "type": ""} self.__text = self.remaining_time_str() + self.pomodoro["type"] core.input.register( self, button=core.input.LEFT_MOUSE, cmd=self.timer_play_pause ) core.input.register(self, button=core.input.RIGHT_MOUSE, cmd=self.timer_reset) def remaining_time_str(self): if self.display_seconds_p and self.display_minutes_p: minutes, seconds = divmod(self.remaining_time.seconds, 60) if not self.display_seconds_p: minutes = ceil(self.remaining_time.seconds / 60) seconds = 0 if not self.display_minutes_p: minutes = 0 seconds = self.remaining_time.seconds minutes = "{:2d}".format(minutes) seconds = "{:02d}".format(seconds) return self.__time_format.replace("%m", minutes).replace("%s", seconds) + " " def text(self, widget): return "{}".format(self.__text) def update(self): if self.pomodoro["state"] == "ON": timediff = datetime.datetime.now() - self.time if timediff.seconds >= 0: self.remaining_time -= timediff self.time = datetime.datetime.now() if self.remaining_time.total_seconds() <= 0: self.notify() if self.pomodoro["type"] == "Work": self.pomodoro["type"] = "Break" self.remaining_time = datetime.timedelta( minutes=self.__break_period ) elif self.pomodoro["type"] == "Break": self.pomodoro["type"] = "Work" self.remaining_time = datetime.timedelta(minutes=self.__work_period) self.__text = self.remaining_time_str() + self.pomodoro["type"] def notify(self): try: wave = sa.WaveObject.from_wave_file(sound) play = wave.play() except FileNotFoundError: pass if self.__notify_cmd: util.cli.execute(self.__notify_cmd) def timer_play_pause(self, widget): if self.pomodoro["state"] == "OFF": self.pomodoro = {"state": "ON", "type": "Work"} self.remaining_time = datetime.timedelta(minutes=self.__work_period) self.time = datetime.datetime.now() elif self.pomodoro["state"] == "ON": self.pomodoro["state"] = "PAUSED" self.remaining_time -= datetime.datetime.now() - self.time self.time = datetime.datetime.now() elif self.pomodoro["state"] == "PAUSED": self.pomodoro["state"] = "ON" self.time = datetime.datetime.now() def timer_reset(self, widget): if self.pomodoro["state"] == "ON" or self.pomodoro["state"] == "PAUSED": self.pomodoro = {"state": "OFF", "type": ""} self.remaining_time = datetime.timedelta(minutes=self.__work_period) def state(self, widget): state = [] state.append(self.pomodoro["state"].lower()) if self.pomodoro["state"] == "ON" or self.pomodoro["state"] == "OFF": state.append(self.pomodoro["type"].lower()) return state # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4