235 lines
6.8 KiB
Dart
235 lines
6.8 KiB
Dart
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
import 'package:slrpg_app/src/shared/domain/entities/exercise.dart';
|
|
import 'package:slrpg_app/src/shared/domain/entities/workout_set.dart';
|
|
|
|
part 'battle_controller.g.dart';
|
|
|
|
class BattleState {
|
|
final List<Exercise> exercises;
|
|
final int currentExerciseIndex;
|
|
final int currentSetIndex;
|
|
final int repsCompleted;
|
|
final bool isLoading;
|
|
final bool isResting;
|
|
final int restSeconds;
|
|
final String? error;
|
|
final bool isExerciseTimerActive;
|
|
final int exerciseTimerSeconds;
|
|
|
|
const BattleState({
|
|
this.exercises = const [],
|
|
this.currentExerciseIndex = 0,
|
|
this.currentSetIndex = 0,
|
|
this.repsCompleted = 0,
|
|
this.isLoading = true,
|
|
this.isResting = false,
|
|
this.restSeconds = 0,
|
|
this.isExerciseTimerActive = false,
|
|
this.exerciseTimerSeconds = 0,
|
|
this.error,
|
|
});
|
|
|
|
BattleState copyWith({
|
|
List<Exercise>? exercises,
|
|
int? currentExerciseIndex,
|
|
int? currentSetIndex,
|
|
int? repsCompleted,
|
|
bool? isLoading,
|
|
bool? isResting,
|
|
int? restSeconds,
|
|
bool? isExerciseTimerActive,
|
|
int? exerciseTimerSeconds,
|
|
String? error,
|
|
}) {
|
|
return BattleState(
|
|
exercises: exercises ?? this.exercises,
|
|
currentExerciseIndex: currentExerciseIndex ?? this.currentExerciseIndex,
|
|
currentSetIndex: currentSetIndex ?? this.currentSetIndex,
|
|
repsCompleted: repsCompleted ?? this.repsCompleted,
|
|
isLoading: isLoading ?? this.isLoading,
|
|
isResting: isResting ?? this.isResting,
|
|
restSeconds: restSeconds ?? this.restSeconds,
|
|
isExerciseTimerActive:
|
|
isExerciseTimerActive ?? this.isExerciseTimerActive,
|
|
exerciseTimerSeconds: exerciseTimerSeconds ?? this.exerciseTimerSeconds,
|
|
error: error ?? this.error,
|
|
);
|
|
}
|
|
}
|
|
|
|
@riverpod
|
|
class BattleController extends _$BattleController {
|
|
@override
|
|
BattleState build() {
|
|
return const BattleState();
|
|
}
|
|
|
|
void setExercises(List<Exercise> exercises) {
|
|
state = state.copyWith(
|
|
exercises: exercises,
|
|
isLoading: false,
|
|
repsCompleted: exercises.isNotEmpty && exercises.first.sets.isNotEmpty
|
|
? exercises.first.sets.first.repsTarget
|
|
: 0,
|
|
);
|
|
}
|
|
|
|
void setLoading(bool loading) {
|
|
state = state.copyWith(isLoading: loading);
|
|
}
|
|
|
|
void setError(String error) {
|
|
state = state.copyWith(error: error, isLoading: false);
|
|
}
|
|
|
|
void updateRepsCompleted(int reps) {
|
|
state = state.copyWith(repsCompleted: reps);
|
|
}
|
|
|
|
void startRest(int seconds) {
|
|
state = state.copyWith(isResting: true, restSeconds: seconds);
|
|
}
|
|
|
|
void tickRest() {
|
|
if (state.restSeconds > 0) {
|
|
state = state.copyWith(restSeconds: state.restSeconds - 1);
|
|
} else {
|
|
state = state.copyWith(isResting: false);
|
|
}
|
|
}
|
|
|
|
void skipRest() {
|
|
state = state.copyWith(isResting: false, restSeconds: 0);
|
|
}
|
|
|
|
void startExerciseTimer(int seconds) {
|
|
state = state.copyWith(
|
|
isExerciseTimerActive: true, exerciseTimerSeconds: seconds);
|
|
}
|
|
|
|
void tickExerciseTimer() {
|
|
if (state.exerciseTimerSeconds > 0) {
|
|
state =
|
|
state.copyWith(exerciseTimerSeconds: state.exerciseTimerSeconds - 1);
|
|
} else {
|
|
state = state.copyWith(isExerciseTimerActive: false);
|
|
}
|
|
}
|
|
|
|
void stopExerciseTimer() {
|
|
state =
|
|
state.copyWith(isExerciseTimerActive: false, exerciseTimerSeconds: 0);
|
|
}
|
|
|
|
void completeSet({required int repsActual}) {
|
|
if (state.isExerciseTimerActive) {
|
|
state = state.copyWith(isExerciseTimerActive: false);
|
|
}
|
|
|
|
final currentExercise = state.exercises[state.currentExerciseIndex];
|
|
final currentSet = currentExercise.sets[state.currentSetIndex];
|
|
|
|
final updatedSet = currentSet.copyWith(
|
|
repsActual: repsActual,
|
|
completed: true,
|
|
);
|
|
|
|
final updatedSets = List<WorkoutSet>.from(currentExercise.sets);
|
|
updatedSets[state.currentSetIndex] = updatedSet;
|
|
|
|
final updatedExercise = currentExercise.copyWith(sets: updatedSets);
|
|
final updatedExercises = List<Exercise>.from(state.exercises);
|
|
updatedExercises[state.currentExerciseIndex] = updatedExercise;
|
|
|
|
state = state.copyWith(exercises: updatedExercises);
|
|
}
|
|
|
|
void moveToNextSet() {
|
|
final currentExercise = state.exercises[state.currentExerciseIndex];
|
|
|
|
if (state.currentSetIndex < currentExercise.sets.length - 1) {
|
|
final nextSet = currentExercise.sets[state.currentSetIndex + 1];
|
|
state = state.copyWith(
|
|
currentSetIndex: state.currentSetIndex + 1,
|
|
repsCompleted: nextSet.repsTarget,
|
|
);
|
|
}
|
|
}
|
|
|
|
void moveToNextExercise() {
|
|
if (state.currentExerciseIndex < state.exercises.length - 1) {
|
|
final nextExercise = state.exercises[state.currentExerciseIndex + 1];
|
|
final nextReps =
|
|
nextExercise.sets.isNotEmpty ? nextExercise.sets.first.repsTarget : 0;
|
|
|
|
state = state.copyWith(
|
|
currentExerciseIndex: state.currentExerciseIndex + 1,
|
|
currentSetIndex: 0,
|
|
repsCompleted: nextReps,
|
|
);
|
|
}
|
|
}
|
|
|
|
void adjustEmomSets(int newTotalSets) {
|
|
final currentEx = state.exercises[state.currentExerciseIndex];
|
|
|
|
if (newTotalSets == currentEx.sets.length) return;
|
|
|
|
List<WorkoutSet> currentSets = List.from(currentEx.sets);
|
|
|
|
if (newTotalSets > currentSets.length) {
|
|
final templateSet = currentSets.last;
|
|
for (int i = currentSets.length; i < newTotalSets; i++) {
|
|
currentSets.add(templateSet.copyWith(
|
|
setNumber: i + 1,
|
|
completed: true,
|
|
repsActual: templateSet.repsTarget,
|
|
));
|
|
}
|
|
} else {
|
|
currentSets = currentSets.sublist(0, newTotalSets);
|
|
}
|
|
|
|
final updatedEx = currentEx.copyWith(sets: currentSets);
|
|
final updatedExercises = List<Exercise>.from(state.exercises);
|
|
updatedExercises[state.currentExerciseIndex] = updatedEx;
|
|
|
|
state = state.copyWith(
|
|
exercises: updatedExercises,
|
|
currentSetIndex: newTotalSets - 1,
|
|
repsCompleted: updatedEx.sets.last.repsTarget,
|
|
);
|
|
}
|
|
|
|
Exercise get currentExercise => state.exercises[state.currentExerciseIndex];
|
|
WorkoutSet get currentSet => currentExercise.sets[state.currentSetIndex];
|
|
|
|
bool get isLastSet =>
|
|
state.currentSetIndex >= currentExercise.sets.length - 1;
|
|
|
|
bool get isLastExercise =>
|
|
state.currentExerciseIndex >= state.exercises.length - 1;
|
|
|
|
int get totalHP => state.exercises.fold<int>(
|
|
0,
|
|
(sum, ex) => sum + ex.sets.fold<int>(0, (s, set) => s + set.repsTarget),
|
|
);
|
|
|
|
int get completedHP {
|
|
int hp = 0;
|
|
|
|
for (int i = 0; i < state.currentExerciseIndex; i++) {
|
|
hp += state.exercises[i].sets.fold<int>(
|
|
0,
|
|
(sum, set) => sum + set.repsActual,
|
|
);
|
|
}
|
|
|
|
final currentExercise = state.exercises[state.currentExerciseIndex];
|
|
for (int i = 0; i < state.currentSetIndex; i++) {
|
|
hp += currentExercise.sets[i].repsActual;
|
|
}
|
|
|
|
return hp;
|
|
}
|
|
}
|