aboutsummaryrefslogtreecommitdiffstats
path: root/ui.py
diff options
context:
space:
mode:
authorThomas Vanbesien <tvanbesi@proton.me>2026-03-11 21:16:57 +0100
committerThomas Vanbesien <tvanbesi@proton.me>2026-03-11 21:47:56 +0100
commit6e7e00846e658cb79d0c23e18939c59fedba06dd (patch)
tree72b9565842186c66a2837ff3561b1010020daebc /ui.py
downloadEgoMetrics-6e7e00846e658cb79d0c23e18939c59fedba06dd.tar.gz
EgoMetrics-6e7e00846e658cb79d0c23e18939c59fedba06dd.zip
Add workout logging CLI with SQLite storage
Exercises CRUD, session logging with sets/reps/RPE/rest/LSRPE, session viewing and deletion. Interactive terminal menu.
Diffstat (limited to 'ui.py')
-rw-r--r--ui.py77
1 files changed, 77 insertions, 0 deletions
diff --git a/ui.py b/ui.py
new file mode 100644
index 0000000..2d63c06
--- /dev/null
+++ b/ui.py
@@ -0,0 +1,77 @@
+from datetime import datetime
+
+
+def print_header(title: str) -> None:
+ print(f"\n--- {title} ---\n")
+
+
+def print_table(headers: list[str], rows: list[list[str]]) -> None:
+ if not rows:
+ print(" (empty)")
+ return
+ all_rows = [headers] + [[str(c) for c in row] for row in rows]
+ widths = [max(len(r[i]) for r in all_rows) for i in range(len(headers))]
+ fmt = " | ".join(f"{{:<{w}}}" for w in widths)
+ print(fmt.format(*headers))
+ print("-+-".join("-" * w for w in widths))
+ for row in all_rows[1:]:
+ print(fmt.format(*row))
+
+
+def prompt_int(
+ prompt: str,
+ required: bool = True,
+ min_val: int | None = None,
+ max_val: int | None = None,
+) -> int | None:
+ while True:
+ val = input(prompt).strip()
+ if not val:
+ if not required:
+ return None
+ print("This field is required.")
+ continue
+ try:
+ n = int(val)
+ except ValueError:
+ print("Please enter a valid integer.")
+ continue
+ if min_val is not None and n < min_val:
+ print(f"Must be at least {min_val}.")
+ continue
+ if max_val is not None and n > max_val:
+ print(f"Must be at most {max_val}.")
+ continue
+ return n
+
+
+def prompt_str(prompt: str, required: bool = True) -> str | None:
+ while True:
+ val = input(prompt).strip()
+ if not val:
+ if not required:
+ return None
+ print("This field is required.")
+ continue
+ return val
+
+
+def prompt_datetime(prompt: str, default_now: bool = True) -> str:
+ while True:
+ default = datetime.now().strftime("%Y-%m-%d %H")
+ val = input(f"{prompt} [{default}]: ").strip()
+ if not val:
+ if default_now:
+ return default
+ else:
+ try:
+ datetime.strptime(val, "%Y-%m-%d %H")
+ return val
+ except ValueError:
+ print("Invalid format. Use YYYY-MM-DD HH.")
+ continue
+
+
+def confirm(prompt: str) -> bool:
+ val = input(f"{prompt} [y/N]: ").strip().lower()
+ return val == "y"