mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-11 18:19:58 +00:00
Add stop action to receiver selectors
This commit is contained in:
@@ -56,6 +56,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
, "popupStopButtonTitle": {
|
||||
"message": "Stop"
|
||||
, "description": "Alternate action button text displayed instead of popupCastButtonTitle."
|
||||
}
|
||||
|
||||
|
||||
, "contextCast": {
|
||||
|
||||
@@ -64,6 +64,17 @@ export default new class StatusManager
|
||||
}
|
||||
}
|
||||
|
||||
public async stopReceiverApp (receiver: Receiver) {
|
||||
if (!this.bridgePort) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.bridgePort.postMessage({
|
||||
subject: "bridge:/stopReceiverApp"
|
||||
, data: { receiver }
|
||||
});
|
||||
}
|
||||
|
||||
private async createBridgePort () {
|
||||
const bridgePort = await bridge.connect();
|
||||
bridgePort.onMessage.addListener(this.onBridgePortMessage);
|
||||
|
||||
@@ -65,6 +65,12 @@ export default class NativeReceiverSelector
|
||||
this.onBridgePortMessageClose();
|
||||
break;
|
||||
}
|
||||
case "main:/receiverSelector/stop": {
|
||||
this.dispatchEvent(new CustomEvent("stop", {
|
||||
detail: message.data
|
||||
}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -96,6 +102,7 @@ export default class NativeReceiverSelector
|
||||
|
||||
, i18n_extensionName: _("extensionName")
|
||||
, i18n_castButtonTitle: _("popupCastButtonTitle")
|
||||
, i18n_stopButtonTitle: _("popupStopButtonTitle")
|
||||
, i18n_mediaTypeApp:
|
||||
knownApps[requestedAppId] ?? _("popupMediaTypeApp")
|
||||
, i18n_mediaTypeTab: _("popupMediaTypeTab")
|
||||
|
||||
@@ -154,6 +154,14 @@ export default class PopupReceiverSelector
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "receiverSelector:/stop": {
|
||||
this.dispatchEvent(new CustomEvent("stop", {
|
||||
detail: message.data
|
||||
}));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ export interface ReceiverSelectorEvents {
|
||||
"selected": ReceiverSelection;
|
||||
"error": string;
|
||||
"cancelled": void;
|
||||
"stop": { receiver: Receiver };
|
||||
}
|
||||
|
||||
export default interface ReceiverSelector
|
||||
|
||||
@@ -17,6 +17,8 @@ import { ReceiverSelection
|
||||
import NativeReceiverSelector from "./NativeReceiverSelector";
|
||||
import PopupReceiverSelector from "./PopupReceiverSelector";
|
||||
|
||||
import { Receiver } from "../../types";
|
||||
|
||||
|
||||
async function createSelector () {
|
||||
const type = await options.get("receiverSelectorType");
|
||||
@@ -60,9 +62,18 @@ async function getSelection (
|
||||
: Promise<ReceiverSelection> {
|
||||
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const currentShim = ShimManager.getShim(
|
||||
let currentShim = ShimManager.getShim(
|
||||
contextTabId, contextFrameId);
|
||||
|
||||
/**
|
||||
* If the current context is running the mirroring app, pretend
|
||||
* it doesn't exist because it shouldn't be launched like this.
|
||||
*/
|
||||
if (currentShim?.requestedAppId ===
|
||||
await options.get("mirroringAppId")) {
|
||||
currentShim = null;
|
||||
}
|
||||
|
||||
let defaultMediaType = ReceiverSelectorMediaType.Tab;
|
||||
let availableMediaTypes;
|
||||
|
||||
@@ -107,20 +118,43 @@ async function getSelection (
|
||||
// Get a new selector for each selection
|
||||
sharedSelector = await createSelector();
|
||||
|
||||
sharedSelector.addEventListener("selected", ev => {
|
||||
sharedSelector.addEventListener("selected", onSelected);
|
||||
sharedSelector.addEventListener("cancelled", onCancelled);
|
||||
sharedSelector.addEventListener("error", onError);
|
||||
sharedSelector.addEventListener("stop", onStop);
|
||||
|
||||
function removeListeners () {
|
||||
sharedSelector.removeEventListener("selected", onSelected);
|
||||
sharedSelector.removeEventListener("cancelled", onCancelled);
|
||||
sharedSelector.removeEventListener("error", onError);
|
||||
sharedSelector.removeEventListener("stop", onStop);
|
||||
}
|
||||
|
||||
function onSelected (ev: any) {
|
||||
console.info("fx_cast (Debug): Selected receiver", ev.detail);
|
||||
resolve(ev.detail);
|
||||
});
|
||||
removeListeners();
|
||||
}
|
||||
|
||||
sharedSelector.addEventListener("cancelled", () => {
|
||||
function onCancelled () {
|
||||
console.info("fx_cast (Debug): Cancelled receiver selection");
|
||||
resolve(null);
|
||||
});
|
||||
removeListeners();
|
||||
}
|
||||
|
||||
sharedSelector.addEventListener("error", () => {
|
||||
function onError () {
|
||||
console.error("fx_cast (Debug): Failed to select receiver");
|
||||
reject();
|
||||
});
|
||||
removeListeners();
|
||||
}
|
||||
|
||||
function onStop (ev: any) {
|
||||
console.info("fx_cast (Debug): Stopped receiver app", ev.detail);
|
||||
|
||||
StatusManager.init().then(() => {
|
||||
StatusManager.stopReceiverApp(ev.detail.receiver);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Ensure status manager is initialized
|
||||
|
||||
@@ -59,6 +59,7 @@ class PopupApp extends Component<{}, PopupAppState> {
|
||||
|
||||
this.onSelectChange = this.onSelectChange.bind(this);
|
||||
this.onCast = this.onCast.bind(this);
|
||||
this.onStop = this.onStop.bind(this);
|
||||
}
|
||||
|
||||
public componentDidMount () {
|
||||
@@ -169,6 +170,7 @@ class PopupApp extends Component<{}, PopupAppState> {
|
||||
? this.state.receivers.map((receiver, i) => (
|
||||
<ReceiverEntry receiver={ receiver }
|
||||
onCast={ this.onCast }
|
||||
onStop={ this.onStop }
|
||||
isLoading={ this.state.isLoading }
|
||||
canCast={ canCast }
|
||||
key={ i } /> ))
|
||||
@@ -196,6 +198,13 @@ class PopupApp extends Component<{}, PopupAppState> {
|
||||
});
|
||||
}
|
||||
|
||||
private onStop (receiver: Receiver) {
|
||||
this.port.postMessage({
|
||||
subject: "receiverSelector:/stop"
|
||||
, data: { receiver }
|
||||
});
|
||||
}
|
||||
|
||||
private onSelectChange (ev: React.ChangeEvent<HTMLSelectElement>) {
|
||||
const mediaType = parseInt(ev.target.value);
|
||||
|
||||
@@ -232,11 +241,13 @@ interface ReceiverEntryProps {
|
||||
isLoading: boolean;
|
||||
canCast: boolean;
|
||||
onCast (receiver: Receiver): void;
|
||||
onStop (receiver: Receiver): void;
|
||||
}
|
||||
|
||||
interface ReceiverEntryState {
|
||||
ellipsis: string;
|
||||
isLoading: boolean;
|
||||
showAlternateAction: boolean;
|
||||
}
|
||||
|
||||
class ReceiverEntry extends Component<ReceiverEntryProps, ReceiverEntryState> {
|
||||
@@ -244,10 +255,26 @@ class ReceiverEntry extends Component<ReceiverEntryProps, ReceiverEntryState> {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isLoading: false
|
||||
, ellipsis: ""
|
||||
ellipsis: ""
|
||||
, isLoading: false
|
||||
, showAlternateAction: false
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", ev => {
|
||||
if (ev.key === "Alt") {
|
||||
this.setState({
|
||||
showAlternateAction: true
|
||||
});
|
||||
}
|
||||
});
|
||||
window.addEventListener("keyup", ev => {
|
||||
if (ev.key === "Alt") {
|
||||
this.setState({
|
||||
showAlternateAction: false
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.handleCast = this.handleCast.bind(this);
|
||||
}
|
||||
|
||||
@@ -273,25 +300,33 @@ class ReceiverEntry extends Component<ReceiverEntryProps, ReceiverEntryState> {
|
||||
, (this.state.isLoading
|
||||
? this.state.ellipsis
|
||||
: ""))
|
||||
: _("popupCastButtonTitle") }
|
||||
: !application.isIdleScreen && this.state.showAlternateAction
|
||||
? _("popupStopButtonTitle")
|
||||
: _("popupCastButtonTitle") }
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
private handleCast () {
|
||||
this.props.onCast(this.props.receiver);
|
||||
const { application } = this.props.receiver.status;
|
||||
|
||||
this.setState({
|
||||
isLoading: true
|
||||
});
|
||||
if (!application.isIdleScreen && this.state.showAlternateAction) {
|
||||
this.props.onStop(this.props.receiver);
|
||||
} else {
|
||||
this.props.onCast(this.props.receiver);
|
||||
|
||||
setInterval(() => {
|
||||
this.setState(state => ({
|
||||
ellipsis: getNextEllipsis(state.ellipsis)
|
||||
}));
|
||||
this.setState({
|
||||
isLoading: true
|
||||
});
|
||||
|
||||
}, 500);
|
||||
setInterval(() => {
|
||||
this.setState(state => ({
|
||||
ellipsis: getNextEllipsis(state.ellipsis)
|
||||
}));
|
||||
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user