surface SMTP delivery failures and add interactive rotor compass target

This commit is contained in:
Deploy
2026-04-08 03:08:53 +02:00
parent e95519a4ea
commit 2bcf6ab1e5
6 changed files with 257 additions and 27 deletions

View File

@@ -11,6 +11,7 @@ let activationWatchInFlight = false;
let activationPending = false;
let remainingUsageTimer = null;
let resumeRefreshInFlight = false;
let rotorCompassDragPointerId = null;
const state = {
user: null,
@@ -716,6 +717,51 @@ function bindEvents() {
await setOpenWebRxRotor();
});
}
if (els.rotorCompass) {
els.rotorCompass.addEventListener("pointerdown", (event) => {
if (!els.rotorTarget || els.rotorTarget.disabled) {
return;
}
if (event.pointerType === "mouse" && event.button !== 0) {
return;
}
event.preventDefault();
rotorCompassDragPointerId = event.pointerId;
if (typeof els.rotorCompass.setPointerCapture === "function") {
try {
els.rotorCompass.setPointerCapture(event.pointerId);
} catch {
// ignore pointer capture errors
}
}
els.rotorCompass.classList.add("is-dragging");
updateRotorTargetFromPointerEvent(event);
});
els.rotorCompass.addEventListener("pointermove", (event) => {
if (rotorCompassDragPointerId !== event.pointerId) {
return;
}
event.preventDefault();
updateRotorTargetFromPointerEvent(event);
});
const stopRotorCompassDrag = (event) => {
if (rotorCompassDragPointerId !== event.pointerId) {
return;
}
if (typeof els.rotorCompass.releasePointerCapture === "function") {
try {
els.rotorCompass.releasePointerCapture(event.pointerId);
} catch {
// ignore pointer capture errors
}
}
rotorCompassDragPointerId = null;
els.rotorCompass.classList.remove("is-dragging");
};
els.rotorCompass.addEventListener("pointerup", stopRotorCompassDrag);
els.rotorCompass.addEventListener("pointercancel", stopRotorCompassDrag);
els.rotorCompass.addEventListener("lostpointercapture", stopRotorCompassDrag);
}
if (els.openwebrxBandSetBtn) {
els.openwebrxBandSetBtn.addEventListener("click", async () => {
await setOpenWebRxBand();
@@ -2031,6 +2077,43 @@ async function setOpenWebRxRotor() {
}
}
function normalizeCompassAzimuth(value) {
return ((Number(value) % 360) + 360) % 360;
}
function rotorTargetBounds() {
const rotor = state.openWebRx && state.openWebRx.rotor ? state.openWebRx.rotor : null;
const min = rotor && Number.isFinite(Number(rotor.min)) ? Number(rotor.min) : 0;
const max = rotor && Number.isFinite(Number(rotor.max)) ? Number(rotor.max) : 360;
return {
min: Math.min(min, max),
max: Math.max(min, max)
};
}
function updateRotorTargetFromPointerEvent(event) {
if (!els.rotorCompass || !els.rotorTarget) {
return;
}
const rect = els.rotorCompass.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const pointerX = Number(event.clientX);
const pointerY = Number(event.clientY);
if (!Number.isFinite(pointerX) || !Number.isFinite(pointerY)) {
return;
}
const dx = pointerX - centerX;
const dy = pointerY - centerY;
if (Math.abs(dx) < 0.5 && Math.abs(dy) < 0.5) {
return;
}
const azimuth = normalizeCompassAzimuth((Math.atan2(dx, -dy) * 180) / Math.PI);
const bounds = rotorTargetBounds();
const clamped = Math.min(bounds.max, Math.max(bounds.min, Math.round(azimuth)));
els.rotorTarget.value = String(clamped);
}
function renderRotorState() {
if (!els.rotorCurrent) {
return;