mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
Minor receiver selector refactoring
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user