Compare commits

..

31 Commits
1237 ... 1252

Author SHA1 Message Date
yanas
12344ab486 Merge pull request #883 from jitsi/contactlist-displayname
Syncs contactlist display names with thumbnails.
2016-09-15 15:22:47 -05:00
yanas
b6e18d8a68 Merge pull request #882 from jitsi/fix-hide-toolbar
Fixes hiding toolbar.
2016-09-15 15:10:54 -05:00
damencho
1a0677cb59 Syncs contactlist display names with thumbnails.
Uses the same display names in the contact list as in the thumbnails, for local and remote.
2016-09-15 15:01:48 -05:00
damencho
c483587853 Fixes hiding toolbar.
Receiving messages docks the toolbar to be able to see number of unread messages. We need to undock it when we read the messages. We skip undocking if we are not in video mode (on large), cause stuff like youtube video share is docking/undocking the toolbar.
2016-09-15 14:02:56 -05:00
hristoterezov
9b25467080 Merge pull request #878 from jitsi/video-thumbnail-redesign
Video thumbnails redesign
2016-09-15 13:48:07 -05:00
yanas
f37fd15fca Merge pull request #876 from jitsi/ui-ringoverlay-stop
feat(ringoverlay): Stop ringing after 30s and change the message
2016-09-14 21:44:59 -05:00
yanas
5092f52716 Merge pull request #874 from jitsi/ui-fix-ringoverlay
feat(ringoverlay): Change the background when the avatar is displayed
2016-09-14 21:40:54 -05:00
yanas
0013745783 Video thumbnails redesign 2016-09-14 21:20:54 -05:00
hristoterezov
ad5fa13339 feat(ringoverlay): Stop ringing after 30s and change the message 2016-09-14 17:55:43 -05:00
yanas
e1fa5ecb34 Merge pull request #873 from jitsi/chat-updates
Chat updates
2016-09-14 17:08:34 -05:00
damencho
e1512e3776 Fixes focusing on write area or nickname input when chat is open. 2016-09-14 16:47:10 -05:00
hristoterezov
dab5252746 feat(ringoverlay): Change the background when the avatar is displayed 2016-09-14 16:26:17 -05:00
damencho
d8dd564b06 Fixes clearing message counter on opening the chat. 2016-09-14 15:22:36 -05:00
damencho
407b082780 Removes changing the message icon and flashing on new message. 2016-09-14 15:18:14 -05:00
damencho
a671093489 Introduces chat_container_id variable. 2016-09-14 15:13:15 -05:00
Дамян Минков
29f0c0b311 Merge pull request #870 from jitsi/add-raised-hand-icon
Adds raise hand icon
2016-09-14 12:17:06 -05:00
yanas
955680018f Merge pull request #872 from jitsi/fix-hiding-toolbars
Fixes hiding toolbars.
2016-09-14 12:16:57 -05:00
damencho
686e85cd4f Fixes hiding toolbars.
Schedule new hide check if toolbar is hovered, overlay is shown or the sideBar container is visible (chat, contactlist , etc.).
2016-09-14 11:51:47 -05:00
hristoterezov
297d4e65fc style(gitignore): Add .sync-config.cson 2016-09-14 11:38:43 -05:00
yanas
0e94bf7e0b Merge pull request #871 from jitsi/fix-remote-video-thumb
Fixes parameters for VideoLayout.resizeThumbnails.
2016-09-14 11:00:14 -05:00
damencho
a5bc9625ef Fixes parameters for VideoLayout.resizeThumbnails. 2016-09-14 10:48:38 -05:00
yanas
cbde4f89b2 Adds raise hand icon 2016-09-14 09:00:59 -05:00
yanas
891c108191 Merges fix from m-voloshin for Firefox toolbar 2016-09-14 08:25:11 -05:00
yanas
764d767789 Update _variables.scss 2016-09-14 01:22:33 -05:00
yanas
7ded10cd8d Merge pull request #865 from jitsi/add-raise-hand-button
Adds a possibility to add raise hand as a button
2016-09-13 23:09:18 -05:00
yanas
3b05a16b32 Fix for button appearing in both toolbars 2016-09-13 22:10:13 -05:00
yanas
cf49c8c6ff Adds raise hand button to the side toolbar 2016-09-13 21:21:31 -05:00
yanas
99bf4bc44d Adds a possibility to add raise hand as a button 2016-09-13 21:21:31 -05:00
yanas
929639b06b Merge pull request #863 from jitsi/contact-list-update
Contact list update
2016-09-13 21:21:03 -05:00
damencho
4c72833f5a Adds an option and hide avatars in contact list. 2016-09-13 17:14:05 -05:00
damencho
e3eaac5bef Disables click toggler. 2016-09-13 17:12:10 -05:00
33 changed files with 608 additions and 286 deletions

1
.gitignore vendored
View File

@@ -9,3 +9,4 @@ all.css
*css.map
unsupported_browser.css
.remote-sync.json
.sync-config.cson

View File

@@ -16,7 +16,7 @@
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 0.75em;
line-height: 1.22em;
font-size: 1.22em;
/* Better Font Rendering =========== */
@@ -84,6 +84,9 @@
.icon-mic-disabled:before {
content: "\e912";
}
.icon-raised-hand:before {
content: "\e91e";
}
.icon-contactList:before {
content: "\e91b";
}

View File

@@ -36,6 +36,19 @@
}
}
@mixin circle($diameter) {
width: $diameter;
height: $diameter;
border-radius: 50%;
}
@mixin absoluteAligning($sizeX, $sizeY) {
top: 50%;
left: 50%;
position: absolute;
@include transform(translate(-#{$sizeX / 2}, -#{$sizeY / 2}))
}
@mixin transform($func) {
-moz-transform: $func;
-ms-transform: $func;

View File

@@ -56,11 +56,11 @@
}
#extendedToolbar {
display: flex;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-box;
display: -webkit-flex;
display: flex;
width: $defaultToolbarSize;
height: 100%;
top: 0px;

View File

@@ -1,5 +1,4 @@
/**
<<<<<<< HEAD
* Style variables
*/
$baseFontFamily: 'open_sanslight', 'Helvetica Neue', Helvetica, Arial, sans-serif;
@@ -11,6 +10,11 @@ $hangupFontSize: 2em;
*/
$defaultToolbarSize: 50px;
// Video layout.
$thumbnailIndicatorSize: 23px;
$thumbnailIndicatorBorder: 0px;
$thumbnailVideoMargin: 2px;
/**
* Color variables.
*/
@@ -18,13 +22,29 @@ $defaultColor: #F1F1F1;
$defaultSemiDarkColor: #ACACAC;
$defaultDarkColor: #4F4F4F;
$defaultBackground: #474747;
// Toolbar
$toolbarSelectBackground: rgba(0, 0, 0, .6);
// Main controls
$inputBackground: rgba(132, 132, 132, .5);
$inputSemiBackground: rgba(132, 132, 132, .8);
$inputLightBackground: #EBEBEB;
$inputBorderColor: #EBEBEB;
$buttonBackground: #44A5FF;
// Video layout.
$videoThumbnailHovered: #44A5FF;
$videoThumbnailSelected: #165ecc;
$participantNameColor: #fff;
$thumbnailPictogramColor: #fff;
$dominantSpeakerBg: #165ecc;
$raiseHandBg: #D6D61E;
$rateStarDefault: #ccc;
$rateStarActivity: #165ecc;
$rateStarLabelColor: #333;
/**
* Misc.
*/
@@ -35,8 +55,4 @@ $defaultWatermarkLink: '../images/watermark.png';
* Z-indexes. TODO: Replace this by a function.
*/
$toolbarZ: 900;
$overlayZ: 800;
$rateStarDefault: #ccc;
$rateStarActivity: #f6c342;
$rateStarLabelColor: #333;
$overlayZ: 800;

View File

@@ -13,17 +13,17 @@
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
flex-direction: row;
flex-direction: row-reverse;
flex-wrap: nowrap;
justify-content: flex-end;
justify-content: flex-start;
position:absolute;
text-align:right;
height:196px;
padding: 18px;
padding: 10px 10px 10px 5px;
bottom: 0;
left: 0;
right: 20px;
right: 0;
width:auto;
border:1px solid transparent;
z-index: 5;
@@ -43,10 +43,23 @@
#remoteVideos .videocontainer {
display: none;
position: relative;
background-color: black;
background-size: contain;
border-radius:1px;
border: 1px solid #212425;
margin: 0 $thumbnailVideoMargin;
border: 1px solid $defaultDarkColor;
}
.videocontainer__toolbar {
position: absolute;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
height: 25px;
max-height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
#remoteVideos .videocontainer.videoContainerFocused {
@@ -58,18 +71,13 @@
-webkit-animation-iteration-count: 1;
}
#remoteVideos .videocontainer:hover {
border: 1px solid #c1c1c1;
}
#remoteVideos .videocontainer.videoContainerFocused {
box-shadow: inset 0 0 28px #006d91;
border: 1px solid #006d91;
border: 1px solid $videoThumbnailSelected;
}
#remoteVideos .videocontainer:hover,
#remoteVideos .videocontainer.videoContainerFocused:hover {
box-shadow: inset 0 0 5px #c1c1c1, 0 0 10px #c1c1c1, inset 0 0 60px #006d91;
border: 1px solid #c1c1c1;
border: 1px solid $videoThumbnailHovered;
}
#localVideoWrapper {
@@ -145,11 +153,11 @@
#remoteVideos .videocontainer>div.remotevideomenu {
position: absolute;
color: #FFFFFF;
top: 0;
left: 0;
bottom: 0;
right: 0;
padding: 5px 0px;
width: 25px;
font-size: 11pt;
font-size: 9pt;
text-shadow: 0px 1px 0px rgba(255,255,255,.3), 0px -1px 0px rgba(0,0,0,.7);
border: 0px;
z-index: 2;
@@ -166,22 +174,28 @@
.videocontainer>span.displayname,
.videocontainer>input.displayname {
display: none;
display: inline-block;
position: absolute;
color: #FFFFFF;
background: rgba(0,0,0,.7);
bottom: 4px;
left: 25%;
color: $participantNameColor;
text-align: center;
text-overflow: ellipsis;
width: 70%;
height: 20%;
left: 15%;
top: 40%;
padding: 5px;
font-size: 11pt;
width: 50%;
font-size: 12px;
font-weight: 100;
letter-spacing: 1px;
overflow: hidden;
white-space: nowrap;
z-index: 2;
border-radius:3px;
}
.videocontainer>input.displayname {
outline: none;
border: none;
background: none;
box-shadow: none;
padding: 0;
}
.videocontainer>span.status {
@@ -291,7 +305,8 @@
display: inline-block;
position: absolute;
color: #FFFFFF;
top: 0;
bottom: 0;
left: 0;
padding: 8px 5px;
width: 25px;
font-size: 8pt;
@@ -305,8 +320,7 @@
display: inline-block;
position: absolute;
color: #FFFFFF;
top: 0;
right: 0;
bottom: 0;
padding: 8px 5px;
width: 25px;
font-size: 8pt;
@@ -316,24 +330,30 @@
}
.videocontainer>span.indicator {
bottom: 0px;
position: absolute;
top: 0px;
left: 0px;
width: 25px;
height: 25px;
@include circle($thumbnailIndicatorSize);
box-sizing: border-box;
line-height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
z-index: 3;
text-align: center;
border-radius: 50%;
background: #21B9FC;
margin: 5px;
background: $dominantSpeakerBg;
margin: 7px;
display: inline-block;
position: absolute;
color: #FFFFFF;
font-size: 11pt;
border: 0px;
color: $thumbnailPictogramColor;
font-size: 8pt;
border: $thumbnailIndicatorBorder solid $thumbnailPictogramColor;
}
.videocontainer>#raisehandindicator {
background: $raiseHandBg;
}
#indicatoricon {
padding-top: 5px;
width: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
line-height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
}
#reloadPresentation {
@@ -395,10 +415,8 @@
}
.userAvatar {
height: 100%;
position: absolute;
left: 0;
border-radius: 2px;
@include circle(60px);
@include absoluteAligning(60px, 60px);
}
.sharedVideoAvatar {

View File

@@ -9,6 +9,11 @@
background: linear-gradient(transparent, #000);
opacity: 0.8;
&.solidBG {
background: $defaultBackground;
opacity: 1;
}
&__content {
position: absolute;
width: 400px;
@@ -33,4 +38,4 @@
color: #333;
}
}
}
}

Binary file not shown.

View File

@@ -41,4 +41,5 @@
<glyph unicode="&#xe91b;" glyph-name="contactList" d="M704 746c-46 0-86-38-86-84s40-86 86-86 86 40 86 86-40 84-86 84zM704 512c-82 0-150 68-150 150s68 148 150 148 150-66 150-148-68-150-150-150zM320 746c-46 0-86-38-86-84s40-86 86-86 86 40 86 86-40 84-86 84zM320 512c-82 0-150 68-150 150s68 148 150 148 150-66 150-148-68-150-150-150zM918 278v52c0 24-110 76-214 76-46 0-90-12-128-24 14-16 22-32 22-52v-52h320zM534 278v52c0 24-110 76-214 76s-214-52-214-76v-52h428zM704 470c92 0 278-48 278-140v-116h-940v116c0 92 186 140 278 140 52 0 130-16 192-44 62 28 140 44 192 44z" />
<glyph unicode="&#xe91c;" glyph-name="toggle-filmstrip" d="M896 896h-768c-46.933 0-85.333-38.4-85.333-85.333v-597.333c0-46.933 38.4-85.333 85.333-85.333h768c46.933 0 85.333 38.4 85.333 85.333v597.333c0 46.933-38.4 85.333-85.333 85.333zM896 213.333h-768v128h768v-128z" />
<glyph unicode="&#xe91d;" glyph-name="feedback" d="M42.667 128h170.667v512h-170.667v-512zM981.333 597.333c0 46.933-38.4 85.333-85.333 85.333h-269.227l40.533 194.987 1.28 13.653c0 17.493-7.253 33.707-18.773 45.227l-45.227 44.8-280.747-281.173c-15.787-15.36-25.173-36.693-25.173-60.16v-426.667c0-46.933 38.4-85.333 85.333-85.333h384c35.413 0 65.707 21.333 78.507 52.053l128.853 300.8c3.84 9.813 5.973 20.053 5.973 31.147v81.493l-0.427 0.427 0.427 3.413z" />
<glyph unicode="&#xe91e;" glyph-name="raised-hand" d="M982 790v-620c0-94-78-170-172-170h-310c-46 0-90 18-122 50l-336 342s54 52 56 52c10 8 22 12 34 12 10 0 18-2 26-6 2 0 184-104 184-104v508c0 36 28 64 64 64s64-28 64-64v-300h42v406c0 36 28 64 64 64s64-28 64-64v-406h42v364c0 36 28 64 64 64s64-28 64-64v-364h44v236c0 36 28 64 64 64s64-28 64-64z" />
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -69,8 +69,10 @@
"tags": [
"account_circle"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 11,
"order": 60,
@@ -93,8 +95,10 @@
"tags": [
"autorenew"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 68,
"order": 84,
@@ -117,8 +121,10 @@
"tags": [
"call_end"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 122,
"order": 63,
@@ -141,8 +147,10 @@
"tags": [
"chat_bubble_outline"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 148,
"order": 61,
@@ -165,8 +173,10 @@
"tags": [
"cloud_download"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 164,
"order": 99,
@@ -189,8 +199,10 @@
"tags": [
"mode_edit"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 185,
"order": 89,
@@ -213,8 +225,10 @@
"tags": [
"description"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 206,
"order": 85,
@@ -237,8 +251,10 @@
"tags": [
"dialer_sip"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 215,
"order": 95,
@@ -261,8 +277,10 @@
"tags": [
"eject"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 242,
"order": 98,
@@ -285,8 +303,10 @@
"tags": [
"fullscreen"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 350,
"order": 94,
@@ -309,8 +329,10 @@
"tags": [
"fullscreen_exit"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 351,
"order": 92,
@@ -333,8 +355,10 @@
"tags": [
"star"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 363,
"order": 101,
@@ -357,8 +381,10 @@
"tags": [
"lock_open"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 473,
"order": 66,
@@ -381,8 +407,10 @@
"tags": [
"lock_outline"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 474,
"order": 65,
@@ -405,8 +433,10 @@
"tags": [
"sync"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 482,
"order": 67,
@@ -429,8 +459,10 @@
"tags": [
"mic"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 492,
"order": 68,
@@ -453,8 +485,10 @@
"tags": [
"mic_none"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 493,
"order": 69,
@@ -477,8 +511,10 @@
"tags": [
"mic_off"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 494,
"order": 70,
@@ -491,6 +527,32 @@
"setId": 2,
"iconIdx": 495
},
{
"icon": {
"paths": [
"M982 234v620c0 94-78 170-172 170h-310c-46 0-90-18-122-50l-336-342s54-52 56-52c10-8 22-12 34-12 10 0 18 2 26 6 2 0 184 104 184 104v-508c0-36 28-64 64-64s64 28 64 64v300h42v-406c0-36 28-64 64-64s64 28 64 64v406h42v-364c0-36 28-64 64-64s64 28 64 64v364h44v-236c0-36 28-64 64-64s64 28 64 64z"
],
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"pan_tool"
],
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 539,
"order": 105,
"ligatures": "pan_tool",
"prevSize": 32,
"code": 59678,
"name": "raised-hand"
},
"setIdx": 0,
"setId": 2,
"iconIdx": 540
},
{
"icon": {
"paths": [
@@ -501,8 +563,10 @@
"tags": [
"people_outline"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 549,
"order": 100,
@@ -525,8 +589,10 @@
"tags": [
"person_add"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 559,
"order": 87,
@@ -549,8 +615,10 @@
"tags": [
"play_circle_outline"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 590,
"order": 82,
@@ -573,8 +641,10 @@
"tags": [
"settings"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 665,
"order": 81,
@@ -597,8 +667,10 @@
"tags": [
"star_border"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 717,
"order": 76,
@@ -621,8 +693,10 @@
"tags": [
"tv"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 783,
"order": 93,
@@ -645,8 +719,10 @@
"tags": [
"videocam"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 798,
"order": 77,
@@ -669,8 +745,10 @@
"tags": [
"videocam_off"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 799,
"order": 78,
@@ -693,8 +771,10 @@
"tags": [
"volume_up"
],
"grid": 0
"grid": 0,
"attrs": []
},
"attrs": [],
"properties": {
"id": 821,
"order": 79,

View File

@@ -123,6 +123,7 @@
<a class="button icon-contactList" id="toolbar_contact_list" data-container="body" data-toggle="popover" data-placement="right" shortcut="contactlistpopover" data-i18n="[content]bottomtoolbar.contactlist" content="Open / close contact list">
<span id="numberOfParticipants"></span>
</a>
<!--a class="button icon-link" id="toolbar_button_link" data-container="body" data-toggle="popover" data-placement="right" data-i18n="[content]toolbar.invite" content="Invite others"></a-->
<a class="button icon-chat" id="toolbar_button_chat" data-container="body" data-toggle="popover" shortcut="toggleChatPopover" data-placement="right" data-i18n="[content]toolbar.chat" content="Open / close chat">
<span id="unreadMessages"></span>
</a>
@@ -137,6 +138,7 @@
<a class="button icon-telephone" id="toolbar_button_sip" data-container="body" data-toggle="popover" data-placement="right" content="Call SIP number" data-i18n="[content]toolbar.sip" style="display: none"></a>
<a class="button icon-dialpad" id="toolbar_button_dialpad" data-container="body" data-toggle="popover" data-placement="right" content="Open dialpad" data-i18n="[content]toolbar.dialpad" style="display: none"></a>
<a class="button icon-settings" id="toolbar_button_settings" data-container="body" data-toggle="popover" data-placement="right" content="Settings" data-i18n="[content]toolbar.Settings"></a>
<a class="button icon-raised-hand" id="toolbar_button_raisehand" data-container="body" data-toggle="popover" data-placement="right" data-i18n="[content]toolbar.raiseHand" content="Raise Hand" shortcut="raiseHandPopover"></a>
<a class="button icon-full-screen" id="toolbar_button_fullScreen" data-container="body" data-toggle="popover" data-placement="right" shortcut="toggleFullscreenPopover" data-i18n="[content]toolbar.fullscreen" content="Enter / Exit Full Screen"></a>
<a class="button icon-toggle-filmstrip" id="toolbar_film_strip" data-container="body" data-toggle="popover" shortcut="filmstripPopover" data-placement="right" data-i18n="[content]toolbar.filmstrip" content="Show / hide videos"></a>
<a class="button icon-feedback" id="feedbackButton" data-container="body" data-toggle="popover" data-placement="right" data-i18n="[content]feedback"></a>
@@ -236,12 +238,13 @@
</div>
<div id="remoteVideos">
<span id="localVideoContainer" class="videocontainer">
<span id="localVideoContainer" class="videocontainer videocontainer_small">
<span id="localVideoWrapper">
<!--<video id="localVideo" autoplay muted></video> - is now per stream generated -->
</span>
<audio id="localAudio" autoplay muted></audio>
<span class="focusindicator"></span>
<div class="videocontainer__toolbar"></div>
</span>
<audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
<audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>

View File

@@ -20,18 +20,23 @@ var interfaceConfig = {
// the toolbar buttons line is intentionally left in one line, to be able
// to easily override values or remove them using regex
MAIN_TOOLBAR_BUTTONS: ['microphone', 'camera', 'desktop', 'invite', 'hangup'], // jshint ignore:line
TOOLBAR_BUTTONS: ['profile', 'authentication', 'microphone', 'camera', 'desktop', 'recording', 'security', 'invite', 'chat', 'etherpad', 'sharedvideo', 'fullscreen', 'sip', 'dialpad', 'settings', 'hangup', 'filmstrip', 'contacts'], // jshint ignore:line
TOOLBAR_BUTTONS: ['profile', 'authentication', 'microphone', 'camera', 'desktop', 'recording', 'security', 'raisehand', 'chat', 'etherpad', 'sharedvideo', 'fullscreen', 'sip', 'dialpad', 'settings', 'hangup', 'filmstrip', 'contacts'], // jshint ignore:line
SETTINGS_SECTIONS: ['language', 'devices', 'moderator'],
// Determines how the video would fit the screen. 'both' would fit the whole
// screen, 'height' would fit the original video height to the height of the
// screen, 'width' would fit the original video width to the width of the
// screen respecting ratio.
VIDEO_LAYOUT_FIT: 'both',
SHOW_CONTACTLIST_AVATARS: false,
/**
* Whether to only show the filmstrip (and hide the toolbar).
*/
filmStripOnly: false,
RANDOM_AVATAR_URL_PREFIX: false,
RANDOM_AVATAR_URL_SUFFIX: false,
FILM_STRIP_MAX_HEIGHT: 120
};
FILM_STRIP_MAX_HEIGHT: 120,
LOCAL_THUMBNAIL_RATIO_WIDTH: 16,
LOCAL_THUMBNAIL_RATIO_HEIGHT: 9,
REMOTE_THUMBNAIL_RATIO_WIDTH: 1,
REMOTE_THUMBNAIL_RATIO_HEIGHT: 1
};

View File

@@ -5,7 +5,6 @@
"downloadlogs": "Download logs",
"feedback": "Give us your feedback",
"roomUrlDefaultMsg": "Your conference is currently being created...",
"participant": "Participant",
"me": "me",
"speaker": "Speaker",
"raisedHand": "Would like to speak",
@@ -94,7 +93,8 @@
"unableToUnmutePopup": "You cannot un-mute while the shared video is on.",
"cameraDisabled": "Camera is not available",
"micDisabled": "Microphone is not available",
"filmstrip": "Show / hide videos"
"filmstrip": "Show / hide videos",
"raiseHand": "Raise hand to speak"
},
"bottomtoolbar": {
"chat": "Open / close chat",

View File

@@ -1,5 +1,6 @@
/* global $, APP, config, interfaceConfig, JitsiMeetJS */
import UIEvents from "../../service/UI/UIEvents";
import UIUtil from "./util/UIUtil";
/**
* Constructs the html for the overall feedback window.

View File

@@ -292,7 +292,7 @@ UI.initConference = function () {
}
// Add myself to the contact list.
ContactList.addContact(id);
ContactList.addContact(id, true);
//update default button states before showing the toolbar
//if local role changes buttons state will be again updated

View File

@@ -10,7 +10,7 @@ let ASDrawContext = null;
let audioLevelCanvasCache = {};
let dominantSpeakerAudioElement = null;
function initDominantSpeakerAudioLevels(dominantSpeakerAvatarSize) {
function _initDominantSpeakerAudioLevels(dominantSpeakerAvatarSize) {
let ASRadius = dominantSpeakerAvatarSize / 2;
let ASCenter = (dominantSpeakerAvatarSize + ASRadius) / 2;
@@ -28,7 +28,9 @@ function initDominantSpeakerAudioLevels(dominantSpeakerAvatarSize) {
/**
* Resizes the given audio level canvas to match the given thumbnail size.
*/
function resizeAudioLevelCanvas(audioLevelCanvas, thumbnailWidth, thumbnailHeight) {
function _resizeAudioLevelCanvas( audioLevelCanvas,
thumbnailWidth,
thumbnailHeight) {
audioLevelCanvas.width = thumbnailWidth + interfaceConfig.CANVAS_EXTRA;
audioLevelCanvas.height = thumbnailHeight + interfaceConfig.CANVAS_EXTRA;
}
@@ -138,18 +140,18 @@ const AudioLevels = {
dominantSpeakerAudioElement.height = dominantSpeakerHeight;
let dominantSpeakerAvatar = $("#dominantSpeakerAvatar");
initDominantSpeakerAudioLevels(dominantSpeakerAvatar.width());
_initDominantSpeakerAudioLevels(dominantSpeakerAvatar.width());
},
/**
* Updates the audio level canvas for the given id. If the canvas
* didn't exist we create it.
*/
updateAudioLevelCanvas (id, thumbWidth, thumbHeight) {
let videoSpanId = 'localVideoContainer';
if (id) {
videoSpanId = `participant_${id}`;
}
createAudioLevelCanvas (id, thumbWidth, thumbHeight) {
let videoSpanId = (id === "local")
? "localVideoContainer"
: `participant_${id}`;
let videoSpan = document.getElementById(videoSpanId);
@@ -172,13 +174,13 @@ const AudioLevels = {
= `-${interfaceConfig.CANVAS_EXTRA/2}px`;
audioLevelCanvas.style.left
= `-${interfaceConfig.CANVAS_EXTRA/2}px`;
resizeAudioLevelCanvas(audioLevelCanvas, thumbWidth, thumbHeight);
_resizeAudioLevelCanvas(audioLevelCanvas, thumbWidth, thumbHeight);
videoSpan.appendChild(audioLevelCanvas);
} else {
audioLevelCanvas = audioLevelCanvas.get(0);
resizeAudioLevelCanvas(audioLevelCanvas, thumbWidth, thumbHeight);
_resizeAudioLevelCanvas(audioLevelCanvas, thumbWidth, thumbHeight);
}
},
@@ -242,19 +244,29 @@ const AudioLevels = {
ASDrawContext.fill();
},
updateCanvasSize (thumbWidth, thumbHeight) {
let canvasWidth = thumbWidth + interfaceConfig.CANVAS_EXTRA;
let canvasHeight = thumbHeight + interfaceConfig.CANVAS_EXTRA;
updateCanvasSize (localVideo, remoteVideo) {
let localCanvasWidth
= localVideo.thumbWidth + interfaceConfig.CANVAS_EXTRA;
let localCanvasHeight
= localVideo.thumbHeight + interfaceConfig.CANVAS_EXTRA;
let remoteCanvasWidth
= remoteVideo.thumbWidth + interfaceConfig.CANVAS_EXTRA;
let remoteCanvasHeight
= remoteVideo.thumbHeight + interfaceConfig.CANVAS_EXTRA;
FilmStrip.getThumbs().children('canvas').each(function () {
$(this).attr('width', canvasWidth);
$(this).attr('height', canvasHeight);
let { remoteThumbs, localThumb } = FilmStrip.getThumbs();
remoteThumbs.children('canvas').each(function () {
$(this).attr('width', remoteCanvasWidth);
$(this).attr('height', remoteCanvasHeight);
});
Object.keys(audioLevelCanvasCache).forEach(function (id) {
audioLevelCanvasCache[id].width = canvasWidth;
audioLevelCanvasCache[id].height = canvasHeight;
});
if(localThumb) {
localThumb.children('canvas').each(function () {
$(this).attr('width', localCanvasWidth);
$(this).attr('height', localCanvasHeight);
});
}
}
};

View File

@@ -1,5 +1,21 @@
/* global $ */
/* global $, APP */
/* jshint -W101 */
import UIEvents from "../../../service/UI/UIEvents";
/**
* Store the current ring overlay instance.
* Note: We want to have only 1 instance at a time.
*/
let overlay = null;
/**
* Handler for UIEvents.LARGE_VIDEO_AVATAR_DISPLAYED event.
* @param {boolean} shown indicates whether the avatar on the large video is
* currently displayed or not.
*/
function onAvatarDisplayed(shown) {
overlay._changeBackground(shown);
}
/**
* Shows ring overlay
@@ -11,25 +27,46 @@ class RingOverlay {
constructor(callee) {
this._containerId = 'ringOverlay';
this._audioContainerId = 'ringOverlayRinging';
this.isRinging = true;
this.callee = callee;
this.render();
this.audio = document.getElementById(this._audioContainerId);
this.audio.play();
this._setAudioTimeout();
this._timeout = setTimeout(() => {
this.destroy();
this.render();
}, 30000);
}
/**
* Chagnes the background of the ring overlay.
* @param {boolean} solid - if true the new background will be the solid
* one, otherwise the background will be default one.
* NOTE: The method just toggles solidBG css class.
*/
_changeBackground(solid) {
const container = $("#" + this._containerId);
if(solid) {
container.addClass("solidBG");
} else {
container.removeClass("solidBG");
}
}
/**
* Builds and appends the ring overlay to the html document
*/
_getHtmlStr(callee) {
let callingLabel = this.isRinging? "<p>Calling...</p>" : "";
let callerStateLabel = this.isRinging? "" : " isn't available";
return `
<div id="${this._containerId}" class='ringing' >
<div class='ringing__content'>
<p>Calling...</p>
${callingLabel}
<img class='ringing__avatar' src="${callee.getAvatarUrl()}" />
<div class="ringing__caller-info">
<p>${callee.getName()}</p>
<p>${callee.getName()}${callerStateLabel}</p>
</div>
</div>
<audio id="${this._audioContainerId}" src="/sounds/ring.ogg" />
@@ -49,10 +86,7 @@ class RingOverlay {
* related to the ring overlay.
*/
destroy() {
if (this.interval) {
clearInterval(this.interval);
}
this._stopAudio();
this._detach();
}
@@ -64,6 +98,16 @@ class RingOverlay {
$(`#${this._containerId}`).remove();
}
_stopAudio() {
this.isRinging = false;
if (this.interval) {
clearInterval(this.interval);
}
if(this._timeout) {
clearTimeout(this._timeout);
}
}
/**
* Sets the interval that is going to play the ringing sound.
*/
@@ -74,12 +118,6 @@ class RingOverlay {
}
}
/**
* Store the current ring overlay instance.
* Note: We want to have only 1 instance at a time.
*/
let overlay = null;
export default {
/**
* Shows the ring overlay for the passed callee.
@@ -92,6 +130,8 @@ export default {
}
overlay = new RingOverlay(callee);
APP.UI.addListener(UIEvents.LARGE_VIDEO_AVATAR_DISPLAYED,
onAvatarDisplayed);
},
/**
@@ -104,6 +144,8 @@ export default {
}
overlay.destroy();
overlay = null;
APP.UI.removeListener(UIEvents.LARGE_VIDEO_AVATAR_DISPLAYED,
onAvatarDisplayed);
return true;
},

View File

@@ -3,20 +3,24 @@
import {processReplacements, linkify} from './Replacement';
import CommandsProcessor from './Commands';
import ToolbarToggler from '../../toolbars/ToolbarToggler';
import VideoLayout from "../../videolayout/VideoLayout";
import UIUtil from '../../util/UIUtil';
import UIEvents from '../../../../service/UI/UIEvents';
var smileys = require("./smileys.json").smileys;
var notificationInterval = false;
var unreadMessages = 0;
/**
* The container id, which is and the element id.
*/
var CHAT_CONTAINER_ID = "chat_container";
/**
* Shows/hides a visual notification, indicating that a message has arrived.
* Updates visual notification, indicating that a message has arrived.
*/
function setVisualNotification(show) {
function updateVisualNotification() {
var unreadMsgElement = document.getElementById('unreadMessages');
var glower = $('#toolbar_button_chat');
@@ -37,27 +41,9 @@ function setVisualNotification(show) {
'style',
'top:' + topIndent +
'; left:' + leftIndent + ';');
if (!glower.hasClass('icon-chat-simple')) {
glower.removeClass('icon-chat');
glower.addClass('icon-chat-simple');
}
}
else {
unreadMsgElement.innerHTML = '';
glower.removeClass('icon-chat-simple');
glower.addClass('icon-chat');
}
if (show && !notificationInterval) {
notificationInterval = window.setInterval(function () {
glower.toggleClass('active');
}, 800);
}
else if (!show && notificationInterval) {
window.clearInterval(notificationInterval);
notificationInterval = false;
glower.removeClass('active');
}
}
@@ -131,7 +117,7 @@ function addSmileys() {
*/
function resizeChatConversation() {
var msgareaHeight = $('#usermsg').outerHeight();
var chatspace = $('#chat_container');
var chatspace = $('#' + CHAT_CONTAINER_ID);
var width = chatspace.width();
var chat = $('#chatconversation');
var smileys = $('#smileysarea');
@@ -187,10 +173,26 @@ var Chat = {
};
usermsg.autosize({callback: onTextAreaResize});
$("#chat_container").bind("shown",
function () {
eventEmitter.on(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
function(containerId, isVisible) {
if (containerId !== CHAT_CONTAINER_ID || !isVisible)
return;
unreadMessages = 0;
setVisualNotification(false);
updateVisualNotification();
// Undock the toolbar when the chat is shown and if we're in a
// video mode.
if (VideoLayout.isLargeVideoVisible()) {
ToolbarToggler.dockToolbar(false);
}
// if we are in conversation mode focus on the text input
// if we are not, focus on the display name input
if (APP.settings.getDisplayName())
$('#usermsg').focus();
else
$('#nickinput').focus();
});
addSmileys();
@@ -210,7 +212,7 @@ var Chat = {
if (!Chat.isVisible()) {
unreadMessages++;
UIUtil.playSoundNotification('chatNotification');
setVisualNotification(true);
updateVisualNotification();
}
}
@@ -271,12 +273,18 @@ var Chat = {
/**
* Sets the chat conversation mode.
* Conversation mode is the normal chat mode, non conversation mode is
* where we ask user to input its display name.
* @param {boolean} isConversationMode if chat should be in
* conversation mode or not.
*/
setChatConversationMode (isConversationMode) {
$('#chat_container')
$('#' + CHAT_CONTAINER_ID)
.toggleClass('is-conversation-mode', isConversationMode);
// this is needed when we transition from no conversation mode to
// conversation mode. When user enters his nickname and hits enter,
// to focus on the write area.
if (isConversationMode) {
$('#usermsg').focus();
}
@@ -286,7 +294,7 @@ var Chat = {
* Resizes the chat area.
*/
resizeChat (width, height) {
$('#chat_container').width(width).height(height);
$('#' + CHAT_CONTAINER_ID).width(width).height(height);
resizeChatConversation();
},
@@ -296,7 +304,7 @@ var Chat = {
*/
isVisible () {
return UIUtil.isVisible(
document.getElementById("chat_container"));
document.getElementById(CHAT_CONTAINER_ID));
},
/**
* Shows and hides the window with the smileys

View File

@@ -1,4 +1,4 @@
/* global $, APP */
/* global $, APP, interfaceConfig */
import Avatar from '../../avatar/Avatar';
import UIEvents from '../../../../service/UI/UIEvents';
import UIUtil from '../../util/UIUtil';
@@ -96,9 +96,9 @@ var ContactList = {
/**
* Adds a contact for the given id.
*
* @param isLocal is an id for the local user.
*/
addContact (id) {
addContact (id, isLocal) {
let contactlist = $('#contacts');
let newContact = document.createElement('li');
@@ -110,8 +110,13 @@ var ContactList = {
}
};
newContact.appendChild(createAvatar(id));
newContact.appendChild(createDisplayNameParagraph("participant"));
if (interfaceConfig.SHOW_CONTACTLIST_AVATARS)
newContact.appendChild(createAvatar(id));
newContact.appendChild(
createDisplayNameParagraph(
isLocal ? interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME : null,
isLocal ? null : interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME));
if (APP.conference.isLocalId(id)) {
contactlist.prepend(newContact);

View File

@@ -7,7 +7,6 @@ import SideContainerToggler from "../side_pannels/SideContainerToggler";
let roomUrl = null;
let emitter = null;
/**
* Opens the invite link dialog.
*/
@@ -168,8 +167,13 @@ const buttonHandlers = {
},
"toolbar_film_strip": function () {
JitsiMeetJS.analytics.sendEvent(
'bottomtoolbar.filmstrip.toggled');
'toolbar.filmstrip.toggled');
emitter.emit(UIEvents.TOGGLE_FILM_STRIP);
},
"toolbar_button_raisehand": function () {
JitsiMeetJS.analytics.sendEvent(
'toolbar.raiseHand.clicked');
APP.conference.maybeToggleRaisedHand();
}
};
@@ -288,6 +292,19 @@ const defaultToolbarButtons = {
APP.UI.toggleFilmStrip();
},
shortcutDescription: "keyboardShortcuts.toggleFilmstrip"
},
'raisehand': {
id: "toolbar_button_raisehand",
className: "button icon-raised-hand",
shortcut: "R",
shortcutAttr: "raiseHandPopover",
shortcutFunc: function() {
JitsiMeetJS.analytics.sendEvent("shortcut.raisehand.clicked");
APP.conference.maybeToggleRaisedHand();
},
shortcutDescription: "keyboardShortcuts.raiseHand",
content: "Raise Hand",
i18n: "[content]toolbar.raiseHand"
}
};
@@ -323,10 +340,14 @@ const Toolbar = {
this.toolbarSelector = $("#mainToolbarContainer");
this.extendedToolbarSelector = $("#extendedToolbar");
this._initMainToolbarButtons();
// First hide all disabled buttons in the extended toolbar.
// TODO: Make the extended toolbar dynamically created.
UIUtil.hideDisabledButtons(defaultToolbarButtons);
// Initialise the main toolbar. The main toolbar will only take into
// account it's own configuration from interface_config.
this._initMainToolbarButtons();
Object.keys(defaultToolbarButtons).forEach(
id => {
if (UIUtil.isButtonEnabled(id)) {
@@ -679,16 +700,9 @@ const Toolbar = {
}
);
},
/**
* TODO: Fix mic popups
* <a class="button icon-microphone" id="toolbar_button_mute" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="mutePopover" data-i18n="[content]toolbar.mute" content="Mute / Unmute">
* <ul id="micMutedPopup" class="loginmenu">
* <li data-i18n="[html]toolbar.micMutedPopup"></li>
* </ul>
* <ul id="unableToUnmutePopup" class="loginmenu">
* <li data-i18n="[html]toolbar.unableToUnmutePopup"></li>
* </ul>
* </a>
* Initialise main toolbar buttons.
*/
_initMainToolbarButtons() {
interfaceConfig.MAIN_TOOLBAR_BUTTONS.forEach((value, index) => {
@@ -751,4 +765,4 @@ const Toolbar = {
}
};
export default Toolbar;
export default Toolbar;

View File

@@ -35,9 +35,11 @@ function hideToolbar(force) {
clearTimeout(toolbarTimeoutObject);
toolbarTimeoutObject = null;
if (Toolbar.isHovered() || APP.UI.isRingOverlayVisible()) {
if (Toolbar.isHovered()
|| APP.UI.isRingOverlayVisible()
|| SideContainerToggler.isVisible()) {
toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
} else if (!SideContainerToggler.isVisible() || force) {
} else {
Toolbar.hide();
$('#subject').animate({top: "-=40"}, 300);
}
@@ -50,7 +52,8 @@ const ToolbarToggler = {
init() {
alwaysVisibleToolbar = (config.alwaysVisibleToolbar === true);
this._registerWindowClickListeners();
// disabled
//this._registerWindowClickListeners();
},
/**

View File

@@ -112,7 +112,8 @@
* is enabled, {false} - otherwise
*/
isButtonEnabled: function (name) {
return interfaceConfig.TOOLBAR_BUTTONS.indexOf(name) !== -1;
return interfaceConfig.TOOLBAR_BUTTONS.indexOf(name) !== -1
|| interfaceConfig.MAIN_TOOLBAR_BUTTONS.indexOf(name) !== -1;
},
/**
* Indicates if the setting section is enabled.

View File

@@ -3,8 +3,6 @@
import UIEvents from "../../../service/UI/UIEvents";
import UIUtil from "../util/UIUtil";
const thumbAspectRatio = 1 / 1;
const FilmStrip = {
/**
*
@@ -66,13 +64,52 @@ const FilmStrip = {
- parseInt(this.filmStrip.css('paddingRight'), 10);
},
/**
* Calculates the thumbnail size.
*/
calculateThumbnailSize () {
let availableHeight = interfaceConfig.FILM_STRIP_MAX_HEIGHT;
calculateThumbnailSize() {
let availableSizes = this.calculateAvailableSize();
let width = availableSizes.availableWidth;
let height = availableSizes.availableHeight;
let numvids = this.getThumbs(true).length;
return this.calculateThumbnailSizeFromAvailable(width, height);
},
/**
* Normalizes local and remote thumbnail ratios
*/
normalizeThumbnailRatio () {
let remoteHeightRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO_HEIGHT;
let remoteWidthRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO_WIDTH;
let localHeightRatio = interfaceConfig.LOCAL_THUMBNAIL_RATIO_HEIGHT;
let localWidthRatio = interfaceConfig.LOCAL_THUMBNAIL_RATIO_WIDTH;
let commonHeightRatio = remoteHeightRatio * localHeightRatio;
let localRatioCoefficient = localWidthRatio / localHeightRatio;
let remoteRatioCoefficient = remoteWidthRatio / remoteHeightRatio;
remoteWidthRatio = commonHeightRatio * remoteRatioCoefficient;
remoteHeightRatio = commonHeightRatio;
localWidthRatio = commonHeightRatio * localRatioCoefficient;
localHeightRatio = commonHeightRatio;
let localRatio = {
widthRatio: localWidthRatio,
heightRatio: localHeightRatio
};
let remoteRatio = {
widthRatio: remoteWidthRatio,
heightRatio: remoteHeightRatio
};
return { localRatio, remoteRatio };
},
calculateAvailableSize() {
let availableHeight = interfaceConfig.FILM_STRIP_MAX_HEIGHT;
let thumbs = this.getThumbs(true);
let numvids = thumbs.remoteThumbs.length;
let localVideoContainer = $("#localVideoContainer");
@@ -92,11 +129,10 @@ const FilmStrip = {
let availableWidth = videoAreaAvailableWidth;
// If the number of videos is 0 or undefined we don't need to calculate
// further.
if (numvids)
// If local thumb is not hidden
if(thumbs.localThumb) {
availableWidth = Math.floor(
(videoAreaAvailableWidth - numvids * (
(videoAreaAvailableWidth - (
UIUtil.parseCssInt(
localVideoContainer.css('borderLeftWidth'), 10)
+ UIUtil.parseCssInt(
@@ -109,36 +145,90 @@ const FilmStrip = {
localVideoContainer.css('marginLeft'), 10)
+ UIUtil.parseCssInt(
localVideoContainer.css('marginRight'), 10)))
/ numvids);
);
}
// If the number of videos is 0 or undefined we don't need to calculate
// further.
if (numvids) {
let remoteVideoContainer = thumbs.remoteThumbs.eq(0);
availableWidth = Math.floor(
(videoAreaAvailableWidth - numvids * (
UIUtil.parseCssInt(
remoteVideoContainer.css('borderLeftWidth'), 10)
+ UIUtil.parseCssInt(
remoteVideoContainer.css('borderRightWidth'), 10)
+ UIUtil.parseCssInt(
remoteVideoContainer.css('paddingLeft'), 10)
+ UIUtil.parseCssInt(
remoteVideoContainer.css('paddingRight'), 10)
+ UIUtil.parseCssInt(
remoteVideoContainer.css('marginLeft'), 10)
+ UIUtil.parseCssInt(
remoteVideoContainer.css('marginRight'), 10)))
);
}
let maxHeight
// If the MAX_HEIGHT property hasn't been specified
// we have the static value.
= Math.min( interfaceConfig.FILM_STRIP_MAX_HEIGHT || 120,
availableHeight);
= Math.min(interfaceConfig.FILM_STRIP_MAX_HEIGHT || 120,
availableHeight);
availableHeight
= Math.min( maxHeight, window.innerHeight - 18);
= Math.min(maxHeight, window.innerHeight - 18);
if (availableHeight < availableWidth) {
availableWidth = availableHeight;
return { availableWidth, availableHeight };
},
calculateThumbnailSizeFromAvailable(availableWidth, availableHeight) {
let { localRatio, remoteRatio } = this.normalizeThumbnailRatio();
let { remoteThumbs } = this.getThumbs(true);
let remoteProportion = remoteRatio.widthRatio * remoteThumbs.length;
let widthProportion = remoteProportion + localRatio.widthRatio;
let heightUnit = availableHeight / localRatio.heightRatio;
let widthUnit = availableWidth / widthProportion;
if (heightUnit < widthUnit) {
widthUnit = heightUnit;
}
else
availableHeight = availableWidth;
heightUnit = widthUnit;
let localVideo = {
thumbWidth: widthUnit * localRatio.widthRatio,
thumbHeight: heightUnit * localRatio.heightRatio
};
let remoteVideo = {
thumbWidth: widthUnit * remoteRatio.widthRatio,
thumbHeight: widthUnit * remoteRatio.heightRatio
};
return {
thumbWidth: availableWidth,
thumbHeight: availableHeight
localVideo,
remoteVideo
};
},
resizeThumbnails (thumbWidth, thumbHeight,
resizeThumbnails (local, remote,
animate = false, forceUpdate = false) {
return new Promise(resolve => {
this.getThumbs(!forceUpdate).animate({
height: thumbHeight,
width: thumbWidth
let thumbs = this.getThumbs(!forceUpdate);
thumbs.localThumb.animate({
height: local.thumbHeight,
width: local.thumbWidth
}, {
queue: false,
duration: animate ? 500 : 0,
complete: resolve
});
thumbs.remoteThumbs.animate({
height: remote.thumbHeight,
width: remote.thumbWidth
}, {
queue: false,
duration: animate ? 500 : 0,
@@ -147,7 +237,7 @@ const FilmStrip = {
this.filmStrip.animate({
// adds 2 px because of small video 1px border
height: thumbHeight + 2
height: remote.thumbHeight + 2
}, {
queue: false,
duration: animate ? 500 : 0
@@ -165,13 +255,19 @@ const FilmStrip = {
selector += ':visible';
}
let localThumb = $("#localVideoContainer");
let remoteThumbs = this.filmStrip.children(selector)
.not("#localVideoContainer");
// Exclude the local video container if it has been hidden.
if ($("#localVideoContainer").hasClass("hidden"))
return this.filmStrip.children(selector)
.not("#localVideoContainer");
else
return this.filmStrip.children(selector);
}
if (localThumb.hasClass("hidden")) {
return { remoteThumbs };
} else {
return { remoteThumbs, localThumb };
}
},
};
export default FilmStrip;

View File

@@ -164,11 +164,12 @@ class VideoContainer extends LargeContainer {
return getStreamOwnerId(this.stream);
}
constructor (onPlay) {
constructor (onPlay, emitter) {
super();
this.stream = null;
this.videoType = null;
this.localFlipX = true;
this.emitter = emitter;
this.isVisible = false;
@@ -327,6 +328,8 @@ class VideoContainer extends LargeContainer {
(show) ? interfaceConfig.DEFAULT_BACKGROUND : "#000");
this.$avatar.css("visibility", show ? "visible" : "hidden");
this.emitter.emit(UIEvents.LARGE_VIDEO_AVATAR_DISPLAYED, show);
}
// We are doing fadeOut/fadeIn animations on parent div which wraps
@@ -385,12 +388,12 @@ class VideoContainer extends LargeContainer {
* Manager for all Large containers.
*/
export default class LargeVideoManager {
constructor () {
constructor (emitter) {
this.containers = {};
this.state = VIDEO_CONTAINER_TYPE;
this.videoContainer = new VideoContainer(
() => this.resizeContainer(VIDEO_CONTAINER_TYPE));
() => this.resizeContainer(VIDEO_CONTAINER_TYPE), emitter);
this.addContainer(VIDEO_CONTAINER_TYPE, this.videoContainer);
// use the same video container to handle and desktop tracks

View File

@@ -11,7 +11,6 @@ function LocalVideo(VideoLayout, emitter) {
this.videoSpanId = "localVideoContainer";
this.container = $("#localVideoContainer").get(0);
this.localVideoId = null;
this.bindHoverHandler();
if(config.enableLocalVideoFlip)
this._buildContextMenu();
this.isLocal = true;
@@ -44,7 +43,7 @@ function createEditDisplayNameButton() {
editButton.className = 'displayname';
UIUtil.setTooltip(editButton,
"videothumbnail.editnickname",
"top");
"left");
editButton.innerHTML = '<i class="icon-edit"></i>';
return editButton;
@@ -72,7 +71,7 @@ LocalVideo.prototype.setDisplayName = function(displayName, key) {
if (displayName && displayName.length > 0) {
meHTML = APP.translation.generateTranslationHTML("me");
$('#localDisplayName').html(
UIUtil.escapeHtml(displayName) + ' (' + meHTML + ')'
`${UIUtil.escapeHtml(displayName)} (${meHTML})`
);
} else {
$('#localDisplayName').html(defaultLocalDisplayName);
@@ -80,11 +79,9 @@ LocalVideo.prototype.setDisplayName = function(displayName, key) {
}
this.updateView();
} else {
var editButton = createEditDisplayNameButton();
nameSpan = document.createElement('span');
nameSpan.className = 'displayname';
$('#' + this.videoSpanId)[0].appendChild(nameSpan);
document.getElementById(this.videoSpanId).appendChild(nameSpan);
if (displayName && displayName.length > 0) {
@@ -97,7 +94,6 @@ LocalVideo.prototype.setDisplayName = function(displayName, key) {
nameSpan.id = 'localDisplayName';
this.container.appendChild(editButton);
//translates popover of edit button
APP.translation.translateElement($("a.displayname"));
@@ -124,21 +120,23 @@ LocalVideo.prototype.setDisplayName = function(displayName, key) {
var self = this;
$('#localVideoContainer .displayname')
.bind("click", function (e) {
let $editDisplayName = $('#editDisplayName');
let $localDisplayName = $('#localDisplayName');
var editDisplayName = $('#editDisplayName');
e.preventDefault();
e.stopPropagation();
$('#localDisplayName').hide();
editDisplayName.show();
editDisplayName.focus();
editDisplayName.select();
$localDisplayName.hide();
$editDisplayName.show();
$editDisplayName.focus();
$editDisplayName.select();
editDisplayName.one("focusout", function (e) {
$editDisplayName.one("focusout", function (e) {
self.emitter.emit(UIEvents.NICKNAME_CHANGED, this.value);
$('#editDisplayName').hide();
$editDisplayName.hide();
$localDisplayName.show();
});
editDisplayName.on('keydown', function (e) {
$editDisplayName.on('keydown', function (e) {
if (e.keyCode === 13) {
e.preventDefault();
$('#editDisplayName').hide();

View File

@@ -17,7 +17,6 @@ function RemoteVideo(id, VideoLayout, emitter) {
this.addRemoteVideoContainer();
this.connectionIndicator = new ConnectionIndicator(this, id);
this.setDisplayName();
this.bindHoverHandler();
this.flipX = false;
this.isLocal = false;
this.isMuted = false;
@@ -34,8 +33,10 @@ RemoteVideo.prototype.addRemoteVideoContainer = function() {
if (APP.conference.isModerator) {
this.addRemoteVideoMenu();
}
let {thumbWidth, thumbHeight} = this.VideoLayout.resizeThumbnails();
AudioLevels.updateAudioLevelCanvas(this.id, thumbWidth, thumbHeight);
let { remoteVideo } = this.VideoLayout.resizeThumbnails();
let { thumbHeight, thumbWidth } = remoteVideo;
AudioLevels.createAudioLevelCanvas(this.id, thumbWidth, thumbHeight);
return this.container;
};
@@ -427,12 +428,16 @@ RemoteVideo.prototype.removeRemoteVideoMenu = function() {
};
RemoteVideo.createContainer = function (spanId) {
var container = document.createElement('span');
let container = document.createElement('span');
container.id = spanId;
container.className = 'videocontainer';
let toolbar = document.createElement('div');
toolbar.className = "videocontainer__toolbar";
container.appendChild(toolbar);
var remotes = document.getElementById('remoteVideos');
return remotes.appendChild(container);
};
export default RemoteVideo;

View File

@@ -171,26 +171,6 @@ SmallVideo.getStreamElementID = function (stream) {
return (isVideo ? 'remoteVideo_' : 'remoteAudio_') + stream.getId();
};
/**
* Configures hoverIn/hoverOut handlers.
*/
SmallVideo.prototype.bindHoverHandler = function () {
// Add hover handler
var self = this;
$(this.container).hover(
function () {
self.showDisplayName(true);
},
function () {
// If the video has been "pinned" by the user we want to
// keep the display name on place.
if (!self.VideoLayout.isLargeVideoVisible() ||
!self.VideoLayout.isCurrentlyOnLarge(self.id))
self.showDisplayName(false);
}
);
};
/**
* Updates the data for the indicator
* @param id the id of the indicator
@@ -219,6 +199,7 @@ SmallVideo.prototype.showAudioIndicator = function(isMuted) {
if (audioMutedSpan.length > 0) {
audioMutedSpan.popover('hide');
audioMutedSpan.remove();
this.updateIconPositions();
}
}
else {
@@ -230,12 +211,14 @@ SmallVideo.prototype.showAudioIndicator = function(isMuted) {
"top");
this.container.appendChild(audioMutedSpan);
APP.translation.translateElement($('#' + this.videoSpanId + " > span"));
APP.translation
.translateElement($('#' + this.videoSpanId + " > span"));
var mutedIndicator = document.createElement('i');
mutedIndicator.className = 'icon-mic-disabled';
audioMutedSpan.appendChild(mutedIndicator);
}
this.updateIconPositions();
}
this.isMuted = isMuted;
@@ -254,6 +237,7 @@ SmallVideo.prototype.setMutedView = function(isMuted) {
if (isMuted === false) {
if (videoMutedSpan.length > 0) {
videoMutedSpan.remove();
this.updateIconPositions();
}
}
else {
@@ -270,7 +254,8 @@ SmallVideo.prototype.setMutedView = function(isMuted) {
"top");
videoMutedSpan.appendChild(mutedIndicator);
//translate texts for muted indicator
APP.translation.translateElement($('#' + this.videoSpanId + " > span > i"));
APP.translation
.translateElement($('#' + this.videoSpanId + " > span > i"));
}
this.updateIconPositions();
@@ -278,13 +263,18 @@ SmallVideo.prototype.setMutedView = function(isMuted) {
};
SmallVideo.prototype.updateIconPositions = function () {
var audioMutedSpan = $('#' + this.videoSpanId + '>span.audioMuted');
var connectionIndicator = $('#' + this.videoSpanId + '>div.connectionindicator');
var videoMutedSpan = $('#' + this.videoSpanId + '>span.videoMuted');
let audioMutedSpan = $('#' + this.videoSpanId + '>span.audioMuted');
let videoMutedSpan = $('#' + this.videoSpanId + '>span.videoMuted');
audioMutedSpan.css({left: "0px"});
videoMutedSpan.css({left: (audioMutedSpan.length > 0? 25 : 0) + "px"});
var connectionIndicator
= $('#' + this.videoSpanId + '>div.connectionindicator');
if(connectionIndicator.length > 0 &&
connectionIndicator[0].style.display != "none") {
audioMutedSpan.css({right: "23px"});
videoMutedSpan.css({right: ((audioMutedSpan.length > 0? 23 : 0) + 30) + "px"});
videoMutedSpan.css({right:
((audioMutedSpan.length > 0? 23 : 0) + 30) + "px"});
} else {
audioMutedSpan.css({right: "0px"});
videoMutedSpan.css({right: (audioMutedSpan.length > 0? 30 : 0) + "px"});
@@ -317,7 +307,8 @@ SmallVideo.prototype.createModeratorIndicatorElement = function () {
"top");
//translates text in focus indicators
APP.translation.translateElement($('#' + this.videoSpanId + ' .focusindicator'));
APP.translation
.translateElement($('#' + this.videoSpanId + ' .focusindicator'));
};
/**
@@ -406,8 +397,6 @@ SmallVideo.prototype.updateView = function () {
setVisibility(video, showVideo);
}
setVisibility(avatar, showAvatar);
this.showDisplayName(!showVideo && !showAvatar);
};
SmallVideo.prototype.avatarChanged = function (avatarUrl) {
@@ -465,9 +454,8 @@ SmallVideo.prototype.showRaisedHandIndicator = function (show) {
var indicatorSpanId = "raisehandindicator";
var indicatorSpan = this.getIndicatorSpan(indicatorSpanId);
indicatorSpan.style.background = "#D6D61E";
indicatorSpan.innerHTML
= "<i id='indicatoricon' class='fa fa-hand-paper-o'></i>";
= "<i id='indicatoricon' class='icon-raised-hand'></i>";
// adds a tooltip
UIUtil.setTooltip(indicatorSpan, "raisedHand", "left");

View File

@@ -105,16 +105,16 @@ var VideoLayout = {
localVideoThumbnail.setVideoType(VIDEO_CONTAINER_TYPE);
// if we do not resize the thumbs here, if there is no video device
// the local video thumb maybe one pixel
let {thumbWidth, thumbHeight}
= this.resizeThumbnails(false, true, false);
AudioLevels.updateAudioLevelCanvas(null, thumbWidth, thumbHeight);
let { localVideo } = this.resizeThumbnails(false, true);
AudioLevels.createAudioLevelCanvas(
"local", localVideo.thumbWidth, localVideo.thumbHeight);
emitter.addListener(UIEvents.CONTACT_CLICKED, onContactClicked);
this.lastNCount = config.channelLastN;
},
initLargeVideo () {
largeVideo = new LargeVideoManager();
largeVideo = new LargeVideoManager(eventEmitter);
if(localFlipX) {
largeVideo.onLocalFlipXChange(localFlipX);
}
@@ -255,7 +255,8 @@ var VideoLayout = {
electLastVisibleVideo () {
// pick the last visible video in the row
// if nobody else is left, this picks the local video
let thumbs = FilmStrip.getThumbs(true).filter('[id!="mixedstream"]');
let remoteThumbs = FilmStrip.getThumbs(true).remoteThumbs;
let thumbs = remoteThumbs.filter('[id!="mixedstream"]');
let lastVisible = thumbs.filter(':visible:last');
if (lastVisible.length) {
@@ -269,7 +270,7 @@ var VideoLayout = {
}
console.info("Last visible video no longer exists");
thumbs = FilmStrip.getThumbs();
thumbs = FilmStrip.getThumbs().remoteThumbs;
if (thumbs.length) {
let id = getPeerContainerResourceId(thumbs[0]);
if (remoteVideos[id]) {
@@ -402,7 +403,7 @@ var VideoLayout = {
// In case this is not currently in the last n we don't show it.
if (localLastNCount && localLastNCount > 0 &&
FilmStrip.getThumbs().length >= localLastNCount + 2) {
FilmStrip.getThumbs().remoteThumbs.length >= localLastNCount + 2) {
remoteVideo.showPeerContainer('hide');
} else {
VideoLayout.resizeThumbnails(false, true);
@@ -414,7 +415,7 @@ var VideoLayout = {
console.info(resourceJid + " video is now active", videoelem);
VideoLayout.resizeThumbnails(
false, false, false, function() {$(videoelem).show();});
false, false, function() {$(videoelem).show();});
// Update the large video to the last added video only if there's no
// current dominant, focused speaker or update it to
@@ -487,19 +488,19 @@ var VideoLayout = {
forceUpdate = false,
onComplete = null) {
let {thumbWidth, thumbHeight}
let { localVideo, remoteVideo }
= FilmStrip.calculateThumbnailSize();
$('.userAvatar').css('left', (thumbWidth - thumbHeight) / 2);
let {thumbWidth, thumbHeight} = remoteVideo;
FilmStrip.resizeThumbnails(thumbWidth, thumbHeight,
FilmStrip.resizeThumbnails(localVideo, remoteVideo,
animate, forceUpdate)
.then(function () {
AudioLevels.updateCanvasSize(thumbWidth, thumbHeight);
AudioLevels.updateCanvasSize(localVideo, remoteVideo);
if (onComplete && typeof onComplete === "function")
onComplete();
});
return {thumbWidth, thumbHeight};
});
return { localVideo, remoteVideo };
},
/**
@@ -657,7 +658,7 @@ var VideoLayout = {
var updateLargeVideo = false;
// Handle LastN/local LastN changes.
FilmStrip.getThumbs().each(( index, element ) => {
FilmStrip.getThumbs().remoteThumbs.each(( index, element ) => {
var resourceJid = getPeerContainerResourceId(element);
var smallVideo = remoteVideos[resourceJid];

View File

@@ -17,11 +17,6 @@ function initGlobalShortcuts() {
APP.UI.toggleKeyboardShortcutsPanel();
}, "keyboardShortcuts.toggleShortcuts");
KeyboardShortcut.registerShortcut("R", null, function() {
JitsiMeetJS.analytics.sendEvent("shortcut.raisedhand.toggled");
APP.conference.maybeToggleRaisedHand();
}, "keyboardShortcuts.raiseHand");
KeyboardShortcut.registerShortcut("T", null, function() {
JitsiMeetJS.analytics.sendEvent("shortcut.talk.clicked");
APP.conference.muteAudio(true);

View File

@@ -21,18 +21,18 @@
"bootstrap": "3.1.1",
"events": "*",
"i18next-client": "1.7.7",
"jquery": "~2.1.1",
"jQuery-Impromptu": "git+https://github.com/trentrichardson/jQuery-Impromptu.git#v6.0.0",
"lib-jitsi-meet": "git+https://github.com/jitsi/lib-jitsi-meet.git",
"jquery": "~2.1.1",
"jquery-contextmenu": "*",
"jquery-ui": "1.10.5",
"jssha": "1.5.0",
"jws": "*",
"lib-jitsi-meet": "git+https://github.com/jitsi/lib-jitsi-meet.git",
"postis": "^2.2.0",
"retry": "0.6.1",
"strophe": "^1.2.2",
"strophejs-plugins": "^0.0.6",
"toastr": "^2.0.3",
"postis": "^2.2.0",
"jws": "*"
"toastr": "^2.0.3"
},
"devDependencies": {
"babel-polyfill": "*",

View File

@@ -105,5 +105,10 @@ export default {
* event must contain the identifier of the container that has been toggled
* and information about toggle on or off.
*/
SIDE_TOOLBAR_CONTAINER_TOGGLED: "UI.side_container_toggled"
SIDE_TOOLBAR_CONTAINER_TOGGLED: "UI.side_container_toggled",
/**
* Notifies that the avatar is displayed or not on the largeVideo.
*/
LARGE_VIDEO_AVATAR_DISPLAYED: "UI.large_video_avatar_displayed"
};