source: flowtimer/flowtimer/RecurringPhaseSequence.py@ f2a2a82

guix
Last change on this file since f2a2a82 was df0449c, checked in by Enrico Schwass <ennoausberlin@…>, 9 months ago

fix one remaining unit test

  • Property mode set to 100644
File size: 4.7 KB
RevLine 
[84123db]1import json
[37ae3b7]2from copy import deepcopy
[3b76475]3from flowtimer.Phase import Phase
[84123db]4
5
6class 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]]
Note: See TracBrowser for help on using the repository browser.