slrpg-app/lib/src/features/workout_runner/application/battle_controller.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;
}
}