diff --git a/.gitignore b/.gitignore
index de64807..549b6f6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+#
# Miscellaneous
*.class
*.lock
@@ -124,3 +125,157 @@ app.*.symbols
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
!/dev/ci/**/Gemfile.lock
+
+## Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/ Flutter
diff --git a/API/README.md b/API/README.md
new file mode 100644
index 0000000..a7ab7a6
--- /dev/null
+++ b/API/README.md
@@ -0,0 +1,9 @@
+# Communication
+
+### How to run
+```bash
+docker-compose up --build
+```
+
+### Webapp
+[Url](http://localhost/)
diff --git a/API/webapp/.gitignore b/API/webapp/.gitignore
new file mode 100644
index 0000000..111de12
--- /dev/null
+++ b/API/webapp/.gitignore
@@ -0,0 +1,2 @@
+# Docker volumes
+/volumes/mongo
\ No newline at end of file
diff --git a/API/webapp/docker-compose.yml b/API/webapp/docker-compose.yml
new file mode 100644
index 0000000..c098f93
--- /dev/null
+++ b/API/webapp/docker-compose.yml
@@ -0,0 +1,33 @@
+version: "3.7"
+
+services:
+ flask:
+ build: ./flask
+ container_name: flask
+ restart: always
+ environment:
+ - APP_NAME=SmartGainsDatabase
+ expose:
+ - 8080
+
+ nginx:
+ build: ./nginx
+ container_name: nginx
+ restart: always
+ ports:
+ - "80:80"
+
+ mongo:
+ image: mongo:4.4.3
+ env_file: ./.env
+ container_name: mongo
+ environment:
+ - MONGO_INITDB_ROOT_USERNAME=$MONGO_ROOT_USERNAME
+ - MONGO_INITDB_ROOT_PASSWORD=$MONGO_ROOT_PASSWORD
+ - MONGO_INITDB_DATABASE=admin
+ volumes:
+ - ./volumes/mongo/data/db/:/data/db/
+ - ./volumes/mongo/log/:/var/log/mongodb/
+ expose:
+ - 27017
+ command: ["--bind_ip", "0.0.0.0"]
\ No newline at end of file
diff --git a/API/webapp/flask/Dockerfile b/API/webapp/flask/Dockerfile
new file mode 100644
index 0000000..76a76dc
--- /dev/null
+++ b/API/webapp/flask/Dockerfile
@@ -0,0 +1,14 @@
+# Use the Python3.7.2 image
+FROM python:3.7.2-stretch
+
+# Set the working directory to /app
+WORKDIR /webapp
+
+# Copy the current directory contents into the container at /challenge
+ADD . /webapp
+
+# Install the dependencies
+RUN pip3 install -r requirements.txt
+
+# run the command to start uWSGI
+CMD ["uwsgi", "app.ini"]
\ No newline at end of file
diff --git a/API/webapp/flask/app.ini b/API/webapp/flask/app.ini
new file mode 100644
index 0000000..bdf5a7d
--- /dev/null
+++ b/API/webapp/flask/app.ini
@@ -0,0 +1,10 @@
+[uwsgi]
+wsgi-file = run.py
+callable = app
+socket = :8080
+processes = 4
+threads = 2
+master = true
+chmod-socket = 660
+vacuum = true
+die-on-term = true
\ No newline at end of file
diff --git a/API/webapp/flask/app/__init__.py b/API/webapp/flask/app/__init__.py
new file mode 100644
index 0000000..ad3de73
--- /dev/null
+++ b/API/webapp/flask/app/__init__.py
@@ -0,0 +1,5 @@
+from flask import Flask, render_template
+
+app = Flask(__name__, static_folder='static', static_url_path='')
+
+from app import views
\ No newline at end of file
diff --git a/API/webapp/flask/app/static/robots.txt b/API/webapp/flask/app/static/robots.txt
new file mode 100644
index 0000000..77470cb
--- /dev/null
+++ b/API/webapp/flask/app/static/robots.txt
@@ -0,0 +1,2 @@
+User-agent: *
+Disallow: /
\ No newline at end of file
diff --git a/API/webapp/flask/app/templates/404.html b/API/webapp/flask/app/templates/404.html
new file mode 100644
index 0000000..d89a149
--- /dev/null
+++ b/API/webapp/flask/app/templates/404.html
@@ -0,0 +1,14 @@
+
+
+
+
+404 - this page does not exist
+
+
+
+
+ 404 Not Found
+
+
+
\ No newline at end of file
diff --git a/API/webapp/flask/app/views.py b/API/webapp/flask/app/views.py
new file mode 100644
index 0000000..5a15e2d
--- /dev/null
+++ b/API/webapp/flask/app/views.py
@@ -0,0 +1,318 @@
+from flask import request, jsonify
+from app import app
+from flask_cors import cross_origin
+import pymongo
+from bson.json_util import dumps
+
+
+# mock database created with pymongo
+myclient = pymongo.MongoClient("mongodb://mongo:27017/", username='admin', password='admin', authSource='admin', authMechanism='SCRAM-SHA-256')
+# create or get db
+mydb = myclient["SmartGainsTest"]
+# create or get collection
+mycol = mydb["CollectionTest"]
+
+mydict = {"init": "yes"}
+x = mycol.insert_one(mydict)
+
+
+# debug material
+@app.route("/")
+@cross_origin()
+def index():
+ return {}
+
+
+@app.route('/user/inf', methods=['PUT'])
+@cross_origin()
+def UserInf():
+
+ username = request.args.get("username")
+
+ # curl http://localhost:8393/user/inf?username=
+ # -d "weight=" -d "height=" -d "gender=" -d "birth="
+ # -X PUT
+
+ if request.method == 'PUT':
+
+ weight = request.form['weight']
+ height = request.form['height']
+ gender = request.form['gender']
+ birth = request.form['dateOfBirth']
+ objective = request.form["dailyGoal"]
+
+ result = []
+ for x in mycol.find({"username": username}):
+ result.append(x)
+
+ if result != []:
+
+ mydict = {"username": username}
+ update_to = {"$set" : {'weight' : weight}}
+ x = mycol.update_one(mydict, update_to)
+ update_to = {"$set" : {'height' : height}}
+ x = mycol.update_one(mydict, update_to)
+ update_to = {"$set" : {'gender' : gender}}
+ x = mycol.update_one(mydict, update_to)
+ update_to = {"$set" : {'dateOfBirth' : birth}}
+ x = mycol.update_one(mydict, update_to)
+ update_to = {"$set" : {'dailyGoal' : objective}}
+ x = mycol.update_one(mydict, update_to)
+
+ return dumps(mycol.find({"username": username}))
+
+ return jsonify({"command": "Failed", "error": "Could not update the user"})
+
+ return jsonify({"command": "Failed", "error": "Request method incorrect"})
+
+
+# @app.route('/user/activity', methods=['PUT'])
+# @cross_origin()
+# def UserActivity():
+
+# username = request.args.get("username")
+
+# # curl http://localhost:8393/user/activity?username=
+# # -d "activity="
+# # -X PUT
+
+# if request.method == 'PUT':
+
+# activity = request.form['activity']
+
+# result = []
+# for x in mycol.find({"username": username}):
+# result.append(x)
+
+# if result != []:
+
+# mydict = {"username": username}
+# update_to = {"$set" : {'activity' : activity}}
+# x = mycol.update_one(mydict, update_to)
+
+# return dumps(mycol.find({"username": username}))
+
+# return jsonify({"command": "Failed", "error": "Could not update the user"})
+
+# return jsonify({"command": "Failed", "error": "Request method incorrect"})
+
+
+# @app.route('/user/goals', methods=['PUT'])
+# @cross_origin()
+# def UserGoals():
+
+# username = request.args.get("username")
+
+# # curl http://localhost:8393/user/activity?username=
+# # -d "goals=" -d "dailyGoal="
+# # -X PUT
+
+# if request.method == 'PUT':
+
+# goals = request.form['goals']
+# dailyGoal = request.form['dailyGoal']
+
+# result = []
+# for x in mycol.find({"username": username}):
+# result.append(x)
+
+# if result != []:
+
+# mydict = {"username": username}
+# update_to = {"$set" : {'goals' : goals}}
+# x = mycol.update_one(mydict, update_to)
+# update_to = {"$set" : {'dailyGoal' : dailyGoal}}
+# x = mycol.update_one(mydict, update_to)
+
+# return dumps(mycol.find({"username": username}))
+
+# return jsonify({"command": "Failed", "error": "Could not update the user"})
+
+# return jsonify({"command": "Failed", "error": "Request method incorrect"})
+
+
+@app.route('/user', methods=['GET', 'POST', 'PUT'])
+@cross_origin()
+def User():
+
+ username = request.args.get("username")
+
+ # curl http://localhost:8393/user?username=
+ # -d "password=" -d "email=""
+ # -X POST
+ if request.method == 'POST':
+
+ password = request.form['password']
+ email = request.form['email']
+
+ result = []
+ for x in mycol.find({"username": username}):
+ result.append(x)
+
+ if result == []:
+ mydict = { "username": username, "password": password, "email": email}
+ x = mycol.insert_one(mydict)
+
+ # return identification and photo
+ return dumps(mycol.find({"username": username}))
+
+ return jsonify({"command": "Failed", "error": "Username already exists"})
+
+
+ # curl http://localhost:8393/user?username=
+ # -X GET
+ elif request.method == 'GET':
+
+ result = []
+ for x in mycol.find({"username": username}):
+ result.append(x)
+
+ return dumps(result)
+
+ # curl http://localhost:8393/user?username=
+ # -d "weight="
+ # -X GET
+ elif request.method == 'PUT':
+
+ weight = request.form['weight']
+ exercise = request.form['exercise']
+
+ mydict = {"username": username}
+ update_to = {"$set" : {exercise : weight}}
+ x = mycol.update_one(mydict, update_to)
+
+ return dumps(mycol.find({"username": username}))
+
+
+ return jsonify({"command": "Failed", "error": "Request method incorrect"})
+
+
+# @app.route('/databackend', methods=['PUT'])
+# @cross_origin()
+# def DataBackend():
+# # curl http://localhost:8393/databackend
+# # -d "repCount=" -d "goodRepCount=" -d "username="
+# # -X PUT
+
+# if request.method == 'PUT':
+
+# repCount = request.form['repCount']
+# goodRepCount = request.form['goodRepCount']
+# badRepCount = request.form['badRepCount']
+# username = request.form["username"]
+
+# result = []
+# for x in mycol.find({"username": username}):
+# result.append(x)
+
+# if result != []:
+# mydict = {"username": username}
+# update_to = {"$set" : {'repCount' : repCount}}
+# x = mycol.update_one(mydict, update_to)
+# update_to = {"$set" : {'goodRepCount' : goodRepCount}}
+# x = mycol.update_one(mydict, update_to)
+# update_to = {"$set" : {'badRepCount' : badRepCount}}
+# x = mycol.update_one(mydict, update_to)
+
+# return dumps(mycol.find({"username": username}))
+
+# return jsonify({"command": "Failed", "error": "Could not update the user"})
+
+# return jsonify({"command": "Failed", "error": "Request method incorrect"})
+
+
+# @app.route('/datafrontend', methods=['PUT'])
+# @cross_origin()
+# def DataFrontend():
+# # curl http://localhost:8393/datafrontend
+# # -d "hours:" -d "day:" -d "username="
+# # -X PUT
+
+# if request.method == 'PUT':
+
+# hours = request.form['hours']
+# days = request.form['day']
+# username = request.form["username"]
+
+# result = []
+# for x in mycol.find({"username": username}):
+# result.append(x)
+
+# if result != []:
+# mydict = {"username": username}
+# update_to = {"$set" : {'hoursDay' : {days: hours}}}
+# x = mycol.update_one(mydict, update_to)
+
+# return dumps(mycol.find({"username": username}))
+
+# return jsonify({"command": "Failed", "error": "Could not update the user"})
+
+# return jsonify({"command": "Failed", "error": "Request method incorrect"})
+
+
+@app.route('/potencial', methods=['PUT'])
+@cross_origin()
+def Potencial():
+ # curl http://localhost:8393/datafrontend
+ # -d "potencial:" -d "exercise:" -d "username="
+ # -X PUT
+
+ if request.method == 'PUT':
+
+ exercise = request.form['exercise']
+ potencial = request.form['class']
+ percetClass = request.form['rate']
+ username = request.form["user"]
+
+ result = []
+ for x in mycol.find({"username": username}):
+ result.append(x)
+
+ if result != []:
+
+ pot = {exercise: {"potencialEx": potencial, "percetClass": percetClass}}
+
+ mydict = {"username": username}
+ update_to = {"$set" : {"potencial" : pot}}
+ x = mycol.update_one(mydict, update_to)
+
+ return dumps(mycol.find({"username": username}))
+
+ return jsonify({"command": "Failed", "error": "Could not update the user"})
+
+ return jsonify({"command": "Failed", "error": "Request method incorrect"})
+
+
+
+
+# @app.route('/gifs', methods=['PUT'])
+# @cross_origin()
+# def Gifs():
+# # curl http://localhost:8393/gifs
+# # -d "gifs:" "username="
+# # -X PUT
+
+# username = request.args.get("username")
+
+# if request.method == 'PUT':
+
+# gifs = request.form['gifs']
+
+# result = []
+# for x in mycol.find({"username": username}):
+# result.append(x)
+
+# if result != []:
+# mydict = {"username": username}
+# update_to = {"$set" : {'gifs' : gifs}}
+# x = mycol.update_one(mydict, update_to)
+
+# return dumps(mycol.find({"username": username}))
+
+# return jsonify({"command": "Failed", "error": "Could not update the user"})
+
+# return jsonify({"command": "Failed", "error": "Request method incorrect"})
+
+@app.errorhandler(404)
+def page_not_found(e):
+ return jsonify({"command": "Failed", "error": "Error handling the request"})
\ No newline at end of file
diff --git a/API/webapp/flask/requirements.txt b/API/webapp/flask/requirements.txt
new file mode 100644
index 0000000..8c51908
--- /dev/null
+++ b/API/webapp/flask/requirements.txt
@@ -0,0 +1,4 @@
+Flask==2.1.1
+uWSGI
+flask_cors
+pymongo
\ No newline at end of file
diff --git a/API/webapp/flask/run.py b/API/webapp/flask/run.py
new file mode 100644
index 0000000..c81cb8d
--- /dev/null
+++ b/API/webapp/flask/run.py
@@ -0,0 +1,5 @@
+from app import app
+
+if __name__ == "__main__":
+ app.run(host='0.0.0.0')
+
\ No newline at end of file
diff --git a/API/webapp/nginx/Dockerfile b/API/webapp/nginx/Dockerfile
new file mode 100644
index 0000000..137f097
--- /dev/null
+++ b/API/webapp/nginx/Dockerfile
@@ -0,0 +1,8 @@
+# Use the Nginx image
+FROM nginx
+
+# Remove the default nginx.conf
+RUN rm /etc/nginx/conf.d/default.conf
+
+# Replace with our own nginx.conf
+COPY nginx.conf /etc/nginx/conf.d/
\ No newline at end of file
diff --git a/API/webapp/nginx/nginx.conf b/API/webapp/nginx/nginx.conf
new file mode 100644
index 0000000..1ffac49
--- /dev/null
+++ b/API/webapp/nginx/nginx.conf
@@ -0,0 +1,10 @@
+server {
+
+ listen 80;
+
+ location / {
+ include uwsgi_params;
+ uwsgi_pass flask:8080;
+ }
+
+}
\ No newline at end of file
diff --git a/API/webapp/volumes/.gitkeep b/API/webapp/volumes/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Backend/ExerciseData/curl_age_f.csv b/Backend/ExerciseData/curl_age_f.csv
new file mode 100644
index 0000000..4258322
--- /dev/null
+++ b/Backend/ExerciseData/curl_age_f.csv
@@ -0,0 +1,17 @@
+Age,Beginner,Novice,Intermediate,Advanced,Elite
+15,6,12,21,33,47
+20,6,14,24,38,53
+25,6,14,25,39,55
+30,6,14,25,39,55
+35,6,14,25,39,55
+40,6,14,25,39,55
+45,6,13,23,37,52
+50,6,12,22,34,49
+55,5,11,20,32,45
+60,5,10,19,29,41
+65,4,9,17,26,37
+70,4,8,15,23,33
+75,4,8,13,21,30
+80,3,7,12,19,27
+85,3,6,11,17,24
+90,3,5,10,15,22
diff --git a/Backend/ExerciseData/curl_age_m.csv b/Backend/ExerciseData/curl_age_m.csv
new file mode 100644
index 0000000..a98816f
--- /dev/null
+++ b/Backend/ExerciseData/curl_age_m.csv
@@ -0,0 +1,17 @@
+Age,Beginner,Novice,Intermediate,Advanced,Elite
+15,15,25,40,58,77
+20,17,29,46,66,89
+25,17,30,47,68,91
+30,17,30,47,68,91
+35,17,30,47,68,91
+40,17,30,47,68,91
+45,16,28,44,64,86
+50,15,27,42,60,81
+55,14,25,39,56,75
+60,13,22,35,51,68
+65,12,20,32,46,62
+70,11,18,29,41,55
+75,9,16,26,37,50
+80,8,15,23,33,44
+85,8,13,20,30,40
+90,7,12,18,27,36
diff --git a/Backend/ExerciseData/curl_bw_f.csv b/Backend/ExerciseData/curl_bw_f.csv
new file mode 100644
index 0000000..d6e3806
--- /dev/null
+++ b/Backend/ExerciseData/curl_bw_f.csv
@@ -0,0 +1,18 @@
+Bodyweight,Beginner,Novice,Intermediate,Advanced,Elite
+40,3,8,17,28,41
+45,4,10,19,30,44
+50,5,11,20,32,47
+55,5,12,22,34,49
+60,6,13,23,36,51
+65,7,14,25,38,54
+70,8,15,26,40,56
+75,8,16,27,41,57
+80,9,17,29,43,59
+85,10,18,30,44,61
+90,10,19,31,46,63
+95,11,20,32,47,64
+100,12,21,33,49,66
+105,12,22,34,50,67
+110,13,23,35,51,69
+115,14,23,36,52,70
+120,14,24,37,53,71
diff --git a/Backend/ExerciseData/curl_bw_m.csv b/Backend/ExerciseData/curl_bw_m.csv
new file mode 100644
index 0000000..1ca5808
--- /dev/null
+++ b/Backend/ExerciseData/curl_bw_m.csv
@@ -0,0 +1,20 @@
+Bodyweight,Beginner,Novice,Intermediate,Advanced,Elite
+50,9,18,30,46,64
+55,11,20,34,50,69
+60,13,23,37,54,73
+65,14,25,40,58,78
+70,16,27,43,61,82
+75,18,30,45,64,85
+80,19,32,48,67,89
+85,21,34,50,70,93
+90,23,36,53,73,96
+95,24,38,55,76,99
+100,26,40,58,79,102
+105,27,42,60,82,105
+110,29,43,62,84,108
+115,30,45,64,87,111
+120,32,47,66,89,114
+125,33,49,68,91,116
+130,34,50,70,94,119
+135,36,52,72,96,121
+140,37,54,74,98,124
\ No newline at end of file
diff --git a/Backend/ExerciseData/curl_rates_f.csv b/Backend/ExerciseData/curl_rates_f.csv
new file mode 100644
index 0000000..e0433c3
--- /dev/null
+++ b/Backend/ExerciseData/curl_rates_f.csv
@@ -0,0 +1,2 @@
+Beginner,Novice,Intermediate,Advanced,Elite
+5,22,52,80,92
diff --git a/Backend/ExerciseData/curl_rates_m.csv b/Backend/ExerciseData/curl_rates_m.csv
new file mode 100644
index 0000000..5e7f2a6
--- /dev/null
+++ b/Backend/ExerciseData/curl_rates_m.csv
@@ -0,0 +1,2 @@
+Beginner,Novice,Intermediate,Advanced,Elite
+6,21,51,80,95
diff --git a/Backend/ExerciseData/pushup_age_f.csv b/Backend/ExerciseData/pushup_age_f.csv
new file mode 100644
index 0000000..e18144d
--- /dev/null
+++ b/Backend/ExerciseData/pushup_age_f.csv
@@ -0,0 +1,17 @@
+Bodyweight,Beginner,Novice,Intermediate,Advanced,Elite
+15, 1, 1,12,27,43
+20, 1,5,18,35,54
+25, 1,5,19,37,56
+30, 1,5,19,37,56
+35, 1,5,19,37,56
+40, 1,5,19,37,56
+45, 1,4,16,33,51
+50, 1,1,14,29,46
+55, 1, 1,10,25,41
+60, 1, 1,8,20,35
+65, 1, 1,5,15,28
+70, 1, 1,1,11,22
+75, 1, 1, 1,7,17
+80, 1, 1, 1,4,12
+85, 1, 1, 1, 1,9
+90, 1, 1, 1, 1,5
diff --git a/Backend/ExerciseData/pushup_age_m.csv b/Backend/ExerciseData/pushup_age_m.csv
new file mode 100644
index 0000000..df7822e
--- /dev/null
+++ b/Backend/ExerciseData/pushup_age_m.csv
@@ -0,0 +1,17 @@
+Age,Beginner,Novice,Intermediate,Advanced,Elite
+15, 1,11,30,54,80
+20, 1,16,39,66,95
+25,1,18,41,68,99
+30,1,18,41,68,99
+35,1,18,41,68,99
+40,1,18,41,68,99
+45, 1,15,37,63,92
+50, 1,12,33,57,85
+55, 1,10,28,51,76
+60, 1,7,23,44,67
+65, 1,4,18,37,58
+70, 1, 1,13,30,49
+75, 1, 1,9,24,40
+80, 1, 1,6,18,33
+85, 1, 1,2,13,27
+90, 1, 1, 1,9,21
diff --git a/Backend/ExerciseData/pushup_bw_f.csv b/Backend/ExerciseData/pushup_bw_f.csv
new file mode 100644
index 0000000..1c0ccf6
--- /dev/null
+++ b/Backend/ExerciseData/pushup_bw_f.csv
@@ -0,0 +1,18 @@
+Bodyweight,Beginner,Novice,Intermediate,Advanced,Elite
+40, 1,4,19,39,61
+45, 1,5,20,38,59
+50, 1,6,20,37,57
+55, 1,6,20,36,54
+60, 1,7,19,35,52
+65, 1,7,19,34,50
+70, 1,7,18,33,48
+75, 1,7,18,31,46
+80, 1,6,17,30,45
+85, 1,6,16,29,43
+90, 1,6,16,28,41
+95, 1,6,15,27,40
+100, 1,6,15,26,38
+105, 1,5,14,25,37
+110, 1,5,13,24,36
+115, 1,5,13,23,35
+120, 1,4,12,22,33
diff --git a/Backend/ExerciseData/pushup_bw_m.csv b/Backend/ExerciseData/pushup_bw_m.csv
new file mode 100644
index 0000000..1e1ca59
--- /dev/null
+++ b/Backend/ExerciseData/pushup_bw_m.csv
@@ -0,0 +1,20 @@
+Bodyweight,Beginner,Novice,Intermediate,Advanced,Elite
+50,1,16,42,73,108
+55,1,17,42,72,105
+60,1,18,42,70,102
+65,2,19,42,69,99
+70,3,19,41,67,96
+75,4,19,41,66,93
+80,5,20,40,64,91
+85,5,20,39,63,88
+90,5,19,39,61,86
+95,6,19,38,60,83
+100,6,19,37,58,81
+105,6,19,37,57,79
+110,6,19,36,56,77
+115,6,18,35,54,75
+120,6,18,34,53,73
+125,6,18,34,52,71
+130,6,17,33,51,70
+135,6,17,32,49,68
+140,6,17,32,48,66
\ No newline at end of file
diff --git a/Backend/ExerciseData/pushup_rates_f.csv b/Backend/ExerciseData/pushup_rates_f.csv
new file mode 100644
index 0000000..9346713
--- /dev/null
+++ b/Backend/ExerciseData/pushup_rates_f.csv
@@ -0,0 +1,2 @@
+Beginner,Novice,Intermediate,Advanced,Elite
+11,22,51,81,95
diff --git a/Backend/ExerciseData/pushup_rates_m.csv b/Backend/ExerciseData/pushup_rates_m.csv
new file mode 100644
index 0000000..38008cc
--- /dev/null
+++ b/Backend/ExerciseData/pushup_rates_m.csv
@@ -0,0 +1,2 @@
+Beginner,Novice,Intermediate,Advanced,Elite
+5,20,50,80,95
diff --git a/Backend/ExerciseData/squat_age_f.csv b/Backend/ExerciseData/squat_age_f.csv
new file mode 100644
index 0000000..993bc62
--- /dev/null
+++ b/Backend/ExerciseData/squat_age_f.csv
@@ -0,0 +1,17 @@
+Age,Beginner,Novice,Intermediate,Advanced,Elite
+15,25,41,62,88,116
+20,29,47,71,100,132
+25,30,48,73,103,136
+30,30,48,73,103,136
+35,30,48,73,103,136
+40,30,48,73,103,136
+45,28,46,69,97,129
+50,26,43,65,92,121
+55,24,40,60,85,112
+60,22,36,55,77,102
+65,20,33,50,70,92
+70,18,29,44,63,83
+75,16,26,40,56,74
+80,14,24,36,50,66
+85,13,21,32,45,59
+90,12,19,29,40,54
diff --git a/Backend/ExerciseData/squat_age_m.csv b/Backend/ExerciseData/squat_age_m.csv
new file mode 100644
index 0000000..e543536
--- /dev/null
+++ b/Backend/ExerciseData/squat_age_m.csv
@@ -0,0 +1,17 @@
+Age,Beginner,Novice,Intermediate,Advanced,Elite
+15,55,80,111,147,187
+20,62,91,127,168,214
+25,64,93,130,173,219
+30,64,93,130,173,219
+35,64,93,130,173,219
+40,64,93,130,173,219
+45,61,89,123,164,208
+50,57,83,116,154,195
+55,53,77,107,142,180
+60,48,70,98,130,165
+65,44,63,88,117,149
+70,39,57,79,105,134
+75,35,51,71,94,119
+80,31,46,63,84,107
+85,28,41,57,75,96
+90,25,37,51,68,86
diff --git a/Backend/ExerciseData/squat_bw_f.csv b/Backend/ExerciseData/squat_bw_f.csv
new file mode 100644
index 0000000..ab24afd
--- /dev/null
+++ b/Backend/ExerciseData/squat_bw_f.csv
@@ -0,0 +1,18 @@
+Bodyweight,Beginner,Novice,Intermediate,Advanced,Elite
+40,17,31,51,75,101
+45,20,36,56,81,109
+50,23,39,61,87,115
+55,26,43,65,92,122
+60,29,47,70,97,128
+65,32,50,74,102,133
+70,34,53,78,106,138
+75,37,56,81,111,143
+80,39,59,85,115,148
+85,41,62,88,119,152
+90,44,65,91,123,157
+95,46,68,95,126,161
+100,48,70,98,130,165
+105,50,73,101,133,169
+110,52,75,103,136,172
+115,54,77,106,140,176
+120,56,80,109,143,179
diff --git a/Backend/ExerciseData/squat_bw_m.csv b/Backend/ExerciseData/squat_bw_m.csv
new file mode 100644
index 0000000..4b9a998
--- /dev/null
+++ b/Backend/ExerciseData/squat_bw_m.csv
@@ -0,0 +1,20 @@
+Bodyweight,Beginner,Novice,Intermediate,Advanced,Elite
+50,33,52,76,104,136
+55,40,60,86,116,149
+60,47,68,95,127,161
+65,53,76,104,137,173
+70,59,83,113,147,184
+75,66,91,122,157,195
+80,72,98,130,166,205
+85,78,105,138,175,215
+90,83,112,146,184,225
+95,89,118,153,192,234
+100,95,125,160,201,243
+105,100,131,168,209,252
+110,106,137,174,216,260
+115,111,143,181,224,269
+120,116,149,188,231,277
+125,121,155,194,238,284
+130,126,160,201,245,292
+135,131,166,207,252,299
+140,136,171,213,259,307
diff --git a/Backend/ExerciseData/squat_rates_f.csv b/Backend/ExerciseData/squat_rates_f.csv
new file mode 100644
index 0000000..0f3c74d
--- /dev/null
+++ b/Backend/ExerciseData/squat_rates_f.csv
@@ -0,0 +1,2 @@
+Beginner,Novice,Intermediate,Advanced,Elite
+5,21,51,80,95
diff --git a/Backend/ExerciseData/squat_rates_m.csv b/Backend/ExerciseData/squat_rates_m.csv
new file mode 100644
index 0000000..49c1568
--- /dev/null
+++ b/Backend/ExerciseData/squat_rates_m.csv
@@ -0,0 +1,2 @@
+Beginner,Novice,Intermediate,Advanced,Elite
+5,20,51,81,95
diff --git a/Backend/README.txt b/Backend/README.txt
new file mode 100644
index 0000000..540eeeb
--- /dev/null
+++ b/Backend/README.txt
@@ -0,0 +1,11 @@
+# Backend
+
+### How to run
+For receiving frames through websocket:
+```bash
+python main.py
+```
+For debugging:
+```bash
+python app.py
+```
diff --git a/Backend/RepetitionGifs/rep_1.gif b/Backend/RepetitionGifs/rep_1.gif
deleted file mode 100644
index a330367..0000000
Binary files a/Backend/RepetitionGifs/rep_1.gif and /dev/null differ
diff --git a/Backend/RepetitionGifs/rep_10.gif b/Backend/RepetitionGifs/rep_10.gif
deleted file mode 100644
index 2efba32..0000000
Binary files a/Backend/RepetitionGifs/rep_10.gif and /dev/null differ
diff --git a/Backend/RepetitionGifs/rep_11.gif b/Backend/RepetitionGifs/rep_11.gif
deleted file mode 100644
index 04aac52..0000000
Binary files a/Backend/RepetitionGifs/rep_11.gif and /dev/null differ
diff --git a/Backend/RepetitionGifs/rep_12.gif b/Backend/RepetitionGifs/rep_12.gif
deleted file mode 100644
index f5e3478..0000000
Binary files a/Backend/RepetitionGifs/rep_12.gif and /dev/null differ
diff --git a/Backend/RepetitionGifs/rep_13.gif b/Backend/RepetitionGifs/rep_13.gif
deleted file mode 100644
index e603fd9..0000000
Binary files a/Backend/RepetitionGifs/rep_13.gif and /dev/null differ
diff --git a/Backend/RepetitionGifs/rep_14.gif b/Backend/RepetitionGifs/rep_14.gif
deleted file mode 100644
index 9e41ad3..0000000
Binary files a/Backend/RepetitionGifs/rep_14.gif and /dev/null differ
diff --git a/Backend/RepetitionGifs/rep_15.gif b/Backend/RepetitionGifs/rep_15.gif
deleted file mode 100644
index 54ed6ab..0000000
Binary files a/Backend/RepetitionGifs/rep_15.gif and /dev/null differ
diff --git a/Backend/RepetitionGifs/rep_16.gif b/Backend/RepetitionGifs/rep_16.gif
deleted file mode 100644
index abdfaf7..0000000
Binary files a/Backend/RepetitionGifs/rep_16.gif and /dev/null differ
diff --git a/Backend/RepetitionGifs/rep_2.gif b/Backend/RepetitionGifs/rep_2.gif
deleted file mode 100644
index 34c9e69..0000000
Binary files a/Backend/RepetitionGifs/rep_2.gif and /dev/null differ
diff --git a/Backend/RepetitionGifs/rep_3.gif b/Backend/RepetitionGifs/rep_3.gif
deleted file mode 100644
index 84441a0..0000000
Binary files a/Backend/RepetitionGifs/rep_3.gif and /dev/null differ
diff --git a/Backend/RepetitionGifs/rep_4.gif b/Backend/RepetitionGifs/rep_4.gif
deleted file mode 100644
index 5e42c0b..0000000
Binary files a/Backend/RepetitionGifs/rep_4.gif and /dev/null differ
diff --git a/Backend/RepetitionGifs/rep_5.gif b/Backend/RepetitionGifs/rep_5.gif
deleted file mode 100644
index acb853a..0000000
Binary files a/Backend/RepetitionGifs/rep_5.gif and /dev/null differ
diff --git a/Backend/RepetitionGifs/rep_6.gif b/Backend/RepetitionGifs/rep_6.gif
deleted file mode 100644
index 7b1496e..0000000
Binary files a/Backend/RepetitionGifs/rep_6.gif and /dev/null differ
diff --git a/Backend/RepetitionGifs/rep_7.gif b/Backend/RepetitionGifs/rep_7.gif
deleted file mode 100644
index 9df3530..0000000
Binary files a/Backend/RepetitionGifs/rep_7.gif and /dev/null differ
diff --git a/Backend/RepetitionGifs/rep_8.gif b/Backend/RepetitionGifs/rep_8.gif
deleted file mode 100644
index ab54bda..0000000
Binary files a/Backend/RepetitionGifs/rep_8.gif and /dev/null differ
diff --git a/Backend/RepetitionGifs/rep_9.gif b/Backend/RepetitionGifs/rep_9.gif
deleted file mode 100644
index fd14e91..0000000
Binary files a/Backend/RepetitionGifs/rep_9.gif and /dev/null differ
diff --git a/Backend/curl.py b/Backend/curl.py
index 53ae2e5..64fd9f6 100644
--- a/Backend/curl.py
+++ b/Backend/curl.py
@@ -122,9 +122,10 @@ def create_draw(self, joints, angles):
return drawing
def check_hip(self, angle):
+ return True
""" Form Checking method """
# Check if hip posture is good
- if angle < 145 and self.stage != 'idle':
+ if angle < 160 and self.stage != 'idle':
self.hip_fail = True
return False
@@ -192,15 +193,15 @@ def count(self, angle):
#Check all form errors
if self.hip_fail:
- self.framework.add_feedback("curl_back")
+ self.framework.add_feedback("Dont bend forward")
print("[FeedBack] Dont bend forward")
if self.knee_fail:
- self.framework.add_feedback("curl_knee")
+ self.framework.add_feedback("Dont bend your knees")
print("[FeedBack] Dont bend your knees")
if not self.perfect_tag:
- self.framework.add_feedback("curl_rom")
+ self.framework.add_feedback("Not full range motion")
print("[FeedBack] Not full motion rep >:(\n\n")
if self.perfect_tag and not self.knee_fail and not self.hip_fail:
diff --git a/Backend/deadlift.py b/Backend/deadlift.py
new file mode 100644
index 0000000..9e1a152
--- /dev/null
+++ b/Backend/deadlift.py
@@ -0,0 +1,250 @@
+from subprocess import check_call
+from draw import DrawInfo
+
+import numpy as np
+import mediapipe as mp
+
+mp_pose = mp.solutions.pose
+
+class Deadlift:
+ """Squat exercise module."""
+
+ def __init__(self):
+
+ # Framework Refernece given by the framework itself
+ self.framework = None
+
+ # Count of the current frame since the exercise started
+ self.start_frame = 0
+
+ # Tags for the counting logic
+ self.knee_fail = False
+ self.back_fail = False
+ self.perfect_tag = False # Rep was perfect (in the range of motion requirement)
+ self.completed = False # Rep was done
+ self.stage = "idle" # "up" or "down" keeps track of the current movement
+
+ # Cues related values
+ self.start_angle = 170 # less then this is not a good rep (bad range of motion)
+ self.min_vizibility = 0.7
+
+ # Debugging Counter of reps
+ self.counter = 0
+
+ def analyze_frame(self, frame_count, landmarks):
+ """ | Analyzes frame | calls method of framework when rep is finished with the rep information"""
+
+ # Sync frame count
+ self.frame_count = frame_count
+
+ if landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value].z< landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value].z:
+ # Get right key positions
+ shoulder = [landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value].x,landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value].y]
+ hip = [landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value].x,landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value].y]
+ knee = [landmarks[mp_pose.PoseLandmark.RIGHT_KNEE.value].x,landmarks[mp_pose.PoseLandmark.RIGHT_KNEE.value].y]
+ elbow = [landmarks[mp_pose.PoseLandmark.RIGHT_ELBOW.value].x,landmarks[mp_pose.PoseLandmark.RIGHT_ELBOW.value].y]
+
+ if landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value].visibility < self.min_vizibility:
+ return None
+ if landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value].visibility < self.min_vizibility:
+ return None
+ if landmarks[mp_pose.PoseLandmark.RIGHT_KNEE.value].visibility < self.min_vizibility:
+ return None
+ if landmarks[mp_pose.PoseLandmark.RIGHT_ELBOW.value].visibility < self.min_vizibility:
+ return None
+ else:
+
+ # Get left key positions
+ shoulder = [landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value].x,landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value].y]
+ hip = [landmarks[mp_pose.PoseLandmark.LEFT_HIP.value].x,landmarks[mp_pose.PoseLandmark.LEFT_HIP.value].y]
+ knee = [landmarks[mp_pose.PoseLandmark.LEFT_KNEE.value].x,landmarks[mp_pose.PoseLandmark.LEFT_KNEE.value].y]
+ elbow = [landmarks[mp_pose.PoseLandmark.LEFT_ELBOW.value].x,landmarks[mp_pose.PoseLandmark.LEFT_ELBOW.value].y]
+
+ if landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value].visibility < self.min_vizibility:
+ return None
+ if landmarks[mp_pose.PoseLandmark.LEFT_HIP.value].visibility < self.min_vizibility:
+ return None
+ if landmarks[mp_pose.PoseLandmark.LEFT_KNEE.value].visibility < self.min_vizibility:
+ return None
+ if landmarks[mp_pose.PoseLandmark.LEFT_ELBOW.value].visibility < self.min_vizibility:
+ return None
+
+
+ # Calculate angle
+ hip_angle = self.calculate_angle(knee, hip, shoulder)
+
+ # Right Curl counter logic
+ self.count(shoulder, knee, elbow, hip_angle)
+
+ # Return body form feed
+ return self.create_draw((shoulder, hip, knee, elbow), hip_angle)
+
+ def create_draw(self, joints, angles):
+ """ Called every frame to give graphycal feedback of the joints (good or bad form)"""
+
+ drawing = DrawInfo()
+
+ drawing.add_point('shoulder', joints[0][0], joints[0][1])
+ drawing.add_point('hip', joints[1][0], joints[1][1])
+ drawing.add_point('knee', joints[2][0], joints[2][1])
+ drawing.add_point('elbow', joints[3][0], joints[3][1])
+
+
+
+ #drawing.add_segment('shoulder', 'hip', True) # Back
+ drawing.add_segment('shoulder', 'elbow', True) # Upper leg
+
+
+ good = self.check_knee(joints[2], joints[1], joints[0], joints[3])
+ drawing.add_segment('hip', 'knee', good) # Lower leg
+
+ good = self.check_back(joints[1], joints[0], joints[3])
+ drawing.add_segment('hip', 'shoulder', good)
+
+ return drawing
+
+ def check_knee(self, knee, hip, shoulder, elbow):
+ """ Form Checking method """
+
+ # shoulder/elbow for reference
+ offset = abs(shoulder[1] - elbow[1])/2
+ print("knee: " + str(knee[1]) + "hip: " + str(hip[1]))
+
+ # hip in relation to knee
+ if (hip[1] > knee[1]-offset) and self.stage != 'idle':
+
+ self.knee_fail = True
+ return False
+
+ return True
+
+ def check_back(self, hip, shoulder, elbow):
+ """ Form Checking method """
+
+ # shoulder/elbow for reference
+ offset = abs(shoulder[1] - elbow[1])/2
+
+ # hip in relation to shoulder
+ if (hip[1] < shoulder[1]-offset) and self.stage != 'idle':
+
+ self.back_fail = True
+ return False
+
+
+ return True
+
+
+ def count(self, shoulder, knee, elbow, angle):
+ """ Responsible for counting reps and keep track of range of motion type problems"""
+
+ offset = abs(shoulder[1] - elbow[1])/3
+
+ if elbow[1] < knee[1] - offset and self.stage == 'idle' and not self.completed:
+ # Started motion
+
+ # Save current frame as the start of the rep
+ self.start_frame = self.frame_count
+ # Update state
+ self.stage = "up"
+ print("\n[State] Movement Started ! \n")
+
+ if angle > self.start_angle and not self.perfect_tag:
+ # Perfected motion rep
+
+ # Update flags
+ self.completed = True
+ self.perfect_tag =True
+
+ # Update state
+ self.stage="down"
+
+ print("[State] Maximum reached...\n")
+
+ if elbow[1] > knee[1] - offset and self.stage =='down' and self.completed:
+ # Completed movement
+
+ # Update counter
+ self.counter +=1
+ # Update state
+ self.stage = "idle"
+
+ # Call framework method to announce that the rep has ended
+ self.framework.repetition_done(self.start_frame)
+
+ print("[State] Rep Finished...\n")
+ print("[Info] Rep Count: " + str(self.counter) + "\n\n")
+
+ #Check all form errors
+ if self.knee_fail:
+ self.framework.add_feedback("Dont let your heap beneath your knees")
+ print("[FeedBack] is not a squat boy")
+
+ if self.back_fail:
+ self.framework.add_feedback("Back shouldnt be paralel to ground")
+ print("[FeedBack] Back shouldnt be paralel to ground")
+
+ if not self.perfect_tag:
+ self.framework.add_feedback("Not full range motion")
+ print("[FeedBack] Not full motion rep >:(\n\n")
+
+ if self.perfect_tag and not self.back_fail and not self.knee_fail:
+ print("[FeedBack] Good rep :)\n")
+
+
+ # Reset flags
+ self.knee_fail = False
+ self.perfect_tag = False
+ self.back_fail = False
+ self.completed = False
+
+ # Get a frame's bounds
+ def get_bounds(self, landmarks) -> tuple:
+
+ # If it's right facing...
+ if landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value].z < landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value].z:
+ x = landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value].x
+ max_y = landmarks[mp_pose.PoseLandmark.RIGHT_SHOULDER.value].y
+ min_y = landmarks[mp_pose.PoseLandmark.RIGHT_ANKLE.value].y
+
+ # The padding will be 10% from max to min
+ padding = (max_y - min_y) / 10
+ # Left facing
+ else:
+ x = landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value].x
+ max_y = landmarks[mp_pose.PoseLandmark.LEFT_SHOULDER.value].y
+ min_y = landmarks[mp_pose.PoseLandmark.LEFT_ANKLE.value].y
+
+ # The padding will be 10% from max to min
+ padding = (max_y - min_y) / 10
+
+ # Adds the padding
+ upper_left = [x + padding * 8, max_y + padding * 2]
+ lower_right = [x - padding * 8, min_y - padding * 2]
+
+ def clamp(n, smallest, largest):
+ return max(smallest, min(n, largest))
+
+ #Clam the values
+ upper_left = [clamp(upper_left[0], 0, 1), clamp(upper_left[1], 0, 1)]
+ lower_right = [clamp(lower_right[0],0,1), clamp(lower_right[1],0,1)]
+
+ return upper_left, lower_right
+
+ def calculate_angle(self, a_,b_,c_):
+ """
+ Utiltity method to calculate angle abc given those 3 coordinates
+ """
+
+ angle = None
+
+ a = np.array(a_)
+ b = np.array(b_)
+ c = np.array(c_)
+
+ radians = np.arctan2(c[1]-b[1], c[0]-b[0]) - np.arctan2(a[1]-b[1], a[0]-b[0])
+ angle = np.abs(radians*180.0/np.pi)
+
+ if angle >180.0:
+ angle = 360-angle
+
+ return angle
\ No newline at end of file
diff --git a/Backend/framework.py b/Backend/framework.py
index 1de6a38..72cf22f 100644
--- a/Backend/framework.py
+++ b/Backend/framework.py
@@ -4,6 +4,7 @@
from PIL import Image, ImageDraw # For creating gifs
from protocol import * # For sending messages
import base64 # For encoding gifs
+import strength_level # For calculating strength
mp_pose = mp.solutions.pose
@@ -182,11 +183,14 @@ def get_distance(p, q):
else:
# If the gesture is done and the detection timer is up, the gesture is computed
if self.set_gesture_count >= self.SET_gesture_DETECT:
- #Start timer!
+ # Start timer!
self.gesture_timer_state = True
self.gesture_timer_count = 0
self.set_gesture_count = 0
+ # Inform the frontend
+ self.send_message(GestureDetected())
+
#Print the timer duration
if not self.started_set:
print(f'Starting {self.gesture_timer_max / self.FPS}s timer...')
@@ -209,8 +213,6 @@ def ccw(A,B,C):
if not (ccw(R1,L1,L2) != ccw(R2,L1,L2) and ccw(R1,R2,L1) != ccw(R1,R2,L2)):
return False
- return True # CHANGE THIS LATER
-
# However, the angle between the forearms should be close to 90º
# Helper dot product function
@@ -368,6 +370,9 @@ def set_ended(self):
if self.rep_count == 0:
return
+ # Write to db
+ strength_level.write_data((type(self.exercise).__name__).lower())
+
# Generate gifs
for count in range(1, self.rep_count+1):
# Generates the gif
@@ -378,7 +383,9 @@ def set_ended(self):
# Sends the encoded gif to the frontend
with open(f'RepetitionGifs/rep_{count}.gif', "rb") as image_file:
encoded_string = base64.b64encode(image_file.read()).decode('utf-8')
- self.send_message(Gif(count, encoded_string))
+ # self.send_message(Gif(count, encoded_string))
+
+ self.send_message(SetState("false"))
# Reset
self.clean()
diff --git a/Backend/protocol.py b/Backend/protocol.py
index 32a2a88..bdf0f13 100644
--- a/Backend/protocol.py
+++ b/Backend/protocol.py
@@ -4,12 +4,14 @@
from curl import Curl
from squat import Squat
from pushup import Pushup
+from deadlift import Deadlift
class Message:
"""Base message. Other messages should extend this."""
def encode(self):
"""Serializes to JSON"""
+ print(json.dumps(self, default=lambda o: o.__dict__, sort_keys=False))
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=False)
@classmethod
@@ -28,6 +30,10 @@ def decode(cls, msg : dict):
elif type == "IN_FRAME":
return InFrame(JSON["in_frame"])
+ # Gesture detected
+ elif type == "GESTURE":
+ return GestureDetected()
+
# Set State
elif type == "SET_STATE":
return SetState(JSON["state"])
@@ -61,6 +67,8 @@ def create_object(self):
return Curl()
elif self.exercise == "Pushup":
return Pushup()
+ elif self.exercise == "Deadlift":
+ return Deadlift()
class InFrame(Message):
"""Message informing whether the user is in frame or not."""
@@ -68,6 +76,11 @@ def __init__(self, in_frame):
self.type = "IN_FRAME"
self.in_frame = in_frame
+class GestureDetected(Message):
+ """Message informing that the starting set gesture has been detected"""
+ def __init__(self):
+ self.type = "GESTURE"
+
class SetState(Message):
"""Message informing that a set has started / ended."""
def __init__(self, state):
diff --git a/Backend/pushup.py b/Backend/pushup.py
index 19aeebc..ebc95f5 100644
--- a/Backend/pushup.py
+++ b/Backend/pushup.py
@@ -230,15 +230,15 @@ def count(self, angle, shoulder, elbow, wrist):
#Check all form errors
if self.hip_fail:
- self.framework.add_feedback("pushup_hip")
+ self.framework.add_feedback("Hip is too hight or too low")
print("[FeedBack] Hip too hight")
if self.elbow_fail:
- self.framework.add_feedback("pushup_elbow")
+ self.framework.add_feedback("Tuck your arms in")
print("[FeedBack] Tuck your arms in")
if not self.perfect_tag:
- self.framework.add_feedback("pushup_rom")
+ self.framework.add_feedback("Not full range motion")
print("[FeedBack] Not full motion rep >:(\n\n")
if self.perfect_tag and not self.elbow_fail and not self.hip_fail:
diff --git a/Backend/requirements.txt b/Backend/requirements.txt
new file mode 100644
index 0000000..e2a935f
--- /dev/null
+++ b/Backend/requirements.txt
@@ -0,0 +1,2 @@
+opencv-python
+mediapipe
\ No newline at end of file
diff --git a/Backend/squat.py b/Backend/squat.py
index 51ff4b2..3f40aca 100644
--- a/Backend/squat.py
+++ b/Backend/squat.py
@@ -199,15 +199,15 @@ def count(self, hip, knee, angle):
#Check all form errors
if self.knee_fail:
- self.framework.add_feedback("squat_knee")
+ self.framework.add_feedback("Knees to far away from toes")
print("[FeedBack] Knee to far from toe")
if self.back_fail:
- self.framework.add_feedback("squat_back")
+ self.framework.add_feedback("Back is too leaned forward")
print("[FeedBack] Back is to leaned forward")
if not self.perfect_tag:
- self.framework.add_feedback("squat_rom")
+ self.framework.add_feedback("Not full range motion")
print("[FeedBack] Not full motion rep >:(\n\n")
if self.perfect_tag and not self.back_fail and not self.knee_fail:
diff --git a/Backend/strength_level.py b/Backend/strength_level.py
new file mode 100644
index 0000000..3da538f
--- /dev/null
+++ b/Backend/strength_level.py
@@ -0,0 +1,135 @@
+import csv # For handling the exercise data
+import os # For paths
+import requests
+import json
+
+from enum import Enum
+
+class Classification(Enum):
+ Beginner = 1
+ Novice = 2
+ Intermediate = 3
+ Advanced = 4
+ Elite = 5
+
+# Base location
+BASE_PATH = "ExerciseData/"
+
+def strength_classification(gender : str, age : int, bodyweight : int, one_rep_max : int, exercise : str) -> dict:
+ """Gets a strength classification in respect to age and bodyweight"""
+
+ # By age
+ age_classification = None
+ with open(os.path.join(BASE_PATH, exercise + '_age_' + gender + '.csv'), 'r') as csv_file:
+ csv_reader = csv.DictReader(csv_file)
+
+ # Find the row
+ selected_row = None
+ for row in csv_reader:
+ if selected_row == None:
+ selected_row = row
+ else:
+ if int(row['Age']) <= age:
+ selected_row = row
+ else:
+ break
+
+ if int(selected_row['Advanced']) < one_rep_max:
+ age_classification = Classification['Elite']
+ age_diff = one_rep_max/int(selected_row['Advanced'])
+
+ elif int(selected_row['Intermediate']) < one_rep_max:
+ age_classification = Classification['Advanced']
+ age_diff = one_rep_max/int(selected_row['Intermediate'])
+
+ elif int(selected_row['Novice']) < one_rep_max:
+ age_classification = Classification['Intermediate']
+ age_diff = one_rep_max/int(selected_row['Novice'])
+
+ elif int(selected_row['Beginner']) < one_rep_max:
+ age_classification = Classification['Novice']
+ age_diff = one_rep_max/int(selected_row['Beginner'])
+
+ else:
+ age_classification = Classification['Beginner']
+ age_diff = one_rep_max/int(selected_row['Beginner'])
+
+ # By bodyweight
+ bw_classification = None
+ with open(os.path.join(BASE_PATH, exercise + '_bw_' + gender + '.csv'), 'r') as csv_file:
+ csv_reader = csv.DictReader(csv_file)
+
+ # Find the row
+ selected_row = None
+ for row in csv_reader:
+ if selected_row == None:
+ selected_row = row
+ else:
+ if int(row['Bodyweight']) <= bodyweight:
+ selected_row = row
+ else:
+ break
+
+ if int(selected_row['Advanced']) < one_rep_max:
+ bw_classification = Classification['Elite']
+ bw_diff = one_rep_max/int(selected_row['Advanced'])
+
+ elif int(selected_row['Intermediate']) < one_rep_max:
+ bw_classification = Classification['Advanced']
+ bw_diff = one_rep_max/int(selected_row['Intermediate'])
+
+ elif int(selected_row['Novice']) < one_rep_max:
+ bw_classification = Classification['Intermediate']
+ bw_diff = one_rep_max/int(selected_row['Novice'])
+
+ elif int(selected_row['Beginner']) < one_rep_max:
+ bw_classification = Classification['Novice']
+ bw_diff = one_rep_max/int(selected_row['Beginner'])
+
+ else:
+ bw_classification = Classification['Beginner']
+ bw_diff = one_rep_max/int(selected_row['Beginner'])
+
+ # Average out
+ average = int(( bw_classification.value + age_classification.value )/2)
+ general_classification = Classification( average )
+
+ # Round diffs to 2 decimals
+ bw_diff = round(bw_diff, 2)
+ age_diff = round(age_diff, 2)
+
+ # How good are ya
+ rate = 'N/A'
+ with open(os.path.join(BASE_PATH, exercise + '_rates_' + gender + '.csv'), 'r') as csv_file:
+ csv_reader = csv.DictReader(csv_file)
+
+ # Find the row
+ selected_row = None
+ for row in csv_reader:
+ rate = row[general_classification.name]
+
+ return {"class" : general_classification.value, "rate" : rate}
+
+
+def write_data(exercise : str):
+ try:
+ user_data= requests.get("http://192.168.10.150/user?username=filipe").json()[0]
+
+ gender = 'm' if user_data['gender'] == 'male' else 'f'
+ age = 22 # Fix later
+ bodyweight = user_data['weight']
+
+ one_rep_max = user_data[exercise]
+
+ result = (strength_classification(gender,age, int(bodyweight), int(one_rep_max), exercise))
+ result['user'] = 'filipe'
+ result['exercise'] = exercise
+
+ requests.put("http://192.168.10.150/potencial", data=result)
+
+ except:
+ pass
+
+ pass
+
+write_data('curl')
\ No newline at end of file
diff --git a/Backend/test.py b/Backend/test.py
deleted file mode 100644
index 54a0a6d..0000000
--- a/Backend/test.py
+++ /dev/null
@@ -1,82 +0,0 @@
-import asyncio
-from websockets import serve
-import cv2
-import numpy as np
-import json
-
-
-
-async def recieve(websocket):
- count = 1
- repCount = 0
- cv2.namedWindow("test")
-
- async for message in websocket:
-
- # frames
- if type(message) != str:
-
- # get image from bytes
- decoded = cv2.imdecode(np.frombuffer(message, np.uint8), -1)
- decoded = cv2.rotate(decoded, cv2.ROTATE_180)
-
- # show image
- cv2.imshow("test", decoded)
- cv2.waitKey(10)
-
- data = {}
-
- # if finished set
- if count % 56 == 0:
-
- # do some shit
-
- data = {'message': 'finished', 'gifs': "there are no gifs available"}
-
- # if finished rep
- elif count % 10 == 0:
-
- # do some shit
-
- repCount += 1
- data = {'message': 'repCount', 'repCount': repCount}
-
- # send message
- if "message" in data.keys():
- print(f"Sending Message: {data}")
- await websocket.send(json.dumps(data))
-
- count += 1
-
- # messages like get statistics
- else:
- json_message = json.loads(message)
-
- # normal message
- if "message" in json_message.keys():
-
- # statistics
- if json_message["message"] == "statistics":
-
- # do some shit
-
- # send statistics
- data = {'message': 'statistics'}
- print(f"Sending Message: {data}")
- await websocket.send(json.dumps(data))
-
-
-async def main():
- async with serve(recieve, port=5000):
- await asyncio.Future()
-
-asyncio.run(main())
-
-
-
-"""
-messages:
- - repCount = {'message': 'repCount', 'repCount': }
- - finishSet = {'message': 'finished', 'gifs': }
- - statistics = {'message': 'statistics'}
-"""
\ No newline at end of file
diff --git a/DemoImages/Curl/good.gif b/DemoImages/Curl/good.gif
new file mode 100644
index 0000000..3196a54
Binary files /dev/null and b/DemoImages/Curl/good.gif differ
diff --git a/DemoImages/Curl/rep_1.gif b/DemoImages/Curl/rep_1.gif
new file mode 100644
index 0000000..43fde32
Binary files /dev/null and b/DemoImages/Curl/rep_1.gif differ
diff --git a/DemoImages/Curl/rep_2.gif b/DemoImages/Curl/rep_2.gif
new file mode 100644
index 0000000..6ef93e9
Binary files /dev/null and b/DemoImages/Curl/rep_2.gif differ
diff --git a/DemoImages/Curl/rep_3.gif b/DemoImages/Curl/rep_3.gif
new file mode 100644
index 0000000..3b9fd6a
Binary files /dev/null and b/DemoImages/Curl/rep_3.gif differ
diff --git a/DemoImages/Curl/rep_4.gif b/DemoImages/Curl/rep_4.gif
new file mode 100644
index 0000000..356fef8
Binary files /dev/null and b/DemoImages/Curl/rep_4.gif differ
diff --git a/DemoImages/Pushups/bad_archRotated.gif b/DemoImages/Pushups/bad_archRotated.gif
new file mode 100644
index 0000000..5ab27f4
Binary files /dev/null and b/DemoImages/Pushups/bad_archRotated.gif differ
diff --git a/DemoImages/Pushups/bad_sagRotated.gif b/DemoImages/Pushups/bad_sagRotated.gif
new file mode 100644
index 0000000..5b21df3
Binary files /dev/null and b/DemoImages/Pushups/bad_sagRotated.gif differ
diff --git a/DemoImages/Pushups/goodRotated.gif b/DemoImages/Pushups/goodRotated.gif
new file mode 100644
index 0000000..2dbc563
Binary files /dev/null and b/DemoImages/Pushups/goodRotated.gif differ
diff --git a/DemoImages/Pushups/rep_1.gif b/DemoImages/Pushups/rep_1.gif
new file mode 100644
index 0000000..b0af359
Binary files /dev/null and b/DemoImages/Pushups/rep_1.gif differ
diff --git a/DemoImages/Pushups/rep_2.gif b/DemoImages/Pushups/rep_2.gif
new file mode 100644
index 0000000..30f33f6
Binary files /dev/null and b/DemoImages/Pushups/rep_2.gif differ
diff --git a/DemoImages/Pushups/rep_3.gif b/DemoImages/Pushups/rep_3.gif
new file mode 100644
index 0000000..130d6ff
Binary files /dev/null and b/DemoImages/Pushups/rep_3.gif differ
diff --git a/DemoImages/Pushups/rep_4.gif b/DemoImages/Pushups/rep_4.gif
new file mode 100644
index 0000000..5844e5b
Binary files /dev/null and b/DemoImages/Pushups/rep_4.gif differ
diff --git a/DemoImages/Pushups/rep_5.gif b/DemoImages/Pushups/rep_5.gif
new file mode 100644
index 0000000..90d505f
Binary files /dev/null and b/DemoImages/Pushups/rep_5.gif differ
diff --git a/DemoImages/Squat/rep_2.gif b/DemoImages/Squat/rep_2.gif
new file mode 100644
index 0000000..66170cc
Binary files /dev/null and b/DemoImages/Squat/rep_2.gif differ
diff --git a/DemoImages/Squat/rep_3.gif b/DemoImages/Squat/rep_3.gif
new file mode 100644
index 0000000..664d337
Binary files /dev/null and b/DemoImages/Squat/rep_3.gif differ
diff --git a/DemoImages/UI/.gitkeep b/DemoImages/UI/.gitkeep
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/DemoImages/UI/.gitkeep
@@ -0,0 +1 @@
+
diff --git a/DemoImages/UI/Create Account UI.gif b/DemoImages/UI/Create Account UI.gif
new file mode 100644
index 0000000..256868f
Binary files /dev/null and b/DemoImages/UI/Create Account UI.gif differ
diff --git a/DemoImages/UI/Select and Perform Exercise UI.gif b/DemoImages/UI/Select and Perform Exercise UI.gif
new file mode 100644
index 0000000..4840dce
Binary files /dev/null and b/DemoImages/UI/Select and Perform Exercise UI.gif differ
diff --git a/DemoImages/UI/Statistics UI.gif b/DemoImages/UI/Statistics UI.gif
new file mode 100644
index 0000000..37cb99e
Binary files /dev/null and b/DemoImages/UI/Statistics UI.gif differ
diff --git a/smart_gains/.gitignore b/Frontend/.gitignore
similarity index 100%
rename from smart_gains/.gitignore
rename to Frontend/.gitignore
diff --git a/smart_gains/.metadata b/Frontend/.metadata
similarity index 100%
rename from smart_gains/.metadata
rename to Frontend/.metadata
diff --git a/smart_gains/README.md b/Frontend/README.md
similarity index 100%
rename from smart_gains/README.md
rename to Frontend/README.md
diff --git a/smart_gains/analysis_options.yaml b/Frontend/analysis_options.yaml
similarity index 100%
rename from smart_gains/analysis_options.yaml
rename to Frontend/analysis_options.yaml
diff --git a/smart_gains/android/.gitignore b/Frontend/android/.gitignore
similarity index 100%
rename from smart_gains/android/.gitignore
rename to Frontend/android/.gitignore
diff --git a/smart_gains/android/app/build.gradle b/Frontend/android/app/build.gradle
similarity index 100%
rename from smart_gains/android/app/build.gradle
rename to Frontend/android/app/build.gradle
diff --git a/smart_gains/android/app/src/debug/AndroidManifest.xml b/Frontend/android/app/src/debug/AndroidManifest.xml
similarity index 100%
rename from smart_gains/android/app/src/debug/AndroidManifest.xml
rename to Frontend/android/app/src/debug/AndroidManifest.xml
diff --git a/smart_gains/android/app/src/main/AndroidManifest.xml b/Frontend/android/app/src/main/AndroidManifest.xml
similarity index 86%
rename from smart_gains/android/app/src/main/AndroidManifest.xml
rename to Frontend/android/app/src/main/AndroidManifest.xml
index 802c9f5..5e2b760 100644
--- a/smart_gains/android/app/src/main/AndroidManifest.xml
+++ b/Frontend/android/app/src/main/AndroidManifest.xml
@@ -1,5 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+Uma boa repetição de bicep curl.
+
+
+
+
+
+
+
+
+Uma má repetição de bicep curl. Em vermelho, a fonte dos erros.
+
+
+
+
+
+
+
+Uma boa repetição de pushups.
+
+
+
+
+
+
+
+Má repetições de pushups. Em vermelho, a fonte dos erros.
+
+
+
+
+
+
+
+
+
+Uma boa repetição de agachamento.
+
+
+
+
+
+
+
+Uma má repetição de agachamento. Em vermelho, a fonte dos erros.
+
+
+
+# UI
+
+
+
+
+
+Criando uma nova conta.
+
+
+
+
+
+
+
+
+
+
+Estatísticas de um usuário em específico.
+
+
+
+
+
+
+
+
+
+
+Selecionar e executar exercícios.
+
+
+
diff --git "a/Sum\303\241rio_Executivo.pdf" "b/Sum\303\241rio_Executivo.pdf"
new file mode 100644
index 0000000..7b98760
Binary files /dev/null and "b/Sum\303\241rio_Executivo.pdf" differ
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index e2b9e8c..0000000
--- a/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-numpy
-opencv-python
-mediapipe
-pillow
diff --git a/smart_gains/lib/CreateAccountPage.dart b/smart_gains/lib/CreateAccountPage.dart
deleted file mode 100644
index 4072b99..0000000
--- a/smart_gains/lib/CreateAccountPage.dart
+++ /dev/null
@@ -1,135 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'InputUserDataPage.dart';
-
-class CreateAccountPage extends StatelessWidget {
- const CreateAccountPage({Key? key, required this.title}) : super(key: key);
- final String title;
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- body: Container(
- decoration: const BoxDecoration(
- image: DecorationImage(
- image: AssetImage("assets/womanImage.jpg"),
- fit: BoxFit.cover,
- ),
- ),
- child: Scaffold(
- appBar: AppBar(
- centerTitle: true,
- elevation: 0,
- bottomOpacity: 0,
- shadowColor: const Color.fromARGB(0, 0, 0, 0),
- backgroundColor: Colors.transparent,
- title: Image.asset(
- "assets/logo.png",
- fit: BoxFit.contain,
- height: 60,
- )),
- backgroundColor: Colors.transparent,
- body: Container(
- decoration: const BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.only(
- topLeft: Radius.circular(40.0),
- topRight: Radius.circular(40.0),
- )),
- alignment: FractionalOffset.center,
- child: SingleChildScrollView(
- reverse: true,
- child: Column(
- children: [
- Padding(
- padding: const EdgeInsets.all(40.0),
- child: Title(
- color: const Color.fromARGB(255, 6, 6, 32),
- child: const Text(
- textAlign: TextAlign.center,
- "Create your Smart Gains Account",
- style: TextStyle(
- fontWeight: FontWeight.bold, fontSize: 25),
- )),
- ),
- Padding(
- padding: const EdgeInsets.only(
- left: 32, right: 32, bottom: 32, top: 32),
- child: TextField(
- decoration: InputDecoration(
- border: OutlineInputBorder(
- borderRadius: BorderRadius.circular(20)),
- prefixIcon: const Icon(Icons.person),
- hintText: 'Email',
- ),
- ),
- ),
- Padding(
- padding:
- const EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: TextField(
- decoration: InputDecoration(
- border: OutlineInputBorder(
- borderRadius: BorderRadius.circular(20)),
- prefixIcon: const Icon(Icons.person),
- hintText: 'Usarname',
- ),
- ),
- ),
- Padding(
- padding:
- const EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: TextField(
- decoration: InputDecoration(
- border: OutlineInputBorder(
- borderRadius: BorderRadius.circular(20)),
- prefixIcon: const Icon(Icons.key),
- hintText: 'Password',
- ),
- obscureText: true,
- enableSuggestions: false,
- autocorrect: false,
- ),
- ),
- Padding(
- padding:
- const EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: TextField(
- decoration: InputDecoration(
- border: OutlineInputBorder(
- borderRadius: BorderRadius.circular(20)),
- prefixIcon: const Icon(Icons.key),
- hintText: 'Repeat Password',
- ),
- obscureText: true,
- enableSuggestions: false,
- autocorrect: false,
- ),
- ),
- Padding(
- padding:
- const EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: ElevatedButton(
- style: ElevatedButton.styleFrom(
- fixedSize: const Size(320, 40),
- shape: const StadiumBorder(),
- backgroundColor:
- const Color.fromARGB(255, 37, 171, 117)),
- onPressed: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) =>
- const InputUserData(title: "here")),
- );
- },
- child: const Text("Continue")),
- ),
- ],
- ),
- ),
- ),
- ),
- ),
- );
- }
-}
diff --git a/smart_gains/lib/FirstPage.dart b/smart_gains/lib/FirstPage.dart
deleted file mode 100644
index b365419..0000000
--- a/smart_gains/lib/FirstPage.dart
+++ /dev/null
@@ -1,129 +0,0 @@
-// ignore_for_file: unnecessary_const
-
-import 'package:flutter/material.dart';
-import 'package:smart_gains/LogInPage.dart';
-
-import 'CreateAccountPage.dart';
-
-class FirstPage extends StatelessWidget {
- const FirstPage({Key? key, required this.title}) : super(key: key);
- final String title;
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- body: Container(
- decoration: const BoxDecoration(
- image: DecorationImage(
- image: AssetImage("assets/womanImage.jpg"),
- fit: BoxFit.cover,
- ),
- ),
- child: Scaffold(
- appBar: AppBar(
- elevation: 0,
- bottomOpacity: 0,
- shadowColor: const Color.fromARGB(0, 0, 0, 0),
- backgroundColor: Colors.transparent,
- title: Row(
- children: [
- Expanded(
- child: Center(
- child: Image.asset(
- "assets/logo.png",
- fit: BoxFit.contain,
- height: 60,
- )),
- ),
- const Icon(Icons.more_vert)
- ],
- )),
- backgroundColor: Colors.transparent,
- body: Column(
- children: [
- Expanded(child: Container()),
- Container(
- decoration: const BoxDecoration(
- color: Colors.white,
- borderRadius: const BorderRadius.only(
- topLeft: Radius.circular(40.0),
- topRight: Radius.circular(40.0),
- )),
- alignment: FractionalOffset.bottomCenter,
- child: Column(
- children: [
- Padding(
- padding: const EdgeInsets.symmetric(
- horizontal: 40.0, vertical: 10),
- child: Title(
- color: const Color.fromARGB(255, 6, 6, 32),
- child: const Center(
- child: Text(
- style: TextStyle(fontWeight: FontWeight.bold),
- "Get healthier and fit with our smart fitness coach",
- textAlign: TextAlign.center,
- ),
- )),
- ),
- Padding(
- padding: const EdgeInsets.symmetric(
- horizontal: 40, vertical: 10),
- child: Title(
- color: const Color.fromARGB(255, 6, 6, 32),
- child: const Center(
- child: Text(
- "Train from home, like you were in a gym, with our Interactive Fitness Coach",
- textAlign: TextAlign.center,
- ),
- )),
- ),
- Padding(
- padding: const EdgeInsets.all(8.0),
- child: ElevatedButton(
- style: ElevatedButton.styleFrom(
- fixedSize: const Size(320, 40),
- shape: const StadiumBorder(),
- backgroundColor:
- const Color.fromARGB(255, 37, 171, 117)),
- onPressed: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) =>
- const CreateAccountPage(title: "here")),
- );
- },
- child: const Text("Get Started")),
- ),
- Center(
- child: Row(
- mainAxisAlignment: MainAxisAlignment.center,
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- const Text(
- "Already have an account?",
- textAlign: TextAlign.center,
- ),
- TextButton(
- child: const Text("Log in"),
- onPressed: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) =>
- const LogInPage(title: "here")),
- );
- },
- )
- ],
- ),
- ),
- ],
- ),
- ),
- ],
- ),
- ),
- ),
- );
- }
-}
diff --git a/smart_gains/lib/FitnessGoalsPage.dart b/smart_gains/lib/FitnessGoalsPage.dart
deleted file mode 100644
index a10853c..0000000
--- a/smart_gains/lib/FitnessGoalsPage.dart
+++ /dev/null
@@ -1,218 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'InputUserDataPage.dart';
-
-class FitnessGoalsPage extends StatelessWidget {
- const FitnessGoalsPage({Key? key, required this.title}) : super(key: key);
- final String title;
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- body: Container(
- decoration: const BoxDecoration(
- image: DecorationImage(
- image: AssetImage("assets/womanImage.jpg"),
- fit: BoxFit.cover,
- ),
- ),
- child: Scaffold(
- appBar: AppBar(
- centerTitle: true,
- elevation: 0,
- bottomOpacity: 0,
- shadowColor: const Color.fromARGB(0, 0, 0, 0),
- backgroundColor: Colors.transparent,
- title: Image.asset(
- "assets/logo.png",
- fit: BoxFit.contain,
- height: 60,
- )),
- backgroundColor: Colors.transparent,
- body: Container(
- decoration: const BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.only(
- topLeft: Radius.circular(40.0),
- topRight: Radius.circular(40.0),
- )),
- alignment: FractionalOffset.center,
- child: SingleChildScrollView(
- reverse: false,
- child: Column(
- children: [
- Padding(
- padding: const EdgeInsets.all(40.0),
- child: Title(
- color: const Color.fromARGB(255, 6, 6, 32),
- child: const Text(
- textAlign: TextAlign.center,
- "Your Fitness Goals",
- style: TextStyle(
- fontWeight: FontWeight.bold, fontSize: 25),
- )),
- ),
- const Padding(
- padding: EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: MyStatefulWidget(
- title: "Get healthier in body and mind"),
- ),
- const Padding(
- padding: EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: MyStatefulWidget(title: "Lose weight/fat"),
- ),
- const Padding(
- padding: EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: MyStatefulWidget(title: "Gain weight/muscle"),
- ),
- const Padding(
- padding: EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: MyStatefulWidget(
- title: "Lose fat and gain muscle (aka “tone” up)"),
- ),
- const Padding(
- padding: EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: MyStatefulWidget(
- title: "Specific Doctor-given weight or exercise goal"),
- ),
- const Padding(
- padding: EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: MyStatefulWidget(
- title:
- "Strengthen the heart and decrease resting heart rate"),
- ),
- const Padding(
- padding: EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: MyStatefulWidget(
- title:
- "build muscle and increase your resting metabolism"),
- ),
- const Padding(
- padding: EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: MyStatefulWidget(title: "Gain Flexibility"),
- ),
- const Padding(
- padding: EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: MyStatefulWidget(title: "Perfect your form"),
- ),
- const Padding(
- padding: EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: MyStatefulWidget(
- title: "Be more explosive for a specific sport"),
- ),
- Padding(
- padding:
- const EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: ElevatedButton(
- style: ElevatedButton.styleFrom(
- fixedSize: const Size(320, 40),
- shape: const StadiumBorder(),
- backgroundColor:
- const Color.fromARGB(255, 37, 171, 117)),
- onPressed: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) =>
- const InputUserData(title: "here")),
- );
- },
- child: const Text("Continue")),
- ),
- ],
- ),
- ),
- ),
- ),
- ),
- );
- }
-}
-
-class LabeledCheckbox extends StatelessWidget {
- const LabeledCheckbox({
- super.key,
- required this.label,
- required this.padding,
- required this.value,
- required this.onChanged,
- });
-
- final String label;
- final EdgeInsets padding;
- final bool value;
- final ValueChanged onChanged;
-
- @override
- Widget build(BuildContext context) {
- return InkWell(
- onTap: () {
- onChanged(!value);
- },
- child: Padding(
- padding: padding,
- child: Container(
- height: 50,
- decoration: const BoxDecoration(
- color: const Color.fromARGB(255, 6, 6, 32),
- borderRadius: BorderRadius.all(Radius.circular(20))),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Padding(
- padding: const EdgeInsets.only(left: 20),
- child: Checkbox(
- fillColor: MaterialStateProperty.all(
- const Color.fromARGB(255, 37, 171, 117)),
- activeColor: Color.fromARGB(255, 37, 171, 117),
- shape: const CircleBorder(),
- value: value,
- onChanged: (bool? newValue) {
- onChanged(newValue!);
- },
- ),
- ),
- Expanded(
- child: Padding(
- padding: const EdgeInsets.only(right: 10),
- child: Text(
- style: const TextStyle(color: Colors.white),
- label,
- textAlign: TextAlign.center,
- ),
- )),
- ],
- ),
- ),
- ),
- );
- }
-}
-
-class MyStatefulWidget extends StatefulWidget {
- const MyStatefulWidget({Key? key, required this.title}) : super(key: key);
- final String title;
- @override
- State createState() => _MyStatefulWidgetState(title);
-}
-
-class _MyStatefulWidgetState extends State {
- bool _isSelected = false;
- String titulo = "";
-
- _MyStatefulWidgetState(String title) {
- titulo = title;
- }
- @override
- Widget build(BuildContext context) {
- return LabeledCheckbox(
- label: titulo,
- padding: const EdgeInsets.symmetric(horizontal: 20.0),
- value: _isSelected,
- onChanged: (bool newValue) {
- setState(() {
- _isSelected = newValue;
- });
- },
- );
- }
-}
diff --git a/smart_gains/lib/InputUserDataPage.dart b/smart_gains/lib/InputUserDataPage.dart
deleted file mode 100644
index 3b2f07f..0000000
--- a/smart_gains/lib/InputUserDataPage.dart
+++ /dev/null
@@ -1,138 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'FitnessGoalsPage.dart';
-
-class InputUserData extends StatelessWidget {
- const InputUserData({Key? key, required this.title}) : super(key: key);
- final String title;
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- body: Container(
- decoration: const BoxDecoration(
- image: DecorationImage(
- image: AssetImage("assets/womanImage.jpg"),
- fit: BoxFit.cover,
- ),
- ),
- child: Scaffold(
- appBar: AppBar(
- centerTitle: true,
- elevation: 0,
- bottomOpacity: 0,
- shadowColor: const Color.fromARGB(0, 0, 0, 0),
- backgroundColor: Colors.transparent,
- title: Image.asset(
- "assets/logo.png",
- fit: BoxFit.contain,
- height: 60,
- )),
- backgroundColor: Colors.transparent,
- body: Container(
- decoration: const BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.only(
- topLeft: Radius.circular(40.0),
- topRight: Radius.circular(40.0),
- )),
- alignment: FractionalOffset.center,
- child: SingleChildScrollView(
- reverse: true,
- child: Column(
- children: [
- Padding(
- padding: const EdgeInsets.all(40.0),
- child: Title(
- color: const Color.fromARGB(255, 6, 6, 32),
- child: const Text(
- textAlign: TextAlign.center,
- "Information about yourself",
- style: TextStyle(
- fontWeight: FontWeight.bold, fontSize: 25),
- )),
- ),
- Padding(
- padding: const EdgeInsets.only(
- left: 32, right: 32, bottom: 32, top: 32),
- child: Row(
- children: [
- Expanded(
- child: TextField(
- decoration: InputDecoration(
- border: OutlineInputBorder(
- borderRadius: BorderRadius.circular(20)),
- prefixIcon: const Icon(Icons.scale),
- hintText: 'Weigth',
- ),
- ),
- ),
- Expanded(
- child: TextField(
- decoration: InputDecoration(
- border: OutlineInputBorder(
- borderRadius: BorderRadius.circular(20)),
- prefixIcon: const Icon(Icons.square_foot),
- hintText: 'Height',
- ),
- ),
- ),
- ],
- ),
- ),
- Padding(
- padding:
- const EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: Row(
- children: [
- Expanded(
- child: TextField(
- decoration: InputDecoration(
- border: OutlineInputBorder(
- borderRadius: BorderRadius.circular(20)),
- prefixIcon: const Icon(Icons.transgender),
- hintText: 'Gender',
- ),
- ),
- ),
- Expanded(
- child: TextField(
- decoration: InputDecoration(
- border: OutlineInputBorder(
- borderRadius: BorderRadius.circular(20)),
- prefixIcon: const Icon(Icons.date_range),
- hintText: 'dd/mm/yyyy',
- ),
- ),
- ),
- ],
- ),
- ),
- Padding(
- padding:
- const EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: ElevatedButton(
- style: ElevatedButton.styleFrom(
- fixedSize: const Size(320, 40),
- shape: const StadiumBorder(),
- backgroundColor:
- const Color.fromARGB(255, 37, 171, 117)),
- onPressed: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) =>
- const FitnessGoalsPage(title: "here")),
- );
- },
- child: const Text("Continue")),
- ),
- ],
- ),
- ),
- ),
- ),
- ),
- );
- }
-}
diff --git a/smart_gains/lib/LogInPage.dart b/smart_gains/lib/LogInPage.dart
deleted file mode 100644
index b721fdd..0000000
--- a/smart_gains/lib/LogInPage.dart
+++ /dev/null
@@ -1,105 +0,0 @@
-import 'package:flutter/material.dart';
-
-class LogInPage extends StatelessWidget {
- const LogInPage({Key? key, required this.title}) : super(key: key);
- final String title;
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- body: Container(
- decoration: const BoxDecoration(
- image: DecorationImage(
- image: AssetImage("assets/womanImage.jpg"),
- fit: BoxFit.cover,
- ),
- ),
- child: Scaffold(
- appBar: AppBar(
- centerTitle: true,
- elevation: 0,
- bottomOpacity: 0,
- shadowColor: const Color.fromARGB(0, 0, 0, 0),
- backgroundColor: Colors.transparent,
- title: Image.asset(
- "assets/logo.png",
- fit: BoxFit.contain,
- height: 60,
- )),
- backgroundColor: Colors.transparent,
- body: Container(
- decoration: const BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.only(
- topLeft: Radius.circular(40.0),
- topRight: Radius.circular(40.0),
- )),
- alignment: FractionalOffset.center,
- child: SingleChildScrollView(
- reverse: true,
- child: Column(
- children: [
- Padding(
- padding: const EdgeInsets.all(40.0),
- child: Title(
- color: const Color.fromARGB(255, 6, 6, 32),
- child: const Text(
- "Sign in",
- style: TextStyle(
- fontWeight: FontWeight.bold, fontSize: 30),
- )),
- ),
- Padding(
- padding: const EdgeInsets.only(
- left: 32, right: 32, bottom: 32, top: 64),
- child: TextField(
- decoration: InputDecoration(
- border: OutlineInputBorder(
- borderRadius: BorderRadius.circular(20)),
- prefixIcon: const Icon(Icons.person),
- hintText: 'Usarname',
- ),
- ),
- ),
- Padding(
- padding:
- const EdgeInsets.only(left: 32, right: 32, bottom: 32),
- child: TextField(
- decoration: InputDecoration(
- border: OutlineInputBorder(
- borderRadius: BorderRadius.circular(20)),
- prefixIcon: const Icon(Icons.key),
- hintText: 'password',
- ),
- obscureText: true,
- enableSuggestions: false,
- autocorrect: false,
- ),
- ),
- Padding(
- padding: const EdgeInsets.only(
- left: 32, right: 32, bottom: 32, top: 32),
- child: ElevatedButton(
- style: ElevatedButton.styleFrom(
- fixedSize: const Size(320, 40),
- shape: const StadiumBorder(),
- backgroundColor:
- const Color.fromARGB(255, 37, 171, 117)),
- onPressed: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) =>
- const LogInPage(title: "here")),
- );
- },
- child: const Text("Log In")),
- ),
- ],
- ),
- ),
- ),
- ),
- ),
- );
- }
-}
diff --git a/smart_gains/lib/TrainTab.dart b/smart_gains/lib/TrainTab.dart
deleted file mode 100644
index 810cfef..0000000
--- a/smart_gains/lib/TrainTab.dart
+++ /dev/null
@@ -1,134 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'models/exercise_model.dart';
-
-class SecondPage extends StatelessWidget {
- const SecondPage({Key? key, required this.title}) : super(key: key);
- final String title;
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- backgroundColor: const Color.fromARGB(255, 255, 255, 255),
- body: Column(
- children: [
- SizedBox(
- height: 260.0,
- child: Scaffold(
- extendBodyBehindAppBar: true,
- appBar: AppBar(
- backgroundColor: Colors.transparent,
- iconTheme: const IconThemeData(
- color: Color.fromARGB(255, 255, 255, 255)),
- elevation: 0,
- bottomOpacity: 0,
- ),
- body: Container(
- height: 300.0,
- width: double.infinity,
- decoration: const BoxDecoration(
- image: DecorationImage(
- image: AssetImage("assets/deadLift.jpg"),
- fit: BoxFit.cover,
- )),
- child: Row(
- children: [
- const SizedBox(
- width: 10,
- ),
- Column(
- mainAxisAlignment: MainAxisAlignment.end,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: const [
- Text(
- "Free Style",
- style: TextStyle(
- fontSize: 33,
- color: Colors.white,
- fontFamily: 'KronaOne-Regular',
- fontWeight: FontWeight.bold),
- ),
- Text(
- "Choose your training",
- style: TextStyle(
- fontSize: 14,
- color: Colors.white,
- fontFamily: 'KronaOne-Regular'),
- ),
- SizedBox(height: 8)
- ]),
- ],
- ),
- ))),
- Container(
- height: 424,
- decoration: const BoxDecoration(color: Colors.white),
- child: ListView.builder(
- itemCount: 4,
- itemBuilder: (BuildContext context, int index) {
- return InkWell(
- child: Container(
- margin: const EdgeInsets.only(
- top: 0.0, bottom: 5.0, right: 10, left: 10),
- padding:
- EdgeInsets.symmetric(horizontal: 5, vertical: 5.0),
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- children: [
- SizedBox(
- height: 50,
- width: 50,
- child: Image.asset(exercises[index]
- .icon), //add image location here
- ),
- const SizedBox(width: 15),
- Column(
- crossAxisAlignment:
- CrossAxisAlignment.start,
- mainAxisAlignment:
- MainAxisAlignment.spaceBetween,
- children: [
- Text(
- exercises[index].name,
- style: const TextStyle(
- fontSize: 20,
- fontWeight: FontWeight.bold,
- color: Colors.black38),
- ),
- const SizedBox(
- height: 6,
- ),
- Text(
- exercises[index].description,
- style: const TextStyle(
- fontSize: 12,
- color: Colors.black87),
- )
- ],
- )
- ],
- ),
- ])));
- },
- ),
- ),
- ],
- ),
- bottomNavigationBar: BottomNavigationBar(items: const [
- BottomNavigationBarItem(
- label: 'Statistics',
- icon: Icon(Icons.insights),
- ),
- BottomNavigationBarItem(
- label: 'Train',
- icon: Icon(Icons.timer),
- ),
- BottomNavigationBarItem(
- icon: Icon(Icons.person_outline),
- label: 'Profile',
- ),
- ]),
- );
- }
-}
diff --git a/smart_gains/lib/main.dart b/smart_gains/lib/main.dart
deleted file mode 100644
index f9e10a0..0000000
--- a/smart_gains/lib/main.dart
+++ /dev/null
@@ -1,19 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:smart_gains/FirstPage.dart';
-
-void main() {
- runApp(const MyApp());
-}
-
-class MyApp extends StatelessWidget {
- const MyApp({Key? key}) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- return const MaterialApp(
- title: 'Flutter Camera Demo',
- debugShowCheckedModeBanner: false,
- home: FirstPage(title: "asdklasd"),
- );
- }
-}
diff --git a/smart_gains/lib/models/exercise_model.dart b/smart_gains/lib/models/exercise_model.dart
deleted file mode 100644
index 7fa656d..0000000
--- a/smart_gains/lib/models/exercise_model.dart
+++ /dev/null
@@ -1,50 +0,0 @@
-class Exercise {
- final int id;
- final String name;
- final String description;
- final String icon;
- final String instructions;
-
- Exercise({
- required this.id,
- required this.name,
- required this.description,
- required this.icon,
- required this.instructions,
- });
-}
-
-final Exercise deadLift = Exercise(
- id: 1,
- name: 'Deadlift',
- description: 'My name Jeff',
- icon: 'assets/icons/deadlift_icon.jpg',
- instructions: '',
-);
-
-final Exercise squat = Exercise(
- id: 1,
- name: 'Squat',
- description: 'My name Jeff',
- icon: 'assets/icons/squat_icon.png',
- instructions:
- "Here’s how to Squat with proper form, using a barbell:\n1. Stand with the bar on your upper-back, and your feet shoulder-width apart\n2. Squat down by pushing your knees to the side while moving hips back\n3. Break parallel by Squatting down until your hips are lower than your knees\n4. Squat back up while keeping your knees out and chest up\n 5.Stand with your hips and knees locked at the top\n",
-);
-
-final Exercise pushup = Exercise(
- id: 1,
- name: 'Pushup',
- description: 'My name Jeff',
- icon: 'assets/icons/pushup_icon.png',
- instructions: '',
-);
-
-final Exercise curl = Exercise(
- id: 1,
- name: 'Curl',
- description: 'My name Jeff',
- icon: 'assets/icons/curl_icon.png',
- instructions: '',
-);
-
-List exercises = [deadLift, squat, pushup, curl];
diff --git a/smart_gains/windows/runner/runner.exe.manifest b/smart_gains/windows/runner/runner.exe.manifest
deleted file mode 100644
index a42ea76..0000000
--- a/smart_gains/windows/runner/runner.exe.manifest
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
- PerMonitorV2
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-