mirror of
https://github.com/smittix/intercept.git
synced 2026-05-27 02:04:45 -07:00
Fix BT Locate startup/map rendering and CelesTrak import reliability
This commit is contained in:
@@ -38,6 +38,7 @@ const BtLocate = (function() {
|
||||
let lastRenderedDetectionKey = null;
|
||||
let pendingHeatSync = false;
|
||||
let mapStabilizeTimer = null;
|
||||
let modeActive = false;
|
||||
|
||||
const MAX_HEAT_POINTS = 1200;
|
||||
const MAX_TRAIL_POINTS = 1200;
|
||||
@@ -85,6 +86,7 @@ const BtLocate = (function() {
|
||||
}
|
||||
|
||||
function init() {
|
||||
modeActive = true;
|
||||
loadOverlayPreferences();
|
||||
syncOverlayControls();
|
||||
|
||||
@@ -92,7 +94,7 @@ const BtLocate = (function() {
|
||||
// Re-invalidate map on re-entry and ensure tiles are present
|
||||
if (map) {
|
||||
setTimeout(() => {
|
||||
safeInvalidateMap();
|
||||
safeInvalidateMap(true);
|
||||
// Re-apply user's tile layer if tiles were lost
|
||||
let hasTiles = false;
|
||||
map.eachLayer(layer => {
|
||||
@@ -142,7 +144,7 @@ const BtLocate = (function() {
|
||||
flushPendingHeatSync();
|
||||
});
|
||||
setTimeout(() => {
|
||||
safeInvalidateMap();
|
||||
safeInvalidateMap(true);
|
||||
flushPendingHeatSync();
|
||||
}, 100);
|
||||
scheduleMapStabilization();
|
||||
@@ -158,10 +160,10 @@ const BtLocate = (function() {
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
function checkStatus() {
|
||||
fetch('/bt_locate/status')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
function checkStatus() {
|
||||
fetch('/bt_locate/status')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.active) {
|
||||
sessionStartedAt = data.started_at ? new Date(data.started_at).getTime() : Date.now();
|
||||
showActiveUI();
|
||||
@@ -171,12 +173,22 @@ const BtLocate = (function() {
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
function start() {
|
||||
const mac = document.getElementById('btLocateMac')?.value.trim();
|
||||
const namePattern = document.getElementById('btLocateNamePattern')?.value.trim();
|
||||
const irk = document.getElementById('btLocateIrk')?.value.trim();
|
||||
}
|
||||
|
||||
function normalizeMacInput(value) {
|
||||
const raw = (value || '').trim().toUpperCase().replace(/-/g, ':');
|
||||
if (!raw) return '';
|
||||
const compact = raw.replace(/[^0-9A-F]/g, '');
|
||||
if (compact.length === 12) {
|
||||
return compact.match(/.{1,2}/g).join(':');
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
function start() {
|
||||
const mac = normalizeMacInput(document.getElementById('btLocateMac')?.value);
|
||||
const namePattern = document.getElementById('btLocateNamePattern')?.value.trim();
|
||||
const irk = document.getElementById('btLocateIrk')?.value.trim();
|
||||
|
||||
const body = { environment: currentEnvironment };
|
||||
if (mac) body.mac_address = mac;
|
||||
@@ -205,13 +217,25 @@ const BtLocate = (function() {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('/bt_locate/start', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
fetch('/bt_locate/start', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
.then(async (r) => {
|
||||
let data = null;
|
||||
try {
|
||||
data = await r.json();
|
||||
} catch (_) {
|
||||
data = {};
|
||||
}
|
||||
if (!r.ok || data.status !== 'started') {
|
||||
const message = data.error || data.message || ('HTTP ' + r.status);
|
||||
throw new Error(message);
|
||||
}
|
||||
return data;
|
||||
})
|
||||
.then(data => {
|
||||
if (data.status === 'started') {
|
||||
sessionStartedAt = data.session?.started_at ? new Date(data.session.started_at).getTime() : Date.now();
|
||||
showActiveUI();
|
||||
@@ -224,8 +248,12 @@ const BtLocate = (function() {
|
||||
restoreTrail();
|
||||
}
|
||||
})
|
||||
.catch(err => console.error('[BtLocate] Start error:', err));
|
||||
}
|
||||
.catch(err => {
|
||||
console.error('[BtLocate] Start error:', err);
|
||||
alert('BT Locate failed to start: ' + (err?.message || 'Unknown error'));
|
||||
showIdleUI();
|
||||
});
|
||||
}
|
||||
|
||||
function stop() {
|
||||
fetch('/bt_locate/stop', { method: 'POST' })
|
||||
@@ -888,7 +916,10 @@ const BtLocate = (function() {
|
||||
if (!map) return;
|
||||
ensureHeatLayer();
|
||||
if (!heatLayer) return;
|
||||
if (!isMapContainerVisible()) {
|
||||
if (!modeActive || !isMapContainerVisible()) {
|
||||
if (map.hasLayer(heatLayer)) {
|
||||
map.removeLayer(heatLayer);
|
||||
}
|
||||
pendingHeatSync = true;
|
||||
return;
|
||||
}
|
||||
@@ -918,6 +949,40 @@ const BtLocate = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function setActiveMode(active) {
|
||||
modeActive = !!active;
|
||||
if (!map) return;
|
||||
|
||||
if (!modeActive) {
|
||||
stopMapStabilization();
|
||||
if (heatLayer && map.hasLayer(heatLayer)) {
|
||||
map.removeLayer(heatLayer);
|
||||
}
|
||||
pendingHeatSync = true;
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (!modeActive) return;
|
||||
safeInvalidateMap(true);
|
||||
if (typeof window.requestAnimationFrame === 'function') {
|
||||
window.requestAnimationFrame(() => {
|
||||
if (!modeActive) return;
|
||||
safeInvalidateMap(true);
|
||||
window.requestAnimationFrame(() => {
|
||||
if (!modeActive) return;
|
||||
safeInvalidateMap(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
syncHeatLayer();
|
||||
syncMovementLayer();
|
||||
syncStrongestMarker();
|
||||
updateConfidenceLayer();
|
||||
scheduleMapStabilization(14);
|
||||
}, 80);
|
||||
}
|
||||
|
||||
function isMapRenderable() {
|
||||
if (!map || !isMapContainerVisible()) return false;
|
||||
if (typeof map.getSize === 'function') {
|
||||
@@ -927,9 +992,26 @@ const BtLocate = (function() {
|
||||
return true;
|
||||
}
|
||||
|
||||
function safeInvalidateMap() {
|
||||
function refreshBaseTiles() {
|
||||
if (!map || typeof L === 'undefined' || typeof map.eachLayer !== 'function') return;
|
||||
map.eachLayer((layer) => {
|
||||
if (layer instanceof L.TileLayer && typeof layer.redraw === 'function') {
|
||||
try {
|
||||
layer.redraw();
|
||||
} catch (_) {}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function safeInvalidateMap(forceRecenter = false) {
|
||||
if (!map || !isMapContainerVisible()) return false;
|
||||
map.invalidateSize({ pan: false, animate: false });
|
||||
map.invalidateSize({ pan: !!forceRecenter, animate: false });
|
||||
if (forceRecenter) {
|
||||
const center = map.getCenter();
|
||||
const zoom = map.getZoom();
|
||||
map.setView(center, zoom, { animate: false });
|
||||
}
|
||||
refreshBaseTiles();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -950,7 +1032,7 @@ const BtLocate = (function() {
|
||||
stopMapStabilization();
|
||||
return;
|
||||
}
|
||||
if (safeInvalidateMap()) {
|
||||
if (safeInvalidateMap(true)) {
|
||||
flushPendingHeatSync();
|
||||
syncMovementLayer();
|
||||
syncStrongestMarker();
|
||||
@@ -1624,7 +1706,7 @@ const BtLocate = (function() {
|
||||
}
|
||||
|
||||
function invalidateMap() {
|
||||
if (safeInvalidateMap()) {
|
||||
if (safeInvalidateMap(true)) {
|
||||
flushPendingHeatSync();
|
||||
syncMovementLayer();
|
||||
syncStrongestMarker();
|
||||
@@ -1633,10 +1715,11 @@ const BtLocate = (function() {
|
||||
scheduleMapStabilization(8);
|
||||
}
|
||||
|
||||
return {
|
||||
init,
|
||||
start,
|
||||
stop,
|
||||
return {
|
||||
init,
|
||||
setActiveMode,
|
||||
start,
|
||||
stop,
|
||||
handoff,
|
||||
clearHandoff,
|
||||
setEnvironment,
|
||||
@@ -1651,4 +1734,6 @@ const BtLocate = (function() {
|
||||
invalidateMap,
|
||||
fetchPairedIrks,
|
||||
};
|
||||
})();
|
||||
})();
|
||||
|
||||
window.BtLocate = BtLocate;
|
||||
|
||||
Reference in New Issue
Block a user