Street Level: leave an interrupted link and an overtaken view alone (gekh review)

- A pasted or start-up link opens its photos only when its restore's camera
  landed: a drag or search during the restore flight keeps the camera.
- A posted view whose photo step was cancelled or superseded no longer closes
  the viewer or flies; one that found a photo it could not load keeps the error.
- openNearest gains `replace` (keep the open photo while it looks, close it
  only when nothing opens, so EXPAND stays) and `proceed()` (asked before a
  found photo loads); the action uses both, so a navigation, a gesture or a
  hiding mode during the lookup loads no billed panorama.
- Mapillary's timeout message is a msg() string with all eleven translations.
This commit is contained in:
Said Turksever committed 2026-11-10 15:12:50 +00:00
1 parent 5370b8a268
commit 9c73939425
22 files changed
+329 -17

No files matched your search

+15 -3
View File
@@ -268,8 +268,14 @@ export async function applyView(
streetLevelArgs(view.street_level, { autoOpen }),
);
if (result?.ok !== true) {
// Overtaken (a click on the map, a newer request): the panel and the
// camera are someone else's now.
if (result?.cancelled || result?.superseded) return steps;
// An earlier view's photo must not stay over a place this view left.
dataManager.layers?.get?.(STREET_LEVEL_LAYER)?.module?.closeViewer?.();
// From the imagery stage on the action has settled the panel itself:
// a photo it found but could not load keeps its error in view.
if (result?.stage !== 'imagery')
dataManager.layers?.get?.(STREET_LEVEL_LAYER)?.module?.closeViewer?.();
if (!result?.location)
steps.push({ step: 'camera', ok: await flyTo(viewer, view.camera) });
}
@@ -332,11 +338,16 @@ export function installViews({
// link must not fly over them.
// A start-up restore that a newer link superseded hands the camera to that
// link: its own steps never run.
// A restore whose camera never landed (the recipient dragged, searched or
// opened another place during its flight) leaves the camera with them.
const cameraLanded = (outcome) => outcome?.share?.camera === 'applied';
let generationAtRestore = null;
let startSuperseded = false;
let queue = ready.then((outcome) => {
generationAtRestore = shell._navigationGeneration;
startSuperseded = outcome?.status === 'superseded';
startSuperseded =
outcome?.status === 'superseded' ||
(Boolean(outcome?.share) && !cameraLanded(outcome));
});
const navigatedSince = (generation) =>
Number.isFinite(generation) && shell._navigationGeneration !== generation;
@@ -397,7 +408,8 @@ export function installViews({
// its photos follow once that restore settles, under the same rule: a plain
// link never loads a billed photo by itself.
const onNavigatedRestore = (event) => {
if (event?.detail?.status !== 'settled') return;
if (event?.detail?.status !== 'settled' || !cameraLanded(event.detail))
return;
const streetLevel = linkedStreetLevel(
new URLSearchParams(String(location?.hash || '').replace(/^#/, '')),
);