mirror of https://github.com/espruino/BangleApps
153 lines
3.7 KiB
JavaScript
153 lines
3.7 KiB
JavaScript
exports = class Exercise {
|
|
constructor(params) {
|
|
this.completed = false;
|
|
this.sets = [];
|
|
this.title = params.title;
|
|
this.weight = params.weight;
|
|
this.weightIncrement = params.weightIncrement;
|
|
this.unit = params.unit;
|
|
this.restPeriod = params.restPeriod;
|
|
this._originalRestPeriod = params.restPeriod;
|
|
this._restTimeout = null;
|
|
this._restInterval = null;
|
|
this._state = null;
|
|
}
|
|
|
|
get humanTitle() {
|
|
return `${this.title} ${this.weight}${this.unit}`;
|
|
}
|
|
|
|
get subTitle() {
|
|
const totalSets = this.sets.length;
|
|
const uncompletedSets = this.sets.filter((set) => !set.isCompleted()).length;
|
|
const currentSet = (totalSets - uncompletedSets) + 1;
|
|
return `Set ${currentSet} of ${totalSets}`;
|
|
}
|
|
|
|
decRestPeriod() {
|
|
this.restPeriod--;
|
|
}
|
|
|
|
addSet(set) {
|
|
this.sets.push(set);
|
|
}
|
|
|
|
currentSet() {
|
|
return this.sets.filter(set => !set.isCompleted())[0];
|
|
}
|
|
|
|
isLastSet() {
|
|
return this.sets.filter(set => !set.isCompleted()).length === 1;
|
|
}
|
|
|
|
isCompleted() {
|
|
return !!this.completed;
|
|
}
|
|
|
|
canSetCompleted() {
|
|
return this.sets.filter(set => set.isCompleted()).length === this.sets.length;
|
|
}
|
|
|
|
setCompleted() {
|
|
if (!this.canSetCompleted()) throw "All sets must be completed";
|
|
if (this.canProgress()) this.weight += this.weightIncrement;
|
|
this.completed = true;
|
|
}
|
|
|
|
canProgress() {
|
|
let completedRepsTotalSum = 0;
|
|
let targetRepsTotalSum = 0;
|
|
this.sets.forEach(set => completedRepsTotalSum += set.reps);
|
|
this.sets.forEach(set => targetRepsTotalSum += set.maxReps);
|
|
|
|
return (targetRepsTotalSum - completedRepsTotalSum) === 0;
|
|
}
|
|
|
|
startRestTimer(workout) {
|
|
this._restTimeout = setTimeout(() => {
|
|
this.next(workout);
|
|
}, 1000 * this.restPeriod);
|
|
|
|
this._restInterval = setInterval(() => {
|
|
this.decRestPeriod();
|
|
|
|
if (this.restPeriod < 0) {
|
|
this.resetRestTimer();
|
|
this.next();
|
|
|
|
return;
|
|
}
|
|
|
|
workout.emit("redraw");
|
|
}, 1000 );
|
|
}
|
|
|
|
resetRestTimer() {
|
|
clearTimeout(this._restTimeout);
|
|
clearInterval(this._restInterval);
|
|
this._restTimeout = null;
|
|
this._restInterval = null;
|
|
this.restPeriod = this._originalRestPeriod;
|
|
}
|
|
|
|
isRestTimerRunning() {
|
|
return this._restTimeout != null;
|
|
}
|
|
|
|
setupStartedButtons(workout) {
|
|
clearWatch();
|
|
|
|
setWatch(() => {
|
|
this.currentSet().incReps();
|
|
workout.emit("redraw");
|
|
}, BTN1, {repeat: true});
|
|
|
|
setWatch(workout.next.bind(workout), BTN2, {repeat: false});
|
|
|
|
setWatch(() => {
|
|
this.currentSet().decReps();
|
|
workout.emit("redraw");
|
|
}, BTN3, {repeat: true});
|
|
}
|
|
|
|
setupRestingButtons(workout) {
|
|
clearWatch();
|
|
setWatch(workout.next.bind(workout), BTN2, {repeat: false});
|
|
}
|
|
|
|
next(workout) {
|
|
const STARTED = 1;
|
|
const RESTING = 2;
|
|
const COMPLETED = 3;
|
|
|
|
switch(this._state) {
|
|
case null:
|
|
this._state = STARTED;
|
|
this.setupStartedButtons(workout);
|
|
break;
|
|
case STARTED:
|
|
this._state = RESTING;
|
|
this.startRestTimer(workout);
|
|
this.setupRestingButtons(workout);
|
|
break;
|
|
case RESTING:
|
|
this.resetRestTimer();
|
|
this.currentSet().setCompleted();
|
|
|
|
if (this.canSetCompleted()) {
|
|
this._state = COMPLETED;
|
|
this.setCompleted();
|
|
} else {
|
|
this._state = null;
|
|
}
|
|
// As we are changing state and require it to be reprocessed
|
|
// invoke the next step of workout
|
|
workout.next();
|
|
break;
|
|
default:
|
|
throw "Exercise: Attempting to move to an unknown state";
|
|
}
|
|
|
|
workout.emit("redraw");
|
|
}
|
|
}; |