feat(watchlist): header counters, mode filter — and the alert checks worked FIRST

DXHunter's header row, ported: Watchlist / Active / Needed counts up front and
the All-Modes select beside the other filters (DIGI matches the digital class,
SSB folds USB/LSB). Counters, card lists and the Active/Needed-only filters all
read the same mode-filtered view, so the numbers add up to what is on screen.

And the notify alert now asks the SAME worked-slot question the tab asks —
before making a sound. It used to fire on the raw spot while the tab's verdict
arrived on a debounce, so the bell rang for a slot that showed Worked a moment
later. Judged in the backend at emit time: exact slot for named modes, digital
class for generic DATA, today-only for contest entries.
This commit is contained in:
2026-08-29 01:03:37 +02:00
parent cb2f8aba72
commit 441eb295c6
4 changed files with 65 additions and 5 deletions
+2 -2
View File
@@ -39,7 +39,7 @@ const en: Dict = {
'cwd.tipOnIdle': 'CW decoder — on, idle until CW mode · click to disable',
'cwd.tipOff': 'CW decoder · click to enable (decodes RX audio in CW mode)',
'tools.watchlist': 'Watchlist…', 'tab.watchlist': 'Watchlist',
'wl.addPh': 'Callsign or prefix', 'wl.add': 'Add', 'wl.contest': 'Contest', 'wl.addAsContest': 'as contest', 'wl.patternPh': 'Auto (WWA)', 'wl.patternHint': 'Auto-add as contest: any spotted callsign CONTAINING this text joins the watchlist as a contest entry by itself. Empty = off; collected entries stay.',
'wl.addPh': 'Callsign or prefix', 'wl.add': 'Add', 'wl.contest': 'Contest', 'wl.addAsContest': 'as contest', 'wl.cTotal': 'Watchlist:', 'wl.cActive': 'Active:', 'wl.cNeeded': 'Needed:', 'wl.allModes': 'All modes', 'wl.modeFilter': 'Only show spots in this mode', 'wl.patternPh': 'Auto (WWA)', 'wl.patternHint': 'Auto-add as contest: any spotted callsign CONTAINING this text joins the watchlist as a contest entry by itself. Empty = off; collected entries stay.',
'wl.contestHint': 'Contest station: worked/needed is judged against the current UTC day — at 00:00 UTC every slot can be worked again.',
'wl.searchPh': 'Search…', 'wl.famAll': 'All', 'wl.famNormal': 'DX', 'wl.famContest': 'Contest',
'wl.activeOnly': 'Active only', 'wl.neededOnly': 'Needed only',
@@ -563,7 +563,7 @@ const fr: Dict = {
'cwd.tipOnIdle': 'Décodeur CW — actif, en veille hors mode CW · clic pour désactiver',
'cwd.tipOff': 'Décodeur CW · clic pour activer (décode laudio RX en mode CW)',
'tools.watchlist': 'Watchlist…', 'tab.watchlist': 'Watchlist',
'wl.addPh': 'Indicatif ou préfixe', 'wl.add': 'Ajouter', 'wl.contest': 'Contest', 'wl.addAsContest': 'comme contest', 'wl.patternPh': 'Auto (WWA)', 'wl.patternHint': "Ajout auto comme contest : tout indicatif spotté CONTENANT ce texte rejoint la watchlist en entrée contest tout seul. Vide = désactivé ; les entrées déjà collectées restent.",
'wl.addPh': 'Indicatif ou préfixe', 'wl.add': 'Ajouter', 'wl.contest': 'Contest', 'wl.addAsContest': 'comme contest', 'wl.cTotal': 'Watchlist :', 'wl.cActive': 'Actives :', 'wl.cNeeded': 'Manquantes :', 'wl.allModes': 'Tous les modes', 'wl.modeFilter': 'Ne montrer que les spots de ce mode', 'wl.patternPh': 'Auto (WWA)', 'wl.patternHint': "Ajout auto comme contest : tout indicatif spotté CONTENANT ce texte rejoint la watchlist en entrée contest tout seul. Vide = désactivé ; les entrées déjà collectées restent.",
'wl.contestHint': "Station contest : contacté/manquant est jugé sur la journée UTC courante — à 00:00 UTC chaque créneau redevient à faire.",
'wl.searchPh': 'Chercher…', 'wl.famAll': 'Tous', 'wl.famNormal': 'DX', 'wl.famContest': 'Contest',
'wl.activeOnly': 'Actifs seulement', 'wl.neededOnly': 'Manquants seulement',