Compare commits

..
3 Commits
Author SHA1 Message Date
rouggy 32dbfbd04e chore(changelog): open 0.26.20 with the per-radio MY_RIG 2026-08-27 01:09:09 +02:00
rouggy a930a4f02d merge: MY_RIG follows the connected radio
Operating conditions describe a plan; a logged QSO asks which radio was
keying. With one rig those were the same answer, with several they are
not — so each saved radio carries its own MY_RIG, ahead of the per-band
station and doing nothing at all when left empty.
2026-08-27 01:08:19 +02:00
rouggy f98a831195 feat(cat): MY_RIG follows the radio that is connected
With one rig, MY_RIG belonged in Operating conditions and nowhere else.
With several, that becomes the wrong place: operating conditions describe
a PLAN — 'on 20 m I use the beam and the 7300' — while the question a
logged QSO asks is which radio was keying.

So each saved radio carries its own MY_RIG, consulted BEFORE the per-band
station. When the two disagree — a second rig borrowed for one evening on
20 m — the one that is transmitting is the true answer.

Left empty it changes nothing at all: the old chain (band default, then
the profile's rig) answers exactly as it did, which is what every
single-radio station will keep doing without touching a setting.
2026-08-27 01:03:27 +02:00
6 changed files with 67 additions and 3 deletions
+10 -1
View File
@@ -3338,6 +3338,10 @@ func (a *App) applyStationDefaults(q *qso.QSO, includeIdentity bool) {
// Per-band rig/antenna from Operating conditions (the antenna ticked as
// DEFAULT for this band) — the same auto-fill the entry strip does, applied
// here so imported QSOs get MY_RIG / MY_ANTENNA from the band defaults.
// The radio that is CONNECTED names itself first — see activeRadioMyRig.
if q.MyRig == "" {
q.MyRig = a.activeRadioMyRig()
}
if a.operating != nil && q.Band != "" && (q.MyRig == "" || q.MyAntenna == "") {
if d, ok, _ := a.operating.BandDefault(a.ctx, p.ID, q.Band); ok {
if q.MyRig == "" {
@@ -13401,7 +13405,12 @@ func (a *App) LogUDPLoggedADIF(adifText string) (int64, error) {
// ── Operating-conditions stamp ──
// Pre-fill MY_RIG / MY_ANTENNA / TX_PWR from the default antenna for
// this band (if the user has configured Operating conditions).
// this band (if the user has configured Operating conditions) — after the
// connected radio has had its say, since it knows which rig is keying and
// the band default only knows which one was planned.
if q.MyRig == "" {
q.MyRig = a.activeRadioMyRig()
}
if a.operating != nil && a.profiles != nil {
if p, err := a.profiles.Active(a.ctx); err == nil {
if d, ok2, _ := a.operating.BandDefault(a.ctx, p.ID, q.Band); ok2 {
+31
View File
@@ -43,6 +43,14 @@ type RadioConfig struct {
// the CAT panel has always edited, so a saved radio is exactly "what the
// settings said the day it was saved".
Settings CATSettings `json:"settings"`
// MyRig is what goes into MY_RIG on a QSO made with this radio.
//
// It belongs here rather than in Operating conditions once there is more
// than one rig: the operating conditions describe a PLAN — "on 20 m I use
// the beam and the 7300" — while this is the fact of which radio is keying.
// Left empty, nothing changes: the old chain (band default, then the
// profile's rig) answers exactly as it did.
MyRig string `json:"my_rig"`
}
// radioLabel is what the status bar shows when the operator never named one.
@@ -204,3 +212,26 @@ func (a *App) syncActiveRadio(s CATSettings) {
}
}
}
// activeRadioMyRig is the MY_RIG of the radio currently connected, or "".
//
// Consulted BEFORE the per-band default, and deliberately: the band default is
// what the operator planned to use on that band, this is which radio is
// actually on the air. When they disagree — a second rig borrowed for one
// evening on 20 m — the one that is transmitting is the true answer.
func (a *App) activeRadioMyRig() string {
if a.settings == nil || strings.TrimSpace(a.settingOr(keyRadiosList, "")) == "" {
return "" // no list was ever made: nothing to say, nothing changes
}
list, err := a.GetRadios()
if err != nil {
return ""
}
id := a.ActiveRadioID()
for _, r := range list {
if r.ID == id {
return strings.TrimSpace(r.MyRig)
}
}
return ""
}
+10
View File
@@ -1,4 +1,14 @@
[
{
"version": "0.26.20",
"date": "",
"en": [
"Each radio carries its own MY_RIG (Settings → CAT), written on every QSO made with it — ahead of the per-band station in Operating conditions, which says what you planned to use rather than which radio is keying. Left empty, nothing changes."
],
"fr": [
"Chaque radio porte son propre MY_RIG (Réglages → CAT), inscrit sur chaque QSO fait avec elle — avant la station par bande des Conditions de trafic, qui dit ce qui était prévu et non quelle radio émet. Laissé vide, rien ne change."
]
},
{
"version": "0.26.19",
"date": "",
+12
View File
@@ -3266,7 +3266,19 @@ function SettingsModalImpl({ onClose, onSaved, initialSection, onMainPaneChanged
<Trash2 className="size-3.5" />
</Button>
</div>
{/* MY_RIG follows the radio, not the profile.
Operating conditions describe a PLAN "on 20 m I use the beam
and the 7300" while this is the fact of which rig is keying.
Empty leaves the old chain alone. */}
<div className="flex items-center gap-2">
<Label className="shrink-0 w-24">{t('cat.radioMyRig')}</Label>
<Input className="h-9 flex-1" placeholder={t('cat.radioMyRigPh')}
value={(radios.find((r: any) => r.id === activeRadio)?.my_rig) ?? ''}
onChange={(e) => setRadios((l) => l.map((r: any) => r.id === activeRadio ? { ...r, my_rig: e.target.value } : r))}
onBlur={() => { SaveRadios(radios as any).catch(() => {}); }} />
</div>
<p className="text-[11px] text-muted-foreground">{t('cat.radioHint')}</p>
<p className="text-[11px] text-muted-foreground">{t('cat.radioMyRigHint')}</p>
</div>
<label className="flex items-center gap-2 text-sm cursor-pointer">
File diff suppressed because one or more lines are too long
+2
View File
@@ -3573,6 +3573,7 @@ export namespace main {
id: string;
name: string;
settings: CATSettings;
my_rig: string;
static createFrom(source: any = {}) {
return new RadioConfig(source);
@@ -3583,6 +3584,7 @@ export namespace main {
this.id = source["id"];
this.name = source["name"];
this.settings = this.convertValues(source["settings"], CATSettings);
this.my_rig = source["my_rig"];
}
convertValues(a: any, classs: any, asMap: boolean = false): any {