diff --git a/appearance.go b/appearance.go
index 9262161..62990a2 100644
--- a/appearance.go
+++ b/appearance.go
@@ -33,8 +33,16 @@ type RowColorSettings struct {
// behind it. The stripe says the same thing and costs nothing to read.
Style string `json:"style"`
// Intensity is the tint strength in percent. Only used by "tint"/"both".
- Intensity int `json:"intensity"`
- Rules []RowColorRule `json:"rules"`
+ Intensity int `json:"intensity"`
+ // BandMapLotw marks stations that upload to LoTW on the band map, with the
+ // same "L" badge the cluster list uses — one visual vocabulary across the two
+ // views rather than a second invention.
+ BandMapLotw bool `json:"bandmap_lotw"`
+ // Configured distinguishes "saved with this off" from "saved before the
+ // option existed", so a new marker can default ON without silently turning
+ // itself back on for an operator who switched it off.
+ Configured bool `json:"configured"`
+ Rules []RowColorRule `json:"rules"`
}
// The rule ids, in priority order. The frontend matches on these and holds the
@@ -66,7 +74,13 @@ func normRowColors(s RowColorSettings) RowColorSettings {
for _, r := range s.Rules {
byID[r.ID] = r
}
- out := RowColorSettings{Enabled: s.Enabled, Style: s.Style, Intensity: s.Intensity}
+ out := RowColorSettings{
+ Enabled: s.Enabled, Style: s.Style, Intensity: s.Intensity,
+ BandMapLotw: s.BandMapLotw, Configured: true,
+ }
+ if !s.Configured {
+ out.BandMapLotw = true // new option, on unless the operator says otherwise
+ }
switch out.Style {
case "bar", "tint", "both":
default:
diff --git a/changelog.json b/changelog.json
index 1458abc..6d6ad46 100644
--- a/changelog.json
+++ b/changelog.json
@@ -4,11 +4,13 @@
"date": "",
"en": [
"Appearance: row colouring now defaults to a left stripe, with a filled row and its strength offered as choices.",
- "The band map now follows the cluster filters — LoTW only, spotter continent, hide worked, status and mode chips."
+ "The band map now follows the cluster filters — LoTW only, spotter continent, hide worked, status and mode chips.",
+ "Band map: stations that upload to LoTW now carry the same L badge as the cluster list, switchable in Appearance."
],
"fr": [
"Apparence : la coloration des lignes se fait par défaut sur une barre à gauche, la ligne remplie et son intensité restant proposées.",
- "La band map suit désormais les filtres du cluster — LoTW seulement, continent du spotter, masquer les contactés, statuts et modes."
+ "La band map suit désormais les filtres du cluster — LoTW seulement, continent du spotter, masquer les contactés, statuts et modes.",
+ "Band map : les stations qui utilisent LoTW portent le même badge L que la liste du cluster, activable dans Apparence."
]
},
{
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index eb0b23c..debbf32 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -6800,6 +6800,7 @@ export default function App() {
onClose={() => toggleBandMapBand(b)}
hideDigital={bandMapHideFt}
fitToBand={bandMapFit}
+ showLotw={!!rowColors?.bandmap_lotw}
/>
))}
diff --git a/frontend/src/components/AppearancePanel.tsx b/frontend/src/components/AppearancePanel.tsx
index 94d0735..5f03bf1 100644
--- a/frontend/src/components/AppearancePanel.tsx
+++ b/frontend/src/components/AppearancePanel.tsx
@@ -57,6 +57,12 @@ export function AppearancePanel() {
return (
+
+ save({ ...cfg, bandmap_lotw: !!c } as any)} />
+ {t('appr.bandmapLotw')} {t('appr.bandmapLotwHint')}
+
+
save({ ...cfg, enabled: !!c })} />
diff --git a/frontend/src/components/BandMap.tsx b/frontend/src/components/BandMap.tsx
index 1a4c03a..4596914 100644
--- a/frontend/src/components/BandMap.tsx
+++ b/frontend/src/components/BandMap.tsx
@@ -38,6 +38,9 @@ type SpotStatusEntry = {
new_county?: boolean;
new_pota?: boolean;
new_pfx?: boolean;
+ // Whether the station uploads to LoTW. Not a status — it says nothing about
+ // whether the spot is worth chasing — so it is drawn as a badge, never a colour.
+ lotw?: boolean;
};
// The extra markers are ORTHOGONAL to the entity status: a spot can be a worked
@@ -79,6 +82,8 @@ interface Props {
// globally from the band-map tab toolbar.
hideDigital?: boolean;
fitToBand?: boolean;
+ // Mark stations that upload to LoTW (Settings → Appearance).
+ showLotw?: boolean;
// keyNav enables Ctrl+↑ / Ctrl+↓ to hop to the next spot above / below the rig
// frequency (and tune to it). Only the docked Main-view band map sets this, so
// the multi-band Band Map tab (several maps) doesn't fight over the shortcut.
@@ -227,7 +232,7 @@ const BOT_PAD = 14; // the top-most freq label isn't clipped at y=0
// last; ties broken by closeness to the rig freq).
const MAX_VISIBLE_SPOTS = 30;
-export function BandMap({ band, spots, spotStatus: spotStatusRaw, currentFreqHz, onSpotClick, onClose, side = 'right', onToggleSide, hideDigital = false, fitToBand = false, keyNav = false }: Props) {
+export function BandMap({ band, spots, spotStatus: spotStatusRaw, currentFreqHz, onSpotClick, onClose, side = 'right', onToggleSide, hideDigital = false, fitToBand = false, keyNav = false, showLotw = false }: Props) {
const { t } = useI18n();
// The two display options are applied ONCE here, on the whole map, so the
@@ -649,6 +654,15 @@ export function BandMap({ band, spots, spotStatus: spotStatusRaw, currentFreqHz,
})()}
{p.spot.dx_call}
+ {/* Same badge the cluster list draws, for the same reason: the
+ muted-blue of a confirmation, never a status colour —
+ whether a station uploads to LoTW says nothing about
+ whether the spot is worth chasing. A glyph rather than a
+ colour also keeps it off the channel the statuses use. */}
+ {showLotw && entry?.lotw && (
+ L
+ )}
{mode && (
{mode}
diff --git a/frontend/src/lib/i18n.tsx b/frontend/src/lib/i18n.tsx
index 81502ae..9fc87a7 100644
--- a/frontend/src/lib/i18n.tsx
+++ b/frontend/src/lib/i18n.tsx
@@ -114,7 +114,7 @@ const en: Dict = {
'nav.user': 'User Configuration', 'nav.software': 'Software Configuration', 'nav.hardware': 'Hardware Configuration', 'nav.lists': 'Lists',
'sec.station': 'Station Information', 'sec.profiles': 'Profiles', 'sec.operating': 'Operating conditions',
'sec.confirmations': 'Confirmations', 'sec.external': 'External services',
- 'sec.general': 'General', 'sec.appearance': 'Appearance', 'appr.enable': 'Colour whole rows by QSL status', 'appr.enableHint': '(in the log grid, like Logger32)', 'appr.orderHint': 'A contact is often several of these at once — the first rule that matches decides the colour.', 'appr.confirmedLotw': 'Confirmed on LoTW', 'appr.confirmedPaper': 'Confirmed by card or eQSL', 'appr.sentWaiting': 'Sent, no answer yet', 'appr.toSend': 'Queued to send (card, LoTW or eQSL)', 'appr.custom': 'Pick any colour', 'appr.style': 'Style', 'appr.styleBar': 'Left stripe', 'appr.styleTint': 'Filled row', 'appr.styleBoth': 'Both', 'appr.intensity': 'Strength', 'sec.email': 'E-mail (SMTP)', 'sec.lookup': 'Callsign Lookup',
+ 'sec.general': 'General', 'sec.appearance': 'Appearance', 'appr.enable': 'Colour whole rows by QSL status', 'appr.enableHint': '(in the log grid, like Logger32)', 'appr.orderHint': 'A contact is often several of these at once — the first rule that matches decides the colour.', 'appr.confirmedLotw': 'Confirmed on LoTW', 'appr.confirmedPaper': 'Confirmed by card or eQSL', 'appr.sentWaiting': 'Sent, no answer yet', 'appr.toSend': 'Queued to send (card, LoTW or eQSL)', 'appr.custom': 'Pick any colour', 'appr.style': 'Style', 'appr.styleBar': 'Left stripe', 'appr.styleTint': 'Filled row', 'appr.styleBoth': 'Both', 'appr.intensity': 'Strength', 'appr.bandmapLotw': 'Mark LoTW users on the band map', 'appr.bandmapLotwHint': '(the same L badge the cluster list uses)', 'sec.email': 'E-mail (SMTP)', 'sec.lookup': 'Callsign Lookup',
'sec.bands': 'Bands', 'sec.modes': 'Modes & default RST', 'sec.cluster': 'DX Cluster',
'sec.udp': 'UDP integrations', 'sec.database': 'Database', 'sec.autostart': 'Autostart', 'sec.backup': 'Database backup', 'sec.uscounties': 'US Counties',
'sec.webpublish': 'Web publishing', 'wpub.hint': 'Publishes your log as a file for a website: a standalone HTML page or a CSV, written locally and optionally uploaded by FTP. It is refreshed when you log a QSO and, if you set an interval, on a timer.', 'wpub.enable': 'Publish the log to a file', 'wpub.fileSection': 'The file', 'wpub.format': 'Format', 'wpub.formatHtml': 'HTML page', 'wpub.formatCsv': 'CSV', 'wpub.folder': 'Output folder', 'wpub.browse': 'Browse…', 'wpub.fileName': 'File name', 'wpub.title': 'Page title', 'wpub.titlePh': 'blank = your callsign', 'wpub.count': 'Last N QSOs', 'wpub.every': 'Refresh every', 'wpub.everyHint': 'minutes — 0 = only when a QSO is logged', 'wpub.columns': 'Columns', 'wpub.columnsCount': '{n} of {total} chosen', 'wpub.columnsPick': 'Choose columns…', 'wpub.columnsSearch': 'Search a field…', 'wpub.removeColumn': 'Click to remove', 'wpub.columnsHint': 'Click to add or remove. The order shown here is the order in the file.', 'wpub.ftpEnable': 'Upload by FTP', 'wpub.ftpHost': 'Server / port', 'wpub.ftpUser': 'User', 'wpub.ftpPassword': 'Password', 'wpub.ftpFolder': 'Remote folder', 'wpub.ftpFileName': 'Remote file name', 'wpub.ftpTls': 'Use TLS (FTPS)', 'wpub.publishNow': 'Publish now', 'wpub.testFtp': 'Test connection', 'wpub.lastRun': 'Last run:', 'sec.adifmon': 'ADIF monitor',
@@ -541,7 +541,7 @@ const fr: Dict = {
'nav.user': 'Configuration utilisateur', 'nav.software': 'Configuration logicielle', 'nav.hardware': 'Configuration matérielle', 'nav.lists': 'Listes',
'sec.station': 'Informations station', 'sec.profiles': 'Profils', 'sec.operating': "Conditions d'opération",
'sec.confirmations': 'Confirmations', 'sec.external': 'Services externes',
- 'sec.general': 'Général', 'sec.appearance': 'Apparence', 'appr.enable': 'Colorer les lignes entières selon le statut QSL', 'appr.enableHint': '(dans le tableau du log, comme Logger32)', 'appr.orderHint': "Un contact est souvent plusieurs de ces états à la fois — la première règle qui correspond décide de la couleur.", 'appr.confirmedLotw': 'Confirmé sur LoTW', 'appr.confirmedPaper': 'Confirmé par carte ou eQSL', 'appr.sentWaiting': 'Envoyé, sans réponse', 'appr.toSend': 'En attente d envoi (carte, LoTW ou eQSL)', 'appr.custom': 'Choisir une couleur', 'appr.style': 'Style', 'appr.styleBar': 'Barre à gauche', 'appr.styleTint': 'Ligne remplie', 'appr.styleBoth': 'Les deux', 'appr.intensity': 'Intensité', 'sec.email': 'E-mail (SMTP)', 'sec.lookup': "Recherche d'indicatif",
+ 'sec.general': 'Général', 'sec.appearance': 'Apparence', 'appr.enable': 'Colorer les lignes entières selon le statut QSL', 'appr.enableHint': '(dans le tableau du log, comme Logger32)', 'appr.orderHint': "Un contact est souvent plusieurs de ces états à la fois — la première règle qui correspond décide de la couleur.", 'appr.confirmedLotw': 'Confirmé sur LoTW', 'appr.confirmedPaper': 'Confirmé par carte ou eQSL', 'appr.sentWaiting': 'Envoyé, sans réponse', 'appr.toSend': 'En attente d envoi (carte, LoTW ou eQSL)', 'appr.custom': 'Choisir une couleur', 'appr.style': 'Style', 'appr.styleBar': 'Barre à gauche', 'appr.styleTint': 'Ligne remplie', 'appr.styleBoth': 'Les deux', 'appr.intensity': 'Intensité', 'appr.bandmapLotw': 'Marquer les utilisateurs LoTW sur la band map', 'appr.bandmapLotwHint': '(le même badge L que la liste du cluster)', 'sec.email': 'E-mail (SMTP)', 'sec.lookup': "Recherche d'indicatif",
'sec.bands': 'Bandes', 'sec.modes': 'Modes & RST par défaut', 'sec.cluster': 'DX Cluster',
'sec.udp': 'Intégrations UDP', 'sec.database': 'Base de données', 'sec.autostart': 'Démarrage auto', 'sec.backup': 'Sauvegarde base', 'sec.uscounties': 'Comtés US',
'sec.webpublish': 'Publication web', 'wpub.hint': "Publie ton journal dans un fichier destiné à un site web : une page HTML autonome ou un CSV, écrit en local et envoyé par FTP si tu le souhaites. Il est rafraîchi à chaque QSO enregistré et, si tu règles un intervalle, périodiquement.", 'wpub.enable': 'Publier le journal dans un fichier', 'wpub.fileSection': 'Le fichier', 'wpub.format': 'Format', 'wpub.formatHtml': 'Page HTML', 'wpub.formatCsv': 'CSV', 'wpub.folder': 'Dossier de sortie', 'wpub.browse': 'Parcourir…', 'wpub.fileName': 'Nom du fichier', 'wpub.title': 'Titre de la page', 'wpub.titlePh': 'vide = ton indicatif', 'wpub.count': 'N derniers QSO', 'wpub.every': 'Rafraîchir toutes les', 'wpub.everyHint': 'minutes — 0 = seulement à chaque QSO', 'wpub.columns': 'Colonnes', 'wpub.columnsCount': '{n} sur {total} choisis', 'wpub.columnsPick': 'Choisir les colonnes…', 'wpub.columnsSearch': 'Chercher un champ…', 'wpub.removeColumn': 'Cliquer pour retirer', 'wpub.columnsHint': 'Clique pour ajouter ou retirer. L ordre affiché ici est celui du fichier.', 'wpub.ftpEnable': 'Envoyer par FTP', 'wpub.ftpHost': 'Serveur / port', 'wpub.ftpUser': 'Utilisateur', 'wpub.ftpPassword': 'Mot de passe', 'wpub.ftpFolder': 'Dossier distant', 'wpub.ftpFileName': 'Nom du fichier distant', 'wpub.ftpTls': 'Utiliser TLS (FTPS)', 'wpub.publishNow': 'Publier maintenant', 'wpub.testFtp': 'Tester la connexion', 'wpub.lastRun': 'Dernière exécution :', 'sec.adifmon': 'Moniteur ADIF',
diff --git a/frontend/src/lib/rowColors.ts b/frontend/src/lib/rowColors.ts
index 0af592f..8b07e68 100644
--- a/frontend/src/lib/rowColors.ts
+++ b/frontend/src/lib/rowColors.ts
@@ -9,6 +9,7 @@ export type RowColorSettings = {
enabled: boolean;
style?: 'bar' | 'tint' | 'both';
intensity?: number;
+ bandmap_lotw?: boolean;
rules: RowColorRule[];
};
diff --git a/frontend/wailsjs/go/models.ts b/frontend/wailsjs/go/models.ts
index 2410a05..1bdfb63 100644
--- a/frontend/wailsjs/go/models.ts
+++ b/frontend/wailsjs/go/models.ts
@@ -3012,6 +3012,8 @@ export namespace main {
enabled: boolean;
style: string;
intensity: number;
+ bandmap_lotw: boolean;
+ configured: boolean;
rules: RowColorRule[];
static createFrom(source: any = {}) {
@@ -3023,6 +3025,8 @@ export namespace main {
this.enabled = source["enabled"];
this.style = source["style"];
this.intensity = source["intensity"];
+ this.bandmap_lotw = source["bandmap_lotw"];
+ this.configured = source["configured"];
this.rules = this.convertValues(source["rules"], RowColorRule);
}