-
-
Save slowlydev/42bbbbfcce626bf0a6abc46bcda17d33 to your computer and use it in GitHub Desktop.
Date & Agenda & Weather
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//this Scriptable Widget is coded by Slowlydev (aka r/Sl0wly-edits, r/Slowlydev) | |
const DEV_MODE = false //for developer only | |
const DEV_PREVIEW = "medium" //for developer only (this script is specialy made for a medium sized widget) | |
const API_KEY = "" //OpenWeather API Key | |
const FORECAST_HOURS = "6" //recommended | |
const UNITS = "metric" //metric for celsius and imperial for Fahrenheit | |
const CALENDAR_URL = "calshow://" //Apple Calendar App, if your favorite app does have a URL scheme feel free to change it | |
const WEATHER_URL = "" //there is no URL for the Apple Weather App, if your favorite app does feel free to add it | |
const widgetBackground = new Color("#D6D6D6") //Widget Background | |
const stackBackground = new Color("#FFFFFF") //Smaller Container Background | |
const calendarColor = new Color("#EA3323") //Calendar Color | |
const stackSize = new Size(0, 65) //0 means its automatic | |
if (config.runsInWidget || DEV_MODE ) { | |
const date = new Date() | |
const dateNow = Date.now() | |
let df_Name = new DateFormatter() | |
let df_Month = new DateFormatter() | |
df_Name.dateFormat = "EEEE" | |
df_Month.dateFormat = "MMMM" | |
const dayName = df_Name.string(date) | |
const dayNumber = date.getDate().toString() | |
const monthName = df_Month.string(date) | |
let loc = await Location.current() | |
let lat = loc["latitude"] | |
let lon = loc["longitude"] | |
const weatherURL = `https://api.openweathermap.org/data/2.5/onecall?lat=${lat}&lon=${lon}&exclude=current,minutely,daily,alerts&units=${UNITS}&appid=${API_KEY}` | |
const weatherRequest = new Request(weatherURL) | |
const weaterData = await weatherRequest.loadJSON() | |
const hourlyForecasts = weaterData.hourly | |
let nextForecasts = [] | |
for (const hourlyForecast of hourlyForecasts) { | |
if (nextForecasts.length == FORECAST_HOURS) { break } | |
let dt = removeDigits(dateNow, 3) | |
if (hourlyForecast.dt > dt) { | |
nextForecasts.push(hourlyForecast) | |
} | |
} | |
const events = await CalendarEvent.today([]) | |
let futureEvents = [] | |
for (const event of events) { | |
if (futureEvents.length == 1) { break } | |
if (event.startDate.getTime() > date.getTime() && !event.isAllDay) { | |
futureEvents.push(event) | |
} | |
} | |
let widget = new ListWidget() | |
widget.backgroundColor = widgetBackground | |
widget.setPadding(10, 10, 10, 10) | |
//widget.spacing = -3 | |
//Top Row (Date & Event) | |
let topRow = widget.addStack() | |
topRow.layoutHorizontally() | |
topRow.url = CALENDAR_URL | |
//Top Row Date | |
let dateStack = topRow.addStack() | |
dateStack.layoutHorizontally() | |
dateStack.centerAlignContent() | |
dateStack.setPadding(7, 7, 7, 7) | |
dateStack.backgroundColor = stackBackground | |
dateStack.cornerRadius = 12 | |
dateStack.size = stackSize | |
dateStack.addSpacer() | |
let dayNumberTxt = dateStack.addText(dayNumber) | |
dayNumberTxt.font = Font.semiboldSystemFont(26) | |
dayNumberTxt.textColor = Color.black() | |
dateStack.addSpacer(7) | |
let dateTextStack = dateStack.addStack() | |
dateTextStack.layoutVertically() | |
let dayNameTxt = dateTextStack.addText(dayName) | |
dayNameTxt.font = Font.mediumSystemFont(12) | |
dayNameTxt.textColor = calendarColor | |
let monthNameTxt = dateTextStack.addText(monthName) | |
monthNameTxt.font = Font.regularSystemFont(10) | |
monthNameTxt.textColor = Color.black() | |
dateStack.addSpacer() | |
topRow.addSpacer() | |
//Top Row Event | |
let eventStack = topRow.addStack() | |
eventStack.layoutHorizontally() | |
eventStack.centerAlignContent() | |
eventStack.setPadding(7, 7, 7, 7) | |
eventStack.backgroundColor = stackBackground | |
eventStack.cornerRadius = 12 | |
eventStack.size = stackSize | |
eventStack.addSpacer() | |
if(futureEvents.length != 0) { | |
const time = formatTime(futureEvents[0].startDate) + " - " + formatTime(futureEvents[0].endDate) | |
const eventColor = new Color("#" + futureEvents[0].calendar.color.hex) | |
const font = Font.lightSystemFont(20) | |
let calendarSymbol = SFSymbol.named("calendar") | |
calendarSymbol.applyFont(font) | |
let eventIcon = eventStack.addImage(calendarSymbol.image) | |
eventIcon.imageSize = new Size(20, 20) | |
eventIcon.resizable = false | |
eventIcon.centerAlignImage() | |
eventStack.addSpacer(7) | |
let eventInfoStack = eventStack.addStack() | |
eventInfoStack.layoutVertically() | |
let eventTitle = eventInfoStack.addText(futureEvents[0].title) | |
eventTitle.font = Font.mediumSystemFont(12) | |
eventTitle.textColor = eventColor | |
eventTitle.lineLimit = 1 | |
let eventTime = eventInfoStack.addText(time) | |
eventTime.font = Font.regularSystemFont(10) | |
eventTime.textColor = Color.black() | |
eventTime.textOpacity = 0.5 | |
} else { | |
let nothingText = eventStack.addText("No more events due today") | |
nothingText.font = Font.regularSystemFont(12) | |
nothingText.textColor = Color.black() | |
nothingText.textOpacity = 0.5 | |
} | |
eventStack.addSpacer() | |
widget.addSpacer() | |
//Bottom Row Weather | |
let weatherStack = widget.addStack() | |
weatherStack.layoutHorizontally() | |
weatherStack.centerAlignContent() | |
weatherStack.setPadding(7, 7, 7, 7) | |
weatherStack.backgroundColor = stackBackground | |
weatherStack.cornerRadius = 12 | |
weatherStack.size = stackSize | |
for (const nextForecast of nextForecasts) { | |
const iconURL = "https://openweathermap.org/img/wn/" + nextForecast.weather[0].icon + "@2x.png" | |
let iconRequest = new Request(iconURL); | |
let icon = await iconRequest.loadImage(); | |
weatherStack.addSpacer() | |
//Hour Forecast Stack | |
let hourStack = weatherStack.addStack() | |
hourStack.layoutVertically() | |
let hourTxt = hourStack.addText(formatAMPM(nextForecast.dt)) | |
hourTxt.centerAlignText() | |
hourTxt.font = Font.systemFont(10) | |
hourTxt.textColor = Color.black() | |
hourTxt.textOpacity = 0.5 | |
let weatherIcon = hourStack.addImage(icon) | |
weatherIcon.centerAlignImage() | |
weatherIcon.size = new Size(25, 25) | |
let tempTxt = hourStack.addText(Math.round(nextForecast.temp) + "°") | |
tempTxt.centerAlignText() | |
tempTxt.font = Font.systemFont(10) | |
tempTxt.textColor = Color.black() | |
} | |
weatherStack.addSpacer() | |
Script.setWidget(widget) | |
if (DEV_MODE) { | |
if (DEV_PREVIEW == "small") { widget.presentSmall() } | |
if (DEV_PREVIEW == "medium") { widget.presentMedium() } | |
if (DEV_PREVIEW == "large") { widget.presentLarge() } | |
} | |
Script.complete() | |
} | |
function removeDigits(x, n) { return (x - (x % Math.pow(10, n))) / Math.pow(10, n) } | |
function formatAMPM(UNIX_timestamp) { | |
var date = new Date(UNIX_timestamp * 1000); | |
var hours = date.getHours(); | |
var ampm = hours >= 12 ? 'PM' : 'AM'; | |
hours = hours % 12; | |
hours = hours ? hours : 12; | |
var strTime = hours + ampm; | |
return strTime; | |
} | |
function formatTime(date) { | |
let df = new DateFormatter() | |
df.useNoDateStyle() | |
df.useShortTimeStyle() | |
return df.string(date) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment