Initial commit
This commit is contained in:
commit
62e3771510
|
@ -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.**
|
|
@ -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).
|
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
|
@ -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
|
|
@ -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)
|
||||
|
|
@ -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
|
|
@ -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 New Issue