From c5f9c19fb0591a1d14777ad205e01e29101715ae Mon Sep 17 00:00:00 2001 From: Thomas Vanbesien Date: Wed, 18 Mar 2026 16:03:00 +0100 Subject: Prefix non-public screen functions with _ and split sessions.py into helpers --- screens/exercises.py | 20 ++--- screens/sessions.py | 223 ++++++++++++++++++++++++++++----------------------- screens/templates.py | 31 ++++--- 3 files changed, 149 insertions(+), 125 deletions(-) (limited to 'screens') diff --git a/screens/exercises.py b/screens/exercises.py index 983f50f..d9a9cda 100644 --- a/screens/exercises.py +++ b/screens/exercises.py @@ -15,18 +15,18 @@ def manage_workout_exercises(conn: sqlite3.Connection) -> None: print("5. Back") choice = input("\n> ").strip() if choice == "1": - list_workout_exercises(conn) + _list_workout_exercises(conn) elif choice == "2": - add_workout_exercise(conn) + _add_workout_exercise(conn) elif choice == "3": - edit_workout_exercise(conn) + _edit_workout_exercise(conn) elif choice == "4": - delete_workout_exercise(conn) + _delete_workout_exercise(conn) elif choice == "5": break -def list_workout_exercises(conn: sqlite3.Connection, pause: bool = True) -> None: +def _list_workout_exercises(conn: sqlite3.Connection, pause: bool = True) -> None: exercises = models.list_workout_exercises(conn) ui.print_header("All Workout Exercises") ui.print_table( @@ -45,7 +45,7 @@ def list_workout_exercises(conn: sqlite3.Connection, pause: bool = True) -> None ui.pause() -def add_workout_exercise(conn: sqlite3.Connection) -> None: +def _add_workout_exercise(conn: sqlite3.Connection) -> None: name = ui.prompt_str("Name: ") assert name is not None bw_relative = ui.confirm("Is weight relative to body weight?") @@ -58,8 +58,8 @@ def add_workout_exercise(conn: sqlite3.Connection) -> None: ui.pause() -def edit_workout_exercise(conn: sqlite3.Connection) -> None: - list_workout_exercises(conn, pause=False) +def _edit_workout_exercise(conn: sqlite3.Connection) -> None: + _list_workout_exercises(conn, pause=False) eid = ui.prompt_int("\nExercise ID to edit: ") assert eid is not None ex = models.get_workout_exercise(conn, eid) @@ -86,8 +86,8 @@ def edit_workout_exercise(conn: sqlite3.Connection) -> None: ui.pause() -def delete_workout_exercise(conn: sqlite3.Connection) -> None: - list_workout_exercises(conn, pause=False) +def _delete_workout_exercise(conn: sqlite3.Connection) -> None: + _list_workout_exercises(conn, pause=False) eid = ui.prompt_int("\nExercise ID to delete: ") assert eid is not None ex = models.get_workout_exercise(conn, eid) diff --git a/screens/sessions.py b/screens/sessions.py index 58b2f71..67ef9ba 100644 --- a/screens/sessions.py +++ b/screens/sessions.py @@ -4,73 +4,67 @@ import models import ui -def log_workout(conn: sqlite3.Connection) -> None: - exercises = models.list_workout_exercises(conn) - if not exercises: - print("No exercises defined. Add some first via Manage Workout Exercises.") - return - - # Session metadata - ui.clear_screen() - ui.print_header("Log Workout") - date_time = ui.prompt_datetime("Date/Time") - session_note = ui.prompt_str("Session note (optional): ", required=False) - - # Check if user wants to start from a template - entries: list[dict] = [] +def _load_from_template(conn: sqlite3.Connection, entries: list[dict]) -> None: + """Offer to pre-fill session exercises from a template.""" templates = models.list_workout_templates(conn) - if templates: - print("\nStart from a template?") - for i, t in enumerate(templates, 1): - print(f" {i}. {t['name']}") - print(" 0. No template (blank session)") - choice = input("\n> ").strip() - try: - idx = int(choice) - if 1 <= idx <= len(templates): - # Load template exercises as defaults - template_id = templates[idx - 1]["id"] - _, tmpl_entries = models.get_workout_template_detail(conn, template_id) - print(f'\nUsing template "{templates[idx - 1]["name"]}"') - print("Press Enter to accept defaults, or type new values.\n") - for te in tmpl_entries: - print(f" -- {te['exercise_name']} --") - sets = ui.prompt_int( - f" Sets [{te['sets'] or ''}]: ", - min_val=1, - default=te["sets"], - ) - assert sets is not None - reps, weight, rest_time = ui.prompt_sets_detail( - sets, - default_reps=te["reps"], - default_rest=te["rest_time"], - bw_relative=bool(te["bw_relative"]), - ) - lsrpe = ui.prompt_int(" Last Set RPE: ", min_val=1, max_val=10) - note = ui.prompt_str( - f" Note [{te['note'] or ''}]: ", - required=False, - default=te["note"], - ) - entries.append( - { - "exercise_id": te["exercise_id"], - "exercise_name": te["exercise_name"], - "bw_relative": bool(te["bw_relative"]), - "sets": sets, - "reps": reps, - "weight": weight, - "rest_time": rest_time, - "lsrpe": lsrpe, - "note": note, - } - ) - print(f' "{te["exercise_name"]}" added to session.') - except (ValueError, IndexError): - pass # Invalid input or 0 — proceed without template - - # Build exercise list — collect everything in memory before saving + if not templates: + return + print("\nStart from a template?") + for i, t in enumerate(templates, 1): + print(f" {i}. {t['name']}") + print(" 0. No template (blank session)") + choice = input("\n> ").strip() + try: + idx = int(choice) + if 1 <= idx <= len(templates): + template_id = templates[idx - 1]["id"] + _, tmpl_entries = models.get_workout_template_detail(conn, template_id) + print(f'\nUsing template "{templates[idx - 1]["name"]}"') + print("Press Enter to accept defaults, or type new values.\n") + for te in tmpl_entries: + print(f" -- {te['exercise_name']} --") + sets = ui.prompt_int( + f" Sets [{te['sets'] or ''}]: ", + min_val=1, + default=te["sets"], + ) + assert sets is not None + reps, weight, rest_time = ui.prompt_sets_detail( + sets, + default_reps=te["reps"], + default_rest=te["rest_time"], + bw_relative=bool(te["bw_relative"]), + ) + lsrpe = ui.prompt_int(" Last Set RPE: ", min_val=1, max_val=10) + note = ui.prompt_str( + f" Note [{te['note'] or ''}]: ", + required=False, + default=te["note"], + ) + entries.append( + { + "exercise_id": te["exercise_id"], + "exercise_name": te["exercise_name"], + "bw_relative": bool(te["bw_relative"]), + "sets": sets, + "reps": reps, + "weight": weight, + "rest_time": rest_time, + "lsrpe": lsrpe, + "note": note, + } + ) + print(f' "{te["exercise_name"]}" added to session.') + except (ValueError, IndexError): + pass # Invalid input or 0 — proceed without template + + +def _prompt_exercises( + conn: sqlite3.Connection, + exercises: list[sqlite3.Row], + entries: list[dict], +) -> bool: + """Prompt user to add exercises manually. Returns False if aborted.""" while True: print("\nAvailable exercises:") for e in exercises: @@ -81,10 +75,9 @@ def log_workout(conn: sqlite3.Connection) -> None: if choice.lower() == "d": if not entries: print("No exercises added. Aborting.") - return - break + return False + return True - # Select existing exercise and prompt for set details try: eid = int(choice) except ValueError: @@ -119,7 +112,14 @@ def log_workout(conn: sqlite3.Connection) -> None: ) print(f' "{ex["name"]}" added to session.') - # Show summary and confirm before writing to DB + +def _confirm_and_save( + conn: sqlite3.Connection, + date_time: str, + session_note: str | None, + entries: list[dict], +) -> None: + """Show session summary and save if confirmed.""" ui.clear_screen() ui.print_header("Session Summary") print(f"Date: {date_time}") @@ -150,10 +150,59 @@ def log_workout(conn: sqlite3.Connection) -> None: ui.pause() +def log_workout(conn: sqlite3.Connection) -> None: + exercises = models.list_workout_exercises(conn) + if not exercises: + print("No exercises defined. Add some first via Manage Workout Exercises.") + return + + ui.clear_screen() + ui.print_header("Log Workout") + date_time = ui.prompt_datetime("Date/Time") + session_note = ui.prompt_str("Session note (optional): ", required=False) + + entries: list[dict] = [] + _load_from_template(conn, entries) + if not _prompt_exercises(conn, exercises, entries): + return + _confirm_and_save(conn, date_time, session_note, entries) + + +def _view_session_detail(conn: sqlite3.Connection, session_id: int) -> None: + """Display a single session's exercises and handle deletion.""" + ui.clear_screen() + session, entries = models.get_workout_session_detail(conn, session_id) + assert session is not None + ui.print_header(f"Session: {session['date_time']}") + if session["note"]: + print(f"Note: {session['note']}\n") + ui.print_table( + ["#", "Exercise", "Sets", "Reps", "Weight", "Rest", "LSRPE", "Note"], + [ + [ + str(e["position"]), + e["exercise_name"], + str(e["sets"]), + str(e["reps"]).replace(",", "/"), + ui.format_weight(str(e["weight"]), bool(e["bw_relative"])), + ui.format_rest_time(e["rest_time"]), + str(e["lsrpe"]), + e["note"] or "", + ] + for e in entries + ], + ) + action = input("\nActions: (b)ack, (d)elete session\n> ").strip().lower() + if action == "d": + if ui.confirm("Delete this session?"): + models.delete_workout_session(conn, session_id) + print("Session deleted.") + ui.pause() + + def view_workout_sessions(conn: sqlite3.Connection) -> None: while True: ui.clear_screen() - # List all sessions with exercise name preview sessions = models.list_workout_sessions(conn) if not sessions: print("\nNo sessions recorded yet.") @@ -167,7 +216,6 @@ def view_workout_sessions(conn: sqlite3.Connection) -> None: ], ) - # Select a session to view details choice = input("\nSelect # for details ('b' = back): ").strip() if choice.lower() == "b": break @@ -180,33 +228,4 @@ def view_workout_sessions(conn: sqlite3.Connection) -> None: print("Invalid input.") continue - # Show full session detail with all exercise entries - ui.clear_screen() - session_id = sessions[idx]["id"] - session, entries = models.get_workout_session_detail(conn, session_id) - assert session is not None - ui.print_header(f"Session: {session['date_time']}") - if session["note"]: - print(f"Note: {session['note']}\n") - ui.print_table( - ["#", "Exercise", "Sets", "Reps", "Weight", "Rest", "LSRPE", "Note"], - [ - [ - str(e["position"]), - e["exercise_name"], - str(e["sets"]), - str(e["reps"]).replace(",", "/"), - ui.format_weight(str(e["weight"]), bool(e["bw_relative"])), - ui.format_rest_time(e["rest_time"]), - str(e["lsrpe"]), - e["note"] or "", - ] - for e in entries - ], - ) - action = input("\nActions: (b)ack, (d)elete session\n> ").strip().lower() - if action == "d": - if ui.confirm("Delete this session?"): - models.delete_workout_session(conn, session_id) - print("Session deleted.") - ui.pause() + _view_session_detail(conn, sessions[idx]["id"]) diff --git a/screens/templates.py b/screens/templates.py index 7c8ff60..fe122ce 100644 --- a/screens/templates.py +++ b/screens/templates.py @@ -15,18 +15,18 @@ def manage_workout_templates(conn: sqlite3.Connection) -> None: print("5. Back") choice = input("\n> ").strip() if choice == "1": - list_workout_templates(conn) + _list_workout_templates(conn) elif choice == "2": - create_workout_template(conn) + _create_workout_template(conn) elif choice == "3": - edit_workout_template(conn) + _edit_workout_template(conn) elif choice == "4": - delete_workout_template(conn) + _delete_workout_template(conn) elif choice == "5": break -def list_workout_templates(conn: sqlite3.Connection, pause: bool = True) -> None: +def _list_workout_templates(conn: sqlite3.Connection, pause: bool = True) -> None: templates = models.list_workout_templates(conn) ui.print_header("All Workout Templates") ui.print_table( @@ -37,7 +37,7 @@ def list_workout_templates(conn: sqlite3.Connection, pause: bool = True) -> None ui.pause() -def create_workout_template(conn: sqlite3.Connection) -> None: +def _create_workout_template(conn: sqlite3.Connection) -> None: name = ui.prompt_str("Template name: ") assert name is not None try: @@ -50,25 +50,25 @@ def create_workout_template(conn: sqlite3.Connection) -> None: # Immediately enter exercise editor print("Now add exercises to the template.") ui.pause() - edit_template_exercises(conn, template_id) + _edit_template_exercises(conn, template_id) -def edit_workout_template(conn: sqlite3.Connection) -> None: +def _edit_workout_template(conn: sqlite3.Connection) -> None: templates = models.list_workout_templates(conn) if not templates: print("\nNo templates defined.") return - list_workout_templates(conn, pause=False) + _list_workout_templates(conn, pause=False) tid = ui.prompt_int("\nTemplate ID to edit: ") assert tid is not None template = models.get_workout_template(conn, tid) if not template: print("Template not found.") return - edit_template_exercises(conn, tid) + _edit_template_exercises(conn, tid) -def edit_template_exercises(conn: sqlite3.Connection, template_id: int) -> None: +def _edit_template_exercises(conn: sqlite3.Connection, template_id: int) -> None: """Interactive editor for a template's exercise list.""" while True: ui.clear_screen() @@ -118,6 +118,7 @@ def edit_template_exercises(conn: sqlite3.Connection, template_id: int) -> None: if action == "b": break + # Rename the template elif action == "n": new_name = ui.prompt_str("New template name: ") assert new_name is not None @@ -128,6 +129,7 @@ def edit_template_exercises(conn: sqlite3.Connection, template_id: int) -> None: print(f'Template "{new_name}" already exists.') ui.pause() + # Add an exercise: pick from available, prompt for defaults, append and save elif action == "a": available = models.list_workout_exercises(conn) if not available: @@ -162,6 +164,7 @@ def edit_template_exercises(conn: sqlite3.Connection, template_id: int) -> None: print(f'"{ex["name"]}" added to template.') ui.pause() + # Remove an exercise by position elif action == "r": if not exercises_data: print("No exercises to remove.") @@ -176,6 +179,7 @@ def edit_template_exercises(conn: sqlite3.Connection, template_id: int) -> None: print(f'Removed "{removed["exercise_name"]}".') ui.pause() + # Reorder: pop from one position and insert at another elif action == "m": if len(exercises_data) < 2: print("Need at least 2 exercises to move.") @@ -193,6 +197,7 @@ def edit_template_exercises(conn: sqlite3.Connection, template_id: int) -> None: print("Exercise moved.") ui.pause() + # Edit default values for an existing exercise (Enter keeps current) elif action == "e": if not exercises_data: print("No exercises to edit.") @@ -231,12 +236,12 @@ def edit_template_exercises(conn: sqlite3.Connection, template_id: int) -> None: ui.pause() -def delete_workout_template(conn: sqlite3.Connection) -> None: +def _delete_workout_template(conn: sqlite3.Connection) -> None: templates = models.list_workout_templates(conn) if not templates: print("\nNo templates defined.") return - list_workout_templates(conn, pause=False) + _list_workout_templates(conn, pause=False) tid = ui.prompt_int("\nTemplate ID to delete: ") assert tid is not None template = models.get_workout_template(conn, tid) -- cgit v1.2.3