|
@@ -1,7 +1,10 @@
|
1
|
1
|
/* global APP, $, interfaceConfig, JitsiMeetJS */
|
2
|
2
|
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
3
|
3
|
|
4
|
|
-import { pinParticipant } from '../../../react/features/base/participants';
|
|
4
|
+import {
|
|
5
|
+ getPinnedParticipant,
|
|
6
|
+ pinParticipant
|
|
7
|
+} from '../../../react/features/base/participants';
|
5
|
8
|
|
6
|
9
|
import Filmstrip from "./Filmstrip";
|
7
|
10
|
import UIEvents from "../../../service/UI/UIEvents";
|
|
@@ -22,14 +25,6 @@ var currentDominantSpeaker = null;
|
22
|
25
|
|
23
|
26
|
var eventEmitter = null;
|
24
|
27
|
|
25
|
|
-// TODO Remove this private reference to pinnedId once other components
|
26
|
|
-// interested in its updates are moved to react/redux.
|
27
|
|
-/**
|
28
|
|
- * Currently focused video jid
|
29
|
|
- * @type {String}
|
30
|
|
- */
|
31
|
|
-var pinnedId = null;
|
32
|
|
-
|
33
|
28
|
/**
|
34
|
29
|
* flipX state of the localVideo
|
35
|
30
|
*/
|
|
@@ -63,7 +58,7 @@ function onContactClicked (id) {
|
63
|
58
|
// let the bridge adjust its lastN set for myjid and store
|
64
|
59
|
// the pinned user in the lastNPickupId variable to be
|
65
|
60
|
// picked up later by the lastN changed event handler.
|
66
|
|
- APP.store.dispatch(pinParticipant(remoteVideo.id));
|
|
61
|
+ this.pinParticipant(remoteVideo.id);
|
67
|
62
|
}
|
68
|
63
|
}
|
69
|
64
|
}
|
|
@@ -281,6 +276,7 @@ var VideoLayout = {
|
281
|
276
|
return;
|
282
|
277
|
}
|
283
|
278
|
|
|
279
|
+ const pinnedId = this.getPinnedId();
|
284
|
280
|
let newId;
|
285
|
281
|
|
286
|
282
|
if (pinnedId)
|
|
@@ -392,11 +388,25 @@ var VideoLayout = {
|
392
|
388
|
},
|
393
|
389
|
|
394
|
390
|
isPinned (id) {
|
395
|
|
- return (pinnedId) ? (id === pinnedId) : false;
|
|
391
|
+ return id === this.getPinnedId();
|
396
|
392
|
},
|
397
|
393
|
|
398
|
394
|
getPinnedId () {
|
399
|
|
- return pinnedId;
|
|
395
|
+ const { id } = getPinnedParticipant(APP.store.getState()) || {};
|
|
396
|
+
|
|
397
|
+ return id || null;
|
|
398
|
+ },
|
|
399
|
+
|
|
400
|
+ /**
|
|
401
|
+ * Updates the desired pinned participant and notifies web UI of the change.
|
|
402
|
+ *
|
|
403
|
+ * @param {string|null} id - The participant id of the participant to be
|
|
404
|
+ * pinned. Pass in null to unpin without pinning another participant.
|
|
405
|
+ * @returns {void}
|
|
406
|
+ */
|
|
407
|
+ pinParticipant(id) {
|
|
408
|
+ APP.store.dispatch(pinParticipant(id));
|
|
409
|
+ APP.UI.emitEvent(UIEvents.PINNED_ENDPOINT, id, Boolean(id));
|
400
|
410
|
},
|
401
|
411
|
|
402
|
412
|
/**
|
|
@@ -406,6 +416,8 @@ var VideoLayout = {
|
406
|
416
|
*/
|
407
|
417
|
handleVideoThumbClicked (id) {
|
408
|
418
|
var smallVideo = VideoLayout.getSmallVideo(id);
|
|
419
|
+ const pinnedId = this.getPinnedId();
|
|
420
|
+
|
409
|
421
|
if(pinnedId) {
|
410
|
422
|
var oldSmallVideo = VideoLayout.getSmallVideo(pinnedId);
|
411
|
423
|
if (oldSmallVideo && !interfaceConfig.filmStripOnly) {
|
|
@@ -416,9 +428,7 @@ var VideoLayout = {
|
416
|
428
|
// Unpin if currently pinned.
|
417
|
429
|
if (pinnedId === id)
|
418
|
430
|
{
|
419
|
|
- pinnedId = null;
|
420
|
|
-
|
421
|
|
- APP.store.dispatch(pinParticipant(null));
|
|
431
|
+ this.pinParticipant(null);
|
422
|
432
|
|
423
|
433
|
// Enable the currently set dominant speaker.
|
424
|
434
|
if (currentDominantSpeaker) {
|
|
@@ -436,14 +446,11 @@ var VideoLayout = {
|
436
|
446
|
return;
|
437
|
447
|
}
|
438
|
448
|
|
439
|
|
- // Lock new video
|
440
|
|
- pinnedId = id;
|
441
|
|
-
|
442
|
449
|
// Update focused/pinned interface.
|
443
|
450
|
if (id) {
|
444
|
451
|
if (smallVideo && !interfaceConfig.filmStripOnly) {
|
445
|
452
|
smallVideo.focus(true);
|
446
|
|
- APP.store.dispatch(pinParticipant(id));
|
|
453
|
+ this.pinParticipant(id);
|
447
|
454
|
}
|
448
|
455
|
}
|
449
|
456
|
|
|
@@ -530,6 +537,8 @@ var VideoLayout = {
|
530
|
537
|
* @returns {void}
|
531
|
538
|
*/
|
532
|
539
|
_maybePlaceParticipantOnLargeVideo(resourceJid) {
|
|
540
|
+ const pinnedId = this.getPinnedId();
|
|
541
|
+
|
533
|
542
|
if ((!pinnedId &&
|
534
|
543
|
!currentDominantSpeaker &&
|
535
|
544
|
this.isLargeContainerTypeVisible(VIDEO_CONTAINER_TYPE)) ||
|
|
@@ -727,7 +736,7 @@ var VideoLayout = {
|
727
|
736
|
// Update the large video if the video source is already available,
|
728
|
737
|
// otherwise wait for the "videoactive.jingle" event.
|
729
|
738
|
// FIXME: there is no "videoactive.jingle" event.
|
730
|
|
- if (!interfaceConfig.filmStripOnly && !pinnedId
|
|
739
|
+ if (!interfaceConfig.filmStripOnly && !this.getPinnedId()
|
731
|
740
|
&& remoteVideo.hasVideoStarted()
|
732
|
741
|
&& !this.getCurrentlyOnLargeContainer().stayOnStage()) {
|
733
|
742
|
this.updateLargeVideo(id);
|
|
@@ -819,10 +828,9 @@ var VideoLayout = {
|
819
|
828
|
|
820
|
829
|
removeParticipantContainer (id) {
|
821
|
830
|
// Unlock large video
|
822
|
|
- if (pinnedId === id) {
|
|
831
|
+ if (this.getPinnedId() === id) {
|
823
|
832
|
logger.info("Focused video owner has left the conference");
|
824
|
|
- pinnedId = null;
|
825
|
|
- APP.store.dispatch(pinParticipant(null));
|
|
833
|
+ this.pinParticipant(null);
|
826
|
834
|
}
|
827
|
835
|
|
828
|
836
|
if (currentDominantSpeaker === id) {
|
|
@@ -1072,6 +1080,8 @@ var VideoLayout = {
|
1072
|
1080
|
// (pinned remote video) use its video type,
|
1073
|
1081
|
// if not then use default type - large video
|
1074
|
1082
|
if (!show) {
|
|
1083
|
+ const pinnedId = this.getPinnedId();
|
|
1084
|
+
|
1075
|
1085
|
if(pinnedId)
|
1076
|
1086
|
containerTypeToShow = this.getRemoteVideoType(pinnedId);
|
1077
|
1087
|
else
|