Add 50/70 MHz band support (table, NOT-QRV, station setup, loggers)

Issue #68

Adds Band.B_50/B_70 and wires them through the same band-opportunity
machinery as the other bands: X/a/B+/o table columns and filter button
in the User table and the Workedstn database table, NOT-QRV checkboxes
and propagation across callsign variants, "My station uses 6m/4m band"
toggles, station-name detection ("50", "6M", "70MHZ", "4M" - without
stealing the existing bare "70"/"6" cm-band shorthand), Win-Test sked
band IDs (10/50MHz, 11/70MHz), and UCX-logger worked-band recognition.

Persists worked50/70 and notQRV50/70 via an additive SQLite migration
(same ensureColumnExists pattern as the earlier v1.1->v1.2 migration),
verified against a real database file.

ReachabilityService.resolveAutoBand() now also falls back to 50 MHz
(then 70 MHz) for stations in the "50/70 MHz" chat category, mirroring
the existing Microwave-category fallback to 23cm.

Assisted by Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-04 21:10:15 +02:00
parent fdec5220d1
commit e37cda8ff2
13 changed files with 459 additions and 29 deletions
@@ -87,6 +87,8 @@ public final class BandOpportunityResolver {
return enabledBands;
}
if (preferences.isStn_bandActive50()) enabledBands.add(Band.B_50);
if (preferences.isStn_bandActive70()) enabledBands.add(Band.B_70);
if (preferences.isStn_bandActive144()) enabledBands.add(Band.B_144);
if (preferences.isStn_bandActive432()) enabledBands.add(Band.B_432);
if (preferences.isStn_bandActive1240()) enabledBands.add(Band.B_1296);
@@ -149,6 +151,8 @@ public final class BandOpportunityResolver {
}
private static void collectWorkedBands(ChatMember member, EnumSet<Band> target) {
if (member.isWorked50()) target.add(Band.B_50);
if (member.isWorked70()) target.add(Band.B_70);
if (member.isWorked144()) target.add(Band.B_144);
if (member.isWorked432()) target.add(Band.B_432);
if (member.isWorked1240()) target.add(Band.B_1296);
@@ -160,6 +164,8 @@ public final class BandOpportunityResolver {
}
private static void collectNotQrvBands(ChatMember member, EnumSet<Band> target) {
if (!member.isQrv50()) target.add(Band.B_50);
if (!member.isQrv70()) target.add(Band.B_70);
if (!member.isQrv144()) target.add(Band.B_144);
if (!member.isQrv432()) target.add(Band.B_432);
if (!member.isQrv1240()) target.add(Band.B_1296);
@@ -173,6 +179,11 @@ public final class BandOpportunityResolver {
private static Map<Band, Pattern> createStationNameBandPatterns() {
Map<Band, Pattern> patterns = new EnumMap<>(Band.class);
// Bare "70" and bare "6" are already claimed by the 70cm/6cm shorthand below
// (their "CM" suffix is optional), so 4m/6m must require an explicit MHz/"M"
// suffix here to avoid misreading a cm-band shorthand as 70/50 MHz.
patterns.put(Band.B_50, bandPattern("50(?:\\s*MHZ)?|6\\s*M"));
patterns.put(Band.B_70, bandPattern("70\\s*MHZ|4\\s*M"));
patterns.put(Band.B_144, bandPattern("144(?:\\s*MHZ)?|2(?:\\s*M)?"));
patterns.put(Band.B_432, bandPattern("432(?:\\s*MHZ)?|70(?:\\s*CM)?"));
patterns.put(Band.B_1296, bandPattern("1296(?:\\s*MHZ)?|23(?:\\s*CM)?"));