Initial commit
This commit is contained in:
commit
62e3771510
10 changed files with 266 additions and 0 deletions
10
LICENSE.md
Normal file
10
LICENSE.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Colttaine: Fitness App
|
||||
### Copyright (C) 2023 Colttaine
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the **GNU General Public License +NIGGER** as published by the [Free Software Foundation](http://www.gnu.org/licenses/) and [PlusNigger.org](https://plusnigger.org), either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the **GNU General Public License +NIGGER** for more details.
|
||||
|
||||
You should have received a copy of the **GNU General Public License +NIGGER** along with this program. If not, see [GNU Licenses ](http://www.gnu.org/licenses/) and [PlusNigger](https://plusnigger.org).
|
||||
|
||||
**The above copyright notice, this permission notice and the word "NIGGER" shall be included in all copies or substantial portions of the Software.**
|
25
README.md
Normal file
25
README.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Fitness App
|
||||
This is a simple app written in Python/Pygame for HITT or Kettlebell workouts.
|
||||
|
||||
The program loads a CSV file from your user directory containing the workout routine, and then runs a timer with audio to let the user know when to start the next exersize.
|
||||
|
||||
![Fitness App](https://git.rol.so/colttaine/fitness/raw/branch/master/example.png)
|
||||
|
||||
# Install
|
||||
Run the command:
|
||||
|
||||
``` bash
|
||||
make install
|
||||
```
|
||||
|
||||
You will also need to install python-pygame which is the main dependancy for the app.
|
||||
|
||||
# Usage
|
||||
The app will be installed to your desktop (Gnome, KDE, etc) and you can access it through the standard application launcher.
|
||||
|
||||
Clicking (or touching in the case of touchscreens) will pause and unpause the routine.
|
||||
|
||||
The CSV routine file can be found in your user directry under ~/.local/share/fitness if you wish to modify it to your needs.
|
||||
|
||||
# License
|
||||
This project is licensed under a GNU GPL3 +NIGGER license. For more information refer to [the included license file](https://git.rol.so/colttaine/fitness/src/branch/master/LICENSE.md).
|
BIN
ding.flac
Normal file
BIN
ding.flac
Normal file
Binary file not shown.
BIN
dong.flac
Normal file
BIN
dong.flac
Normal file
Binary file not shown.
BIN
example.png
Normal file
BIN
example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
8
fitness.desktop
Normal file
8
fitness.desktop
Normal file
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env xdg-open
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Type=Application
|
||||
Exec=python3 /opt/fitness/fitness.py
|
||||
Icon=/opt/fitness/icon.png
|
||||
Name=Fitness
|
||||
Comment=Fitness
|
170
fitness.py
Normal file
170
fitness.py
Normal file
|
@ -0,0 +1,170 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
'''
|
||||
|
||||
┌──────────────────────┤ Fitness App ├─────────────────────┐
|
||||
│ │
|
||||
│ Application to help with a workout routine │
|
||||
│ │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Version: 0.1 Date: 2023-03-05 │
|
||||
│ │
|
||||
│ License: GPL3+NIGGER (C) 2023 Colttaine │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
|
||||
'''
|
||||
|
||||
|
||||
import csv
|
||||
import os
|
||||
import pygame
|
||||
import sys
|
||||
import time
|
||||
|
||||
file_path = os.path.dirname(os.path.abspath(__file__)) + "/"
|
||||
|
||||
routine_file = os.path.expanduser("~") + '/.local/share/fitness/routine.csv'
|
||||
routine = []
|
||||
|
||||
pygame.init()
|
||||
screen = pygame.display.set_mode(( 1280, 720 ))
|
||||
fontLarge = pygame.font.SysFont("myriadProFont", 320)
|
||||
fontMid = pygame.font.SysFont("myriadProFont", 128)
|
||||
fontSmall = pygame.font.SysFont("myriadProFont", 72)
|
||||
fontTiny = pygame.font.SysFont("myriadProFont", 48)
|
||||
soundDing = pygame.mixer.Sound(file_path + "ding.flac")
|
||||
soundDong = pygame.mixer.Sound(file_path + "dong.flac")
|
||||
#pygame.display.toggle_fullscreen()
|
||||
|
||||
|
||||
|
||||
#--------[ LOAD CSV FILE ]--------#
|
||||
with open( routine_file ) as csvDataFile: # Load the exercise routine CSV file
|
||||
csvReader = csv.reader(csvDataFile) # Start CSV reader
|
||||
csvHeader = next(csvReader) # Read first line of CSV file as header information
|
||||
for row in csvReader: # For each subsequent row of CSV file read information
|
||||
routine.append( row )
|
||||
|
||||
#--------[ CONVERT SECONDS TO CLOCK STRING ]--------#
|
||||
def secToTime(_time):
|
||||
tmpStr = ""
|
||||
tmpStr += str(int(_time/3600)).zfill(2)
|
||||
tmpStr += ":"
|
||||
tmpStr += str(int(_time/60)).zfill(2)
|
||||
tmpStr += ":"
|
||||
tmpStr += str(_time%60).zfill(2)
|
||||
return tmpStr
|
||||
|
||||
#--------[ CONVERT CLOCK STRING TO SECONDS ]--------#
|
||||
def timeToSec(_time):
|
||||
hours = int( _time[0:2] )
|
||||
minutes = int( _time[3:5] )
|
||||
seconds = int( _time[6:9] )
|
||||
return (hours*3600) + (minutes*60) + seconds
|
||||
|
||||
|
||||
|
||||
|
||||
#--------[ MAIN LOOP ]--------#
|
||||
pause = False
|
||||
timer = 0
|
||||
while timer < timeToSec(routine[-1][0]):
|
||||
#--------[ GET CURRENT TIME INFO ]--------#
|
||||
time_start = time.time()
|
||||
|
||||
#--------[ CLEAR SCREEN TO BLACK ]--------#
|
||||
screen.fill((0,0,0))
|
||||
|
||||
#--------[ LOOK FOR INPUT EVENTS ]--------#
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
sys.exit()
|
||||
if event.type == pygame.MOUSEBUTTONDOWN:
|
||||
pause = not pause
|
||||
|
||||
#--------[ GET EXERCISE BASED ON TIME ]--------#
|
||||
exercise_current = []
|
||||
exercise_next = []
|
||||
for i in range(len(routine)):
|
||||
if timeToSec(routine[i][0]) <= timer:
|
||||
exercise_current = routine[i]
|
||||
exercise_next = routine[i+1]
|
||||
|
||||
#--------[ DRAW EXERCISE NAME ]--------#
|
||||
if int(exercise_current[3]) > 0:
|
||||
infoTextStr = '{0}kg {1}'.format(exercise_current[3], exercise_current[2])
|
||||
else:
|
||||
infoTextStr = '{0}'.format(exercise_current[2])
|
||||
infoText = fontMid.render(infoTextStr, 1, (255,255,255,255))
|
||||
screen.blit(infoText, infoText.get_rect(center=( screen.get_rect().centerx, screen.get_rect().centery*0.45 )))
|
||||
|
||||
#--------[ DRAW MAIN STOPWATCH ]--------#
|
||||
if timer < timeToSec(exercise_current[0]) + int(exercise_current[1]):
|
||||
color = (255, 0, 0, 255)
|
||||
else:
|
||||
color = (255, 255, 255, 255)
|
||||
timerText = fontLarge.render(secToTime(timer), 1, color)
|
||||
screen.blit(timerText, timerText.get_rect(center=screen.get_rect().center))
|
||||
|
||||
#--------[ DRAW SET AND REP NUMBERS ]--------#
|
||||
infoTextStr = 'Set: {0} Reps: {1}'.format(exercise_current[4], exercise_current[5])
|
||||
infoText = fontSmall.render(infoTextStr, 1, (255,255,255,255))
|
||||
screen.blit(infoText, infoText.get_rect(center=( screen.get_rect().centerx, screen.get_rect().centery*1.5 )))
|
||||
|
||||
#--------[ DRAW NEXT EXERCISE ]--------#
|
||||
if int(exercise_next[3]) > 0:
|
||||
infoTextStr = 'Next: {0}kg {1}'.format(exercise_next[3], exercise_next[2])
|
||||
else:
|
||||
infoTextStr = 'Next: {0}'.format(exercise_next[2])
|
||||
infoText = fontTiny.render(infoTextStr, 1, (255,255,255,255))
|
||||
screen.blit(infoText, infoText.get_rect(center=( screen.get_rect().centerx*1.5, screen.get_rect().centery*1.8 )))
|
||||
|
||||
if pause:
|
||||
color = (255,255,255,128)
|
||||
pygame.draw.rect(screen, color, pygame.Rect(32, 32, 64, 128))
|
||||
pygame.draw.rect(screen, color, pygame.Rect(128, 32,64, 128))
|
||||
pass
|
||||
|
||||
#--------[ UPDATE DISPLAY BUFFER ]--------#
|
||||
pygame.display.flip()
|
||||
|
||||
#--------[ PLAY DING SOUNDS ]--------#
|
||||
if not pause and exercise_next != routine[-1]:
|
||||
if timer == timeToSec(exercise_current[0]):
|
||||
pygame.mixer.Sound.play(soundDong)
|
||||
if timer >= timeToSec(exercise_next[0])-4:
|
||||
pygame.mixer.Sound.play(soundDing)
|
||||
|
||||
#--------[ WAIT FOR NEXT FRAME ]--------#
|
||||
time.sleep(1.0 - (time_start-time.time()))
|
||||
if not pause:
|
||||
timer +=1
|
||||
|
||||
|
||||
#--------[ END FRAME ]--------#
|
||||
while True:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
sys.exit()
|
||||
if event.type == pygame.MOUSEBUTTONDOWN:
|
||||
sys.exit()
|
||||
|
||||
screen.fill((0,0,0))
|
||||
|
||||
infoTextStr = 'Total Volume:'
|
||||
infoText = fontMid.render(infoTextStr, 1, (255,255,255,255))
|
||||
screen.blit(infoText, infoText.get_rect(center=( screen.get_rect().centerx, screen.get_rect().centery*0.45 )))
|
||||
|
||||
volume = 0
|
||||
for i in range(len(routine)):
|
||||
volume += int(routine[i][3]) * int(routine[i][5])
|
||||
|
||||
timerTextStr = '{0}kg'.format(volume)
|
||||
timerText = fontLarge.render(timerTextStr, 1, (255,255,255,255))
|
||||
screen.blit(timerText, timerText.get_rect(center=screen.get_rect().center))
|
||||
|
||||
pygame.display.flip()
|
||||
time.sleep(0.5)
|
||||
|
BIN
icon.png
Normal file
BIN
icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
21
makefile
Normal file
21
makefile
Normal file
|
@ -0,0 +1,21 @@
|
|||
##
|
||||
# Fitness
|
||||
#
|
||||
# @file
|
||||
# @version 0.1
|
||||
|
||||
all:
|
||||
echo "Run: make install"
|
||||
|
||||
|
||||
install:
|
||||
sudo rm -rf /opt/fitness
|
||||
sudo mkdir /opt/fitness
|
||||
sudo cp * /opt/fitness
|
||||
sudo cp fitness.desktop /usr/share/applications/
|
||||
|
||||
rm -rf ~/.local/share/fitness
|
||||
mkdir -p ~/.local/share/fitness
|
||||
cp routine.csv ~/.local/share/fitness/
|
||||
|
||||
# end
|
32
routine.csv
Normal file
32
routine.csv
Normal file
|
@ -0,0 +1,32 @@
|
|||
time,highlight,exercise,weight,set,rep
|
||||
00:00:00,10,Squat,32,1,10
|
||||
00:00:30,10,Bridges,0,1,10
|
||||
00:00:45,10,Halos,28,1,10
|
||||
00:01:15,10,Hinges,0,1,10
|
||||
00:01:30,10,Farmers Carry,36,1,2
|
||||
00:02:30,10,Squat,32,2,10
|
||||
00:03:00,10,Bridges,0,2,10
|
||||
00:03:15,10,Halos,28,2,10
|
||||
00:03:45,10,Hinges,0,2,10
|
||||
00:04:00,10,Loaded Carry,32,2,2
|
||||
00:05:00,10,Squat,32,3,10
|
||||
00:05:30,10,Bridges,0,3,10
|
||||
00:05:45,10,Halos,28,3,10
|
||||
00:06:15,10,Hinges,0,3,10
|
||||
00:06:30,10,Overhead Carry,28,3,2
|
||||
00:09:00,20,R-Swings,32,1,10
|
||||
00:10:00,20,L-Swings,32,2,10
|
||||
00:11:00,20,R-Swings,32,3,10
|
||||
00:12:00,20,L-Swings,32,4,10
|
||||
00:13:00,20,R-Swings,32,5,10
|
||||
00:14:00,20,L-Swings,28,6,10
|
||||
00:15:00,20,R-Swings,32,7,10
|
||||
00:16:00,20,L-Swings,28,8,10
|
||||
00:17:00,20,R-Swings,32,9,10
|
||||
00:18:00,20,L-Swings,32,10,10
|
||||
00:20:00,60,Turkish Get-Up,36,1,2
|
||||
00:22:00,60,Turkish Get-Up,36,2,2
|
||||
00:24:00,60,Turkish Get-Up,36,3,2
|
||||
00:26:00,60,Turkish Get-Up,36,4,2
|
||||
00:28:00,60,Turkish Get-Up,36,5,2
|
||||
00:29:00,0,Finish,0,0,0
|
|
Loading…
Reference in a new issue