mirror of
https://github.com/smittix/intercept.git
synced 2026-06-13 08:13:32 -07:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ec316fbe2 |
@@ -2,6 +2,15 @@
|
|||||||
|
|
||||||
All notable changes to iNTERCEPT will be documented in this file.
|
All notable changes to iNTERCEPT will be documented in this file.
|
||||||
|
|
||||||
|
## [2.21.1] - 2026-02-20
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- BT Locate map first-load rendering race that could cause blank/late map initialization
|
||||||
|
- BT Locate mode switch timing so Leaflet invalidation runs after panel visibility settles
|
||||||
|
- BT Locate trail restore startup latency by batching historical GPS point rendering
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [2.21.0] - 2026-02-20
|
## [2.21.0] - 2026-02-20
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -7,10 +7,19 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
# Application version
|
# Application version
|
||||||
VERSION = "2.21.0"
|
VERSION = "2.21.1"
|
||||||
|
|
||||||
# Changelog - latest release notes (shown on welcome screen)
|
# Changelog - latest release notes (shown on welcome screen)
|
||||||
CHANGELOG = [
|
CHANGELOG = [
|
||||||
|
{
|
||||||
|
"version": "2.21.1",
|
||||||
|
"date": "February 2026",
|
||||||
|
"highlights": [
|
||||||
|
"BT Locate map first-load fix with render stabilization retries during initial mode open",
|
||||||
|
"BT Locate trail restore optimization for faster startup when historical GPS points exist",
|
||||||
|
"BT Locate mode-switch map invalidation timing fix to prevent delayed/blank map render",
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "2.21.0",
|
"version": "2.21.0",
|
||||||
"date": "February 2026",
|
"date": "February 2026",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "intercept"
|
name = "intercept"
|
||||||
version = "2.21.0"
|
version = "2.21.1"
|
||||||
description = "Signal Intelligence Platform - Pager/433MHz/ADS-B/Satellite/WiFi/Bluetooth"
|
description = "Signal Intelligence Platform - Pager/433MHz/ADS-B/Satellite/WiFi/Bluetooth"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.9"
|
requires-python = ">=3.9"
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ const BtLocate = (function() {
|
|||||||
let smoothingEnabled = true;
|
let smoothingEnabled = true;
|
||||||
let lastRenderedDetectionKey = null;
|
let lastRenderedDetectionKey = null;
|
||||||
let pendingHeatSync = false;
|
let pendingHeatSync = false;
|
||||||
|
let mapStabilizeTimer = null;
|
||||||
|
|
||||||
const MAX_HEAT_POINTS = 1200;
|
const MAX_HEAT_POINTS = 1200;
|
||||||
const MAX_TRAIL_POINTS = 1200;
|
const MAX_TRAIL_POINTS = 1200;
|
||||||
@@ -44,6 +45,8 @@ const BtLocate = (function() {
|
|||||||
const OUTLIER_HARD_JUMP_METERS = 2000;
|
const OUTLIER_HARD_JUMP_METERS = 2000;
|
||||||
const OUTLIER_SOFT_JUMP_METERS = 450;
|
const OUTLIER_SOFT_JUMP_METERS = 450;
|
||||||
const OUTLIER_MAX_SPEED_MPS = 50;
|
const OUTLIER_MAX_SPEED_MPS = 50;
|
||||||
|
const MAP_STABILIZE_INTERVAL_MS = 150;
|
||||||
|
const MAP_STABILIZE_ATTEMPTS = 28;
|
||||||
const OVERLAY_STORAGE_KEYS = {
|
const OVERLAY_STORAGE_KEYS = {
|
||||||
heatmap: 'btLocateHeatmapEnabled',
|
heatmap: 'btLocateHeatmapEnabled',
|
||||||
movement: 'btLocateMovementEnabled',
|
movement: 'btLocateMovementEnabled',
|
||||||
@@ -99,6 +102,7 @@ const BtLocate = (function() {
|
|||||||
Settings.createTileLayer().addTo(map);
|
Settings.createTileLayer().addTo(map);
|
||||||
}
|
}
|
||||||
flushPendingHeatSync();
|
flushPendingHeatSync();
|
||||||
|
scheduleMapStabilization(10);
|
||||||
}, 150);
|
}, 150);
|
||||||
}
|
}
|
||||||
checkStatus();
|
checkStatus();
|
||||||
@@ -113,15 +117,23 @@ const BtLocate = (function() {
|
|||||||
zoom: 2,
|
zoom: 2,
|
||||||
zoomControl: true,
|
zoomControl: true,
|
||||||
});
|
});
|
||||||
|
let tileLayer = null;
|
||||||
// Use tile provider from user settings
|
// Use tile provider from user settings
|
||||||
if (typeof Settings !== 'undefined' && Settings.createTileLayer) {
|
if (typeof Settings !== 'undefined' && Settings.createTileLayer) {
|
||||||
Settings.createTileLayer().addTo(map);
|
tileLayer = Settings.createTileLayer();
|
||||||
|
tileLayer.addTo(map);
|
||||||
Settings.registerMap(map);
|
Settings.registerMap(map);
|
||||||
} else {
|
} else {
|
||||||
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
tileLayer = L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
||||||
maxZoom: 19,
|
maxZoom: 19,
|
||||||
attribution: '© OSM © CARTO'
|
attribution: '© OSM © CARTO'
|
||||||
}).addTo(map);
|
});
|
||||||
|
tileLayer.addTo(map);
|
||||||
|
}
|
||||||
|
if (tileLayer && typeof tileLayer.on === 'function') {
|
||||||
|
tileLayer.on('load', () => {
|
||||||
|
scheduleMapStabilization(8);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
ensureHeatLayer();
|
ensureHeatLayer();
|
||||||
syncMovementLayer();
|
syncMovementLayer();
|
||||||
@@ -133,6 +145,7 @@ const BtLocate = (function() {
|
|||||||
safeInvalidateMap();
|
safeInvalidateMap();
|
||||||
flushPendingHeatSync();
|
flushPendingHeatSync();
|
||||||
}, 100);
|
}, 100);
|
||||||
|
scheduleMapStabilization();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init RSSI chart canvas
|
// Init RSSI chart canvas
|
||||||
@@ -524,6 +537,8 @@ const BtLocate = (function() {
|
|||||||
const lon = Number(point.lon);
|
const lon = Number(point.lon);
|
||||||
if (!isFinite(lat) || !isFinite(lon)) return false;
|
if (!isFinite(lat) || !isFinite(lon)) return false;
|
||||||
if (!shouldAcceptMapPoint(point, lat, lon)) return false;
|
if (!shouldAcceptMapPoint(point, lat, lon)) return false;
|
||||||
|
const suppressFollow = options.suppressFollow === true;
|
||||||
|
const bulkLoad = options.bulkLoad === true;
|
||||||
|
|
||||||
const trailPoint = normalizeTrailPoint(point, lat, lon);
|
const trailPoint = normalizeTrailPoint(point, lat, lon);
|
||||||
const band = (trailPoint.proximity_band || 'FAR').toLowerCase();
|
const band = (trailPoint.proximity_band || 'FAR').toLowerCase();
|
||||||
@@ -563,13 +578,17 @@ const BtLocate = (function() {
|
|||||||
if (heatPoints.length > MAX_HEAT_POINTS) {
|
if (heatPoints.length > MAX_HEAT_POINTS) {
|
||||||
heatPoints.splice(0, heatPoints.length - MAX_HEAT_POINTS);
|
heatPoints.splice(0, heatPoints.length - MAX_HEAT_POINTS);
|
||||||
}
|
}
|
||||||
|
if (bulkLoad) {
|
||||||
|
pendingHeatSync = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
syncHeatLayer();
|
syncHeatLayer();
|
||||||
|
|
||||||
if (!isMapRenderable()) {
|
if (!isMapRenderable()) {
|
||||||
safeInvalidateMap();
|
safeInvalidateMap();
|
||||||
}
|
}
|
||||||
const canFollowMap = isMapRenderable();
|
const canFollowMap = isMapRenderable();
|
||||||
if (autoFollowEnabled && !options.suppressFollow && canFollowMap) {
|
if (autoFollowEnabled && !suppressFollow && canFollowMap) {
|
||||||
if (!gpsLocked) {
|
if (!gpsLocked) {
|
||||||
gpsLocked = true;
|
gpsLocked = true;
|
||||||
map.setView([lat, lon], Math.max(map.getZoom(), 16));
|
map.setView([lat, lon], Math.max(map.getZoom(), 16));
|
||||||
@@ -645,8 +664,13 @@ const BtLocate = (function() {
|
|||||||
|
|
||||||
const gpsTrail = Array.isArray(trail.gps_trail) ? trail.gps_trail : [];
|
const gpsTrail = Array.isArray(trail.gps_trail) ? trail.gps_trail : [];
|
||||||
const allTrail = Array.isArray(trail.trail) ? trail.trail : [];
|
const allTrail = Array.isArray(trail.trail) ? trail.trail : [];
|
||||||
|
const recentGpsTrail = gpsTrail.slice(-MAX_TRAIL_POINTS);
|
||||||
|
|
||||||
gpsTrail.forEach(p => addMapMarker(p, { suppressFollow: true }));
|
recentGpsTrail.forEach(p => addMapMarker(p, {
|
||||||
|
suppressFollow: true,
|
||||||
|
bulkLoad: true,
|
||||||
|
}));
|
||||||
|
syncHeatLayer();
|
||||||
|
|
||||||
if (allTrail.length > 0) {
|
if (allTrail.length > 0) {
|
||||||
rssiHistory = allTrail.map(p => p.rssi).filter(v => typeof v === 'number' && isFinite(v)).slice(-MAX_RSSI_POINTS);
|
rssiHistory = allTrail.map(p => p.rssi).filter(v => typeof v === 'number' && isFinite(v)).slice(-MAX_RSSI_POINTS);
|
||||||
@@ -659,7 +683,7 @@ const BtLocate = (function() {
|
|||||||
drawRssiChart();
|
drawRssiChart();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStats(allTrail.length, gpsTrail.length);
|
updateStats(allTrail.length, recentGpsTrail.length);
|
||||||
|
|
||||||
if (trailPoints.length > 0 && map) {
|
if (trailPoints.length > 0 && map) {
|
||||||
const latestGps = trailPoints[trailPoints.length - 1];
|
const latestGps = trailPoints[trailPoints.length - 1];
|
||||||
@@ -675,6 +699,7 @@ const BtLocate = (function() {
|
|||||||
syncStrongestMarker();
|
syncStrongestMarker();
|
||||||
updateConfidenceLayer();
|
updateConfidenceLayer();
|
||||||
updateMovementStats();
|
updateMovementStats();
|
||||||
|
scheduleMapStabilization(12);
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
@@ -908,6 +933,45 @@ const BtLocate = (function() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stopMapStabilization() {
|
||||||
|
if (mapStabilizeTimer) {
|
||||||
|
clearInterval(mapStabilizeTimer);
|
||||||
|
mapStabilizeTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleMapStabilization(attempts = MAP_STABILIZE_ATTEMPTS) {
|
||||||
|
if (!map) return;
|
||||||
|
stopMapStabilization();
|
||||||
|
let remaining = Math.max(1, Number(attempts) || MAP_STABILIZE_ATTEMPTS);
|
||||||
|
|
||||||
|
const tick = () => {
|
||||||
|
if (!map) {
|
||||||
|
stopMapStabilization();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (safeInvalidateMap()) {
|
||||||
|
flushPendingHeatSync();
|
||||||
|
syncMovementLayer();
|
||||||
|
syncStrongestMarker();
|
||||||
|
updateConfidenceLayer();
|
||||||
|
if (isMapRenderable()) {
|
||||||
|
stopMapStabilization();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
remaining -= 1;
|
||||||
|
if (remaining <= 0) {
|
||||||
|
stopMapStabilization();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
tick();
|
||||||
|
if (map && !mapStabilizeTimer && !isMapRenderable()) {
|
||||||
|
mapStabilizeTimer = setInterval(tick, MAP_STABILIZE_INTERVAL_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function flushPendingHeatSync() {
|
function flushPendingHeatSync() {
|
||||||
if (!pendingHeatSync) return;
|
if (!pendingHeatSync) return;
|
||||||
syncHeatLayer();
|
syncHeatLayer();
|
||||||
@@ -1566,6 +1630,7 @@ const BtLocate = (function() {
|
|||||||
syncStrongestMarker();
|
syncStrongestMarker();
|
||||||
updateConfidenceLayer();
|
updateConfidenceLayer();
|
||||||
}
|
}
|
||||||
|
scheduleMapStabilization(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -4242,6 +4242,12 @@
|
|||||||
SubGhz.init();
|
SubGhz.init();
|
||||||
} else if (mode === 'bt_locate') {
|
} else if (mode === 'bt_locate') {
|
||||||
BtLocate.init();
|
BtLocate.init();
|
||||||
|
setTimeout(() => {
|
||||||
|
if (typeof BtLocate !== 'undefined' && BtLocate.invalidateMap) BtLocate.invalidateMap();
|
||||||
|
}, 100);
|
||||||
|
setTimeout(() => {
|
||||||
|
if (typeof BtLocate !== 'undefined' && BtLocate.invalidateMap) BtLocate.invalidateMap();
|
||||||
|
}, 320);
|
||||||
} else if (mode === 'spaceweather') {
|
} else if (mode === 'spaceweather') {
|
||||||
SpaceWeather.init();
|
SpaceWeather.init();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user