import json from copy import deepcopy from flowtimer.Phase import Phase class RecurringPhaseSequence: @classmethod def from_json(cls, a_json_string): def custom_object_hook(d): if 'title' in d and 'initial_ticks' in d: return Phase(d['title'], d['initial_ticks']) if 'phase_list' in d and 'initial_repetitions' in d: return RecurringPhaseSequence(d["title"], d['phase_list'], d['initial_repetitions']) print("Wrong format") return d return json.loads(a_json_string, object_hook=custom_object_hook) @classmethod def default_json_string(cls): return json.dumps({"title": "default", "phase_list": [{"title": "Huddle", "initial_ticks": 10}, {"title": "Tasking", "initial_ticks": 5}, {"title": "Work", "initial_ticks": 45}, {"title": "Break", "initial_ticks": 15}], "initial_repetitions": 3}) @classmethod def default(cls): return cls.from_json(cls.default_json_string()) def __init__(self, title, phase_list, repetitions): assert repetitions > 0 assert phase_list is not [] self._title = title self.state = "initial" self.phase_list = phase_list self.current_phase = phase_list[0] self.initial_repetitions = repetitions self.passes_left = repetitions def to_json(self): return json.dumps(self.__dict__, default=lambda each: each.to_json()) @property def title(self): return self.current_phase.title def current_phase_number(self): return self.phase_list.index(self.current_phase) def phases_left_in_pass(self): return len(self.upcoming_phases_in_pass()) def upcoming_phases_in_pass(self): if self.current_phase_number() < len(self.phase_list) - 1: return self.phase_list[self.current_phase_number()+1:] return [] @property def initial_ticks(self): return sum([each.initial_ticks for each in self.phase_list]) @property def ticks_left(self): return ( (self.passes_left-1) * sum([each.initial_ticks for each in self.phase_list]) + self.current_phase.ticks_left + sum([each.ticks_left for each in self.upcoming_phases_in_pass()])) def finished(self): return (self.passes_left < 1) and (not self.upcoming_phases_in_pass()) def abort(self): self.current_phase.abort() self.state = "finished" def start(self): self.state = "running" def tick(self, ticks): if not self.finished(): result = self.current_phase.tick(ticks) if self.current_phase.finished(): if self.upcoming_phases_in_pass(): self.current_phase.reset() self.current_phase = self.upcoming_phases_in_pass()[0] self.current_phase.start() self.tick(abs(result)) return True self.passes_left -= 1 if self.finished(): self.state = "finished" else: self.current_phase.reset() self.current_phase = self.phase_list[0] return True def unrolled(self): return [deepcopy(seq) for seq in [each for each in self.initial_repetitions * self.phase_list]]