Skip to content

Commit 1c04cb1

Browse files
authored
Bump mobile to 1.1.13 and improve photo map detail visibility (#6)
1 parent 63f4ae0 commit 1c04cb1

6 files changed

Lines changed: 119 additions & 15 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.1.13] — 2026-02-22
9+
10+
### Fixed
11+
- Corrected preview contact interpolation so C1/C2/C3/C4 remain geometrically consistent even when the moon track has a non-zero closest-approach offset.
12+
- Improved satellite/hybrid map readability by reducing eclipse overlay opacity in photo map modes and forcing map remount when switching map type to refresh tile detail loading.
13+
14+
### Changed
15+
- Bumped `apps/mobile` version to `1.1.13`.
16+
17+
### Tests
18+
- Added a regression test that verifies C1/C4 tangency remains exact for partial eclipse preview geometry with non-zero closest approach and directional travel.
19+
820
## [1.1.12] — 2026-02-22
921

1022
### Changed

apps/mobile/app.config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ if (typeof packageVersion !== "string" || !/^\d+\.\d+\.\d+$/.test(packageVersion
1414

1515
expo.version = packageVersion;
1616
expo.runtimeVersion = packageVersion;
17+
expo.extra = {
18+
...expo.extra,
19+
googleMapsAndroidApiKeyConfigured: Boolean(googleMapsAndroidApiKey),
20+
};
1721

1822
if (!googleMapsAndroidApiKey) {
1923
console.warn(

apps/mobile/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@eclipse-timer/mobile",
3-
"version": "1.1.12",
3+
"version": "1.1.13",
44
"private": true,
55
"main": "index.js",
66
"scripts": {

apps/mobile/src/screens/TimerScreen.tsx

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ function normalizeLongitudeDeg(lonDeg: number) {
8989
return (((lonDeg % 360) + 540) % 360) - 180;
9090
}
9191

92+
function mapTypeLabel(mapType: TimerState["mapType"]) {
93+
if (mapType === "satellite") return "Satellite";
94+
if (mapType === "hybrid") return "Hybrid";
95+
return "Standard";
96+
}
97+
9298
function destinationPoint(
9399
latDeg: number,
94100
lonDeg: number,
@@ -182,6 +188,13 @@ export default function TimerScreen({
182188
: activeKindCode === "H"
183189
? "Central Path"
184190
: "Totality Path";
191+
const isPhotoMapMode = timer.mapType !== "standard";
192+
const visibleOverlayColor = isPhotoMapMode ? "rgba(79, 195, 247, 0.12)" : VISIBLE_PATH_COLOR;
193+
const activeCentralOverlayColor = isPhotoMapMode
194+
? activeKindCode === "A"
195+
? "rgba(255, 167, 38, 0.16)"
196+
: "rgba(255, 82, 82, 0.16)"
197+
: centralOverlayColor;
185198
const favoriteAtCurrentPin = useMemo(
186199
() =>
187200
favoriteLocations.find((location) =>
@@ -242,6 +255,7 @@ export default function TimerScreen({
242255
timer.result,
243256
]);
244257
const hasDirectionsData = contactDirectionOverlays.length > 0;
258+
const mapTypeText = mapTypeLabel(timer.mapType);
245259

246260
const closeAddFavoriteModal = () => {
247261
setIsAddFavoriteModalOpen(false);
@@ -341,19 +355,24 @@ export default function TimerScreen({
341355

342356
<View style={styles.mapWrap}>
343357
<MapView
358+
key={`map-${timer.mapType}`}
344359
ref={timer.mapRef}
345360
style={styles.map}
346361
region={timer.region}
347362
onRegionChangeComplete={timer.onRegionChangeComplete}
348363
onPress={timer.onMapPress}
349364
mapType={timer.mapType}
365+
showsBuildings
366+
showsCompass
367+
showsIndoors
368+
showsPointsOfInterest
350369
>
351370
{timer.showVisibleOverlay
352371
? timer.overlayVisiblePolygons.map((coordinates, idx) => (
353372
<Polygon
354373
key={`visible-${idx}`}
355374
coordinates={coordinates}
356-
fillColor={VISIBLE_PATH_COLOR}
375+
fillColor={visibleOverlayColor}
357376
strokeColor="rgba(79, 195, 247, 0.05)"
358377
strokeWidth={0.5}
359378
/>
@@ -364,7 +383,7 @@ export default function TimerScreen({
364383
<Polygon
365384
key={`central-${idx}`}
366385
coordinates={coordinates}
367-
fillColor={centralOverlayColor}
386+
fillColor={activeCentralOverlayColor}
368387
strokeColor="rgba(255,255,255,0.08)"
369388
strokeWidth={0.5}
370389
/>
@@ -438,15 +457,18 @@ export default function TimerScreen({
438457
</Pressable>
439458

440459
<Pressable style={styles.mapOverlayBtn} onPress={timer.cycleMapType}>
441-
<Text style={styles.mapOverlayBtnText}>
442-
{timer.mapType === "standard"
443-
? "Standard"
444-
: timer.mapType === "satellite"
445-
? "Satellite"
446-
: "Hybrid"}
447-
</Text>
460+
<Text style={styles.mapOverlayBtnText}>{mapTypeText}</Text>
448461
</Pressable>
449462

463+
{timer.mapType !== "standard" ? (
464+
<View style={styles.mapModeHint}>
465+
<Text style={styles.mapModeHintText}>
466+
If satellite/hybrid tiles look old or blank on Android, rebuild with
467+
GOOGLE_MAPS_ANDROID_API_KEY in apps/mobile/.env.local.
468+
</Text>
469+
</View>
470+
) : null}
471+
450472
<View style={styles.mapLegend}>
451473
<Pressable
452474
style={[
@@ -464,7 +486,7 @@ export default function TimerScreen({
464486
}
465487
>
466488
<View style={styles.mapLegendRow}>
467-
<View style={[styles.mapLegendSwatch, { backgroundColor: VISIBLE_PATH_COLOR }]} />
489+
<View style={[styles.mapLegendSwatch, { backgroundColor: visibleOverlayColor }]} />
468490
<Text style={styles.mapLegendText}>Eclipse Visible</Text>
469491
</View>
470492
<Text style={styles.mapLegendState}>{timer.showVisibleOverlay ? "On" : "Off"}</Text>
@@ -484,7 +506,9 @@ export default function TimerScreen({
484506
}
485507
>
486508
<View style={styles.mapLegendRow}>
487-
<View style={[styles.mapLegendSwatch, { backgroundColor: centralOverlayColor }]} />
509+
<View
510+
style={[styles.mapLegendSwatch, { backgroundColor: activeCentralOverlayColor }]}
511+
/>
488512
<Text style={styles.mapLegendText}>{centralLegendLabel}</Text>
489513
</View>
490514
<Text style={styles.mapLegendState}>{timer.showCentralOverlay ? "On" : "Off"}</Text>
@@ -948,6 +972,21 @@ const styles = StyleSheet.create({
948972
fontWeight: "700",
949973
fontSize: 12,
950974
},
975+
mapModeHint: {
976+
position: "absolute",
977+
top: 52,
978+
right: 10,
979+
maxWidth: 230,
980+
borderRadius: 10,
981+
paddingHorizontal: 10,
982+
paddingVertical: 6,
983+
backgroundColor: "rgba(0,0,0,0.72)",
984+
},
985+
mapModeHintText: {
986+
color: "#d2d2d2",
987+
fontSize: 11,
988+
lineHeight: 14,
989+
},
951990
mapGpsBtn: {
952991
position: "absolute",
953992
top: 10,

apps/mobile/src/utils/previewGeometry.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,18 @@ function buildMotionAnchors(
128128
contacts: PreviewMotionContacts,
129129
sunRadius: number,
130130
moonRadius: number,
131+
moonClosestOffset: number,
131132
): Array<{ progress: number; offsetX: number }> {
132-
const externalTouchOffset = sunRadius + moonRadius;
133-
const internalTouchOffset = Math.abs(sunRadius - moonRadius);
133+
const axisDistanceForTouchOffset = (touchOffset: number) => {
134+
const radialSq = touchOffset * touchOffset;
135+
const closestSq = moonClosestOffset * moonClosestOffset;
136+
const axisSq = radialSq - closestSq;
137+
if (!Number.isFinite(axisSq) || axisSq <= 0) return 0;
138+
return Math.sqrt(axisSq);
139+
};
140+
141+
const externalTouchOffset = axisDistanceForTouchOffset(sunRadius + moonRadius);
142+
const internalTouchOffset = axisDistanceForTouchOffset(Math.abs(sunRadius - moonRadius));
134143

135144
const anchors: Array<{ progress: number; offsetX: number }> = [
136145
{ progress: 0, offsetX: -externalTouchOffset },
@@ -195,7 +204,12 @@ export function calculatePreviewMoonGeometry(params: {
195204
sunRadius,
196205
);
197206

198-
const anchors = buildMotionAnchors(params.contacts ?? {}, sunRadius, moonRadius);
207+
const anchors = buildMotionAnchors(
208+
params.contacts ?? {},
209+
sunRadius,
210+
moonRadius,
211+
moonClosestOffset,
212+
);
199213
const axisOffset = interpolateOffsetX(params.progress, anchors);
200214
const travelVector = params.travelVector ?? { x: 1, y: 0 };
201215
const moonOffsetX = axisOffset * travelVector.x - moonClosestOffset * travelVector.y;

apps/mobile/tests/preview-geometry.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,39 @@ describe("preview moon geometry", () => {
9595
);
9696
expect(describePreviewTravelDirection({ x: -0.7, y: 0.1 })).toBe("right to left");
9797
});
98+
99+
it("keeps C1 and C4 as tangency even with non-zero closest approach", () => {
100+
const travelVector = determinePreviewTravelVector({
101+
c1BearingDeg: 230,
102+
c4BearingDeg: 30,
103+
});
104+
105+
const c1Geometry = calculatePreviewMoonGeometry({
106+
progress: 0,
107+
kindAtLocation: "partial",
108+
magnitude: 0.72,
109+
contacts: { c1: 0, max: 0.5, c4: 1 },
110+
travelVector,
111+
});
112+
const c4Geometry = calculatePreviewMoonGeometry({
113+
progress: 1,
114+
kindAtLocation: "partial",
115+
magnitude: 0.72,
116+
contacts: { c1: 0, max: 0.5, c4: 1 },
117+
travelVector,
118+
});
119+
120+
const stageCenter = 150;
121+
const c1Distance = Math.hypot(
122+
c1Geometry.moonCenterX - stageCenter,
123+
c1Geometry.moonCenterY - stageCenter,
124+
);
125+
const c4Distance = Math.hypot(
126+
c4Geometry.moonCenterX - stageCenter,
127+
c4Geometry.moonCenterY - stageCenter,
128+
);
129+
130+
expect(c1Distance).toBeCloseTo(PREVIEW_SUN_RADIUS + c1Geometry.moonRadius, 6);
131+
expect(c4Distance).toBeCloseTo(PREVIEW_SUN_RADIUS + c4Geometry.moonRadius, 6);
132+
});
98133
});

0 commit comments

Comments
 (0)