@@ -184,16 +184,32 @@ def update_progress_bar(self):
184184 completed_exercises = self .exercise_manager .completed_count
185185
186186 bar_length = 55
187- progress_fraction = completed_exercises / total_exercises if total_exercises > 0 else 0
187+ if total_exercises > 0 :
188+ progress_fraction = completed_exercises / total_exercises
189+ else :
190+ progress_fraction = 0
191+ log .debug ("PylingsUI.update_progress_bar.progress_fraction: %s" , progress_fraction )
188192
189193 filled = int (progress_fraction * bar_length )
190- remaining = bar_length - filled - 1
194+ if filled > bar_length :
195+ filled = bar_length
191196
192197 progress_bar = Text ("Progress: [" , style = "bold" )
193- progress_bar .append ("#" * filled , style = "green" )
194- progress_bar .append (">" , style = "green" )
195- progress_bar .append ("-" * remaining , style = "red" )
196- progress_bar .append (f"] { completed_exercises } /{ total_exercises } " , style = "bold" )
198+
199+ # Green part
200+ if filled > 0 :
201+ progress_bar .append ("#" * filled , style = "green" )
202+
203+ # Arrow if not full
204+ if filled < bar_length :
205+ progress_bar .append (">" , style = "green" )
206+
207+ # Remaining red part
208+ remaining = bar_length - filled - 1
209+ if remaining > 0 :
210+ progress_bar .append ("-" * remaining , style = "red" )
211+
212+ progress_bar .append (f"] { completed_exercises :>3} /{ total_exercises :>3} " , style = "bold" )
197213 log .debug ("PylingsUI.update_progress_bar.progress_bar: %s" , progress_bar )
198214 progress_bar_widget .update (progress_bar )
199215
@@ -258,7 +274,14 @@ def toggle_list_view(self):
258274 log .debug ("PylingsUI.toggle_list_view.sidebar.selected_index: %s" ,selected_index )
259275
260276 def update_exercise_content (self ):
261- """Update displayed exercise details, refresh output, and efficiently update the list."""
277+ """Update exercise rows in the list view.
278+
279+ If no index is supplied, all rows will be updated. This ensures that the display
280+ text for each exercise reflects its current status.
281+
282+ Args:
283+ index (int | None): The index of the exercise to update. If None, all rows are updated.
284+ """
262285 log .debug ("PylingsUI.update_exercise_content: Entered" )
263286
264287 exercise_path = self .current_exercise or "No exercise selected"
@@ -269,42 +292,56 @@ def update_exercise_content(self):
269292
270293 list_view = self .query_one ("#exercise-list" , ListView )
271294 selected_index = list_view .index or 0
272- self .update_list_row (selected_index )
295+ self .update_list_row ()
273296 self .restore_list_selection (selected_index )
274-
275- # Show completion notice briefly
276- #self.finished_check_progress_notice(clear=False)
277- #self.set_timer(2.0, lambda: self.finished_check_progress_notice(clear=True))
278297 self .update_progress_bar ()
279298
280- def update_list_row (self , index : int ):
281- """Update the display text for the exercise at the given index in the list .
299+ def update_list_row (self , index : int | None = None ):
300+ """Update the display text for a single exercise row at the given index.
282301
283- If the exercise status has changed, the line is updated accordingly.
302+ The display text is updated only if it differs from the current display.
303+ The row text is formatted as "<STATUS> <EXERCISE_NAME>".
284304
285305 Args:
286- index (int): Index of the exercise to update.
306+ idx (int): The index of the list view row to update.
307+ name (str): The name of the exercise corresponding to the row.
308+ list_view (ListView): The ListView widget containing the exercise rows.
309+ exercise_keys (list): The list of exercise names in order.
287310 """
288311 list_view = self .query_one ("#exercise-list" , ListView )
289312 exercise_keys = list (self .exercise_manager .exercises .keys ())
290313
291- if 0 <= index < len (exercise_keys ):
314+ if index is not None :
315+ if not (0 <= index < len (exercise_keys )):
316+ log .warning (f"update_list_row: supplied index { index } out of range" )
317+ return
292318 name = exercise_keys [index ]
293- if self .exercise_manager .exercises [name ]["status" ] == "DONE" :
294- new_status = DONE
295- else :
296- new_status = PENDING
319+ log .debug (f"update_list_row: using supplied index { index } , name: { name } " )
320+ self ._update_list_row_at (index , name , list_view , exercise_keys )
321+ else :
322+ log .debug ("update_list_row: updating entire list" )
323+ for idx , name in enumerate (exercise_keys ):
324+ self ._update_list_row_at (idx , name , list_view , exercise_keys )
297325
298- new_display = f"{ new_status } { name } "
299326
300- list_item = list_view .children [index ]
327+ def _update_list_row_at (self , idx : int , name : str , list_view , exercise_keys ):
328+ exercise_data = self .exercise_manager .exercises [name ]
329+ new_status = DONE if exercise_data ["status" ] == "DONE" else PENDING
330+ new_display = f"{ new_status } { name } "
331+
332+ if 0 <= idx < len (list_view .children ):
333+ list_item = list_view .children [idx ]
301334 static_widget = list_item .query_one (Static )
302335 renderable = static_widget .renderable
303336 current_display = renderable .plain if hasattr (renderable , 'plain' ) else str (renderable )
304337
305338 if current_display != new_display :
306- log .debug ("Updating line %s: %s -> %s" ,index , current_display ,new_display )
339+ log .debug ("Updating line %s: %s -> %s" , idx , current_display , new_display )
307340 static_widget .update (new_display )
341+ else :
342+ log .warning (f"update_list_row: index { idx } out of range of list_view.children" )
343+
344+
308345
309346 def restore_list_selection (self , index : int ):
310347 """Restore focus and visibility for the given list item index.
0 commit comments