aboutsummaryrefslogtreecommitdiffstats
path: root/screens/sessions.py
diff options
context:
space:
mode:
authorThomas Vanbesien <tvanbesi@proton.me>2026-03-18 15:18:46 +0100
committerThomas Vanbesien <tvanbesi@proton.me>2026-03-18 15:18:46 +0100
commit81c3cbf634e1e6929317d3ffcd87df6426808417 (patch)
tree3c4045f2ae4329983c3fabe6710a1caa3168e06c /screens/sessions.py
parent7ceb22f1e12e3a040874a43b5e1177db83be15ed (diff)
downloadEgoMetrics-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/sessions.py')
-rw-r--r--screens/sessions.py212
1 files changed, 212 insertions, 0 deletions
diff --git a/screens/sessions.py b/screens/sessions.py
new file mode 100644
index 0000000..58b2f71
--- /dev/null
+++ b/screens/sessions.py
@@ -0,0 +1,212 @@
+import sqlite3
+
+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] = []
+ 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
+ while True:
+ print("\nAvailable exercises:")
+ for e in exercises:
+ print(f" {e['id']}. {e['name']}")
+ print()
+ choice = input("Select exercise ID ('d' = done): ").strip()
+
+ if choice.lower() == "d":
+ if not entries:
+ print("No exercises added. Aborting.")
+ return
+ break
+
+ # Select existing exercise and prompt for set details
+ try:
+ eid = int(choice)
+ except ValueError:
+ print("Invalid input.")
+ continue
+ ex = models.get_workout_exercise(conn, eid)
+ if not ex:
+ print("Exercise not found.")
+ continue
+
+ print(f"\n -- {ex['name']} --")
+ sets = ui.prompt_int(" Sets: ", min_val=1)
+ assert sets is not None
+ reps, weight, rest_time = ui.prompt_sets_detail(
+ sets, bw_relative=bool(ex["bw_relative"])
+ )
+ lsrpe = ui.prompt_int(" Last Set RPE: ", min_val=1, max_val=10)
+ note = ui.prompt_str(" Note (optional): ", required=False)
+
+ entries.append(
+ {
+ "exercise_id": eid,
+ "exercise_name": ex["name"],
+ "bw_relative": bool(ex["bw_relative"]),
+ "sets": sets,
+ "reps": reps,
+ "weight": weight,
+ "rest_time": rest_time,
+ "lsrpe": lsrpe,
+ "note": note,
+ }
+ )
+ print(f' "{ex["name"]}" added to session.')
+
+ # Show summary and confirm before writing to DB
+ ui.clear_screen()
+ ui.print_header("Session Summary")
+ print(f"Date: {date_time}")
+ if session_note:
+ print(f"Note: {session_note}")
+ ui.print_table(
+ ["#", "Exercise", "Sets", "Reps", "Weight", "Rest", "LSRPE", "Note"],
+ [
+ [
+ str(i),
+ e["exercise_name"],
+ str(e["sets"]),
+ str(e["reps"]).replace(",", "/"),
+ ui.format_weight(e["weight"], e["bw_relative"]),
+ ui.format_rest_time(e["rest_time"]),
+ str(e["lsrpe"]),
+ e["note"] or "",
+ ]
+ for i, e in enumerate(entries, 1)
+ ],
+ )
+
+ if ui.confirm("\nSave this session?"):
+ models.save_workout_session(conn, date_time, session_note, entries)
+ print("Session saved!")
+ else:
+ print("Session discarded.")
+ 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.")
+ return
+ ui.print_header("Past Workout Sessions")
+ ui.print_table(
+ ["#", "Date", "Exercises", "Note"],
+ [
+ [str(i), s["date_time"], s["exercises"] or "", s["note"] or ""]
+ for i, s in enumerate(sessions, 1)
+ ],
+ )
+
+ # Select a session to view details
+ choice = input("\nSelect # for details ('b' = back): ").strip()
+ if choice.lower() == "b":
+ break
+ try:
+ idx = int(choice) - 1
+ if idx < 0 or idx >= len(sessions):
+ print("Invalid selection.")
+ continue
+ except ValueError:
+ 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()