Merge branch 'main' into development

This commit is contained in:
2025-10-18 14:42:51 +02:00
8 changed files with 163 additions and 17 deletions

View File

@@ -17,15 +17,12 @@
</li> </li>
</ul> </ul>
<ul class="navbar-nav"> <ul class="navbar-nav">
{% if current_user.is_authenticated %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{{ url_for('auth.logout') }}">Logout</a> <a class="nav-link" href="{{ url_for('auth.logout') }}">Logout</a>
</li> </li>
{% else %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{{ url_for('auth.login') }}">Login</a> <a class="nav-link" href="{{ url_for('auth.logout') }}">Set</a>
</li> </li>
{% endif %}
<li class="nav-item"> <li class="nav-item">
<button id="toggleTheme" class="btn btn-outline-light">Toggle Theme</button> <button id="toggleTheme" class="btn btn-outline-light">Toggle Theme</button>
</li> </li>

View File

@@ -24,6 +24,7 @@
</a> </a>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="accountDropdown"> <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="accountDropdown">
<li><a class="dropdown-item" href='{{ url_for("auth.change_pass") }}'>Change Password</a></li> <li><a class="dropdown-item" href='{{ url_for("auth.change_pass") }}'>Change Password</a></li>
<li><a class="dropdown-item" href='{{ url_for("user.set_macros") }}'>Set macros</a></li>
<li><a class="dropdown-item" href="#">Profile</a></li> <li><a class="dropdown-item" href="#">Profile</a></li>
<li> <li>
<hr class="dropdown-divider"> <hr class="dropdown-divider">

View File

@@ -9,7 +9,7 @@ from flask import (
) )
from flask_login import current_user from flask_login import current_user
from application import db from application import db
from forms import FoodItemForm from forms import FoodItemForm, MacroForm
from models import FoodItem, FoodLog from models import FoodItem, FoodLog
from datetime import datetime from datetime import datetime
from application.utils import login_required, macro_arr_to_json from application.utils import login_required, macro_arr_to_json
@@ -117,3 +117,20 @@ def remove_log(id: int):
db.session.delete(log) db.session.delete(log)
db.session.commit() db.session.commit()
return redirect(url_for("user.daily_log")) return redirect(url_for("user.daily_log"))
@user_bp.route("/set_macros", methods=["GET", "POST"])
def set_macros():
form = MacroForm()
if form.validate_on_submit():
current_user.set_macros(
form.protein.data,
form.carbohydrates.data,
form.fat.data,
form.calories.data,
)
db.session.commit()
return redirect(url_for("user.daily_log"))
return render_template("settings.html", form=form)

View File

@@ -0,0 +1,30 @@
{% extends "base.html"%}
{% block title %} Daily Macro Settings {% endblock %}
{% block content %}
<div class="container py-5">
<h2 class="mb-4 text-center">Set Your Daily Macro Targets</h2>
<form action="{{ url_for('user.set_macros') }}" method="POST" class="card p-4 shadow-sm bg-body-secondary">
{{ form.hidden_tag() }}
<div class="mb-3">
<label for="protein" class="form-label">Protein (g)</label>
{{form.protein(class="form-control")}}
</div>
<div class="mb-3">
<label for="carbs" class="form-label">Carbohydrates (g)</label>
{{form.carbohydrates(class="form-control")}}
</div>
<div class="mb-3">
<label for="fat" class="form-label">Fat (g)</label>
{{form.fat(class="form-control")}}
</div>
<div class="mb-3">
<label for="calories" class="form-label">Calories (kcal)</label>
{{form.calories(class="form-control")}}
</div>
{{form.submit(class="btn btn-primary")}}
</form>
</div>
{% endblock %}

View File

@@ -41,9 +41,11 @@ def macro_arr_to_json(data: list[float]):
{ {
"name": "Calories", "name": "Calories",
"current": cal, "current": cal,
"target": 2000, "target": current_user.calories,
"bar_width": 100 - abs(cal / 20 - 100), "bar_width": 100 - abs(cal * 100 / current_user.calories - 100),
"bar_width_overflow": max(0, cal / 20 - 100), "bar_width_overflow": max(
0, cal * 100 / current_user.calories - 100
),
"unit": " kcal", "unit": " kcal",
"color": "bg-calories", "color": "bg-calories",
"overflow_color": "bg-calories-dark", "overflow_color": "bg-calories-dark",
@@ -51,9 +53,11 @@ def macro_arr_to_json(data: list[float]):
{ {
"name": "Protein", "name": "Protein",
"current": pro, "current": pro,
"target": 150, "target": current_user.protein,
"bar_width": 100 - abs(pro / 1.5 - 100), "bar_width": 100 - abs(pro * 100 / current_user.protein - 100),
"bar_width_overflow": max(0, pro / 1.5 - 100), "bar_width_overflow": max(
0, pro * 100 / current_user.protein - 100
),
"unit": "g", "unit": "g",
"color": "bg-protein", "color": "bg-protein",
"overflow_color": "bg-protein-dark", "overflow_color": "bg-protein-dark",
@@ -61,9 +65,12 @@ def macro_arr_to_json(data: list[float]):
{ {
"name": "Carbs", "name": "Carbs",
"current": car, "current": car,
"target": 250, "target": current_user.carbohydrates,
"bar_width": 100 - abs(car / 2.5 - 100), "bar_width": 100
"bar_width_overflow": max(0, car / 2.5 - 100), - abs(car * 100 / current_user.carbohydrates - 100),
"bar_width_overflow": max(
0, car * 100 / current_user.carbohydrates - 100
),
"unit": "g", "unit": "g",
"color": "bg-carbs", "color": "bg-carbs",
"overflow_color": "bg-carbs-dark", "overflow_color": "bg-carbs-dark",
@@ -71,9 +78,9 @@ def macro_arr_to_json(data: list[float]):
{ {
"name": "Fat", "name": "Fat",
"current": fat, "current": fat,
"target": 70, "target": current_user.fat,
"bar_width": 100 - abs(fat / 0.7 - 100), "bar_width": 100 - abs(fat * 100 / current_user.fat - 100),
"bar_width_overflow": max(0, fat / 0.7 - 100), "bar_width_overflow": max(0, fat * 100 / current_user.fat - 100),
"unit": "g", "unit": "g",
"color": "bg-fat", "color": "bg-fat",
"overflow_color": "bg-fat-dark", "overflow_color": "bg-fat-dark",

View File

@@ -68,6 +68,30 @@ class FoodItemForm(FlaskForm):
submit = SubmitField("Add Item") submit = SubmitField("Add Item")
class MacroForm(FlaskForm):
protein = FloatField(
"Protein (g)",
validators=[InputRequired()],
render_kw={"inputmode": "decimal"},
)
carbohydrates = FloatField(
"Carbohydrates (g)",
validators=[InputRequired()],
render_kw={"inputmode": "decimal"},
)
fat = FloatField(
"Fat (g)",
validators=[InputRequired()],
render_kw={"inputmode": "decimal"},
)
calories = FloatField(
"Calories (kcal)",
validators=[InputRequired()],
render_kw={"inputmode": "decimal"},
)
submit = SubmitField("Update macros")
class FoodLogForm(FlaskForm): class FoodLogForm(FlaskForm):
amount = FloatField("amount of food (g/ml)", validators=[DataRequired()]) amount = FloatField("amount of food (g/ml)", validators=[DataRequired()])
submit = SubmitField("Log Item") submit = SubmitField("Log Item")

View File

@@ -0,0 +1,56 @@
"""empty message
Revision ID: 21ec41b645e9
Revises: 65eaeafb0904
Create Date: 2025-10-10 19:26:21.718736
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "21ec41b645e9"
down_revision = "65eaeafb0904"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("user", schema=None) as batch_op:
batch_op.add_column(
sa.Column(
"protein", sa.Float(), nullable=False, server_default="100"
)
)
batch_op.add_column(
sa.Column(
"carbohydrates",
sa.Float(),
nullable=False,
server_default="250",
)
)
batch_op.add_column(
sa.Column("fat", sa.Float(), nullable=False, server_default="60")
)
batch_op.add_column(
sa.Column(
"calories", sa.Float(), nullable=False, server_default="2000"
)
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("user", schema=None) as batch_op:
batch_op.drop_column("calories")
batch_op.drop_column("fat")
batch_op.drop_column("carbohydrates")
batch_op.drop_column("protein")
# ### end Alembic commands ###

View File

@@ -16,6 +16,11 @@ class User(UserMixin, db.Model):
is_admin = db.Column(db.Boolean, nullable=False, default=False) is_admin = db.Column(db.Boolean, nullable=False, default=False)
must_change_password = db.Column(db.Boolean, nullable=False, default=False) must_change_password = db.Column(db.Boolean, nullable=False, default=False)
protein = db.Column(db.Float, nullable=False)
carbohydrates = db.Column(db.Float, nullable=False)
fat = db.Column(db.Float, nullable=False)
calories = db.Column(db.Float, nullable=False)
food_items = db.relationship("FoodItem", lazy="dynamic", backref="user") food_items = db.relationship("FoodItem", lazy="dynamic", backref="user")
food_logs = db.relationship("FoodLog", lazy="dynamic", backref="user") food_logs = db.relationship("FoodLog", lazy="dynamic", backref="user")
@@ -32,6 +37,15 @@ class User(UserMixin, db.Model):
self.is_admin = is_admin self.is_admin = is_admin
self.must_change_password = must_change_password self.must_change_password = must_change_password
def set_macros(
self, protein: float, carbs: float, fat: float, calories: float
):
self.protein = protein
self.carbohydrates = carbs
self.fat = fat
self.calories = calories
return
def check_password(self, password: str) -> bool: def check_password(self, password: str) -> bool:
return check_password_hash(pwhash=self.password, password=password) return check_password_hash(pwhash=self.password, password=password)