feat(appearance): four QSL categories, each scoped to chosen channels
Replaces the four fixed rules with the model Logger32 uses and the operator asked for: Worked / Confirmed / QSL sent / To be sent, and inside each, which channels count — paper QSL, LoTW, eQSL, QRZ.com. No ticks means every channel, because a rule the operator has not narrowed must not quietly become a rule about nothing. "To be sent" is FIRST in the order, and that is the substantive decision here. A contact can be confirmed on LoTW and still owe a paper card; the colour an operator scans for is the one meaning "something is still owed". Placed after "confirmed" that row goes green and the card never gets printed. "Worked" is the catch-all — nothing sent, nothing requested, nothing back — and is off by default, since turning it on paints every remaining row. R and Q both count as owed: ADIF says requested and queued, and both mean the card has not gone out.
This commit is contained in:
+41
-8
@@ -19,8 +19,16 @@ type RowColorRule struct {
|
||||
ID string `json:"id"`
|
||||
Color string `json:"color"`
|
||||
Enabled bool `json:"enabled"`
|
||||
// Channels this rule looks at: qsl (paper), lotw, eqsl, qrz.
|
||||
//
|
||||
// Empty means ALL of them — what an operator expects from a rule they have
|
||||
// not narrowed, and what keeps a config written before this field meaningful.
|
||||
Channels []string `json:"channels"`
|
||||
}
|
||||
|
||||
// The QSL channels a rule can be scoped to.
|
||||
var rowColorChannels = []string{"qsl", "lotw", "eqsl", "qrz"}
|
||||
|
||||
// RowColorSettings is the whole appearance block.
|
||||
type RowColorSettings struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
@@ -47,21 +55,30 @@ type RowColorSettings struct {
|
||||
|
||||
// The rule ids, in priority order. The frontend matches on these and holds the
|
||||
// labels, so a translated name never has to travel through the settings.
|
||||
// The four categories, in the order they are tested — first match wins.
|
||||
//
|
||||
// "To send" comes FIRST on purpose. A contact can be confirmed on LoTW and
|
||||
// still owe a paper card, and the colour an operator scans for is the one that
|
||||
// means "there is something left to do here". Put after "confirmed", that row
|
||||
// would go green and the card would never be printed.
|
||||
//
|
||||
// "Worked" is the catch-all: a contact with nothing sent, nothing asked for and
|
||||
// nothing back. Off by default — with it on, every remaining row is painted.
|
||||
var rowColorOrder = []string{
|
||||
"confirmed_lotw", // LoTW confirmation received
|
||||
"confirmed_paper", // card or eQSL received
|
||||
"sent_waiting", // sent by some route, nothing back yet
|
||||
"to_send", // a card is requested / queued and has not gone out
|
||||
"to_send", // requested or queued on a watched channel, not gone out
|
||||
"confirmed", // a watched channel has a confirmation back
|
||||
"sent", // gone out on a watched channel, nothing back yet
|
||||
"worked", // none of the above
|
||||
}
|
||||
|
||||
// Defaults: green for done, amber for waiting, blue for owed. Deliberately
|
||||
// muted — they are composited at low opacity over a dark grid, and a saturated
|
||||
// value there reads as an error state rather than a status.
|
||||
var rowColorDefaults = map[string]string{
|
||||
"confirmed_lotw": "#16a34a",
|
||||
"confirmed_paper": "#0ea5e9",
|
||||
"sent_waiting": "#f59e0b",
|
||||
"to_send": "#a855f7",
|
||||
"to_send": "#a855f7",
|
||||
"confirmed": "#16a34a",
|
||||
"sent": "#f59e0b",
|
||||
"worked": "#64748b",
|
||||
}
|
||||
|
||||
// hexColor guards what reaches the stylesheet. The value is interpolated into a
|
||||
@@ -94,12 +111,28 @@ func normRowColors(s RowColorSettings) RowColorSettings {
|
||||
} else if out.Intensity > 45 {
|
||||
out.Intensity = 45
|
||||
}
|
||||
ok := map[string]bool{}
|
||||
for _, c := range rowColorChannels {
|
||||
ok[c] = true
|
||||
}
|
||||
for _, id := range rowColorOrder {
|
||||
r := byID[id]
|
||||
r.ID = id
|
||||
if !hexColor.MatchString(strings.TrimSpace(r.Color)) {
|
||||
r.Color = rowColorDefaults[id]
|
||||
}
|
||||
// Keep only channels we know, in the canonical order, de-duplicated.
|
||||
want := map[string]bool{}
|
||||
for _, c := range r.Channels {
|
||||
want[strings.ToLower(strings.TrimSpace(c))] = true
|
||||
}
|
||||
chans := []string{}
|
||||
for _, c := range rowColorChannels {
|
||||
if want[c] {
|
||||
chans = append(chans, c)
|
||||
}
|
||||
}
|
||||
r.Channels = chans
|
||||
out.Rules = append(out.Rules, r)
|
||||
}
|
||||
return out
|
||||
|
||||
Reference in New Issue
Block a user