diff options
| author | Thomas Vanbesien <tvanbesi@proton.me> | 2026-03-18 15:18:46 +0100 |
|---|---|---|
| committer | Thomas Vanbesien <tvanbesi@proton.me> | 2026-03-18 15:18:46 +0100 |
| commit | 81c3cbf634e1e6929317d3ffcd87df6426808417 (patch) | |
| tree | 3c4045f2ae4329983c3fabe6710a1caa3168e06c /screens/templates.py | |
| parent | 7ceb22f1e12e3a040874a43b5e1177db83be15ed (diff) | |
| download | EgoMetrics-81c3cbf634e1e6929317d3ffcd87df6426808417.tar.gz EgoMetrics-81c3cbf634e1e6929317d3ffcd87df6426808417.zip | |
Refactor screen logic into screens/ package
Split egometrics.py (610 lines) into domain-specific modules:
exercises, sessions, and templates. Entry point now just wires
the main menu to the screen modules.
Diffstat (limited to 'screens/templates.py')
| -rw-r--r-- | screens/templates.py | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/screens/templates.py b/screens/templates.py new file mode 100644 index 0000000..7c8ff60 --- /dev/null +++ b/screens/templates.py @@ -0,0 +1,250 @@ +import sqlite3 + +import models +import ui + + +def manage_workout_templates(conn: sqlite3.Connection) -> None: + while True: + ui.clear_screen() + ui.print_header("Manage Workout Templates") + print("1. List Templates") + print("2. Create Template") + print("3. View/Edit Template") + print("4. Delete Template") + print("5. Back") + choice = input("\n> ").strip() + if choice == "1": + list_workout_templates(conn) + elif choice == "2": + create_workout_template(conn) + elif choice == "3": + edit_workout_template(conn) + elif choice == "4": + delete_workout_template(conn) + elif choice == "5": + break + + +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( + ["ID", "Name", "Exercises"], + [[str(t["id"]), t["name"], t["exercises"] or ""] for t in templates], + ) + if pause: + ui.pause() + + +def create_workout_template(conn: sqlite3.Connection) -> None: + name = ui.prompt_str("Template name: ") + assert name is not None + try: + template_id = models.create_workout_template(conn, name) + print(f'Template "{name}" created.') + except sqlite3.IntegrityError: + print(f'Template "{name}" already exists.') + ui.pause() + return + # Immediately enter exercise editor + print("Now add exercises to the template.") + ui.pause() + edit_template_exercises(conn, template_id) + + +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) + 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) + + +def edit_template_exercises(conn: sqlite3.Connection, template_id: int) -> None: + """Interactive editor for a template's exercise list.""" + while True: + ui.clear_screen() + template, entries = models.get_workout_template_detail(conn, template_id) + assert template is not None + ui.print_header(f'Template: {template["name"]}') + + # Build in-memory list from current DB state + exercises_data: list[dict] = [ + { + "exercise_id": e["exercise_id"], + "exercise_name": e["exercise_name"], + "bw_relative": bool(e["bw_relative"]), + "sets": e["sets"], + "reps": e["reps"], + "lsrpe": e["lsrpe"], + "rest_time": e["rest_time"], + "note": e["note"], + } + for e in entries + ] + + if exercises_data: + ui.print_table( + ["#", "Exercise", "Sets", "Reps", "LSRPE", "Rest", "Note"], + [ + [ + str(i), + e["exercise_name"], + str(e["sets"]), + str(e["reps"]), + str(e["lsrpe"]), + f"{e['rest_time']}s", + e["note"] or "", + ] + for i, e in enumerate(exercises_data, 1) + ], + ) + else: + print(" (no exercises)") + + print( + "\nActions: (a)dd exercise, (r)emove, (m)ove, (e)dit defaults, (n)ame, (b)ack" + ) + action = input("> ").strip().lower() + + if action == "b": + break + + elif action == "n": + new_name = ui.prompt_str("New template name: ") + assert new_name is not None + try: + models.update_workout_template_name(conn, template_id, new_name) + print(f'Template renamed to "{new_name}".') + except sqlite3.IntegrityError: + print(f'Template "{new_name}" already exists.') + ui.pause() + + elif action == "a": + available = models.list_workout_exercises(conn) + if not available: + print("No exercises defined. Create some first.") + continue + print("\nAvailable exercises:") + for e in available: + print(f" {e['id']}. {e['name']}") + eid = ui.prompt_int("\nExercise ID to add: ") + assert eid is not None + ex = models.get_workout_exercise(conn, eid) + if not ex: + print("Exercise not found.") + continue + print(f"\n -- {ex['name']} (defaults) --") + sets = ui.prompt_int(" Sets: ", min_val=1) + reps = ui.prompt_int(" Reps: ", min_val=1) + lsrpe = ui.prompt_int(" LSRPE: ", min_val=1, max_val=10) + rest_time = ui.prompt_int(" Rest time in seconds: ", min_val=0) + note = ui.prompt_str(" Note (optional): ", required=False) + exercises_data.append( + { + "exercise_id": eid, + "sets": sets, + "reps": reps, + "lsrpe": lsrpe, + "rest_time": rest_time, + "note": note, + } + ) + models.save_workout_template_exercises(conn, template_id, exercises_data) + print(f'"{ex["name"]}" added to template.') + ui.pause() + + elif action == "r": + if not exercises_data: + print("No exercises to remove.") + continue + pos = ui.prompt_int("Position # to remove: ", min_val=1) + assert pos is not None + if pos > len(exercises_data): + print("Invalid position.") + continue + removed = exercises_data.pop(pos - 1) + models.save_workout_template_exercises(conn, template_id, exercises_data) + print(f'Removed "{removed["exercise_name"]}".') + ui.pause() + + elif action == "m": + if len(exercises_data) < 2: + print("Need at least 2 exercises to move.") + continue + from_pos = ui.prompt_int( + "Move from position #: ", min_val=1, max_val=len(exercises_data) + ) + to_pos = ui.prompt_int( + "Move to position #: ", min_val=1, max_val=len(exercises_data) + ) + assert from_pos is not None and to_pos is not None + item = exercises_data.pop(from_pos - 1) + exercises_data.insert(to_pos - 1, item) + models.save_workout_template_exercises(conn, template_id, exercises_data) + print("Exercise moved.") + ui.pause() + + elif action == "e": + if not exercises_data: + print("No exercises to edit.") + continue + pos = ui.prompt_int("Position # to edit: ", min_val=1) + assert pos is not None + if pos > len(exercises_data): + print("Invalid position.") + continue + entry = exercises_data[pos - 1] + print(f'\n -- {entry["exercise_name"]} (edit defaults) --') + entry["sets"] = ui.prompt_int( + f" Sets [{entry['sets'] or ''}]: ", min_val=1, default=entry["sets"] + ) + entry["reps"] = ui.prompt_int( + f" Reps [{entry['reps'] or ''}]: ", min_val=1, default=entry["reps"] + ) + entry["lsrpe"] = ui.prompt_int( + f" LSRPE [{entry['lsrpe']}]: ", + min_val=1, + max_val=10, + default=entry["lsrpe"], + ) + entry["rest_time"] = ui.prompt_int( + f" Rest time in seconds [{entry['rest_time']}]: ", + min_val=0, + default=entry["rest_time"], + ) + entry["note"] = ui.prompt_str( + f" Note [{entry['note'] or ''}]: ", + required=False, + default=entry["note"], + ) + models.save_workout_template_exercises(conn, template_id, exercises_data) + print("Defaults updated.") + ui.pause() + + +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) + tid = ui.prompt_int("\nTemplate ID to delete: ") + assert tid is not None + template = models.get_workout_template(conn, tid) + if not template: + print("Template not found.") + return + if not ui.confirm(f'Delete template "{template["name"]}"?'): + return + models.delete_workout_template(conn, tid) + print("Template deleted.") + ui.pause() |
