Changeset d7a66ad in flowtimer


Ignore:
Timestamp:
08/25/24 18:20:14 (9 months ago)
Author:
Enrico Schwass <ennoausberlin@…>
Branches:
guix
Children:
d310de3
Parents:
5f4ef8e
Message:

more refactorings

Signed-off-by: Enrico Schwass <ennoausberlin@…>

Files:
7 edited

Legend:

Unmodified
Added
Removed
  • flowtimer/Phase.py

    r5f4ef8e rd7a66ad  
    4747        """
    4848
    49         return ("-->" + self.title + "\nTicks left=" +
     49        return ("Title:" + self.title + "\nTicks left=" +
    5050                str(self._ticks_left) + "\n" + str(self._state) + "\n")
    5151
     
    5454
    5555    def abort(self):
    56         self._state = "finished"
     56        self._state = "aborted"
     57
     58    def aborted(self):
     59        return self.state == "aborted"
    5760
    5861    def start(self):
     
    7073        # return self.time_left > 0
    7174
    72     def finished(self):
    73         return self._state == "finished"
     75    def completed(self):
     76        return self._state == "completed"
    7477
    7578    def paused(self):
     
    8184        if result <= 0:
    8285            self._ticks_left = 0
    83             self._state = "finished"
     86            self._state = "completed"
    8487        else:
    8588            self._ticks_left = result
  • flowtimer/RecurringPhaseSequence.py

    r5f4ef8e rd7a66ad  
    2020    def default_json_string(cls):
    2121        return json.dumps({"title": "default",
    22                            "phase_list": [{"title": "Huddle", "initial_ticks": 10},
    23                                           {"title": "Tasking", "initial_ticks": 5},
     22                           "phase_list": [{"title": "Tasking", "initial_ticks": 5},
    2423                                          {"title": "Work", "initial_ticks": 45},
    2524                                          {"title": "Break", "initial_ticks": 15}],
     
    4645    def title(self):
    4746        return self._title
     47
     48    def __str__(self):
     49        return ("Sequence title:" + self.title + "\n" + str(self.current_phase))
    4850
    4951    def is_sequence(self):
     
    7274            sum([each.ticks_left for each in self.upcoming_phases_in_pass()]))
    7375
    74     def finished(self):
     76    def completed(self):
    7577        return ((self.passes_left < 1) and
    7678                (not self.upcoming_phases_in_pass() and
    77                  self.current_phase.finished()))
     79                 self.current_phase.completed()))
    7880
    7981    def abort(self):
    8082        self.current_phase.abort()
    81         self.state = "finished"
     83        self.state = "aborted"
    8284
    8385    def start(self):
     
    99101                self.current_phase = self.phase_list[0]
    100102
     103    def advance_to_next_phase(self):
     104        current_index = self.current_phase_number()
     105        if current_index < len(self.phase_list) - 1:
     106            # Move to the next phase in the sequence
     107            self.current_phase.reset()
     108            self.current_phase = self.phase_list[current_index + 1]
     109        else:
     110            # Completed a full sequence; check if more repetitions are needed
     111            self.passes_left -= 1
     112            if self.passes_left < 1:
     113                self.state = "completed"
     114            else:
     115                self.current_phase.reset()
     116                self.current_phase = self.phase_list[0]  # Reset to the first phase
     117
    101118    def tick(self, ticks):
    102         if not self.finished():
     119        print("Before tick")
     120        print(self.current_phase)
     121        print("Tick:", ticks)
     122        if not self.completed():
    103123            result = self.current_phase.tick(ticks)
    104             if self.current_phase.finished():
    105                 if self.upcoming_phases_in_pass():
    106                     self.current_phase.reset()
    107                     self.current_phase = self.upcoming_phases_in_pass()[0]
    108                     self.current_phase.start()
    109                     self.tick(abs(result))
    110                     return True
    111                 self.passes_left -= 1
    112                 if self.finished():
    113                     self.state = "finished"
    114                 else:
    115                     self.current_phase.reset()
    116                     self.current_phase = self.phase_list[0]
    117         return True
     124            print("Result", result, "\n")
     125            if self.current_phase.completed():
     126                print(self.current_phase.title, "Phase Completed")
     127                self.advance_to_next_phase()
     128                print("Advanced to", self.current_phase, "\n")
     129                result = self.tick(abs(result))
     130                return
     131        if self.completed():
     132            self.advance_to_next_phase()
     133        print("Passes left:", self.passes_left)
    118134
    119135    def unrolled(self):
  • flowtimer/Schedule.py

    r5f4ef8e rd7a66ad  
    66I represent a Schedule consisting of blocks. Blocks can be a single phase or
    77a sequence of phases.
     8There are 6 states a Schedule can be in: initial, running, completed, aborted, paused, terminated.
    89"""
    910
     
    7273    def to_json(self):
    7374        def serialize_block(block):
    74             if not block.is_sequence:
     75            if not block.is_sequence():
    7576                return {"type": "Phase", "title": block.title, "initial_ticks": block.initial_ticks}
    76             if block.is_sequence:
     77            if block.is_sequence():
    7778                return {
    7879                    "type": "Sequence",
    7980                    "title": block.title,
    80                     "sequence": [serialize_block(phase) for phase in block.sequence],
     81                    "sequence": [serialize_block(phase) for phase in block.phase_list],
    8182                    "initial_repetitions": block.initial_repetitions
    8283                }
     
    9899        return self.state == "running"
    99100
    100     def is_paused(self):
     101    def paused(self):
    101102        return self.state == "paused"
    102103
    103104    def abort(self):
    104105        self.current_block.abort()
    105         self.state = "finished"
     106        self.state = "aborted"
    106107
    107     def finished(self):
    108         if (self.current_block.finished()) and (self.current_block.is_final()):
    109             self.state = "finished"
     108    def current_block_is_final(self):
     109        index = self.blocks.index(self.current_block)
     110        return index == (len(self.blocks) - 1)
     111
     112    def completed(self):
     113        if (self.current_block.completed()) and (self.current_block_is_final()):
     114            self.state = "completed"
    110115            return True
    111116        else:
    112117            return False
    113118
     119    def aborted(self):
     120        return self.state == "aborted"
     121
     122    def terminated(self):
     123        return (self.aborted() or self.completed())
     124
    114125    def advance_to_next_block(self):
    115126        """Helper method to move to the next block in the schedule."""
    116         if self.current_block_index < len(self.blocks) - 1:
    117             self.current_block_index += 1
    118             self.current_block = self.blocks[self.current_block_index]
     127        current_block_index = self.blocks.index(self.current_block)
     128        if current_block_index < len(self.blocks) - 1:
     129            self.current_block = self.blocks[current_block_index+1]
    119130
    120131    def skip(self):
     
    126137            print("Skip the next phase in sequence")
    127138            self.current_block.skip()
    128             if self.current_block.finished():
     139            if self.current_block.completed():
    129140                self.current_block = self.upcoming_blocks()[0]
    130141            return
     
    143154        return []
    144155
    145     def current_block_is_final(self):
    146         index = self.blocks.index(self.current_block)
    147         return index == (len(self.blocks) - 1)
    148 
    149156    def tick(self, ticks):
    150         if not self.finished():
     157        if not self.completed():
    151158            self.current_block.tick(ticks)
    152             if self.current_block.finished():
     159            if self.current_block.completed():
    153160                if self.current_block_is_final():
    154                     self.abort()
     161                    self.state = "completed"
    155162                else:
    156163                    self.skip()
  • flowtimer/main.py

    r5f4ef8e rd7a66ad  
    117117    def tick(self):
    118118
    119         if self.schedule.is_paused():
     119        if self.schedule.paused():
    120120            return
    121121        self.label_start.pack_forget()
     
    161161    def skip(self):
    162162        self.schedule.skip()
    163         if self.schedule.finished():
    164             print("finished")
    165163
    166164    def toggle_tick(self):
    167         if self.schedule.is_paused():
     165        if self.schedule.paused():
    168166            self.freeze_button.config(relief="raised", fg='black')
    169167            self.label_sequence.config(fg="white")
  • tests/test_phase.py

    r5f4ef8e rd7a66ad  
    3232        phase = Phase("Warm-up", 300)
    3333        phase.abort()
    34         assert phase.state == "finished"
    35         assert phase.finished() is True
     34        assert phase.state == "aborted"
     35        assert phase.aborted() is True
    3636
    3737    def test_phase_tick(self):
     
    4747        phase.tick(300)
    4848        assert phase.ticks_left == 0
    49         assert phase.finished() is True
     49        assert phase.completed() is True
    5050
    5151    def test_phase_tick_beyond_completion(self):
  • tests/test_recurring_phase_sequence.py

    r5f4ef8e rd7a66ad  
    1010    @pytest.fixture
    1111    def recurring_phase_sequence(self):
    12         phase_list = [Phase("Huddle", 10), Phase("Tasking", 5),
    13                       Phase("Work", 45), Phase("Break", 15)]
    14         return RecurringPhaseSequence(phase_list, 3)
     12        return RecurringPhaseSequence.default()
    1513
    1614    def test_from_json(self):
     
    1917        assert isinstance(sequence, RecurringPhaseSequence)
    2018        assert sequence.initial_repetitions == 3
    21         assert len(sequence.phase_list) == 4
    22         assert sequence.phase_list[0].title == "Huddle"
     19        assert len(sequence.phase_list) == 3
     20        assert sequence.phase_list[0].title == "Tasking"
    2321
    2422    def test_to_json(self, recurring_phase_sequence):
     
    2826        assert data['initial_repetitions'] == 3
    2927        assert data['passes_left'] == 3
    30         assert len(data['phase_list']) == 4
     28        assert len(data['phase_list']) == 3
    3129
    3230    def test_initial_state(self, recurring_phase_sequence):
    3331        assert recurring_phase_sequence.state == "initial"
    34         assert recurring_phase_sequence.current_phase.title == "Huddle"
     32        assert recurring_phase_sequence.current_phase.title == "Tasking"
    3533        assert recurring_phase_sequence.passes_left == 3
    3634
     
    4139
    4240    def test_phases_left_in_pass(self, recurring_phase_sequence):
    43         assert recurring_phase_sequence.phases_left_in_pass() == 3
     41        assert recurring_phase_sequence.phases_left_in_pass() == 2
    4442        recurring_phase_sequence.tick(10)
    45         assert recurring_phase_sequence.phases_left_in_pass() == 2
     43        assert recurring_phase_sequence.phases_left_in_pass() == 1
    4644
    4745    def test_upcoming_phases_in_pass(self, recurring_phase_sequence):
    4846        upcoming = recurring_phase_sequence.upcoming_phases_in_pass()
    49         assert len(upcoming) == 3
    50         assert upcoming[0].title == "Tasking"
     47        assert len(upcoming) == 2
     48        assert upcoming[0].title == "Work"
    5149
    5250    def test_ticks_left(self, recurring_phase_sequence):
     
    5856        assert recurring_phase_sequence.ticks_left == (total_ticks - 10)
    5957
    60     def test_finished(self, recurring_phase_sequence):
    61         assert not recurring_phase_sequence.finished()
     58    def test_completed(self, recurring_phase_sequence):
     59        assert not recurring_phase_sequence.completed()
    6260        for _ in range(3):
    6361            for phase in recurring_phase_sequence.phase_list:
    6462                recurring_phase_sequence.tick(phase.initial_ticks)
    65         assert recurring_phase_sequence.finished()
     63        assert recurring_phase_sequence.completed()
    6664
    6765    def test_abort(self, recurring_phase_sequence):
    6866        recurring_phase_sequence.abort()
    69         assert recurring_phase_sequence.state == "finished"
    70         assert recurring_phase_sequence.current_phase.finished()
     67        assert recurring_phase_sequence.state == "aborted"
     68        assert recurring_phase_sequence.current_phase.aborted()
    7169
    7270    def test_tick_progression(self, recurring_phase_sequence):
    73         recurring_phase_sequence.tick(10)
    74         assert recurring_phase_sequence.current_phase.title == "Tasking"
    75         assert recurring_phase_sequence.passes_left == 3
    76 
    77         recurring_phase_sequence.tick(5)
     71        recurring_phase_sequence.tick(6)
    7872        assert recurring_phase_sequence.current_phase.title == "Work"
    7973        assert recurring_phase_sequence.passes_left == 3
     
    8478
    8579        recurring_phase_sequence.tick(15)
    86         assert recurring_phase_sequence.current_phase.title == "Huddle"
     80        assert recurring_phase_sequence.current_phase.title == "Tasking"
    8781        assert recurring_phase_sequence.passes_left == 2
    8882
    8983    def test_unrolled(self, recurring_phase_sequence):
    9084        unrolled_phases = recurring_phase_sequence.unrolled()
    91         assert len(unrolled_phases) == 12
    92         assert unrolled_phases[0].title == "Huddle"
     85        assert len(unrolled_phases) == 9
     86        assert unrolled_phases[0].title == "Tasking"
    9387        assert unrolled_phases[-1].title == "Break"
  • tests/test_schedule.py

    r5f4ef8e rd7a66ad  
    11import pytest
     2import json
    23from flowtimer.Schedule import Schedule
    34from flowtimer.Phase import Phase
     5from flowtimer.RecurringPhaseSequence import RecurringPhaseSequence
     6
    47
    58class TestSchedule:
    6    
    7     def test_schedule_initialization(self):
    8         phase1 = Phase("Warm-up", 300)
    9         phase2 = Phase("Workout", 600)
    10         schedule = Schedule([phase1, phase2])
    11    
    12         assert schedule.phase_list == [phase1, phase2]
    13         assert schedule.current_phase == phase1
     9
     10    @pytest.fixture
     11    def setup_schedule(self):
     12        #  Set up some real Phase and RecurringPhaseSequence objects for testing
     13        phase1 = Phase("Phase 1", 300)
     14        phase2 = Phase("Phase 2", 600)
     15        sequence = RecurringPhaseSequence("Sequence 1", [phase1, phase2], 2)
     16        blocks = [phase1, sequence]
     17        schedule = Schedule("Test Schedule", blocks)
     18        return schedule, phase1, phase2, sequence
     19
     20    def test_initialization(self, setup_schedule):
     21        schedule, phase1, _, _ = setup_schedule
     22        assert schedule.title == "Test Schedule"
     23        assert schedule.blocks == [phase1, schedule.blocks[1]]
     24        assert schedule.current_block == phase1
    1425        assert schedule.state == "initial"
    1526
    16     def test_schedule_start(self):
    17         phase1 = Phase("Warm-up", 300)
    18         schedule = Schedule([phase1])
     27    def test_default_json_string(self):
     28        default_json = Schedule.default_json_string()
     29        assert isinstance(default_json, str)
     30
     31    def test_from_json(self):
     32        json_string = Schedule.default_json_string()
     33        schedule = Schedule.from_json(json_string)
     34        assert schedule.title == "Default"
     35        assert len(schedule.blocks) == 2
     36        assert isinstance(schedule.blocks[0], Phase)
     37        assert isinstance(schedule.blocks[1], RecurringPhaseSequence)
     38
     39    def test_to_json(self, setup_schedule):
     40        schedule, _, _, _ = setup_schedule
     41        json_string = schedule.to_json()
     42        assert isinstance(json_string, str)
     43        data = json.loads(json_string)
     44        assert data['title'] == "Test Schedule"
     45        assert len(data['blocks']) == 2
     46
     47    def test_start(self, setup_schedule):
     48        schedule, phase1, _, _ = setup_schedule
    1949        schedule.start()
    20    
    2150        assert schedule.state == "running"
    22         assert schedule.current_phase.running() is True
    23    
    24     def test_schedule_pause(self):
    25         phase1 = Phase("Warm-up", 300)
    26         schedule = Schedule([phase1])
     51        # assert phase1.ticks_left < phase1.initial_ticks  # Assuming the phase reduces ticks when started
     52
     53    def test_running(self, setup_schedule):
     54        schedule, _, _, _ = setup_schedule
    2755        schedule.start()
     56        assert schedule.running() is True
    2857        schedule.pause()
    29    
    30         assert schedule.state == "paused"
    31         assert schedule.is_paused() is True
     58        assert schedule.running() is False
    3259
    33     def test_schedule_abort(self):
    34         phase1 = Phase("Warm-up", 300)
    35         schedule = Schedule([phase1])
    36         schedule.start()
     60    def test_paused(self, setup_schedule):
     61        schedule, _, _, _ = setup_schedule
     62        schedule.pause()
     63        assert schedule.paused() is True
     64
     65    def test_abort(self, setup_schedule):
     66        schedule, _, _, _ = setup_schedule
    3767        schedule.abort()
    38    
    39         assert schedule.state == "finished"
    40         assert schedule.current_phase.finished() is True
     68        assert schedule.state == "aborted"
    4169
    42     def test_schedule_finished(self):
    43         phase1 = Phase("Warm-up", 300)
    44         phase2 = Phase("Workout", 600)
    45         schedule = Schedule([phase1, phase2])
    46    
    47         assert schedule.finished() is False
    48    
    49         phase1.start()
    50         phase1.tick(300)
    51         assert phase1.finished() is True
    52         assert schedule.finished() is False
    53    
     70    def test_completed(self, setup_schedule):
     71        schedule, phase1, _, sequence = setup_schedule
     72        schedule.tick(phase1.initial_ticks)  # Complete phase1
     73        schedule.tick(sequence.initial_ticks)  # Complete sequence
     74        schedule.tick(phase1.initial_ticks)  # Complete phase1
     75        schedule.tick(sequence.initial_ticks)  # Complete sequence
     76        print(schedule.current_block)
     77        assert schedule.completed() is True
     78        assert schedule.state == "completed"
     79
     80    def test_advance_to_next_block(self, setup_schedule):
     81        schedule, _, _, sequence = setup_schedule
     82        schedule.advance_to_next_block()
     83        assert schedule.current_block == schedule.blocks[1]
     84
     85    def test_skip(self, setup_schedule):
     86        schedule, _, _, sequence = setup_schedule
    5487        schedule.skip()
    55         schedule.current_phase.tick(600)
    56         assert schedule.finished() is True
     88        assert schedule.current_block == schedule.blocks[1]  # Should skip to Phase 2 within the sequence
    5789
    58     def test_schedule_skip(self):
    59         phase1 = Phase("Warm-up", 300)
    60         phase2 = Phase("Workout", 600)
    61         schedule = Schedule([phase1, phase2])
    62    
    63         schedule.start()
    64         schedule.skip()
    65    
    66         assert schedule.current_phase == phase2
     90    def test_total_ticks_left(self, setup_schedule):
     91        schedule, phase1, phase2, sequence = setup_schedule
     92        expected_total_ticks = phase1.ticks_left + sequence.ticks_left
     93        assert schedule.total_ticks_left() == expected_total_ticks
    6794
    68     def test_schedule_skip_at_final_phase(self):
    69         phase1 = Phase("Warm-up", 300)
    70         schedule = Schedule([phase1])
    71    
    72         schedule.start()
    73         schedule.skip()
    74    
    75         assert schedule.state == "finished"
     95    def test_upcoming_blocks(self, setup_schedule):
     96        schedule, _, _, sequence = setup_schedule
     97        assert schedule.upcoming_blocks() == [sequence]
    7698
    77     def test_schedule_tick(self):
    78         phase1 = Phase("Warm-up", 300)
    79         phase2 = Phase("Workout", 600)
    80         schedule = Schedule([phase1, phase2])
    81    
    82         schedule.start()
    83         schedule.tick(300)
    84    
    85         assert phase1.finished() is True
    86         assert schedule.current_phase == phase2
    87         assert schedule.state == "running"
     99    def test_current_block_is_final(self, setup_schedule):
     100        schedule, _, _, sequence = setup_schedule
     101        assert schedule.current_block_is_final() is False
     102        schedule.advance_to_next_block()
     103        assert schedule.current_block_is_final() is True
    88104
    89     def test_schedule_tick_to_completion(self):
    90         phase1 = Phase("Warm-up", 300)
    91         phase2 = Phase("Workout", 600)
    92         schedule = Schedule([phase1, phase2])
    93    
    94         schedule.start()
    95         schedule.tick(300)  # Should finish phase1 and move to phase2
    96         schedule.tick(600)  # Should finish phase2 and complete the schedule
    97    
    98         assert phase2.finished() is True
    99         assert schedule.finished() is True
     105    def test_tick(self, setup_schedule):
     106        schedule, phase1, _, _ = setup_schedule
     107        initial_ticks = phase1.ticks_left
     108        schedule.tick(100)
     109        assert phase1.ticks_left == initial_ticks - 100
    100110
    101     def test_schedule_current_phase_is_final(self):
    102         phase1 = Phase("Warm-up", 300)
    103         phase2 = Phase("Workout", 600)
    104         schedule = Schedule([phase1, phase2])
    105    
    106         assert schedule.current_phase_is_final() is False
    107    
    108         schedule.skip()
    109         assert schedule.current_phase_is_final() is True
    110 
     111        schedule.tick(phase1.ticks_left)  # Finish phase1
     112        assert schedule.current_block == schedule.blocks[1]  # Should advance to the next block
Note: See TracChangeset for help on using the changeset viewer.