171 lines
6.3 KiB
Python
171 lines
6.3 KiB
Python
#!/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)
|
|
|