jiti-meet/react/features/recording/components/LiveStream/StartLiveStreamDialog.web.js

344 lines
10 KiB
JavaScript
Raw Normal View History

feat(recording): frontend logic can support live streaming and recording (#2952) * feat(recording): frontend logic can support live streaming and recording Instead of either live streaming or recording, now both can live together. The changes to facilitate such include the following: - Killing the state storing in Recording.js. Instead state is stored in the lib and updated in redux for labels to display the necessary state updates. - Creating a new container, Labels, for recording labels. Previously labels were manually created and positioned. The container can create a reasonable number of labels and only the container itself needs to be positioned with CSS. The VideoQualityLabel has been shoved into the container as well because it moves along with the recording labels. - The action for updating recording state has been modified to enable updating an array of recording sessions to support having multiple sessions. - Confirmation dialogs for stopping and starting a file recording session have been created, as they previously were jquery modals opened by Recording.js. - Toolbox.web displays live streaming and recording buttons based on configuration instead of recording availability. - VideoQualityLabel and RecordingLabel have been simplified to remove any positioning logic, as the Labels container handles such. - Previous recording state update logic has been moved into the RecordingLabel component. Each RecordingLabel is in charge of displaying state for a recording session. The display UX has been left alone. - Sipgw availability is no longer broadcast so remove logic depending on its state. Some moving around of code was necessary to get around linting errors about the existing code being too deeply nested (even though I didn't touch it). * work around lib-jitsi-meet circular dependency issues * refactor labels to use html base * pass in translation keys to video quality label * add video quality classnames for torture tests * break up, rearrange recorder session update listener * add comment about disabling startup resize animation * rename session to sessionData * chore(deps): update to latest lib for recording changes
2018-05-16 14:00:16 +00:00
// @flow
import Spinner from '@atlaskit/spinner';
2018-07-05 11:17:45 +00:00
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../base/i18n';
import {
GOOGLE_API_STATES,
Google & Microsoft calendar API integration (#3340) * Refactor calendar-sync feature to be loaded on web. For the web part it just adds new property to enable/disable calendar web integration, disabled by default. * Initial implementation of retrieving google calendar events. * Initial implementation of retrieving microsoft calendar events. * Fixes comments. * Rework to use the promise part of microsoft-graph-client api. * Moves dispatching some actions, fixing comments. * Makes sure we do not initializeClient google-api client multiple times. * Do not try to login when fetching calendar entries. The case where there is a calendar type google selected, but not logged in, trying to login on loading welcome page will show a warning that it tried to open a popup, which was denied by browser. * Updates profile display data on sign in. * Propagate google-api state to calendar-sync only if we use google cal. * Adds sign out action. * Clears the event listener when the popup closes. * Clears calendarIntegrationInstance on signOut. * WIP: UI for calendar settings, refactor auth flows * Clean up some unused constants, functions and exports. * break circular dependency of function and constant * Exports only isCalendarEnabled from functions. * Checks isSignedIn when doing fetchCalendarEntries on web. * address comments List microsoftApiApplicationClientID in undocument config. remove unused SET_CALENDAR_TYPE action use helper for calendar enabled in bootstrap reorder actions reorder imports change order of signin -> set type -> update profile add logging for signout error reword setting dialog desc to avoid redundancy add jsdoc to microsoft button props reorder calendar constants move default state to reducer (not reused anywhere) update comment about calendar-sync due to removal of getCalendarState update comment for getCalendarIntegration remove vague comment alpha order reducer, return default state on reset alpha order persistence registry remove unnecessary getType from apis update comments in microsoftCalendar alpha order google-api exports, use api.get in loadGoogleAPI set jsdoc for google signin props alpha order googleapi methods fix calendartab docs * Moves fetching calendar from APP_WILL_MOUNT to SET_CONFIG. The web part needs configuration in order to refresh tokens (Microsoft). * Fixes storing token expire time and refreshing tokens in Microsoft impl. * Address comments updateProfile changed to getCurrentEmail rename result to results stop storing integration in redux, store if ready for use use existing helpers to parse redirect url * update jsdocs, get google app id from redux * clear integration instead of actual sign out
2018-08-15 20:11:54 +00:00
GoogleSignInButton,
loadGoogleAPI,
requestAvailableYouTubeBroadcasts,
requestLiveStreamsForYouTubeBroadcast,
showAccountSelection,
Google & Microsoft calendar API integration (#3340) * Refactor calendar-sync feature to be loaded on web. For the web part it just adds new property to enable/disable calendar web integration, disabled by default. * Initial implementation of retrieving google calendar events. * Initial implementation of retrieving microsoft calendar events. * Fixes comments. * Rework to use the promise part of microsoft-graph-client api. * Moves dispatching some actions, fixing comments. * Makes sure we do not initializeClient google-api client multiple times. * Do not try to login when fetching calendar entries. The case where there is a calendar type google selected, but not logged in, trying to login on loading welcome page will show a warning that it tried to open a popup, which was denied by browser. * Updates profile display data on sign in. * Propagate google-api state to calendar-sync only if we use google cal. * Adds sign out action. * Clears the event listener when the popup closes. * Clears calendarIntegrationInstance on signOut. * WIP: UI for calendar settings, refactor auth flows * Clean up some unused constants, functions and exports. * break circular dependency of function and constant * Exports only isCalendarEnabled from functions. * Checks isSignedIn when doing fetchCalendarEntries on web. * address comments List microsoftApiApplicationClientID in undocument config. remove unused SET_CALENDAR_TYPE action use helper for calendar enabled in bootstrap reorder actions reorder imports change order of signin -> set type -> update profile add logging for signout error reword setting dialog desc to avoid redundancy add jsdoc to microsoft button props reorder calendar constants move default state to reducer (not reused anywhere) update comment about calendar-sync due to removal of getCalendarState update comment for getCalendarIntegration remove vague comment alpha order reducer, return default state on reset alpha order persistence registry remove unnecessary getType from apis update comments in microsoftCalendar alpha order google-api exports, use api.get in loadGoogleAPI set jsdoc for google signin props alpha order googleapi methods fix calendartab docs * Moves fetching calendar from APP_WILL_MOUNT to SET_CONFIG. The web part needs configuration in order to refresh tokens (Microsoft). * Fixes storing token expire time and refreshing tokens in Microsoft impl. * Address comments updateProfile changed to getCurrentEmail rename result to results stop storing integration in redux, store if ready for use use existing helpers to parse redirect url * update jsdocs, get google app id from redux * clear integration instead of actual sign out
2018-08-15 20:11:54 +00:00
signIn,
updateProfile
} from '../../../google-api';
2018-07-05 11:17:45 +00:00
import AbstractStartLiveStreamDialog, {
_mapStateToProps,
type Props
} from './AbstractStartLiveStreamDialog';
import StreamKeyPicker from './StreamKeyPicker';
import StreamKeyForm from './StreamKeyForm';
feat(recording): frontend logic can support live streaming and recording (#2952) * feat(recording): frontend logic can support live streaming and recording Instead of either live streaming or recording, now both can live together. The changes to facilitate such include the following: - Killing the state storing in Recording.js. Instead state is stored in the lib and updated in redux for labels to display the necessary state updates. - Creating a new container, Labels, for recording labels. Previously labels were manually created and positioned. The container can create a reasonable number of labels and only the container itself needs to be positioned with CSS. The VideoQualityLabel has been shoved into the container as well because it moves along with the recording labels. - The action for updating recording state has been modified to enable updating an array of recording sessions to support having multiple sessions. - Confirmation dialogs for stopping and starting a file recording session have been created, as they previously were jquery modals opened by Recording.js. - Toolbox.web displays live streaming and recording buttons based on configuration instead of recording availability. - VideoQualityLabel and RecordingLabel have been simplified to remove any positioning logic, as the Labels container handles such. - Previous recording state update logic has been moved into the RecordingLabel component. Each RecordingLabel is in charge of displaying state for a recording session. The display UX has been left alone. - Sipgw availability is no longer broadcast so remove logic depending on its state. Some moving around of code was necessary to get around linting errors about the existing code being too deeply nested (even though I didn't touch it). * work around lib-jitsi-meet circular dependency issues * refactor labels to use html base * pass in translation keys to video quality label * add video quality classnames for torture tests * break up, rearrange recorder session update listener * add comment about disabling startup resize animation * rename session to sessionData * chore(deps): update to latest lib for recording changes
2018-05-16 14:00:16 +00:00
/**
* A React Component for requesting a YouTube stream key to use for live
* streaming of the current conference.
*
* @extends Component
*/
2018-07-05 11:17:45 +00:00
class StartLiveStreamDialog
extends AbstractStartLiveStreamDialog<Props> {
/**
* Initializes a new {@code StartLiveStreamDialog} instance.
*
* @param {Props} props - The React {@code Component} props to initialize
* the new {@code StartLiveStreamDialog} instance with.
*/
feat(recording): frontend logic can support live streaming and recording (#2952) * feat(recording): frontend logic can support live streaming and recording Instead of either live streaming or recording, now both can live together. The changes to facilitate such include the following: - Killing the state storing in Recording.js. Instead state is stored in the lib and updated in redux for labels to display the necessary state updates. - Creating a new container, Labels, for recording labels. Previously labels were manually created and positioned. The container can create a reasonable number of labels and only the container itself needs to be positioned with CSS. The VideoQualityLabel has been shoved into the container as well because it moves along with the recording labels. - The action for updating recording state has been modified to enable updating an array of recording sessions to support having multiple sessions. - Confirmation dialogs for stopping and starting a file recording session have been created, as they previously were jquery modals opened by Recording.js. - Toolbox.web displays live streaming and recording buttons based on configuration instead of recording availability. - VideoQualityLabel and RecordingLabel have been simplified to remove any positioning logic, as the Labels container handles such. - Previous recording state update logic has been moved into the RecordingLabel component. Each RecordingLabel is in charge of displaying state for a recording session. The display UX has been left alone. - Sipgw availability is no longer broadcast so remove logic depending on its state. Some moving around of code was necessary to get around linting errors about the existing code being too deeply nested (even though I didn't touch it). * work around lib-jitsi-meet circular dependency issues * refactor labels to use html base * pass in translation keys to video quality label * add video quality classnames for torture tests * break up, rearrange recorder session update listener * add comment about disabling startup resize animation * rename session to sessionData * chore(deps): update to latest lib for recording changes
2018-05-16 14:00:16 +00:00
constructor(props: Props) {
super(props);
// Bind event handlers so they are only bound once per instance.
this._onGetYouTubeBroadcasts = this._onGetYouTubeBroadcasts.bind(this);
this._onInitializeGoogleApi = this._onInitializeGoogleApi.bind(this);
this._onGoogleSignIn = this._onGoogleSignIn.bind(this);
this._onRequestGoogleSignIn = this._onRequestGoogleSignIn.bind(this);
this._onYouTubeBroadcastIDSelected
= this._onYouTubeBroadcastIDSelected.bind(this);
2018-07-05 11:17:45 +00:00
this._renderDialogContent = this._renderDialogContent.bind(this);
}
/**
* Implements {@link Component#componentDidMount()}. Invoked immediately
* after this component is mounted.
*
* @inheritdoc
* @returns {void}
*/
componentDidMount() {
super.componentDidMount();
if (this.props._googleApiApplicationClientID) {
this._onInitializeGoogleApi();
}
}
2018-07-05 11:17:45 +00:00
_onInitializeGoogleApi: () => Promise<*>;
feat(recording): frontend logic can support live streaming and recording (#2952) * feat(recording): frontend logic can support live streaming and recording Instead of either live streaming or recording, now both can live together. The changes to facilitate such include the following: - Killing the state storing in Recording.js. Instead state is stored in the lib and updated in redux for labels to display the necessary state updates. - Creating a new container, Labels, for recording labels. Previously labels were manually created and positioned. The container can create a reasonable number of labels and only the container itself needs to be positioned with CSS. The VideoQualityLabel has been shoved into the container as well because it moves along with the recording labels. - The action for updating recording state has been modified to enable updating an array of recording sessions to support having multiple sessions. - Confirmation dialogs for stopping and starting a file recording session have been created, as they previously were jquery modals opened by Recording.js. - Toolbox.web displays live streaming and recording buttons based on configuration instead of recording availability. - VideoQualityLabel and RecordingLabel have been simplified to remove any positioning logic, as the Labels container handles such. - Previous recording state update logic has been moved into the RecordingLabel component. Each RecordingLabel is in charge of displaying state for a recording session. The display UX has been left alone. - Sipgw availability is no longer broadcast so remove logic depending on its state. Some moving around of code was necessary to get around linting errors about the existing code being too deeply nested (even though I didn't touch it). * work around lib-jitsi-meet circular dependency issues * refactor labels to use html base * pass in translation keys to video quality label * add video quality classnames for torture tests * break up, rearrange recorder session update listener * add comment about disabling startup resize animation * rename session to sessionData * chore(deps): update to latest lib for recording changes
2018-05-16 14:00:16 +00:00
/**
* Loads the Google web client application used for fetching stream keys.
* If the user is already logged in, then a request for available YouTube
* broadcasts is also made.
*
* @private
* @returns {Promise}
*/
_onInitializeGoogleApi() {
this.props.dispatch(
loadGoogleAPI(this.props._googleApiApplicationClientID))
.catch(response => this._parseErrorFromResponse(response));
}
/**
* Automatically selects the input field's value after starting to edit the
* display name.
*
* @inheritdoc
* @returns {void}
*/
componentDidUpdate(previousProps) {
if (previousProps._googleAPIState === GOOGLE_API_STATES.LOADED
&& this.props._googleAPIState === GOOGLE_API_STATES.SIGNED_IN) {
this._onGetYouTubeBroadcasts();
}
}
2018-07-05 11:17:45 +00:00
_onGetYouTubeBroadcasts: () => Promise<*>;
feat(recording): frontend logic can support live streaming and recording (#2952) * feat(recording): frontend logic can support live streaming and recording Instead of either live streaming or recording, now both can live together. The changes to facilitate such include the following: - Killing the state storing in Recording.js. Instead state is stored in the lib and updated in redux for labels to display the necessary state updates. - Creating a new container, Labels, for recording labels. Previously labels were manually created and positioned. The container can create a reasonable number of labels and only the container itself needs to be positioned with CSS. The VideoQualityLabel has been shoved into the container as well because it moves along with the recording labels. - The action for updating recording state has been modified to enable updating an array of recording sessions to support having multiple sessions. - Confirmation dialogs for stopping and starting a file recording session have been created, as they previously were jquery modals opened by Recording.js. - Toolbox.web displays live streaming and recording buttons based on configuration instead of recording availability. - VideoQualityLabel and RecordingLabel have been simplified to remove any positioning logic, as the Labels container handles such. - Previous recording state update logic has been moved into the RecordingLabel component. Each RecordingLabel is in charge of displaying state for a recording session. The display UX has been left alone. - Sipgw availability is no longer broadcast so remove logic depending on its state. Some moving around of code was necessary to get around linting errors about the existing code being too deeply nested (even though I didn't touch it). * work around lib-jitsi-meet circular dependency issues * refactor labels to use html base * pass in translation keys to video quality label * add video quality classnames for torture tests * break up, rearrange recorder session update listener * add comment about disabling startup resize animation * rename session to sessionData * chore(deps): update to latest lib for recording changes
2018-05-16 14:00:16 +00:00
/**
* Asks the user to sign in, if not already signed in, and then requests a
* list of the user's YouTube broadcasts.
*
* @private
* @returns {void}
*/
_onGetYouTubeBroadcasts() {
this.props.dispatch(updateProfile())
.catch(response => this._parseErrorFromResponse(response));
this.props.dispatch(requestAvailableYouTubeBroadcasts())
.then(broadcasts => {
this._setStateIfMounted({
broadcasts
});
if (broadcasts.length === 1) {
const broadcast = broadcasts[0];
this._onYouTubeBroadcastIDSelected(broadcast.boundStreamID);
}
})
.catch(response => this._parseErrorFromResponse(response));
}
_onGoogleSignIn: () => Object;
/**
* Forces the Google web client application to prompt for a sign in, such as
* when changing account, and will then fetch available YouTube broadcasts.
*
* @private
* @returns {Promise}
*/
_onGoogleSignIn() {
this.props.dispatch(signIn())
.catch(response => this._parseErrorFromResponse(response));
}
feat(recording): frontend logic can support live streaming and recording (#2952) * feat(recording): frontend logic can support live streaming and recording Instead of either live streaming or recording, now both can live together. The changes to facilitate such include the following: - Killing the state storing in Recording.js. Instead state is stored in the lib and updated in redux for labels to display the necessary state updates. - Creating a new container, Labels, for recording labels. Previously labels were manually created and positioned. The container can create a reasonable number of labels and only the container itself needs to be positioned with CSS. The VideoQualityLabel has been shoved into the container as well because it moves along with the recording labels. - The action for updating recording state has been modified to enable updating an array of recording sessions to support having multiple sessions. - Confirmation dialogs for stopping and starting a file recording session have been created, as they previously were jquery modals opened by Recording.js. - Toolbox.web displays live streaming and recording buttons based on configuration instead of recording availability. - VideoQualityLabel and RecordingLabel have been simplified to remove any positioning logic, as the Labels container handles such. - Previous recording state update logic has been moved into the RecordingLabel component. Each RecordingLabel is in charge of displaying state for a recording session. The display UX has been left alone. - Sipgw availability is no longer broadcast so remove logic depending on its state. Some moving around of code was necessary to get around linting errors about the existing code being too deeply nested (even though I didn't touch it). * work around lib-jitsi-meet circular dependency issues * refactor labels to use html base * pass in translation keys to video quality label * add video quality classnames for torture tests * break up, rearrange recorder session update listener * add comment about disabling startup resize animation * rename session to sessionData * chore(deps): update to latest lib for recording changes
2018-05-16 14:00:16 +00:00
_onRequestGoogleSignIn: () => Object;
/**
* Forces the Google web client application to prompt for a sign in, such as
* when changing account, and will then fetch available YouTube broadcasts.
*
* @private
* @returns {Promise}
*/
_onRequestGoogleSignIn() {
// when there is an error we show the google sign-in button.
// once we click it we want to clear the error from the state
this.props.dispatch(showAccountSelection())
.then(() =>
this._setStateIfMounted({
broadcasts: undefined,
errorType: undefined
}))
.then(() => this._onGetYouTubeBroadcasts());
}
2018-07-05 11:17:45 +00:00
_onStreamKeyChange: string => void;
feat(recording): frontend logic can support live streaming and recording (#2952) * feat(recording): frontend logic can support live streaming and recording Instead of either live streaming or recording, now both can live together. The changes to facilitate such include the following: - Killing the state storing in Recording.js. Instead state is stored in the lib and updated in redux for labels to display the necessary state updates. - Creating a new container, Labels, for recording labels. Previously labels were manually created and positioned. The container can create a reasonable number of labels and only the container itself needs to be positioned with CSS. The VideoQualityLabel has been shoved into the container as well because it moves along with the recording labels. - The action for updating recording state has been modified to enable updating an array of recording sessions to support having multiple sessions. - Confirmation dialogs for stopping and starting a file recording session have been created, as they previously were jquery modals opened by Recording.js. - Toolbox.web displays live streaming and recording buttons based on configuration instead of recording availability. - VideoQualityLabel and RecordingLabel have been simplified to remove any positioning logic, as the Labels container handles such. - Previous recording state update logic has been moved into the RecordingLabel component. Each RecordingLabel is in charge of displaying state for a recording session. The display UX has been left alone. - Sipgw availability is no longer broadcast so remove logic depending on its state. Some moving around of code was necessary to get around linting errors about the existing code being too deeply nested (even though I didn't touch it). * work around lib-jitsi-meet circular dependency issues * refactor labels to use html base * pass in translation keys to video quality label * add video quality classnames for torture tests * break up, rearrange recorder session update listener * add comment about disabling startup resize animation * rename session to sessionData * chore(deps): update to latest lib for recording changes
2018-05-16 14:00:16 +00:00
_onYouTubeBroadcastIDSelected: (string) => Object;
/**
* Fetches the stream key for a YouTube broadcast and updates the internal
* state to display the associated stream key as being entered.
*
* @param {string} boundStreamID - The bound stream ID associated with the
* broadcast from which to get the stream key.
* @private
* @returns {Promise}
*/
_onYouTubeBroadcastIDSelected(boundStreamID) {
this.props.dispatch(
requestLiveStreamsForYouTubeBroadcast(boundStreamID))
.then(({ streamKey, selectedBoundStreamID }) =>
this._setStateIfMounted({
streamKey,
selectedBoundStreamID
}));
}
/**
* Only show an error if an external request was made with the Google api.
* Do not error if the login in canceled.
* And searches in a Google API error response for the error type.
*
* @param {Object} response - The Google API response that may contain an
* error.
* @private
* @returns {string|null}
*/
_parseErrorFromResponse(response) {
if (!response || !response.result) {
return;
}
const result = response.result;
const error = result.error;
const errors = error && error.errors;
const firstError = errors && errors[0];
this._setStateIfMounted({
errorType: (firstError && firstError.reason) || null
});
}
2018-07-05 11:17:45 +00:00
_renderDialogContent: () => React$Component<*>
/**
* Renders the platform specific dialog content.
*
* @returns {React$Component}
*/
_renderDialogContent() {
const { _googleApiApplicationClientID } = this.props;
return (
<div className = 'live-stream-dialog'>
{ _googleApiApplicationClientID
? this._renderYouTubePanel() : null }
<StreamKeyForm
onChange = { this._onStreamKeyChange }
value = { this.state.streamKey || this.props._streamKey } />
</div>
);
}
/**
* Renders a React Element for authenticating with the Google web client.
*
* @private
* @returns {ReactElement}
*/
_renderYouTubePanel() {
const {
t,
_googleProfileEmail
} = this.props;
const {
broadcasts,
selectedBoundStreamID
} = this.state;
let googleContent, helpText;
switch (this.props._googleAPIState) {
case GOOGLE_API_STATES.LOADED:
googleContent
= <GoogleSignInButton onClick = { this._onGoogleSignIn } />;
helpText = t('liveStreaming.signInCTA');
break;
case GOOGLE_API_STATES.SIGNED_IN:
googleContent = (
<StreamKeyPicker
broadcasts = { broadcasts }
onBroadcastSelected = { this._onYouTubeBroadcastIDSelected }
selectedBoundStreamID = { selectedBoundStreamID } />
);
/**
* FIXME: Ideally this help text would be one translation string
* that also accepts the anchor. This can be done using the Trans
* component of react-i18next but I couldn't get it working...
*/
helpText = (
<div>
{ `${t('liveStreaming.chooseCTA',
{ email: _googleProfileEmail })} ` }
<a onClick = { this._onRequestGoogleSignIn }>
{ t('liveStreaming.changeSignIn') }
</a>
</div>
);
break;
case GOOGLE_API_STATES.NEEDS_LOADING:
default:
googleContent = (
<Spinner
isCompleting = { false }
size = 'medium' />
);
break;
}
if (this.state.errorType !== undefined) {
googleContent = (
<GoogleSignInButton
onClick = { this._onRequestGoogleSignIn } />
);
helpText = this._getGoogleErrorMessageToDisplay();
}
return (
<div className = 'google-panel'>
<div className = 'live-stream-cta'>
{ helpText }
</div>
<div className = 'google-api'>
{ googleContent }
</div>
</div>
);
}
2018-07-05 11:17:45 +00:00
_setStateIfMounted: Object => void
/**
* Returns the error message to display for the current error state.
*
* @private
* @returns {string} The error message to display.
*/
_getGoogleErrorMessageToDisplay() {
let text;
switch (this.state.errorType) {
case 'liveStreamingNotEnabled':
text = this.props.t(
'liveStreaming.errorLiveStreamNotEnabled',
{ email: this.props._googleProfileEmail });
break;
default:
text = this.props.t('liveStreaming.errorAPI');
break;
}
return <div className = 'google-error'>{ text }</div>;
}
}
export default translate(connect(_mapStateToProps)(StartLiveStreamDialog));