From fcc687b97d0acb878d2167a2ef47939b8bc47598 Mon Sep 17 00:00:00 2001 From: stilbruch Date: Sat, 23 Apr 2022 12:38:19 -0500 Subject: Add select page (it sucks) --- app/routes.py | 5 +++++ app/templates/workout/record.html | 28 ++-------------------------- app/templates/workout/select.html | 23 +++++++++++++++++++++++ 3 files changed, 30 insertions(+), 26 deletions(-) create mode 100644 app/templates/workout/select.html diff --git a/app/routes.py b/app/routes.py index 7ee3986..8f5d8c1 100644 --- a/app/routes.py +++ b/app/routes.py @@ -116,3 +116,8 @@ def editWorkout(): @login_required def recordWorkout(): return render_template('workout/record.html') + +@app.route("/workout/select", methods=['GET']) +@login_required +def selectWorkout(): + return render_template('workout/select.html') diff --git a/app/templates/workout/record.html b/app/templates/workout/record.html index 1a544fc..bc6b695 100644 --- a/app/templates/workout/record.html +++ b/app/templates/workout/record.html @@ -5,32 +5,8 @@
-

Leg Day

-
- -
-
+ +
diff --git a/app/templates/workout/select.html b/app/templates/workout/select.html new file mode 100644 index 0000000..c01a4f8 --- /dev/null +++ b/app/templates/workout/select.html @@ -0,0 +1,23 @@ +{% extends 'base/layout.html' %} + +{% block content %} +
+
+ {% for workout in current_user.workouts %} +
+
+
+

{{ workout.name }}

+
+
+
+ Start +
+
+
+
+ {% endfor %} +
+
+ +{% endblock %} -- cgit v1.2.3 From 5d08424481a8a6ae1b69c96a6ee43394d9aa8963 Mon Sep 17 00:00:00 2001 From: stilbruch Date: Sat, 23 Apr 2022 13:24:57 -0500 Subject: Start workout record page --- app/routes.py | 11 +++++++++- app/templates/workout/record.html | 45 +++++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/app/routes.py b/app/routes.py index 8f5d8c1..76ea96a 100644 --- a/app/routes.py +++ b/app/routes.py @@ -115,7 +115,16 @@ def editWorkout(): @app.route("/workout/record", methods=['GET']) @login_required def recordWorkout(): - return render_template('workout/record.html') + # Id is required + if 'id' not in request.args: + return redirect(url_for('home')) + + # Matching workout required + workout = Workout.query.filter_by(id=int(request.args['id']), user_id=current_user.id).first() + if not workout: + return redirect(url_for('home')); + + return render_template('workout/record.html', workout=workout) @app.route("/workout/select", methods=['GET']) @login_required diff --git a/app/templates/workout/record.html b/app/templates/workout/record.html index bc6b695..6463fe4 100644 --- a/app/templates/workout/record.html +++ b/app/templates/workout/record.html @@ -1,12 +1,49 @@ {% extends 'base/layout.html' %} {% block content %} - -
+
- -
+

Record {{ workout.name }}

+
+ {% for exercise in workout.exercises %} +

{{ exercise.name }}

+
+
+
+ +
+ +
+
+
+ +
+ +
+
+ + +

+ + + +

+
+
+ +
+ + +
+ {% endfor %} +
+
-- cgit v1.2.3 From 404bba9d518271533d5e4c83dabd8541726bf248 Mon Sep 17 00:00:00 2001 From: stilbruch Date: Sat, 23 Apr 2022 14:15:35 -0500 Subject: Move routes into seperate folder --- app/routes.py | 132 -------------------------------------- app/routes/__init__.py | 3 + app/routes/basic.py | 11 ++++ app/routes/user.py | 52 +++++++++++++++ app/routes/workout.py | 77 ++++++++++++++++++++++ app/static/js/record.js | 9 +++ app/templates/workout/record.html | 9 +-- 7 files changed, 157 insertions(+), 136 deletions(-) delete mode 100644 app/routes.py create mode 100644 app/routes/__init__.py create mode 100644 app/routes/basic.py create mode 100644 app/routes/user.py create mode 100644 app/routes/workout.py create mode 100644 app/static/js/record.js diff --git a/app/routes.py b/app/routes.py deleted file mode 100644 index 76ea96a..0000000 --- a/app/routes.py +++ /dev/null @@ -1,132 +0,0 @@ -from app import app, db -from flask import render_template, redirect, request, url_for, flash -from flask_login import current_user, login_user, login_required, logout_user -from forms import LoginForm, RegisterForm, WorkoutCreateForm -from tables import User, Workout - -@app.route("/", methods=["GET"]) -def index(): - return render_template('index.html') - -@app.route("/home", methods=["GET"]) -@login_required -def home(): - return render_template('home.html') - -@app.route("/login", methods=['GET', 'POST']) -def login(): - form = LoginForm() - username = form.username.data - password = form.password.data - - if form.validate_on_submit(): - # Valid submission - user = User.query.filter_by(username=username).first() - - # TODO: show user if login succeeded - if user and user.verify_password(password): - login_user(user) - return redirect(url_for('home')) - else: - flash("Invalid username or password", "danger") - - return render_template('user/login.html', form=form) - -@app.route("/logout", methods=['GET', 'POST']) -def logout(): - logout_user() - return redirect('/') - -@app.route("/register", methods=['GET', 'POST']) -def register(): - form = RegisterForm() - # Load data from form - username = form.username.data - password = form.password.data - email = form.email.data - - if form.validate_on_submit(): - # Valid submission - user = User.query.filter_by(username=username).first() - if not user: - # No user with this username - user = User(username, password, email) - db.session.add(user) - db.session.commit() - return redirect(url_for('login')) - else: - flash("User already exists", "danger") - - return render_template('user/register.html', form=form) - -@app.route("/workout/create", methods=['GET', 'POST']) -@login_required -def createWorkout(): - form = WorkoutCreateForm() - name = form.name.data - - if form.validate_on_submit(): - # Make sure the user doesn't already have a workout with this name - workout = Workout.query.filter_by(user_id=current_user.id, name=name).first() - if not workout: - # TODO: add exercises - workout = Workout(current_user, name, [e.data for e in form.exercises.entries]) - db.session.add(workout) - db.session.commit() - - return redirect(url_for('home')); - else: - flash("Workout with this name already exists", "danger") - - return render_template('workout/create.html', form=form, title="Create a Workout") - -@app.route("/workout/edit", methods=['GET', 'POST']) -@login_required -def editWorkout(): - # Id is required - if 'id' not in request.args: - return redirect(url_for('home')) - - # Validate Id - workout = Workout.query.filter_by(id=int(request.args['id']), user_id=current_user.id).first() - if not workout: - return redirect(url_for('home')) - - form = WorkoutCreateForm() - - if form.validate_on_submit(): - # Form has been submitted, write changes - - workout.name = form.name.data - # TODO: Add exercise changes - - # Write changes to database - db.session.commit() - return redirect(url_for('home')); - else: - form.name.data = workout.name - form.exercises.pop_entry() # TODO: better way to do this? - - for exercise in workout.exercises: - form.exercises.append_entry(exercise) - - return render_template('workout/create.html', form=form, title=f'Edit Workout "{workout.name}"') - -@app.route("/workout/record", methods=['GET']) -@login_required -def recordWorkout(): - # Id is required - if 'id' not in request.args: - return redirect(url_for('home')) - - # Matching workout required - workout = Workout.query.filter_by(id=int(request.args['id']), user_id=current_user.id).first() - if not workout: - return redirect(url_for('home')); - - return render_template('workout/record.html', workout=workout) - -@app.route("/workout/select", methods=['GET']) -@login_required -def selectWorkout(): - return render_template('workout/select.html') diff --git a/app/routes/__init__.py b/app/routes/__init__.py new file mode 100644 index 0000000..e243576 --- /dev/null +++ b/app/routes/__init__.py @@ -0,0 +1,3 @@ +from routes.user import * +from routes.workout import * +from routes.basic import * diff --git a/app/routes/basic.py b/app/routes/basic.py new file mode 100644 index 0000000..36f42f5 --- /dev/null +++ b/app/routes/basic.py @@ -0,0 +1,11 @@ +from app import app, db +from flask_login import login_required + +@app.route("/", methods=["GET"]) +def index(): + return render_template('index.html') + +@app.route("/home", methods=["GET"]) +@login_required +def home(): + return render_template('home.html') diff --git a/app/routes/user.py b/app/routes/user.py new file mode 100644 index 0000000..4568d97 --- /dev/null +++ b/app/routes/user.py @@ -0,0 +1,52 @@ +from app import app, db +from flask import render_template, redirect, request, url_for, flash +from flask_login import current_user, login_user, login_required, logout_user +from forms import LoginForm, RegisterForm +from tables import User + +@app.route("/login", methods=['GET', 'POST']) +def login(): + form = LoginForm() + username = form.username.data + password = form.password.data + + if form.validate_on_submit(): + # Valid submission + user = User.query.filter_by(username=username).first() + + # TODO: show user if login succeeded + if user and user.verify_password(password): + login_user(user) + return redirect(url_for('home')) + else: + flash("Invalid username or password", "danger") + + return render_template('user/login.html', form=form) + +@app.route("/logout", methods=['GET', 'POST']) +def logout(): + logout_user() + return redirect('/') + +@app.route("/register", methods=['GET', 'POST']) +def register(): + form = RegisterForm() + # Load data from form + username = form.username.data + password = form.password.data + email = form.email.data + + if form.validate_on_submit(): + # Valid submission + user = User.query.filter_by(username=username).first() + if not user: + # No user with this username + user = User(username, password, email) + db.session.add(user) + db.session.commit() + return redirect(url_for('login')) + else: + flash("User already exists", "danger") + + return render_template('user/register.html', form=form) + diff --git a/app/routes/workout.py b/app/routes/workout.py new file mode 100644 index 0000000..db8ab48 --- /dev/null +++ b/app/routes/workout.py @@ -0,0 +1,77 @@ +from app import app, db +from flask import render_template, redirect, request, url_for, flash +from flask_login import current_user, login_required +from forms import LoginForm, RegisterForm, WorkoutCreateForm +from tables import User, Workout + +@app.route("/workout/create", methods=['GET', 'POST']) +@login_required +def createWorkout(): + form = WorkoutCreateForm() + name = form.name.data + + if form.validate_on_submit(): + # Make sure the user doesn't already have a workout with this name + workout = Workout.query.filter_by(user_id=current_user.id, name=name).first() + if not workout: + # TODO: add exercises + workout = Workout(current_user, name, [e.data for e in form.exercises.entries]) + db.session.add(workout) + db.session.commit() + + return redirect(url_for('home')); + else: + flash("Workout with this name already exists", "danger") + + return render_template('workout/create.html', form=form, title="Create a Workout") + +@app.route("/workout/edit", methods=['GET', 'POST']) +@login_required +def editWorkout(): + # Id is required + if 'id' not in request.args: + return redirect(url_for('home')) + + # Validate Id + workout = Workout.query.filter_by(id=int(request.args['id']), user_id=current_user.id).first() + if not workout: + return redirect(url_for('home')) + + form = WorkoutCreateForm() + + if form.validate_on_submit(): + # Form has been submitted, write changes + + workout.name = form.name.data + # TODO: Add exercise changes + + # Write changes to database + db.session.commit() + return redirect(url_for('home')); + else: + form.name.data = workout.name + form.exercises.pop_entry() # TODO: better way to do this? + + for exercise in workout.exercises: + form.exercises.append_entry(exercise) + + return render_template('workout/create.html', form=form, title=f'Edit Workout "{workout.name}"') + +@app.route("/workout/record", methods=['GET']) +@login_required +def recordWorkout(): + # Id is required + if 'id' not in request.args: + return redirect(url_for('home')) + + # Matching workout required + workout = Workout.query.filter_by(id=int(request.args['id']), user_id=current_user.id).first() + if not workout: + return redirect(url_for('home')); + + return render_template('workout/record.html', workout=workout) + +@app.route("/workout/select", methods=['GET']) +@login_required +def selectWorkout(): + return render_template('workout/select.html') diff --git a/app/static/js/record.js b/app/static/js/record.js new file mode 100644 index 0000000..fedbdd7 --- /dev/null +++ b/app/static/js/record.js @@ -0,0 +1,9 @@ + +// Called when the check at the end of a set line is clicked +function onClickSetCheck(elem) { + if (elem.classList.contains('is-success')) { + elem.classList.remove('is-success'); + } else { + elem.classList.add('is-success'); + } +} diff --git a/app/templates/workout/record.html b/app/templates/workout/record.html index 6463fe4..0908ef8 100644 --- a/app/templates/workout/record.html +++ b/app/templates/workout/record.html @@ -22,13 +22,12 @@
- - -

+ +

@@ -47,4 +46,6 @@ + + {% endblock %} -- cgit v1.2.3 From 316edff9e6b90ab310978c10adbeffa87d18e746 Mon Sep 17 00:00:00 2001 From: stilbruch Date: Sat, 23 Apr 2022 14:26:59 -0500 Subject: Fix workout deleting option --- app/routes/__init__.py | 1 + app/routes/api.py | 17 +++++++++++++++++ app/routes/basic.py | 1 + app/routes/user.py | 1 + app/templates/home.html | 2 +- 5 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 app/routes/api.py diff --git a/app/routes/__init__.py b/app/routes/__init__.py index e243576..09fcbf3 100644 --- a/app/routes/__init__.py +++ b/app/routes/__init__.py @@ -1,3 +1,4 @@ +from routes.api import * from routes.user import * from routes.workout import * from routes.basic import * diff --git a/app/routes/api.py b/app/routes/api.py new file mode 100644 index 0000000..58b4732 --- /dev/null +++ b/app/routes/api.py @@ -0,0 +1,17 @@ +from app import app, db +from flask import redirect, request +from flask_login import current_user, login_required +from tables import Workout + +@app.route("/api/workout/delete", methods=['GET']) +@login_required +def api_workout_delete(): + if 'id' not in request.args: + return redirect('/home'); + + workout = Workout.query.filter_by(id=int(request.args['id']), user_id=current_user.id).first() + if workout: + db.session.delete(workout) + db.session.commit() + + return redirect('/home') diff --git a/app/routes/basic.py b/app/routes/basic.py index 36f42f5..5883b97 100644 --- a/app/routes/basic.py +++ b/app/routes/basic.py @@ -1,4 +1,5 @@ from app import app, db +from flask import render_template from flask_login import login_required @app.route("/", methods=["GET"]) diff --git a/app/routes/user.py b/app/routes/user.py index 4568d97..d218738 100644 --- a/app/routes/user.py +++ b/app/routes/user.py @@ -24,6 +24,7 @@ def login(): return render_template('user/login.html', form=form) @app.route("/logout", methods=['GET', 'POST']) +@login_required def logout(): logout_user() return redirect('/') diff --git a/app/templates/home.html b/app/templates/home.html index 9f8dfe9..c9aa90d 100644 --- a/app/templates/home.html +++ b/app/templates/home.html @@ -79,7 +79,7 @@

-- cgit v1.2.3 From 3d0202b4faaef7ff0900bcfefca4c88907a2b6d4 Mon Sep 17 00:00:00 2001 From: stilbruch Date: Sat, 23 Apr 2022 15:08:27 -0500 Subject: Update record workout page --- app/static/js/record.js | 33 ++++++++++++++++++++ app/templates/base/layout.html | 2 +- app/templates/workout/record.html | 64 ++++++++++++++++++++------------------- 3 files changed, 67 insertions(+), 32 deletions(-) diff --git a/app/static/js/record.js b/app/static/js/record.js index fedbdd7..75aa148 100644 --- a/app/static/js/record.js +++ b/app/static/js/record.js @@ -1,9 +1,42 @@ +// Register 'Enter' listeners on all inputs +Array.from(document.getElementsByClassName('input')) + .filter(e => e.type == 'number') + .forEach(e => e.addEventListener('keyup', function(event) { + if (event.key == 'Enter') { + console.log("ENTER"); + } + })) + +function checkSet(row) { + // Disable input editing + row.children[1].firstChild.disabled = true; + row.children[2].firstChild.disabled = true; + + // Add is-success to inputs + row.children[1].firstChild.classList.add('is-success') + row.children[2].firstChild.classList.add('is-success') +} + +function uncheckSet(row) { + // Re-enable input editing + row.children[1].firstChild.disabled = false; + row.children[2].firstChild.disabled = false; + + // Remove is-success from inputs + row.children[1].firstChild.classList.remove('is-success') + row.children[2].firstChild.classList.remove('is-success') +} + // Called when the check at the end of a set line is clicked function onClickSetCheck(elem) { if (elem.classList.contains('is-success')) { elem.classList.remove('is-success'); + + uncheckSet(elem.parentElement.parentElement); } else { elem.classList.add('is-success'); + + checkSet(elem.parentElement.parentElement); } } diff --git a/app/templates/base/layout.html b/app/templates/base/layout.html index 89ad385..fe83440 100644 --- a/app/templates/base/layout.html +++ b/app/templates/base/layout.html @@ -47,7 +47,7 @@ - + diff --git a/app/templates/workout/record.html b/app/templates/workout/record.html index 0908ef8..3dfb2c8 100644 --- a/app/templates/workout/record.html +++ b/app/templates/workout/record.html @@ -7,39 +7,41 @@

Record {{ workout.name }}

{% for exercise in workout.exercises %} -

{{ exercise.name }}

-
-
-
- -
- -
-
-
- -
- -
-
- - -
-
- +

{{ exercise.name }}

+ + + + + + + + + {% for i in range(exercise.sets) %} + + + + + + + {% endfor %} + +
SetlbsRepsDone
{{ i }} + +
- - + +
+
{% endfor %}
-- cgit v1.2.3 From 4f1e55112138a1f3b4be3bf23e3740ae3effac35 Mon Sep 17 00:00:00 2001 From: stilbruch Date: Sat, 23 Apr 2022 15:48:45 -0500 Subject: Add javascript to add sets while recording workout --- app/routes/workout.py | 2 +- app/static/js/record.js | 64 ++++++++++++++++++++++-------- app/templates/base/form.html | 2 +- app/templates/workout/record.html | 83 ++++++++++++++++++--------------------- 4 files changed, 89 insertions(+), 62 deletions(-) diff --git a/app/routes/workout.py b/app/routes/workout.py index db8ab48..8615156 100644 --- a/app/routes/workout.py +++ b/app/routes/workout.py @@ -69,7 +69,7 @@ def recordWorkout(): if not workout: return redirect(url_for('home')); - return render_template('workout/record.html', workout=workout) + return render_template('workout/record.html', workout=workout, form=None) @app.route("/workout/select", methods=['GET']) @login_required diff --git a/app/static/js/record.js b/app/static/js/record.js index 75aa148..aba6785 100644 --- a/app/static/js/record.js +++ b/app/static/js/record.js @@ -4,11 +4,44 @@ Array.from(document.getElementsByClassName('input')) .filter(e => e.type == 'number') .forEach(e => e.addEventListener('keyup', function(event) { if (event.key == 'Enter') { - console.log("ENTER"); + // TODO implement + console.log("ENTER") } })) -function checkSet(row) { +function setReset(row, values=true) { + let lbsInput = row.children[1].children[0]; + let repsInput = row.children[2].children[0]; + let doneButton = row.children[3].children[0]; + + // Enable inputs + lbsInput.disabled = false; + repsInput.disabled = false; + + // Remove classes + lbsInput.classList.remove('is-success'); + lbsInput.classList.remove('is-danger'); + repsInput.classList.remove('is-success'); + repsInput.classList.remove('is-danger'); + + doneButton.classList.remove('is-success'); + + if (values) { + lbsInput.value = ''; + repsInput.value = ''; + } +} + +function setSetid(row, id) { + let setNumber = row.children[0]; + let lbsInput = row.children[1].children[0]; + let repsInput = row.children[2].children[0]; + let doneButton = row.children[3].children[0]; + + setNumber.textContent = id + 1; +} + +function setCheck(row) { // Disable input editing row.children[1].firstChild.disabled = true; row.children[2].firstChild.disabled = true; @@ -18,25 +51,24 @@ function checkSet(row) { row.children[2].firstChild.classList.add('is-success') } -function uncheckSet(row) { - // Re-enable input editing - row.children[1].firstChild.disabled = false; - row.children[2].firstChild.disabled = false; - - // Remove is-success from inputs - row.children[1].firstChild.classList.remove('is-success') - row.children[2].firstChild.classList.remove('is-success') -} - // Called when the check at the end of a set line is clicked function onClickSetCheck(elem) { if (elem.classList.contains('is-success')) { - elem.classList.remove('is-success'); - - uncheckSet(elem.parentElement.parentElement); + setReset(elem.parentElement.parentElement, false); } else { elem.classList.add('is-success'); - checkSet(elem.parentElement.parentElement); + setCheck(elem.parentElement.parentElement); } } + +function onClickAddSet(elem) { + // Create the new row + let tableBody = elem.parentElement.parentElement.children[1].children[1]; + let row = tableBody.children[0].cloneNode(true); + + // Add new row to table + setReset(row); + setSetid(row, tableBody.children.length) + tableBody.appendChild(row) +} diff --git a/app/templates/base/form.html b/app/templates/base/form.html index 72083ae..9f356e0 100644 --- a/app/templates/base/form.html +++ b/app/templates/base/form.html @@ -4,7 +4,7 @@