fitx-widget.js
November 22, 2022 ยท View on GitHub
//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)); }