Finish BuffGym app
parent
6deb376d99
commit
8272b19bb6
|
|
@ -1,116 +1,76 @@
|
||||||
const STARTED = 1;
|
|
||||||
const RESTING = 2;
|
|
||||||
const COMPLETED = 3;
|
|
||||||
const ONE_SECOND = 1000;
|
|
||||||
|
|
||||||
exports = class Exercise {
|
exports = class Exercise {
|
||||||
constructor(params /*{title, weight, unit, restPeriod}*/) {
|
constructor(params) {
|
||||||
const DEFAULTS = {
|
this.title = params.title;
|
||||||
title: "Unknown",
|
this.weight = params.weight;
|
||||||
weight: 0,
|
this.unit = params.unit;
|
||||||
unit: "Kg",
|
this.restPeriod = params.restPeriod;
|
||||||
restPeriod: 90,
|
this.completed = false;
|
||||||
weightIncrement: 2.5,
|
this.sets = [];
|
||||||
};
|
|
||||||
const p = Object.assign({}, DEFAULTS, params);
|
|
||||||
|
|
||||||
this._title = p.title;
|
|
||||||
this._weight = p.weight;
|
|
||||||
this._unit = p.unit;
|
|
||||||
this._originalRestPeriod = p.restPeriod; // Used when reseting _restPeriod
|
|
||||||
this._restPeriod = p.restPeriod;
|
|
||||||
this._weightIncrement = p.weightIncrement;
|
|
||||||
this._started = new Date();
|
|
||||||
this._completed = false;
|
|
||||||
this._sets = [];
|
|
||||||
this._restTimeout = null;
|
this._restTimeout = null;
|
||||||
this._restInterval = null;
|
this._restInterval = null;
|
||||||
this._state = null;
|
this._state = null;
|
||||||
}
|
this._originalRestPeriod = params.restPeriod;
|
||||||
|
this._weightIncrement = params.weightIncrement || 2.5;
|
||||||
get title() {
|
|
||||||
return this._title;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get humanTitle() {
|
get humanTitle() {
|
||||||
return `${this._title} ${this._weight}${this._unit}`;
|
return `${this.title} ${this.weight}${this.unit}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
get subTitle() {
|
get subTitle() {
|
||||||
const totalSets = this._sets.length;
|
const totalSets = this.sets.length;
|
||||||
const uncompletedSets = this._sets.filter((set) => !set.isCompleted()).length;
|
const uncompletedSets = this.sets.filter((set) => !set.isCompleted()).length;
|
||||||
const currentSet = (totalSets - uncompletedSets) + 1;
|
const currentSet = (totalSets - uncompletedSets) + 1;
|
||||||
return `Set ${currentSet} of ${totalSets}`;
|
return `Set ${currentSet} of ${totalSets}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
get restPeriod() {
|
|
||||||
return this._restPeriod;
|
|
||||||
}
|
|
||||||
|
|
||||||
decRestPeriod() {
|
decRestPeriod() {
|
||||||
this._restPeriod--;
|
this.restPeriod--;
|
||||||
}
|
|
||||||
|
|
||||||
get weight() {
|
|
||||||
return this._weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
get unit() {
|
|
||||||
return this._unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
get started() {
|
|
||||||
return this._started;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addSet(set) {
|
addSet(set) {
|
||||||
this._sets.push(set);
|
this.sets.push(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
addSets(sets) {
|
currentSet() {
|
||||||
sets.forEach(set => this.addSet(set));
|
return this.sets.filter(set => !set.isCompleted())[0];
|
||||||
}
|
|
||||||
|
|
||||||
get currentSet() {
|
|
||||||
return this._sets.filter(set => !set.isCompleted())[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isLastSet() {
|
isLastSet() {
|
||||||
return this._sets.filter(set => !set.isCompleted()).length === 1;
|
return this.sets.filter(set => !set.isCompleted()).length === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
isCompleted() {
|
isCompleted() {
|
||||||
return !!this._completed;
|
return !!this.completed;
|
||||||
}
|
}
|
||||||
|
|
||||||
canSetCompleted() {
|
canSetCompleted() {
|
||||||
return this._sets.filter(set => set.isCompleted()).length === this._sets.length;
|
return this.sets.filter(set => set.isCompleted()).length === this.sets.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCompleted() {
|
setCompleted() {
|
||||||
if (!this.canSetCompleted()) throw "All sets must be completed";
|
if (!this.canSetCompleted()) throw "All sets must be completed";
|
||||||
if (this.canProgress) this._weight += this._weightIncrement;
|
if (this.canProgress()) this.weight += this._weightIncrement;
|
||||||
this._completed = true;
|
this.completed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
get canProgress() {
|
canProgress() {
|
||||||
let completedRepsTotalSum = 0;
|
let completedRepsTotalSum = 0;
|
||||||
let targetRepsTotalSum = 0;
|
let targetRepsTotalSum = 0;
|
||||||
|
this.sets.forEach(set => completedRepsTotalSum += set.reps);
|
||||||
const completedRepsTotal = this._sets.forEach(set => completedRepsTotalSum += set.reps);
|
this.sets.forEach(set => targetRepsTotalSum += set.maxReps);
|
||||||
const targetRepsTotal = this._sets.forEach(set => targetRepsTotalSum += set.maxReps);
|
|
||||||
|
|
||||||
return (targetRepsTotalSum - completedRepsTotalSum) === 0;
|
return (targetRepsTotalSum - completedRepsTotalSum) === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
startRestTimer(program) {
|
startRestTimer(program) {
|
||||||
this._restTimeout = setTimeout(() => {
|
this._restTimeout = setTimeout(() => {
|
||||||
this.next();
|
this.next(program);
|
||||||
}, ONE_SECOND * this._restPeriod);
|
}, 1000 * this.restPeriod);
|
||||||
|
|
||||||
this._restInterval = setInterval(() => {
|
this._restInterval = setInterval(() => {
|
||||||
program.emit("redraw");
|
program.emit("redraw");
|
||||||
}, ONE_SECOND);
|
}, 1000 );
|
||||||
}
|
}
|
||||||
|
|
||||||
resetRestTimer() {
|
resetRestTimer() {
|
||||||
|
|
@ -118,7 +78,7 @@ exports = class Exercise {
|
||||||
clearInterval(this._restInterval);
|
clearInterval(this._restInterval);
|
||||||
this._restTimeout = null;
|
this._restTimeout = null;
|
||||||
this._restInterval = null;
|
this._restInterval = null;
|
||||||
this._restPeriod = this._originalRestPeriod;
|
this.restPeriod = this._originalRestPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
isRestTimerRunning() {
|
isRestTimerRunning() {
|
||||||
|
|
@ -129,52 +89,51 @@ exports = class Exercise {
|
||||||
clearWatch();
|
clearWatch();
|
||||||
|
|
||||||
setWatch(() => {
|
setWatch(() => {
|
||||||
this.currentSet.incReps();
|
this.currentSet().incReps();
|
||||||
program.emit("redraw");
|
program.emit("redraw");
|
||||||
}, BTN1, {repeat: true});
|
}, BTN1, {repeat: true});
|
||||||
|
|
||||||
setWatch(program.next.bind(program), BTN2, {repeat: false});
|
setWatch(program.next.bind(program), BTN2, {repeat: false});
|
||||||
|
|
||||||
setWatch(() => {
|
setWatch(() => {
|
||||||
this.currentSet.decReps();
|
this.currentSet().decReps();
|
||||||
program.emit("redraw");
|
program.emit("redraw");
|
||||||
}, BTN3, {repeat: true});
|
}, BTN3, {repeat: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
setupRestingButtons(program) {
|
setupRestingButtons(program) {
|
||||||
clearWatch();
|
clearWatch();
|
||||||
setWatch(program.next.bind(program), BTN2, {repeat: true});
|
setWatch(program.next.bind(program), BTN2, {repeat: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
next(program) {
|
next(program) {
|
||||||
global.poo = this;
|
const STARTED = 1;
|
||||||
|
const RESTING = 2;
|
||||||
|
const COMPLETED = 3;
|
||||||
|
|
||||||
switch(this._state) {
|
switch(this._state) {
|
||||||
case null:
|
case null:
|
||||||
console.log("XXX 1 moving null -> STARTED");
|
|
||||||
this._state = STARTED;
|
this._state = STARTED;
|
||||||
this.setupStartedButtons(program);
|
this.setupStartedButtons(program);
|
||||||
break;
|
break;
|
||||||
case STARTED:
|
case STARTED:
|
||||||
console.log("XXX 2 moving STARTED -> RESTING");
|
|
||||||
this._state = RESTING;
|
this._state = RESTING;
|
||||||
this.startRestTimer(program);
|
this.startRestTimer(program);
|
||||||
this.setupRestingButtons(program);
|
this.setupRestingButtons(program);
|
||||||
break;
|
break;
|
||||||
case RESTING:
|
case RESTING:
|
||||||
this.resetRestTimer();
|
this.resetRestTimer();
|
||||||
this.currentSet.setCompleted();
|
this.currentSet().setCompleted();
|
||||||
|
|
||||||
if (this.canSetCompleted()) {
|
if (this.canSetCompleted()) {
|
||||||
console.log("XXX 3b moving RESTING -> COMPLETED");
|
|
||||||
this._state = COMPLETED;
|
this._state = COMPLETED;
|
||||||
this.setCompleted();
|
this.setCompleted();
|
||||||
} else {
|
} else {
|
||||||
console.log("XXX 3a moving RESTING -> null");
|
|
||||||
this._state = null;
|
this._state = null;
|
||||||
}
|
}
|
||||||
// As we are changing state and require it to be reprocessed
|
// As we are changing state and require it to be reprocessed
|
||||||
// invoke the next step of program
|
// invoke the next step of program
|
||||||
program.next(program);
|
program.next();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw "Exercise: Attempting to move to an unknown state";
|
throw "Exercise: Attempting to move to an unknown state";
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
require("heatshrink").decompress(atob("mEwwhC/AFEEolAC6lN7vdDCcECwPd6guVGCYuDC4cCBQMikQXQJAMjkECmcyIx4XDmUjmYvLC4XUDARHBIoIWLgATCGQdA7tEonQC5ouDDYg0BOxgSEAggwKRwgUCC6ZIDSwoXNogWDDgNCAgIWIkUEoUk6kiCgMkokipsiBIQXIki2CAgNCAoYADC5Eic4Mic4ICCAIIJCC5MzAAcykYGEAAIXOABAXTmUzGoIXVAIIXLB4SICDIovjO76PZbYR3PDI4XiI6530MIh3SC6R33C/oAOC48CCxsgC44A/ADY="))
|
require("heatshrink").decompress(atob("mEwxH+ACPI5AUSADAtB5vNGFQtBAIfNF95hoF4wwoF5AwmF5BhmXYbAEF/6QbF1QwIF04qB54ADAwIwoF4oRKBoIvsB4gvZ58kkgCDFxoxaF5wuHGDQcMF5IwXDZwLDGDmlDIWlkgJDSwIABCRAwPDQohCFgIABDQIOCFwYABr4RCCQIvQDYguEAAwtFF5owJDZAvHFw4vFOYQvKFAowMBxIvFMQwvPAB4wFUQ4vJGDYvUGC4vNdgyuEGDIsNFwYwGNAgAPExAvMGIdfTIovfTpYvrfRCOkZ44ugF44NGF05gUFyQvKGIoueGKIufGJ4uhG5oupGItfr4vvAAgvlGAQvt/wrEF9oEGF841IF9QGHX0oGIAD8kAAYJOFzwEBBQoMFACA="));
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"title": "Program A",
|
||||||
|
"exercises": [
|
||||||
|
{
|
||||||
|
"title": "Squats",
|
||||||
|
"weight": 40,
|
||||||
|
"unit": "Kg",
|
||||||
|
"sets": [5, 5, 5, 5, 5],
|
||||||
|
"restPeriod": 90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Overhead press",
|
||||||
|
"weight": 20,
|
||||||
|
"unit": "Kg",
|
||||||
|
"sets": [5, 5, 5, 5, 5],
|
||||||
|
"restPeriod": 90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Deadlift",
|
||||||
|
"weight": 20,
|
||||||
|
"unit": "Kg",
|
||||||
|
"sets": [5],
|
||||||
|
"restPeriod": 90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Pullups",
|
||||||
|
"weight": 0,
|
||||||
|
"unit": "Kg",
|
||||||
|
"sets": [10, 10, 10],
|
||||||
|
"restPeriod": 90
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"title": "Program B",
|
||||||
|
"exercises": [
|
||||||
|
{
|
||||||
|
"title": "Squats",
|
||||||
|
"weight": 40,
|
||||||
|
"unit": "Kg",
|
||||||
|
"sets": [5, 5, 5, 5, 5],
|
||||||
|
"restPeriod": 90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Bench press",
|
||||||
|
"weight": 20,
|
||||||
|
"unit": "Kg",
|
||||||
|
"sets": [5, 5, 5, 5, 5],
|
||||||
|
"restPeriod": 90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Row",
|
||||||
|
"weight": 20,
|
||||||
|
"unit":"Kg",
|
||||||
|
"sets": [5, 5, 5, 5, 5],
|
||||||
|
"restPeriod": 90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Tricep extension",
|
||||||
|
"weight": 20,
|
||||||
|
"unit": "Kg",
|
||||||
|
"sets": [10, 10, 10],
|
||||||
|
"restPeriod": 90
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"title": "Program A",
|
||||||
|
"file": "buffgym-program-a.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Program B",
|
||||||
|
"file": "buffgym-program-b.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
@ -1,68 +1,56 @@
|
||||||
exports = class Program {
|
exports = class Program {
|
||||||
constructor(params) {
|
constructor(params) {
|
||||||
const DEFAULTS = {
|
this.title = params.title;
|
||||||
title: "Unknown",
|
this.exercises = [];
|
||||||
trainDay: "", // Day of week
|
this.completed = false;
|
||||||
};
|
|
||||||
const p = Object.assign({}, DEFAULTS, params);
|
|
||||||
|
|
||||||
this._title = p.title;
|
|
||||||
this._trainDay = p.trainDay;
|
|
||||||
this._exercises = [];
|
|
||||||
|
|
||||||
this.on("redraw", redraw.bind(null, this));
|
this.on("redraw", redraw.bind(null, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
get title() {
|
|
||||||
return `${this._title} - ${this._trainDay}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
addExercise(exercise) {
|
|
||||||
this._exercises.push(exercise);
|
|
||||||
}
|
|
||||||
|
|
||||||
addExercises(exercises) {
|
addExercises(exercises) {
|
||||||
exercises.forEach(exercise => this.addExercise(exercise));
|
exercises.forEach(exercise => this.exercises.push(exercise));
|
||||||
}
|
}
|
||||||
|
|
||||||
currentExercise() {
|
currentExercise() {
|
||||||
return (
|
return this.exercises.filter(exercise => !exercise.isCompleted())[0];
|
||||||
this._exercises
|
|
||||||
.filter(exercise => !exercise.isCompleted())[0]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
canComplete() {
|
canComplete() {
|
||||||
return (
|
return this.exercises.filter(exercise => exercise.isCompleted()).length === this.exercises.length;
|
||||||
this._exercises
|
|
||||||
.filter(exercise => exercise.isCompleted())
|
|
||||||
.length === this._exercises.length
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setCompleted() {
|
setCompleted() {
|
||||||
if (!this.canComplete()) throw "All exercises must be completed";
|
if (!this.canComplete()) throw "All exercises must be completed";
|
||||||
this._completed = true;
|
this.completed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
isCompleted() {
|
isCompleted() {
|
||||||
return !!this._completed;
|
return !!this.completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
title: this.title,
|
||||||
|
exercises: this.exercises.map(exercise => {
|
||||||
|
return {
|
||||||
|
title: exercise.title,
|
||||||
|
weight: exercise.weight,
|
||||||
|
unit: exercise.unit,
|
||||||
|
sets: exercise.sets.map(set => set.maxReps),
|
||||||
|
restPeriod: exercise.restPeriod,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// State machine
|
// State machine
|
||||||
next() {
|
next() {
|
||||||
console.log("XXX Program.next");
|
|
||||||
const exercise = this.currentExercise();
|
|
||||||
|
|
||||||
// All exercises are completed so mark the
|
|
||||||
// Program as comleted
|
|
||||||
if (this.canComplete()) {
|
if (this.canComplete()) {
|
||||||
this.setCompleted();
|
this.setCompleted();
|
||||||
this.emit("redraw");
|
this.emit("redraw");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
exercise.next(this);
|
// Call current exercise state machine
|
||||||
|
this.currentExercise().next(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
[{"title":"Program A","exercises":[{"title":"Squats","weight":40,"unit":"Kg","sets":[5,5,5,5,5]},{"title":"Overhead press","weight":20,"unit":"Kg","sets":[5,5,5,5,5]},{"title":"Deadlift","weight":20,"unit":"Kg","sets":[5]},{"title":"Pullups","weight":0,"unit":"Kg","sets":[10,10,10]}]},{"title":"Program B","exercises":[{"title":"Squats","weight":40,"unit":"Kg","sets":[5,5,5,5,5]},{"title":"Bench press","weight":20,"unit":"Kg","sets":[5,5,5,5,5]},{"title":"Row","weight":20,"unit":"Kg","sets":[5,5,5,5,5]},{"title":"Tricep extension","weight":20,"unit":"Kg","sets":[10,10,10]}]}]
|
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"title": "Program A",
|
|
||||||
"exercises": [
|
|
||||||
{
|
|
||||||
"title": "Squats",
|
|
||||||
"weight": 40,
|
|
||||||
"unit": "Kg",
|
|
||||||
"sets": [
|
|
||||||
5,
|
|
||||||
5,
|
|
||||||
5,
|
|
||||||
5,
|
|
||||||
5
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Overhead press",
|
|
||||||
"weight": 20,
|
|
||||||
"unit": "Kg",
|
|
||||||
"sets": [
|
|
||||||
5,
|
|
||||||
5,
|
|
||||||
5,
|
|
||||||
5,
|
|
||||||
5
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Deadlift",
|
|
||||||
"weight": 20,
|
|
||||||
"unit": "Kg",
|
|
||||||
"sets": [
|
|
||||||
5
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Pullups",
|
|
||||||
"weight": 0,
|
|
||||||
"unit": "Kg",
|
|
||||||
"sets": [
|
|
||||||
10,
|
|
||||||
10,
|
|
||||||
10
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Program B",
|
|
||||||
"exercises": [
|
|
||||||
{
|
|
||||||
"title": "Squats",
|
|
||||||
"weight": 40,
|
|
||||||
"unit": "Kg",
|
|
||||||
"sets": [
|
|
||||||
5,
|
|
||||||
5,
|
|
||||||
5,
|
|
||||||
5,
|
|
||||||
5
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Bench press",
|
|
||||||
"weight": 20,
|
|
||||||
"unit": "Kg",
|
|
||||||
"sets": [
|
|
||||||
5,
|
|
||||||
5,
|
|
||||||
5,
|
|
||||||
5,
|
|
||||||
5
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Row",
|
|
||||||
"weight": 20,
|
|
||||||
"unit":"Kg",
|
|
||||||
"sets": [
|
|
||||||
5,
|
|
||||||
5,
|
|
||||||
5,
|
|
||||||
5,
|
|
||||||
5
|
|
||||||
]
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Tricep extension",
|
|
||||||
"weight": 20,
|
|
||||||
"unit": "Kg",
|
|
||||||
"sets": [
|
|
||||||
10,
|
|
||||||
10,
|
|
||||||
10
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
@ -1,46 +1,28 @@
|
||||||
exports = class Set {
|
exports = class Set {
|
||||||
constructor(maxReps) {
|
constructor(maxReps) {
|
||||||
this._minReps = 0;
|
this.minReps = 0;
|
||||||
this._maxReps = maxReps;
|
this.maxReps = maxReps;
|
||||||
this._reps = 0;
|
this.reps = 0;
|
||||||
this._completed = false;
|
this.completed = false;
|
||||||
}
|
|
||||||
|
|
||||||
get title() {
|
|
||||||
return this._title;
|
|
||||||
}
|
|
||||||
|
|
||||||
get weight() {
|
|
||||||
return this._weight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isCompleted() {
|
isCompleted() {
|
||||||
return !!this._completed;
|
return !!this.completed;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCompleted() {
|
setCompleted() {
|
||||||
this._completed = true;
|
this.completed = true;
|
||||||
}
|
|
||||||
|
|
||||||
get reps() {
|
|
||||||
return this._reps;
|
|
||||||
}
|
|
||||||
|
|
||||||
get maxReps() {
|
|
||||||
return this._maxReps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
incReps() {
|
incReps() {
|
||||||
if (this._completed) return;
|
if (this.completed) return;
|
||||||
if (this._reps >= this._maxReps) return;
|
if (this.reps >= this.maxReps) return;
|
||||||
|
this.reps++;
|
||||||
this._reps++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
decReps() {
|
decReps() {
|
||||||
if (this._completed) return;
|
if (this.completed) return;
|
||||||
if (this._reps <= this._minReps) return;
|
if (this.reps <= this.minReps) return;
|
||||||
|
this.reps--;
|
||||||
this._reps--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,177 +1,135 @@
|
||||||
|
Bangle.setLCDMode("120x120");
|
||||||
|
|
||||||
const W = g.getWidth();
|
const W = g.getWidth();
|
||||||
const H = g.getHeight();
|
const H = g.getHeight();
|
||||||
const RED = "#d32e29";
|
const RED = "#d32e29";
|
||||||
const PINK = "#f05a56";
|
const PINK = "#f05a56";
|
||||||
const WHITE = "#ffffff";
|
const WHITE = "#ffffff";
|
||||||
|
|
||||||
const Set = require("buffgym-set.js");
|
|
||||||
const Exercise = require("buffgym-exercise.js");
|
|
||||||
const Program = require("buffgym-program.js");
|
|
||||||
|
|
||||||
function centerStringX(str) {
|
|
||||||
return (W - g.stringWidth(str)) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
function iconIncrement() {
|
|
||||||
const img = require("heatshrink").decompress(atob("ikUxH+AA3XAAgNHCJIVMBYXQ5PC4XJ6AUJCIQQBAAoVCCQwjCAA/JCgglHA4IpJBYwTHA4RMJCY5oDJo4THKIQKET5IMGCaY7TMaKLTWajbTFJIlICgoVBFYXJYQYSGCggAGCRAVIBgw"));
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
|
|
||||||
function iconDecrement() {
|
|
||||||
const img = require("heatshrink").decompress(atob("ikUxH+AA3XAAgNHCJIVMBYXQ5PC4XJ6AUJCIQQBAAoVCCQwjCAA/JCgglKFJADBCRYABCYQmOFAhNMKIw6FTw4LHCaY7TMaKLTWajbTFJglFCgoVBFYXJYQYSGCggAGCRAVIBgw="));
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
|
|
||||||
function iconOk() {
|
|
||||||
const img = require("heatshrink").decompress(atob("ikUxH+AA3XAAgNHCJIVMBYXQ5PC4XJ6AUJCIQQBAAoVCCQwjCAA/JCgglKFJADBCJQxCCYQmMIwZoDJpQMCKIg6KBYwTGFQgeHHYouCCRI7EMYTXFRhILEK5SfFRgYSIborbSbpglFCgoVBFYXJYQYSGCggAGCRAVIBgwA=="));
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawMenu(params) {
|
function drawMenu(params) {
|
||||||
|
const hs = require("heatshrink");
|
||||||
|
const incImg = hs.decompress(atob("gsFwMAkM+oUA"));
|
||||||
|
const decImg = hs.decompress(atob("gsFwIEBnwCBA"));
|
||||||
|
const okImg = hs.decompress(atob("gsFwMAhGFo0A"));
|
||||||
const DEFAULT_PARAMS = {
|
const DEFAULT_PARAMS = {
|
||||||
showBTN1: false,
|
showBTN1: false,
|
||||||
showBTN2: false,
|
showBTN2: false,
|
||||||
showBTN3: false,
|
showBTN3: false,
|
||||||
};
|
};
|
||||||
const p = Object.assign({}, DEFAULT_PARAMS, params);
|
const p = Object.assign({}, DEFAULT_PARAMS, params);
|
||||||
if (p.showBTN1) g.drawImage(iconIncrement(), W - 30, 10);
|
if (p.showBTN1) g.drawImage(incImg, W - 10, 10);
|
||||||
if (p.showBTN2) g.drawImage(iconOk(), W - 30, 110);
|
if (p.showBTN2) g.drawImage(okImg, W - 10, 60);
|
||||||
if (p.showBTN3) g.drawImage(iconDecrement(), W - 30, 210);
|
if (p.showBTN3) g.drawImage(decImg, W - 10, 110);
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearScreen() {
|
function drawSet(exercise) {
|
||||||
g.setColor(RED);
|
const set = exercise.currentSet();
|
||||||
g.fillRect(0,0,W,H);
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawTitle(exercise) {
|
|
||||||
const title = exercise.humanTitle;
|
|
||||||
|
|
||||||
g.setFont("Vector",20);
|
|
||||||
g.setColor(WHITE);
|
|
||||||
g.drawString(title, centerStringX(title), 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawReps(exercise) {
|
|
||||||
const set = exercise.currentSet;
|
|
||||||
if (set.isCompleted()) return;
|
if (set.isCompleted()) return;
|
||||||
|
|
||||||
|
g.clear();
|
||||||
|
|
||||||
|
// Draw exercise title
|
||||||
g.setColor(PINK);
|
g.setColor(PINK);
|
||||||
g.fillCircle(W / 2, H / 2, 50);
|
g.fillRect(15, 0, W - 15, 18);
|
||||||
|
g.setFontAlign(0, -1);
|
||||||
|
g.setFont("6x8", 1);
|
||||||
g.setColor(WHITE);
|
g.setColor(WHITE);
|
||||||
g.setFont("Vector", 40);
|
g.drawString(exercise.title, W / 2, 5);
|
||||||
g.drawString(set.reps, centerStringX(set.reps), (H - 45) / 2);
|
g.setFont("6x8", 1);
|
||||||
g.setFont("Vector", 15);
|
g.drawString(exercise.weight + " " + exercise.unit, W / 2, 27);
|
||||||
const note = `of ${set.maxReps}`;
|
// Draw completed reps counter
|
||||||
g.drawString(note, centerStringX(note), (H / 2) + 25);
|
g.setFontAlign(0, 0);
|
||||||
}
|
g.setColor(PINK);
|
||||||
|
g.fillRect(15, 42, W - 15, 80);
|
||||||
function drawSets(exercise) {
|
|
||||||
const sets = exercise.subTitle;
|
|
||||||
|
|
||||||
g.setColor(WHITE);
|
g.setColor(WHITE);
|
||||||
g.setFont("Vector", 15);
|
g.setFont("6x8", 5);
|
||||||
g.drawString(sets, centerStringX(sets), H - 25);
|
g.drawString(set.reps, (W / 2) + 2, (H / 2) + 1);
|
||||||
}
|
g.setFont("6x8", 1);
|
||||||
|
const note = `Target reps: ${set.maxReps}`;
|
||||||
|
g.drawString(note, W / 2, H - 24);
|
||||||
|
// Draw sets monitor
|
||||||
|
g.drawString(exercise.subTitle, W / 2, H - 12);
|
||||||
|
|
||||||
function drawSetProgress(exercise) {
|
|
||||||
drawTitle(exercise);
|
|
||||||
drawReps(exercise);
|
|
||||||
drawSets(exercise);
|
|
||||||
drawMenu({showBTN1: true, showBTN2: true, showBTN3: true});
|
drawMenu({showBTN1: true, showBTN2: true, showBTN3: true});
|
||||||
|
|
||||||
|
g.flip();
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawStartNextExercise() {
|
function drawProgDone() {
|
||||||
const title = "Good work";
|
|
||||||
const msg = "No need to rest\nmove straight on\nto the next exercise";
|
|
||||||
|
|
||||||
g.setColor(WHITE);
|
|
||||||
g.setFont("Vector", 35);
|
|
||||||
g.drawString(title, centerStringX(title), 10);
|
|
||||||
g.setFont("Vector", 15);
|
|
||||||
g.drawString(msg, 30, 150);
|
|
||||||
drawMenu({showBTN1: false, showBTN2: true, showBTN3: false});
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawProgramCompleted() {
|
|
||||||
const title1 = "You did";
|
const title1 = "You did";
|
||||||
const title2 = "GREAT!";
|
const title2 = "GREAT!";
|
||||||
const msg = "That's the program\ncompleted. Now eat\nsome food and\nget plenty of rest.";
|
const msg = "That's the program\ncompleted. Now eat\nsome food and\nget plenty of rest.";
|
||||||
|
|
||||||
clearWatch();
|
clearWatch();
|
||||||
setWatch(Bangle.showLauncher, BTN2, {repeat: false});
|
setWatch(Bangle.showLauncher, BTN2, {repeat: false});
|
||||||
|
|
||||||
g.setColor(WHITE);
|
|
||||||
g.setFont("Vector", 35);
|
|
||||||
g.drawString(title1, centerStringX(title1), 10);
|
|
||||||
g.setFont("Vector", 40);
|
|
||||||
g.drawString(title2, centerStringX(title2), 50);
|
|
||||||
g.setFont("Vector", 15);
|
|
||||||
g.drawString(msg, 30, 150);
|
|
||||||
drawMenu({showBTN1: false, showBTN2: true, showBTN3: false});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
function drawExerciseCompleted(program) {
|
|
||||||
const exercise = program.currentExercise();
|
|
||||||
const title = exercise.canProgress?
|
|
||||||
"WELL DONE!" :
|
|
||||||
"NOT BAD!";
|
|
||||||
const msg = exercise.canProgress?
|
|
||||||
`You weight is automatically increased\nfor ${exercise.title} to ${exercise.weight}${exercise.unit}` :
|
|
||||||
"It looks like you struggled\non a few sets, your weight will\nstay the same";
|
|
||||||
const action = "Move straight on to the next exercise";
|
|
||||||
|
|
||||||
clearScreen();
|
|
||||||
g.setColor(WHITE);
|
|
||||||
g.setFont("Vector", 20);
|
|
||||||
g.drawString(title, centerStringX(title), 10);
|
|
||||||
g.setFont("Vector", 10);
|
|
||||||
g.drawString(msg, centerStringX(msg), 180);
|
|
||||||
g.drawString(action, centerStringX(action), 210);
|
|
||||||
drawMenu({showBTN2: true});
|
drawMenu({showBTN2: true});
|
||||||
|
|
||||||
clearWatch();
|
g.setFontAlign(0, -1);
|
||||||
setWatch(() => {
|
g.setColor(WHITE);
|
||||||
init(program);
|
g.setFont("6x8", 2);
|
||||||
}, BTN2, {repeat: false});
|
g.drawString(title1, W / 2, 10);
|
||||||
|
g.drawString(title2, W / 2, 30);
|
||||||
|
g.setFont("6x8", 1);
|
||||||
|
g.drawString(msg, (W / 2) + 3, 70);
|
||||||
|
g.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawSetComp() {
|
||||||
|
const title = "Good work";
|
||||||
|
const msg = "No need to rest\nmove straight on\nto the next\nexercise.Your\nweight has been\nincreased for\nnext time!";
|
||||||
|
|
||||||
|
g.clear();
|
||||||
|
drawMenu({showBTN2: true});
|
||||||
|
|
||||||
|
g.setFontAlign(0, -1);
|
||||||
|
g.setColor(WHITE);
|
||||||
|
g.setFont("6x8", 2);
|
||||||
|
g.drawString(title, W / 2, 10);
|
||||||
|
g.setFont("6x8", 1);
|
||||||
|
g.drawString(msg, (W / 2) - 2, 45);
|
||||||
|
|
||||||
|
g.flip();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
function drawRestTimer(program) {
|
function drawRestTimer(program) {
|
||||||
const exercise = program.currentExercise();
|
const exercise = program.currentExercise();
|
||||||
const motivation = "Take a breather..";
|
const motivation = "Take a breather..";
|
||||||
clearScreen();
|
|
||||||
drawMenu({showBTN2: true});
|
|
||||||
|
|
||||||
g.setColor(PINK);
|
|
||||||
g.fillCircle(W / 2, H / 2, 50);
|
|
||||||
g.setColor(WHITE);
|
|
||||||
g.setFont("Vector", 15);
|
|
||||||
g.drawString(motivation, centerStringX(motivation), 25);
|
|
||||||
g.setFont("Vector", 40);
|
|
||||||
g.drawString(exercise.restPeriod, centerStringX(exercise.restPeriod), (H - 45) / 2);
|
|
||||||
exercise.decRestPeriod();
|
|
||||||
|
|
||||||
if (exercise.restPeriod <= 0) {
|
if (exercise.restPeriod <= 0) {
|
||||||
exercise.resetRestTimer();
|
exercise.resetRestTimer();
|
||||||
redraw(program);
|
program.next();
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g.clear();
|
||||||
|
drawMenu({showBTN2: true});
|
||||||
|
g.setFontAlign(0, -1);
|
||||||
|
g.setColor(PINK);
|
||||||
|
g.fillRect(15, 42, W - 15, 80);
|
||||||
|
g.setColor(WHITE);
|
||||||
|
g.setFont("6x8", 1);
|
||||||
|
g.drawString("Have a short\nrest period.", W / 2, 10);
|
||||||
|
g.setFont("6x8", 5);
|
||||||
|
g.drawString(exercise.restPeriod, (W / 2) + 2, (H / 2) - 19);
|
||||||
|
g.flip();
|
||||||
|
|
||||||
|
exercise.decRestPeriod();
|
||||||
}
|
}
|
||||||
|
|
||||||
function redraw(program) {
|
function redraw(program) {
|
||||||
const exercise = program.currentExercise();
|
const exercise = program.currentExercise();
|
||||||
|
g.clear();
|
||||||
clearScreen();
|
|
||||||
|
|
||||||
if (program.isCompleted()) {
|
if (program.isCompleted()) {
|
||||||
drawProgramCompleted(program);
|
saveProg(program);
|
||||||
|
drawProgDone(program);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exercise.isRestTimerRunning()) {
|
if (exercise.isRestTimerRunning()) {
|
||||||
if (exercise.isLastSet()) {
|
if (exercise.isLastSet()) {
|
||||||
drawStartNextExercise(program);
|
drawSetComp(program);
|
||||||
} else {
|
} else {
|
||||||
drawRestTimer(program);
|
drawRestTimer(program);
|
||||||
}
|
}
|
||||||
|
|
@ -179,33 +137,126 @@ function redraw(program) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
drawSetProgress(exercise);
|
drawSet(exercise);
|
||||||
}
|
}
|
||||||
|
|
||||||
function init(program) {
|
function drawProgMenu(programs, selProgIdx) {
|
||||||
clearWatch();
|
g.clear();
|
||||||
program.next();
|
g.setFontAlign(0, -1);
|
||||||
|
g.setColor(WHITE);
|
||||||
|
g.setFont("6x8", 2);
|
||||||
|
g.drawString("BuffGym", W / 2, 10);
|
||||||
|
|
||||||
|
g.setFont("6x8", 1);
|
||||||
|
g.setFontAlign(-1, -1);
|
||||||
|
let selectedProgram = programs[selProgIdx].title;
|
||||||
|
let yPos = 50;
|
||||||
|
programs.forEach(program => {
|
||||||
|
g.setColor("#f05a56");
|
||||||
|
g.fillRect(0, yPos, W, yPos + 11);
|
||||||
|
g.setColor("#ffffff");
|
||||||
|
if (selectedProgram === program.title) {
|
||||||
|
g.drawRect(0, yPos, W - 1, yPos + 11);
|
||||||
}
|
}
|
||||||
|
g.drawString(program.title, 10, yPos + 2);
|
||||||
// Setup training program. This should come from file
|
yPos += 15;
|
||||||
|
|
||||||
// Squats
|
|
||||||
function buildPrograms() {
|
|
||||||
const programsJSON = require("Storage").readJSON("buffgym-programs.json", 1);
|
|
||||||
|
|
||||||
if (!programsJSON) throw "No programs JSON found";
|
|
||||||
|
|
||||||
const programs = [];
|
|
||||||
|
|
||||||
programsJSON.forEach(programJSON => {
|
|
||||||
const program = new Program({
|
|
||||||
title: programJSON.title,
|
|
||||||
});
|
});
|
||||||
const exercises = programJSON.exercises.map(exerciseJSON => {
|
g.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupMenu() {
|
||||||
|
clearWatch();
|
||||||
|
const progs = getProgIndex();
|
||||||
|
let selProgIdx = 0;
|
||||||
|
drawProgMenu(progs, selProgIdx);
|
||||||
|
|
||||||
|
setWatch(()=>{
|
||||||
|
selProgIdx--;
|
||||||
|
if (selProgIdx< 0) selProgIdx = 0;
|
||||||
|
drawProgMenu(progs, selProgIdx);
|
||||||
|
}, BTN1, {repeat: true});
|
||||||
|
|
||||||
|
setWatch(()=>{
|
||||||
|
const prog = buildProg(progs[selProgIdx].file);
|
||||||
|
prog.next();
|
||||||
|
}, BTN2, {repeat: false});
|
||||||
|
|
||||||
|
setWatch(()=>{
|
||||||
|
selProgIdx++;
|
||||||
|
if (selProgIdx > progs.length - 1) selProgIdx = progs.length - 1;
|
||||||
|
drawProgMenu(progs, selProgIdx);
|
||||||
|
}, BTN3, {repeat: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawSplash() {
|
||||||
|
g.reset();
|
||||||
|
g.setBgColor(RED);
|
||||||
|
g.clear();
|
||||||
|
g.setColor(WHITE);
|
||||||
|
g.setFontAlign(0,-1);
|
||||||
|
g.setFont("6x8", 2);
|
||||||
|
g.drawString("BuffGym", W / 2, 10);
|
||||||
|
g.setFont("6x8", 1);
|
||||||
|
g.drawString("5x5", W / 2, 42);
|
||||||
|
g.drawString("training app", W / 2, 55);
|
||||||
|
g.drawRect(19, 38, 100, 99);
|
||||||
|
const img = require("heatshrink").decompress(atob("lkdxH+AB/I5ASQACwpB5vNFkwpBAIfNFdZZkFYwskFZAsiFZBZiVYawEFf6ETFUwsIFUYmB54ADAwIskFYoRKBoIroB4grV58kkgCDFRotWFZwqHFiwYMFZIsTC5wLDFjGlCoWlkgJDRQIABCRAsLCwodCFAIABCwIOCFQYABr4RCCQIrMC4gqEAAwpFFZosFC5ArHFQ4rFNYQrGEgosMBxIrFLQwrLAB4sFSw4rFFjYrQFi4rNbASeEFjIoJFQYsGMAgAPEQgAIGwosCRoorbA="));
|
||||||
|
g.drawImage(img, 40, 70);
|
||||||
|
g.flip();
|
||||||
|
|
||||||
|
let flasher = false;
|
||||||
|
let bgCol, txtCol;
|
||||||
|
const i = setInterval(() => {
|
||||||
|
if (flasher) {
|
||||||
|
bgCol = WHITE;
|
||||||
|
txtCol = RED;
|
||||||
|
} else {
|
||||||
|
bgCol = RED;
|
||||||
|
txtCol = WHITE;
|
||||||
|
}
|
||||||
|
flasher = !flasher;
|
||||||
|
g.setColor(bgCol);
|
||||||
|
g.fillRect(0, 108, W, 120);
|
||||||
|
g.setColor(txtCol);
|
||||||
|
g.drawString("Press btn to begin", W / 2, 110);
|
||||||
|
g.flip();
|
||||||
|
}, 250);
|
||||||
|
|
||||||
|
setWatch(()=>{
|
||||||
|
clearInterval(i);
|
||||||
|
setupMenu();
|
||||||
|
}, BTN1, {repeat: false});
|
||||||
|
|
||||||
|
setWatch(()=>{
|
||||||
|
clearInterval(i);
|
||||||
|
setupMenu();
|
||||||
|
}, BTN2, {repeat: false});
|
||||||
|
|
||||||
|
setWatch(()=>{
|
||||||
|
clearInterval(i);
|
||||||
|
setupMenu();
|
||||||
|
}, BTN3, {repeat: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProgIndex() {
|
||||||
|
const progIdx = require("Storage").readJSON("buffgym-program-index.json");
|
||||||
|
return progIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildProg(fName) {
|
||||||
|
const Set = require("buffgym-set.js");
|
||||||
|
const Exercise = require("buffgym-exercise.js");
|
||||||
|
const Program = require("buffgym-program.js");
|
||||||
|
const progJSON = require("Storage").readJSON(fName);
|
||||||
|
const prog = new Program({
|
||||||
|
title: progJSON.title,
|
||||||
|
});
|
||||||
|
const exercises = progJSON.exercises.map(exerciseJSON => {
|
||||||
const exercise = new Exercise({
|
const exercise = new Exercise({
|
||||||
title: exerciseJSON.title,
|
title: exerciseJSON.title,
|
||||||
weight: exerciseJSON.weight,
|
weight: exerciseJSON.weight,
|
||||||
unit: exerciseJSON.unit,
|
unit: exerciseJSON.unit,
|
||||||
|
restPeriod: exerciseJSON.restPeriod,
|
||||||
});
|
});
|
||||||
exerciseJSON.sets.forEach(setJSON => {
|
exerciseJSON.sets.forEach(setJSON => {
|
||||||
exercise.addSet(new Set(setJSON));
|
exercise.addSet(new Set(setJSON));
|
||||||
|
|
@ -213,14 +264,14 @@ function buildPrograms() {
|
||||||
|
|
||||||
return exercise;
|
return exercise;
|
||||||
});
|
});
|
||||||
program.addExercises(exercises);
|
prog.addExercises(exercises);
|
||||||
programs.push(program);
|
|
||||||
});
|
|
||||||
|
|
||||||
return programs;
|
return prog;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For this spike, just run the first program, what will
|
function saveProg(program) {
|
||||||
// really happen is the user picks a program to do from
|
const fName = getProgIndex().find(prog => prog.title === program.title).file;
|
||||||
// some menu on a start page.
|
require("Storage").writeJSON(fName, program.toJSON());
|
||||||
init(buildPrograms()[0]);
|
}
|
||||||
|
|
||||||
|
drawSplash();
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 7.4 KiB |
Loading…
Reference in New Issue