Skip to content

Instantly share code, notes, and snippets.

@mzeryck
Last active August 29, 2021 14:40
Show Gist options
  • Select an option

  • Save mzeryck/4f9255224fe707ee74d86dc6465feea2 to your computer and use it in GitHub Desktop.

Select an option

Save mzeryck/4f9255224fe707ee74d86dc6465feea2 to your computer and use it in GitHub Desktop.
A Scriptable widget that shows upcoming calendar events to mimic the built-in Calendar widget, with some modifications.
// 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()
}
@baelfire33
Copy link
Copy Markdown

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

@mzeryck
Copy link
Copy Markdown
Author

mzeryck commented Nov 25, 2020

@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.

@baelfire33
Copy link
Copy Markdown

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?

@mzeryck
Copy link
Copy Markdown
Author

mzeryck commented Dec 21, 2020

@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.

@Luk141888
Copy link
Copy Markdown

Hi, how to show TODAY all day events?

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