|
@@ -1,8 +1,8 @@
|
1
|
1
|
import React, { Component } from 'react';
|
2
|
2
|
import { connect } from 'react-redux';
|
3
|
3
|
|
4
|
|
-import AudioOnlyLabel from './AudioOnlyLabel';
|
5
|
|
-import HDVideoLabel from './HDVideoLabel';
|
|
4
|
+import { toggleAudioOnly } from '../../base/conference';
|
|
5
|
+import { translate } from '../../base/i18n';
|
6
|
6
|
|
7
|
7
|
/**
|
8
|
8
|
* React {@code Component} responsible for displaying a label that indicates
|
|
@@ -23,26 +23,118 @@ export class VideoStatusLabel extends Component {
|
23
|
23
|
*/
|
24
|
24
|
_audioOnly: React.PropTypes.bool,
|
25
|
25
|
|
|
26
|
+ /**
|
|
27
|
+ * Whether or not a connection to a conference has been established.
|
|
28
|
+ */
|
|
29
|
+ _conferenceStarted: React.PropTypes.bool,
|
|
30
|
+
|
26
|
31
|
/**
|
27
|
32
|
* Whether or not a high-definition large video is displayed.
|
28
|
33
|
*/
|
29
|
|
- _largeVideoHD: React.PropTypes.bool
|
|
34
|
+ _largeVideoHD: React.PropTypes.bool,
|
|
35
|
+
|
|
36
|
+ /**
|
|
37
|
+ * Invoked to request toggling of audio only mode.
|
|
38
|
+ */
|
|
39
|
+ dispatch: React.PropTypes.func,
|
|
40
|
+
|
|
41
|
+ /**
|
|
42
|
+ * Invoked to obtain translated strings.
|
|
43
|
+ */
|
|
44
|
+ t: React.PropTypes.func
|
|
45
|
+ }
|
|
46
|
+
|
|
47
|
+ /**
|
|
48
|
+ * Initializes a new {@code VideoStatusLabel} instance.
|
|
49
|
+ *
|
|
50
|
+ * @param {Object} props - The read-only React Component props with which
|
|
51
|
+ * the new instance is to be initialized.
|
|
52
|
+ */
|
|
53
|
+ constructor(props) {
|
|
54
|
+ super(props);
|
|
55
|
+
|
|
56
|
+ // Bind event handler so it is only bound once for every instance.
|
|
57
|
+ this._toggleAudioOnly = this._toggleAudioOnly.bind(this);
|
30
|
58
|
}
|
31
|
59
|
|
32
|
60
|
/**
|
33
|
61
|
* Implements React's {@link Component#render()}.
|
34
|
62
|
*
|
35
|
63
|
* @inheritdoc
|
36
|
|
- * @returns {ReactElement|null}
|
|
64
|
+ * @returns {ReactElement}
|
37
|
65
|
*/
|
38
|
66
|
render() {
|
39
|
|
- if (this.props._audioOnly) {
|
40
|
|
- return <AudioOnlyLabel />;
|
41
|
|
- } else if (this.props._largeVideoHD) {
|
42
|
|
- return <HDVideoLabel />;
|
|
67
|
+ const { _audioOnly, _conferenceStarted, _largeVideoHD, t } = this.props;
|
|
68
|
+
|
|
69
|
+ // FIXME These truthy checks should not be necessary. The
|
|
70
|
+ // _conferenceStarted check is used to be defensive against toggling
|
|
71
|
+ // audio only mode while there is no conference and hides the need for
|
|
72
|
+ // error handling around audio only mode toggling. The _largeVideoHD
|
|
73
|
+ // check is used to prevent the label from displaying while the video
|
|
74
|
+ // resolution status is unknown but ties this component to the
|
|
75
|
+ // LargeVideoManager.
|
|
76
|
+ if (!_conferenceStarted || _largeVideoHD === undefined) {
|
|
77
|
+ return null;
|
|
78
|
+ }
|
|
79
|
+
|
|
80
|
+ let displayedLabel;
|
|
81
|
+
|
|
82
|
+ if (_audioOnly) {
|
|
83
|
+ displayedLabel = <i className = 'icon-visibility-off' />;
|
|
84
|
+ } else {
|
|
85
|
+ displayedLabel = _largeVideoHD
|
|
86
|
+ ? t('videoStatus.hd') : t('videoStatus.sd');
|
43
|
87
|
}
|
44
|
88
|
|
45
|
|
- return null;
|
|
89
|
+ return (
|
|
90
|
+ <div
|
|
91
|
+ className = 'video-state-indicator moveToCorner'
|
|
92
|
+ id = 'videoResolutionLabel' >
|
|
93
|
+ { displayedLabel }
|
|
94
|
+ { this._renderVideonMenu() }
|
|
95
|
+ </div>
|
|
96
|
+ );
|
|
97
|
+ }
|
|
98
|
+
|
|
99
|
+ /**
|
|
100
|
+ * Renders a dropdown menu for changing video modes.
|
|
101
|
+ *
|
|
102
|
+ * @private
|
|
103
|
+ * @returns {ReactElement}
|
|
104
|
+ */
|
|
105
|
+ _renderVideonMenu() {
|
|
106
|
+ const { _audioOnly, t } = this.props;
|
|
107
|
+ const audioOnlyAttributes = _audioOnly ? { className: 'active' }
|
|
108
|
+ : { onClick: this._toggleAudioOnly };
|
|
109
|
+ const videoAttributes = _audioOnly ? { onClick: this._toggleAudioOnly }
|
|
110
|
+ : { className: 'active' };
|
|
111
|
+
|
|
112
|
+ return (
|
|
113
|
+ <div className = 'video-state-indicator-menu'>
|
|
114
|
+ <div className = 'video-state-indicator-menu-options'>
|
|
115
|
+ <div { ...audioOnlyAttributes }>
|
|
116
|
+ <i className = 'icon-visibility' />
|
|
117
|
+ { t('audioOnly.audioOnly') }
|
|
118
|
+ </div>
|
|
119
|
+ <div { ...videoAttributes }>
|
|
120
|
+ <i className = 'icon-camera' />
|
|
121
|
+ { this.props._largeVideoHD
|
|
122
|
+ ? t('videoStatus.hdVideo')
|
|
123
|
+ : t('videoStatus.sdVideo') }
|
|
124
|
+ </div>
|
|
125
|
+ </div>
|
|
126
|
+ </div>
|
|
127
|
+ );
|
|
128
|
+ }
|
|
129
|
+
|
|
130
|
+ /**
|
|
131
|
+ * Dispatches an action to toggle the state of audio only mode.
|
|
132
|
+ *
|
|
133
|
+ * @private
|
|
134
|
+ * @returns {void}
|
|
135
|
+ */
|
|
136
|
+ _toggleAudioOnly() {
|
|
137
|
+ this.props.dispatch(toggleAudioOnly());
|
46
|
138
|
}
|
47
|
139
|
}
|
48
|
140
|
|
|
@@ -54,16 +146,22 @@ export class VideoStatusLabel extends Component {
|
54
|
146
|
* @private
|
55
|
147
|
* @returns {{
|
56
|
148
|
* _audioOnly: boolean,
|
57
|
|
- * _largeVideoHD: boolean
|
|
149
|
+ * _conferenceStarted: boolean,
|
|
150
|
+ * _largeVideoHD: (boolean|undefined)
|
58
|
151
|
* }}
|
59
|
152
|
*/
|
60
|
153
|
function _mapStateToProps(state) {
|
61
|
|
- const { audioOnly, isLargeVideoHD } = state['features/base/conference'];
|
|
154
|
+ const {
|
|
155
|
+ audioOnly,
|
|
156
|
+ conference,
|
|
157
|
+ isLargeVideoHD
|
|
158
|
+ } = state['features/base/conference'];
|
62
|
159
|
|
63
|
160
|
return {
|
64
|
161
|
_audioOnly: audioOnly,
|
|
162
|
+ _conferenceStarted: Boolean(conference),
|
65
|
163
|
_largeVideoHD: isLargeVideoHD
|
66
|
164
|
};
|
67
|
165
|
}
|
68
|
166
|
|
69
|
|
-export default connect(_mapStateToProps)(VideoStatusLabel);
|
|
167
|
+export default translate(connect(_mapStateToProps)(VideoStatusLabel));
|