Skip to content

Instantly share code, notes, and snippets.

@flasozzi
Last active June 12, 2021 06:15
Show Gist options
  • Save flasozzi/3e7f05ff3f1de342f16b2b31a8923651 to your computer and use it in GitHub Desktop.
Save flasozzi/3e7f05ff3f1de342f16b2b31a8923651 to your computer and use it in GitHub Desktop.
Greetings, weather, date, countdown, battery (Frankenstein) widget for iOS using Scriptable.
// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: blue; icon-glyph: calendar-alt;
// CREDITS
// Greetings code Autumn Vibes by u/ben5292001
// Battery code by u/_Bisho_
// Weather stack code by u/coderjones
// Countdown code and assemble by u/flasozzi
// READ THE INSTRUCTIONS BELOW
// You need to both edit the code and add parameters in order to personalise the widget.
// To add parameters, add the widget to your home, long press it and tap 'edit widget'
// Your parameter must have the following format: image.png|padding-top|text-color|
// The image should be placed in the iCloud Scriptable folder (case-sensitive).
// The padding-top spacing parameter moves the text down by a set amount.
// The text color parameter should be a hex value.
// For example, to use the image bkg_fall.PNG with a padding of 20 and a text color of red
// the parameter should be typed as: bkg_fall.png|20|#ff0000
// All parameters are required and separated with "|"
// Parameters allow different settings for multiple widget instances.
// You also need to edit the info below with your own info.
// You can grab your weather API and city ID from openweathermap.org (free account needed).
var yourAPI = "32eb932e0efcb95dc46ad66fb8718083";
var cityID = "3448879";
var userName = "Flávia";
var countdownTo = "December 16 2020";
var countdownTitle = "summer holidays";
// Now this is where the fun begins and you don't really need to do anything else from this point on.
let widgetHello = new ListWidget();
var today = new Date();
var widgetInputRAW = args.widgetParameter;
try {
widgetInputRAW.toString();
} catch(e) {
throw new Error("Please long press the widget and add a parameter.");
}
var widgetInput = widgetInputRAW.toString();
var inputArr = widgetInput.split("|");
var spacing = parseInt(inputArr[1]);
// iCloud file path
var scriptableFilePath = "/var/mobile/Library/Mobile Documents/iCloud~dk~simonbs~Scriptable/Documents/";
var removeSpaces1 = inputArr[0].split(" "); // Remove spaces from file name
var removeSpaces2 = removeSpaces1.join('');
var tempPath = removeSpaces2.split(".");
var backgroundImageURLRAW = scriptableFilePath + tempPath[0];
var fm = FileManager.iCloud();
var backgroundImageURL = scriptableFilePath + tempPath[0] + ".";
var backgroundImageURLInput = scriptableFilePath + removeSpaces2;
// For users having trouble with extensions
// Uses user-input file path is the file is found
// Checks for common file format extensions if the file is not found
if (fm.fileExists(backgroundImageURLInput) == false) {
var fileTypes = ['png', 'jpg', 'jpeg', 'tiff', 'webp', 'gif'];
fileTypes.forEach(function(item) {
if (fm.fileExists((backgroundImageURL + item.toLowerCase())) == true) {
backgroundImageURL = backgroundImageURLRAW + "." + item.toLowerCase();
} else if (fm.fileExists((backgroundImageURL + item.toUpperCase())) == true) {
backgroundImageURL = backgroundImageURLRAW + "." + item.toUpperCase();
}
});
} else {
backgroundImageURL = scriptableFilePath + removeSpaces2;
}
var spacing = parseInt(inputArr[1]);
//API_KEY
let API_WEATHER = yourAPI;
let CITY_WEATHER = cityID;
//Get storage
var base_path = "/var/mobile/Library/Mobile Documents/iCloud~dk~simonbs~Scriptable/Documents/weather/";
var fm = FileManager.iCloud();
// Fetch Image from Url
async function fetchimageurl(url) {
const request = new Request(url)
var res = await request.loadImage();
return res;
}
// Get formatted Date
function getformatteddate(){
var months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
return months[today.getMonth()] + " " + today.getDate()
}
// Long-form days and months
var days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
var months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
// Load image from local drive
async function fetchimagelocal(path){
var finalPath = base_path + path + ".png";
if(fm.fileExists(finalPath)==true){
console.log("file exists: " + finalPath);
return finalPath;
}else{
//throw new Error("Error file not found: " + path);
if(fm.fileExists(base_path)==false){
console.log("Directry not exist creating one.");
fm.createDirectory(base_path);
}
console.log("Downloading file: " + finalPath);
await downloadimg(path);
if(fm.fileExists(finalPath)==true){
console.log("file exists after download: " + finalPath);
return finalPath;
}else{
throw new Error("Error file not found: " + path);
}
}
}
async function downloadimg(path){
const url = "http://a.animedlweb.ga/weather/weathers25_2.json";
const data = await fetchWeatherData(url);
var dataimg = null;
var name = null;
if(path.includes("bg")){
dataimg = data.background;
name = path.replace("_bg","");
}else{
dataimg = data.icon;
name = path.replace("_ico","");
}
var imgurl=null;
switch (name){
case "01d":
imgurl = dataimg._01d;
break;
case "01n":
imgurl = dataimg._01n;
break;
case "02d":
imgurl = dataimg._02d;
break;
case "02n":
imgurl = dataimg._02n;
break;
case "03d":
imgurl = dataimg._03d;
break;
case "03n":
imgurl = dataimg._03n;
break;
case "04d":
imgurl = dataimg._04d;
break;
case "04n":
imgurl = dataimg._04n;
break;
case "09d":
imgurl = dataimg._09d;
break;
case "09n":
imgurl = dataimg._09n;
break;
case "10d":
imgurl = dataimg._10d;
break;
case "10n":
imgurl = dataimg._10n;
break;
case "11d":
imgurl = dataimg._11d;
break;
case "11n":
imgurl = dataimg._11n;
break;
case "13d":
imgurl = dataimg._13d;
break;
case "13n":
imgurl = dataimg._13n;
break;
case "50d":
imgurl = dataimg._50d;
break;
case "50n":
imgurl = dataimg._50n;
break;
}
const image = await fetchimageurl(imgurl);
console.log("Downloaded Image");
fm.writeImage(base_path+path+".png",image);
}
//get Json weather
async function fetchWeatherData(url) {
const request = new Request(url);
const res = await request.loadJSON();
return res;
}
// Get Location
/*Location.setAccuracyToBest();
let curLocation = await Location.current();
console.log(curLocation.latitude);
console.log(curLocation.longitude);*/
let wetherurl = "http://api.openweathermap.org/data/2.5/weather?id=" + CITY_WEATHER + "&APPID=" + API_WEATHER + "&units=metric";
//"http://api.openweathermap.org/data/2.5/weather?lat=" + curLocation.latitude + "&lon=" + curLocation.longitude + "&appid=" + API_WEATHER + "&units=metric";
//"http://api.openweathermap.org/data/2.5/weather?id=" + CITY_WEATHER + "&APPID=" + API_WEATHER + "&units=metric"
const weatherJSON = await fetchWeatherData(wetherurl);
const cityName = weatherJSON.name;
const weatherarry = weatherJSON.weather;
const iconData = weatherarry[0].icon;
const weathername = weatherarry[0].main;
const curTempObj = weatherJSON.main;
const curTemp = curTempObj.temp;
const highTemp = curTempObj.temp_max;
const lowTemp = curTempObj.temp_min;
const feel_like = curTempObj.feels_like;
//Completed loading weather data
// Greetings arrays per time period.
var greetingsMorning = [
'Good morning, ' + userName + '.'
];
var greetingsAfternoon = [
'Good afternoon, ' + userName + '.'
];
var greetingsEvening = [
'Good evening, ' + userName + '.'
];
var greetingsNight = [
'Good night, ' + userName + '.'
];
var greetingsLateNight = [
'Go to sleep, ' + userName + '.'
];
// Holiday customization
var holidaysByKey = {
// month,week,day: datetext
"11,4,4": "Happy Thanksgiving!"
}
var holidaysByDate = {
// month,date: greeting
"1,1": "Happy " + (today.getFullYear()).toString() + "!",
"10,31": "Happy Halloween!",
"12,25": "Merry Christmas!"
}
var holidayKey = (today.getMonth() + 1).toString() + "," + (Math.ceil(today.getDate() / 7)).toString() + "," + (today.getDay()).toString();
var holidayKeyDate = (today.getMonth() + 1).toString() + "," + (today.getDate()).toString();
// Date Calculations
var weekday = days[ today.getDay() ];
var month = months[ today.getMonth() ];
var date = today.getDate();
var hour = today.getHours();
// Append ordinal suffix to date
function ordinalSuffix(input) {
if (input % 10 == 1 && date != 11) {
return input.toString() + "st";
} else if (input % 10 == 2 && date != 12) {
return input.toString() + "nd";
} else if (input % 10 == 3 && date != 13) {
return input.toString() + "rd";
} else {
return input.toString() + "th";
}
}
// Generate date string
var datefull = weekday + ", " + month + " " + ordinalSuffix(date);
// Support for multiple greetings per time period
function randomGreeting(greetingArray) {
return Math.floor(Math.random() * greetingArray.length);
}
var greeting = new String("Howdy.")
if (hour < 5 && hour >= 1) { // 1am - 5am
greeting = greetingsLateNight[randomGreeting(greetingsLateNight)];
} else if (hour >= 23 || hour < 1) { // 11pm - 1am
greeting = greetingsNight[randomGreeting(greetingsNight)];
} else if (hour < 12) { // Before noon (5am - 12pm)
greeting = greetingsMorning[randomGreeting(greetingsMorning)];
} else if (hour >= 12 && hour <= 17) { // 12pm - 5pm
greeting = greetingsAfternoon[randomGreeting(greetingsAfternoon)];
} else if (hour > 17 && hour < 23) { // 5pm - 11pm
greeting = greetingsEvening[randomGreeting(greetingsEvening)];
}
// Overwrite greeting if calculated holiday
if (holidaysByKey[holidayKey]) {
greeting = holidaysByKey[holidayKey];
}
// Overwrite all greetings if specific holiday
if (holidaysByDate[holidayKeyDate]) {
greeting = holidaysByDate[holidayKeyDate];
}
// Try/catch for color input parameter
try {
inputArr[2].toString();
} catch(e) {
throw new Error("Please long press the widget and add a parameter.");
}
let themeColor = new Color(inputArr[2].toString());
/* --------------- */
/* Assemble Widget */
/* --------------- */
//Top spacing
widgetHello.addSpacer(parseInt(spacing));
let shadow = new Color('#A9A9A9')
// Greeting label
let hello = widgetHello.addText(greeting);
hello.font = Font.boldSystemFont(29);
hello.textColor = themeColor;
hello.shadowColor = shadow;
hello.shadowOffset = new Point(1,1);
hello.shadowRadius = 2;
hello.textOpacity = (1);
hello.centerAlignText();
widgetHello.addSpacer(10);
let hStack = widgetHello.addStack();
hStack.layoutHorizontally();
// Centers weather line
hStack.addSpacer(45);
// Date label in stack
let datetext = hStack.addText(datefull + '\xa0\xa0\xa0\xa0');
datetext.font = Font.boldSystemFont(18);
datetext.textColor = themeColor;
datetext.shadowColor = shadow;
datetext.shadowOffset = new Point(1,1);
datetext.shadowRadius = 1;
datetext.textOpacity = (0.9);
datetext.centerAlignText();
//image
var tempImg = Image.fromFile(await fetchimagelocal(iconData + "_ico"));
//image in stack
let widgetimg = hStack.addImage(tempImg);
widgetimg.imageSize = new Size(20, 20);
widgetimg.shadowColor = shadow;
widgetimg.shadowOffset = new Point(1,1);
widgetimg.shadowRadius = 1;
widgetimg.imageOpacity = (0.9);
widgetimg.centerAlignImage();
//tempeture label in stack
let temptext = hStack.addText('\xa0\xa0'+ Math.round(curTemp).toString()+"\u2103");
temptext.font = Font.boldSystemFont(18);
temptext.textColor = themeColor;
temptext.shadowColor = shadow;
temptext.shadowOffset = new Point(1,1);
temptext.shadowRadius = 1;
temptext.textOpacity = (0.9);
temptext.centerAlignText();
// Countdown
const endtime = countdownTo;
function getTimeRemaining(endtime){
const total = Date.parse(endtime) - Date.parse(new Date());
const seconds = Math.floor( (total/1000) % 60 );
const minutes = Math.floor( (total/1000/60) % 60 );
const hours = Math.floor( (total/(1000*60*60)) % 24 );
const days = Math.floor( total/(1000*60*60*24) );
return {
total,
days,
hours,
minutes,
seconds
};
}
const total = Date.parse(endtime) - Date.parse(new Date());
let progressText = widgetHello.addText(String(getTimeRemaining(endtime).days + 1) + ' days until ' + countdownTitle)
progressText.font = Font.boldSystemFont(18);
progressText.textColor = themeColor;
progressText.shadowColor = shadow;
progressText.shadowOffset = new Point(1,1);
progressText.shadowRadius = 1;
progressText.textOpacity = (0.9);
progressText.centerAlignText();
//Battery
const batteryLine = widgetHello.addText(renderBattery());
batteryLine.textColor = themeColor;
batteryLine.font = Font.boldSystemFont(18);
batteryLine.shadowColor = shadow;
batteryLine.shadowOffset = new Point(1,1);
batteryLine.shadowRadius = 1;
batteryLine.shadowOpacity = (0.7);
batteryLine.textOpacity = (0.9);
function renderBattery() {
const batteryLevel = Device.batteryLevel();
const batteryAscii = "⚡️" + Math.round(batteryLevel * 100) + "%";
return batteryAscii;
}
batteryLine.centerAlignText();
// Bottom Spacer
widgetHello.addSpacer();
widgetHello.setPadding(0, 0, 0, 0);
// Background image
widgetHello.backgroundImage = Image.fromFile(backgroundImageURL);
// Set widget
Script.setWidget(widgetHello);
@flasozzi
Copy link
Author

flasozzi commented Oct 6, 2020

widget

@benedicatdeisub
Copy link

Hi there,
How did u make the background invisible

@VachetVirginie
Copy link

Hello, how can we add an img or make the background invisible please?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment