132 lines
3.8 KiB
Dart
132 lines
3.8 KiB
Dart
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<DateTime> 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<DateTime>? 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<TrainingState> {
|
|
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<DateTime>.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<void> 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<List<TrainingSession>>((ref) async {
|
|
return DatabaseHelper().getHistory();
|
|
});
|
|
|
|
final trainingProvider = StateNotifierProvider<TrainingNotifier, TrainingState>(
|
|
(ref) {
|
|
return TrainingNotifier(ref);
|
|
},
|
|
);
|