feat(cluster): "already worked only on the same slot" option

New DX Cluster setting (Settings → DX Cluster). Off (today's behaviour) a call
worked anywhere reads as already worked; on, the WORKED-call flag needs the same
band AND mode. It folds through the digital-mode grouping (Settings → General):
grouped, a 20m FT8 contact also marks a 20m FT4 spot worked; ungrouped they are
separate slots. Backend: qso.WorkedCallSlotKeys builds CALL|band and
CALL|band|mode(grouped) keys; ClusterSpotStatuses uses them when the option is on
(a spot with no inferable mode falls back to same-band).
This commit is contained in:
2026-08-05 14:11:06 +02:00
parent f91b83ee12
commit d0f25aea9b
5 changed files with 80 additions and 3 deletions
+30
View File
@@ -2163,6 +2163,36 @@ func (r *Repo) WorkedCallBandModeKeys(ctx context.Context) (map[string]struct{},
return out, rows.Err()
}
// WorkedCallSlotKeys backs the cluster "already worked only on the same slot"
// option. It returns each worked slot keyed BOTH as "CALL|band" (mode-agnostic,
// for a spot whose mode couldn't be inferred) and "CALL|band|MODE" with the mode
// run through normMode — so when digital grouping is on, FT8/FT4/RTTY fold into
// one "DIG" and a call worked on 20m FT8 also matches a 20m FT4 spot. Call is
// upper-cased and band lower-cased to match the spot keys ClusterSpotStatuses
// builds. normMode may be nil (no grouping).
func (r *Repo) WorkedCallSlotKeys(ctx context.Context, normMode func(string) string) (map[string]struct{}, error) {
rows, err := r.db.QueryContext(ctx,
`SELECT upper(callsign), lower(band), upper(mode) FROM qso
WHERE callsign != '' AND band IS NOT NULL AND band != '' AND mode IS NOT NULL AND mode != ''`)
if err != nil {
return nil, err
}
defer rows.Close()
out := make(map[string]struct{}, 4096)
for rows.Next() {
var c, b, m string
if err := rows.Scan(&c, &b, &m); err != nil {
return nil, err
}
if normMode != nil {
m = normMode(m)
}
out[c+"|"+b] = struct{}{}
out[c+"|"+b+"|"+m] = struct{}{}
}
return out, rows.Err()
}
// WorkedPOTARefs returns the set of POTA park references already worked
// (upper-cased). A QSO's pota_ref may hold several comma-separated parks
// (an n-fer); each is added separately.