feat(radio): answer the RTL-SDR card through the radio store

SdrCard calls LocalSdrControls through radio store actions instead of
DOM listeners, and renders its gain options from the receiver's own
R820T gain steps with page-language labels. The display and radio
stores share one owner list (createOwners): the newest connected owner
with an action answers it.
This commit is contained in:
Sameh Khamis committed 2026-11-01 10:52:50 -08:00
1 parent e5fa31d01e
commit 61d11ce369
12 files changed
+320 -206

No files matched your search

+43
View File
@@ -0,0 +1,43 @@
/**
* The owners answering a store's controls. A view calls `act(name, ...args)`;
* the newest connected owner with an action of that name answers it, so an
* owner that connects again replaces itself, and owners of different actions
* sit side by side.
* @returns {{connect: Function, detach: Function, act: Function}}
*/
export function createOwners() {
/** @type {Array<{actions: object}>} Oldest first. */
const owners = [];
/**
* Answer the actions named in `actions`.
* @param {Record<string, Function>} actions
* @returns {object} Token for detach().
*/
function connect(actions) {
const token = { actions };
owners.push(token);
return token;
}
/** Stop answering for the owner holding `token`; the others stay. */
function detach(token) {
const index = owners.indexOf(token);
if (index >= 0) owners.splice(index, 1);
}
/**
* A control's change: call the newest connected owner's action of that
* name, if any.
* @param {string} name
* @param {...unknown} args
*/
function act(name, ...args) {
for (let index = owners.length - 1; index >= 0; index -= 1) {
const action = owners[index].actions[name];
if (action) return void action(...args);
}
}
return { connect, detach, act };
}