-
-
Save goldfarbalex/2fbb5970aebf4fabd6c412707faa86e1 to your computer and use it in GitHub Desktop.
Date & Agenda & Weather Scriptable widget (german localization)
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) and adapted by @marco79 | |
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 = "" // 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("#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) | |
// 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) + " - " + 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 + " Uhr") | |
eventTime.font = Font.semiboldMonospacedSystemFont(10) | |
eventTime.textColor = Color.black() | |
eventTime.textOpacity = 0.5 | |
if (i == 0) { | |
eventItemsStack.addSpacer(3) | |
} | |
} | |
} else { | |
let nothingText = eventStack.addText("Heute hast du keine Termine!") | |
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) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment