feat: QSO rate meter (10/60 min) in the header
Opt-in via Settings→General (portable pref opslog.showQsoRate). Shows the contest-style QSO rate in QSOs/hour, projected from the trailing 10-minute (count ×6) and 60-minute windows, between the widget icons and propagation. Backend: qso.RecentRate counts QSOs whose start time falls in each trailing window, scanning only the last 400 rows (cheap on a large log); App.GetQSORate exposes the 10/60-min counts. Frontend refreshes on qso:logged and a 30s tick. The meter shares the propagation grid cell — the header is a fixed 6-column grid, so adding it as its own child pushed profile/band-map/compact onto a second row. i18n EN + FR.
This commit is contained in:
@@ -4501,6 +4501,27 @@ func (a *App) GetOperators() ([]string, error) {
|
||||
return a.qso.Operators(a.ctx)
|
||||
}
|
||||
|
||||
// QSORate is the live QSO-rate meter shown in the header: how many QSOs were
|
||||
// logged in the trailing 10 and 60 minutes.
|
||||
type QSORate struct {
|
||||
Last10 int `json:"last10"`
|
||||
Last60 int `json:"last60"`
|
||||
}
|
||||
|
||||
// GetQSORate returns the number of QSOs logged in the last 10 and 60 minutes.
|
||||
// Cheap (scans only the most recent rows); polled by the header and refreshed on
|
||||
// each qso:logged event.
|
||||
func (a *App) GetQSORate() QSORate {
|
||||
if a.qso == nil {
|
||||
return QSORate{}
|
||||
}
|
||||
counts, err := a.qso.RecentRate(a.ctx, time.Now(), 10*time.Minute, 60*time.Minute)
|
||||
if err != nil || len(counts) < 2 {
|
||||
return QSORate{}
|
||||
}
|
||||
return QSORate{Last10: counts[0], Last60: counts[1]}
|
||||
}
|
||||
|
||||
// GetContestRuns lists the (contest, year) pairs actually present in the log, so
|
||||
// the Statistics picker only ever offers contests you really entered.
|
||||
func (a *App) GetContestRuns() ([]qso.ContestRun, error) {
|
||||
|
||||
Reference in New Issue
Block a user