355 lines
9.4 KiB
Go
355 lines
9.4 KiB
Go
// package services
|
|
//
|
|
// import (
|
|
//
|
|
// "log"
|
|
// "time"
|
|
//
|
|
// "git.patanix.de/git/kettlebell-app/internal/data"
|
|
//
|
|
// )
|
|
//
|
|
// // TrainingState hält den aktuellen Zustand einer laufenden Trainingseinheit.
|
|
//
|
|
// type TrainingState struct {
|
|
// IsTrainingRunning bool
|
|
// RemainingSeconds int
|
|
// InitialDurationSeconds int
|
|
// SetsDone int
|
|
// GoalSets int
|
|
// RepsPerSet int
|
|
// SetTimes []time.Time
|
|
// Progress float64
|
|
// SecondsSinceLastSet int
|
|
// LastSetTimestamp *time.Time
|
|
// CurrentProgram string
|
|
// CurrentBlockDay int
|
|
// CurrentReps int
|
|
// TotalTrainingDays int
|
|
// }
|
|
//
|
|
// func NewTrainingState() *TrainingState {
|
|
// return &TrainingState{
|
|
// IsTrainingRunning: false,
|
|
// RemainingSeconds: 0,
|
|
// InitialDurationSeconds: 0,
|
|
// SetsDone: 0,
|
|
// GoalSets: 5,
|
|
// RepsPerSet: 5,
|
|
// Progress: 0.0,
|
|
// SecondsSinceLastSet: 0,
|
|
// LastSetTimestamp: nil,
|
|
// CurrentProgram: "giant_1.0",
|
|
// CurrentBlockDay: 1,
|
|
// CurrentReps: 5,
|
|
// TotalTrainingDays: 0,
|
|
// SetTimes: []time.Time{},
|
|
// }
|
|
// }
|
|
//
|
|
// type TrainingService struct {
|
|
// State *TrainingState
|
|
// dbService *data.DatabaseService
|
|
// settingsService *SettingsService
|
|
// }
|
|
//
|
|
// func NewTrainingService(db *data.DatabaseService, settings *SettingsService) *TrainingService {
|
|
// initialState := NewTrainingState()
|
|
// trainingCount, err := db.GetTrainingCount()
|
|
// if err != nil {
|
|
// log.Printf("Fehler beim Abrufen der Trainingsanzahl, setze auf 0: %v", err)
|
|
// initialState.TotalTrainingDays = 0
|
|
// } else {
|
|
// initialState.TotalTrainingDays = trainingCount
|
|
// }
|
|
// return &TrainingService{
|
|
// State: initialState,
|
|
// dbService: db,
|
|
// settingsService: settings,
|
|
// }
|
|
// }
|
|
//
|
|
// func (s *TrainingService) updateProgram() {
|
|
// st := s.State
|
|
// newTotalDays := st.TotalTrainingDays + 1
|
|
// newProgram := st.CurrentProgram
|
|
// newDay := (st.CurrentBlockDay % 3) + 1
|
|
// newReps := st.CurrentReps
|
|
//
|
|
// if newTotalDays > 0 && newTotalDays%12 == 0 {
|
|
// switch st.CurrentProgram {
|
|
// case "giant_1.0":
|
|
// newProgram = "ksk_1.0"
|
|
// case "giant_1.1":
|
|
// newProgram = "ksk_1.1"
|
|
// case "giant_1.2":
|
|
// newProgram = "ksk_1.2"
|
|
// case "ksk_1.0":
|
|
// newProgram = "giant_1.1"
|
|
// case "ksk_1.1":
|
|
// newProgram = "giant_1.2"
|
|
// case "ksk_1.2":
|
|
// newProgram = "giant_1.0"
|
|
// default:
|
|
// newProgram = "giant_1.0"
|
|
// }
|
|
// newDay = 1
|
|
// }
|
|
//
|
|
// repsMap := map[string][]int{
|
|
// "giant_1.0": {5, 6, 4},
|
|
// "giant_1.1": {6, 8, 7},
|
|
// "giant_1.2": {7, 9, 8},
|
|
// "ksk_1.0": {5, 6, 4},
|
|
// "ksk_1.1": {6, 8, 7},
|
|
// "ksk_1.2": {7, 9, 8},
|
|
// }
|
|
//
|
|
// if reps, ok := repsMap[newProgram]; ok && len(reps) >= newDay {
|
|
// newReps = reps[newDay-1]
|
|
// } else {
|
|
// newReps = 5
|
|
// }
|
|
//
|
|
// st.CurrentProgram = newProgram
|
|
// st.CurrentBlockDay = newDay
|
|
// st.CurrentReps = newReps
|
|
// st.TotalTrainingDays = newTotalDays
|
|
// }
|
|
//
|
|
// func (s *TrainingService) StartTraining(minutes, goal int) {
|
|
// s.updateProgram()
|
|
// duration := minutes * 60
|
|
// s.State = &TrainingState{
|
|
// IsTrainingRunning: true,
|
|
// InitialDurationSeconds: duration,
|
|
// RemainingSeconds: duration,
|
|
// GoalSets: goal,
|
|
// RepsPerSet: s.State.CurrentReps,
|
|
// CurrentProgram: s.State.CurrentProgram,
|
|
// CurrentBlockDay: s.State.CurrentBlockDay,
|
|
// TotalTrainingDays: s.State.TotalTrainingDays,
|
|
// SetTimes: []time.Time{},
|
|
// }
|
|
// }
|
|
//
|
|
// func (s *TrainingService) Tick() {
|
|
// if s.State.RemainingSeconds > 0 {
|
|
// s.State.RemainingSeconds--
|
|
// }
|
|
// }
|
|
//
|
|
// func (s *TrainingService) TickLastSetTimer() {
|
|
// if s.State.IsTrainingRunning && s.State.LastSetTimestamp != nil {
|
|
// s.State.SecondsSinceLastSet = int(time.Since(*s.State.LastSetTimestamp).Seconds())
|
|
// }
|
|
// }
|
|
//
|
|
// func (s *TrainingService) CompleteSet() {
|
|
// st := s.State
|
|
// st.SetsDone++
|
|
// now := time.Now()
|
|
// st.SetTimes = append(st.SetTimes, now)
|
|
// if st.GoalSets > 0 {
|
|
// st.Progress = min(float64(st.SetsDone)/float64(st.GoalSets), 1.0)
|
|
// }
|
|
// st.LastSetTimestamp = &now
|
|
// st.SecondsSinceLastSet = 0
|
|
// }
|
|
//
|
|
// func (s *TrainingService) FinishTraining(session *data.TrainingSession) error {
|
|
// session.Program = s.State.CurrentProgram
|
|
// session.BlockDay = int64(s.State.CurrentBlockDay)
|
|
//
|
|
// err := s.dbService.SaveTraining(session)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
//
|
|
// // Platzhalter für den API-Aufruf (aus api_service.dart)
|
|
// s.sendToBackend(session)
|
|
//
|
|
// s.ResetTraining()
|
|
// return nil
|
|
// }
|
|
//
|
|
// func (s *TrainingService) ResetTraining() {
|
|
// // Diesen Teil nochmals pruefen
|
|
// s.State = NewTrainingState()
|
|
// trainingCount, err := s.dbService.GetTrainingCount()
|
|
// if err != nil {
|
|
// log.Print("Unable to get training count")
|
|
// }
|
|
// s.State.CurrentBlockDay = trainingCount
|
|
// // Hier müsste man TotalTrainingDays wieder korrekt laden.
|
|
// }
|
|
//
|
|
// // sendToBackend ist ein Platzhalter für deinen API-Aufruf.
|
|
//
|
|
// func (s *TrainingService) sendToBackend(session *data.TrainingSession) {
|
|
// // Hier würde die Logik aus deinem `api_service.dart` hinkommen.
|
|
// // z.B. ein HTTP POST Request mit den Trainingsdaten.
|
|
// // Da der Service nicht existiert, loggen wir es nur.
|
|
// log.Println("Sende Trainingsdaten an das Backend (Platzhalter)...")
|
|
// // rest := float64(session.Duration) / float64(session.Sets)
|
|
// // log.Printf("Reps: %d, Rest: %.2f, Sets: %d", session.RepsPerSet, rest, session.Sets)
|
|
// }
|
|
package services
|
|
|
|
import (
|
|
"log"
|
|
"time"
|
|
|
|
"git.patanix.de/git/kettlebell-app/internal/data"
|
|
)
|
|
|
|
type TrainingState struct {
|
|
IsTrainingRunning bool
|
|
RemainingSeconds int
|
|
InitialDurationSeconds int
|
|
SetsDone int
|
|
GoalSets int
|
|
RepsPerSet int
|
|
SetTimes []time.Time
|
|
Progress float64
|
|
SecondsSinceLastSet int
|
|
LastSetTimestamp *time.Time
|
|
CurrentProgram string
|
|
CurrentBlockDay int
|
|
CurrentReps int
|
|
TotalTrainingDays int
|
|
}
|
|
|
|
func calculateStateByDayCount(totalDays int) (program string, blockDay, reps int) {
|
|
program = "clean_1.0"
|
|
blockDay = 1
|
|
reps = 5
|
|
|
|
if totalDays > 0 {
|
|
cycleIndex := (totalDays / 12) % 6
|
|
|
|
programs := []string{"clean_1.0", "snatch_1.0", "clean_1.1", "snatch_1.1", "clean_1.2", "snatch_1.2"}
|
|
program = programs[cycleIndex]
|
|
|
|
blockDay = (totalDays % 3) + 1
|
|
}
|
|
|
|
repsMap := map[string][]int{
|
|
"clean_1.0": {5, 6, 4},
|
|
"clean_1.1": {6, 8, 7},
|
|
"clean_1.2": {7, 9, 8},
|
|
"snatch_1.0": {5, 6, 4},
|
|
"snatch_1.1": {6, 8, 7},
|
|
"snatch_1.2": {7, 9, 8},
|
|
}
|
|
|
|
if r, ok := repsMap[program]; ok && len(r) >= blockDay {
|
|
reps = r[blockDay-1]
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func NewTrainingState(db *data.DatabaseService) *TrainingState {
|
|
trainingCount, err := db.GetTrainingCount()
|
|
if err != nil {
|
|
log.Printf("Fehler beim Abrufen der Trainingsanzahl, setze auf 0: %v", err)
|
|
trainingCount = 0
|
|
}
|
|
|
|
program, blockDay, reps := calculateStateByDayCount(trainingCount)
|
|
|
|
return &TrainingState{
|
|
IsTrainingRunning: false,
|
|
TotalTrainingDays: trainingCount,
|
|
CurrentProgram: program,
|
|
CurrentBlockDay: blockDay,
|
|
CurrentReps: reps,
|
|
SetTimes: []time.Time{},
|
|
GoalSets: 5,
|
|
RepsPerSet: reps,
|
|
}
|
|
}
|
|
|
|
type TrainingService struct {
|
|
State *TrainingState
|
|
dbService *data.DatabaseService
|
|
settingsService *SettingsService
|
|
apiService *ApiService
|
|
}
|
|
|
|
func NewTrainingService(db *data.DatabaseService, settings *SettingsService, api *ApiService) *TrainingService {
|
|
return &TrainingService{
|
|
State: NewTrainingState(db),
|
|
dbService: db,
|
|
settingsService: settings,
|
|
apiService: api,
|
|
}
|
|
}
|
|
|
|
func (s *TrainingService) StartTraining(minutes, goal int) {
|
|
program, blockDay, reps := calculateStateByDayCount(s.State.TotalTrainingDays)
|
|
|
|
st := s.State
|
|
st.IsTrainingRunning = true
|
|
st.InitialDurationSeconds = minutes * 60
|
|
st.RemainingSeconds = st.InitialDurationSeconds
|
|
st.GoalSets = goal
|
|
st.CurrentProgram = program
|
|
st.CurrentBlockDay = blockDay
|
|
st.CurrentReps = reps
|
|
st.RepsPerSet = reps
|
|
|
|
st.SetsDone = 0
|
|
st.Progress = 0.0
|
|
st.SetTimes = []time.Time{}
|
|
st.LastSetTimestamp = nil
|
|
}
|
|
|
|
func (s *TrainingService) Tick() {
|
|
if s.State.RemainingSeconds > 0 {
|
|
s.State.RemainingSeconds--
|
|
}
|
|
}
|
|
|
|
func (s *TrainingService) TickLastSetTimer() {
|
|
if s.State.IsTrainingRunning && s.State.LastSetTimestamp != nil {
|
|
s.State.SecondsSinceLastSet = int(time.Since(*s.State.LastSetTimestamp).Seconds())
|
|
}
|
|
}
|
|
|
|
func (s *TrainingService) CompleteSet() {
|
|
st := s.State
|
|
st.SetsDone++
|
|
now := time.Now()
|
|
st.SetTimes = append(st.SetTimes, now)
|
|
if st.GoalSets > 0 {
|
|
st.Progress = min(float64(st.SetsDone)/float64(st.GoalSets), 1.0)
|
|
}
|
|
st.LastSetTimestamp = &now
|
|
st.SecondsSinceLastSet = 0
|
|
}
|
|
|
|
func (s *TrainingService) FinishTraining(session *data.TrainingSession) error {
|
|
session.Program = s.State.CurrentProgram
|
|
session.BlockDay = int64(s.State.CurrentBlockDay)
|
|
|
|
err := s.dbService.SaveTraining(session)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
go s.apiService.SendTrainingData(session)
|
|
|
|
s.ResetTraining()
|
|
return nil
|
|
}
|
|
|
|
func (s *TrainingService) ResetTraining() {
|
|
s.State = NewTrainingState(s.dbService)
|
|
}
|
|
|
|
// sendToBackend ist ein Platzhalter für deinen API-Aufruf.
|
|
func (s *TrainingService) sendToBackend(session *data.TrainingSession) {
|
|
log.Println("Sende Trainingsdaten an das Backend (Platzhalter)...")
|
|
}
|