mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-05-11 16:22:30 +00:00
Rearrange recording feature files
This commit is contained in:
committed by
Zoltan Bettenbuk
parent
2b1cb75e40
commit
71edea8aac
@@ -0,0 +1,243 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { Platform, Text, View } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../../../base/i18n';
|
||||
|
||||
import {
|
||||
GOOGLE_API_STATES,
|
||||
GOOGLE_SCOPE_YOUTUBE,
|
||||
googleApi,
|
||||
GoogleSignInButton,
|
||||
setGoogleAPIState
|
||||
} from '../../../../google-api';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||
|
||||
/**
|
||||
* Prop type of the component {@code GoogleSigninForm}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The Redux dispatch Function.
|
||||
*/
|
||||
dispatch: Function,
|
||||
|
||||
/**
|
||||
* The current state of the Google api as defined in {@code constants.js}.
|
||||
*/
|
||||
googleAPIState: number,
|
||||
|
||||
/**
|
||||
* The recently received Google response.
|
||||
*/
|
||||
googleResponse: Object,
|
||||
|
||||
/**
|
||||
* A callback to be invoked when an authenticated user changes, so
|
||||
* then we can get (or clear) the YouTube stream key.
|
||||
*/
|
||||
onUserChanged: Function,
|
||||
|
||||
/**
|
||||
* Function to be used to translate i18n labels.
|
||||
*/
|
||||
t: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* Class to render a google sign in form, or a google stream picker dialog.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
class GoogleSigninForm extends Component<Props> {
|
||||
/**
|
||||
* Instantiates a new {@code GoogleSigninForm} component.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this._logGoogleError = this._logGoogleError.bind(this);
|
||||
this._onGoogleButtonPress = this._onGoogleButtonPress.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's Component.componentDidMount.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidMount() {
|
||||
if (Platform.OS === 'ios') {
|
||||
const majorVersionIOS = parseInt(Platform.Version, 10);
|
||||
|
||||
if (majorVersionIOS <= 10) {
|
||||
// Disable it on iOS 10 and earlier, since it doesn't work
|
||||
// properly.
|
||||
this._setApiState(GOOGLE_API_STATES.NOT_AVAILABLE);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
googleApi.hasPlayServices()
|
||||
.then(() => {
|
||||
googleApi.configure({
|
||||
offlineAccess: false,
|
||||
scopes: [ GOOGLE_SCOPE_YOUTUBE ]
|
||||
});
|
||||
|
||||
googleApi.signInSilently().then(response => {
|
||||
this._setApiState(response
|
||||
? GOOGLE_API_STATES.SIGNED_IN
|
||||
: GOOGLE_API_STATES.LOADED,
|
||||
response);
|
||||
}, () => {
|
||||
this._setApiState(GOOGLE_API_STATES.LOADED);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
this._logGoogleError(error);
|
||||
this._setApiState(GOOGLE_API_STATES.NOT_AVAILABLE);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
const { googleAPIState, googleResponse } = this.props;
|
||||
const signedInUser = googleResponse
|
||||
&& googleResponse.user
|
||||
&& googleResponse.user.email;
|
||||
|
||||
if (googleAPIState === GOOGLE_API_STATES.NOT_AVAILABLE
|
||||
|| googleAPIState === GOOGLE_API_STATES.NEEDS_LOADING
|
||||
|| typeof googleAPIState === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style = { styles.formWrapper }>
|
||||
<View style = { styles.helpText }>
|
||||
{ signedInUser ? <Text>
|
||||
{ `${t('liveStreaming.signedInAs')} ${signedInUser}` }
|
||||
</Text> : <Text>
|
||||
{ t('liveStreaming.signInCTA') }
|
||||
</Text> }
|
||||
</View>
|
||||
<GoogleSignInButton
|
||||
onClick = { this._onGoogleButtonPress }
|
||||
signedIn = {
|
||||
googleAPIState === GOOGLE_API_STATES.SIGNED_IN } />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_logGoogleError: Object => void
|
||||
|
||||
/**
|
||||
* A helper function to log developer related errors.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} error - The error to be logged.
|
||||
* @returns {void}
|
||||
*/
|
||||
_logGoogleError(error) {
|
||||
// NOTE: This is a developer error message, not intended for the
|
||||
// user to see.
|
||||
logger.error('Google API error. Possible cause: bad config.', error);
|
||||
}
|
||||
|
||||
_onGoogleButtonPress: () => void
|
||||
|
||||
/**
|
||||
* Callback to be invoked when the user presses the Google button,
|
||||
* regardless of being logged in or out.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onGoogleButtonPress() {
|
||||
const { googleResponse } = this.props;
|
||||
|
||||
if (googleResponse && googleResponse.user) {
|
||||
// the user is signed in
|
||||
this._onSignOut();
|
||||
} else {
|
||||
this._onSignIn();
|
||||
}
|
||||
}
|
||||
|
||||
_onSignIn: () => void
|
||||
|
||||
/**
|
||||
* Initiates a sign in if the user is not signed in yet.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onSignIn() {
|
||||
googleApi.signIn().then(response => {
|
||||
this._setApiState(GOOGLE_API_STATES.SIGNED_IN, response);
|
||||
}, this._logGoogleError);
|
||||
}
|
||||
|
||||
_onSignOut: () => void
|
||||
|
||||
/**
|
||||
* Initiates a sign out if the user is signed in.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onSignOut() {
|
||||
googleApi.signOut().then(response => {
|
||||
this._setApiState(GOOGLE_API_STATES.LOADED, response);
|
||||
}, this._logGoogleError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the API (Google Auth) state.
|
||||
*
|
||||
* @private
|
||||
* @param {number} apiState - The state of the API.
|
||||
* @param {?Object} googleResponse - The response from the API.
|
||||
* @returns {void}
|
||||
*/
|
||||
_setApiState(apiState, googleResponse) {
|
||||
this.props.onUserChanged(googleResponse);
|
||||
this.props.dispatch(setGoogleAPIState(apiState, googleResponse));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to the associated props for the
|
||||
* {@code GoogleSigninForm} component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* googleAPIState: number,
|
||||
* googleResponse: Object
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state: Object) {
|
||||
const { googleAPIState, googleResponse } = state['features/google-api'];
|
||||
|
||||
return {
|
||||
googleAPIState,
|
||||
googleResponse
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(GoogleSigninForm));
|
||||
@@ -0,0 +1,20 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../../../base/i18n';
|
||||
|
||||
import AbstractLiveStreamButton, {
|
||||
_mapStateToProps,
|
||||
type Props
|
||||
} from '../AbstractLiveStreamButton';
|
||||
|
||||
/**
|
||||
* An implementation of a button for starting and stopping live streaming.
|
||||
*/
|
||||
class LiveStreamButton extends AbstractLiveStreamButton<Props> {
|
||||
iconName = 'public';
|
||||
toggledIconName = 'public';
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(LiveStreamButton));
|
||||
@@ -0,0 +1,130 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { googleApi } from '../../../../google-api';
|
||||
|
||||
|
||||
import { setLiveStreamKey } from '../../../actions';
|
||||
|
||||
import AbstractStartLiveStreamDialog,
|
||||
{ _mapStateToProps, type Props } from '../AbstractStartLiveStreamDialog';
|
||||
|
||||
import GoogleSigninForm from './GoogleSigninForm';
|
||||
import StreamKeyForm from './StreamKeyForm';
|
||||
import StreamKeyPicker from './StreamKeyPicker';
|
||||
import styles from './styles';
|
||||
|
||||
/**
|
||||
* A React Component for requesting a YouTube stream key to use for live
|
||||
* streaming of the current conference.
|
||||
*/
|
||||
class StartLiveStreamDialog extends AbstractStartLiveStreamDialog<Props> {
|
||||
/**
|
||||
* Constructor of the component.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._onStreamKeyChangeNative
|
||||
= this._onStreamKeyChangeNative.bind(this);
|
||||
this._onStreamKeyPick = this._onStreamKeyPick.bind(this);
|
||||
this._onUserChanged = this._onUserChanged.bind(this);
|
||||
this._renderDialogContent = this._renderDialogContent.bind(this);
|
||||
}
|
||||
|
||||
_onStreamKeyChange: string => void
|
||||
|
||||
_onStreamKeyChangeNative: string => void;
|
||||
|
||||
/**
|
||||
* Callback to handle stream key changes.
|
||||
*
|
||||
* FIXME: This is a temporary method to store the streaming key on mobile
|
||||
* for easier use, until the Google sign-in is implemented. We don't store
|
||||
* the key on web for security reasons (e.g. We don't want to have the key
|
||||
* stored if the used signed out).
|
||||
*
|
||||
* @private
|
||||
* @param {string} streamKey - The new key value.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onStreamKeyChangeNative(streamKey) {
|
||||
this.props.dispatch(setLiveStreamKey(streamKey));
|
||||
this._onStreamKeyChange(streamKey);
|
||||
}
|
||||
|
||||
_onStreamKeyPick: string => void
|
||||
|
||||
/**
|
||||
* Callback to be invoked when the user selects a stream from the picker.
|
||||
*
|
||||
* @private
|
||||
* @param {string} streamKey - The key of the selected stream.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onStreamKeyPick(streamKey) {
|
||||
this.setState({
|
||||
streamKey
|
||||
});
|
||||
}
|
||||
|
||||
_onUserChanged: Object => void
|
||||
|
||||
/**
|
||||
* A callback to be invoked when an authenticated user changes, so
|
||||
* then we can get (or clear) the YouTube stream key.
|
||||
*
|
||||
* TODO: Handle errors by showing some indication to the user.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} response - The retreived signin response.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onUserChanged(response) {
|
||||
if (response && response.accessToken) {
|
||||
googleApi.getYouTubeLiveStreams(response.accessToken)
|
||||
.then(broadcasts => {
|
||||
this.setState({
|
||||
broadcasts
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
broadcasts: undefined,
|
||||
streamKey: undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_renderDialogContent: () => React$Component<*>
|
||||
|
||||
/**
|
||||
* Renders the platform specific dialog content.
|
||||
*
|
||||
* @returns {React$Component}
|
||||
*/
|
||||
_renderDialogContent() {
|
||||
return (
|
||||
<View style = { styles.startDialogWrapper }>
|
||||
<GoogleSigninForm
|
||||
onUserChanged = { this._onUserChanged } />
|
||||
<StreamKeyPicker
|
||||
broadcasts = { this.state.broadcasts }
|
||||
onChange = { this._onStreamKeyPick } />
|
||||
<StreamKeyForm
|
||||
onChange = { this._onStreamKeyChangeNative }
|
||||
value = { this.state.streamKey || this.props._streamKey } />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(StartLiveStreamDialog));
|
||||
@@ -0,0 +1,37 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { DialogContent } from '../../../../base/dialog';
|
||||
import { translate } from '../../../../base/i18n';
|
||||
|
||||
import AbstractStopLiveStreamDialog, {
|
||||
_mapStateToProps
|
||||
} from '../AbstractStopLiveStreamDialog';
|
||||
|
||||
/**
|
||||
* A React Component for confirming the participant wishes to stop the currently
|
||||
* active live stream of the conference.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
class StopLiveStreamDialog extends AbstractStopLiveStreamDialog {
|
||||
|
||||
/**
|
||||
* Renders the platform specific {@code Dialog} content.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
_renderDialogContent() {
|
||||
return (
|
||||
<DialogContent>
|
||||
{
|
||||
this.props.t('dialog.stopStreamingWarning')
|
||||
}
|
||||
</DialogContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(StopLiveStreamDialog));
|
||||
@@ -0,0 +1,87 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Linking, Text, TextInput, TouchableOpacity, View } from 'react-native';
|
||||
|
||||
import { translate } from '../../../../base/i18n';
|
||||
|
||||
import AbstractStreamKeyForm, {
|
||||
type Props
|
||||
} from '../AbstractStreamKeyForm';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
/**
|
||||
* A React Component for entering a key for starting a YouTube live stream.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
class StreamKeyForm extends AbstractStreamKeyForm {
|
||||
/**
|
||||
* Initializes a new {@code StreamKeyForm} instance.
|
||||
*
|
||||
* @param {Props} props - The React {@code Component} props to initialize
|
||||
* the new {@code StreamKeyForm} instance with.
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._onOpenHelp = this._onOpenHelp.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
|
||||
return (
|
||||
<View style = { styles.formWrapper }>
|
||||
<Text style = { styles.streamKeyInputLabel }>
|
||||
{
|
||||
t('dialog.streamKey')
|
||||
}
|
||||
</Text>
|
||||
<TextInput
|
||||
onChangeText = { this._onInputChange }
|
||||
placeholder = { t('liveStreaming.enterStreamKey') }
|
||||
style = { styles.streamKeyInput }
|
||||
value = { this.state.value } />
|
||||
<TouchableOpacity
|
||||
onPress = { this._onOpenHelp }
|
||||
style = { styles.streamKeyHelp } >
|
||||
<Text>
|
||||
{
|
||||
t('liveStreaming.streamIdHelp')
|
||||
}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_onInputChange: Object => void
|
||||
|
||||
_onOpenHelp: () => void
|
||||
|
||||
/**
|
||||
* Opens the information link on how to manually locate a YouTube broadcast
|
||||
* stream key.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onOpenHelp() {
|
||||
const { helpURL } = this;
|
||||
|
||||
if (typeof helpURL === 'string') {
|
||||
Linking.openURL(helpURL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(StreamKeyForm);
|
||||
@@ -0,0 +1,122 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { Text, TouchableHighlight, View } from 'react-native';
|
||||
|
||||
import { translate } from '../../../../base/i18n';
|
||||
|
||||
import styles, { ACTIVE_OPACITY, TOUCHABLE_UNDERLAY } from './styles';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The list of broadcasts the user can pick from.
|
||||
*/
|
||||
broadcasts: ?Array<Object>,
|
||||
|
||||
/**
|
||||
* Callback to be invoked when the user picked a broadcast. To be invoked
|
||||
* with a single key (string).
|
||||
*/
|
||||
onChange: Function,
|
||||
|
||||
/**
|
||||
* Function to be used to translate i18n labels.
|
||||
*/
|
||||
t: Function
|
||||
}
|
||||
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* The key of the currently selected stream.
|
||||
*/
|
||||
streamKey: ?string
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to implement a stream key picker (dropdown) component to allow the user
|
||||
* to choose from the available Google Broadcasts/Streams.
|
||||
*
|
||||
* NOTE: This component is currently only used on mobile, but it is advised at
|
||||
* a later point to unify mobile and web logic for this functionality. But it's
|
||||
* out of the scope for now of the mobile live streaming functionality.
|
||||
*/
|
||||
class StreamKeyPicker extends Component<Props, State> {
|
||||
|
||||
/**
|
||||
* Instantiates a new instance of StreamKeyPicker.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
streamKey: null
|
||||
};
|
||||
|
||||
this._onStreamPick = this._onStreamPick.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
const { broadcasts } = this.props;
|
||||
|
||||
if (!broadcasts || !broadcasts.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style = { styles.formWrapper }>
|
||||
<View style = { styles.streamKeyPickerCta }>
|
||||
<Text>
|
||||
{ this.props.t('liveStreaming.choose') }
|
||||
</Text>
|
||||
</View>
|
||||
<View style = { styles.streamKeyPickerWrapper } >
|
||||
{ broadcasts.map((broadcast, index) =>
|
||||
(<TouchableHighlight
|
||||
activeOpacity = { ACTIVE_OPACITY }
|
||||
key = { index }
|
||||
onPress = { this._onStreamPick(broadcast.key) }
|
||||
style = { [
|
||||
styles.streamKeyPickerItem,
|
||||
this.state.streamKey === broadcast.key
|
||||
? styles.streamKeyPickerItemHighlight : null
|
||||
] }
|
||||
underlayColor = { TOUCHABLE_UNDERLAY }>
|
||||
<Text style = { styles.streamKeyPickerItemText }>
|
||||
{ broadcast.title }
|
||||
</Text>
|
||||
</TouchableHighlight>))
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_onStreamPick: string => Function
|
||||
|
||||
/**
|
||||
* Callback to be invoked when the user picks a stream from the list.
|
||||
*
|
||||
* @private
|
||||
* @param {string} streamKey - The key of the stream selected.
|
||||
* @returns {Function}
|
||||
*/
|
||||
_onStreamPick(streamKey) {
|
||||
return () => {
|
||||
this.setState({
|
||||
streamKey
|
||||
});
|
||||
this.props.onChange(streamKey);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(StreamKeyPicker);
|
||||
@@ -0,0 +1,5 @@
|
||||
// @flow
|
||||
|
||||
export { default as LiveStreamButton } from './LiveStreamButton';
|
||||
export { default as StartLiveStreamDialog } from './StartLiveStreamDialog';
|
||||
export { default as StopLiveStreamDialog } from './StopLiveStreamDialog';
|
||||
124
react/features/recording/components/LiveStream/native/styles.js
Normal file
124
react/features/recording/components/LiveStream/native/styles.js
Normal file
@@ -0,0 +1,124 @@
|
||||
// @flow
|
||||
|
||||
import {
|
||||
BoxModel,
|
||||
ColorPalette,
|
||||
createStyleSheet
|
||||
} from '../../../../base/styles';
|
||||
|
||||
/**
|
||||
* Opacity of the TouchableHighlight.
|
||||
*/
|
||||
export const ACTIVE_OPACITY = 0.3;
|
||||
|
||||
/**
|
||||
* Underlay of the TouchableHighlight.
|
||||
*/
|
||||
export const TOUCHABLE_UNDERLAY = ColorPalette.lightGrey;
|
||||
|
||||
/**
|
||||
* The styles of the React {@code Components} of LiveStream.
|
||||
*/
|
||||
export default createStyleSheet({
|
||||
betaTag: {
|
||||
backgroundColor: ColorPalette.darkGrey,
|
||||
borderRadius: 2,
|
||||
marginLeft: 16,
|
||||
opacity: 0.90,
|
||||
paddingLeft: 6,
|
||||
paddingRight: 6
|
||||
},
|
||||
|
||||
betaTagText: {
|
||||
color: ColorPalette.white,
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
|
||||
/**
|
||||
* Generic component to wrap form sections into achieving a unified look.
|
||||
*/
|
||||
formWrapper: {
|
||||
alignItems: 'stretch',
|
||||
flexDirection: 'column',
|
||||
padding: BoxModel.padding
|
||||
},
|
||||
|
||||
/**
|
||||
* Explaining text on the top of the sign in form.
|
||||
*/
|
||||
helpText: {
|
||||
marginBottom: BoxModel.margin
|
||||
},
|
||||
|
||||
/**
|
||||
* Wrapper for the StartLiveStreamDialog form.
|
||||
*/
|
||||
startDialogWrapper: {
|
||||
flexDirection: 'column'
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper link text.
|
||||
*/
|
||||
streamKeyHelp: {
|
||||
alignSelf: 'flex-end'
|
||||
},
|
||||
|
||||
/**
|
||||
* Input field to manually enter stream key.
|
||||
*/
|
||||
streamKeyInput: {
|
||||
alignSelf: 'stretch',
|
||||
height: 50
|
||||
},
|
||||
|
||||
/**
|
||||
* Label for the previous field.
|
||||
*/
|
||||
streamKeyInputLabel: {
|
||||
alignSelf: 'flex-start'
|
||||
},
|
||||
|
||||
/**
|
||||
* Custom component to pick a broadcast from the list fetched from Google.
|
||||
*/
|
||||
streamKeyPicker: {
|
||||
alignSelf: 'stretch',
|
||||
flex: 1,
|
||||
height: 40,
|
||||
marginHorizontal: 4,
|
||||
width: 300
|
||||
},
|
||||
|
||||
/**
|
||||
* CTA (label) of the picker.
|
||||
*/
|
||||
streamKeyPickerCta: {
|
||||
marginBottom: 8
|
||||
},
|
||||
|
||||
/**
|
||||
* Style of a single item in the list.
|
||||
*/
|
||||
streamKeyPickerItem: {
|
||||
padding: 4
|
||||
},
|
||||
|
||||
/**
|
||||
* Additional style for the selected item.
|
||||
*/
|
||||
streamKeyPickerItemHighlight: {
|
||||
backgroundColor: ColorPalette.lighterGrey
|
||||
},
|
||||
|
||||
/**
|
||||
* Overall wrapper for the picker.
|
||||
*/
|
||||
streamKeyPickerWrapper: {
|
||||
borderColor: ColorPalette.lightGrey,
|
||||
borderRadius: 3,
|
||||
borderWidth: 1,
|
||||
flexDirection: 'column'
|
||||
}
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user