mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-12 18:39:58 +00:00
Add stop action to receiver selectors
This commit is contained in:
@@ -2,6 +2,7 @@ import Cocoa
|
|||||||
|
|
||||||
protocol ReceiverViewDelegate : AnyObject {
|
protocol ReceiverViewDelegate : AnyObject {
|
||||||
func didCast (_ receiver: Receiver)
|
func didCast (_ receiver: Receiver)
|
||||||
|
func didStop (_ receiver: Receiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReceiverView : NSStackView {
|
class ReceiverView : NSStackView {
|
||||||
@@ -74,6 +75,23 @@ class ReceiverView : NSStackView {
|
|||||||
self.addArrangedSubview(self.castButton)
|
self.addArrangedSubview(self.castButton)
|
||||||
|
|
||||||
self.distribution = .fill
|
self.distribution = .fill
|
||||||
|
|
||||||
|
NSEvent.addLocalMonitorForEvents(
|
||||||
|
matching: .flagsChanged) { event in
|
||||||
|
|
||||||
|
if !self.receiver.status.application.isIdleScreen &&
|
||||||
|
event.modifierFlags.contains(.option) {
|
||||||
|
self.castButton.title =
|
||||||
|
InitDataProvider.shared.data.i18n_stopButtonTitle
|
||||||
|
self.castButton.action = #selector(ReceiverView.onStop)
|
||||||
|
} else {
|
||||||
|
self.castButton.title =
|
||||||
|
InitDataProvider.shared.data.i18n_castButtonTitle
|
||||||
|
self.castButton.action = #selector(ReceiverView.onCast)
|
||||||
|
}
|
||||||
|
|
||||||
|
return event
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateConstraints () {
|
override func updateConstraints () {
|
||||||
@@ -103,4 +121,9 @@ class ReceiverView : NSStackView {
|
|||||||
self.castingSpinner.isHidden = false
|
self.castingSpinner.isHidden = false
|
||||||
self.castingSpinner.startAnimation(nil)
|
self.castingSpinner.startAnimation(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
func onStop () {
|
||||||
|
self.receiverViewDelegate?.didStop(self.receiver);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,4 +197,20 @@ extension ViewController : ReceiverViewDelegate {
|
|||||||
fatalError("Error: Failed to encode output data")
|
fatalError("Error: Failed to encode output data")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func didStop (_ receiver: Receiver) {
|
||||||
|
// TODO: Use separate type and do proper JSON encoding
|
||||||
|
let selection = ReceiverSelection(
|
||||||
|
receiver: receiver
|
||||||
|
, mediaType: nil
|
||||||
|
, filePath: nil)
|
||||||
|
|
||||||
|
if let jsonData = try? JSONEncoder().encode(selection)
|
||||||
|
, let jsonString = String(data: jsonData, encoding: .utf8) {
|
||||||
|
print(jsonString)
|
||||||
|
fflush(stdout)
|
||||||
|
} else {
|
||||||
|
fatalError("Error: Failed to encode output data")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ struct InitData : Decodable {
|
|||||||
|
|
||||||
let i18n_extensionName: String
|
let i18n_extensionName: String
|
||||||
let i18n_castButtonTitle: String
|
let i18n_castButtonTitle: String
|
||||||
|
let i18n_stopButtonTitle: String
|
||||||
let i18n_mediaTypeApp: String
|
let i18n_mediaTypeApp: String
|
||||||
let i18n_mediaTypeTab: String
|
let i18n_mediaTypeTab: String
|
||||||
let i18n_mediaTypeScreen: String
|
let i18n_mediaTypeScreen: String
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
struct ReceiverSelection : Codable {
|
struct ReceiverSelection : Codable {
|
||||||
let receiver: Receiver
|
let receiver: Receiver
|
||||||
let mediaType: MediaType
|
let mediaType: MediaType?
|
||||||
let filePath: String?
|
let filePath: String?
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,16 @@ import { Message
|
|||||||
, SendMessageCallback } from "./types";
|
, SendMessageCallback } from "./types";
|
||||||
|
|
||||||
|
|
||||||
const NS_CONNECTION = "urn:x-cast:com.google.cast.tp.connection";
|
export const NS_CONNECTION = "urn:x-cast:com.google.cast.tp.connection";
|
||||||
const NS_HEARTBEAT = "urn:x-cast:com.google.cast.tp.heartbeat";
|
export const NS_HEARTBEAT = "urn:x-cast:com.google.cast.tp.heartbeat";
|
||||||
const NS_RECEIVER = "urn:x-cast:com.google.cast.receiver";
|
export const NS_RECEIVER = "urn:x-cast:com.google.cast.receiver";
|
||||||
|
|
||||||
export default class Session {
|
export default class Session {
|
||||||
public channelMap = new Map<string, Channel>();
|
public channelMap = new Map<string, Channel>();
|
||||||
|
|
||||||
|
public host: string;
|
||||||
|
public port: number;
|
||||||
|
|
||||||
private sendMessageCallback: SendMessageCallback;
|
private sendMessageCallback: SendMessageCallback;
|
||||||
private sessionId: number;
|
private sessionId: number;
|
||||||
private referenceId: string;
|
private referenceId: string;
|
||||||
@@ -38,6 +41,9 @@ export default class Session {
|
|||||||
, referenceId: string
|
, referenceId: string
|
||||||
, sendMessageCallback: SendMessageCallback) {
|
, sendMessageCallback: SendMessageCallback) {
|
||||||
|
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
|
||||||
this.sessionId = sessionId;
|
this.sessionId = sessionId;
|
||||||
this.referenceId = referenceId;
|
this.referenceId = referenceId;
|
||||||
this.sendMessageCallback = sendMessageCallback;
|
this.sendMessageCallback = sendMessageCallback;
|
||||||
@@ -176,6 +182,10 @@ export default class Session {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public stop () {
|
||||||
|
this.clientConnection!.send({ type: "STOP" });
|
||||||
|
}
|
||||||
|
|
||||||
private sendMessage (subject: string, data: any = {}) {
|
private sendMessage (subject: string, data: any = {}) {
|
||||||
this.sendMessageCallback({
|
this.sendMessageCallback({
|
||||||
subject
|
subject
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
import { Channel, Client } from "castv2";
|
import { Channel, Client } from "castv2";
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
|
|
||||||
const NS_CONNECTION = "urn:x-cast:com.google.cast.tp.connection";
|
import { NS_CONNECTION
|
||||||
const NS_HEARTBEAT = "urn:x-cast:com.google.cast.tp.heartbeat";
|
, NS_HEARTBEAT
|
||||||
const NS_RECEIVER = "urn:x-cast:com.google.cast.receiver";
|
, NS_RECEIVER } from "./Session";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,11 +16,16 @@ import { DecodeTransform
|
|||||||
|
|
||||||
import { ReceiverStatus } from "./castTypes";
|
import { ReceiverStatus } from "./castTypes";
|
||||||
|
|
||||||
import { Message } from "./types";
|
import { Message, Receiver } from "./types";
|
||||||
|
|
||||||
import { __applicationName
|
import { __applicationName
|
||||||
, __applicationVersion } from "../../package.json";
|
, __applicationVersion } from "../../package.json";
|
||||||
|
|
||||||
|
import { Channel, Client } from "castv2";
|
||||||
|
import { NS_CONNECTION
|
||||||
|
, NS_HEARTBEAT
|
||||||
|
, NS_RECEIVER } from "./Session";
|
||||||
|
|
||||||
|
|
||||||
// Increase listener limit
|
// Increase listener limit
|
||||||
events.EventEmitter.defaultMaxListeners = 50;
|
events.EventEmitter.defaultMaxListeners = 50;
|
||||||
@@ -86,7 +91,9 @@ process.on("SIGTERM", () => {
|
|||||||
receiverSelectorApp.kill();
|
receiverSelectorApp.kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
browser.stop();
|
if (browser) {
|
||||||
|
browser.stop();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -175,6 +182,24 @@ async function handleMessage (message: Message) {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "bridge:/stopReceiverApp": {
|
||||||
|
const receiver: Receiver = message.data.receiver;
|
||||||
|
const client = new Client();
|
||||||
|
|
||||||
|
client.connect({ host: receiver.host, port: receiver.port }, () => {
|
||||||
|
const sourceId = "sender-0";
|
||||||
|
const destinationId = "receiver-0";
|
||||||
|
|
||||||
|
const clientConnection = client.createChannel(
|
||||||
|
sourceId, destinationId, NS_CONNECTION, "JSON");
|
||||||
|
const clientReceiver = client.createChannel(
|
||||||
|
sourceId, destinationId, NS_RECEIVER, "JSON");
|
||||||
|
|
||||||
|
clientConnection.send({ type: "CONNECT" });
|
||||||
|
clientReceiver.send({ type: "STOP", requestId: 1 });
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,9 +240,13 @@ function handleReceiverSelectorMessage (message: Message) {
|
|||||||
|
|
||||||
receiverSelectorApp.stdout!.setEncoding("utf8");
|
receiverSelectorApp.stdout!.setEncoding("utf8");
|
||||||
receiverSelectorApp.stdout!.on("data", data => {
|
receiverSelectorApp.stdout!.on("data", data => {
|
||||||
|
const parsedData = JSON.parse(data);
|
||||||
|
|
||||||
sendMessage({
|
sendMessage({
|
||||||
subject: "main:/receiverSelector/selected"
|
subject: !parsedData.mediaType
|
||||||
, data: JSON.parse(data)
|
? "main:/receiverSelector/stop"
|
||||||
|
: "main:/receiverSelector/selected"
|
||||||
|
, data: parsedData
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
import { ReceiverStatus } from "./castTypes";
|
||||||
|
|
||||||
export interface Message {
|
export interface Message {
|
||||||
subject: string;
|
subject: string;
|
||||||
data?: any;
|
data?: any;
|
||||||
_id?: string;
|
_id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Receiver {
|
||||||
|
host: string;
|
||||||
|
friendlyName: string;
|
||||||
|
id: string;
|
||||||
|
port: number;
|
||||||
|
status?: ReceiverStatus;
|
||||||
|
}
|
||||||
|
|
||||||
export type SendMessageCallback = (message: Message) => void;
|
export type SendMessageCallback = (message: Message) => void;
|
||||||
|
|||||||
@@ -56,6 +56,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
, "popupStopButtonTitle": {
|
||||||
|
"message": "Stop"
|
||||||
|
, "description": "Alternate action button text displayed instead of popupCastButtonTitle."
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
, "contextCast": {
|
, "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 () {
|
private async createBridgePort () {
|
||||||
const bridgePort = await bridge.connect();
|
const bridgePort = await bridge.connect();
|
||||||
bridgePort.onMessage.addListener(this.onBridgePortMessage);
|
bridgePort.onMessage.addListener(this.onBridgePortMessage);
|
||||||
|
|||||||
@@ -65,6 +65,12 @@ export default class NativeReceiverSelector
|
|||||||
this.onBridgePortMessageClose();
|
this.onBridgePortMessageClose();
|
||||||
break;
|
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_extensionName: _("extensionName")
|
||||||
, i18n_castButtonTitle: _("popupCastButtonTitle")
|
, i18n_castButtonTitle: _("popupCastButtonTitle")
|
||||||
|
, i18n_stopButtonTitle: _("popupStopButtonTitle")
|
||||||
, i18n_mediaTypeApp:
|
, i18n_mediaTypeApp:
|
||||||
knownApps[requestedAppId] ?? _("popupMediaTypeApp")
|
knownApps[requestedAppId] ?? _("popupMediaTypeApp")
|
||||||
, i18n_mediaTypeTab: _("popupMediaTypeTab")
|
, i18n_mediaTypeTab: _("popupMediaTypeTab")
|
||||||
|
|||||||
@@ -154,6 +154,14 @@ export default class PopupReceiverSelector
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "receiverSelector:/stop": {
|
||||||
|
this.dispatchEvent(new CustomEvent("stop", {
|
||||||
|
detail: message.data
|
||||||
|
}));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export interface ReceiverSelectorEvents {
|
|||||||
"selected": ReceiverSelection;
|
"selected": ReceiverSelection;
|
||||||
"error": string;
|
"error": string;
|
||||||
"cancelled": void;
|
"cancelled": void;
|
||||||
|
"stop": { receiver: Receiver };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default interface ReceiverSelector
|
export default interface ReceiverSelector
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import { ReceiverSelection
|
|||||||
import NativeReceiverSelector from "./NativeReceiverSelector";
|
import NativeReceiverSelector from "./NativeReceiverSelector";
|
||||||
import PopupReceiverSelector from "./PopupReceiverSelector";
|
import PopupReceiverSelector from "./PopupReceiverSelector";
|
||||||
|
|
||||||
|
import { Receiver } from "../../types";
|
||||||
|
|
||||||
|
|
||||||
async function createSelector () {
|
async function createSelector () {
|
||||||
const type = await options.get("receiverSelectorType");
|
const type = await options.get("receiverSelectorType");
|
||||||
@@ -60,9 +62,18 @@ async function getSelection (
|
|||||||
: Promise<ReceiverSelection> {
|
: Promise<ReceiverSelection> {
|
||||||
|
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
const currentShim = ShimManager.getShim(
|
let currentShim = ShimManager.getShim(
|
||||||
contextTabId, contextFrameId);
|
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 defaultMediaType = ReceiverSelectorMediaType.Tab;
|
||||||
let availableMediaTypes;
|
let availableMediaTypes;
|
||||||
|
|
||||||
@@ -107,20 +118,43 @@ async function getSelection (
|
|||||||
// Get a new selector for each selection
|
// Get a new selector for each selection
|
||||||
sharedSelector = await createSelector();
|
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);
|
console.info("fx_cast (Debug): Selected receiver", ev.detail);
|
||||||
resolve(ev.detail);
|
resolve(ev.detail);
|
||||||
});
|
removeListeners();
|
||||||
|
}
|
||||||
|
|
||||||
sharedSelector.addEventListener("cancelled", () => {
|
function onCancelled () {
|
||||||
console.info("fx_cast (Debug): Cancelled receiver selection");
|
console.info("fx_cast (Debug): Cancelled receiver selection");
|
||||||
resolve(null);
|
resolve(null);
|
||||||
});
|
removeListeners();
|
||||||
|
}
|
||||||
|
|
||||||
sharedSelector.addEventListener("error", () => {
|
function onError () {
|
||||||
console.error("fx_cast (Debug): Failed to select receiver");
|
console.error("fx_cast (Debug): Failed to select receiver");
|
||||||
reject();
|
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
|
// Ensure status manager is initialized
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ class PopupApp extends Component<{}, PopupAppState> {
|
|||||||
|
|
||||||
this.onSelectChange = this.onSelectChange.bind(this);
|
this.onSelectChange = this.onSelectChange.bind(this);
|
||||||
this.onCast = this.onCast.bind(this);
|
this.onCast = this.onCast.bind(this);
|
||||||
|
this.onStop = this.onStop.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount () {
|
public componentDidMount () {
|
||||||
@@ -169,6 +170,7 @@ class PopupApp extends Component<{}, PopupAppState> {
|
|||||||
? this.state.receivers.map((receiver, i) => (
|
? this.state.receivers.map((receiver, i) => (
|
||||||
<ReceiverEntry receiver={ receiver }
|
<ReceiverEntry receiver={ receiver }
|
||||||
onCast={ this.onCast }
|
onCast={ this.onCast }
|
||||||
|
onStop={ this.onStop }
|
||||||
isLoading={ this.state.isLoading }
|
isLoading={ this.state.isLoading }
|
||||||
canCast={ canCast }
|
canCast={ canCast }
|
||||||
key={ i } /> ))
|
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>) {
|
private onSelectChange (ev: React.ChangeEvent<HTMLSelectElement>) {
|
||||||
const mediaType = parseInt(ev.target.value);
|
const mediaType = parseInt(ev.target.value);
|
||||||
|
|
||||||
@@ -232,11 +241,13 @@ interface ReceiverEntryProps {
|
|||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
canCast: boolean;
|
canCast: boolean;
|
||||||
onCast (receiver: Receiver): void;
|
onCast (receiver: Receiver): void;
|
||||||
|
onStop (receiver: Receiver): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ReceiverEntryState {
|
interface ReceiverEntryState {
|
||||||
ellipsis: string;
|
ellipsis: string;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
|
showAlternateAction: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReceiverEntry extends Component<ReceiverEntryProps, ReceiverEntryState> {
|
class ReceiverEntry extends Component<ReceiverEntryProps, ReceiverEntryState> {
|
||||||
@@ -244,10 +255,26 @@ class ReceiverEntry extends Component<ReceiverEntryProps, ReceiverEntryState> {
|
|||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
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);
|
this.handleCast = this.handleCast.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,25 +300,33 @@ class ReceiverEntry extends Component<ReceiverEntryProps, ReceiverEntryState> {
|
|||||||
, (this.state.isLoading
|
, (this.state.isLoading
|
||||||
? this.state.ellipsis
|
? this.state.ellipsis
|
||||||
: ""))
|
: ""))
|
||||||
: _("popupCastButtonTitle") }
|
: !application.isIdleScreen && this.state.showAlternateAction
|
||||||
|
? _("popupStopButtonTitle")
|
||||||
|
: _("popupCastButtonTitle") }
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleCast () {
|
private handleCast () {
|
||||||
this.props.onCast(this.props.receiver);
|
const { application } = this.props.receiver.status;
|
||||||
|
|
||||||
this.setState({
|
if (!application.isIdleScreen && this.state.showAlternateAction) {
|
||||||
isLoading: true
|
this.props.onStop(this.props.receiver);
|
||||||
});
|
} else {
|
||||||
|
this.props.onCast(this.props.receiver);
|
||||||
|
|
||||||
setInterval(() => {
|
this.setState({
|
||||||
this.setState(state => ({
|
isLoading: true
|
||||||
ellipsis: getNextEllipsis(state.ellipsis)
|
});
|
||||||
}));
|
|
||||||
|
|
||||||
}, 500);
|
setInterval(() => {
|
||||||
|
this.setState(state => ({
|
||||||
|
ellipsis: getNextEllipsis(state.ellipsis)
|
||||||
|
}));
|
||||||
|
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user