Auto dark/bright follows the sun at the tablet's own location
/ crosscheck (push) Successful in 1s
CI / Analyze & Test (push) Successful in 22s
CI / Debug APK (push) Successful in 39s

Without a light sensor an app may read (the Redmi Pad SE has none), auto is dark while
the sun is more than 4° below the horizon (lib/theme/sun.dart), at Android's coarse
location, polled and kept across restarts. The tablet's own, not the Orin's GNSS: the
tablet has its own GNSS and cellular. Android's dark theme is the last fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-15 22:33:43 +09:00
parent 317de3425a
commit 31a844bb94
9 changed files with 164 additions and 19 deletions
+48
View File
@@ -0,0 +1,48 @@
// 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<double>('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),
),
);
}