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)); }