feat(connection-indicator): implement automatic hiding on good connection (#2009)

* ref(connection-stats): use PropTypes package

* feat(connection-stats): display a summary of the connection quality

* feat(connection-indicator): show empty bars for interrupted connection

* feat(connection-indicator): change background color based on status

* feat(connection-indicator): implement automatic hiding on good connection

* fix(connection-indicator): explicitly set font size

Currently non-react code will set an icon size on ConnectionIndicator.
This doesn't work on initial call join in vertical filmstrip after
some changes to support hiding the indicator. The chosen fix is
passing in the icon size to mirror what would happe with full
filmstrip reactification.

* ref(connection-stats): rename statuses

* feat(connection-indicator): make hiding behavior configurable

The original implementation made the auto hiding of the indicator
configured in interfaceConfig.

* fix(connection-indicator): readd class expected by torture tests

* fix(connection-indicator): change connection quality display styling

Bold the connection summary in the stats popover so it stands out.
Change the summaries so there are only three--strong, nonoptimal,
poor.

* fix(connection-indicator): gray background on lost connection

* feat(icons): add new gsm bars icon

* feat(connection-indicator): use new 3-bar icon

* ref(icons): remove icon-connection and icon-connection-lost

Both have been replaced by icon-gsm-bars so they are not
being referenced anymore. Mobile looks to have connect-lost
as a separate icon in font-icons/jitsi.json.
This commit is contained in:
virtuacoplenny 2017-09-26 09:55:09 -07:00 committed by yanas
parent e08d240a89
commit 483e2ee202
13 changed files with 403 additions and 261 deletions

View File

@ -37,6 +37,11 @@
color: $downloadConnectionIconColor;
}
&__status
{
font-weight: bold;
}
&__upload
{
@extend .connection-info__icon;

View File

@ -127,12 +127,6 @@
.icon-volume:before {
content: "\e91a";
}
.icon-connection-lost:before {
content: "\e900";
}
.icon-connection:before {
content: "\e61a";
}
.icon-recDisable:before {
content: "\e613";
}
@ -160,3 +154,6 @@
.icon-info:before {
content: "\e922";
}
.icon-gsm-bars:before {
content: "\e926";
}

View File

@ -87,6 +87,7 @@
* positioning depends on the trigger (indicator icon).
*/
.indicator {
margin-left: 5px;
margin-top: $toolbarIconMargin;
}
@ -94,16 +95,6 @@
margin-left: $toolbarIconMargin;
}
.connection-indicator,
div.indicator-container,
{
margin-right: 4px;
}
div.indicator:last-child {
margin-right: 0;
}
.indicator-container {
display: inline-block;
vertical-align: top;
@ -138,18 +129,13 @@
left: 0;
@include transform(translate(0, -50%));
&_empty
&_empty,
&_lost
{
color: #8B8B8B;/*#FFFFFF*/
overflow: hidden;
}
&_lost
{
color: #8B8B8B;
overflow: visible;
}
&_full
{
@include topLeft();
@ -163,12 +149,15 @@
}
}
.icon-connection,
.icon-connection-lost {
.icon-gsm-bars {
cursor: pointer;
font-size: 1em;
}
}
.hide-connection-indicator {
display: none;
}
}
&__hoverOverlay {
@ -355,7 +344,27 @@
}
.connection-indicator {
background: $connectionIndicatorBg;
background: $connectionIndicatorBg;
&.status-high {
background: green;
}
&.status-med {
background: #FFD740;
}
&.status-lost {
background: gray;
}
&.status-low {
background: #BF2117;
}
&.status-other {
background: $connectionIndicatorBg;
}
}
.remote-video-menu-trigger,

Binary file not shown.

View File

@ -13,8 +13,6 @@
<glyph unicode="&#xe603;" glyph-name="presentation" horiz-adv-x="1088" d="M952.495 1019.065h-818.689c-72.81 0-132.183-60.63-132.183-135.162v-750.719c0-74.473 59.372-135.101 132.183-135.101h818.686c72.936 0 132.314 60.625 132.314 135.101v750.722c0.003 74.532-59.378 135.159-132.311 135.159zM946.346 139.651h-806.14v737.822h806.015l0.126-737.822zM685.753 738.544h216.911v-566.758h-216.911v566.758zM428.672 610.002h216.911v-438.216h-216.911v438.216zM172.339 481.46h216.161v-309.677h-216.161v309.677z" />
<glyph unicode="&#xe613;" glyph-name="recDisable" horiz-adv-x="1140" d="M1123.444 1003.015c-23.593 26.481-64.131 28.989-90.74 5.395l-1008.269-893.436c-26.609-23.468-28.991-64.131-5.46-90.676 12.674-14.306 30.308-21.649 48.126-21.649 15.123 0 30.372 5.401 42.544 16.195l130.045 115.22c90.743-81.844 210.569-132.165 342.473-132.101 282.816 0.061 510.913 227.969 511.287 510.972 0.126 109.934-34.682 211.367-93.499 294.72l118.088 104.625c26.483 23.526 28.997 64.129 5.404 90.735zM944.422 513.818c0.128-200.922-161.896-363.201-362.509-362.952-87.56 0.123-167.573 31.151-230.061 82.569l331.277 293.509v-73.176c1.071-60.993 32.696-92.18 94.944-93.692 61.997 1.512 93.686 32.763 95.131 93.756v41.096h-72.227v-47.499c0.251-4.642-0.564-10.607-2.511-17.949-1.25-3.261-3.448-6.020-6.525-8.093-3.197-2.572-7.845-3.828-13.868-3.828-10.543 0.31-17.132 4.268-19.827 11.921-1.068 3.512-1.947 6.905-2.508 10.163-0.254 2.887-0.377 5.532-0.377 7.786v143.511l42.477 37.634c0.215-0.432 0.452-0.851 0.63-1.303 1.947-6.467 2.762-12.799 2.511-19.076v-36.772h72.227v30.121c-0.246 31.245-9.086 54.699-26.363 70.447l40.711 36.069c35.787-56.055 56.803-122.585 56.867-194.244zM239.795 395.47c-12.613 37.023-19.827 76.557-19.827 117.913-0.19 200.236 161.584 362.009 361.945 362.135 56.853 0 110.313-13.302 158.133-36.398l117.846 104.421c-79.444 50.952-173.758 80.817-275.292 80.948-283.377 0.181-511.354-227.729-511.789-511.675-0.126-79.567 18.636-154.679 51.137-221.882l117.848 104.538zM388.576 690.020h-97.514v-249.057l72.23 64.070v0.689h0.815l117.72 104.418c0 0.564 0.123 0.94 0.123 1.509 0.753 53.898-30.369 80.069-93.374 78.37zM405.959 625.517c1.942-2.767 3.074-6.469 3.323-11.112 0.312-4.452 0.438-9.6 0.438-15.246 0.251-10.916-0.689-19.83-2.949-26.985-2.952-7.594-10.983-11.357-24.159-11.357h-19.325v74.043h15.31c7.842 0 13.865-0.683 18.072-2.19 4.397-1.573 7.468-3.953 9.29-7.153z" />
<glyph unicode="&#xe614;" glyph-name="recEnable" horiz-adv-x="1142" d="M581.278 1025.708c284.857-0.19 514.807-230.517 514.427-514.997-0.378-285.047-230.073-514.553-514.869-514.615-284.541-0.062-515.311 230.517-514.933 514.422 0.439 285.936 230.009 515.439 515.375 515.19zM580.579 875.756c-201.764-0.123-364.666-163.032-364.478-364.663 0-202.018 162.524-364.735 364.478-364.984 202.018-0.316 365.174 163.030 365.048 365.423-0.252 201.767-163.156 364.35-365.048 364.224zM287.698 688.907h98.196c63.442 1.767 94.785-24.518 94.027-78.863 0.254-19.081-2.211-34.882-7.456-47.521-6.005-12.508-18.706-21.988-38.167-28.181v-0.819c28.373-6.259 43.031-23.573 43.981-51.946v-57.689c0-11.247 0.254-22.813 0.758-34.756 0.819-12.005 3.033-20.979 6.696-27.043h-71.846c-3.727 6.064-6.128 15.038-7.14 27.043-1.012 11.943-1.454 23.509-1.138 34.756v52.321c0 9.603-2.214 16.553-6.573 20.979-4.675 4.107-12.701 6.19-24.012 6.19h-14.599v-141.291h-72.73v326.82zM360.428 558.861h19.463c13.271 0 21.359 3.794 24.331 11.375 2.276 7.204 3.221 16.304 2.969 27.171 0 5.815-0.126 10.867-0.442 15.418-0.252 4.675-1.392 8.404-3.352 11.247-1.831 3.157-4.926 5.561-9.352 7.14-4.233 1.454-10.299 2.211-18.2 2.211h-15.418v-74.564zM498.372 688.907h162.082v-62.687h-89.35v-65.587h78.103v-62.685h-78.103v-73.11h92.822v-62.749h-165.557v326.818zM682.507 599.999c0.316 31.782 9.416 55.542 27.425 71.407 17.44 15.29 40.185 22.936 68.181 22.936 28.247 0 51.119-7.646 68.623-23 17.82-15.798 26.92-39.623 27.171-71.407v-30.333h-72.73v37.031c0.254 6.192-0.57 12.639-2.527 19.209-1.264 3.157-3.475 5.938-6.573 8.214-3.221 1.515-7.898 2.404-13.964 2.404-10.615-0.316-17.249-3.855-19.967-10.618-2.211-6.573-3.223-13.017-2.907-19.209v-161.956c0-2.273 0.126-4.865 0.38-7.772 0.568-3.411 1.454-6.824 2.527-10.233 2.717-7.775 9.352-11.756 19.967-12.007 6.067 0 10.744 1.261 13.964 3.791 3.098 2.15 5.309 4.867 6.573 8.216 1.96 7.33 2.782 13.33 2.527 18.007v47.837h72.73v-41.328c-1.451-61.547-33.364-93.015-95.794-94.469-62.685 1.454-94.53 32.922-95.607 94.343v148.937z" />
<glyph unicode="&#xe61a;" glyph-name="connection" horiz-adv-x="1444" d="M3.881 210.835h220.26v-210.835h-220.26v210.835zM308.817 414.143h220.27v-414.143h-220.27v414.143zM613.764 617.412h220.268v-617.412h-220.268v617.412zM918.685 820.715h220.265v-820.715h-220.265v820.715zM1223.629 1024h220.263v-1024h-220.263v1024z" />
<glyph unicode="&#xe900;" glyph-name="connection-lost" horiz-adv-x="1414" d="M0 299.153h196.337v-187.951h-196.337v187.951zM271.842 480.372h196.337v-369.169h-196.337v369.169zM543.656 661.562h196.337v-550.36h-196.337v550.36zM815.47 842.766v-731.564h119.56c-14.589 33.025-23.125 71.503-23.232 111.943 0.132 86.42 38.697 163.851 99.656 216.468l0.348 403.153h-196.332zM1087.292 1024v-533.672c28.874 10.572 62.222 16.73 97.009 16.825 35.717-0.129 69.823-6.614 101.322-18.371l-1.999 535.218h-196.332zM1192.868 439.852c-0.009 0-0.020 0-0.031 0-122.247 0-221.351-98.447-221.372-219.896 0-0.007 0-0.014 0-0.021 0-121.467 99.111-219.935 221.372-219.935 0.011 0 0.021 0 0.032 0 122.248 0.014 221.345 98.477 221.345 219.935 0 0.007 0 0.013 0 0.020-0.021 121.441-99.11 219.883-221.345 219.897zM1194.706 372.607c87.601-0.006 158.614-69.787 158.614-155.866 0-0.006 0-0.012 0-0.019-0.022-86.062-71.026-155.822-158.614-155.828-87.588 0.006-158.593 69.766-158.615 155.826 0 0.007 0 0.014 0 0.020 0 86.079 71.013 155.86 158.613 155.866zM1286.795 355.682l48.348-52.528-236.375-217.567-48.348 52.528 236.375 217.567z" />
<glyph unicode="&#xe901;" glyph-name="avatar" d="M512 204c106 0 200 56 256 138-2 84-172 132-256 132-86 0-254-48-256-132 56-82 150-138 256-138zM512 810c-70 0-128-58-128-128s58-128 128-128 128 58 128 128-58 128-128 128zM512 938c236 0 426-190 426-426s-190-426-426-426-426 190-426 426 190 426 426 426z" />
<glyph unicode="&#xe902;" glyph-name="download" d="M726 470h-128v170h-172v-170h-128l214-214zM826 596c110-8 198-100 198-212 0-118-96-214-214-214h-554c-142 0-256 114-256 256 0 132 100 240 228 254 54 102 160 174 284 174 156 0 284-110 314-258z" />
<glyph unicode="&#xe903;" glyph-name="mic-camera-combined" d="M756.704 628.138l267.296 202.213v-635.075l-267.296 202.213v-191.923c0-12.085-11.296-21.863-25.216-21.863h-706.272c-13.92 0-25.216 9.777-25.216 21.863v612.25c0 12.085 11.296 21.863 25.216 21.863h706.272c13.92 0 25.216-9.777 25.216-21.863v-189.679zM371.338 376.228c47.817 0 86.529 40.232 86.529 89.811v184.835c0 49.651-38.713 89.883-86.529 89.883-47.788 0-86.515-40.232-86.515-89.883v-184.835c0-49.579 38.756-89.811 86.515-89.811v0zM356.754 314.070v-32.78h33.718v33.412c73.858 9.606 131.235 73.73 131.235 151.351v88.232h-30.636v-88.232c0-67.57-53.696-122.534-119.734-122.534-66.024 0-119.691 54.964-119.691 122.534v88.232h-30.636v-88.232c0-79.215 59.674-144.502 135.744-151.969v-0.014z" />
@ -52,4 +50,5 @@
<glyph unicode="&#xe923;" glyph-name="visibility" d="M512 640c70 0 128-58 128-128s-58-128-128-128-128 58-128 128 58 128 128 128zM512 298c118 0 214 96 214 214s-96 214-214 214-214-96-214-214 96-214 214-214zM512 832c214 0 396-132 470-320-74-188-256-320-470-320s-396 132-470 320c74 188 256 320 470 320z" />
<glyph unicode="&#xe924;" glyph-name="visibility-off" d="M506 640h6c70 0 128-58 128-128v-8zM322 606c-14-28-24-60-24-94 0-118 96-214 214-214 34 0 66 10 94 24l-66 66c-8-2-18-4-28-4-70 0-128 58-128 128 0 10 2 20 4 28zM86 842l54 54 756-756-54-54c-47.968 47.365-96.266 94.401-144 142-58-24-120-36-186-36-214 0-396 132-470 320 34 84 90 156 160 212-39.017 38.983-77.307 78.693-116 118zM512 726c-28 0-54-6-78-16l-92 92c52 20 110 30 170 30 214 0 394-132 468-320-32-80-82-148-146-202l-124 124c10 24 16 50 16 78 0 118-96 214-214 214z" />
<glyph unicode="&#xe925;" glyph-name="dialpad" d="M512 982c46 0 86-40 86-86s-40-86-86-86-86 40-86 86 40 86 86 86zM512 726c46 0 86-40 86-86s-40-86-86-86-86 40-86 86 40 86 86 86zM768 726c46 0 86-40 86-86s-40-86-86-86-86 40-86 86 40 86 86 86zM768 470c46 0 86-40 86-86s-40-86-86-86-86 40-86 86 40 86 86 86zM512 470c46 0 86-40 86-86s-40-86-86-86-86 40-86 86 40 86 86 86zM768 810c-46 0-86 40-86 86s40 86 86 86 86-40 86-86-40-86-86-86zM256 470c46 0 86-40 86-86s-40-86-86-86-86 40-86 86 40 86 86 86zM256 726c46 0 86-40 86-86s-40-86-86-86-86 40-86 86 40 86 86 86zM256 982c46 0 86-40 86-86s-40-86-86-86-86 40-86 86 40 86 86 86zM512 214c46 0 86-40 86-86s-40-86-86-86-86 40-86 86 40 86 86 86z" />
<glyph unicode="&#xe926;" glyph-name="gsm-bars-black" d="M896 1024c70.692 0 128-57.308 128-128v-768c0-70.692-57.308-128-128-128s-128 57.308-128 128v768c0 70.692 57.308 128 128 128zM512 768c70.692 0 128-57.308 128-128v-512c0-70.692-57.308-128-128-128s-128 57.308-128 128v512c0 70.692 57.308 128 128 128zM128 384v0c70.692 0 128-57.308 128-128v-128c0-70.692-57.308-128-128-128s-128 57.308-128 128v128c0 70.692 57.308 128 128 128v0z" />
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,35 @@
{
"IcoMoonType": "selection",
"icons": [
{
"icon": {
"paths": [
"M896 0c70.692 0 128 57.308 128 128v768c0 70.692-57.308 128-128 128s-128-57.308-128-128v-768c0-70.692 57.308-128 128-128zM512 256c70.692 0 128 57.308 128 128v512c0 70.692-57.308 128-128 128s-128-57.308-128-128v-512c0-70.692 57.308-128 128-128zM128 640v0c70.692 0 128 57.308 128 128v128c0 70.692-57.308 128-128 128s-128-57.308-128-128v-128c0-70.692 57.308-128 128-128v0z"
],
"attrs": [
{}
],
"isMulticolor": false,
"isMulticolor2": false,
"grid": 0,
"tags": [
"gsm-bars-black"
]
},
"attrs": [
{}
],
"properties": {
"order": 901,
"id": 0,
"name": "gsm-bars-black",
"prevSize": 32,
"code": 59686
},
"setIdx": 0,
"setId": 1,
"iconIdx": 0
},
{
"icon": {
"paths": [
@ -28,7 +57,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 0
"iconIdx": 1
},
{
"icon": {
@ -57,7 +86,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 1
"iconIdx": 2
},
{
"icon": {
@ -86,7 +115,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 2
"iconIdx": 3
},
{
"icon": {
@ -115,7 +144,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 3
"iconIdx": 4
},
{
"icon": {
@ -141,7 +170,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 4
"iconIdx": 5
},
{
"icon": {
@ -167,7 +196,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 5
"iconIdx": 6
},
{
"icon": {
@ -193,7 +222,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 6
"iconIdx": 7
},
{
"icon": {
@ -219,7 +248,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 7
"iconIdx": 8
},
{
"icon": {
@ -245,7 +274,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 8
"iconIdx": 9
},
{
"icon": {
@ -271,7 +300,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 9
"iconIdx": 10
},
{
"icon": {
@ -297,7 +326,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 10
"iconIdx": 11
},
{
"icon": {
@ -323,7 +352,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 11
"iconIdx": 12
},
{
"icon": {
@ -349,7 +378,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 12
"iconIdx": 13
},
{
"icon": {
@ -375,7 +404,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 13
"iconIdx": 14
},
{
"icon": {
@ -401,7 +430,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 14
"iconIdx": 15
},
{
"icon": {
@ -427,7 +456,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 15
"iconIdx": 16
},
{
"icon": {
@ -453,7 +482,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 16
"iconIdx": 17
},
{
"icon": {
@ -479,7 +508,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 17
"iconIdx": 18
},
{
"icon": {
@ -505,7 +534,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 18
"iconIdx": 19
},
{
"icon": {
@ -531,7 +560,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 19
"iconIdx": 20
},
{
"icon": {
@ -557,7 +586,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 20
"iconIdx": 21
},
{
"icon": {
@ -583,7 +612,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 21
"iconIdx": 22
},
{
"icon": {
@ -609,7 +638,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 22
"iconIdx": 23
},
{
"icon": {
@ -635,7 +664,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 23
"iconIdx": 24
},
{
"icon": {
@ -661,7 +690,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 24
"iconIdx": 25
},
{
"icon": {
@ -687,7 +716,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 25
"iconIdx": 26
},
{
"icon": {
@ -713,7 +742,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 26
"iconIdx": 27
},
{
"icon": {
@ -739,7 +768,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 27
"iconIdx": 28
},
{
"icon": {
@ -765,7 +794,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 28
"iconIdx": 29
},
{
"icon": {
@ -791,7 +820,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 29
"iconIdx": 30
},
{
"icon": {
@ -817,7 +846,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 30
"iconIdx": 31
},
{
"icon": {
@ -843,7 +872,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 31
"iconIdx": 32
},
{
"icon": {
@ -869,129 +898,8 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 32
},
{
"icon": {
"paths": [
"M-0 724.847h196.337v187.951h-196.337v-187.951z",
"M271.842 543.628h196.337v369.169h-196.337v-369.169z",
"M543.656 362.438h196.337v550.36h-196.337v-550.36z",
"M815.47 181.234v731.564h119.56c-14.589-33.025-23.125-71.503-23.232-111.943 0.132-86.42 38.697-163.851 99.656-216.468l0.348-403.153h-196.332z",
"M1087.292-0v533.672c28.874-10.572 62.222-16.73 97.009-16.825 35.717 0.129 69.823 6.614 101.322 18.371l-1.999-535.218h-196.332z",
"M1192.868 584.148c-0.009-0-0.020-0-0.031-0-122.247 0-221.351 98.447-221.372 219.896-0 0.007-0 0.014-0 0.021 0 121.467 99.111 219.935 221.372 219.935 0.011 0 0.021-0 0.032-0 122.248-0.014 221.345-98.477 221.345-219.935 0-0.007-0-0.013-0-0.020-0.021-121.441-99.11-219.883-221.345-219.897zM1194.706 651.393c87.601 0.006 158.614 69.787 158.614 155.866 0 0.006-0 0.012-0 0.019-0.022 86.062-71.026 155.822-158.614 155.828-87.588-0.006-158.593-69.766-158.615-155.826-0-0.007-0-0.014-0-0.020 0-86.079 71.013-155.86 158.613-155.866z",
"M1286.795 668.318l48.348 52.528-236.375 217.567-48.348-52.528 236.375-217.567z"
],
"width": 1414,
"attrs": [
{},
{},
{},
{},
{},
{},
{}
],
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"connection-lost"
],
"grid": 0
},
"attrs": [
{},
{},
{},
{},
{},
{},
{}
],
"properties": {
"order": 888,
"id": 32,
"name": "connection-lost",
"prevSize": 32,
"code": 59648
},
"setIdx": 0,
"setId": 1,
"iconIdx": 33
},
{
"icon": {
"paths": [
"M3.881 813.165h220.26v210.835h-220.26v-210.835z",
"M308.817 609.857h220.27v414.143h-220.27v-414.143z",
"M613.764 406.588h220.268v617.412h-220.268v-617.412z",
"M918.685 203.285h220.265v820.715h-220.265v-820.715z",
"M1223.629 0h220.263v1024h-220.263v-1024z"
],
"width": 1444,
"attrs": [
{
"opacity": 1,
"visibility": false
},
{
"opacity": 1,
"visibility": false
},
{
"opacity": 1,
"visibility": false
},
{
"opacity": 1,
"visibility": false
},
{
"opacity": 1,
"visibility": false
}
],
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"connection-2"
],
"grid": 0
},
"attrs": [
{
"opacity": 1,
"visibility": false
},
{
"opacity": 1,
"visibility": false
},
{
"opacity": 1,
"visibility": false
},
{
"opacity": 1,
"visibility": false
},
{
"opacity": 1,
"visibility": false
}
],
"properties": {
"order": 889,
"id": 33,
"prevSize": 32,
"code": 58906,
"name": "connection",
"ligatures": ""
},
"setIdx": 0,
"setId": 1,
"iconIdx": 34
},
{
"icon": {
"paths": [
@ -1019,7 +927,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 35
"iconIdx": 36
},
{
"icon": {
@ -1049,7 +957,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 36
"iconIdx": 37
},
{
"icon": {
@ -1079,7 +987,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 37
"iconIdx": 38
},
{
"icon": {
@ -1105,7 +1013,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 38
"iconIdx": 39
},
{
"icon": {
@ -1131,7 +1039,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 39
"iconIdx": 40
},
{
"icon": {
@ -1157,7 +1065,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 40
"iconIdx": 41
},
{
"icon": {
@ -1184,7 +1092,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 41
"iconIdx": 42
},
{
"icon": {
@ -1213,7 +1121,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 42
"iconIdx": 43
},
{
"icon": {
@ -1240,7 +1148,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 43
"iconIdx": 44
},
{
"icon": {
@ -1267,7 +1175,7 @@
},
"setIdx": 0,
"setId": 1,
"iconIdx": 44
"iconIdx": 45
}
],
"height": 1024,

View File

@ -98,11 +98,30 @@ var interfaceConfig = { // eslint-disable-line no-unused-vars
*
* @type {number}
*/
MAXIMUM_ZOOMING_COEFFICIENT: 1.3
MAXIMUM_ZOOMING_COEFFICIENT: 1.3,
/*
* If indicated some of the error dialogs may point to the support URL for
* help.
*/
// SUPPORT_URL: ""
// SUPPORT_URL: "",
/**
* Whether the connection indicator icon should hide itself based on
* connection strength. If true, the connection indicator will remain
* displayed while the participant has a weak connection and will hide
* itself after the CONNECTION_INDICATOR_HIDE_TIMEOUT when the connection is
* strong.
*
* @type {boolean}
*/
CONNECTION_INDICATOR_AUTO_HIDE_ENABLED: false,
/**
* How long the connection indicator should remain displayed before hiding.
* Used in conjunction with CONNECTION_INDICATOR_AUTOHIDE_ENABLED.
*
* @type {number}
*/
CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT: 5000
};

View File

@ -200,7 +200,15 @@
"bandwidth": "Estimated bandwidth:",
"na": "Come back here for connection information once the conference starts",
"peer_to_peer": " (p2p)",
"turn": " (turn)"
"turn": " (turn)",
"quality": {
"good": "Good",
"inactive": "Inactive",
"lost": "Lost",
"nonoptimal": "Nonoptimal",
"poor": "Poor"
},
"status": "Connection:"
},
"notify": {
"disconnected": "disconnected",

View File

@ -253,10 +253,12 @@ SmallVideo.prototype.bindHoverHandler = function () {
() => {
this.videoIsHovered = true;
this.updateView();
this.updateIndicators();
},
() => {
this.videoIsHovered = false;
this.updateView();
this.updateIndicators();
}
);
};
@ -755,6 +757,8 @@ SmallVideo.prototype.updateIndicators = function () {
= this.container.querySelector('.videocontainer__toptoolbar');
const iconSize = UIUtil.getIndicatorFontSize();
const showConnectionIndicator = this.videoIsHovered
|| !interfaceConfig.CONNECTION_INDICATOR_AUTO_HIDE_ENABLED;
const tooltipPosition = interfaceConfig.VERTICAL_FILMSTRIP ? 'left' : 'top';
/* jshint ignore:start */
@ -763,7 +767,9 @@ SmallVideo.prototype.updateIndicators = function () {
<div>
{ this._showConnectionIndicator
? <ConnectionIndicator
alwaysVisible = { showConnectionIndicator }
connectionStatus = { this._connectionStatus }
iconSize = { iconSize }
isLocalVideo = { this.isLocal }
enableStatsDisplay = { !interfaceConfig.filmStripOnly }
statsPopoverPosition = { this.statsPopoverLocation }

View File

@ -1,48 +1,57 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { translate } from '../../base/i18n';
import { JitsiParticipantConnectionStatus } from '../../base/lib-jitsi-meet';
import { Popover } from '../../base/popover';
import { ConnectionStatsTable } from '../../connection-stats';
import statsEmitter from '../statsEmitter';
declare var $: Object;
declare var interfaceConfig: Object;
// Converts the percent for connection quality into a string recognized for CSS.
/**
* The connection quality percentage that must be reached to be considered of
* good quality and can result in the connection indicator being hidden.
*
* @type {number}
*/
const INDICATOR_DISPLAY_THRESHOLD = 70;
/**
* An array of display configurations for the connection indicator and its bars.
* The ordering is done specifically for faster iteration to find a matching
* configuration to the current connection strength percentage.
*
* @type {Object[]}
*/
const QUALITY_TO_WIDTH = [
// Full (5 bars)
// Full (3 bars)
{
percent: 80,
colorClass: 'status-high',
percent: INDICATOR_DISPLAY_THRESHOLD,
tip: 'connectionindicator.quality.good',
width: '100%'
},
// 4 bars
{
percent: 60,
width: '80%'
},
// 3 bars
{
percent: 40,
width: '55%'
},
// 2 bars
{
percent: 20,
width: '40%'
colorClass: 'status-med',
percent: 40,
tip: 'connectionindicator.quality.nonoptimal',
width: '66%'
},
// 1 bar
{
colorClass: 'status-low',
percent: 0,
width: '20%'
tip: 'connectionindicator.quality.poor',
width: '33%'
}
// Note: we never show 0 bars.
// Note: we never show 0 bars as long as there is a connection.
];
/**
@ -58,41 +67,52 @@ class ConnectionIndicator extends Component {
* @static
*/
static propTypes = {
/**
* Whether or not the component should ignore setting a visibility class
* for hiding the component when the connection quality is not strong.
*/
alwaysVisible: PropTypes.bool,
/**
* The current condition of the user's connection, matching one of the
* enumerated values in the library.
*
* @type {JitsiParticipantConnectionStatus}
*/
connectionStatus: React.PropTypes.string,
connectionStatus: PropTypes.string,
/**
* Whether or not clicking the indicator should display a popover for
* more details.
*/
enableStatsDisplay: React.PropTypes.bool,
enableStatsDisplay: PropTypes.bool,
/**
* The font-size for the icon.
*/
iconSize: PropTypes.number,
/**
* Whether or not the displays stats are for local video.
*/
isLocalVideo: React.PropTypes.bool,
isLocalVideo: PropTypes.bool,
/**
* Relative to the icon from where the popover for more connection
* details should display.
*/
statsPopoverPosition: React.PropTypes.string,
statsPopoverPosition: PropTypes.string,
/**
* Invoked to obtain translated strings.
*/
t: React.PropTypes.func,
t: PropTypes.func,
/**
* The user ID associated with the displayed connection indication and
* stats.
*/
userID: React.PropTypes.string
userID: PropTypes.string
};
/**
@ -105,6 +125,23 @@ class ConnectionIndicator extends Component {
super(props);
this.state = {
/**
* The timeout for automatically hiding the indicator.
*
* @type {timeoutID}
*/
autoHideTimeout: null,
/**
* Whether or not a CSS class should be applied to the root for
* hiding the connection indicator. By default the indicator should
* start out hidden because the current connection status is not
* known at mount.
*
* @type {boolean}
*/
showIndicator: false,
/**
* Whether or not the popover content should display additional
* statistics.
@ -154,7 +191,8 @@ class ConnectionIndicator extends Component {
}
/**
* Sets the state to hide the Statistics Table popover.
* Cleans up any queued processes, which includes listening for new stats
* and clearing any timeout to hide the indicator.
*
* @private
* @returns {void}
@ -162,6 +200,8 @@ class ConnectionIndicator extends Component {
componentWillUnmount() {
statsEmitter.unsubscribeToClientStats(
this.props.userID, this._onStatsUpdated);
clearTimeout(this.state.autoHideTimeout);
}
/**
@ -171,13 +211,22 @@ class ConnectionIndicator extends Component {
* @returns {ReactElement}
*/
render() {
const visibilityClass = this._getVisibilityClass();
const rootClassNames = `indicator-container ${visibilityClass}`;
const colorClass = this._getConnectionColorClass();
const indicatorContainerClassNames
= `connection-indicator indicator ${colorClass}`;
return (
<Popover
className = 'indicator-container'
className = { rootClassNames }
content = { this._renderStatisticsTable() }
position = { this.props.statsPopoverPosition }>
<div className = 'popover-trigger'>
<div className = 'connection-indicator indicator'>
<div
className = { indicatorContainerClassNames }
style = {{ fontSize: this.props.iconSize }}>
<div className = 'connection indicatoricon'>
{ this._renderIcon() }
</div>
@ -187,6 +236,83 @@ class ConnectionIndicator extends Component {
);
}
/**
* Returns a CSS class that interprets the current connection status as a
* color.
*
* @private
* @returns {string}
*/
_getConnectionColorClass() {
const { connectionStatus } = this.props;
const { percent } = this.state.stats;
const { INACTIVE, INTERRUPTED } = JitsiParticipantConnectionStatus;
if (connectionStatus === INACTIVE) {
return 'status-other';
} else if (connectionStatus === INTERRUPTED) {
return 'status-lost';
} else if (typeof percent === 'undefined') {
return 'status-high';
}
return QUALITY_TO_WIDTH.find(x => percent >= x.percent).colorClass;
}
/**
* Returns a string that describes the current connection status.
*
* @private
* @returns {string}
*/
_getConnectionStatusTip() {
let tipKey;
switch (this.props.connectionStatus) {
case JitsiParticipantConnectionStatus.INTERRUPTED:
tipKey = 'connectionindicator.quality.lost';
break;
case JitsiParticipantConnectionStatus.INACTIVE:
tipKey = 'connectionindicator.quality.inactive';
break;
default: {
const { percent } = this.state.stats;
if (typeof percent === 'undefined') {
// If percentage is undefined then there are no stats available
// yet, likely because only a local connection has been
// established so far. Assume a strong connection to start.
tipKey = 'connectionindicator.quality.good';
} else {
const config = QUALITY_TO_WIDTH.find(x => percent >= x.percent);
tipKey = config.tip;
}
}
}
return this.props.t(tipKey);
}
/**
* Returns additional class names to add to the root of the component. The
* class names are intended to be used for hiding or showing the indicator.
*
* @private
* @returns {string}
*/
_getVisibilityClass() {
const { connectionStatus } = this.props;
return this.state.showIndicator
|| this.props.alwaysVisible
|| connectionStatus === JitsiParticipantConnectionStatus.INTERRUPTED
|| connectionStatus === JitsiParticipantConnectionStatus.INACTIVE
? 'show-connection-indicator' : 'hide-connection-indicator';
}
/**
* Callback invoked when new connection stats associated with the passed in
* user ID are available. Will update the component's display of current
@ -209,6 +335,9 @@ class ConnectionIndicator extends Component {
this.setState({
stats: newStats
});
// Rely on React to batch setState actions.
this._updateIndicatorAutoHide(newStats.percent);
}
/**
@ -229,40 +358,46 @@ class ConnectionIndicator extends Component {
* @returns {ReactElement}
*/
_renderIcon() {
switch (this.props.connectionStatus) {
case JitsiParticipantConnectionStatus.INTERRUPTED:
return (
<span className = 'connection_lost'>
<i className = 'icon-connection-lost' />
</span>
);
case JitsiParticipantConnectionStatus.INACTIVE:
if (this.props.connectionStatus
=== JitsiParticipantConnectionStatus.INACTIVE) {
return (
<span className = 'connection_ninja'>
<i className = 'icon-ninja' />
</span>
);
default: {
const { percent } = this.state.stats;
const width = QUALITY_TO_WIDTH.find(x => percent >= x.percent);
const iconWidth = width && width.width
? { width: width && width.width } : {};
}
return [
<span
className = 'connection_empty'
key = 'icon-empty'>
<i className = 'icon-connection' />
</span>,
<span
className = 'connection_full'
key = 'icon-full'
style = { iconWidth }>
<i className = 'icon-connection' />
</span>
];
}
let iconWidth;
let emptyIconWrapperClassName = 'connection_empty';
if (this.props.connectionStatus
=== JitsiParticipantConnectionStatus.INTERRUPTED) {
// emptyIconWrapperClassName is used by the torture tests to
// identify lost connection status handling.
emptyIconWrapperClassName = 'connection_lost';
iconWidth = '0%';
} else if (typeof this.state.stats.percent === 'undefined') {
iconWidth = '100%';
} else {
const { percent } = this.state.stats;
iconWidth = QUALITY_TO_WIDTH.find(x => percent >= x.percent).width;
}
return [
<span
className = { emptyIconWrapperClassName }
key = 'icon-empty'>
<i className = 'icon-gsm-bars' />
</span>,
<span
className = 'connection_full'
key = 'icon-full'
style = {{ width: iconWidth }}>
<i className = 'icon-gsm-bars' />
</span>
];
}
/**
@ -284,6 +419,7 @@ class ConnectionIndicator extends Component {
<ConnectionStatsTable
bandwidth = { bandwidth }
bitrate = { bitrate }
connectionSummary = { this._getConnectionStatusTip() }
framerate = { framerate }
isLocalVideo = { this.props.isLocalVideo }
onShowMore = { this._onToggleShowMore }
@ -293,6 +429,36 @@ class ConnectionIndicator extends Component {
transport = { transport } />
);
}
/**
* Updates the internal state for automatically hiding the indicator.
*
* @param {number} percent - The current connection quality percentage
* between the values 0 and 100.
* @private
* @returns {void}
*/
_updateIndicatorAutoHide(percent) {
if (percent < INDICATOR_DISPLAY_THRESHOLD) {
clearTimeout(this.state.autoHideTimeout);
this.setState({
autoHideTimeout: null,
showIndicator: true
});
} else if (this.state.autoHideTimeout) {
// This clause is intentionally left blank because no further action
// is needed if the percent is below the threshold and there is an
// autoHideTimeout set.
} else {
this.setState({
autoHideTimeout: setTimeout(() => {
this.setState({
showIndicator: false
});
}, interfaceConfig.CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT)
});
}
}
}
export default ConnectionIndicator;
export default translate(ConnectionIndicator);

View File

@ -1,3 +1,4 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { translate } from '../../base/i18n';
@ -21,7 +22,7 @@ class ConnectionStatsTable extends Component {
* upload: Number
* }}
*/
bandwidth: React.PropTypes.object,
bandwidth: PropTypes.object,
/**
* Statistics related to bitrate.
@ -30,7 +31,12 @@ class ConnectionStatsTable extends Component {
* upload: Number
* }}
*/
bitrate: React.PropTypes.object,
bitrate: PropTypes.object,
/**
* A message describing the connection quality.
*/
connectionSummary: PropTypes.string,
/**
* Statistics related to framerates for each ssrc.
@ -38,17 +44,17 @@ class ConnectionStatsTable extends Component {
* [ ssrc ]: Number
* }}
*/
framerate: React.PropTypes.object,
framerate: PropTypes.object,
/**
* Whether or not the statitics are for local video.
*/
isLocalVideo: React.PropTypes.bool,
isLocalVideo: PropTypes.bool,
/**
* Callback to invoke when the show additional stats link is clicked.
*/
onShowMore: React.PropTypes.func,
onShowMore: PropTypes.func,
/**
* Statistics related to packet loss.
@ -57,7 +63,7 @@ class ConnectionStatsTable extends Component {
* upload: Number
* }}
*/
packetLoss: React.PropTypes.object,
packetLoss: PropTypes.object,
/**
* Statistics related to display resolutions for each ssrc.
@ -68,23 +74,23 @@ class ConnectionStatsTable extends Component {
* }
* }}
*/
resolution: React.PropTypes.object,
resolution: PropTypes.object,
/**
* Whether or not additional stats about bandwidth and transport should
* be displayed. Will not display even if true for remote participants.
*/
shouldShowMore: React.PropTypes.bool,
shouldShowMore: PropTypes.bool,
/**
* Invoked to obtain translated strings.
*/
t: React.PropTypes.func,
t: PropTypes.func,
/**
* Statistics related to transports.
*/
transport: React.PropTypes.array
transport: PropTypes.array
};
/**
@ -184,6 +190,24 @@ class ConnectionStatsTable extends Component {
);
}
/**
* Creates a table row as a ReactElement for displaying a summary message
* about the current connection status.
*
* @private
* @returns {ReactElement}
*/
_renderConnectionSummary() {
return (
<tr className = 'connection-info__status'>
<td>
<span>{ this.props.t('connectionindicator.status') }</span>
</td>
<td>{ this.props.connectionSummary }</td>
</tr>
);
}
/**
* Creates a table row as a ReactElement for displaying frame rate related
* statistics.
@ -309,6 +333,7 @@ class ConnectionStatsTable extends Component {
return (
<table className = 'connection-info__container'>
<tbody>
{ this._renderConnectionSummary() }
{ this._renderBitrate() }
{ this._renderPacketLoss() }
{ this._renderResolution() }