import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:kettlebell_tracker/models/training_session.dart'; import 'package:kettlebell_tracker/services/api_service.dart'; import 'package:kettlebell_tracker/services/database_helper.dart'; import 'dart:async'; // Training State class TrainingState { final bool isTrainingRunning; final int remainingSeconds; final int initialDurationSeconds; final int setsDone; final int goalSets; final int repsPerSet; final List setTimes; final double progress; final int secondsSinceLastSet; final DateTime? lastSetTimestamp; TrainingState({ this.isTrainingRunning = false, this.remainingSeconds = 0, this.initialDurationSeconds = 0, this.setsDone = 0, this.goalSets = 5, this.repsPerSet = 5, this.setTimes = const [], this.progress = 0.0, this.secondsSinceLastSet = 0, this.lastSetTimestamp, }); TrainingState copyWith({ bool? isTrainingRunning, int? remainingSeconds, int? initialDurationSeconds, int? setsDone, int? goalSets, int? repsPerSet, List? setTimes, double? progress, int? secondsSinceLastSet, DateTime? lastSetTimestamp, bool clearLastSetTimestamp = false, }) { return TrainingState( isTrainingRunning: isTrainingRunning ?? this.isTrainingRunning, remainingSeconds: remainingSeconds ?? this.remainingSeconds, initialDurationSeconds: initialDurationSeconds ?? this.initialDurationSeconds, setsDone: setsDone ?? this.setsDone, goalSets: goalSets ?? this.goalSets, repsPerSet: repsPerSet ?? this.repsPerSet, setTimes: setTimes ?? this.setTimes, progress: progress ?? this.progress, secondsSinceLastSet: secondsSinceLastSet ?? this.secondsSinceLastSet, lastSetTimestamp: clearLastSetTimestamp ? null : lastSetTimestamp ?? this.lastSetTimestamp, ); } } class TrainingNotifier extends StateNotifier { final Ref ref; TrainingNotifier(this.ref) : super(TrainingState()); void startTraining(int minutes, int reps, int goal) { final duration = minutes * 60; state = TrainingState( isTrainingRunning: true, initialDurationSeconds: duration, remainingSeconds: duration, repsPerSet: reps, goalSets: goal, ); } void tick() { if (state.remainingSeconds > 0) { state = state.copyWith(remainingSeconds: state.remainingSeconds - 1); } } void tickLastSetTimer() { if (state.isTrainingRunning && state.lastSetTimestamp != null) { state = state.copyWith( secondsSinceLastSet: DateTime.now().difference(state.lastSetTimestamp!).inSeconds, ); } } void completeSet() { final newSetsDone = state.setsDone + 1; final newSetTimes = List.from(state.setTimes) ..add(DateTime.now()); final newProgress = state.goalSets > 0 ? newSetsDone / state.goalSets : 0.0; state = state.copyWith( setsDone: newSetsDone, setTimes: newSetTimes, progress: newProgress > 1.0 ? 1.0 : newProgress, lastSetTimestamp: DateTime.now(), secondsSinceLastSet: 0, ); } Future finishTraining(TrainingSession session) async { await DatabaseHelper().saveTraining(session); await sendTrainingToBackend( reps: session.repsPerSet, rest: session.duration / session.sets, sets: session.sets); ref.refresh(historyProvider); resetTraining(); } void resetTraining() { state = TrainingState(); } } final historyProvider = FutureProvider>((ref) async { return DatabaseHelper().getHistory(); }); final trainingProvider = StateNotifierProvider( (ref) { return TrainingNotifier(ref); }, );