-
-
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() | |
| } |
@Johnnyt12 You could change it to const events = await CalendarEvent.thisWeek([])
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?
How do I have to modify line 42 to incluce future events, like for the next few days?