Set browser action details to match cast session states

This commit is contained in:
hensm
2022-09-10 19:48:46 +01:00
parent 764a5e0a00
commit e761d4756a
5 changed files with 143 additions and 9 deletions

View File

@@ -8,6 +8,23 @@
"description": "Description of the extension shown in the add-ons manager."
},
"actionTitleDefault": {
"message": "fx_cast: Ready to cast",
"description": "Title for toolbar button in default state."
},
"actionTitleDisabled": {
"message": "fx_cast: Unable to cast",
"description": "Title for toolbar button in disabled state."
},
"actionTitleConnecting": {
"message": "fx_cast: Connecting",
"description": "Title for toolbar button whilst connecting."
},
"actionTitleConnected": {
"message": "fx_cast: Connected",
"description": "Title for toolbar button whilst connected."
},
"popupBridgeErrorBanner": {
"message": "There is a problem with the bridge!",
"description": "Bridge error banner message."

View File

@@ -0,0 +1,75 @@
import logger from "../lib/logger";
import castManager from "./castManager";
const _ = browser.i18n.getMessage;
const ACTION_ICON_DEFAULT_DARK = "icons/cast-default-dark.svg";
const ACTION_ICON_DEFAULT_LIGHT = "icons/cast-default-light.svg";
const ACTION_ICON_CONNECTING_DARK = "icons/cast-connecting-dark.svg";
const ACTION_ICON_CONNECTING_LIGHT = "icons/cast-connecting-light.svg";
const ACTION_ICON_CONNECTED = "icons/cast-connected.svg";
const ACTION_ICON_DISABLED_DARK = "icons/cast-disabled-dark.svg";
const ACTION_ICON_DISABLED_LIGHT = "icons/cast-disabled-light.svg";
const isDarkTheme = window.matchMedia("(prefers-color-scheme: dark)").matches;
export enum ActionState {
Default,
Connecting,
Connected,
Disabled
}
/** Updates action details depending on given state. */
export function updateActionState(state: ActionState, tabId?: number) {
let title: string;
let path: string;
switch (state) {
case ActionState.Default:
title = _("actionTitleDefault");
path = isDarkTheme
? ACTION_ICON_DEFAULT_LIGHT
: ACTION_ICON_DEFAULT_DARK;
break;
case ActionState.Connecting:
title = _("actionTitleConnecting");
path = isDarkTheme
? ACTION_ICON_CONNECTING_LIGHT
: ACTION_ICON_CONNECTING_DARK;
break;
case ActionState.Connected:
title = _("actionTitleConnected");
path = ACTION_ICON_CONNECTED;
break;
case ActionState.Disabled:
title = _("actionTitleDisabled");
path = isDarkTheme
? ACTION_ICON_DISABLED_LIGHT
: ACTION_ICON_DISABLED_DARK;
break;
}
if (state === ActionState.Disabled) {
browser.browserAction.disable(tabId);
} else {
browser.browserAction.enable(tabId);
}
browser.browserAction.setTitle({ tabId, title });
browser.browserAction.setIcon({ tabId, path });
}
export function initAction() {
logger.info("init (action)");
updateActionState(ActionState.Default);
browser.browserAction.onClicked.addListener(async tab => {
if (tab.id === undefined) {
logger.error("Tab ID not found in browser action handler.");
return;
}
castManager.triggerCast(tab.id);
});
}

View File

@@ -9,6 +9,7 @@ import messaging from "../messaging";
import castManager from "./castManager";
import deviceManager from "./deviceManager";
import { initAction } from "./action";
import { initMenus } from "./menus";
import { initWhitelist } from "./whitelist";
@@ -129,6 +130,7 @@ async function init() {
await deviceManager.init();
await castManager.init();
await initAction();
await initMenus();
await initWhitelist();
@@ -139,15 +141,6 @@ async function init() {
break;
}
});
browser.browserAction.onClicked.addListener(async tab => {
if (tab.id === undefined) {
logger.error("Tab ID not found in browser action handler.");
return;
}
castManager.triggerCast(tab.id);
});
}
cacheBaseConfig();

View File

@@ -27,6 +27,7 @@ import ReceiverSelector, {
} from "./ReceiverSelector";
import deviceManager from "./deviceManager";
import { ActionState, updateActionState } from "./action";
type AnyPort = Port | TypedMessagePort<Message>;
@@ -85,6 +86,13 @@ async function createCastSession(opts: {
destroyCastInstance(opts.instance)
);
if (opts.instance.contentContext?.tabId) {
updateActionState(
ActionState.Connecting,
opts.instance.contentContext?.tabId
);
}
return session;
}
@@ -161,6 +169,10 @@ function destroyCastInstance(instance: CastInstance) {
);
}
if (instance.contentContext?.tabId) {
updateActionState(ActionState.Default, instance.contentContext?.tabId);
}
activeInstances.delete(instance);
}
@@ -227,6 +239,13 @@ const castManager = new (class {
});
delete instance.session;
if (instance.contentContext?.tabId) {
updateActionState(
ActionState.Default,
instance.contentContext?.tabId
);
}
}
}
@@ -407,6 +426,13 @@ async function handleBridgeMessage(instance: CastInstance, message: Message) {
}
});
if (instance.contentContext?.tabId) {
updateActionState(
ActionState.Connected,
instance.contentContext?.tabId
);
}
break;
}
@@ -529,6 +555,13 @@ async function handleContentMessage(instance: CastInstance, message: Message) {
}
});
if (instance.contentContext?.tabId) {
updateActionState(
ActionState.Connected,
instance.contentContext?.tabId
);
}
break sessionLoop;
}
}

View File

@@ -13,6 +13,8 @@ import type {
} from "../cast/sdk/types";
import { PlayerState } from "../cast/sdk/media/enums";
import { ActionState, updateActionState } from "./action";
interface EventMap {
deviceUp: { deviceInfo: ReceiverDevice };
deviceDown: { deviceId: string };
@@ -45,6 +47,8 @@ export default new (class extends TypedEventTarget<EventMap> {
async refresh() {
this.bridgePort?.disconnect();
updateActionState(ActionState.Disabled);
try {
this.bridgeInfo = await bridge.getInfo();
// eslint-disable-next-line no-empty
@@ -65,6 +69,14 @@ export default new (class extends TypedEventTarget<EventMap> {
}
}
private updateAction() {
if (this.receiverDevices.size > 0) {
updateActionState(ActionState.Default);
} else {
updateActionState(ActionState.Disabled);
}
}
getBridgeInfo() {
return this.bridgeInfo;
}
@@ -142,6 +154,8 @@ export default new (class extends TypedEventTarget<EventMap> {
})
);
this.updateAction();
break;
}
@@ -157,6 +171,8 @@ export default new (class extends TypedEventTarget<EventMap> {
})
);
this.updateAction();
break;
}