feat(sat): the Satellites tab

Three questions answered at once, because on a pass there is no time to
go looking for any of them: where the bird is, when the next one comes,
and what to tune. The map draws each satellite's footprint — the honest
answer to "can I hear it", since everything inside the circle has the
satellite above its horizon — and the selected one's path over the
ground. The pass list is every favourite in time order, the one in
progress in green.

The readout shows the corrected frequency large and the nominal one
beneath it. Only one of them, and an operator cannot tell a Doppler
correction from a mistuned transponder.

The map opens on the station rather than the Atlantic, and remembers
where it was left like the others. The panel is mounted only while its
tab is visible: it asks for the tuning once a second, and there is no
reason to compute an orbit nobody is looking at.
This commit is contained in:
2026-09-07 10:56:28 +02:00
parent 1009d06a4c
commit 680bf410fe
5 changed files with 526 additions and 1 deletions
+12
View File
@@ -576,6 +576,12 @@ const en: Dict = {
'aud.testPtt': 'Test PTT', 'aud.pttPort': 'PTT COM port', 'aud.pickPort': 'Pick a COM port', 'aud.selectPort': '— select —', 'aud.refresh': 'Refresh',
'aud.msgPlaceholder': 'Message {n} label (CQ, report, 73…)', 'aud.holdRec': '● Hold to rec', 'aud.recordingNow': '● Recording…', 'aud.play': '▶ Play', 'aud.stop': '■ Stop',
'aud.errPttTest': 'PTT test: ', 'aud.errRecord': 'Record: ', 'aud.errSave': 'Save: ', 'aud.errPlay': 'Play: ',
'sat.tab': 'Satellites', 'sat.title': 'Satellites', 'sat.az': 'Azimuth', 'sat.el': 'Elevation', 'sat.down': 'Down', 'sat.up': 'Up',
'sat.nextPasses': 'Next passes', 'sat.noPasses': 'No pass above your minimum elevation in the window — or your locator is not set.', 'sat.now': 'now',
'sat.refreshTle': 'Elements', 'sat.tleAge': '{n} satellites · {h} h old', 'sat.tleNone': 'no elements yet — fetch them', 'sat.tleCustom': '{n} of your own',
'sat.noElements': 'no elements', 'sat.inverting': 'inverting', 'sat.geo': 'geostationary', 'sat.favTip': 'Track this satellite by default',
'sat.paste': 'Paste…', 'sat.pasteTip': 'Paste elements for a satellite no feed carries yet. They are kept in their own file and survive every refresh.',
'sat.pastePrompt': 'Paste the elements (name, then the two lines):', 'sat.pasteNone': 'Nothing usable in that text.',
};
const fr: Dict = {
@@ -1115,6 +1121,12 @@ const fr: Dict = {
'aud.testPtt': 'Tester le PTT', 'aud.pttPort': 'Port COM du PTT', 'aud.pickPort': 'Choisir un port COM', 'aud.selectPort': '— choisir —', 'aud.refresh': 'Actualiser',
'aud.msgPlaceholder': 'Libellé du message {n} (CQ, report, 73…)', 'aud.holdRec': '● Maintenir pour enreg.', 'aud.recordingNow': '● Enregistrement…', 'aud.play': '▶ Lire', 'aud.stop': '■ Arrêter',
'aud.errPttTest': 'Test PTT : ', 'aud.errRecord': 'Enregistrement : ', 'aud.errSave': 'Sauvegarde : ', 'aud.errPlay': 'Lecture : ',
'sat.tab': 'Satellites', 'sat.title': 'Satellites', 'sat.az': 'Azimut', 'sat.el': 'Élévation', 'sat.down': 'Desc.', 'sat.up': 'Mont.',
'sat.nextPasses': 'Prochains passages', 'sat.noPasses': 'Aucun passage au-dessus de votre élévation minimale sur la fenêtre — ou votre locator nest pas renseigné.', 'sat.now': 'en cours',
'sat.refreshTle': 'Éléments', 'sat.tleAge': '{n} satellites · {h} h', 'sat.tleNone': 'aucun élément — récupérez-les', 'sat.tleCustom': 'dont {n} à vous',
'sat.noElements': 'sans éléments', 'sat.inverting': 'inverseur', 'sat.geo': 'géostationnaire', 'sat.favTip': 'Suivre ce satellite par défaut',
'sat.paste': 'Coller…', 'sat.pasteTip': 'Collez les éléments dun satellite quaucun flux ne diffuse encore. Ils sont conservés dans leur propre fichier et survivent à chaque mise à jour.',
'sat.pastePrompt': 'Collez les éléments (nom, puis les deux lignes) :', 'sat.pasteNone': 'Rien dutilisable dans ce texte.',
};
const dicts: Record<Lang, Dict> = { en, fr };
+1 -1
View File
@@ -31,7 +31,7 @@ const PORTABLE_KEYS = [
'opslog.mapView', // Main map: remembered free-pan view (lat/lon/zoom)
// The same, for the FT decodes map and the grid-square map: a view an
// operator set up is theirs, and it should follow the folder like the rest.
'opslog.ftMapView', 'opslog.gridMapView',
'opslog.ftMapView', 'opslog.gridMapView', 'opslog.satMapView',
'opslog.lookupOnBlur', // run the callsign lookup on blur instead of while typing
'opslog.groupDigitalSlots', // matrix + cluster: all digital modes count as ONE (DXCC-style) instead of per-mode slots
'opslog.clusterShowFilters', // cluster filter sidebar shown (tab + Main pane)