fix(street-level): re-check an unknown key, Esc leaves full screen, say why a view is empty

- A failed or missing key status is asked again on the next switch-on, and
  the check gives up after 10 s instead of holding LOADING forever.
- Waiting for the key status reads as LOADING while the layer is on.
- Esc shrinks the photo in full screen too, before the panel's own Esc.
- Destroying the panel with the iPhone popover open leaves no popover behind.
- An empty view says whether the filter emptied it.
- A freed upstream tile slot passes straight to the oldest waiter.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
German KhokhlovandClaude Opus 5.5 committed 2026-10-08 18:25:16 +04:00
1 parent d313b6e62c
commit 8e5e3cdd3b
10 files changed
+201 -30

No files matched your search

+12 -10
View File
@@ -94,9 +94,14 @@ let upstreamActive = 0;
/** @type {Array<() => void>} fetches waiting for a slot, oldest first */
const upstreamWaiting = [];
/** Run `task` once an upstream slot is free, unless `signal` aborts first. */
/**
* Run `task` in an upstream slot, waiting for one unless `signal` aborts
* first. A freed slot passes straight to the oldest waiter, still counted, so
* a request arriving meanwhile cannot take it first.
*/
async function withUpstreamSlot(signal, task) {
while (upstreamActive >= TILE_UPSTREAM_CONCURRENCY)
if (upstreamActive < TILE_UPSTREAM_CONCURRENCY) upstreamActive++;
else
await new Promise((resolve, reject) => {
const wake = () => {
signal.removeEventListener('abort', leave);
@@ -110,17 +115,14 @@ async function withUpstreamSlot(signal, task) {
upstreamWaiting.push(wake);
signal.addEventListener('abort', leave, { once: true });
});
if (signal.aborted) {
// Woken, then left: hand the free slot on.
upstreamWaiting.shift()?.();
throw signal.reason;
}
upstreamActive++;
try {
// Handed a slot after leaving: it goes on to the next waiter.
signal.throwIfAborted();
return await task();
} finally {
upstreamActive--;
upstreamWaiting.shift()?.();
const next = upstreamWaiting.shift();
if (next) next();
else upstreamActive--;
}
}