Skip to content

Instantly share code, notes, and snippets.

@Leibinger015
Last active November 23, 2022 10:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Leibinger015/93f27b6cea99493c47197078e7424f7e to your computer and use it in GitHub Desktop.
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.
// 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);
}
@Leibinger015
Copy link
Author

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.
E60C4F68-0F39-4118-9814-0AC1426F2620

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment