-
-
Save icsAT/23e5a5290f5b56eed277241964fbb4b8 to your computer and use it in GitHub Desktop.
// Variables used by Scriptable. | |
// These must be at the very top of the file. Do not edit. | |
// icon-color: deep-brown; icon-glyph: magic; | |
// Crypto Coin Widget | |
// by icsAT (https://gist.github.com/icsAT) | |
// Version 0.81 from the 15th of Oktober 2021 | |
// Data from Coin Market Cap Crypto API. | |
// Get your own privat API Key to use with this widget | |
// const cmcApiKey = "enter Your own API Key here xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" | |
const cmcApiKey = "enter Your own API Key here xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" | |
// With the Basic Plan you have a maximum of 333 API-Calls a Day and 10.000 API-Calls a Month. | |
// That means about 1 Call every 5 minutes. | |
// But be aware , that the refresh of a widget is regulated by iOS (approx. every 7 minutes afaik). | |
// Also be aware, that more than one widget means more API-Calls. | |
const cmcRefresh = 20 | |
// The widget will dispay the actual price of the crypto currencies in the given reference value | |
// You may set what you want to see here in the script or in the widget parameters. | |
// The widget parameter has the format: | |
// referenceValue;crypto1,crypto2,crypto3,... f.e. EUR;BTC,ETH,ADA,SOL,DOT,DOGE,AVAX,LTC | |
// The widget parameter will overrule the values set here. | |
// Reference Value in wich the price is displayed f.e EUR, USD, BTC | |
var referenceValue = "EUR" | |
// Crypto Currencies to be displayed, seperated by "," f.e. BTC,ETH,ADA,SOL,DOT,DOGE,AVAX,LTC | |
// var cryptoCurrencies = "ADA,AVAX,BTC,DOGE,DOT,ETH,LTC" | |
var cryptoCurrencies = "ADA,AVAX,BTC,CHZ,DOGE,DOT,ETH,LINK,LTC,MIOTA,SOL,UNI,AMP,COMP,GRT,SXP,XLM" | |
// Maximum Number of Cryptocurrency Lines | |
// Depending on your device there are more or less lines possible | |
// small and medium | |
const maxLinesSM = 7 | |
// large and extraLarge | |
const maxLinesLX = 17 | |
// Widget Size to be displayed if running from Scriptable App | |
// Use 'small' (max. 8 values), 'medium' (max. 8 values), 'large' (max.21 values) or 'extraLarge' (iPad only, max.21 values) | |
config.widgetFamily = config.widgetFamily || 'large' | |
// Weitere Parameter | |
const COLOR_RED = new Color('#FF0000') | |
const COLOR_GREEN = new Color('#008000') | |
const COLOR_BLACK = new Color('#000000') | |
const COLOR_WHITE = new Color('#FFFFFF') | |
const COLOR_GREY90 = new Color('#E6E6E6') | |
const COLOR_GREY70 = new Color('#B3B3B3') | |
const COLOR_GREY50 = new Color('#808080') | |
const COLOR_GREY30 = new Color('#4D4D4D') | |
const COLOR_GREY10 = new Color('#1a1a1a') | |
// debugging (set to false or to true to disable or enable console logging) | |
const debug = false | |
// Script Name | |
const scriptName = Script.name().replace(".js","") | |
// running the script | |
let widget = await createWidget() | |
if (config.runsInWidget) { | |
Script.setWidget(widget) | |
} else { | |
switch (config.widgetFamily) { | |
case 'small': await widget.presentSmall(); break; | |
case 'medium': await widget.presentMedium(); break; | |
case 'large': await widget.presentLarge(); break; | |
case 'extraLarge': await widget.presentExtraLarge(); break; | |
} | |
} | |
Script.complete() | |
// create the widget | |
async function createWidget() { | |
if (debug) console.log("START async function crateWidget()") | |
if (args.widgetParameter) { | |
var parameters = args.widgetParameter.split(";") | |
referenceValue = parameters[0] | |
cryptoCurrencies = parameters[1] | |
} | |
referenceValue = referenceValue.trim() | |
referenceValue = referenceValue.replace(" ", "") | |
if (debug) console.log("referenceValue: " + referenceValue) | |
cryptoCurrencies = cryptoCurrencies.trim() | |
cryptoCurrencies = cryptoCurrencies.replace(" ", "") | |
if (debug) console.log("cryptoCurrencies: " + cryptoCurrencies) | |
numberCoins = 0 | |
var coins = cryptoCurrencies.split(",") | |
for (coin of coins) { | |
numberCoins++ | |
} | |
if (debug) console.log("numberCoins: " + numberCoins) | |
let listWidget = new ListWidget() | |
listWidget.backgroundColor = Color.clear() | |
listWidget.centerAlignContent | |
let darkMode = !(Color.dynamic(Color.white(),Color.black()).red) | |
if (debug) console.log("darkMode: " + darkMode) | |
const fm = FileManager.local() | |
let directoryPath = fm.joinPath(fm.documentsDirectory(), "Crypto") | |
if (debug) console.log("directoryPath: " + directoryPath) | |
const extension = scriptName + (darkMode ? "_dark" : "_light") + ".jpg" | |
if (debug) console.log("extension: " + extension) | |
const imagePath = fm.joinPath(directoryPath, extension) | |
if (debug) console.log("imagePath: " + imagePath) | |
if (!config.runsInWidget) { | |
changeBackground = !(await generatePrompt("Change Background?", "Would you like to change the background?",["Yes","No"])) | |
if (debug) console.log("setBackground: " + setBackground) | |
if (changeBackground) { | |
setBackground = !(await generatePrompt("New Background?", "Would you like to set a new image or erase the actual image?",["Set","Erase"])) | |
if (setBackground) { | |
if (!fm.fileExists(directoryPath) || !fm.isDirectory(directoryPath)) { | |
fm.createDirectory(directoryPath) | |
} | |
let newImage = await Photos.fromLibrary() | |
fm.writeImage(fm.joinPath(directoryPath, scriptName + "_light.jpg"), newImage) | |
let setBackgroundDark = !(await generatePrompt("Dark Background?", "Would you like to use a different image in dark mode?",["Yes","No"])) | |
if (debug) console.log("setBackgroundDark: " + setBackgroundDark) | |
if (setBackgroundDark) { | |
let newDarkImage = await Photos.fromLibrary() | |
fm.writeImage(fm.joinPath(directoryPath, scriptName + "_dark.jpg"), newImage) | |
} else { | |
fm.writeImage(fm.joinPath(directoryPath, scriptName + "_dark.jpg"), newImage) | |
} | |
} else { | |
if (fm.fileExists(fm.joinPath(directoryPath, scriptName + "_light.jpg"))) { | |
fm.remove(fm.joinPath(directoryPath, scriptName + "_light.jpg")) | |
} | |
if (fm.fileExists(fm.joinPath(directoryPath, scriptName + "_dark.jpg"))) { | |
fm.remove(fm.joinPath(directoryPath, scriptName + "_dark.jpg")) | |
} | |
} | |
} | |
} | |
if (fm.fileExists(imagePath)) { | |
if (fm.isFileStoredIniCloud(imagePath)) { | |
await fm.downloadFileFromiCloud(imagePath) | |
} | |
listWidget.backgroundImage = fm.readImage(imagePath) | |
if (debug) console.log("Background Image gesetzt.") | |
} | |
headLine = listWidget.addStack() | |
headLine.centerAlignContent | |
headLine.addSpacer() | |
headLineText = headLine.addText("Crypto Prices") | |
headLineText.font = Font.boldSystemFont(15) | |
headLineText.centerAlignText() | |
headLine.addSpacer() | |
stack = listWidget.addStack() | |
stack.layoutVertically() | |
stack.centerAlignContent | |
if ((numberCoins<maxLinesSM && (config.widgetFamily == 'small' || config.widgetFamily == 'medium')) || (numberCoins<maxLinesLX && (config.widgetFamily == 'large' || config.widgetFamily == 'extraLarge'))) { | |
stack.addSpacer(8) | |
} | |
lastUpdate = "1900-01-01T00:00:00.000Z" | |
if (debug) console.log("lastUpdate: "+ lastUpdate) | |
cmcUrlParameter = "?convert="+referenceValue+"&symbol="+cryptoCurrencies | |
if (debug) console.log("cmcUrlParameter: "+ cmcUrlParameter) | |
cryptoData = await getCryptoData(fm, cmcUrlParameter) | |
if (cryptoData && cryptoData.status.error_code == 0) { | |
if (config.widgetFamily == 'small') { | |
if (numberCoins <= maxLinesSM) { | |
await smallTable(coins, cryptoData) | |
} else { | |
errorLine = stack.addStack() | |
errorLine.layoutVertically() | |
fehlerText = errorLine.addText("Please use not more than " + maxLinesSM + " coins in a small widget!") | |
fehlerText.font = Font.boldSystemFont(8) | |
fehlerText.textColor = COLOR_RED | |
fehlerText = errorLine.addText("You tried to use " + numberCoins + " coins.") | |
fehlerText.font = Font.boldSystemFont(8) | |
fehlerText.textColor = COLOR_RED | |
} | |
} | |
if (config.widgetFamily == 'medium') { | |
if (numberCoins <= maxLinesSM) { | |
await wideTable(coins, cryptoData) | |
} else { | |
errorLine = stack.addStack() | |
errorLine.layoutVertically() | |
fehlerText = errorLine.addText("Please use not more than " + maxLinesSM + " coins in a medium widget!") | |
fehlerText.font = Font.boldSystemFont(15) | |
fehlerText.textColor = COLOR_RED | |
fehlerText = errorLine.addText("You tried to use " + numberCoins + " coins.") | |
fehlerText.font = Font.boldSystemFont(15) | |
fehlerText.textColor = COLOR_RED | |
} | |
} | |
if (config.widgetFamily == 'large') { | |
if (numberCoins <= maxLinesLX) { | |
await wideTable(coins, cryptoData) | |
} else { | |
errorLine = stack.addStack() | |
errorLine.layoutVertically() | |
fehlerText = errorLine.addText("Please use not more than " + maxLinesLX + " coins in a large widget!") | |
fehlerText.font = Font.boldSystemFont(15) | |
fehlerText.textColor = COLOR_RED | |
fehlerText = errorLine.addText("You tried to use " + numberCoins + " coins.") | |
fehlerText.font = Font.boldSystemFont(15) | |
fehlerText.textColor = COLOR_RED | |
} | |
} | |
if (config.widgetFamily == 'extraLarge') { | |
if (numberCoins <= maxLinesLX) { | |
await extraLargeTable(coins, cryptoData) | |
} else { | |
errorLine = stack.addStack() | |
errorLine.layoutVertically() | |
fehlerText = errorLine.addText("Please use not more than " + maxLinesLX + " coins in a extraLarge widget!") | |
fehlerText.font = Font.boldSystemFont(15) | |
fehlerText.textColor = COLOR_RED | |
fehlerText = errorLine.addText("You tried to use " + numberCoins + " coins.") | |
fehlerText.font = Font.boldSystemFont(15) | |
fehlerText.textColor = COLOR_RED | |
} | |
} | |
df = new DateFormatter() | |
df.dateFormat = "yyyy-MM-dd HH:mm" | |
lastUpdate = df.string(new Date(cryptoData.status.timestamp)) | |
if ((numberCoins<(maxLinesSM - 1) && (config.widgetFamily == 'small' || config.widgetFamily == 'medium')) || (numberCoins<(maxLinesLX - 1) && (config.widgetFamily == 'large' || config.widgetFamily == 'extraLarge'))) { | |
stack.addSpacer(8) | |
} | |
footerLine = listWidget.addStack() | |
footerLine.addSpacer() | |
footerLineText = footerLine.addText(lastUpdate) | |
footerLineText.font = Font.mediumSystemFont(8) | |
footerLineText.textColor = Color.dynamic(COLOR_GREY30, COLOR_GREY70) | |
footerLine.addSpacer() | |
} else { | |
errorLine = stack.addStack() | |
errorLine.layoutHorizontally() | |
if (cryptoData) { | |
errorText = errorLine.addText("Error Calling the Coin Market Cap API: "+cryptoData.status.error_message) | |
} else { | |
errorText = errorLine.addText("Not able to get Data from Coin Market Cap, nor from Cache. Try again.") | |
} | |
errorText.font = Font.boldSystemFont(15) | |
errorText.textColor = COLOR_RED | |
} | |
if (debug) console.log("END async function crateWidget()") | |
return listWidget | |
} | |
// small widget table | |
async function smallTable(coins, cryptoData) { | |
if (debug) console.log("START async function smallTable(coins, cryptoData)") | |
firstLine = stack.addStack() | |
firstLine.layoutHorizontally() | |
firstLine.centerAlignContent() | |
firstLine.backgroundColor = Color.dynamic(COLOR_BLACK, COLOR_WHITE) | |
firstLine.cornerRadius = 5 | |
firstLine.addSpacer() | |
firstLineStack = firstLine.addStack() | |
firstLineStack.size = new Size(50,0) | |
nameText = firstLineStack.addText("Name") | |
nameText.font = Font.mediumSystemFont(12) | |
nameText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK) | |
nameText.leftAlignText() | |
firstLineStack.addSpacer() | |
firstLineStack = firstLine.addStack() | |
firstLineStack.size = new Size(70,0) | |
firstLineStack.addSpacer() | |
priceText = firstLineStack.addText("Price "+referenceValue) | |
priceText.font = Font.mediumSystemFont(12) | |
priceText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK) | |
priceText.rightAlignText() | |
firstLine.addSpacer() | |
lineCount = 1 | |
for (coin of coins) { | |
if (debug) console.log("coin: "+ coin) | |
coinLine = stack.addStack() | |
coinLine.layoutHorizontally() | |
coinLine.centerAlignContent() | |
coinLine.addSpacer() | |
if (lineCount % 2 == 0) { | |
coinLine.backgroundColor = Color.dynamic(COLOR_GREY90, COLOR_GREY10) | |
} | |
coinLineStack = coinLine.addStack() | |
coinLineStack.size = new Size(50,0) | |
nameText = coinLineStack.addText(cryptoData.data[coin].symbol) | |
nameText.font = Font.mediumSystemFont(12) | |
nameText.leftAlignText() | |
coinLineStack.addSpacer() | |
coinLineStack = coinLine.addStack() | |
coinLineStack.size = new Size(70,0) | |
coinLineStack.addSpacer() | |
priceText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].price.toFixed(2)).toLocaleString()) | |
priceText.font = Font.mediumSystemFont(12) | |
priceText.textColor = getTextColor("price", cryptoData.data[coin].quote[referenceValue].percent_change_1h) | |
priceText.rightAlignText() | |
coinLine.addSpacer() | |
lineCount++ | |
} | |
if (debug) console.log("END async function smallTable(coins, cryptoData)") | |
} | |
// medium and large widget table | |
async function wideTable(coins, cryptoData) { | |
if (debug) console.log("START async function wideTable(coins, cryptoData)") | |
firstLine = stack.addStack() | |
firstLine.layoutHorizontally() | |
firstLine.centerAlignContent() | |
firstLine.backgroundColor = Color.dynamic(COLOR_BLACK, COLOR_WHITE) | |
firstLine.cornerRadius = 5 | |
firstLine.addSpacer() | |
firstLineStack = firstLine.addStack() | |
firstLineStack.size = new Size(115,0) | |
nameText = firstLineStack.addText("Name") | |
nameText.font = Font.mediumSystemFont(12) | |
nameText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK) | |
nameText.leftAlignText() | |
firstLineStack.addSpacer() | |
firstLineStack = firstLine.addStack() | |
firstLineStack.size = new Size(70,0) | |
firstLineStack.addSpacer() | |
priceText = firstLineStack.addText("Price "+referenceValue) | |
priceText.font = Font.mediumSystemFont(12) | |
priceText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK) | |
priceText.rightAlignText() | |
firstLineStack = firstLine.addStack() | |
firstLineStack.size = new Size(50,0) | |
firstLineStack.addSpacer() | |
dayText = firstLineStack.addText("24h %") | |
dayText.font = Font.mediumSystemFont(12) | |
dayText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK) | |
dayText.rightAlignText() | |
firstLineStack = firstLine.addStack() | |
firstLineStack.size = new Size(50,0) | |
firstLineStack.addSpacer() | |
weekText = firstLineStack.addText("7d %") | |
weekText.font = Font.mediumSystemFont(12) | |
weekText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK) | |
weekText.rightAlignText() | |
firstLine.addSpacer() | |
lineCount = 1 | |
for (coin of coins) { | |
if (debug) console.log("coin: "+ coin) | |
coinLine = stack.addStack() | |
coinLine.layoutHorizontally() | |
coinLine.centerAlignContent() | |
coinLine.addSpacer() | |
if (lineCount % 2 == 0) { | |
coinLine.backgroundColor = Color.dynamic(COLOR_GREY90, COLOR_GREY10) | |
} | |
coinLineStack = coinLine.addStack() | |
coinLineStack.size = new Size(115,0) | |
nameText = coinLineStack.addText(cryptoData.data[coin].symbol + "/" + cryptoData.data[coin].name) | |
nameText.font = Font.mediumSystemFont(12) | |
nameText.leftAlignText() | |
coinLineStack.addSpacer() | |
coinLineStack = coinLine.addStack() | |
coinLineStack.size = new Size(70,0) | |
coinLineStack.addSpacer() | |
priceText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].price.toFixed(2)).toLocaleString()) | |
priceText.font = Font.mediumSystemFont(12) | |
priceText.textColor = getTextColor("price", cryptoData.data[coin].quote[referenceValue].percent_change_1h) | |
priceText.rightAlignText() | |
coinLineStack = coinLine.addStack() | |
coinLineStack.size = new Size(50,0) | |
coinLineStack.addSpacer() | |
dayText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].percent_change_24h.toFixed(2)).toLocaleString()) | |
dayText.font = Font.mediumSystemFont(12) | |
dayText.textColor = getTextColor("day", cryptoData.data[coin].quote[referenceValue].percent_change_24h) | |
dayText.rightAlignText() | |
coinLineStack = coinLine.addStack() | |
coinLineStack.size = new Size(50,0) | |
coinLineStack.addSpacer() | |
weekText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].percent_change_7d.toFixed(2)).toLocaleString()) | |
weekText.font = Font.mediumSystemFont(12) | |
weekText.textColor = getTextColor("week", cryptoData.data[coin].quote[referenceValue].percent_change_7d) | |
weekText.rightAlignText() | |
coinLine.addSpacer() | |
lineCount++ | |
} | |
if (debug) console.log("END async function wideTable(coins, cryptoData)") | |
} | |
//extraLarge table | |
async function extraLargeTable(coins, cryptoData) { | |
if (debug) console.log("START async function extraLargeTable(coins, cryptoData)") | |
firstLine = stack.addStack() | |
firstLine.layoutHorizontally() | |
firstLine.centerAlignContent() | |
firstLine.backgroundColor = Color.dynamic(COLOR_BLACK, COLOR_WHITE) | |
firstLine.cornerRadius = 5 | |
firstLine.addSpacer() | |
firstLineStack = firstLine.addStack() | |
firstLineStack.size = new Size(125,0) | |
nameText = firstLineStack.addText("Name") | |
nameText.font = Font.mediumSystemFont(12) | |
nameText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK) | |
nameText.leftAlignText() | |
firstLineStack.addSpacer() | |
firstLineStack = firstLine.addStack() | |
firstLineStack.size = new Size(75,0) | |
firstLineStack.addSpacer() | |
priceText = firstLineStack.addText("Price "+referenceValue) | |
priceText.font = Font.mediumSystemFont(12) | |
priceText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK) | |
priceText.rightAlignText() | |
firstLineStack = firstLine.addStack() | |
firstLineStack.size = new Size(50,0) | |
firstLineStack.addSpacer() | |
hourText = firstLineStack.addText("1h %") | |
hourText.font = Font.mediumSystemFont(12) | |
hourText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK) | |
hourText.rightAlignText() | |
firstLineStack = firstLine.addStack() | |
firstLineStack.size = new Size(50,0) | |
firstLineStack.addSpacer() | |
dayText = firstLineStack.addText("24h %") | |
dayText.font = Font.mediumSystemFont(12) | |
dayText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK) | |
dayText.rightAlignText() | |
firstLineStack = firstLine.addStack() | |
firstLineStack.size = new Size(55,0) | |
firstLineStack.addSpacer() | |
weekText = firstLineStack.addText("7d %") | |
weekText.font = Font.mediumSystemFont(12) | |
weekText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK) | |
weekText.rightAlignText() | |
firstLineStack = firstLine.addStack() | |
firstLineStack.size = new Size(125,0) | |
firstLineStack.addSpacer() | |
mcText = firstLineStack.addText("Market Cap "+referenceValue) | |
mcText.font = Font.mediumSystemFont(12) | |
mcText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK) | |
mcText.rightAlignText() | |
firstLineStack = firstLine.addStack() | |
firstLineStack.size = new Size(120,0) | |
firstLineStack.addSpacer() | |
csText = firstLineStack.addText("Circulating Supply") | |
csText.font = Font.mediumSystemFont(12) | |
csText.textColor = Color.dynamic(COLOR_WHITE, COLOR_BLACK) | |
csText.rightAlignText() | |
firstLine.addSpacer() | |
lineCount = 1 | |
for (coin of coins) { | |
if (debug) console.log("coin: "+ coin) | |
coinLine = stack.addStack() | |
coinLine.layoutHorizontally() | |
coinLine.centerAlignContent() | |
coinLine.addSpacer() | |
if (lineCount % 2 == 0) { | |
coinLine.backgroundColor = Color.dynamic(COLOR_GREY90, COLOR_GREY10) | |
} | |
coinLineStack = coinLine.addStack() | |
coinLineStack.size = new Size(125,0) | |
nameText = coinLineStack.addText(cryptoData.data[coin].symbol + "/" + cryptoData.data[coin].name) | |
nameText.font = Font.mediumSystemFont(12) | |
nameText.leftAlignText() | |
coinLineStack.addSpacer() | |
coinLineStack = coinLine.addStack() | |
coinLineStack.size = new Size(75,0) | |
coinLineStack.addSpacer() | |
priceText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].price.toFixed(2)).toLocaleString()) | |
priceText.font = Font.mediumSystemFont(12) | |
priceText.textColor = getTextColor("price", cryptoData.data[coin].quote[referenceValue].percent_change_1h) | |
priceText.rightAlignText() | |
coinLineStack = coinLine.addStack() | |
coinLineStack.size = new Size(50,0) | |
coinLineStack.addSpacer() | |
hourText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].percent_change_1h.toFixed(2)).toLocaleString()) | |
hourText.font = Font.mediumSystemFont(12) | |
hourText.textColor = getTextColor("hour", cryptoData.data[coin].quote[referenceValue].percent_change_1h) | |
hourText.rightAlignText() | |
coinLineStack = coinLine.addStack() | |
coinLineStack.size = new Size(50,0) | |
coinLineStack.addSpacer() | |
dayText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].percent_change_24h.toFixed(2)).toLocaleString()) | |
dayText.font = Font.mediumSystemFont(12) | |
dayText.textColor = getTextColor("day", cryptoData.data[coin].quote[referenceValue].percent_change_24h) | |
dayText.rightAlignText() | |
coinLineStack = coinLine.addStack() | |
coinLineStack.size = new Size(55,0) | |
coinLineStack.addSpacer() | |
weekText = coinLineStack.addText(parseFloat(cryptoData.data[coin].quote[referenceValue].percent_change_7d.toFixed(2)).toLocaleString()) | |
weekText.font = Font.mediumSystemFont(12) | |
weekText.textColor = getTextColor("week", cryptoData.data[coin].quote[referenceValue].percent_change_7d) | |
weekText.rightAlignText() | |
coinLineStack = coinLine.addStack() | |
coinLineStack.size = new Size(125,0) | |
coinLineStack.addSpacer() | |
mcText = coinLineStack.addText(Math.round(cryptoData.data[coin].quote[referenceValue].market_cap).toLocaleString()) | |
mcText.font = Font.mediumSystemFont(12) | |
mcText.rightAlignText() | |
coinLineStack = coinLine.addStack() | |
coinLineStack.size = new Size(120,0) | |
coinLineStack.addSpacer() | |
csText = coinLineStack.addText(Math.round(cryptoData.data[coin].circulating_supply).toLocaleString()) | |
csText.font = Font.mediumSystemFont(12) | |
csText.rightAlignText() | |
coinLine.addSpacer() | |
lineCount++ | |
} | |
if (debug) console.log("END async function extraLargeTable(coins, cryptoData)") | |
} | |
// get crypto data from API | |
async function getCryptoData(fm, mcUrlParameter) { | |
if (debug) console.log("START async function getCryptoData(fm, cmcUrlParameter)") | |
let directoryPath = fm.joinPath(fm.libraryDirectory(), scriptName + ".cache") | |
if (debug) console.log("directoryPath: "+ directoryPath) | |
let cmcApiData = getCache(fm, directoryPath, cmcRefresh) | |
if (!cmcApiData || cmcApiData.length == 0 || cmcApiData.cacheExpired) { | |
try { | |
const cmcApiUrl = "https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest" + cmcUrlParameter | |
if (debug) console.log("cmcApiUrl: "+ cmcApiUrl) | |
let cmcApiRequest = new Request(cmcApiUrl) | |
cmcApiRequest.headers = { 'X-CMC_PRO_API_KEY': cmcApiKey, 'Accept': 'application/json' } | |
cmcApiData = await cmcApiRequest.loadJSON() | |
if (!cmcApiData || cmcApiData.length == 0) { throw 0 } | |
fm.writeString(directoryPath, JSON.stringify(cmcApiData, null, 2)) | |
} catch(e) { | |
cmcApiData = getCache(fm, directoryPath, cmcRefresh) | |
} | |
} | |
if (debug) console.log("Return cmcApiData: "+ JSON.stringify(cmcApiData, null, 2)) | |
if (debug) console.log("END async function getCryptoData(fm, cmcUrlParameter)") | |
return cmcApiData | |
} | |
// get text color | |
function getTextColor(object, value) { | |
if (debug) console.log("START function getTextColor(object, value)") | |
let textColor = Color.dynamic(COLOR_BLACK, COLOR_WHITE) | |
if ((object=="price" && value>=1) || (object=="hour" && value>=1) || (object=="day" && value>=5) || (object=="week" && value>=10)) { | |
textColor = COLOR_GREEN | |
} else if ((object=="price" && value<=-1) || (object=="hour" && value<=-1) || (object=="day" && value<=-5) || (object=="week" && value<=-10)) { | |
textColor = COLOR_RED | |
} | |
if (debug) console.log("Return textColor: "+ textColor) | |
if (debug) console.log("END function getTextColor(object, value)") | |
return textColor | |
} | |
// get cache | |
function getCache(fm, path, minAge = -1, maxAge) { | |
if (debug) console.log("START function getCache(fm, path, minAge = -1, maxAge)") | |
if (debug) console.log("path: "+ path) | |
if (debug) console.log("minAge: "+ minAge) | |
if (debug) console.log("maxAge: "+ maxAge) | |
if (!fm.fileExists(path)) { | |
if (debug) console.log("Cache File does not exists. Return null") | |
return null | |
} | |
const cache = JSON.parse(fm.readString(path)) | |
if (debug) console.log("cache: "+ JSON.stringify(cache, null, 2)) | |
now = new Date() | |
if (debug) console.log("now: "+ now) | |
const age = (now.getTime() - fm.modificationDate(path).getTime())/60000 | |
if (debug) console.log("age: "+ age) | |
if (Number.isInteger(maxAge) && age > maxAge) { | |
if (debug) console.log("Age is grater than maxAge. Return null.") | |
return null | |
} | |
if (minAge != -1 && (!minAge || age > minAge)) cache.cacheExpired = true | |
if (debug) console.log("Return cache: "+ JSON.stringify(cache, null, 2)) | |
if (debug) console.log("END function getCache(fm, path, minAge = -1, maxAge)") | |
return cache | |
} | |
// generate prompt. | |
async function generatePrompt(title,message,options) { | |
if (debug) console.log("START async function generatePrompt(title,message,options)") | |
if (debug) console.log("title: "+ title) | |
if (debug) console.log("message: "+ message) | |
if (debug) console.log("options: "+ options) | |
let alert = new Alert() | |
alert.title = title | |
if (message) alert.message = message | |
let buttons = options || ["OK"] | |
for (button of buttons) { | |
alert.addAction(button) | |
} | |
if (debug) console.log("END async function generatePrompt(title,message,options)") | |
return await alert.presentAlert() | |
} |
icsAT
commented
Oct 12, 2021
First of all you have to get a free API key from Coin Market Cap an put it in the code.
You are able to set the reference currency and the displayed cryptocurrencies in the code or as a script parameter. The script parameter overrules the setting in the code. If you use the script parameter, you have write the reference currency first followed by a semicolon. Then you have to write all the cryptocurrencies to be shown, separated by comma. Do not use any spaces.
Script parameter example: EUR;ADA,BTC,ETH,LTC,UNI,DOGE
If you want to setup more than one crypto widget on one device with different reference currencies and/or different cryptocurrencies you need to have one Scriptable script for each Widget. This is because otherwise one widget would set the cache an the other widget would not find the needed information in this cache.
Version 0.81 (10/15/2021)
- added possibility to remove background.
Version 0.80 (10/12/2021)
- Very first version.