Skip to content

Instantly share code, notes, and snippets.

@mzeryck
Last active August 29, 2021 14:40
Show Gist options
  • Save mzeryck/4f9255224fe707ee74d86dc6465feea2 to your computer and use it in GitHub Desktop.
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()
}
@Luk141888
Copy link

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