refactor: replace feature globals with typed services

This commit is contained in:
sjg
2026-08-01 16:05:40 +02:00
parent 3d49839ed5
commit 26a167cb82
16 changed files with 219 additions and 149 deletions
@@ -50,13 +50,21 @@ interface VirtualChannelBridge {
applyLocalTunedFrequency?: (frequencyHz: number) => void;
setRigFrequency?: (frequencyHz: number) => void;
refreshFreqDisplay?: () => void;
vchanTakeSchedulerControl?: () => Promise<void>;
vchanInterceptMode?: (mode: string) => Promise<boolean>;
vchanInterceptBandwidth?: (bandwidthHz: number) => Promise<boolean>;
vchanHandleSession?: (data: string) => void;
vchanHandleChannels?: (data: string) => void;
vchanApplyCapabilities?: (capabilities: { filter_controls?: boolean } | null) => void;
vchanIsOnVirtual?: () => boolean;
trx?: { modules?: { vchan?: VirtualChannelService } };
}
interface VirtualChannelService {
readonly channels: readonly VirtualChannel[];
readonly activeId: string | null;
activeChannel(): VirtualChannel | null;
applyCapabilities(capabilities: { filter_controls?: boolean } | null): void;
handleSession(data: string): void;
handleChannels(data: string): void;
isOnVirtual(): boolean;
interceptMode(mode: string): Promise<boolean>;
interceptBandwidth(bandwidthHz: number): Promise<boolean>;
takeSchedulerControl(): Promise<void>;
releaseToScheduler(): Promise<void>;
}
const vchanWindow = window as unknown as VirtualChannelBridge;
@@ -169,7 +177,6 @@ async function vchanTakeSchedulerControl() {
console.error("scheduler control takeover failed", e);
}
}
vchanWindow.vchanTakeSchedulerControl = vchanTakeSchedulerControl;
// Called by app.js when the SSE `session` event arrives.
function vchanHandleSession(data: string): void {
@@ -208,8 +215,6 @@ function vchanHandleChannels(data: string): void {
console.warn("vchan: bad channels event", e);
}
}
vchanWindow.vchanHandleSession = vchanHandleSession;
vchanWindow.vchanHandleChannels = vchanHandleChannels;
function vchanRender() {
const picker = document.getElementById("vchan-picker");
@@ -388,7 +393,6 @@ function vchanApplyCapabilities(caps: { filter_controls?: boolean } | null): voi
picker.style.display = (caps && caps.filter_controls) ? "" : "none";
vchanRenderSchedulerRelease();
}
vchanWindow.vchanApplyCapabilities = vchanApplyCapabilities;
// ---------------------------------------------------------------------------
// Freq / mode interception + UI accent
@@ -399,7 +403,6 @@ function vchanIsOnVirtual(): boolean {
if (!vchanActiveId || vchanChannels.length === 0) return false;
return vchanActiveId !== vchanChannels[0]?.id;
}
vchanWindow.vchanIsOnVirtual = vchanIsOnVirtual;
function vchanActiveChannel(): VirtualChannel | null {
return vchanChannels.find(c => c.id === vchanActiveId) || null;
@@ -554,18 +557,34 @@ async function vchanSetChannelMode(mode: string): Promise<void> {
// Called by app.js (applyModeFromPicker) and bookmarks.js (bmApply) before
// sending /set_mode to the server. Returns true if the change was handled
// by the virtual channel (caller should skip the server request).
vchanWindow.vchanInterceptMode = async function(mode: string) {
async function vchanInterceptMode(mode: string): Promise<boolean> {
if (!vchanIsOnVirtual()) return false;
await vchanSetChannelMode(mode);
return true;
};
}
// Called by app.js bandwidth setters before sending /set_bandwidth to the
// server. Returns true if the change was handled by the virtual channel.
vchanWindow.vchanInterceptBandwidth = async function(bwHz: number) {
async function vchanInterceptBandwidth(bwHz: number): Promise<boolean> {
if (!vchanIsOnVirtual()) return false;
await vchanSetChannelBandwidth(bwHz);
return true;
}
vchanWindow.trx ??= {};
vchanWindow.trx.modules ??= {};
vchanWindow.trx.modules.vchan = {
get channels() { return vchanChannels; },
get activeId() { return vchanActiveId; },
activeChannel: vchanActiveChannel,
applyCapabilities: vchanApplyCapabilities,
handleSession: vchanHandleSession,
handleChannels: vchanHandleChannels,
isOnVirtual: vchanIsOnVirtual,
interceptMode: vchanInterceptMode,
interceptBandwidth: vchanInterceptBandwidth,
takeSchedulerControl: vchanTakeSchedulerControl,
releaseToScheduler: vchanToggleSchedulerRelease,
};
// Wrap setRigFrequency (defined in app.js, loaded before this file) so that