Minor receiver selector refactoring

This commit is contained in:
hensm
2022-04-28 13:58:34 +01:00
parent dececa46c3
commit 70ac18511a
2 changed files with 90 additions and 117 deletions

View File

@@ -16,13 +16,6 @@ import {
const POPUP_URL = browser.runtime.getURL("ui/popup/index.html"); const POPUP_URL = browser.runtime.getURL("ui/popup/index.html");
interface ReceiverSelectorEvents {
selected: ReceiverSelectionCast;
error: string;
cancelled: void;
stop: ReceiverSelectionStop;
}
export interface PageInfo { export interface PageInfo {
url: string; url: string;
tabId: number; tabId: number;
@@ -30,17 +23,27 @@ export interface PageInfo {
sessionRequest?: SessionRequest; sessionRequest?: SessionRequest;
} }
interface ReceiverSelectorEvents {
selected: ReceiverSelectionCast;
error: string;
cancelled: void;
stop: ReceiverSelectionStop;
}
/** /**
* Manages the receiver selector popup window and communication with the * Manages the receiver selector popup window and communication with the
* extension page hosted within. * extension page hosted within.
*/ */
export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorEvents> { export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorEvents> {
/** Popup window ID. */
private windowId?: number; private windowId?: number;
/** Message port to extension page within popup window. */
private messagePort?: Port; private messagePort?: Port;
private messagePortDisconnected?: boolean; private messagePortDisconnected?: boolean;
private receiverDevices?: ReceiverDevice[]; private receiverDevices?: ReceiverDevice[];
private defaultMediaType?: ReceiverSelectorMediaType; private defaultMediaType?: ReceiverSelectorMediaType;
private availableMediaTypes?: ReceiverSelectorMediaType; private availableMediaTypes?: ReceiverSelectorMediaType;
@@ -68,6 +71,7 @@ export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorE
messaging.onConnect.addListener(this.onConnect); messaging.onConnect.addListener(this.onConnect);
} }
/** Is receiver selector window currently open. */
get isOpen() { get isOpen() {
return this.#isOpen; return this.#isOpen;
} }
@@ -75,24 +79,24 @@ export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorE
/** /**
* Creates and opens a receiver selector window. * Creates and opens a receiver selector window.
*/ */
public async open( public async open(opts: {
receiverDevices: ReceiverDevice[], receiverDevices: ReceiverDevice[];
defaultMediaType: ReceiverSelectorMediaType, defaultMediaType: ReceiverSelectorMediaType;
availableMediaTypes: ReceiverSelectorMediaType, availableMediaTypes: ReceiverSelectorMediaType;
appId?: string, appId?: string;
pageInfo?: PageInfo pageInfo?: PageInfo;
) { }) {
this.appId = appId; this.appId = opts.appId;
this.pageInfo = pageInfo; this.pageInfo = opts.pageInfo;
// If popup already exists, close it // If popup already exists, close it
if (this.windowId) { if (this.windowId) {
await browser.windows.remove(this.windowId); await browser.windows.remove(this.windowId);
} }
this.receiverDevices = receiverDevices; this.receiverDevices = opts.receiverDevices;
this.defaultMediaType = defaultMediaType; this.defaultMediaType = opts.defaultMediaType;
this.availableMediaTypes = availableMediaTypes; this.availableMediaTypes = opts.availableMediaTypes;
const popupSizePosition = { const popupSizePosition = {
width: 350, width: 350,
@@ -163,7 +167,6 @@ export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorE
await browser.windows.remove(this.windowId); await browser.windows.remove(this.windowId);
} }
this.#isOpen = false;
this.appId = undefined; this.appId = undefined;
if (this.messagePort && !this.messagePortDisconnected) { if (this.messagePort && !this.messagePortDisconnected) {
@@ -255,6 +258,8 @@ export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorE
return; return;
} }
this.#isOpen = false;
browser.windows.onRemoved.removeListener(this.onWindowsRemoved); browser.windows.onRemoved.removeListener(this.onWindowsRemoved);
browser.windows.onFocusChanged.removeListener( browser.windows.onFocusChanged.removeListener(
this.onWindowsFocusChanged this.onWindowsFocusChanged
@@ -265,11 +270,11 @@ export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorE
} }
// Cleanup // Cleanup
this.windowId = undefined; delete this.windowId;
this.messagePort = undefined; delete this.messagePort;
this.receiverDevices = undefined; delete this.receiverDevices;
this.defaultMediaType = undefined; delete this.defaultMediaType;
this.availableMediaTypes = undefined; delete this.availableMediaTypes;
this.wasReceiverSelected = false; this.wasReceiverSelected = false;
} }

View File

@@ -12,21 +12,18 @@ import { getMediaTypesForPageUrl } from "../../lib/utils";
import { import {
ReceiverSelection, ReceiverSelection,
ReceiverSelectionActionType, ReceiverSelectionActionType,
ReceiverSelectionCast,
ReceiverSelectionStop,
ReceiverSelectorMediaType ReceiverSelectorMediaType
} from "./index"; } from "./index";
import ReceiverSelector from "./ReceiverSelector"; import ReceiverSelector from "./ReceiverSelector";
async function createSelector() {
return new ReceiverSelector();
}
let sharedSelector: ReceiverSelector; let sharedSelector: ReceiverSelector;
async function getSelector() { async function getSelector() {
if (!sharedSelector) { if (!sharedSelector) {
try { try {
sharedSelector = await createSelector(); sharedSelector = new ReceiverSelector();
} catch (err) { } catch (err) {
throw logger.error("Failed to create receiver selector."); throw logger.error("Failed to create receiver selector.");
} }
@@ -68,7 +65,7 @@ async function getSelection(
} }
let defaultMediaType = ReceiverSelectorMediaType.Tab; let defaultMediaType = ReceiverSelectorMediaType.Tab;
let availableMediaTypes; let availableMediaTypes = ReceiverSelectorMediaType.None;
let pageUrl: string | undefined; let pageUrl: string | undefined;
try { try {
@@ -84,10 +81,9 @@ async function getSelection(
logger.error( logger.error(
"Failed to locate frame, falling back to default available media types." "Failed to locate frame, falling back to default available media types."
); );
availableMediaTypes = ReceiverSelectorMediaType.File;
} }
// Enable app media type if initialized sender app is found // Enable app media type if sender application is present
if (castInstance || selectionOpts?.withMediaSender) { if (castInstance || selectionOpts?.withMediaSender) {
defaultMediaType = ReceiverSelectorMediaType.App; defaultMediaType = ReceiverSelectorMediaType.App;
availableMediaTypes |= ReceiverSelectorMediaType.App; availableMediaTypes |= ReceiverSelectorMediaType.App;
@@ -95,7 +91,7 @@ async function getSelection(
const opts = await options.getAll(); const opts = await options.getAll();
// Remove mirroring media types if mirroring is not enabled // Disable mirroring media types if mirroring is not enabled
if (!opts.mirroringEnabled) { if (!opts.mirroringEnabled) {
availableMediaTypes &= ~( availableMediaTypes &= ~(
ReceiverSelectorMediaType.Tab | ReceiverSelectorMediaType.Screen ReceiverSelectorMediaType.Tab | ReceiverSelectorMediaType.Screen
@@ -113,7 +109,7 @@ async function getSelection(
} }
// Get a new selector for each selection // Get a new selector for each selection
sharedSelector = await createSelector(); sharedSelector = new ReceiverSelector();
function onReceiverChange() { function onReceiverChange() {
sharedSelector.update(receiverDevices.getDevices()); sharedSelector.update(receiverDevices.getDevices());
@@ -129,34 +125,52 @@ async function getSelection(
onReceiverChange onReceiverChange
); );
let onSelected: any; function onSelectorSelected(ev: CustomEvent<ReceiverSelectionCast>) {
let onCancelled: any; logger.info("Selected receiver", ev.detail);
let onError: any;
let onStop: any;
type EvParamsType = Parameters< removeListeners();
typeof sharedSelector.addEventListener resolve({
>[0]; actionType: ReceiverSelectionActionType.Cast,
receiverDevice: ev.detail.receiverDevice,
mediaType: ev.detail.mediaType,
filePath: ev.detail.filePath
});
}
function onSelectorStop(ev: CustomEvent<ReceiverSelectionStop>) {
logger.info("Stopping receiver app...", ev.detail);
function storeListener<T>(type: EvParamsType, fn: T) { receiverDevices.stopReceiverApp(ev.detail.receiverDevice.id);
if (type === "selected") {
onSelected = fn;
} else if (type === "cancelled") {
onCancelled = fn;
} else if (type === "error") {
onError = fn;
} else if (type === "stop") {
onStop = fn;
}
return fn; removeListeners();
resolve({
actionType: ReceiverSelectionActionType.Stop,
receiverDevice: ev.detail.receiverDevice
});
}
function onSelectorCancelled() {
logger.info("Cancelled receiver selection");
removeListeners();
resolve(null);
}
function onSelectorError(ev: CustomEvent<string>) {
removeListeners();
reject(ev.detail);
} }
sharedSelector.addEventListener("selected", onSelectorSelected);
sharedSelector.addEventListener("stop", onSelectorStop);
sharedSelector.addEventListener("cancelled", onSelectorCancelled);
sharedSelector.addEventListener("error", onSelectorError);
function removeListeners() { function removeListeners() {
sharedSelector.removeEventListener("selected", onSelected); sharedSelector.removeEventListener("selected", onSelectorSelected);
sharedSelector.removeEventListener("cancelled", onCancelled); sharedSelector.removeEventListener("stop", onSelectorStop);
sharedSelector.removeEventListener("error", onError); sharedSelector.removeEventListener(
sharedSelector.removeEventListener("stop", onStop); "cancelled",
onSelectorCancelled
);
sharedSelector.removeEventListener("error", onSelectorError);
receiverDevices.removeEventListener( receiverDevices.removeEventListener(
"receiverDeviceUp", "receiverDeviceUp",
@@ -172,70 +186,24 @@ async function getSelection(
); );
} }
sharedSelector.addEventListener(
"selected",
storeListener("selected", ev => {
logger.info("Selected receiver", ev.detail);
resolve({
actionType: ReceiverSelectionActionType.Cast,
receiverDevice: ev.detail.receiverDevice,
mediaType: ev.detail.mediaType,
filePath: ev.detail.filePath
});
removeListeners();
})
);
sharedSelector.addEventListener(
"cancelled",
storeListener("cancelled", () => {
logger.info("Cancelled receiver selection");
resolve(null);
removeListeners();
})
);
sharedSelector.addEventListener(
"error",
storeListener("error", ev => {
reject(ev.detail);
removeListeners();
})
);
sharedSelector.addEventListener(
"stop",
storeListener("stop", async ev => {
logger.info("Stopping receiver app...", ev.detail);
receiverDevices.stopReceiverApp(ev.detail.receiverDevice.id);
resolve({
actionType: ReceiverSelectionActionType.Stop,
receiverDevice: ev.detail.receiverDevice
});
removeListeners();
})
);
// Ensure status manager is initialized // Ensure status manager is initialized
await receiverDevices.init(); await receiverDevices.init();
const pageInfo = pageUrl sharedSelector.open({
? { receiverDevices: receiverDevices.getDevices(),
url: pageUrl,
tabId: contextTabId,
frameId: contextFrameId,
sessionRequest: selectionOpts?.sessionRequest
}
: undefined;
sharedSelector.open(
receiverDevices.getDevices(),
defaultMediaType, defaultMediaType,
availableMediaTypes, availableMediaTypes,
castInstance?.appId, appId: castInstance?.appId,
pageInfo // Create page info
); pageInfo: pageUrl
? {
url: pageUrl,
tabId: contextTabId,
frameId: contextFrameId,
sessionRequest: selectionOpts?.sessionRequest
}
: undefined
});
}); });
} }