[84123db] | 1 | import json
|
---|
[37ae3b7] | 2 | from copy import deepcopy
|
---|
[3b76475] | 3 | from flowtimer.Phase import Phase
|
---|
[84123db] | 4 |
|
---|
| 5 |
|
---|
| 6 | class RecurringPhaseSequence:
|
---|
| 7 |
|
---|
[37ae3b7] | 8 | @classmethod
|
---|
| 9 | def from_json(cls, a_json_string):
|
---|
| 10 | def custom_object_hook(d):
|
---|
[daa2276] | 11 | if 'title' in d and 'initial_ticks' in d:
|
---|
| 12 | return Phase(d['title'], d['initial_ticks'])
|
---|
[d310de3] | 13 | if 'phases' in d and 'initial_repetitions' in d:
|
---|
| 14 | return RecurringPhaseSequence(d["title"], d['phases'], d['initial_repetitions'])
|
---|
[1fd7029] | 15 | print("Wrong format")
|
---|
[37ae3b7] | 16 | return d
|
---|
| 17 | return json.loads(a_json_string, object_hook=custom_object_hook)
|
---|
| 18 |
|
---|
| 19 | @classmethod
|
---|
| 20 | def default_json_string(cls):
|
---|
[1fd7029] | 21 | return json.dumps({"title": "default",
|
---|
[d310de3] | 22 | "phases": [{"title": "Tasking", "initial_ticks": 5},
|
---|
| 23 | {"title": "Work", "initial_ticks": 45},
|
---|
| 24 | {"title": "Break", "initial_ticks": 15}],
|
---|
[daa2276] | 25 | "initial_repetitions": 3})
|
---|
[37ae3b7] | 26 |
|
---|
[f959488] | 27 | @classmethod
|
---|
| 28 | def default(cls):
|
---|
| 29 | return cls.from_json(cls.default_json_string())
|
---|
| 30 |
|
---|
[d310de3] | 31 | def __init__(self, title, phases, repetitions):
|
---|
[f959488] | 32 | assert repetitions > 0
|
---|
[d310de3] | 33 | assert phases is not []
|
---|
[1fd7029] | 34 | self._title = title
|
---|
[813e855] | 35 | self._state = "initial"
|
---|
[d310de3] | 36 | self.phases = phases
|
---|
| 37 | self.current_phase = phases[0]
|
---|
[f959488] | 38 | self.initial_repetitions = repetitions
|
---|
[8f41b95] | 39 | self.passes_left = repetitions - 1
|
---|
[84123db] | 40 |
|
---|
| 41 | def to_json(self):
|
---|
| 42 | return json.dumps(self.__dict__, default=lambda each: each.to_json())
|
---|
| 43 |
|
---|
[1fd7029] | 44 | @property
|
---|
[44c3377] | 45 | def title(self):
|
---|
[36c9ef5] | 46 | return self._title
|
---|
[44c3377] | 47 |
|
---|
[d7a66ad] | 48 | def __str__(self):
|
---|
| 49 | return ("Sequence title:" + self.title + "\n" + str(self.current_phase))
|
---|
| 50 |
|
---|
[5741f6d] | 51 | def is_sequence(self):
|
---|
| 52 | return True
|
---|
| 53 |
|
---|
[daa2276] | 54 | def current_phase_number(self):
|
---|
[d310de3] | 55 | return self.phases.index(self.current_phase)
|
---|
[daa2276] | 56 |
|
---|
| 57 | def phases_left_in_pass(self):
|
---|
| 58 | return len(self.upcoming_phases_in_pass())
|
---|
| 59 |
|
---|
[f959488] | 60 | def upcoming_phases_in_pass(self):
|
---|
[d310de3] | 61 | if self.current_phase_number() < len(self.phases) - 1:
|
---|
| 62 | return self.phases[self.current_phase_number()+1:]
|
---|
[f959488] | 63 | return []
|
---|
| 64 |
|
---|
[1fd7029] | 65 | @property
|
---|
| 66 | def initial_ticks(self):
|
---|
[d310de3] | 67 | return sum([each.initial_ticks for each in self.phases])
|
---|
[1fd7029] | 68 |
|
---|
[daa2276] | 69 | @property
|
---|
[f959488] | 70 | def ticks_left(self):
|
---|
[daa2276] | 71 | return (
|
---|
[df0449c] | 72 | (self.passes_left) * sum([each.initial_ticks for each in self.phases]) +
|
---|
[daa2276] | 73 | self.current_phase.ticks_left +
|
---|
| 74 | sum([each.ticks_left for each in self.upcoming_phases_in_pass()]))
|
---|
[f959488] | 75 |
|
---|
[813e855] | 76 | def state(self):
|
---|
| 77 | if self.is_completed():
|
---|
| 78 | return "completed"
|
---|
| 79 | return self._state
|
---|
| 80 |
|
---|
| 81 | def is_final_round(self):
|
---|
| 82 | return self.passes_left == 0
|
---|
| 83 |
|
---|
| 84 | def is_completed(self):
|
---|
[a438158] | 85 | return ((self.passes_left < 1) and
|
---|
| 86 | (not self.upcoming_phases_in_pass() and
|
---|
[813e855] | 87 | self.current_phase.is_completed()))
|
---|
| 88 |
|
---|
| 89 | def is_terminated(self):
|
---|
| 90 | return (self.is_aborted() or self.is_completed())
|
---|
| 91 |
|
---|
| 92 | def is_aborted(self):
|
---|
| 93 | return self._state == 'aborted'
|
---|
[f959488] | 94 |
|
---|
| 95 | def abort(self):
|
---|
| 96 | self.current_phase.abort()
|
---|
[813e855] | 97 | self._state = "aborted"
|
---|
[f959488] | 98 |
|
---|
[1fd7029] | 99 | def start(self):
|
---|
[813e855] | 100 | self._state = "running"
|
---|
[1fd7029] | 101 |
|
---|
[36c9ef5] | 102 | def skip(self):
|
---|
| 103 | if self.upcoming_phases_in_pass():
|
---|
| 104 | self.current_phase.reset()
|
---|
| 105 | self.current_phase = self.upcoming_phases_in_pass()[0]
|
---|
| 106 | return
|
---|
| 107 | else:
|
---|
[813e855] | 108 | if self.is_final_round():
|
---|
[36c9ef5] | 109 | self.abort()
|
---|
| 110 | return
|
---|
| 111 | else:
|
---|
| 112 | self.passes_left -= 1
|
---|
| 113 | self.current_phase.reset()
|
---|
[d310de3] | 114 | self.current_phase = self.phases[0]
|
---|
[36c9ef5] | 115 |
|
---|
[d7a66ad] | 116 | def advance_to_next_phase(self):
|
---|
| 117 | current_index = self.current_phase_number()
|
---|
[d310de3] | 118 | if current_index < len(self.phases) - 1:
|
---|
[d7a66ad] | 119 | # Move to the next phase in the sequence
|
---|
| 120 | self.current_phase.reset()
|
---|
[d310de3] | 121 | self.current_phase = self.phases[current_index + 1]
|
---|
[df0449c] | 122 | # self.current_phase.start()
|
---|
[d7a66ad] | 123 | else:
|
---|
| 124 | # Completed a full sequence; check if more repetitions are needed
|
---|
| 125 | self.passes_left -= 1
|
---|
| 126 | if self.passes_left < 1:
|
---|
[813e855] | 127 | self._state = "completed"
|
---|
[d7a66ad] | 128 | else:
|
---|
| 129 | self.current_phase.reset()
|
---|
[d310de3] | 130 | self.current_phase = self.phases[0] # Reset to the first phase
|
---|
[df0449c] | 131 | # self.current_phase.start()
|
---|
[d7a66ad] | 132 |
|
---|
[f959488] | 133 | def tick(self, ticks):
|
---|
[813e855] | 134 | if not self.is_completed():
|
---|
[f959488] | 135 | result = self.current_phase.tick(ticks)
|
---|
[813e855] | 136 | if self.current_phase.is_completed():
|
---|
[d7a66ad] | 137 | self.advance_to_next_phase()
|
---|
| 138 | result = self.tick(abs(result))
|
---|
[df0449c] | 139 | return result
|
---|
| 140 | return result
|
---|
| 141 | else:
|
---|
| 142 | return 0
|
---|
[f959488] | 143 |
|
---|
[84123db] | 144 | def unrolled(self):
|
---|
[d310de3] | 145 | return [deepcopy(seq) for seq in [each for each in self.initial_repetitions * self.phases]]
|
---|