chore(ui): temporary Android WebView boot diagnostic (test contour only) #176

Merged
developer merged 7 commits from feature/webview-boot-diagnostic into development 2026-07-04 20:36:05 +00:00
Showing only changes of commit 8499f388af - Show all commits
+25 -19
View File
@@ -228,16 +228,11 @@
let sy = 0; let sy = 0;
let sl = 0; let sl = 0;
let st = 0; let st = 0;
const onDown = (e: PointerEvent) => { // Track the drag on window rather than vp.setPointerCapture. Capturing the pointer on the very
if (e.pointerType === 'touch' || e.button !== 0 || !zoomed) return; // element being scrolled makes an older Chromium — the Chrome 74 Android 10 System WebView —
if ((e.target as HTMLElement | null)?.closest('.cell.pending')) return; // drop or displace the capture as scrollLeft/Top are written mid-drag, so the board judders and
armed = true; // will not pan. Window listeners give the same "keep receiving moves past the element edge"
panning = false; // without capturing the scroll container; modern engines behave identically.
sx = e.clientX;
sy = e.clientY;
sl = vp.scrollLeft;
st = vp.scrollTop;
};
const onMove = (e: PointerEvent) => { const onMove = (e: PointerEvent) => {
if (!armed) return; if (!armed) return;
const dx = e.clientX - sx; const dx = e.clientX - sx;
@@ -245,16 +240,17 @@
if (!panning) { if (!panning) {
if (Math.hypot(dx, dy) < 4) return; // a small move is still a click, not a pan if (Math.hypot(dx, dy) < 4) return; // a small move is still a click, not a pan
panning = true; panning = true;
vp.setPointerCapture(e.pointerId);
} }
vp.scrollLeft = sl - dx; vp.scrollLeft = sl - dx;
vp.scrollTop = st - dy; vp.scrollTop = st - dy;
}; };
const onUp = (e: PointerEvent) => { const onUp = () => {
window.removeEventListener('pointermove', onMove);
window.removeEventListener('pointerup', onUp);
window.removeEventListener('pointercancel', onUp);
armed = false; armed = false;
if (!panning) return; if (!panning) return;
panning = false; panning = false;
if (vp.hasPointerCapture(e.pointerId)) vp.releasePointerCapture(e.pointerId);
// Swallow the click the drag would otherwise produce (capture phase, before it reaches the // Swallow the click the drag would otherwise produce (capture phase, before it reaches the
// cell); self-remove on that click, and clean up on the next tick if none fired. // cell); self-remove on that click, and clean up on the next tick if none fired.
const swallow = (ev: Event) => { const swallow = (ev: Event) => {
@@ -264,15 +260,25 @@
vp.addEventListener('click', swallow, true); vp.addEventListener('click', swallow, true);
setTimeout(() => vp.removeEventListener('click', swallow, true), 0); setTimeout(() => vp.removeEventListener('click', swallow, true), 0);
}; };
const onDown = (e: PointerEvent) => {
if (e.pointerType === 'touch' || e.button !== 0 || !zoomed) return;
if ((e.target as HTMLElement | null)?.closest('.cell.pending')) return;
armed = true;
panning = false;
sx = e.clientX;
sy = e.clientY;
sl = vp.scrollLeft;
st = vp.scrollTop;
window.addEventListener('pointermove', onMove);
window.addEventListener('pointerup', onUp);
window.addEventListener('pointercancel', onUp);
};
vp.addEventListener('pointerdown', onDown); vp.addEventListener('pointerdown', onDown);
vp.addEventListener('pointermove', onMove);
vp.addEventListener('pointerup', onUp);
vp.addEventListener('pointercancel', onUp);
return () => { return () => {
vp.removeEventListener('pointerdown', onDown); vp.removeEventListener('pointerdown', onDown);
vp.removeEventListener('pointermove', onMove); window.removeEventListener('pointermove', onMove);
vp.removeEventListener('pointerup', onUp); window.removeEventListener('pointerup', onUp);
vp.removeEventListener('pointercancel', onUp); window.removeEventListener('pointercancel', onUp);
}; };
}); });