Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- const { transparent } = importModule('no-background')
- const widget = new ListWidget()
- widget.backgroundImage = await transparent(Script.name())
- // this Scriptable Widget is coded by Slowlydev (aka r/Sl0wly-edits, r/Slowlydev) and adapted by @marco79
- const DEV_MODE = true //for developer only
- const DEV_PREVIEW = "medium" //for developer only (this script is specialy made for a medium sized widget)
- const API_KEY = "b07bcc62baf142854c86ac6aaed52729" // enter your openweathermap.com api key
- const FORECAST_HOURS = "3"
- 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("#DD0133") //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 = "MMM YYY"
- const dayName = df_Name.string(date)
- const dayNumber = date.getDate().toString()
- const monthName = df_Month.string(date)
- // Option 1: uncomment this to use let the script locate you each time (which takes longer and needs more battery)
- let loc = await Location.current()
- let lat = loc["latitude"]
- let lon = loc["longitude"]
- // Option 2: hard coded longitude/latitude
- // let lat = "50.95330938278102"
- // let lon = "6.915087611808545"
- 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 == 2) { 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)
- //Top Row (Date & Weather)
- let topRow = widget.addStack()
- topRow.layoutHorizontally()
- //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(32)
- dayNumberTxt.textColor = Color.black()
- dateStack.addSpacer(7)
- let dateTextStack = dateStack.addStack()
- dateTextStack.layoutVertically()
- let monthNameTxt = dateTextStack.addText(monthName.toUpperCase())
- monthNameTxt.font = Font.boldSystemFont(10)
- monthNameTxt.textColor = Color.black()
- let dayNameTxt = dateTextStack.addText(dayName)
- dayNameTxt.font = Font.boldSystemFont(12)
- dayNameTxt.textColor = calendarColor
- dateStack.addSpacer()
- topRow.addSpacer()
- widget.addSpacer()
- //Top Row Weather
- let weatherStack = topRow.addStack()
- weatherStack.layoutHorizontally()
- weatherStack.centerAlignContent()
- weatherStack.setPadding(7, 7, 7, 7)
- weatherStack.backgroundColor = stackBackground
- weatherStack.cornerRadius = 12
- weatherStack.size = stackSize
- weatherStack.url = WEATHER_URL
- 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()
- //Bottom Row Events
- let eventStack = widget.addStack()
- eventStack.layoutHorizontally()
- eventStack.centerAlignContent()
- eventStack.setPadding(7, 7, 7, 7)
- eventStack.backgroundColor = stackBackground
- eventStack.cornerRadius = 12
- eventStack.size = stackSize
- let eventInfoStack
- const font = Font.lightSystemFont(20)
- let calendarSymbol = SFSymbol.named("calendar")
- calendarSymbol.applyFont(font)
- eventStack.addSpacer(8)
- let eventIcon = eventStack.addImage(calendarSymbol.image)
- eventIcon.imageSize = new Size(20, 20)
- eventIcon.resizable = false
- eventIcon.centerAlignImage()
- eventStack.addSpacer(14)
- eventStack.url = CALENDAR_URL
- let eventItemsStack = eventStack.addStack()
- eventItemsStack.layoutVertically()
- if (futureEvents.length != 0) {
- for (let i = 0; i < futureEvents.length; i++) {
- let futureEvent = futureEvents[i]
- const time = formatTime(futureEvent.startDate) + " to " + formatTime(futureEvent.endDate)
- const eventColor = new Color("#" + futureEvent.calendar.color.hex)
- eventInfoStack = eventItemsStack.addStack()
- eventInfoStack.layoutVertically()
- let eventTitle = eventItemsStack.addText(futureEvent.title)
- eventTitle.font = Font.semiboldSystemFont(12)
- eventTitle.textColor = eventColor
- eventTitle.lineLimit = 1
- let eventTime = eventItemsStack.addText(time + ".")
- eventTime.font = Font.semiboldMonospacedSystemFont(10)
- eventTime.textColor = Color.black()
- eventTime.textOpacity = 0.5
- if (i == 0) {
- eventItemsStack.addSpacer(3)
- }
- }
- } else {
- let nothingText = eventStack.addText("You have no upcoming events. Enjoy!")
- nothingText.font = Font.semiboldMonospacedSystemFont(12)
- nothingText.textColor = Color.black()
- nothingText.textOpacity = 0.5
- }
- eventStack.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()
- // Option 1: uncomment this for am/pm time with hours from 0-12
- var ampm = hours >= 12 ? ' PM' : ' AM'
- hours = hours % 12
- hours = hours ? hours : 12
- var strTime = hours.toString() + ampm
- // Option 2: german localisation
- // var strTime = hours.toString() + ":00"
- return strTime
- }
- function formatTime(date) {
- let df = new DateFormatter()
- df.useNoDateStyle()
- df.useShortTimeStyle()
- return df.string(date)
- }
Advertisement
Add Comment
Please, Sign In to add comment