From 3a43c25b13df3c961d6e0a575414712ad467b4ac Mon Sep 17 00:00:00 2001 From: Stian Aune Date: Wed, 6 Nov 2019 22:15:17 +0100 Subject: [PATCH] Maybe working now???. --- background.js | 9 - contentScript.js | 471 +++++++++++++++++++++++++++++++++++++++++++---- manifest.json | 3 +- popup.js | 15 +- 4 files changed, 446 insertions(+), 52 deletions(-) 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 += `${minutes}  ${calories}`; + }); + + if (lines.length > 0) { + this.writeBottomRight(` + + ${lines} +
+ `); + } else { + this.writeBottomRight(null); + } + } + + writeTopLeft(message) { + this.mTopLeft.innerHTML = message; + + if (message === null || !this.display) { + this.mTopLeft.style.display = "none"; + } else { + this.mTopLeft.style.display = "block"; + } + } + + writeCenter(message) { + this.mCenter.innerHTML = message; + + if (message === null || !this.display) { + this.mCenter.style.display = "none"; + } else { + this.mCenter.style.display = "block"; + } + } + + writeBottomRight(message) { + this.mBottomRight.innerHTML = message; + + if (message === null || !this.display) { + this.mBottomRight.style.display = "none"; + } else { + this.mBottomRight.style.display = "block"; + } + } + + calorieDiff() { + const {minutes, seconds, calories} = this.workoutStatus; + + const expected = this.expectedCalories(minutes, seconds); + return calories - expected; + } + + expectedCalories(minutes, seconds) { + const {warmupMin, warmupCpm, cpm} = this.program; + + let preWarmup = 0; + if (warmupMin > 0) { + // Pre-warmup + const warmedUpMinutes = Math.min(minutes, warmupMin); + const warmedUpSeconds = warmedUpMinutes >= warmupMin ? 0 : seconds; + preWarmup = Math.round((warmupCpm * (warmedUpMinutes + (warmedUpSeconds / 60)))); + } + + // Post-warmup + const trainedMinutes = minutes - warmupMin; + const postWarmup = Math.round((cpm * (trainedMinutes + (seconds / 60)))); + + // Sum + return Math.round(preWarmup + postWarmup); + } + + getState() { + return (this.workout || this.setup || {state: "down"}).state; + } + }; } -let mCalorieCount = document.createElement("div"); -mCalorieCount.id = "ykonsole-calorie-count"; -applyDefaultStyle(mCalorieCount); -mCalorieCount.style.left = 0; -mCalorieCount.style.top = 0; -mCalorieCount.innerHTML = ` -25:23 -
-883 kal -`; -document.body.append(mCalorieCount); - -let mResults = document.createElement("div"); -mResults.id = "ykonsole-result"; -applyDefaultStyle(mResults); -mResults.style.right = 0; -mResults.style.bottom = 0; -mResults.style.textAlign = "right"; -mResults.innerHTML = ` -5 161
-10 332
-15 490
-20 712
-25 875
-`; -document.body.append(mResults); +function pad(number) { + return number >= 10 ? `${number}` : `0${number}`; +} + +function url(path, prefix = "http") { + return `${prefix}://127.0.0.1:9999/api${path}`; +} + +function get(path) { + return fetch(url(path), { + method: "GET", + }).then(r => r.json()); +} + +function post(path, data = {}) { + return fetch(url(path), { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data) + }).then(r => r.json()); +} + + +const overlay = + new Overlay( + document.body, + document.createElement("div"), + document.createElement("div"), + document.createElement("div")); + +overlay.show(); +overlay.setUp(); chrome.storage.sync.get('color', ({color}) => { }); diff --git a/manifest.json b/manifest.json index 936f99c..72edc0b 100644 --- a/manifest.json +++ b/manifest.json @@ -19,6 +19,7 @@ "activeTab", "declarativeContent", "https://www.youtube.com/", - "https://indigo.stian-aune.com/" + "https://indigo.stian-aune.com/", + "http://127.0.0.1:9999/" ] } \ No newline at end of file diff --git a/popup.js b/popup.js index c541879..382a209 100644 --- a/popup.js +++ b/popup.js @@ -4,13 +4,10 @@ chrome.storage.sync.get('color', function(data) { changeColor.setAttribute('value', data.color); }); -changeColor.onclick = function(element) { - // TODO: Add settings to STORAGE +chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { + console.log("test"); - let color = element.target.value; - chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { - chrome.tabs.executeScript( - tabs[0].id, - {file: 'contentScript.js'}); - }); -}; \ No newline at end of file + chrome.tabs.executeScript( + tabs[0].id, + {file: 'contentScript.js'}); +});