From 07bcb38dd6d3ac9f9a392ddbb828a2ffbc1f2e3e Mon Sep 17 00:00:00 2001 From: Leonard Kim Date: Mon, 17 Dec 2018 20:21:18 -0800 Subject: [PATCH] fix(live-streaming): show message if no broadcasts are found It's possible for the YouTube api to return zero broadcasts or broadcasts without any streams--streams are what are associated with stream keys. In this case, instead of showing an empty selector or no selector, show a message with a link to where the stream key can be obtained. --- css/_recording.scss | 20 +++++----- lang/main.json | 1 + .../components/LiveStream/constants.js | 6 +++ .../LiveStream/native/StreamKeyPicker.js | 40 ++++++++++++++++++- .../LiveStream/web/StartLiveStreamDialog.js | 21 +++++++--- .../LiveStream/web/StreamKeyForm.js | 2 +- .../LiveStream/web/StreamKeyPicker.js | 14 +++++++ 7 files changed, 84 insertions(+), 20 deletions(-) create mode 100644 react/features/recording/components/LiveStream/constants.js diff --git a/css/_recording.scss b/css/_recording.scss index d2e42f823..75a2cc564 100644 --- a/css/_recording.scss +++ b/css/_recording.scss @@ -95,17 +95,15 @@ padding-bottom: 10px; } - .stream-key-form { - .helper-link { - cursor: pointer; - display: inline-block; - flex-shrink: 0; - margin-left: auto; - } + .helper-link { + cursor: pointer; + display: inline-block; + flex-shrink: 0; + margin-left: auto; + } - .validation-error { - color:#FFD740; - font-size: 12px; - } + .warning-text { + color:#FFD740; + font-size: 12px; } } diff --git a/lang/main.json b/lang/main.json index 6a0f2049b..b464e56a0 100644 --- a/lang/main.json +++ b/lang/main.json @@ -516,6 +516,7 @@ "expandedPending": "The live streaming is being started...", "failedToStart": "Live Streaming failed to start", "invalidStreamKey": "Live stream key may be incorrect.", + "getStreamKeyManually": "We weren’t able to fetch any live streams. Try getting your live stream key from YouTube.", "off": "Live Streaming stopped", "on": "Live Streaming", "pending": "Starting Live Stream...", diff --git a/react/features/recording/components/LiveStream/constants.js b/react/features/recording/components/LiveStream/constants.js new file mode 100644 index 000000000..fec5b3d47 --- /dev/null +++ b/react/features/recording/components/LiveStream/constants.js @@ -0,0 +1,6 @@ +/** + * The URL that is the main landing page for YouTube live streaming and should + * have a user's live stream key. + */ +export const YOUTUBE_LIVE_DASHBOARD_URL + = 'https://www.youtube.com/live_dashboard'; diff --git a/react/features/recording/components/LiveStream/native/StreamKeyPicker.js b/react/features/recording/components/LiveStream/native/StreamKeyPicker.js index eeb818b19..f9dabdda3 100644 --- a/react/features/recording/components/LiveStream/native/StreamKeyPicker.js +++ b/react/features/recording/components/LiveStream/native/StreamKeyPicker.js @@ -1,10 +1,18 @@ // @flow import React, { Component } from 'react'; -import { Text, TouchableHighlight, View } from 'react-native'; +import { + Linking, + Text, + TouchableHighlight, + TouchableOpacity, + View +} from 'react-native'; import { translate } from '../../../../base/i18n'; +import { YOUTUBE_LIVE_DASHBOARD_URL } from '../constants'; + import styles, { ACTIVE_OPACITY, TOUCHABLE_UNDERLAY } from './styles'; type Props = { @@ -56,6 +64,7 @@ class StreamKeyPicker extends Component { streamKey: null }; + this._onOpenYoutubeDashboard = this._onOpenYoutubeDashboard.bind(this); this._onStreamPick = this._onStreamPick.bind(this); } @@ -67,10 +76,24 @@ class StreamKeyPicker extends Component { render() { const { broadcasts } = this.props; - if (!broadcasts || !broadcasts.length) { + if (!broadcasts) { return null; } + if (!broadcasts.length) { + return ( + + + + { this.props.t( + 'liveStreaming.getStreamKeyManually') } + + + + ); + } + return ( @@ -100,6 +123,19 @@ class StreamKeyPicker extends Component { ); } + _onOpenYoutubeDashboard: () => void; + + /** + * Opens the link which should display the YouTube broadcast live stream + * key. + * + * @private + * @returns {void} + */ + _onOpenYoutubeDashboard() { + Linking.openURL(YOUTUBE_LIVE_DASHBOARD_URL); + } + _onStreamPick: string => Function /** diff --git a/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.js b/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.js index 48bff41d9..c8294e235 100644 --- a/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.js +++ b/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.js @@ -280,12 +280,21 @@ class StartLiveStreamDialog break; case GOOGLE_API_STATES.SIGNED_IN: - googleContent = ( - - ); + if (broadcasts) { + googleContent = ( + + ); + } else { + googleContent = ( + + ); + } /** * FIXME: Ideally this help text would be one translation string diff --git a/react/features/recording/components/LiveStream/web/StreamKeyForm.js b/react/features/recording/components/LiveStream/web/StreamKeyForm.js index 130e3a9f5..abd627e1d 100644 --- a/react/features/recording/components/LiveStream/web/StreamKeyForm.js +++ b/react/features/recording/components/LiveStream/web/StreamKeyForm.js @@ -55,7 +55,7 @@ class StreamKeyForm extends AbstractStreamKeyForm {
{ this.state.showValidationError - ? + ? { t('liveStreaming.invalidStreamKey') } : null diff --git a/react/features/recording/components/LiveStream/web/StreamKeyPicker.js b/react/features/recording/components/LiveStream/web/StreamKeyPicker.js index f83ae05dd..b0d793771 100644 --- a/react/features/recording/components/LiveStream/web/StreamKeyPicker.js +++ b/react/features/recording/components/LiveStream/web/StreamKeyPicker.js @@ -9,6 +9,8 @@ import React, { PureComponent } from 'react'; import { translate } from '../../../../base/i18n'; +import { YOUTUBE_LIVE_DASHBOARD_URL } from '../constants'; + /** * The type of the React {@code Component} props of {@link StreamKeyPicker}. */ @@ -95,6 +97,18 @@ class StreamKeyPicker extends PureComponent { render() { const { broadcasts, selectedBoundStreamID, t } = this.props; + if (!broadcasts.length) { + return ( + + { t('liveStreaming.getStreamKeyManually') } + + ); + } + const dropdownItems = broadcasts.map(broadcast => (