Parcourir la source

feat(alwaysontop): refactor toolbox

Use the new abstractions, which already take care of the rendering part.
j8
Saúl Ibarra Corretgé il y a 7 ans
Parent
révision
01cb4ac7c8

+ 3
- 102
react/features/always-on-top/AlwaysOnTop.js Voir le fichier

@@ -2,7 +2,7 @@
2 2
 
3 3
 import React, { Component } from 'react';
4 4
 
5
-import ToolboxAlwaysOnTop from './ToolboxAlwaysOnTop';
5
+import Toolbar from './Toolbar';
6 6
 
7 7
 const { api } = window.alwaysOnTop;
8 8
 
@@ -15,13 +15,9 @@ const TOOLBAR_TIMEOUT = 4000;
15 15
  * The type of the React {@code Component} state of {@link FeedbackButton}.
16 16
  */
17 17
 type State = {
18
-    audioAvailable: boolean,
19
-    audioMuted: boolean,
20 18
     avatarURL: string,
21 19
     displayName: string,
22 20
     isVideoDisplayed: boolean,
23
-    videoAvailable: boolean,
24
-    videoMuted: boolean,
25 21
     visible: boolean
26 22
 };
27 23
 
@@ -45,19 +41,12 @@ export default class AlwaysOnTop extends Component<*, State> {
45 41
 
46 42
         this.state = {
47 43
             visible: true,
48
-            audioMuted: false,
49
-            videoMuted: false,
50
-            audioAvailable: false,
51
-            videoAvailable: false,
52 44
             displayName: '',
53 45
             isVideoDisplayed: true,
54 46
             avatarURL: ''
55 47
         };
56 48
 
57 49
         // Bind event handlers so they are only bound once per instance.
58
-        this._audioAvailabilityListener
59
-            = this._audioAvailabilityListener.bind(this);
60
-        this._audioMutedListener = this._audioMutedListener.bind(this);
61 50
         this._avatarChangedListener = this._avatarChangedListener.bind(this);
62 51
         this._largeVideoChangedListener
63 52
             = this._largeVideoChangedListener.bind(this);
@@ -66,33 +55,6 @@ export default class AlwaysOnTop extends Component<*, State> {
66 55
         this._mouseMove = this._mouseMove.bind(this);
67 56
         this._onMouseOut = this._onMouseOut.bind(this);
68 57
         this._onMouseOver = this._onMouseOver.bind(this);
69
-        this._videoAvailabilityListener
70
-            = this._videoAvailabilityListener.bind(this);
71
-        this._videoMutedListener = this._videoMutedListener.bind(this);
72
-    }
73
-
74
-    _audioAvailabilityListener: ({ available: boolean }) => void;
75
-
76
-    /**
77
-     * Handles audio available api events.
78
-     *
79
-     * @param {{ available: boolean }} status - The new available status.
80
-     * @returns {void}
81
-     */
82
-    _audioAvailabilityListener({ available }) {
83
-        this.setState({ audioAvailable: available });
84
-    }
85
-
86
-    _audioMutedListener: ({ muted: boolean }) => void;
87
-
88
-    /**
89
-     * Handles audio muted api events.
90
-     *
91
-     * @param {{ muted: boolean }} status - The new muted status.
92
-     * @returns {void}
93
-     */
94
-    _audioMutedListener({ muted }) {
95
-        this.setState({ audioMuted: muted });
96 58
     }
97 59
 
98 60
     _avatarChangedListener: () => void;
@@ -200,8 +162,6 @@ export default class AlwaysOnTop extends Component<*, State> {
200 162
         this._hovered = true;
201 163
     }
202 164
 
203
-    _videoAvailabilityListener: ({ available: boolean }) => void;
204
-
205 165
     /**
206 166
      * Renders display name and avatar for the on stage participant.
207 167
      *
@@ -234,28 +194,6 @@ export default class AlwaysOnTop extends Component<*, State> {
234 194
         );
235 195
     }
236 196
 
237
-    /**
238
-     * Handles audio available api events.
239
-     *
240
-     * @param {{ available: boolean }} status - The new available status.
241
-     * @returns {void}
242
-     */
243
-    _videoAvailabilityListener({ available }) {
244
-        this.setState({ videoAvailable: available });
245
-    }
246
-
247
-    _videoMutedListener: ({ muted: boolean }) => void;
248
-
249
-    /**
250
-     * Handles video muted api events.
251
-     *
252
-     * @param {{ muted: boolean }} status - The new muted status.
253
-     * @returns {void}
254
-     */
255
-    _videoMutedListener({ muted }) {
256
-        this.setState({ videoMuted: muted });
257
-    }
258
-
259 197
     /**
260 198
      * Sets mouse move listener and initial toolbar timeout.
261 199
      *
@@ -263,37 +201,12 @@ export default class AlwaysOnTop extends Component<*, State> {
263 201
      * @returns {void}
264 202
      */
265 203
     componentDidMount() {
266
-        api.on('audioMuteStatusChanged', this._audioMutedListener);
267
-        api.on('videoMuteStatusChanged', this._videoMutedListener);
268
-        api.on('audioAvailabilityChanged', this._audioAvailabilityListener);
269
-        api.on('videoAvailabilityChanged', this._videoAvailabilityListener);
270 204
         api.on('largeVideoChanged', this._largeVideoChangedListener);
271 205
         api.on('displayNameChange', this._displayNameChangedListener);
272 206
         api.on('avatarChanged', this._avatarChangedListener);
273 207
 
274 208
         this._largeVideoChangedListener();
275 209
 
276
-        Promise.all([
277
-            api.isAudioMuted(),
278
-            api.isVideoMuted(),
279
-            api.isAudioAvailable(),
280
-            api.isVideoAvailable()
281
-        ])
282
-        .then(([
283
-            audioMuted = false,
284
-            videoMuted = false,
285
-            audioAvailable = false,
286
-            videoAvailable = false
287
-        ]) =>
288
-            this.setState({
289
-                audioMuted,
290
-                videoMuted,
291
-                audioAvailable,
292
-                videoAvailable
293
-            })
294
-        )
295
-        .catch(console.error);
296
-
297 210
         window.addEventListener('mousemove', this._mouseMove);
298 211
 
299 212
         this._hideToolbarAfterTimeout();
@@ -306,14 +219,6 @@ export default class AlwaysOnTop extends Component<*, State> {
306 219
      * @returns {void}
307 220
      */
308 221
     componentWillUnmount() {
309
-        api.removeListener('audioMuteStatusChanged',
310
-            this._audioMutedListener);
311
-        api.removeListener('videoMuteStatusChanged',
312
-            this._videoMutedListener);
313
-        api.removeListener('audioAvailabilityChanged',
314
-            this._audioAvailabilityListener);
315
-        api.removeListener('videoAvailabilityChanged',
316
-            this._videoAvailabilityListener);
317 222
         api.removeListener('largeVideoChanged',
318 223
             this._largeVideoChangedListener);
319 224
         api.removeListener('displayNameChange',
@@ -343,14 +248,10 @@ export default class AlwaysOnTop extends Component<*, State> {
343 248
     render() {
344 249
         return (
345 250
             <div id = 'alwaysOnTop'>
346
-                <ToolboxAlwaysOnTop
347
-                    audioAvailable = { this.state.audioAvailable }
348
-                    audioMuted = { this.state.audioMuted }
251
+                <Toolbar
349 252
                     className = { this.state.visible ? 'fadeIn' : 'fadeOut' }
350 253
                     onMouseOut = { this._onMouseOut }
351
-                    onMouseOver = { this._onMouseOver }
352
-                    videoAvailable = { this.state.videoAvailable }
353
-                    videoMuted = { this.state.videoMuted } />
254
+                    onMouseOver = { this._onMouseOver } />
354 255
                 {
355 256
                     this._renderVideoNotAvailableScreen()
356 257
                 }

+ 145
- 0
react/features/always-on-top/AudioMuteButton.js Voir le fichier

@@ -0,0 +1,145 @@
1
+// @flow
2
+
3
+// XXX: AlwaysOnTop imports the button directly in order to avoid bringing in
4
+// other components that use lib-jitsi-meet, which always on top does not
5
+// import.
6
+import AbstractAudioMuteButton
7
+    from '../toolbox/components/buttons/AbstractAudioMuteButton';
8
+import type { Props } from '../toolbox/components/buttons/AbstractButton';
9
+
10
+const { api } = window.alwaysOnTop;
11
+
12
+type State = {
13
+
14
+    /**
15
+     * Whether audio is available is not.
16
+     */
17
+    audioAvailable: boolean,
18
+
19
+    /**
20
+     * Whether audio is muted or not.
21
+     */
22
+    audioMuted: boolean
23
+};
24
+
25
+/**
26
+ * Stateless hangup button for the Always-on-Top windows.
27
+ */
28
+export default class AudioMuteButton
29
+    extends AbstractAudioMuteButton<Props, State> {
30
+
31
+    /**
32
+     * Initializes a new {@code AudioMuteButton} instance.
33
+     *
34
+     * @param {Props} props - The React {@code Component} props to initialize
35
+     * the new {@code AudioMuteButton} instance with.
36
+     */
37
+    constructor(props: Props) {
38
+        super(props);
39
+
40
+        this.state = {
41
+            audioAvailable: false,
42
+            audioMuted: true
43
+        };
44
+
45
+        // Bind event handlers so they are only bound once per instance.
46
+        this._audioAvailabilityListener
47
+            = this._audioAvailabilityListener.bind(this);
48
+        this._audioMutedListener = this._audioMutedListener.bind(this);
49
+    }
50
+
51
+    /**
52
+     * Sets mouse move listener and initial toolbar timeout.
53
+     *
54
+     * @inheritdoc
55
+     * @returns {void}
56
+     */
57
+    componentDidMount() {
58
+        api.on('audioAvailabilityChanged', this._audioAvailabilityListener);
59
+        api.on('audioMuteStatusChanged', this._audioMutedListener);
60
+
61
+        Promise.all([
62
+            api.isAudioAvailable(),
63
+            api.isAudioMuted()
64
+        ])
65
+            .then(values => {
66
+                const [ audioAvailable, audioMuted ] = values;
67
+
68
+                this.setState({
69
+                    audioAvailable,
70
+                    audioMuted
71
+                });
72
+            })
73
+            .catch(console.error);
74
+    }
75
+
76
+    /**
77
+     * Removes all listeners.
78
+     *
79
+     * @inheritdoc
80
+     * @returns {void}
81
+     */
82
+    componentWillUnmount() {
83
+        api.removeListener('audioAvailabilityChanged',
84
+            this._audioAvailabilityListener);
85
+        api.removeListener('audioMuteStatusChanged',
86
+            this._audioMutedListener);
87
+    }
88
+
89
+    /**
90
+     * Indicates whether this button is disabled or not.
91
+     *
92
+     * @override
93
+     * @private
94
+     * @returns {boolean}
95
+     */
96
+    _isDisabled() {
97
+        return !this.state.audioAvailable;
98
+    }
99
+
100
+    /**
101
+     * Indicates if audio is currently muted ot nor.
102
+     *
103
+     * @override
104
+     * @private
105
+     * @returns {boolean}
106
+     */
107
+    _isAudioMuted() {
108
+        return this.state.audioMuted;
109
+    }
110
+
111
+    /**
112
+     * Changes the muted state.
113
+     *
114
+     * @param {boolean} audioMuted - Whether audio should be muted or not.
115
+     * @private
116
+     * @returns {void}
117
+     */
118
+    _setAudioMuted(audioMuted: boolean) { // eslint-disable-line no-unused-vars
119
+        this.state.audioAvailable && api.executeCommand('toggleAudio');
120
+    }
121
+
122
+    _audioAvailabilityListener: ({ available: boolean }) => void;
123
+
124
+    /**
125
+     * Handles audio available api events.
126
+     *
127
+     * @param {{ available: boolean }} status - The new available status.
128
+     * @returns {void}
129
+     */
130
+    _audioAvailabilityListener({ available }) {
131
+        this.setState({ audioAvailable: available });
132
+    }
133
+
134
+    _audioMutedListener: ({ muted: boolean }) => void;
135
+
136
+    /**
137
+     * Handles audio muted api events.
138
+     *
139
+     * @param {{ muted: boolean }} status - The new muted status.
140
+     * @returns {void}
141
+     */
142
+    _audioMutedListener({ muted }) {
143
+        this.setState({ audioMuted: muted });
144
+    }
145
+}

+ 38
- 0
react/features/always-on-top/HangupButton.js Voir le fichier

@@ -0,0 +1,38 @@
1
+// @flow
2
+
3
+// XXX: AlwaysOnTop imports the button directly in order to avoid bringing in
4
+// other components that use lib-jitsi-meet, which always on top does not
5
+// import.
6
+import AbstractHangupButton
7
+    from '../toolbox/components/buttons/AbstractHangupButton';
8
+import type { Props } from '../toolbox/components/buttons/AbstractButton';
9
+
10
+const { api } = window.alwaysOnTop;
11
+
12
+/**
13
+ * Stateless hangup button for the Always-on-Top windows.
14
+ */
15
+export default class HangupButton extends AbstractHangupButton<Props, *> {
16
+    /**
17
+     * Helper function to perform the actual hangup action.
18
+     *
19
+     * @override
20
+     * @private
21
+     * @returns {void}
22
+     */
23
+    _doHangup() {
24
+        api.executeCommand('hangup');
25
+        window.close();
26
+    }
27
+
28
+    /**
29
+     * Indicates whether this button is disabled or not.
30
+     *
31
+     * @override
32
+     * @private
33
+     * @returns {boolean}
34
+     */
35
+    _isDisabled() {
36
+        return false;
37
+    }
38
+}

+ 60
- 0
react/features/always-on-top/Toolbar.js Voir le fichier

@@ -0,0 +1,60 @@
1
+// @flow
2
+
3
+import React, { Component } from 'react';
4
+
5
+import AudioMuteButton from './AudioMuteButton';
6
+import HangupButton from './HangupButton';
7
+import VideoMuteButton from './VideoMuteButton';
8
+
9
+/**
10
+ * The type of the React {@code Component} props of {@link Toolbar}.
11
+ */
12
+type Props = {
13
+
14
+    /**
15
+     * Additional CSS class names to add to the root of the toolbar.
16
+     */
17
+    className: string,
18
+
19
+    /**
20
+     * Callback invoked when no longer moused over the toolbar.
21
+     */
22
+    onMouseOut: Function,
23
+
24
+    /**
25
+     * Callback invoked when the mouse has moved over the toolbar.
26
+     */
27
+     onMouseOver: Function
28
+};
29
+
30
+/**
31
+ * Represents the toolbar in the Always On Top window.
32
+ *
33
+ * @extends Component
34
+ */
35
+export default class Toolbar extends Component<Props> {
36
+    /**
37
+     * Implements React's {@link Component#render()}.
38
+     *
39
+     * @inheritdoc
40
+     * @returns {ReactElement}
41
+     */
42
+    render() {
43
+        const {
44
+            className = '',
45
+            onMouseOut,
46
+            onMouseOver
47
+        } = this.props;
48
+
49
+        return (
50
+            <div
51
+                className = { `always-on-top-toolbox ${className}` }
52
+                onMouseOut = { onMouseOut }
53
+                onMouseOver = { onMouseOver }>
54
+                <AudioMuteButton />
55
+                <HangupButton />
56
+                <VideoMuteButton />
57
+            </div>
58
+        );
59
+    }
60
+}

+ 0
- 159
react/features/always-on-top/ToolboxAlwaysOnTop.js Voir le fichier

@@ -1,159 +0,0 @@
1
-// @flow
2
-
3
-import React, { Component } from 'react';
4
-
5
-// FIXME: AlwaysOnTop imports the button directly in order to avoid bringing in
6
-// other components that use lib-jitsi-meet, which always on top does not
7
-// import.
8
-import ToolbarButton from '../toolbox/components/ToolbarButton';
9
-
10
-const { api } = window.alwaysOnTop;
11
-
12
-/**
13
- * The type of the React {@code Component} props of {@link ToolboxAlwaysOnTop}.
14
- */
15
-type Props = {
16
-
17
-    /**
18
-     * Whether or not microphone access is available.
19
-     */
20
-    audioAvailable: boolean,
21
-
22
-    /**
23
-     * Whether or not the user is currently audio muted.
24
-     */
25
-    audioMuted: boolean,
26
-
27
-    /**
28
-     * Additional CSS class names to add to the root of the toolbar.
29
-     */
30
-    className: string,
31
-
32
-    /**
33
-     * Callback invoked when no longer moused over the toolbar.
34
-     */
35
-    onMouseOut: Function,
36
-
37
-    /**
38
-     * Callback invoked when the mouse has moved over the toolbar.
39
-     */
40
-     onMouseOver: Function,
41
-
42
-    /**
43
-     * Whether or not camera access is available.
44
-     */
45
-    videoAvailable: boolean,
46
-
47
-    /**
48
-     * Whether or not the user is currently video muted.
49
-     */
50
-    videoMuted: boolean
51
-};
52
-
53
-/**
54
- * Represents the toolbar in the Always On Top window.
55
- *
56
- * @extends Component
57
- */
58
-export default class ToolboxAlwaysOnTop extends Component<Props> {
59
-    /**
60
-     * Initializes a new {@code ToolboxAlwaysOnTop} instance.
61
-     *
62
-     * @param {Props} props - The read-only properties with which the new
63
-     * instance is to be initialized.
64
-     */
65
-    constructor(props: Props) {
66
-        super(props);
67
-
68
-        // Bind event handlers so they are only bound once per instance.
69
-        this._onToolbarHangup = this._onToolbarHangup.bind(this);
70
-        this._onToolbarToggleAudio = this._onToolbarToggleAudio.bind(this);
71
-        this._onToolbarToggleVideo = this._onToolbarToggleVideo.bind(this);
72
-    }
73
-
74
-    /**
75
-     * Implements React's {@link Component#render()}.
76
-     *
77
-     * @inheritdoc
78
-     * @returns {ReactElement}
79
-     */
80
-    render() {
81
-        const {
82
-            audioAvailable,
83
-            audioMuted,
84
-            className = '',
85
-            onMouseOut,
86
-            onMouseOver,
87
-            videoAvailable,
88
-            videoMuted
89
-        } = this.props;
90
-
91
-        const videoMuteIcon = `${videoMuted || !videoAvailable
92
-            ? 'icon-camera-disabled toggled' : 'icon-camera'} ${
93
-            videoAvailable ? '' : 'disabled'}`;
94
-        const audioMuteIcon = `${audioMuted || !audioAvailable
95
-            ? 'icon-mic-disabled toggled' : 'icon-microphone'} ${
96
-            audioAvailable ? '' : 'disabled'}`;
97
-
98
-        return (
99
-            <div
100
-                className = { `always-on-top-toolbox ${className}` }
101
-                onMouseOut = { onMouseOut }
102
-                onMouseOver = { onMouseOver }>
103
-                <ToolbarButton
104
-                    accessibilityLabel = 'Audio mute'
105
-                    iconName = { audioMuteIcon }
106
-                    onClick = { this._onToolbarToggleAudio } />
107
-                <ToolbarButton
108
-                    accessibilityLabel = 'Hangup'
109
-                    iconName = 'icon-hangup'
110
-                    onClick = { this._onToolbarHangup } />
111
-                <ToolbarButton
112
-                    accessibilityLabel = 'Video mute'
113
-                    iconName = { videoMuteIcon }
114
-                    onClick = { this._onToolbarToggleVideo } />
115
-            </div>
116
-        );
117
-    }
118
-
119
-    _onToolbarHangup: () => void;
120
-
121
-    /**
122
-     * Ends the conference call and closes the always on top window.
123
-     *
124
-     * @private
125
-     * @returns {void}
126
-     */
127
-    _onToolbarHangup() {
128
-        api.executeCommand('hangup');
129
-        window.close();
130
-    }
131
-
132
-    _onToolbarToggleAudio: () => void;
133
-
134
-    /**
135
-     * Toggles audio mute if audio is avaiable.
136
-     *
137
-     * @private
138
-     * @returns {void}
139
-     */
140
-    _onToolbarToggleAudio() {
141
-        if (this.props.audioAvailable) {
142
-            api.executeCommand('toggleAudio');
143
-        }
144
-    }
145
-
146
-    _onToolbarToggleVideo: () => void;
147
-
148
-    /**
149
-     * Toggles video mute if video is avaiable.
150
-     *
151
-     * @private
152
-     * @returns {void}
153
-     */
154
-    _onToolbarToggleVideo() {
155
-        if (this.props.videoAvailable) {
156
-            api.executeCommand('toggleVideo');
157
-        }
158
-    }
159
-}

+ 145
- 0
react/features/always-on-top/VideoMuteButton.js Voir le fichier

@@ -0,0 +1,145 @@
1
+// @flow
2
+
3
+// XXX: AlwaysOnTop imports the button directly in order to avoid bringing in
4
+// other components that use lib-jitsi-meet, which always on top does not
5
+// import.
6
+import AbstractVideoMuteButton
7
+    from '../toolbox/components/buttons/AbstractVideoMuteButton';
8
+import type { Props } from '../toolbox/components/buttons/AbstractButton';
9
+
10
+const { api } = window.alwaysOnTop;
11
+
12
+type State = {
13
+
14
+    /**
15
+     * Whether video is available is not.
16
+     */
17
+    videoAvailable: boolean,
18
+
19
+    /**
20
+     * Whether video is muted or not.
21
+     */
22
+    videoMuted: boolean
23
+};
24
+
25
+/**
26
+ * Stateless hangup button for the Always-on-Top windows.
27
+ */
28
+export default class VideoMuteButton
29
+    extends AbstractVideoMuteButton<Props, State> {
30
+
31
+    /**
32
+     * Initializes a new {@code VideoMuteButton} instance.
33
+     *
34
+     * @param {Props} props - The React {@code Component} props to initialize
35
+     * the new {@code VideoMuteButton} instance with.
36
+     */
37
+    constructor(props: Props) {
38
+        super(props);
39
+
40
+        this.state = {
41
+            videoAvailable: false,
42
+            videoMuted: true
43
+        };
44
+
45
+        // Bind event handlers so they are only bound once per instance.
46
+        this._videoAvailabilityListener
47
+            = this._videoAvailabilityListener.bind(this);
48
+        this._videoMutedListener = this._videoMutedListener.bind(this);
49
+    }
50
+
51
+    /**
52
+     * Sets mouse move listener and initial toolbar timeout.
53
+     *
54
+     * @inheritdoc
55
+     * @returns {void}
56
+     */
57
+    componentDidMount() {
58
+        api.on('videoAvailabilityChanged', this._videoAvailabilityListener);
59
+        api.on('videoMuteStatusChanged', this._videoMutedListener);
60
+
61
+        Promise.all([
62
+            api.isVideoAvailable(),
63
+            api.isVideoMuted()
64
+        ])
65
+            .then(values => {
66
+                const [ videoAvailable, videoMuted ] = values;
67
+
68
+                this.setState({
69
+                    videoAvailable,
70
+                    videoMuted
71
+                });
72
+            })
73
+            .catch(console.error);
74
+    }
75
+
76
+    /**
77
+     * Removes all listeners.
78
+     *
79
+     * @inheritdoc
80
+     * @returns {void}
81
+     */
82
+    componentWillUnmount() {
83
+        api.removeListener('videoAvailabilityChanged',
84
+            this._videoAvailabilityListener);
85
+        api.removeListener('videoMuteStatusChanged',
86
+            this._videoMutedListener);
87
+    }
88
+
89
+    /**
90
+     * Indicates whether this button is disabled or not.
91
+     *
92
+     * @override
93
+     * @private
94
+     * @returns {boolean}
95
+     */
96
+    _isDisabled() {
97
+        return !this.state.videoAvailable;
98
+    }
99
+
100
+    /**
101
+     * Indicates if video is currently muted ot nor.
102
+     *
103
+     * @override
104
+     * @private
105
+     * @returns {boolean}
106
+     */
107
+    _isVideoMuted() {
108
+        return this.state.videoMuted;
109
+    }
110
+
111
+    /**
112
+     * Changes the muted state.
113
+     *
114
+     * @param {boolean} videoMuted - Whether video should be muted or not.
115
+     * @private
116
+     * @returns {void}
117
+     */
118
+    _setVideoMuted(videoMuted: boolean) { // eslint-disable-line no-unused-vars
119
+        this.state.videoAvailable && api.executeCommand('toggleVideo');
120
+    }
121
+
122
+    _videoAvailabilityListener: ({ available: boolean }) => void;
123
+
124
+    /**
125
+     * Handles video available api events.
126
+     *
127
+     * @param {{ available: boolean }} status - The new available status.
128
+     * @returns {void}
129
+     */
130
+    _videoAvailabilityListener({ available }) {
131
+        this.setState({ videoAvailable: available });
132
+    }
133
+
134
+    _videoMutedListener: ({ muted: boolean }) => void;
135
+
136
+    /**
137
+     * Handles video muted api events.
138
+     *
139
+     * @param {{ muted: boolean }} status - The new muted status.
140
+     * @returns {void}
141
+     */
142
+    _videoMutedListener({ muted }) {
143
+        this.setState({ videoMuted: muted });
144
+    }
145
+}

Chargement…
Annuler
Enregistrer