Last active
November 3, 2023 18:57
-
-
Save DanielStefanK/487175b6f65ede401e37ee4848970176 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Can be obtained here https://fitx-proxy.daniel-stefan.dev/ | |
let studioId = 1266927; | |
// Proxy for the utilization api | |
let proxyUrl = "https://fitx-proxy.daniel-stefan.dev/api/utilization/" | |
let param = args.widgetParameter; | |
if (param != null && param.length > 0) { | |
studioId = param; | |
} | |
const contextSize = 282; | |
const fitXOrange = new Color("#ff8c00"); | |
const lightGrey = new Color("#bfbbbb"); | |
const widget = new ListWidget(); | |
let studioInfo; | |
try { | |
studioInfo = await fetchStoreInformation(); | |
await createWidget(); | |
} catch (e) { | |
console.log(e); | |
widget.addSpacer(4); | |
const logoImg = await getImage("logo.png"); | |
widget.setPadding(10, 10, 10, 10); | |
const titleFontSize = 14; | |
const detailFontSize = 14; | |
const logoStack = widget.addStack(); | |
logoStack.addSpacer(4); | |
const logoImageStack = logoStack.addStack(); | |
logoStack.layoutHorizontally(); | |
logoImageStack.backgroundColor = new Color("#ffffff", 1.0); | |
logoImageStack.cornerRadius = 8; | |
const wimg = logoImageStack.addImage(logoImg); | |
wimg.imageSize = new Size(40, 40); | |
wimg.rightAlignImage(); | |
widget.addSpacer(); | |
const row = widget.addStack(); | |
row.layoutVertically(); | |
const percentTitle = row.addText("Fehler beim Laden"); | |
} | |
// used for debugging if script runs inside the app | |
if (!config.runsInWidget) { | |
await widget.presentSmall(); | |
} | |
Script.setWidget(widget); | |
Script.complete(); | |
// build the content of the widget | |
async function createWidget() { | |
var d = new Date(); | |
const currentWeekDay = d.getDay(); | |
const currentHour = Math.abs(d.getHours() - 2) % 24; | |
widget.addSpacer(4); | |
const logoImg = await getImage("logo.png"); | |
widget.setPadding(10, 10, 10, 10); | |
const titleFontSize = 14; | |
const detailFontSize = 14; | |
const logoStack = widget.addStack(); | |
const name = logoStack.addText(studioInfo.name); | |
name.font = Font.regularSystemFont(titleFontSize); | |
name.minimumScaleFactor = 0.5; | |
logoStack.addSpacer(4); | |
const logoImageStack = logoStack.addStack(); | |
logoStack.layoutHorizontally(); | |
logoImageStack.backgroundColor = new Color("#ffffff", 1.0); | |
logoImageStack.cornerRadius = 8; | |
const wimg = logoImageStack.addImage(logoImg); | |
wimg.imageSize = new Size(40, 40); | |
wimg.rightAlignImage(); | |
widget.addSpacer(); | |
const row = widget.addStack(); | |
row.layoutVertically(); | |
const percentTitle = row.addText("Aktuelle Auslastung: "); | |
percentTitle.font = Font.regularSystemFont(detailFontSize); | |
const percentage = row.addText(studioInfo.workload + "%"); | |
percentage.font = Font.regularSystemFont(detailFontSize); | |
let drawContext = new DrawContext(); | |
drawContext.size = new Size(contextSize, contextSize); | |
drawContext.opaque = false; | |
drawContext.setTextAlignedCenter(); | |
const data = studioInfo.items.map((i) => i.percentage); | |
let min, max, diff; | |
for (let i = 0; i <= 24; i++) { | |
let temp = data[i]; | |
min = temp < min || min == undefined ? temp : min; | |
max = temp > max || max == undefined ? temp : max; | |
} | |
diff = max - min; | |
let spaceBetweenDays = 10; | |
for (let i = 0; i < 24; i++) { | |
let current = data[i]; | |
let nextHour = data[i + 1]; | |
let delta = diff > 0 ? (current - min) / diff : 0.5; | |
let nextDelta = diff > 0 ? (nextHour - min) / diff : 0.5; | |
drawPoint( | |
spaceBetweenDays * i + 25, | |
175 - 50 * delta, | |
drawContext, | |
fitXOrange, | |
currentHour === i - 2 ? 15 : 3 | |
); | |
if (i % 3 == 0) { | |
drawText( | |
data[i], | |
10, | |
spaceBetweenDays * i + (data[i] > 9 ? 16 : 22), | |
175 - 50 * delta - 25, | |
drawContext, | |
lightGrey | |
); | |
drawText( | |
i, | |
10, | |
spaceBetweenDays * i + (data[i] > 9 ? 16 : 22), | |
180, | |
drawContext, | |
lightGrey | |
); | |
} | |
drawLine( | |
spaceBetweenDays * i + 25, | |
175 - 50 * delta, | |
spaceBetweenDays * (i + 1) + 25, | |
175 - 50 * nextDelta, | |
drawContext, | |
4, | |
fitXOrange | |
); | |
} | |
widget.backgroundImage = drawContext.getImage(); | |
} | |
// fetches information of the configured store, e.g. opening hours, address etc. | |
async function fetchStoreInformation() { | |
let url = proxyUrl + studioId; | |
let req = new Request(url); | |
let apiResult = await req.loadString(); | |
if (req.response.statusCode == 404) { | |
// TODO: implement error handling | |
} else if (req.response.statusCode == 200) { | |
apiResult = JSON.parse(apiResult); | |
widget.url = "https://mein.fitx.de/studio/" + apiResult.uuid; | |
} | |
return apiResult; | |
} | |
// get images from local filestore or download them once | |
async function getImage(image) { | |
let fm = FileManager.local(); | |
let dir = fm.documentsDirectory(); | |
let path = fm.joinPath(dir, image); | |
if (fm.fileExists(path)) { | |
return fm.readImage(path); | |
} else { | |
// download once | |
let imageUrl; | |
switch (image) { | |
case "logo.png": | |
imageUrl = "https://i.imgur.com/2T54ySh.png"; | |
break; | |
default: | |
console.log(`Sorry, couldn't find ${image}.`); | |
} | |
let iconImage = await loadImage(imageUrl); | |
fm.writeImage(path, iconImage); | |
return iconImage; | |
} | |
} | |
// helper function to download an image from a given url | |
async function loadImage(imgUrl) { | |
const req = new Request(imgUrl); | |
return await req.loadImage(); | |
} | |
function drawLine(x1, y1, x2, y2, ctx, width, color) { | |
const path = new Path(); | |
path.move(new Point(x1, y1)); | |
path.addLine(new Point(x2, y2)); | |
ctx.addPath(path); | |
ctx.setStrokeColor(color); | |
ctx.setLineWidth(width); | |
ctx.strokePath(); | |
} | |
function drawPoint(x, y, ctx, color, width = 2) { | |
const rec = new Rect(x - width / 2, y - width / 2, width, width); | |
ctx.setStrokeColor(color); | |
ctx.setFillColor(color); | |
ctx.setLineWidth(2); | |
ctx.strokeEllipse(rec); | |
ctx.fillEllipse(rec); | |
} | |
function drawText(text, fontSize, x, y, ctx, color = Color.black()) { | |
ctx.setFont(Font.boldSystemFont(fontSize)); | |
ctx.setTextColor(color); | |
ctx.drawText(new String(text).toString(), new Point(x, y)); | |
} |
Seeehr geiles script! Habe ich zwar nicht nach gesucht aber installiert. Danke dir <3
finds geil. location service an sich wäre noch nice. ist mit scriptable ja problemlos möglich. Also immer das FitX anzeigen, was in der nähe ist. es müssten nur die locations in der proxy gespeichert werden..
Habe aktuell das Problem das der Graph nicht mehr gerendert wird. Nur ich?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you very much for this, I appreciate this as I am not super knowledgeable with regard to GitHub and Scriptable in general.