Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save rafaelmaeuer/9e7258522f56bde2948f836067e03929 to your computer and use it in GitHub Desktop.
Save rafaelmaeuer/9e7258522f56bde2948f836067e03929 to your computer and use it in GitHub Desktop.
Shows the available amount of Covid Tests in your local drug store and online
// https://gist.github.com/marco79cgn/685804b731e2c8e466501e4b88341286
// https://gist.github.com/tofi86/5e95708cff0b1746b57806a78bdb2eda
let country = "de"; // replace with 'at' for shops in Austria
let storeId = 251;
let param = args.widgetParameter;
if (param != null && param.length > 0) {
if (param.indexOf(";") > 0) {
const paramSplit = param.split(";");
storeId = paramSplit[0];
country = paramSplit[1].toLowerCase();
} else {
storeId = param;
}
}
const widget = new ListWidget();
const storeInfo = await fetchStoreInformation();
const storeCapacity = await fetchAmountOfPaper();
const isOnlineAvailable = await isAvailableOnline();
await createWidget();
// 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() {
// Add background color
widget.backgroundColor = new Color("ffffff");
widget.backgroundColor = Color.dynamic(widget.backgroundColor, new Color("1c1c1c"));
const logoImg = await getImage("dm-logo.png");
widget.setPadding(6, 10, 8, 10);
const titleFontSize = 12;
const detailFontSize = 36;
const logoStack = widget.addStack();
logoStack.addSpacer();
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(32, 32);
wimg.rightAlignImage();
widget.addSpacer(6);
const paperText = widget.addText("CORONA-SELBSTTEST");
paperText.font = Font.semiboldRoundedSystemFont(11);
widget.addSpacer(6);
const icon = await getImage("covidtest.png");
let row = widget.addStack();
row.layoutHorizontally();
row.addSpacer(2);
const iconImg = row.addImage(icon);
iconImg.imageSize = new Size(32, 32);
row.addSpacer(10);
let column = row.addStack();
column.layoutVertically();
const storeText = column.addText("STORE");
storeText.textOpacity = 0.8;
storeText.font = Font.mediumRoundedSystemFont(10);
const packageCount = column.addText(storeCapacity.toString());
if (storeCapacity > 999) {
packageCount.font = Font.mediumRoundedSystemFont(16);
} else {
packageCount.font = Font.mediumRoundedSystemFont(19);
}
// packageCount.minimumScaleFactor = 0.8
if (storeCapacity < 5) {
packageCount.textColor = new Color("#E50000");
} else {
packageCount.textColor = new Color("#00CD66");
}
row.addSpacer(10);
let column2 = row.addStack();
column2.layoutVertically();
const onlineText = column2.addText("ONLINE");
onlineText.textOpacity = 0.8;
onlineText.font = Font.mediumRoundedSystemFont(10);
column2.addSpacer(3);
let onlineAvailableIcon;
if (isOnlineAvailable) {
onlineAvailableIcon = "✅";
} else {
onlineAvailableIcon = "⛔️";
}
const onlineAvailableText = column2.addText(onlineAvailableIcon);
if (storeCapacity > 999) {
onlineAvailableText.font = Font.regularSystemFont(11);
} else {
onlineAvailableText.font = Font.regularSystemFont(13);
}
widget.addSpacer(6);
const row2 = widget.addStack();
row2.layoutVertically();
const street = row2.addText(storeInfo.address.street);
street.font = Font.regularSystemFont(11);
street.minimumScaleFactor = 0.8;
street.lineLimit = 2;
const zipCity = row2.addText(
storeInfo.address.zip + " " + storeInfo.address.city
);
zipCity.font = Font.regularSystemFont(11);
zipCity.minimumScaleFactor = 0.8;
zipCity.lineLimit = 1;
let currentTime = new Date().toLocaleTimeString("de-DE", {
hour: "numeric",
minute: "numeric",
});
let currentDay = new Date().getDay();
let isOpen;
if (currentDay > 0) {
const todaysOpeningHour =
storeInfo.openingHours[currentDay - 1].timeRanges[0].opening;
const todaysClosingHour =
storeInfo.openingHours[currentDay - 1].timeRanges[0].closing;
const range = [todaysOpeningHour, todaysClosingHour];
isOpen = isInRange(currentTime, range);
} else {
isOpen = false;
}
let shopStateText;
if (isOpen) {
shopStateText = row2.addText("GEÖFFNET");
shopStateText.textColor = new Color("#00CD66");
} else {
shopStateText = row2.addText("GESCHLOSSEN");
shopStateText.textColor = new Color("#E50000");
}
shopStateText.font = Font.semiboldSystemFont(10);
}
// fetches the amount of milk packages
async function fetchAmountOfPaper() {
let url;
let counter = 0;
if (country.toLowerCase() === "at") {
// Austria
const array = ["188896"];
for (var i = 0; i < array.length; i++) {
let currentItem = array[i];
url =
"https://products.dm.de/store-availability/AT/products/dans/" +
currentItem +
"/stocklevel?storeNumbers=" +
storeId;
let req = new Request(url);
let apiResult = await req.loadJSON();
if (req.response.statusCode == 200) {
if (apiResult.storeAvailability[0].stockLevel) {
counter += apiResult.storeAvailability[0].stockLevel;
}
}
}
} else {
// Germany
url =
"https://products.dm.de/store-availability/DE/availability?dans=796724,797046,798989,799454,800208,800021,796724,799462&storeNumbers=" +
storeId;
const req = new Request(url);
const apiResult = await req.loadJSON();
for (var i in apiResult.storeAvailabilities) {
if (apiResult.storeAvailabilities[i][0].stockLevel) {
counter += apiResult.storeAvailabilities[i][0].stockLevel;
}
}
}
return counter;
}
async function isAvailableOnline() {
let url;
if (country.toLowerCase() === "at") {
url =
"https://products.dm.de/product/at/search?productQuery=%3Arelevance%3Adan%3A188896";
} else {
url =
"https://products.dm.de/product/de/search?productQuery=%3Arelevance%3Adan%797046&purchasableOnly=false&hideFacets=false&hideSorts=false&pageSize=30";
}
let req = new Request(url);
let apiResult = await req.loadJSON();
if (req.response.statusCode == 200) {
for (var i = 0; i < apiResult.products.length; i++) {
if (apiResult.products[i].purchasable) {
return true;
}
}
}
return false;
}
// fetches information of the configured store, e.g. opening hours, address etc.
async function fetchStoreInformation() {
let url;
if (country.toLowerCase() === "at") {
url =
"https://store-data-service.services.dmtech.com/stores/item/at/" +
storeId;
widget.url =
"https://www.dm.at/keine-marke-coronavirus-antigen-schnelltest-fuer-zuhause-p2099999042083.html";
} else {
url =
"https://store-data-service.services.dmtech.com/stores/item/de/" +
storeId;
widget.url =
"https://www.dm.de/gesundheit/corona-schnell-antikoerpertest";
}
let req = new Request(url);
let apiResult = await req.loadJSON();
return apiResult;
}
// checks whether the store is currently open or closed
function isInRange(value, range) {
return value >= range[0] && value <= range[1];
}
// 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 "dm-logo.png":
imageUrl =
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/50/Dm_Logo.svg/300px-Dm_Logo.svg.png";
break;
case "covidtest.png":
imageUrl = "https://i.imgur.com/HFQe5io.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();
}
//
// make sure to copy everything!
//
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment