// Auto dark/bright from the sun: dark once it is far enough below the horizon, at the // tablet's own rough location (Android's, not the Orin's: the tablet stands on its own). // Google Maps on this tablet does the same (it reads no light sensor; checked). Needs no // sensor; does not know about tunnels or car parks. import 'dart:math' as math; import 'package:flutter/services.dart'; /// The tablet's newest known location, roughly, from MainActivity; null without one /// (or before location is granted: the first call asks). Future<(double, double)?> androidLocation() async { try { final v = await const MethodChannel('yukart/location') .invokeListMethod('last'); return v == null || v.length < 2 ? null : (v[0], v[1]); } catch (_) { return null; // No Android side (tests, desktop). } } /// Dark while the sun is lower than this (degrees; sunset is -0.8, civil dusk -6). const darkBelowDeg = -4.0; /// The sun's elevation above the horizon, in degrees, at [lat], [lon] (degrees, east /// positive) and [time]. The usual low-precision formulae (the Astronomical Almanac's, /// as NOAA uses them): within about a degree, plenty for this. double sunElevation(double lat, double lon, DateTime time) { double rad(double d) => d * math.pi / 180; double deg(double r) => r * 180 / math.pi; final d = time.toUtc().millisecondsSinceEpoch / 86400000 + 2440587.5 - 2451545.0; final g = rad(357.529 + 0.98560028 * d); // mean anomaly final q = 280.459 + 0.98564736 * d; // mean longitude final l = rad(q + 1.915 * math.sin(g) + 0.020 * math.sin(2 * g)); final e = rad(23.439 - 0.00000036 * d); // obliquity final ra = math.atan2(math.cos(e) * math.sin(l), math.cos(l)); final dec = math.asin(math.sin(e) * math.sin(l)); final gmst = (18.697374558 + 24.06570982441908 * d) % 24; final ha = rad(gmst * 15 + lon) - ra; final phi = rad(lat); return deg( math.asin( math.sin(phi) * math.sin(dec) + math.cos(phi) * math.cos(dec) * math.cos(ha), ), ); }