diff --git a/background.js b/background.js
index c6839d4..a85f643 100644
--- a/background.js
+++ b/background.js
@@ -1,8 +1,4 @@
chrome.runtime.onInstalled.addListener(function () {
- chrome.storage.sync.set({color: '#3aa757'}, function () {
- console.log("The color is green.");
- });
-
chrome.declarativeContent.onPageChanged.removeRules(undefined, function () {
chrome.declarativeContent.onPageChanged.addRules([{
conditions: [new chrome.declarativeContent.PageStateMatcher({
@@ -12,9 +8,4 @@ chrome.runtime.onInstalled.addListener(function () {
actions: [new chrome.declarativeContent.ShowPageAction()]
}]);
});
-
- let i = 0;
- setInterval(() => {
- console.log(`${++i}s since start`)
- }, 1000);
});
\ No newline at end of file
diff --git a/contentScript.js b/contentScript.js
index a6699c8..ee1dbfa 100644
--- a/contentScript.js
+++ b/contentScript.js
@@ -1,38 +1,443 @@
-function applyDefaultStyle(element) {
- element.style.position = "fixed";
- element.style.zIndex = 99999999;
- element.style.color = "#FFF";
- element.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
- element.style.padding = "0.25em 0.5ch";
- element.style.fontSize = "3vmax";
+if (typeof Overlay === "undefined") {
+ var Overlay = class {
+ workout = null;
+ workoutState = null;
+ workoutStatus = null;
+ display = false;
+ milestones = [];
+ program = null;
+ currentCpm = null;
+ bikes = [];
+ programs = [];
+ workouts = [];
+ bike = null;
+ setup = null;
+
+ colors = {
+ "-2": "#F44",
+ "-1": "#FAA",
+ "0": "#FFF",
+ "1": "#AFA",
+ "2": "#4F4",
+ };
+
+ /**
+ * @param {HTMLElement} mBody
+ * @param {HTMLElement} mTopLeft
+ * @param {HTMLElement} mCenter
+ * @param {HTMLElement} mBottomRight
+ */
+ constructor(mBody, mTopLeft, mCenter, mBottomRight) {
+ this.mBody = mBody;
+ this.mTopLeft = mTopLeft;
+ this.mCenter = mCenter;
+ this.mBottomRight = mBottomRight;
+
+ this.initStyle();
+ this.hide();
+ }
+
+ initStyle() {
+ this.applyDefaultStyle(this.mTopLeft);
+ this.applyDefaultStyle(this.mCenter);
+ this.applyDefaultStyle(this.mBottomRight);
+
+ this.mTopLeft.id = "overlay-mTopLeft";
+ this.mTopLeft.style.left = 0;
+ this.mTopLeft.style.top = "25%";
+
+ this.mCenter.id = "overlay-mCenter";
+ this.mCenter.style.left = "50%";
+ this.mCenter.style.top = "50%";
+ this.mCenter.style.transform = "translate(-50%, -50%)";
+
+ this.mBottomRight.id = "overlay-mBottomRight";
+ this.mBottomRight.style.right = 0;
+ this.mBottomRight.style.bottom = 0;
+ this.mBottomRight.style.fontSize = "2vmax";
+ }
+
+ applyDefaultStyle(element) {
+ this.mBody.append(element);
+
+ element.style.position = "fixed";
+ element.style.zIndex = 99999999;
+ element.style.color = "#FFF";
+ element.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
+ element.style.padding = "0.25em 0.5ch";
+ element.style.fontSize = "3vmax";
+ element.style.lineHeight = "1.33em";
+ }
+
+ hide() {
+ this.mTopLeft.style.display = "none";
+ this.mCenter.style.display = "none";
+ this.mBottomRight.style.display = "none";
+
+ this.display = false;
+ }
+
+ show() {
+ this.mTopLeft.style.display = "block";
+ this.mCenter.style.display = "block";
+ this.mBottomRight.style.display = "block";
+
+ this.display = true;
+ }
+
+ async setUp() {
+ this.writeCenter("Loading...");
+
+ this.bikes = await get("/bike");
+ this.programs = await get("/program");
+ this.workouts = await get("/workout?active=true");
+
+ this.writeCenter(null);
+ this.updateCenterState();
+ }
+
+ async updateCenterState() {
+ const state = this.getState();
+
+ switch (state) {
+ case "down":
+ this.writeCenter(`
+ (1) Ny økt
+ (2) Fortsett forrige økt
+ `);
+ break;
+ case "bike":
+ // TODO: Add this??
+ if (this.bikes.length === 1) {
+ this.setup = {state: "program", bike: this.bikes[0]};
+ this.updateCenterState();
+ } else {
+ this.writeCenter("Sykkelvalg ikke støttet");
+ }
+ break;
+ case "program":
+ const options = this.programs.map((p, i) => `(${i + 1}) ${p.name}`)
+
+ this.writeCenter("Velg programm:
" + options.join("
"));
+ break;
+ case "disconnected":
+ this.writeCenter("Kobler til...");
+ break;
+ case "connected":
+ this.writeCenter(`
+ (Enter) Start/Pause
+ (Esc) Stopp
+ `);
+ break;
+ case "started":
+ const calorieDiff = this.calorieDiff();
+ if (calorieDiff < 0) {
+ this.writeCenter(`
+ ${calorieDiff} kcal!
+ `);
+ } else {
+ this.writeCenter(null);
+ }
+ break;
+ default:
+ this.writeCenter(`Ugyldig tilstand: ${state}`);
+ }
+
+ this.updateKeyBindings();
+ }
+
+ updateKeyBindings() {
+ const dis = this;
+
+ this.mBody.onkeyup = function (event) {
+ const state = dis.getState();
+
+ if (state === "program") {
+ const i = parseInt(event.key, 10);
+ if (!isNaN(i) && typeof dis.programs[i - 1] !== "undefined") {
+ dis.bike = {...dis.setup.bike};
+ dis.startWorkout(dis.bike, dis.programs[i - 1]);
+ }
+ }
+
+ let handled = false;
+ switch (event.key) {
+ case "1":
+ if (state === "down") {
+ dis.setup = {state: "bike"};
+ handled = true;
+ }
+ break;
+ case "2":
+ if (state === "down") {
+ const last = dis.workouts[dis.workouts.length - 1];
+ console.log(last);
+ if (last !== undefined) {
+ dis.resumeWorkout(last);
+ }
+
+ handled = true;
+ }
+ break;
+ case "Enter":
+ if (state === "connected") {
+ dis.start();
+ handled = true;
+ } else if (state === "started") {
+ dis.pause();
+ handled = true;
+ }
+ break;
+ case "Escape":
+ if (state === "connected") {
+ dis.stop();
+ handled = true;
+ }
+ break;
+ }
+
+ if (handled) {
+ dis.updateCenterState();
+ event.preventDefault();
+ }
+ }
+ }
+
+ async startWorkout(bike, program) {
+ this.bike = bike;
+ this.program = program;
+
+ const bikeId = bike.id;
+ const programId = program.id;
+
+ this.workout = await post("/workout", {bikeId, programId});
+ this.updateCenterState();
+
+ this.workout = await post(`/workout/${this.workout.id}/connect`);
+ this.updateCenterState();
+
+ this.setup = null;
+ this.webSocket();
+ }
+
+ async resumeWorkout(workout) {
+ this.bike = workout.bike;
+ this.program = workout.program;
+ this.workout = workout;
+
+ this.setup = null;
+ this.webSocket();
+ }
+
+ async start() {
+ this.workout = await post(`/workout/${this.workout.id}/start`);
+ this.updateCenterState();
+ }
+
+ async pause() {
+ this.workout = await post(`/workout/${this.workout.id}/pause`);
+ this.updateCenterState();
+ }
+
+ async stop() {
+ await post(`/workout/${this.workout.id}/stop`);
+
+ this.workout = null;
+ this.workouts = await post(`/workout?active=true`);
+ this.updateCenterState();
+ }
+
+ async webSocket() {
+ let dis = this;
+
+ this.socket = new WebSocket(url(`/workout/${this.workout.id}/subscribe`, "ws"));
+
+ this.socket.onmessage = function ({data, timeStamp}) {
+ let body = JSON.parse(data);
+
+ if (typeof body.workout !== "undefined") {
+ dis.workout = {...body.workout, ...dis.workout}
+ }
+
+ if (typeof body.workoutStatusBackfill !== "undefined") {
+ body.workoutStatusBackfill.forEach(wsbf => dis.updateWorkoutStatus(wsbf));
+ }
+
+ if (typeof body.workoutStatus !== "undefined") {
+ dis.updateWorkoutStatus(body.workoutStatus)
+ }
+ }
+ }
+
+ updateWorkoutStatus(newState = null) {
+ if (newState !== null) {
+ this.workoutStatus = newState;
+ }
+
+ if (this.workoutStatus === null) {
+ this.writeTopLeft("");
+ return;
+ }
+
+ const {minutes, seconds, calories, distance, rpm} = this.workoutStatus;
+
+ const cpmState = this.checkCpm();
+ const color = this.colors[cpmState];
+
+ this.writeTopLeft(`
+ ${pad(minutes)} : ${pad(seconds)}
+ ${calories} kcal
+ ${distance.toFixed(1)} km
+ ${rpm} rpm
+ KPM: ${this.currentCpm.toFixed(1)}
+ `);
+
+ if (seconds === 0 && minutes > 0) {
+ this.updateMilestones(minutes, calories);
+ }
+
+ this.updateCenterState();
+ }
+
+ checkCpm() {
+ const {calories, minutes, seconds} = this.workoutStatus;
+
+ this.currentCpm = calories * 60 / ((minutes * 60) + seconds);
+ if (this.currentCpm === Infinity) {
+ this.currentCpm = 0;
+ }
+
+ const program = this.program;
+ if (program === null || this.currentCpm === 0) {
+ return 0;
+ }
+
+ if (this.calorieDiff() < 0) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+
+ updateMilestones(minutes, calories) {
+ this.milestones.push({minutes, calories});
+
+ if (minutes % 5 === 0) {
+ this.milestones = this.milestones.filter(m => m.minutes % 5 === 0)
+ }
+
+ let lines = "";
+ this.milestones.sort((i, j) => j.minutes - i.minutes).forEach(({minutes, calories}) => {
+ lines += `