-
-
Save mzeryck/4f9255224fe707ee74d86dc6465feea2 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: red; icon-glyph: calendar-alt; | |
// This widget was created by Max Zeryck @mzeryck | |
// Note: before using this script in a widget, change const TEST_MODE to true and run it in the Scriptable app. | |
// The app will prompt you to give calendar access, and then show a preview of the widget. | |
// Make sure to change it back to const TEST_MODE = false prior to adding it to a widget. Happy coding! | |
const IMAGE_SOURCE = "Unsplash" | |
const TERMS = "nature,water" | |
const FORCE_IMAGE_UPDATE = false | |
const TEST_MODE = false | |
// Store current datetime | |
const date = new Date() | |
// If we're running the script normally, go to the Calendar. | |
if (!config.runsInWidget && !TEST_MODE) { | |
const appleDate = new Date('2001/01/01') | |
const timestamp = (date.getTime() - appleDate.getTime()) / 1000 | |
const callback = new CallbackURL("calshow:"+timestamp) | |
callback.open() | |
Script.complete() | |
// Otherwise, create the widget. | |
} else { | |
let widget = new ListWidget() | |
// Format the date info | |
let df = new DateFormatter() | |
df.dateFormat = "EEEE" | |
let dayOfWeek = widget.addText(df.string(date).toUpperCase()) | |
let dateNumber = widget.addText(date.getDate().toString()) | |
dayOfWeek.font = Font.semiboldSystemFont(13) | |
dateNumber.font = Font.lightSystemFont(34) | |
// Find future events that aren't all day and aren't canceled | |
const events = await CalendarEvent.today([]) | |
let futureEvents = [] | |
for (const event of events) { | |
if (event.startDate.getTime() > date.getTime() && !event.isAllDay && !event.title.startsWith("Canceled:")) { | |
futureEvents.push(event) | |
} | |
} | |
// If there is at least one future event today | |
if (futureEvents.length != 0) { | |
dayOfWeek.textColor = Color.red() | |
widget.addSpacer() | |
let titleOne = widget.addText(futureEvents[0].title) | |
titleOne.font = Font.mediumSystemFont(14) | |
widget.addSpacer(7) | |
let timeOne = widget.addText(formatTime(futureEvents[0].startDate)) | |
timeOne.font = Font.regularSystemFont(14) | |
timeOne.textColor = Color.gray() | |
// If we have multiple future events, show the following one | |
if (futureEvents.length > 1) { | |
// We only have room for single-line event names | |
titleOne.lineLimit = 1 | |
widget.addSpacer(12) | |
let titleTwo = widget.addText(futureEvents[1].title) | |
titleTwo.font = Font.mediumSystemFont(14) | |
titleTwo.lineLimit = 1 | |
widget.addSpacer(7) | |
let timeTwo = widget.addText(formatTime(futureEvents[1].startDate)) | |
timeTwo.font = Font.regularSystemFont(14) | |
timeTwo.textColor = Color.gray() | |
} | |
// If there are no future events today | |
} else { | |
dayOfWeek.textColor = Color.white() | |
dateNumber.textColor = Color.white() | |
let files = FileManager.local() | |
const path = files.joinPath(files.documentsDirectory(), "mz_calendar_widget.jpg") | |
const modificationDate = files.modificationDate(path) | |
// Download image if it doesn't exist, wasn't created today, or update is forced | |
if (!modificationDate || !sameDay(modificationDate,date) || FORCE_IMAGE_UPDATE) { | |
try { | |
let img = await provideImage(IMAGE_SOURCE,TERMS) | |
files.writeImage(path,img) | |
widget.backgroundImage = img | |
} catch { | |
widget.backgroundImage = files.readImage(path) | |
} | |
} else { | |
widget.backgroundImage = files.readImage(path) | |
} | |
// Add overlay to image | |
let gradient = new LinearGradient() | |
gradient.colors = [new Color("#000000",0.5), new Color("#000000",0)] | |
gradient.locations = [0, 0.5] | |
widget.backgroundGradient = gradient | |
widget.addSpacer() | |
} | |
// Finalize widget settings | |
widget.setPadding(16,16,16,0) | |
widget.spacing = -3 | |
Script.setWidget(widget) | |
widget.presentSmall() | |
Script.complete() | |
} | |
// Helper function to interpret sources and terms | |
async function provideImage(source,terms) { | |
if (source == "Bing") { | |
const url = "http://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=en-US" | |
const req = new Request(url) | |
const json = await req.loadJSON() | |
const imgURL = "http://bing.com" + json.images[0].url | |
const img = await downloadImage(imgURL) | |
const rect = new Rect(-78,0,356,200) | |
return cropImage(img, rect) | |
} else if (source == "Unsplash") { | |
const img = await downloadImage("https://source.unsplash.com/featured/500x500/?"+terms) | |
return img | |
} | |
} | |
// Helper function to download images | |
async function downloadImage(url) { | |
const req = new Request(url) | |
return await req.loadImage() | |
} | |
// Crop an image into a rect | |
function cropImage(img,rect) { | |
let draw = new DrawContext() | |
draw.respectScreenScale = true | |
draw.drawImageInRect(img,rect) | |
return draw.getImage() | |
} | |
// Formats the times under each event | |
function formatTime(date) { | |
let df = new DateFormatter() | |
df.useNoDateStyle() | |
df.useShortTimeStyle() | |
return df.string(date) | |
} | |
// Determines if two dates occur on the same day | |
function sameDay(d1, d2) { | |
return d1.getFullYear() === d2.getFullYear() && | |
d1.getMonth() === d2.getMonth() && | |
d1.getDate() === d2.getDate() | |
} |
Possible to make it localized?!
Add locale code.
@ mzeryck
Hey Max, your widget is really good!!! However, I have problems at "weather calendar widget builder” and always get the following hint:
2020-11-08 17:09:55: Error on line 769:51: TypeError: undefined is not an object (evaluating 'weatherDataRaw.current.temp')
Can you help meines me?
I’m looking forward to a feedback.
@ mzeryck
Hey Max, your widget is really good!!! However, I have problems at "weather calendar widget builder” and always get the following hint:
2020-11-08 17:09:55: Error on line 769:51: TypeError: undefined is not an object (evaluating 'weatherDataRaw.current.temp')
Can you help meines me?
I’m looking forward to a feedback.
Ditto.
@Augustus88 @FijianCoconut In order for the widget to work, you need an API key from OpenWeather. You just need to sign up for a free account using this link. Then, you'll get the API key (it looks like a bunch of random letters and numbers). Depending on which version of the script you're using, you'll see apiKey = ""
at the top - just paste the key in between the quotation marks, like this: apiKey = "abcdefgh"
Hi @mzerck, thanks for this code but do you know if we can change the temperature units and go from ° F to ° C? And how not to put a background to see that the wallpaper ? thank you so much
@baelfire33 I'm guessing you are using Weather Cal, rather than this calendar script? In Weather Cal, you can change the units to "metric" (instead of imperial) to get ° C. For a transparent background, use Widget Blur to export an image, and then use that image as the background of the widget.
thank you so much ! Do you have a solution for switching from light mode to dark mode with the image behind, even without dynamic image change?
@baelfire33 Sorry I always forget to check comments on my Gists! I don't have a solution yet, but I'm hoping that during my vacation this week I can work on it.
Hi, how to show TODAY all day events?
@Johnnyt12 You could change it to
const events = await CalendarEvent.thisWeek([])