Last active
November 23, 2022 10:45
-
-
Save Leibinger015/93f27b6cea99493c47197078e7424f7e to your computer and use it in GitHub Desktop.
Revised version for the new iOS 16.x lockscreen widgets for the Sunset or Sunrise time.
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
// Revised version (by www.anb030.de) for the new iOS 16 lockscreen widgets. Edit date: 23.11.2022 | |
/////////////////////////////////////////////////////////////////////// | |
// Quelle: https://gist.github.com/HendrikRunte/4b5d03cb26e31508bc96553ad3c10f47 | |
// Lokalisiert: Deutsch | |
// Datum: 05.11.2020 | |
/////////////////////////////////////////////////////////////////////// | |
// Extending the JavaScritp Date object. | |
// Usage: | |
// const sunriseDateObject = new Date().sunrise(lat, long); | |
// const sunsetDateObject = new Date().sunrise(lat, long); | |
// All the other methods just help. | |
Date.prototype.sunrise = function (latitude, longitude, zenith) { | |
return this.setSun(latitude, longitude, true, zenith); | |
}; | |
Date.prototype.sunset = function (latitude, longitude, zenith) { | |
return this.setSun(latitude, longitude, false, zenith); | |
}; | |
Date.prototype.setSun = function (latitude, longitude, isSunrise, zenith) { | |
zenith = zenith || 90.8333; | |
const DEGREES_PER_HOUR = 360 / 24; | |
const hoursFromMeridian = longitude / DEGREES_PER_HOUR; | |
const dayOfYear = this.getDayOfYear(); | |
const approxTimeOfEventInDays = isSunrise | |
? dayOfYear + (6 - hoursFromMeridian) / 24 | |
: dayOfYear + (18 - hoursFromMeridian) / 24; | |
const sunMeanAnomaly = 0.9856 * approxTimeOfEventInDays - 3.289; | |
const sunTrueLongitude = Math.mod( | |
sunMeanAnomaly + | |
1.916 * Math.sinDeg(sunMeanAnomaly) + | |
0.02 * Math.sinDeg(2 * sunMeanAnomaly) + | |
282.634, | |
360 | |
); | |
const ascension = 0.91764 * Math.tanDeg(sunTrueLongitude); | |
let rightAscension = (360 / (2 * Math.PI)) * Math.atan(ascension); | |
rightAscension = Math.mod((360 / (2 * Math.PI)) * Math.atan(ascension), 360); | |
const lQuadrant = Math.floor(sunTrueLongitude / 90) * 90; | |
const raQuadrant = Math.floor(rightAscension / 90) * 90; | |
rightAscension = rightAscension + (lQuadrant - raQuadrant); | |
rightAscension /= DEGREES_PER_HOUR; | |
const sinDec = 0.39782 * Math.sinDeg(sunTrueLongitude); | |
const cosDec = Math.cosDeg(Math.asinDeg(sinDec)); | |
const cosLocalHourAngle = | |
(Math.cosDeg(zenith) - sinDec * Math.sinDeg(latitude)) / | |
(cosDec * Math.cosDeg(latitude)); | |
const localHourAngle = Math.acosDeg(cosLocalHourAngle); | |
const localHour = isSunrise | |
? (360 - localHourAngle) / DEGREES_PER_HOUR | |
: localHourAngle / DEGREES_PER_HOUR; | |
const localMeanTime = | |
localHour + rightAscension - 0.06571 * approxTimeOfEventInDays - 6.622; | |
let time = localMeanTime - longitude / DEGREES_PER_HOUR; | |
time = Math.mod(time, 24); | |
const midnight = new Date(0); | |
midnight.setUTCFullYear(this.getUTCFullYear()); | |
midnight.setUTCMonth(this.getUTCMonth()); | |
midnight.setUTCDate(this.getUTCDate()); | |
const milli = midnight.getTime() + time * 60 * 60 * 1000; | |
return new Date(milli); | |
}; | |
// Utility functions | |
Date.prototype.getDayOfYear = function () { | |
return Math.ceil((this - new Date(this.getFullYear(), 0, 1)) / 86400000); | |
}; | |
Math.degToRad = function (num) { | |
return (num * Math.PI) / 180; | |
}; | |
Math.radToDeg = function (radians) { | |
return (radians * 180.0) / Math.PI; | |
}; | |
Math.sinDeg = function (deg) { | |
return Math.sin((deg * 2.0 * Math.PI) / 360.0); | |
}; | |
Math.acosDeg = function (x) { | |
return (Math.acos(x) * 360.0) / (2 * Math.PI); | |
}; | |
Math.asinDeg = function (x) { | |
return (Math.asin(x) * 360.0) / (2 * Math.PI); | |
}; | |
Math.tanDeg = function (deg) { | |
return Math.tan((deg * 2.0 * Math.PI) / 360.0); | |
}; | |
Math.cosDeg = function (deg) { | |
return Math.cos((deg * 2.0 * Math.PI) / 360.0); | |
}; | |
Math.mod = function (a, b) { | |
let result = a % b; | |
if (result < 0) { | |
result += b; | |
} | |
return result; | |
}; | |
/////////////////////////////////////////////////////////////////////// | |
// Here comes the actual Scriptable widget stuff. | |
/////////////////////////////////////////////////////////////////////// | |
const widget = await createWidget(); | |
if (!config.runsInWidget) { | |
await widget.presentSmall(); | |
} | |
Script.setWidget(widget); | |
Script.complete(); | |
async function createWidget(items) { | |
const now = +new Date(); | |
const fontSettings = { | |
big: 26, | |
small: 10, | |
}; | |
const list = new ListWidget(); | |
// Returns an object with latitude and longitude. | |
const location = await getLocation(); | |
// Location.reverseGeocode returns an array with object properties. | |
// Uses Apple CLLocation. | |
const address = await Location.reverseGeocode( | |
location.latitude, | |
location.longitude | |
); | |
const moonIcons = ['', '', '', '', '', '', '', '']; | |
let todaysDate = new Date(now); | |
let todaysSunrise = todaysDate.sunrise(location.latitude, location.longitude); | |
let todaysSunset = todaysDate.sunset(location.latitude, location.longitude); | |
let headerText = ''; | |
let headerColor = Color.white(); | |
const gradient = new LinearGradient(); | |
const gradientByTime = | |
now >= todaysSunrise.getTime() - 900000 && | |
now < todaysSunset.getTime() + 900000 | |
? { gradientStart: '#808080', gradientStop: '#202020' } // day | |
: { gradientStart: '#202020', gradientStop: '#808080' }; // night | |
gradient.locations = [0, 1]; | |
gradient.colors = [ | |
new Color(gradientByTime.gradientStart), | |
new Color(gradientByTime.gradientStop), | |
]; | |
list.backgroundGradient = gradient; | |
// Is it before midnight but later than today's sunset | |
// we'll look at tomorrow: | |
if ( | |
now <= todaysDate.setHours(23, 59, 59, 999) && | |
now > todaysSunset.getTime() | |
) { | |
todaysDate = new Date(new Date().setDate(todaysDate.getDate() + 1)); // tomorrow | |
headerText = 'Sonnenlauf morgen'; | |
todaysSunrise = todaysDate.sunrise(location.latitude, location.longitude); | |
todaysSunset = todaysDate.sunset(location.latitude, location.longitude); | |
headerColor = Color.white(); | |
} | |
const header = list.addText(headerText.toUpperCase()); | |
header.font = Font.regularRoundedSystemFont(fontSettings.small); | |
header.textColor = headerColor; | |
list.addSpacer(12); | |
// Sunrise | |
const sunriseStack = list.addStack(); | |
const sunriseStackColor = Color.white(); | |
addSymbol({ | |
symbolName: 'sun.max.circle', | |
stack: sunriseStack, | |
color: sunriseStackColor, | |
size: 26, | |
}); | |
sunriseStack.addSpacer(); | |
const sunriseLabel = sunriseStack.addText( | |
` ${todaysSunrise | |
.getHours() | |
.toString() | |
.replace(/^0(?:0:0?)?/, '')}:${('0' + todaysSunrise.getMinutes()).slice( | |
-2 | |
)}` | |
); | |
sunriseLabel.font = Font.mediumRoundedSystemFont(fontSettings.big); | |
sunriseLabel.textColor = sunriseStackColor; | |
// Sunset | |
const sunsetStack = list.addStack(); | |
const sunsetStackColor = Color.white(); | |
addSymbol({ | |
symbolName: 'moon.circle', | |
stack: sunsetStack, | |
color: sunsetStackColor, | |
size: 26, | |
}); | |
sunsetStack.addSpacer(); | |
const sunsetLabel = sunsetStack.addText( | |
` ${todaysSunset | |
.getHours() | |
.toString() | |
.replace(/^0(?:0:0?)?/, '')}:${('0' + todaysSunset.getMinutes()).slice( | |
-2 | |
)}` | |
); | |
sunsetLabel.font = Font.mediumRoundedSystemFont(fontSettings.big); | |
sunsetLabel.textColor = sunsetStackColor; | |
list.addSpacer(12); | |
// Address: | |
const geoStack = list.addStack(); | |
addSymbol({ | |
symbolName: 'location.fill', | |
stack: geoStack, | |
color: Color.white(), | |
size: 10, | |
}); | |
const geoLabel = geoStack.addText(` ${address[0].locality.toUpperCase()}`); | |
geoStack.addSpacer(); | |
geoStack.addText(moonIcons[getMoonphase(new Date())]); | |
geoLabel.font = Font.regularRoundedSystemFont(fontSettings.small); | |
geoLabel.textColor = Color.white(); | |
// render | |
return list; | |
} | |
// Locate yourself or use params. | |
async function getLocation() { | |
try { | |
if (args.widgetParameter) { | |
const fixedCoordinates = args.widgetParameter.split(',').map(parseFloat); | |
return { latitude: fixedCoordinates[0], longitude: fixedCoordinates[1] }; | |
} else { | |
Location.setAccuracyToThreeKilometers(); | |
return await Location.current(); | |
} | |
} catch (e) { | |
return null; | |
} | |
} | |
function getMoonphase(dateObj) { | |
// Bluntly copied from https://gist.github.com/endel/dfe6bb2fbe679781948c | |
let c = 0; | |
let e = 0; | |
let jd = 0; | |
let b = 0; | |
let year = dateObj.getFullYear(); | |
let month = dateObj.getMonth() + 1; | |
let day = dateObj.getDate(); | |
if (month < 3) { | |
year--; | |
month += 12; | |
} | |
++month; | |
c = 365.25 * year; | |
e = 30.6 * month; | |
jd = c + e + day - 694039.09; // jd is total days elapsed | |
jd /= 29.5305882; // divide by the moon cycle | |
b = parseInt(jd); // int(jd) -> b, take integer part of jd | |
jd -= b; // subtract integer part to leave fractional part of original jd | |
b = Math.round(jd * 8); // scale fraction from 0-8 and round | |
if (b >= 8) { | |
b = 0; // 0 and 8 are the same so turn 8 into 0 | |
} | |
return b; | |
} | |
// Helps adding icons from SF Symbols. | |
function addSymbol({ | |
symbolName = 'applelogo', | |
stack, | |
color = Color.white(), | |
size = 26, | |
}) { | |
const icon = stack.addImage(SFSymbol.named(symbolName).image); | |
icon.tintColor = color; | |
icon.imageSize = new Size(size, size); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Dies ist ein angepasster Scriptable Code für den neuen iOS 16.x iPhone Lockscreen. Der Code funktioniert für den Sperrbildschirm sowie für den Home-Bildschirm mit einem Widget.