@elgato/streamdeck
Version:
The official Node.js SDK for creating Stream Deck plugins.
120 lines (119 loc) • 4.64 kB
JavaScript
import { actionStore } from "./actions/store.js";
import { connection } from "./connection.js";
import { ActionWithoutPayloadEvent } from "./events/action-event.js";
import { SendToPluginEvent, } from "./events/index.js";
/**
* Controller capable of sending/receiving payloads with the property inspector, and listening for events.
*/
class UIController {
/**
* Action associated with the current property inspector.
*/
#action;
/**
* To overcome event races, the debounce counter keeps track of appear vs disappear events, ensuring
* we only clear the current ui when an equal number of matching disappear events occur.
*/
#appearanceStackCount = 0;
/**
* Initializes a new instance of the {@link UIController} class.
*/
constructor() {
// Track the action for the current property inspector.
this.onDidAppear((ev) => {
if (this.#isCurrent(ev.action)) {
this.#appearanceStackCount++;
}
else {
this.#appearanceStackCount = 1;
this.#action = ev.action;
}
});
this.onDidDisappear((ev) => {
if (this.#isCurrent(ev.action)) {
this.#appearanceStackCount--;
if (this.#appearanceStackCount <= 0) {
this.#action = undefined;
}
}
});
}
/**
* Gets the action associated with the current property.
* @returns The action; otherwise `undefined` when a property inspector is not visible.
*/
get action() {
return this.#action;
}
/**
* Occurs when the property inspector associated with the action becomes visible, i.e. the user
* selected an action in the Stream Deck application..
* @template T The type of settings associated with the action.
* @param listener Function to be invoked when the event occurs.
* @returns A disposable that, when disposed, removes the listener.
*/
onDidAppear(listener) {
return connection.disposableOn("propertyInspectorDidAppear", (ev) => {
const action = actionStore.getActionById(ev.context);
if (action) {
listener(new ActionWithoutPayloadEvent(action, ev));
}
});
}
/**
* Occurs when the property inspector associated with the action disappears, i.e. the user unselected
* the action in the Stream Deck application.
* @template T The type of settings associated with the action.
* @param listener Function to be invoked when the event occurs.
* @returns A disposable that, when disposed, removes the listener.
*/
onDidDisappear(listener) {
return connection.disposableOn("propertyInspectorDidDisappear", (ev) => {
const action = actionStore.getActionById(ev.context);
if (action) {
listener(new ActionWithoutPayloadEvent(action, ev));
}
});
}
/**
* Occurs when a message was sent to the plugin _from_ the property inspector.
* @template TPayload The type of the payload received from the property inspector.
* @template TSettings The type of settings associated with the action.
* @param listener Function to be invoked when the event occurs.
* @returns A disposable that, when disposed, removes the listener.
*/
onSendToPlugin(listener) {
return connection.disposableOn("sendToPlugin", (ev) => {
const action = actionStore.getActionById(ev.context);
if (action) {
listener(new SendToPluginEvent(action, ev));
}
});
}
/**
* Sends the payload to the property inspector; the payload is only sent when the property inspector
* is visible for an action provided by this plugin.
* @param payload Payload to send.
*/
async sendToPropertyInspector(payload) {
if (this.#action) {
await connection.send({
event: "sendToPropertyInspector",
context: this.#action.id,
payload,
});
}
}
/**
* Determines whether the specified action is the action for the current property inspector.
* @param action Action to check against.
* @returns `true` when the actions are the same.
*/
#isCurrent(action) {
return (this.#action?.id === action.id &&
this.#action?.manifestId === action.manifestId &&
this.#action?.device?.id === action.device.id);
}
}
export const ui = new UIController();
export {};