Преглед на файлове

Remote control - display the authorization dialog in meet (#1541)

* fix(react/participant): store display name in redux

* feat(remotecontrol): Add option to display the authorization dialog in meet

* feat(remotecontrol): Enable ESLint and Flow
master
hristoterezov преди 8 години
родител
ревизия
d91340166d

+ 6
- 0
.flowconfig Целия файл

@@ -35,6 +35,11 @@ module.system=haste
35 35
 
36 36
 experimental.strict_type_args=true
37 37
 
38
+; FIXME: munge_underscores should be false but right now there are some errors
39
+; if we change the value to false
40
+; Treats class properties with underscore as private. Disabled because currently
41
+; for us "_" can mean protected too.
42
+; munge_underscores=false
38 43
 munge_underscores=true
39 44
 
40 45
 module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
@@ -46,6 +51,7 @@ suppress_type=$FixMe
46 51
 suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-8]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
47 52
 suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-8]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
48 53
 suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
54
+suppress_comment=\\(.\\|\n\\)*\\$FlowDisableNextLine
49 55
 
50 56
 unsafe.enable_getters_and_setters=true
51 57
 

+ 1
- 1
.jshintignore Целия файл

@@ -9,7 +9,7 @@ node_modules/
9 9
 # supersedes JSHint.
10 10
 flow-typed/
11 11
 modules/API/
12
-modules/remotecontrol/RemoteControlParticipant.js
12
+modules/remotecontrol/
13 13
 modules/transport/
14 14
 react/
15 15
 

+ 10
- 0
conference.js Целия файл

@@ -1442,6 +1442,10 @@ export default {
1442 1442
         room.on(ConferenceEvents.DISPLAY_NAME_CHANGED, (id, displayName) => {
1443 1443
             const formattedDisplayName
1444 1444
                 = displayName.substr(0, MAX_DISPLAY_NAME_LENGTH);
1445
+            APP.store.dispatch(participantUpdated({
1446
+                id,
1447
+                name: formattedDisplayName
1448
+            }));
1445 1449
             APP.API.notifyDisplayNameChanged(id, formattedDisplayName);
1446 1450
             APP.UI.changeDisplayName(id, formattedDisplayName);
1447 1451
         });
@@ -2053,6 +2057,12 @@ export default {
2053 2057
             return;
2054 2058
         }
2055 2059
 
2060
+        APP.store.dispatch(participantUpdated({
2061
+            id: this.getMyUserId(),
2062
+            local: true,
2063
+            name: formattedNickname
2064
+        }));
2065
+
2056 2066
         APP.settings.setDisplayName(formattedNickname);
2057 2067
         if (room) {
2058 2068
             room.setDisplayName(formattedNickname);

+ 4
- 1
lang/main.json Целия файл

@@ -212,6 +212,7 @@
212 212
     },
213 213
     "dialog": {
214 214
         "add": "Add",
215
+        "allow": "Allow",
215 216
         "kickMessage": "Ouch! You have been kicked out of the meet!",
216 217
         "popupError": "Your browser is blocking popup windows from this site. Please enable popups in your browser's security settings and try again.",
217 218
         "passwordErrorTitle": "Password Error",
@@ -330,7 +331,9 @@
330 331
         "muteParticipantTitle": "Mute this participant?",
331 332
         "muteParticipantBody": "You won't be able to unmute them, but they can unmute themselves at any time.",
332 333
         "muteParticipantButton": "Mute",
333
-        "remoteControlTitle": "Remote Control",
334
+        "remoteControlTitle": "Remote desktop control",
335
+        "remoteControlRequestMessage": "Will you allow __user__ to remotely control your desktop?",
336
+        "remoteControlShareScreenWarning": "Note that if you press \"Allow\" you will share your screen!",
334 337
         "remoteControlDeniedMessage": "__user__ rejected your remote control request!",
335 338
         "remoteControlAllowedMessage": "__user__ accepted your remote control request!",
336 339
         "remoteControlErrorMessage": "An error occurred while trying to request remote control permissions from __user__!",

+ 3
- 0
modules/remotecontrol/.eslintrc.js Целия файл

@@ -0,0 +1,3 @@
1
+module.exports = {
2
+    'extends': '../../react/.eslintrc.js'
3
+};

+ 215
- 139
modules/remotecontrol/Controller.js Целия файл

@@ -1,20 +1,29 @@
1
-/* global $, JitsiMeetJS, APP */
2
-const logger = require("jitsi-meet-logger").getLogger(__filename);
3
-import * as KeyCodes from "../keycode/keycode";
1
+/* @flow */
2
+
3
+import { getLogger } from 'jitsi-meet-logger';
4
+
5
+import * as KeyCodes from '../keycode/keycode';
4 6
 import {
5 7
     EVENT_TYPES,
6 8
     PERMISSIONS_ACTIONS,
7 9
     REMOTE_CONTROL_EVENT_NAME
8
-} from "../../service/remotecontrol/Constants";
9
-import RemoteControlParticipant from "./RemoteControlParticipant";
10
-import UIEvents from "../../service/UI/UIEvents";
10
+} from '../../service/remotecontrol/Constants';
11
+import UIEvents from '../../service/UI/UIEvents';
12
+
13
+import RemoteControlParticipant from './RemoteControlParticipant';
14
+
15
+declare var $: Function;
16
+declare var APP: Object;
17
+declare var JitsiMeetJS: Object;
11 18
 
12 19
 const ConferenceEvents = JitsiMeetJS.events.conference;
20
+const logger = getLogger(__filename);
13 21
 
14 22
 /**
15 23
  * Extract the keyboard key from the keyboard event.
16
- * @param event {KeyboardEvent} the event.
17
- * @returns {KEYS} the key that is pressed or undefined.
24
+ *
25
+ * @param {KeyboardEvent} event - The event.
26
+ * @returns {KEYS} The key that is pressed or undefined.
18 27
  */
19 28
 function getKey(event) {
20 29
     return KeyCodes.keyboardEventToKey(event);
@@ -22,26 +31,28 @@ function getKey(event) {
22 31
 
23 32
 /**
24 33
  * Extract the modifiers from the keyboard event.
25
- * @param event {KeyboardEvent} the event.
26
- * @returns {Array} with possible values: "shift", "control", "alt", "command".
34
+ *
35
+ * @param {KeyboardEvent} event - The event.
36
+ * @returns {Array} With possible values: "shift", "control", "alt", "command".
27 37
  */
28 38
 function getModifiers(event) {
29
-    let modifiers = [];
30
-    if(event.shiftKey) {
31
-        modifiers.push("shift");
39
+    const modifiers = [];
40
+
41
+    if (event.shiftKey) {
42
+        modifiers.push('shift');
32 43
     }
33 44
 
34
-    if(event.ctrlKey) {
35
-        modifiers.push("control");
45
+    if (event.ctrlKey) {
46
+        modifiers.push('control');
36 47
     }
37 48
 
38 49
 
39
-    if(event.altKey) {
40
-        modifiers.push("alt");
50
+    if (event.altKey) {
51
+        modifiers.push('alt');
41 52
     }
42 53
 
43
-    if(event.metaKey) {
44
-        modifiers.push("command");
54
+    if (event.metaKey) {
55
+        modifiers.push('command');
45 56
     }
46 57
 
47 58
     return modifiers;
@@ -53,14 +64,22 @@ function getModifiers(event) {
53 64
  * party of the remote control session.
54 65
  */
55 66
 export default class Controller extends RemoteControlParticipant {
67
+    _area: ?Object;
68
+    _controlledParticipant: string | null;
69
+    _isCollectingEvents: boolean;
70
+    _largeVideoChangedListener: Function;
71
+    _requestedParticipant: string | null;
72
+    _stopListener: Function;
73
+    _userLeftListener: Function;
74
+
56 75
     /**
57 76
      * Creates new instance.
58 77
      */
59 78
     constructor() {
60 79
         super();
61
-        this.isCollectingEvents = false;
62
-        this.controlledParticipant = null;
63
-        this.requestedParticipant = null;
80
+        this._isCollectingEvents = false;
81
+        this._controlledParticipant = null;
82
+        this._requestedParticipant = null;
64 83
         this._stopListener = this._handleRemoteControlStoppedEvent.bind(this);
65 84
         this._userLeftListener = this._onUserLeft.bind(this);
66 85
         this._largeVideoChangedListener
@@ -69,24 +88,28 @@ export default class Controller extends RemoteControlParticipant {
69 88
 
70 89
     /**
71 90
      * Requests permissions from the remote control receiver side.
72
-     * @param {string} userId the user id of the participant that will be
91
+     *
92
+     * @param {string} userId - The user id of the participant that will be
73 93
      * requested.
74
-     * @param {JQuerySelector} eventCaptureArea the area that is going to be
94
+     * @param {JQuerySelector} eventCaptureArea - The area that is going to be
75 95
      * used mouse and keyboard event capture.
76
-     * @returns {Promise<boolean>} - resolve values:
77
-     * true - accept
78
-     * false - deny
79
-     * null - the participant has left.
96
+     * @returns {Promise<boolean>} Resolve values - true(accept), false(deny),
97
+     * null(the participant has left).
80 98
      */
81
-    requestPermissions(userId, eventCaptureArea) {
82
-        if(!this.enabled) {
83
-            return Promise.reject(new Error("Remote control is disabled!"));
99
+    requestPermissions(userId: string, eventCaptureArea: Object) {
100
+        if (!this.enabled) {
101
+            return Promise.reject(new Error('Remote control is disabled!'));
84 102
         }
85
-        this.area = eventCaptureArea;// $("#largeVideoWrapper")
86
-        logger.log("Requsting remote control permissions from: " + userId);
103
+
104
+        this._area = eventCaptureArea;// $("#largeVideoWrapper")
105
+        logger.log(`Requsting remote control permissions from: ${userId}`);
106
+
87 107
         return new Promise((resolve, reject) => {
108
+            // eslint-disable-next-line prefer-const
109
+            let onUserLeft, permissionsReplyListener;
110
+
88 111
             const clearRequest = () => {
89
-                this.requestedParticipant = null;
112
+                this._requestedParticipant = null;
90 113
                 APP.conference.removeConferenceListener(
91 114
                     ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
92 115
                     permissionsReplyListener);
@@ -94,31 +117,35 @@ export default class Controller extends RemoteControlParticipant {
94 117
                     ConferenceEvents.USER_LEFT,
95 118
                     onUserLeft);
96 119
             };
97
-            const permissionsReplyListener = (participant, event) => {
120
+
121
+            permissionsReplyListener = (participant, event) => {
98 122
                 let result = null;
123
+
99 124
                 try {
100 125
                     result = this._handleReply(participant, event);
101 126
                 } catch (e) {
127
+                    clearRequest();
102 128
                     reject(e);
103 129
                 }
104
-                if(result !== null) {
130
+                if (result !== null) {
105 131
                     clearRequest();
106 132
                     resolve(result);
107 133
                 }
108 134
             };
109
-            const onUserLeft = (id) => {
110
-                if(id === this.requestedParticipant) {
135
+            onUserLeft = id => {
136
+                if (id === this._requestedParticipant) {
111 137
                     clearRequest();
112 138
                     resolve(null);
113 139
                 }
114 140
             };
141
+
115 142
             APP.conference.addConferenceListener(
116 143
                 ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
117 144
                 permissionsReplyListener);
118 145
             APP.conference.addConferenceListener(ConferenceEvents.USER_LEFT,
119 146
                 onUserLeft);
120
-            this.requestedParticipant = userId;
121
-            this._sendRemoteControlEvent(userId, {
147
+            this._requestedParticipant = userId;
148
+            this.sendRemoteControlEvent(userId, {
122 149
                 type: EVENT_TYPES.permissions,
123 150
                 action: PERMISSIONS_ACTIONS.request
124 151
             }, e => {
@@ -130,54 +157,58 @@ export default class Controller extends RemoteControlParticipant {
130 157
 
131 158
     /**
132 159
      * Handles the reply of the permissions request.
133
-     * @param {JitsiParticipant} participant the participant that has sent the
134
-     * reply
135
-     * @param {RemoteControlEvent} event the remote control event.
160
+     *
161
+     * @param {JitsiParticipant} participant - The participant that has sent the
162
+     * reply.
163
+     * @param {RemoteControlEvent} event - The remote control event.
164
+     * @returns {void}
136 165
      */
137
-    _handleReply(participant, event) {
166
+    _handleReply(participant: Object, event: Object) {
138 167
         const userId = participant.getId();
139
-        if(this.enabled
168
+
169
+        if (this.enabled
140 170
                 && event.name === REMOTE_CONTROL_EVENT_NAME
141 171
                 && event.type === EVENT_TYPES.permissions
142
-                && userId === this.requestedParticipant) {
143
-            if(event.action !== PERMISSIONS_ACTIONS.grant) {
144
-                this.area = null;
172
+                && userId === this._requestedParticipant) {
173
+            if (event.action !== PERMISSIONS_ACTIONS.grant) {
174
+                this._area = undefined;
145 175
             }
146
-            switch(event.action) {
147
-                case PERMISSIONS_ACTIONS.grant: {
148
-                    this.controlledParticipant = userId;
149
-                    logger.log("Remote control permissions granted to: "
150
-                        + userId);
151
-                    this._start();
152
-                    return true;
153
-                }
154
-                case PERMISSIONS_ACTIONS.deny:
155
-                    return false;
156
-                case PERMISSIONS_ACTIONS.error:
157
-                    throw new Error("Error occurred on receiver side");
158
-                default:
159
-                    throw new Error("Unknown reply received!");
176
+            switch (event.action) {
177
+            case PERMISSIONS_ACTIONS.grant: {
178
+                this._controlledParticipant = userId;
179
+                logger.log('Remote control permissions granted to:', userId);
180
+                this._start();
181
+
182
+                return true;
183
+            }
184
+            case PERMISSIONS_ACTIONS.deny:
185
+                return false;
186
+            case PERMISSIONS_ACTIONS.error:
187
+                throw new Error('Error occurred on receiver side');
188
+            default:
189
+                throw new Error('Unknown reply received!');
160 190
             }
161 191
         } else {
162
-            //different message type or another user -> ignoring the message
192
+            // different message type or another user -> ignoring the message
163 193
             return null;
164 194
         }
165 195
     }
166 196
 
167 197
     /**
168 198
      * Handles remote control stopped.
169
-     * @param {JitsiParticipant} participant the participant that has sent the
170
-     * event
171
-     * @param {Object} event EndpointMessage event from the data channels.
172
-     * @property {string} type property. The function process only events with
173
-     * name REMOTE_CONTROL_EVENT_NAME
174
-     * @property {RemoteControlEvent} event - the remote control event.
199
+     *
200
+     * @param {JitsiParticipant} participant - The participant that has sent the
201
+     * event.
202
+     * @param {Object} event - EndpointMessage event from the data channels.
203
+     * @property {string} type - The function process only events with
204
+     * name REMOTE_CONTROL_EVENT_NAME.
205
+     * @returns {void}
175 206
      */
176
-    _handleRemoteControlStoppedEvent(participant, event) {
177
-        if(this.enabled
207
+    _handleRemoteControlStoppedEvent(participant: Object, event: Object) {
208
+        if (this.enabled
178 209
                 && event.name === REMOTE_CONTROL_EVENT_NAME
179 210
                 && event.type === EVENT_TYPES.stop
180
-                && participant.getId() === this.controlledParticipant) {
211
+                && participant.getId() === this._controlledParticipant) {
181 212
             this._stop();
182 213
         }
183 214
     }
@@ -185,9 +216,11 @@ export default class Controller extends RemoteControlParticipant {
185 216
     /**
186 217
      * Starts processing the mouse and keyboard events. Sets conference
187 218
      * listeners. Disables keyboard events.
219
+     *
220
+     * @returns {void}
188 221
      */
189 222
     _start() {
190
-        logger.log("Starting remote control controller.");
223
+        logger.log('Starting remote control controller.');
191 224
         APP.UI.addListener(UIEvents.LARGE_VIDEO_ID_CHANGED,
192 225
             this._largeVideoChangedListener);
193 226
         APP.conference.addConferenceListener(
@@ -200,35 +233,53 @@ export default class Controller extends RemoteControlParticipant {
200 233
 
201 234
     /**
202 235
      * Disables the keyboatd shortcuts. Starts collecting remote control
203
-     * events.
236
+     * events. It can be used to resume an active remote control session wchich
237
+     * was paused with this.pause().
204 238
      *
205
-     * It can be used to resume an active remote control session wchich was
206
-     * paused with this.pause().
239
+     * @returns {void}
207 240
      */
208 241
     resume() {
209
-        if(!this.enabled || this.isCollectingEvents) {
242
+        if (!this.enabled || this._isCollectingEvents || !this._area) {
210 243
             return;
211 244
         }
212
-        logger.log("Resuming remote control controller.");
213
-        this.isCollectingEvents = true;
245
+        logger.log('Resuming remote control controller.');
246
+        this._isCollectingEvents = true;
214 247
         APP.keyboardshortcut.enable(false);
215
-        this.area.mousemove(event => {
216
-            const position = this.area.position();
217
-            this._sendRemoteControlEvent(this.controlledParticipant, {
248
+
249
+        // $FlowDisableNextLine: we are sure that this._area is not null.
250
+        this._area.mousemove(event => {
251
+            // $FlowDisableNextLine: we are sure that this._area is not null.
252
+            const position = this._area.position();
253
+
254
+            this.sendRemoteControlEvent(this._controlledParticipant, {
218 255
                 type: EVENT_TYPES.mousemove,
219
-                x: (event.pageX - position.left)/this.area.width(),
220
-                y: (event.pageY - position.top)/this.area.height()
256
+
257
+                // $FlowDisableNextLine: we are sure that this._area is not null
258
+                x: (event.pageX - position.left) / this._area.width(),
259
+
260
+                // $FlowDisableNextLine: we are sure that this._area is not null
261
+                y: (event.pageY - position.top) / this._area.height()
221 262
             });
222 263
         });
223
-        this.area.mousedown(this._onMouseClickHandler.bind(this,
264
+
265
+        // $FlowDisableNextLine: we are sure that this._area is not null.
266
+        this._area.mousedown(this._onMouseClickHandler.bind(this,
224 267
             EVENT_TYPES.mousedown));
225
-        this.area.mouseup(this._onMouseClickHandler.bind(this,
268
+
269
+        // $FlowDisableNextLine: we are sure that this._area is not null.
270
+        this._area.mouseup(this._onMouseClickHandler.bind(this,
226 271
             EVENT_TYPES.mouseup));
227
-        this.area.dblclick(
272
+
273
+        // $FlowDisableNextLine: we are sure that this._area is not null.
274
+        this._area.dblclick(
228 275
             this._onMouseClickHandler.bind(this, EVENT_TYPES.mousedblclick));
229
-        this.area.contextmenu(() => false);
230
-        this.area[0].onmousewheel = event => {
231
-            this._sendRemoteControlEvent(this.controlledParticipant, {
276
+
277
+        // $FlowDisableNextLine: we are sure that this._area is not null.
278
+        this._area.contextmenu(() => false);
279
+
280
+        // $FlowDisableNextLine: we are sure that this._area is not null.
281
+        this._area[0].onmousewheel = event => {
282
+            this.sendRemoteControlEvent(this._controlledParticipant, {
232 283
                 type: EVENT_TYPES.mousescroll,
233 284
                 x: event.deltaX,
234 285
                 y: event.deltaY
@@ -243,12 +294,14 @@ export default class Controller extends RemoteControlParticipant {
243 294
      * Stops processing the mouse and keyboard events. Removes added listeners.
244 295
      * Enables the keyboard shortcuts. Displays dialog to notify the user that
245 296
      * remote control session has ended.
297
+     *
298
+     * @returns {void}
246 299
      */
247 300
     _stop() {
248
-        if(!this.controlledParticipant) {
301
+        if (!this._controlledParticipant) {
249 302
             return;
250 303
         }
251
-        logger.log("Stopping remote control controller.");
304
+        logger.log('Stopping remote control controller.');
252 305
         APP.UI.removeListener(UIEvents.LARGE_VIDEO_ID_CHANGED,
253 306
             this._largeVideoChangedListener);
254 307
         APP.conference.removeConferenceListener(
@@ -256,29 +309,28 @@ export default class Controller extends RemoteControlParticipant {
256 309
             this._stopListener);
257 310
         APP.conference.removeConferenceListener(ConferenceEvents.USER_LEFT,
258 311
             this._userLeftListener);
259
-        this.controlledParticipant = null;
312
+        this._controlledParticipant = null;
260 313
         this.pause();
261
-        this.area = null;
314
+        this._area = undefined;
262 315
         APP.UI.messageHandler.openMessageDialog(
263
-            "dialog.remoteControlTitle",
264
-            "dialog.remoteControlStopMessage"
316
+            'dialog.remoteControlTitle',
317
+            'dialog.remoteControlStopMessage'
265 318
         );
266 319
     }
267 320
 
268 321
     /**
269
-     * Executes this._stop() mehtod:
270
-     * Stops processing the mouse and keyboard events. Removes added listeners.
271
-     * Enables the keyboard shortcuts. Displays dialog to notify the user that
272
-     * remote control session has ended.
322
+     * Executes this._stop() mehtod which stops processing the mouse and
323
+     * keyboard events, removes added listeners, enables the keyboard shortcuts,
324
+     * displays dialog to notify the user that remote control session has ended.
325
+     * In addition sends stop message to the controlled participant.
273 326
      *
274
-     * In addition:
275
-     * Sends stop message to the controlled participant.
327
+     * @returns {void}
276 328
      */
277 329
     stop() {
278
-        if(!this.controlledParticipant) {
330
+        if (!this._controlledParticipant) {
279 331
             return;
280 332
         }
281
-        this._sendRemoteControlEvent(this.controlledParticipant, {
333
+        this.sendRemoteControlEvent(this._controlledParticipant, {
282 334
             type: EVENT_TYPES.stop
283 335
         });
284 336
         this._stop();
@@ -288,88 +340,112 @@ export default class Controller extends RemoteControlParticipant {
288 340
      * Pauses the collecting of events and enables the keyboard shortcus. But
289 341
      * it doesn't removes any other listeners. Basically the remote control
290 342
      * session will be still active after this.pause(), but no events from the
291
-     * controller side will be captured and sent.
343
+     * controller side will be captured and sent. You can resume the collecting
344
+     * of the events with this.resume().
292 345
      *
293
-     * You can resume the collecting of the events with this.resume().
346
+     * @returns {void}
294 347
      */
295 348
     pause() {
296
-        if(!this.controlledParticipant) {
349
+        if (!this._controlledParticipant) {
297 350
             return;
298 351
         }
299
-        logger.log("Pausing remote control controller.");
300
-        this.isCollectingEvents = false;
352
+        logger.log('Pausing remote control controller.');
353
+        this._isCollectingEvents = false;
301 354
         APP.keyboardshortcut.enable(true);
302
-        this.area.off( "mousemove" );
303
-        this.area.off( "mousedown" );
304
-        this.area.off( "mouseup" );
305
-        this.area.off( "contextmenu" );
306
-        this.area.off( "dblclick" );
307
-        $(window).off( "keydown");
308
-        $(window).off( "keyup");
309
-        this.area[0].onmousewheel = undefined;
355
+
356
+        // $FlowDisableNextLine: we are sure that this._area is not null.
357
+        this._area.off('mousemove');
358
+
359
+        // $FlowDisableNextLine: we are sure that this._area is not null.
360
+        this._area.off('mousedown');
361
+
362
+        // $FlowDisableNextLine: we are sure that this._area is not null.
363
+        this._area.off('mouseup');
364
+
365
+        // $FlowDisableNextLine: we are sure that this._area is not null.
366
+        this._area.off('contextmenu');
367
+
368
+        // $FlowDisableNextLine: we are sure that this._area is not null.
369
+        this._area.off('dblclick');
370
+
371
+        $(window).off('keydown');
372
+        $(window).off('keyup');
373
+
374
+        // $FlowDisableNextLine: we are sure that this._area is not null.
375
+        this._area[0].onmousewheel = undefined;
310 376
     }
311 377
 
312 378
     /**
313 379
      * Handler for mouse click events.
314
-     * @param {String} type the type of event ("mousedown"/"mouseup")
315
-     * @param {Event} event the mouse event.
380
+     *
381
+     * @param {string} type - The type of event ("mousedown"/"mouseup").
382
+     * @param {Event} event - The mouse event.
383
+     * @returns {void}
316 384
      */
317
-    _onMouseClickHandler(type, event) {
318
-        this._sendRemoteControlEvent(this.controlledParticipant, {
319
-            type: type,
385
+    _onMouseClickHandler(type: string, event: Object) {
386
+        this.sendRemoteControlEvent(this._controlledParticipant, {
387
+            type,
320 388
             button: event.which
321 389
         });
322 390
     }
323 391
 
324 392
     /**
325 393
      * Returns true if the remote control session is started.
394
+     *
326 395
      * @returns {boolean}
327 396
      */
328 397
     isStarted() {
329
-        return this.controlledParticipant !== null;
398
+        return this._controlledParticipant !== null;
330 399
     }
331 400
 
332 401
     /**
333
-     * Returns the id of the requested participant
334
-     * @returns {string} this.requestedParticipant.
402
+     * Returns the id of the requested participant.
403
+     *
404
+     * @returns {string} The id of the requested participant.
335 405
      * NOTE: This id should be the result of JitsiParticipant.getId() call.
336 406
      */
337 407
     getRequestedParticipant() {
338
-        return this.requestedParticipant;
408
+        return this._requestedParticipant;
339 409
     }
340 410
 
341 411
     /**
342 412
      * Handler for key press events.
343
-     * @param {String} type the type of event ("keydown"/"keyup")
344
-     * @param {Event} event the key event.
413
+     *
414
+     * @param {string} type - The type of event ("keydown"/"keyup").
415
+     * @param {Event} event - The key event.
416
+     * @returns {void}
345 417
      */
346
-    _onKeyPessHandler(type, event) {
347
-        this._sendRemoteControlEvent(this.controlledParticipant, {
348
-            type: type,
418
+    _onKeyPessHandler(type: string, event: Object) {
419
+        this.sendRemoteControlEvent(this._controlledParticipant, {
420
+            type,
349 421
             key: getKey(event),
350
-            modifiers: getModifiers(event),
422
+            modifiers: getModifiers(event)
351 423
         });
352 424
     }
353 425
 
354 426
     /**
355 427
      * Calls the stop method if the other side have left.
356
-     * @param {string} id - the user id for the participant that have left
428
+     *
429
+     * @param {string} id - The user id for the participant that have left.
430
+     * @returns {void}
357 431
      */
358
-    _onUserLeft(id) {
359
-        if(this.controlledParticipant === id) {
432
+    _onUserLeft(id: string) {
433
+        if (this._controlledParticipant === id) {
360 434
             this._stop();
361 435
         }
362 436
     }
363 437
 
364 438
     /**
365 439
      * Handles changes of the participant displayed on the large video.
366
-     * @param {string} id - the user id for the participant that is displayed.
440
+     *
441
+     * @param {string} id - The user id for the participant that is displayed.
442
+     * @returns {void}
367 443
      */
368
-    _onLargeVideoIdChanged(id) {
369
-        if (!this.controlledParticipant) {
444
+    _onLargeVideoIdChanged(id: string) {
445
+        if (!this._controlledParticipant) {
370 446
             return;
371 447
         }
372
-        if(this.controlledParticipant == id) {
448
+        if (this._controlledParticipant === id) {
373 449
             this.resume();
374 450
         } else {
375 451
             this.pause();

+ 164
- 78
modules/remotecontrol/Receiver.js Целия файл

@@ -1,6 +1,11 @@
1
-/* global APP, config, interfaceConfig, JitsiMeetJS */
1
+/* @flow */
2
+
3
+import { getLogger } from 'jitsi-meet-logger';
2 4
 
3 5
 import * as JitsiMeetConferenceEvents from '../../ConferenceEvents';
6
+import {
7
+    openRemoteControlAuthorizationDialog
8
+} from '../../react/features/remote-control';
4 9
 import {
5 10
     DISCO_REMOTE_CONTROL_FEATURE,
6 11
     EVENT_TYPES,
@@ -11,8 +16,13 @@ import { getJitsiMeetTransport } from '../transport';
11 16
 
12 17
 import RemoteControlParticipant from './RemoteControlParticipant';
13 18
 
19
+declare var APP: Object;
20
+declare var config: Object;
21
+declare var interfaceConfig: Object;
22
+declare var JitsiMeetJS: Object;
23
+
14 24
 const ConferenceEvents = JitsiMeetJS.events.conference;
15
-const logger = require("jitsi-meet-logger").getLogger(__filename);
25
+const logger = getLogger(__filename);
16 26
 
17 27
 /**
18 28
  * The transport instance used for communication with external apps.
@@ -28,17 +38,23 @@ const transport = getJitsiMeetTransport();
28 38
  * and executed.
29 39
  */
30 40
 export default class Receiver extends RemoteControlParticipant {
41
+    _controller: ?string;
42
+    _enabled: boolean;
43
+    _hangupListener: Function;
44
+    _remoteControlEventsListener: Function;
45
+    _userLeftListener: Function;
46
+
31 47
     /**
32 48
      * Creates new instance.
33
-     * @constructor
34 49
      */
35 50
     constructor() {
36 51
         super();
37
-        this.controller = null;
52
+        this._controller = null;
38 53
         this._remoteControlEventsListener
39 54
             = this._onRemoteControlEvent.bind(this);
40 55
         this._userLeftListener = this._onUserLeft.bind(this);
41 56
         this._hangupListener = this._onHangup.bind(this);
57
+
42 58
         // We expect here that even if we receive the supported event earlier
43 59
         // it will be cached and we'll receive it.
44 60
         transport.on('event', event => {
@@ -53,16 +69,19 @@ export default class Receiver extends RemoteControlParticipant {
53 69
     }
54 70
 
55 71
     /**
56
-     * Enables / Disables the remote control
57
-     * @param {boolean} enabled the new state.
72
+     * Enables / Disables the remote control.
73
+     *
74
+     * @param {boolean} enabled - The new state.
75
+     * @returns {void}
58 76
      */
59
-    _enable(enabled) {
60
-        if(this.enabled === enabled) {
77
+    _enable(enabled: boolean) {
78
+        if (this._enabled === enabled) {
61 79
             return;
62 80
         }
63
-        this.enabled = enabled;
64
-        if(enabled === true) {
65
-            logger.log("Remote control receiver enabled.");
81
+        this._enabled = enabled;
82
+        if (enabled === true) {
83
+            logger.log('Remote control receiver enabled.');
84
+
66 85
             // Announce remote control support.
67 86
             APP.connection.addFeature(DISCO_REMOTE_CONTROL_FEATURE, true);
68 87
             APP.conference.addConferenceListener(
@@ -71,7 +90,7 @@ export default class Receiver extends RemoteControlParticipant {
71 90
             APP.conference.addListener(JitsiMeetConferenceEvents.BEFORE_HANGUP,
72 91
                 this._hangupListener);
73 92
         } else {
74
-            logger.log("Remote control receiver disabled.");
93
+            logger.log('Remote control receiver disabled.');
75 94
             this._stop(true);
76 95
             APP.connection.removeFeature(DISCO_REMOTE_CONTROL_FEATURE);
77 96
             APP.conference.removeConferenceListener(
@@ -88,36 +107,43 @@ export default class Receiver extends RemoteControlParticipant {
88 107
      * events. Sends stop message to the wrapper application. Optionally
89 108
      * displays dialog for informing the user that remote control session
90 109
      * ended.
91
-     * @param {boolean} dontShowDialog - if true the dialog won't be displayed.
110
+     *
111
+     * @param {boolean} [dontShowDialog] - If true the dialog won't be
112
+     * displayed.
113
+     * @returns {void}
92 114
      */
93
-    _stop(dontShowDialog = false) {
94
-        if(!this.controller) {
115
+    _stop(dontShowDialog: boolean = false) {
116
+        if (!this._controller) {
95 117
             return;
96 118
         }
97
-        logger.log("Remote control receiver stop.");
98
-        this.controller = null;
119
+        logger.log('Remote control receiver stop.');
120
+        this._controller = null;
99 121
         APP.conference.removeConferenceListener(ConferenceEvents.USER_LEFT,
100 122
             this._userLeftListener);
101
-        transport.sendEvent({
102
-            name: REMOTE_CONTROL_EVENT_NAME,
103
-            type: EVENT_TYPES.stop
104
-        });
105
-        if(!dontShowDialog) {
123
+        if (this.remoteControlExternalAuth) {
124
+            transport.sendEvent({
125
+                name: REMOTE_CONTROL_EVENT_NAME,
126
+                type: EVENT_TYPES.stop
127
+            });
128
+        }
129
+        if (!dontShowDialog) {
106 130
             APP.UI.messageHandler.openMessageDialog(
107
-                "dialog.remoteControlTitle",
108
-                "dialog.remoteControlStopMessage"
131
+                'dialog.remoteControlTitle',
132
+                'dialog.remoteControlStopMessage'
109 133
             );
110 134
         }
111 135
     }
112 136
 
113 137
     /**
114
-     * Calls this._stop() and sends stop message to the controller participant
138
+     * Calls this._stop() and sends stop message to the controller participant.
139
+     *
140
+     * @returns {void}
115 141
      */
116 142
     stop() {
117
-        if(!this.controller) {
143
+        if (!this._controller) {
118 144
             return;
119 145
         }
120
-        this._sendRemoteControlEvent(this.controller, {
146
+        this.sendRemoteControlEvent(this._controller, {
121 147
             type: EVENT_TYPES.stop
122 148
         });
123 149
         this._stop();
@@ -127,91 +153,145 @@ export default class Receiver extends RemoteControlParticipant {
127 153
      * Listens for data channel EndpointMessage events. Handles only events of
128 154
      * type remote control. Sends "remote-control-event" events to the API
129 155
      * module.
130
-     * @param {JitsiParticipant} participant the controller participant
131
-     * @param {Object} event EndpointMessage event from the data channels.
132
-     * @property {string} type property. The function process only events with
133
-     * name REMOTE_CONTROL_EVENT_NAME
134
-     * @property {RemoteControlEvent} event - the remote control event.
156
+     *
157
+     * @param {JitsiParticipant} participant - The controller participant.
158
+     * @param {Object} event - EndpointMessage event from the data channels.
159
+     * @param {string} event.name - The function process only events with
160
+     * name REMOTE_CONTROL_EVENT_NAME.
161
+     * @returns {void}
135 162
      */
136
-    _onRemoteControlEvent(participant, event) {
163
+    _onRemoteControlEvent(participant: Object, event: Object) {
137 164
         if (event.name !== REMOTE_CONTROL_EVENT_NAME) {
138 165
             return;
139 166
         }
140 167
 
141 168
         const remoteControlEvent = Object.assign({}, event);
142 169
 
143
-        if (this.enabled) {
144
-            if (this.controller === null
170
+        if (this._enabled) {
171
+            if (this._controller === null
145 172
                     && event.type === EVENT_TYPES.permissions
146 173
                     && event.action === PERMISSIONS_ACTIONS.request) {
174
+                const userId = participant.getId();
175
+
176
+                if (!config.remoteControlExternalAuth) {
177
+                    APP.store.dispatch(
178
+                        openRemoteControlAuthorizationDialog(userId));
179
+
180
+                    return;
181
+                }
182
+
147 183
                 // FIXME: Maybe use transport.sendRequest in this case???
148
-                remoteControlEvent.userId = participant.getId();
184
+                remoteControlEvent.userId = userId;
149 185
                 remoteControlEvent.userJID = participant.getJid();
150 186
                 remoteControlEvent.displayName = participant.getDisplayName()
151 187
                     || interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;
152 188
                 remoteControlEvent.screenSharing
153 189
                     = APP.conference.isSharingScreen;
154
-            } else if (this.controller !== participant.getId()) {
190
+            } else if (this._controller !== participant.getId()) {
155 191
                 return;
156 192
             } else if (event.type === EVENT_TYPES.stop) {
157 193
                 this._stop();
194
+
158 195
                 return;
159 196
             }
160 197
             transport.sendEvent(remoteControlEvent);
161 198
         } else {
162
-            logger.log("Remote control event is ignored because remote "
163
-                + "control is disabled", event);
199
+            logger.log('Remote control event is ignored because remote '
200
+                + 'control is disabled', event);
164 201
         }
165 202
     }
166 203
 
167 204
     /**
168 205
      * Handles remote control permission events.
169
-     * @param {String} userId the user id of the participant related to the
206
+     *
207
+     * @param {string} userId - The user id of the participant related to the
170 208
      * event.
171
-     * @param {PERMISSIONS_ACTIONS} action the action related to the event.
209
+     * @param {PERMISSIONS_ACTIONS} action - The action related to the event.
210
+     * @returns {void}
211
+     */
212
+    _onRemoteControlPermissionsEvent(userId: string, action: string) {
213
+        switch (action) {
214
+        case PERMISSIONS_ACTIONS.grant:
215
+            this.grant(userId);
216
+            break;
217
+        case PERMISSIONS_ACTIONS.deny:
218
+            this.deny(userId);
219
+            break;
220
+        case PERMISSIONS_ACTIONS.error:
221
+            this.sendRemoteControlEvent(userId, {
222
+                type: EVENT_TYPES.permissions,
223
+                action
224
+            });
225
+            break;
226
+        default:
227
+
228
+                // Unknown action. Ignore.
229
+        }
230
+    }
231
+
232
+    /**
233
+     * Denies remote control access for user associated with the passed user id.
234
+     *
235
+     * @param {string} userId - The id associated with the user who sent the
236
+     * request for remote control authorization.
237
+     * @returns {void}
238
+     */
239
+    deny(userId: string) {
240
+        this.sendRemoteControlEvent(userId, {
241
+            type: EVENT_TYPES.permissions,
242
+            action: PERMISSIONS_ACTIONS.deny
243
+        });
244
+    }
245
+
246
+    /**
247
+     * Grants remote control access to user associated with the passed user id.
248
+     *
249
+     * @param {string} userId - The id associated with the user who sent the
250
+     * request for remote control authorization.
251
+     * @returns {void}
172 252
      */
173
-    _onRemoteControlPermissionsEvent(userId, action) {
174
-        if (action === PERMISSIONS_ACTIONS.grant) {
175
-            APP.conference.addConferenceListener(ConferenceEvents.USER_LEFT,
176
-                this._userLeftListener);
177
-            this.controller = userId;
178
-            logger.log("Remote control permissions granted to: " + userId);
179
-            if(!APP.conference.isSharingScreen) {
180
-                APP.conference.toggleScreenSharing();
181
-                APP.conference.screenSharingPromise.then(() => {
182
-                    if(APP.conference.isSharingScreen) {
183
-                        this._sendRemoteControlEvent(userId, {
184
-                            type: EVENT_TYPES.permissions,
185
-                            action: action
186
-                        });
187
-                    } else {
188
-                        this._sendRemoteControlEvent(userId, {
189
-                            type: EVENT_TYPES.permissions,
190
-                            action: PERMISSIONS_ACTIONS.error
191
-                        });
192
-                    }
193
-                }).catch(() => {
194
-                    this._sendRemoteControlEvent(userId, {
253
+    grant(userId: string) {
254
+        APP.conference.addConferenceListener(ConferenceEvents.USER_LEFT,
255
+            this._userLeftListener);
256
+        this._controller = userId;
257
+        logger.log(`Remote control permissions granted to: ${userId}`);
258
+        if (APP.conference.isSharingScreen) {
259
+            this.sendRemoteControlEvent(userId, {
260
+                type: EVENT_TYPES.permissions,
261
+                action: PERMISSIONS_ACTIONS.grant
262
+            });
263
+        } else {
264
+            APP.conference.toggleScreenSharing();
265
+            APP.conference.screenSharingPromise.then(() => {
266
+                if (APP.conference.isSharingScreen) {
267
+                    this.sendRemoteControlEvent(userId, {
268
+                        type: EVENT_TYPES.permissions,
269
+                        action: PERMISSIONS_ACTIONS.grant
270
+                    });
271
+                } else {
272
+                    this.sendRemoteControlEvent(userId, {
195 273
                         type: EVENT_TYPES.permissions,
196 274
                         action: PERMISSIONS_ACTIONS.error
197 275
                     });
276
+                }
277
+            }).catch(() => {
278
+                this.sendRemoteControlEvent(userId, {
279
+                    type: EVENT_TYPES.permissions,
280
+                    action: PERMISSIONS_ACTIONS.error
198 281
                 });
199
-                return;
200
-            }
282
+            });
201 283
         }
202
-        this._sendRemoteControlEvent(userId, {
203
-            type: EVENT_TYPES.permissions,
204
-            action
205
-        });
206 284
     }
207 285
 
208 286
     /**
209 287
      * Handles remote control events from the external app. Currently only
210
-     * events with type = EVENT_TYPES.supported or EVENT_TYPES.permissions
211
-     * @param {RemoteControlEvent} event the remote control event.
288
+     * events with type = EVENT_TYPES.supported or EVENT_TYPES.permissions.
289
+     *
290
+     * @param {RemoteControlEvent} event - The remote control event.
291
+     * @returns {void}
212 292
      */
213
-    _onRemoteControlAPIEvent(event) {
214
-        switch(event.type) {
293
+    _onRemoteControlAPIEvent(event: Object) {
294
+        switch (event.type) {
215 295
         case EVENT_TYPES.permissions:
216 296
             this._onRemoteControlPermissionsEvent(event.userId, event.action);
217 297
             break;
@@ -224,11 +304,13 @@ export default class Receiver extends RemoteControlParticipant {
224 304
     /**
225 305
      * Handles events for support for executing remote control events into
226 306
      * the wrapper application.
307
+     *
308
+     * @returns {void}
227 309
      */
228 310
     _onRemoteControlSupported() {
229
-        logger.log("Remote Control supported.");
311
+        logger.log('Remote Control supported.');
230 312
         if (config.disableRemoteControl) {
231
-            logger.log("Remote Control disabled.");
313
+            logger.log('Remote Control disabled.');
232 314
         } else {
233 315
             this._enable(true);
234 316
         }
@@ -236,16 +318,20 @@ export default class Receiver extends RemoteControlParticipant {
236 318
 
237 319
     /**
238 320
      * Calls the stop method if the other side have left.
239
-     * @param {string} id - the user id for the participant that have left
321
+     *
322
+     * @param {string} id - The user id for the participant that have left.
323
+     * @returns {void}
240 324
      */
241
-    _onUserLeft(id) {
242
-        if(this.controller === id) {
325
+    _onUserLeft(id: string) {
326
+        if (this._controller === id) {
243 327
             this._stop();
244 328
         }
245 329
     }
246 330
 
247 331
     /**
248 332
      * Handles hangup events. Disables the receiver.
333
+     *
334
+     * @returns {void}
249 335
      */
250 336
     _onHangup() {
251 337
         this._enable(false);

+ 23
- 12
modules/remotecontrol/RemoteControl.js Целия файл

@@ -1,4 +1,6 @@
1
-/* global APP, config */
1
+/* @flow */
2
+
3
+import { getLogger } from 'jitsi-meet-logger';
2 4
 
3 5
 import { DISCO_REMOTE_CONTROL_FEATURE }
4 6
     from '../../service/remotecontrol/Constants';
@@ -6,44 +8,53 @@ import { DISCO_REMOTE_CONTROL_FEATURE }
6 8
 import Controller from './Controller';
7 9
 import Receiver from './Receiver';
8 10
 
9
-const logger = require('jitsi-meet-logger').getLogger(__filename);
11
+const logger = getLogger(__filename);
12
+
13
+declare var APP: Object;
14
+declare var config: Object;
10 15
 
11 16
 /**
12 17
  * Implements the remote control functionality.
13 18
  */
14 19
 class RemoteControl {
20
+    _initialized: boolean;
21
+    controller: Controller;
22
+    receiver: Receiver;
23
+
15 24
     /**
16 25
      * Constructs new instance. Creates controller and receiver properties.
17
-     * @constructor
18 26
      */
19 27
     constructor() {
20 28
         this.controller = new Controller();
21
-        this.initialized = false;
29
+        this._initialized = false;
22 30
     }
23 31
 
24 32
     /**
25 33
      * Initializes the remote control - checks if the remote control should be
26 34
      * enabled or not.
35
+     *
36
+     * @returns {void}
27 37
      */
28 38
     init() {
29
-        if(config.disableRemoteControl
30
-                || this.initialized
39
+        if (config.disableRemoteControl
40
+                || this._initialized
31 41
                 || !APP.conference.isDesktopSharingEnabled) {
32 42
             return;
33 43
         }
34
-        logger.log("Initializing remote control.");
35
-        this.initialized = true;
44
+        logger.log('Initializing remote control.');
45
+        this._initialized = true;
36 46
         this.controller.enable(true);
37 47
         this.receiver = new Receiver();
38 48
     }
39 49
 
40 50
     /**
41
-     * Checks whether the passed user supports remote control or not
42
-     * @param {JitsiParticipant} user the user to be tested
43
-     * @returns {Promise<boolean>} the promise will be resolved with true if
51
+     * Checks whether the passed user supports remote control or not.
52
+     *
53
+     * @param {JitsiParticipant} user - The user to be tested.
54
+     * @returns {Promise<boolean>} The promise will be resolved with true if
44 55
      * the user supports remote control and with false if not.
45 56
      */
46
-    checkUserRemoteControlSupport(user) {
57
+    checkUserRemoteControlSupport(user: Object) {
47 58
         return user.getFeatures().then(
48 59
             features => features.has(DISCO_REMOTE_CONTROL_FEATURE),
49 60
             () => false);

+ 36
- 16
modules/remotecontrol/RemoteControlParticipant.js Целия файл

@@ -1,50 +1,70 @@
1
-/* global APP */
1
+/* @flow */
2
+
3
+import { getLogger } from 'jitsi-meet-logger';
2 4
 
3 5
 import {
4 6
     REMOTE_CONTROL_EVENT_NAME
5
-} from "../../service/remotecontrol/Constants";
7
+} from '../../service/remotecontrol/Constants';
8
+
9
+const logger = getLogger(__filename);
6 10
 
7
-const logger = require("jitsi-meet-logger").getLogger(__filename);
11
+declare var APP: Object;
8 12
 
13
+/**
14
+ * Implements common logic for Receiver class and Controller class.
15
+ */
9 16
 export default class RemoteControlParticipant {
17
+    _enabled: boolean;
18
+
10 19
     /**
11 20
      * Creates new instance.
12 21
      */
13 22
     constructor() {
14
-        this.enabled = false;
23
+        this._enabled = false;
15 24
     }
16 25
 
17 26
     /**
18
-     * Enables / Disables the remote control
19
-     * @param {boolean} enabled the new state.
27
+     * Enables / Disables the remote control.
28
+     *
29
+     * @param {boolean} enabled - The new state.
30
+     * @returns {void}
20 31
      */
21
-    enable(enabled) {
22
-        this.enabled = enabled;
32
+    enable(enabled: boolean) {
33
+        this._enabled = enabled;
23 34
     }
24 35
 
25 36
     /**
26 37
      * Sends remote control event to other participant trough data channel.
27
-     * @param {RemoteControlEvent} event the remote control event.
28
-     * @param {Function} onDataChannelFail handler for data channel failure.
38
+     *
39
+     * @param {string} to - The participant who will receive the event.
40
+     * @param {RemoteControlEvent} event - The remote control event.
41
+     * @param {Function} onDataChannelFail - Handler for data channel failure.
42
+     * @returns {void}
29 43
      */
30
-    _sendRemoteControlEvent(to, event, onDataChannelFail = () => {}) {
31
-        if(!this.enabled || !to) {
44
+    sendRemoteControlEvent(
45
+            to: ?string,
46
+            event: Object,
47
+            onDataChannelFail: ?Function) {
48
+        if (!this._enabled || !to) {
32 49
             logger.warn(
33
-                "Remote control: Skip sending remote control event. Params:",
50
+                'Remote control: Skip sending remote control event. Params:',
34 51
                 this.enable,
35 52
                 to);
53
+
36 54
             return;
37 55
         }
38
-        try{
56
+        try {
39 57
             APP.conference.sendEndpointMessage(to, {
40 58
                 name: REMOTE_CONTROL_EVENT_NAME,
41 59
                 ...event
42 60
             });
43 61
         } catch (e) {
44 62
             logger.error(
45
-                "Failed to send EndpointMessage via the datachannels",
63
+                'Failed to send EndpointMessage via the datachannels',
46 64
                 e);
47
-            onDataChannelFail(e);
65
+            if (typeof onDataChannelFail === 'function') {
66
+                onDataChannelFail(e);
67
+            }
48 68
         }
49 69
     }
50 70
 }

+ 2
- 1
react/features/app/components/AbstractApp.js Целия файл

@@ -88,7 +88,8 @@ export class AbstractApp extends Component {
88 88
             localParticipant = {
89 89
                 avatarID: APP.settings.getAvatarId(),
90 90
                 avatarURL: APP.settings.getAvatarUrl(),
91
-                email: APP.settings.getEmail()
91
+                email: APP.settings.getEmail(),
92
+                name: APP.settings.getDisplayName()
92 93
             };
93 94
         }
94 95
         dispatch(localParticipantJoined(localParticipant));

+ 1
- 1
react/features/base/dialog/components/AbstractDialog.js Целия файл

@@ -24,7 +24,7 @@ export default class AbstractDialog extends Component {
24 24
         cancelTitleKey: React.PropTypes.string,
25 25
 
26 26
         /**
27
-         * Used to show hide the dialog on cancel.
27
+         * Used to show/hide the dialog on cancel.
28 28
          */
29 29
         dispatch: React.PropTypes.func,
30 30
 

+ 21
- 0
react/features/remote-control/actions.js Целия файл

@@ -0,0 +1,21 @@
1
+import { openDialog } from '../base/dialog';
2
+
3
+import { RemoteControlAuthorizationDialog } from './components';
4
+
5
+/**
6
+ * Signals that the remote control authorization dialog should be displayed.
7
+ *
8
+ * @param {string} participantId - The id of the participant who is requesting
9
+ * the authorization.
10
+ * @returns {{
11
+ *     type: OPEN_DIALOG,
12
+ *     component: {RemoteControlAuthorizationDialog},
13
+ *     componentProps: {
14
+ *         participantId: {string}
15
+ *      }
16
+ * }}
17
+ * @public
18
+ */
19
+export function openRemoteControlAuthorizationDialog(participantId) {
20
+    return openDialog(RemoteControlAuthorizationDialog, { participantId });
21
+}

+ 165
- 0
react/features/remote-control/components/RemoteControlAuthorizationDialog.js Целия файл

@@ -0,0 +1,165 @@
1
+import React, { Component } from 'react';
2
+import { connect } from 'react-redux';
3
+
4
+import {
5
+    Dialog,
6
+    hideDialog
7
+} from '../../base/dialog';
8
+import { translate } from '../../base/i18n';
9
+import { getParticipantById } from '../../base/participants';
10
+
11
+declare var APP: Object;
12
+
13
+/**
14
+ * Implements a dialog for remote control authorization.
15
+ */
16
+class RemoteControlAuthorizationDialog extends Component {
17
+    /**
18
+     * RemoteControlAuthorizationDialog component's property types.
19
+     *
20
+     * @static
21
+     */
22
+    static propTypes = {
23
+        /**
24
+         * The display name of the participant who is requesting authorization
25
+         * for remote desktop control session.
26
+         *
27
+         * @private
28
+         */
29
+        _displayName: React.PropTypes.string,
30
+
31
+        /**
32
+         * Used to show/hide the dialog on cancel.
33
+         */
34
+        dispatch: React.PropTypes.func,
35
+
36
+        /**
37
+         * The ID of the participant who is requesting authorization for remote
38
+         * desktop control session.
39
+         *
40
+         * @public
41
+         */
42
+        participantId: React.PropTypes.string,
43
+
44
+        /**
45
+         * Invoked to obtain translated strings.
46
+         */
47
+        t: React.PropTypes.func
48
+    }
49
+
50
+    /**
51
+     * Initializes a new RemoteControlAuthorizationDialog instance.
52
+     *
53
+     * @param {Object} props - The read-only properties with which the new
54
+     * instance is to be initialized.
55
+     */
56
+    constructor(props) {
57
+        super(props);
58
+
59
+        this._onCancel = this._onCancel.bind(this);
60
+        this._onSubmit = this._onSubmit.bind(this);
61
+    }
62
+
63
+    /**
64
+     * Implements React's {@link Component#render()}.
65
+     *
66
+     * @inheritdoc
67
+     */
68
+    render() {
69
+        return (
70
+            <Dialog
71
+                okTitleKey = { 'dialog.allow' }
72
+                onCancel = { this._onCancel }
73
+                onSubmit = { this._onSubmit }
74
+                titleKey = 'dialog.remoteControlTitle'
75
+                width = 'small'>
76
+                {
77
+                    this.props.t('dialog.remoteControlRequestMessage',
78
+                    { user: this.props._displayName })
79
+                }
80
+                {
81
+                    this._getAdditionalMessage()
82
+                }
83
+            </Dialog>
84
+        );
85
+    }
86
+
87
+    /**
88
+     * Renders additional message text for the dialog.
89
+     *
90
+     * @private
91
+     * @returns {ReactElement}
92
+     */
93
+    _getAdditionalMessage() {
94
+        // FIXME: Once we have this information in redux we should
95
+        // start getting it from there.
96
+        if (APP.conference.isSharingScreen) {
97
+            return null;
98
+        }
99
+
100
+        return (
101
+            <div>
102
+                <br />
103
+                { this.props.t('dialog.remoteControlShareScreenWarning') }
104
+            </div>
105
+        );
106
+    }
107
+
108
+    /**
109
+     * Notifies the remote control module about the denial of the remote control
110
+     * request.
111
+     *
112
+     * @private
113
+     * @returns {boolean} Returns true to close the dialog.
114
+     */
115
+    _onCancel() {
116
+        // FIXME: This should be action one day.
117
+        APP.remoteControl.receiver.deny(this.props.participantId);
118
+
119
+        return true;
120
+    }
121
+
122
+    /**
123
+     * Notifies the remote control module that the remote control request is
124
+     * accepted.
125
+     *
126
+     * @private
127
+     * @returns {boolean} Returns false to prevent closure because the dialog is
128
+     * closed manually to be sure that if the desktop picker dialog can be
129
+     * displayed (if this dialog is displayed when we try to display the desktop
130
+     * picker window, the action will be ignored).
131
+     */
132
+    _onSubmit() {
133
+        this.props.dispatch(hideDialog());
134
+
135
+        // FIXME: This should be action one day.
136
+        APP.remoteControl.receiver.grant(this.props.participantId);
137
+
138
+        return false;
139
+    }
140
+}
141
+
142
+/**
143
+ * Maps (parts of) the Redux state to the RemoteControlAuthorizationDialog's
144
+ * props.
145
+ *
146
+ * @param {Object} state - The Redux state.
147
+ * @param {Object} ownProps - The React Component props passed to the associated
148
+ * (instance of) RemoteControlAuthorizationDialog.
149
+ * @private
150
+ * @returns {{
151
+ *     _displayName: string
152
+ * }}
153
+ */
154
+function _mapStateToProps(state, ownProps) {
155
+    const { _displayName, participantId } = ownProps;
156
+    const participant = getParticipantById(
157
+            state['features/base/participants'], participantId);
158
+
159
+    return {
160
+        _displayName: participant ? participant.name : _displayName
161
+    };
162
+}
163
+
164
+export default translate(
165
+    connect(_mapStateToProps)(RemoteControlAuthorizationDialog));

+ 2
- 0
react/features/remote-control/components/index.js Целия файл

@@ -0,0 +1,2 @@
1
+export { default as RemoteControlAuthorizationDialog }
2
+    from './RemoteControlAuthorizationDialog';

+ 2
- 0
react/features/remote-control/index.js Целия файл

@@ -0,0 +1,2 @@
1
+export * from './actions';
2
+export * from './components';

Loading…
Отказ
Запис