aboutsummaryrefslogtreecommitdiffstats
path: root/screens/templates.py
diff options
context:
space:
mode:
Diffstat (limited to 'screens/templates.py')
-rw-r--r--screens/templates.py250
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()