diff --git a/app.go b/app.go index ba89f2d..8aa8b6f 100644 --- a/app.go +++ b/app.go @@ -753,6 +753,9 @@ type App struct { // is consulted once per message. chaseBandsMu sync.RWMutex chaseBands map[string]bool + // The Chase new panel's OWN band filter, as the set switched off. Read per + // message like the list above, so an atomic rather than a settings lookup. + chaseNewBandsOff atomic.Value // map[string]bool // pskr is the PSK Reporter MQTT feed, up only while the opening watch is on. // It is the source that makes VHF detection work at all: the cluster and RBN // carry a handful of 6 m spots where PSK Reporter carries hundreds. @@ -773,8 +776,12 @@ type App struct { // FT8 window and an FT4 one do not even share a period length — and one // buffer for both cut every slot into fragments, each judged as a period of // its own. The engine then counted a missed period several times a slot. - acPeriod map[string]string - acAt map[string]time.Time + acPeriod map[string]string + acAt map[string]time.Time + // acFed is when the last decode of the open period ARRIVED, wall clock. The + // period's own timestamp cannot answer "has it gone quiet" — it is the start + // of the slot, thirteen seconds before its decodes exist. + acFed map[string]time.Time acTR map[string]int acBuf map[string][]acDecode acTX autocall.TXState @@ -782,6 +789,10 @@ type App struct { acLastJudge time.Time // acTXPeriod is the last transmit period already counted — see autoCallNoteTX. acTXPeriod string + // What the decodes panel is SHOWING, and whether it is publishing at all. + // The panel owns the filters; this is its answer, not a second copy of them. + acVisible map[string]bool + acVisibleOn bool // Self-spot throttle: when and on what frequency we last announced ourselves. // Held in memory only — a restart legitimately re-announces the station. selfSpotMu sync.Mutex @@ -1653,6 +1664,7 @@ func (a *App) startup(ctx context.Context) { a.startGridCache() a.chaseNew = newChaseNewStore() a.refreshChaseNew() + a.refreshChaseNewBands() // PSK Reporter. After the operator's grid is known: without it there is no // distance to measure and no receiver squares to filter on, so it stays down. a.startBandOpenFeed() @@ -20578,6 +20590,15 @@ func (a *App) SaveChaseSettings(cs ChaseSettings) error { a.clusterStatusMu.Lock() a.clusterStatusIdx = nil a.clusterStatusMu.Unlock() + // Chase new judges each decode AS IT ARRIVES and keeps only what was new at + // that moment, so its list is a set of verdicts reached under the old rule — + // and nothing in it would ever be re-judged. Switching to "new only" left + // rows listed that are merely unconfirmed; switching the other way could not + // bring back what had already been refused. Emptied, it refills from the + // live feed within a period or two, under the rule now in force. + if a.chaseNew != nil { + a.chaseNew.clear() + } // The frontend caches resolved verdicts and only asks about unknown keys — // without this it kept judging half the screen under the OLD rules until a // restart, which read as the new mode simply not working. diff --git a/frontend/wailsjs/go/main/App.d.ts b/frontend/wailsjs/go/main/App.d.ts index a667b07..82b4831 100644 --- a/frontend/wailsjs/go/main/App.d.ts +++ b/frontend/wailsjs/go/main/App.d.ts @@ -454,6 +454,8 @@ export function GetChangelog():Promise>; export function GetChaseNew():Promise; +export function GetChaseNewBands():Promise>; + export function GetChaseNewGrids():Promise; export function GetChaseNewSpots():Promise>; @@ -654,6 +656,8 @@ export function GetYaesuState():Promise; export function GridSquares(arg1:string):Promise>; +export function HaltAutoCall():Promise; + export function HaltDecodeTx(arg1:string,arg2:boolean):Promise; export function HasBuiltinReferences(arg1:string):Promise; @@ -1158,6 +1162,8 @@ export function SetAutoCall(arg1:boolean):Promise; export function SetAutoCallOnly(arg1:string):Promise; +export function SetAutoCallVisible(arg1:Array,arg2:boolean):Promise; + export function SetCATFrequency(arg1:number):Promise; export function SetCATMode(arg1:string):Promise; @@ -1168,6 +1174,8 @@ export function SetCWDecoderPitch(arg1:number):Promise; export function SetChaseNew(arg1:boolean):Promise; +export function SetChaseNewBands(arg1:Array):Promise; + export function SetChaseNewGrids(arg1:boolean):Promise; export function SetClublogCtyEnabled(arg1:boolean):Promise; diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js index 74e5f7e..4f4713b 100644 --- a/frontend/wailsjs/go/main/App.js +++ b/frontend/wailsjs/go/main/App.js @@ -842,6 +842,10 @@ export function GetChaseNew() { return window['go']['main']['App']['GetChaseNew'](); } +export function GetChaseNewBands() { + return window['go']['main']['App']['GetChaseNewBands'](); +} + export function GetChaseNewGrids() { return window['go']['main']['App']['GetChaseNewGrids'](); } @@ -1242,6 +1246,10 @@ export function GridSquares(arg1) { return window['go']['main']['App']['GridSquares'](arg1); } +export function HaltAutoCall() { + return window['go']['main']['App']['HaltAutoCall'](); +} + export function HaltDecodeTx(arg1, arg2) { return window['go']['main']['App']['HaltDecodeTx'](arg1, arg2); } @@ -2250,6 +2258,10 @@ export function SetAutoCallOnly(arg1) { return window['go']['main']['App']['SetAutoCallOnly'](arg1); } +export function SetAutoCallVisible(arg1, arg2) { + return window['go']['main']['App']['SetAutoCallVisible'](arg1, arg2); +} + export function SetCATFrequency(arg1) { return window['go']['main']['App']['SetCATFrequency'](arg1); } @@ -2270,6 +2282,10 @@ export function SetChaseNew(arg1) { return window['go']['main']['App']['SetChaseNew'](arg1); } +export function SetChaseNewBands(arg1) { + return window['go']['main']['App']['SetChaseNewBands'](arg1); +} + export function SetChaseNewGrids(arg1) { return window['go']['main']['App']['SetChaseNewGrids'](arg1); } diff --git a/frontend/wailsjs/go/models.ts b/frontend/wailsjs/go/models.ts index 8a202b4..53685a0 100644 --- a/frontend/wailsjs/go/models.ts +++ b/frontend/wailsjs/go/models.ts @@ -1962,6 +1962,8 @@ export namespace main { misses: number; max_rounds: number; rest_min: number; + on_screen_only: boolean; + trace: boolean; static createFrom(source: any = {}) { return new AutoCallSettings(source); @@ -1976,6 +1978,8 @@ export namespace main { this.misses = source["misses"]; this.max_rounds = source["max_rounds"]; this.rest_min = source["rest_min"]; + this.on_screen_only = source["on_screen_only"]; + this.trace = source["trace"]; } } export class AutoCallStatus { @@ -1987,6 +1991,7 @@ export namespace main { misses: number; max_miss: number; stopped: boolean; + greylisted: number; reason: string; static createFrom(source: any = {}) { @@ -2003,6 +2008,7 @@ export namespace main { this.misses = source["misses"]; this.max_miss = source["max_miss"]; this.stopped = source["stopped"]; + this.greylisted = source["greylisted"]; this.reason = source["reason"]; } } @@ -4962,6 +4968,8 @@ export namespace pskr { last_err?: string; broker: string; bands: string[]; + near_km: number; + squares: number; static createFrom(source: any = {}) { return new Status(source); @@ -4975,6 +4983,8 @@ export namespace pskr { this.last_err = source["last_err"]; this.broker = source["broker"]; this.bands = source["bands"]; + this.near_km = source["near_km"]; + this.squares = source["squares"]; } convertValues(a: any, classs: any, asMap: boolean = false): any {