mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-01-12 01:30:18 +00:00
Compare commits
97 Commits
fix/preven
...
react-thum
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d1ed86e49 | ||
|
|
88c02fb658 | ||
|
|
0f64c66f91 | ||
|
|
9f65ae52f1 | ||
|
|
a242e86b23 | ||
|
|
4211db0893 | ||
|
|
9a35026d6a | ||
|
|
9742e90bb5 | ||
|
|
2a01d3550c | ||
|
|
efce5a831b | ||
|
|
e0117e03e8 | ||
|
|
1648e4b407 | ||
|
|
b02136d013 | ||
|
|
734631a7a4 | ||
|
|
9fbb35b6e1 | ||
|
|
f45af351d8 | ||
|
|
1f4cd22875 | ||
|
|
53cc724b3b | ||
|
|
b9ccc3ad8c | ||
|
|
68a0bdce2c | ||
|
|
b71d92a139 | ||
|
|
30fc04ba61 | ||
|
|
d2046c2c8f | ||
|
|
35b5f6df06 | ||
|
|
ca2343c31a | ||
|
|
3657c19e60 | ||
|
|
007183c151 | ||
|
|
9c10ac3028 | ||
|
|
4b429112f2 | ||
|
|
d067c4e731 | ||
|
|
07d8611988 | ||
|
|
b0d55f9450 | ||
|
|
5f2ee6d951 | ||
|
|
ddea7d0294 | ||
|
|
348c6416e5 | ||
|
|
ad265d5815 | ||
|
|
d5b2da02c1 | ||
|
|
fbfaed07b2 | ||
|
|
da33d8a033 | ||
|
|
830817d7b4 | ||
|
|
8c67f1fdf3 | ||
|
|
b57da04553 | ||
|
|
b428c3bca8 | ||
|
|
96c34b7774 | ||
|
|
f2bbc874b3 | ||
|
|
b18398f016 | ||
|
|
a6e58c3101 | ||
|
|
c5f6df5210 | ||
|
|
e67c08d837 | ||
|
|
d854b2cd3d | ||
|
|
ab5c8d49c3 | ||
|
|
820d9b2ba8 | ||
|
|
e4c1046d7c | ||
|
|
223187c640 | ||
|
|
35e8821679 | ||
|
|
3125345793 | ||
|
|
5e6c4d67ed | ||
|
|
a3fb996ff0 | ||
|
|
65a9de346f | ||
|
|
036d810d46 | ||
|
|
b5f9b575ca | ||
|
|
a7fa9d8a97 | ||
|
|
4762d5a153 | ||
|
|
e8c2c89343 | ||
|
|
d77a7cac3a | ||
|
|
6030c32272 | ||
|
|
8e19597e38 | ||
|
|
bf6a1540df | ||
|
|
9434d3c349 | ||
|
|
b891a7526d | ||
|
|
5bf20517e7 | ||
|
|
0d7a730497 | ||
|
|
59caa0cf42 | ||
|
|
bdda8c56c7 | ||
|
|
c239ba71e6 | ||
|
|
1005f8f498 | ||
|
|
f6e2bd1249 | ||
|
|
cd68c72338 | ||
|
|
1740aaf973 | ||
|
|
a270e4300a | ||
|
|
5e2ee3bdcd | ||
|
|
bdd2845917 | ||
|
|
f9888e5dbb | ||
|
|
44d7828e9c | ||
|
|
82b14ba7f1 | ||
|
|
63fe1de789 | ||
|
|
39af6f5943 | ||
|
|
f01869c21c | ||
|
|
6d2f8ae37d | ||
|
|
35bea1a1d0 | ||
|
|
afa4306ae8 | ||
|
|
1d9daa8da7 | ||
|
|
478f1a731e | ||
|
|
9f9e192c3c | ||
|
|
943996e5b6 | ||
|
|
bfde13cb15 | ||
|
|
5939820271 |
4
.github/ISSUE_TEMPLATE/2-feature-request.md
vendored
4
.github/ISSUE_TEMPLATE/2-feature-request.md
vendored
@@ -1,7 +1,9 @@
|
||||
---
|
||||
name: "Feature request"
|
||||
about: Suggest an idea for this project
|
||||
|
||||
title: ''
|
||||
labels: 'feature-request'
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!--
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -85,3 +85,9 @@ ios/app/dropbox.key
|
||||
ios/app/GoogleService-Info.plist
|
||||
|
||||
.vscode
|
||||
|
||||
# TWA
|
||||
twa/*.apk
|
||||
twa/*.aab
|
||||
twa/assetlinks.json
|
||||
|
||||
|
||||
@@ -2,10 +2,3 @@
|
||||
* Notifies interested parties that hangup procedure will start.
|
||||
*/
|
||||
export const BEFORE_HANGUP = 'conference.before_hangup';
|
||||
|
||||
/**
|
||||
* Notifies interested parties that desktop sharing enable/disable state is
|
||||
* changed.
|
||||
*/
|
||||
export const DESKTOP_SHARING_ENABLED_CHANGED
|
||||
= 'conference.desktop_sharing_enabled_changed';
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.jitsi.meet.sdk.JitsiMeet;
|
||||
@@ -78,6 +79,12 @@ public class MainActivity extends JitsiMeetActivity {
|
||||
// JitsiMeetActivity overrides
|
||||
//
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
JitsiMeet.showSplashScreen(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean extraInitialize() {
|
||||
Log.d(this.getClass().getSimpleName(), "LIBRE_BUILD="+BuildConfig.LIBRE_BUILD);
|
||||
|
||||
70
android/app/src/main/res/drawable/ic_jitsi_logosvg.xml
Normal file
70
android/app/src/main/res/drawable/ic_jitsi_logosvg.xml
Normal file
@@ -0,0 +1,70 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="262.91376dp"
|
||||
android:height="262.91376dp"
|
||||
android:viewportWidth="262.91376"
|
||||
android:viewportHeight="262.91376">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="m0,0 l262.914,-0L262.914,262.914 0,262.914 0,0Z"/>
|
||||
<path
|
||||
android:pathData="m142.646,105.099c0.117,0.026 0.255,0.036 0.406,0.036 3.186,-0 10.297,-4.615 11.617,-6.721l0.1,-0.17 0.153,-0.135c0.451,-0.441 1.746,-2.773 2.374,-4.17 -6.751,-2.023 -7.49,-5.677 -8.153,-8.919 -0.069,-0.376 -0.138,-0.717 -0.204,-1.019 -0.074,-0.397 -0.153,-0.8 -0.226,-1.112C138.668,86.221 135.593,88.094 133.921,89.483 133.056,90.201 132.542,92.251 135.042,97.926 136.323,100.816 140.727,104.733 142.646,105.099"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="nonZero"/>
|
||||
<path
|
||||
android:pathData="m115.413,146.042c5.934,-0 18.464,-3.543 26.748,-5.887 1.21,-0.336 2.33,-0.66 3.351,-0.944 0.166,-0.046 0.321,-0.091 0.472,-0.124 -0.463,-0.461 -1.239,-1.159 -2.497,-2.216 -5.521,-3.741 -10.736,-5.484 -16.403,-5.484 -1.237,-0 -2.522,0.071 -3.923,0.231 -4.801,0.55 -8.8,1.69 -10.722,2.237 -0.967,0.284 -1.263,0.366 -1.567,0.366 -0.58,-0 -1.079,-0.341 -1.273,-0.878 -0.194,-0.534 -0.027,-1.121 0.425,-1.507l0.024,-0.011c3.316,-2.784 9.489,-7.951 21.198,-10.256 2.027,-0.401 4.202,-0.605 6.454,-0.605 5.242,-0 10.67,1.086 16.125,3.219 7.436,2.899 12.521,6.625 16.602,9.62 2.199,1.609 4.105,3.007 5.755,3.771 0.421,0.2 0.637,0.255 0.746,0.265 0.074,-0.095 0.23,-0.365 0.474,-1.069 0.066,-0.185 0.529,-2.161 -2.806,-13.374 -1.931,-6.51 -4.264,-13.156 -5.479,-16.104 -2.356,-5.711 -1.778,-9.76 -1.051,-12.125 -1.999,0.735 -4.033,1.87 -6.174,3.446L161.758,98.711C160.694,99.506 159.599,100.404 158.426,101.454 151.517,107.64 146.344,110.864 143.035,111.04l-0.093,0.004 -0.093,-0.009c-2.912,-0.245 -7.324,-4.489 -9.133,-6.634 -0.373,-0.251 -0.8,-0.366 -1.366,-0.366 -0.564,-0 -1.202,0.116 -1.82,0.235C130.086,104.354 129.623,104.441 129.167,104.489 127.708,104.632 125.668,105.106 123.694,105.561 122.746,105.777 121.762,106.005 120.864,106.189 120.851,106.19 120.463,106.272 119.774,106.454 114.903,107.891 111.228,109.55 109.432,111.111 109.414,111.127 109.352,111.174 109.266,111.242 108.048,112.105 105.124,114.567 104.248,118.762L104.237,118.795C102.398,126.516 105.187,136.087 108.892,141.554 110.636,144.125 112.513,145.727 114.048,145.959 114.437,146.015 114.891,146.042 115.413,146.042"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="nonZero"/>
|
||||
<path
|
||||
android:pathData="m90.093,173.175c-1.252,-1.472 -1.783,-3.324 -1.574,-5.521 0.884,-10.642 -0.329,-13.215 -0.891,-13.829 -0.131,-0.144 -0.207,-0.144 -0.265,-0.144 -0.022,-0 -0.041,0.003 -0.064,0.003 -1.044,0.248 -8.066,5.002 -9.615,19.171 -0.749,6.845 0.561,15.63 1.679,20.974 0.897,-3.155 2.314,-6.624 5.057,-10.204 2.556,-3.326 5.345,-5.955 8.801,-8.253C92.143,174.93 90.991,174.235 90.093,173.175"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="nonZero"/>
|
||||
<path
|
||||
android:pathData="m94.906,156.389c-0.03,2.229 -0.326,4.36 -0.61,6.445 -0.151,1.119 -0.314,2.286 -0.434,3.46 -0.161,2.341 0.346,3.166 0.571,3.406 0.127,0.136 0.326,0.287 0.76,0.287 0.339,-0 0.741,-0.091 1.161,-0.268 4.202,-1.756 8.195,-4.815 10.115,-6.515C103.522,161.892 98.995,159.058 94.906,156.389"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="nonZero"/>
|
||||
<path
|
||||
android:pathData="m154.002,81.595c-0.031,0.074 -0.065,0.148 -0.101,0.216 -0.821,2.403 0.306,5.664 2.419,6.898 0.561,0.327 1.106,0.526 1.624,0.596 0.072,0.006 0.148,0.009 0.219,0.009 1.645,-0 2.971,-1.199 3.961,-3.561C162.752,83.959 162.836,81.827 162.37,79.904 162.003,78.409 161.057,76.627 160.453,75.738 159.332,76.509 157.111,78.207 155.585,79.553 154.518,80.582 154.136,81.229 154.002,81.595"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="nonZero"/>
|
||||
<path
|
||||
android:pathData="M148.97,77.699C153.957,73.194 156.988,65.754 158.253,61.334 153.915,65.513 148.633,67.758 145.25,69.198 144.084,69.695 143.08,70.124 142.477,70.476 142.224,70.623 141.965,70.77 141.708,70.919 139.654,72.109 136.55,73.905 136.1,75.011l-0.012,0.036 -0.012,0.034c-1.406,2.956 -2.199,7.401 -2.457,9.95 3.266,-1.99 6.625,-3.322 9.416,-4.42C145.628,79.585 147.863,78.703 148.97,77.699"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="nonZero"/>
|
||||
<path
|
||||
android:pathData="m164.464,51.921c-0.84,5.539 -2.205,10.799 -4.751,16.347 2.781,-3.144 4.396,-6.568 4.941,-10.401C164.886,56.275 165.097,54.756 164.464,51.921"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="nonZero"/>
|
||||
<path
|
||||
android:pathData="M148.749,142.639C148.718,142.598 148.684,142.56 148.658,142.519 148.523,142.539 148.307,142.584 147.972,142.683l-0.14,0.04c-1.726,0.644 -4.899,1.708 -8.556,2.946 -4.396,1.479 -9.365,3.154 -13.526,4.649 -5.297,1.975 -7.021,2.755 -7.557,3.024 -0.098,0.266 -0.203,0.599 -0.327,0.965 -1.254,3.816 -4.125,12.541 -18.276,18.653 2.928,2.956 9.289,8.27 21.809,8.27 1.082,-0 2.21,-0.036 3.341,-0.12 9.451,-0.666 18.342,-4.855 25.026,-11.78 6.087,-6.291 9.538,-14.136 9.585,-21.7C157.876,147.509 155.367,147.135 153.043,146.033 153.014,146.02 150.361,144.745 148.749,142.639"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="nonZero"/>
|
||||
<path
|
||||
android:pathData="m189.478,117.853c-0.523,9.749 -2.122,18.424 -4.744,25.8 -2.128,5.988 -4.94,11.134 -8.356,15.316 -5.676,6.931 -11.555,9.256 -12.804,9.304 -0.866,-0 -1.313,-0.309 -3.046,-1.528 -0.17,-0.114 -0.37,-0.252 -0.581,-0.4 -3.313,5.953 -8.505,11.097 -15.065,14.959 -7.079,4.144 -15.297,6.423 -23.157,6.423 -9.078,-0 -17.13,-2.924 -23.341,-8.456 -7.467,4.799 -12.31,9.074 -16.267,27.005l-1.363,6.17 -2.971,-5.564c-0.424,-0.786 -1.929,-3.731 -3.332,-8.887 -1.934,-7.104 -2.86,-15.181 -2.758,-24.01 0.117,-10.049 3.154,-16.526 5.68,-20.186 2.98,-4.314 6.837,-6.994 10.076,-6.994 0.216,-0 0.428,0.006 0.616,0.035 5.159,0.575 8.435,2.75 14.396,6.686l1.899,1.252c2.059,1.344 4.481,2.7 5.259,2.989 0.54,-0.284 1.749,-2.3 2.155,-5.271l0.069,-0.451c0.005,-0.045 0.009,-0.091 0.014,-0.131 -0.036,-0.02 -0.065,-0.029 -0.094,-0.041 -4.008,-1.375 -9.539,-7.7 -12.364,-17.134 -2.684,-9.382 -2.129,-17.185 1.644,-23.193 6.12,-9.736 19.198,-11.974 23.466,-12.702 1.331,-0.266 2.716,-0.511 4.041,-0.717 0.255,-0.061 0.469,-0.121 0.642,-0.168 -0.031,-0.126 -0.071,-0.265 -0.114,-0.43 -0.108,-0.417 -0.23,-0.891 -0.354,-1.447 -1.345,-6.035 -0.664,-11.069 0.181,-15.193 0.928,-4.546 1.489,-7.287 3.747,-9.936 3.029,-4.165 8.319,-5.936 11.479,-6.991 0.746,-0.249 1.511,-0.509 1.894,-0.689 8.988,-4.31 11.82,-8.739 12.615,-11.694 0.656,-2.451 1.699,-8.884 1.251,-13.335 -0.085,-0.805 0.129,-1.521 0.621,-2.065 0.45,-0.505 1.101,-0.794 1.778,-0.794 1.515,-0 2.82,-0 7.511,14.598 2.481,7.698 0.645,14.903 -5.45,21.424l-0.226,0.231c0.024,0.044 0.049,0.09 0.08,0.144 2.57,4.236 3.963,9.54 3.553,13.51 -0.099,0.906 -0.265,1.775 -0.419,2.549 -0.003,0.01 -0.003,0.016 -0.004,0.029 0.516,-0.032 1.119,-0.055 1.775,-0.055 3.052,-0 7.435,0.474 10.989,2.735 2.135,1.352 4.845,3.439 6.835,7.615C189.223,102.942 190.076,109.575 189.478,117.853m4.77,-23.191c-2.916,-6.1 -6.989,-9.177 -9.793,-10.96 -2.355,-1.494 -5.064,-2.584 -8.077,-3.24l-0.676,-0.146 -0.111,-0.689c-0.339,-2.119 -0.918,-4.275 -1.715,-6.406l-0.185,-0.49 0.292,-0.434c5.095,-7.594 6.323,-16.17 3.54,-24.802 -2.191,-6.824 -3.895,-11.211 -5.341,-13.799 -2.954,-5.305 -7.006,-6.417 -9.891,-6.417 -2.964,-0 -5.8,1.261 -7.789,3.457 -2.043,2.254 -2.993,5.207 -2.678,8.31 0.316,3.134 -0.494,8.516 -1.014,10.439 -0.04,0.117 -0.975,2.929 -8.201,6.428 -0.162,0.056 -0.512,0.179 -1.053,0.359 -3.729,1.246 -10.666,3.571 -15.258,9.64 -3.465,4.205 -4.332,8.441 -5.338,13.346 -0.586,2.865 -1.236,6.744 -1.079,11.344l0.026,0.841 -0.824,0.188c-11.646,2.585 -20.025,7.835 -24.909,15.605 -5.054,8.04 -5.919,18.055 -2.543,29.853 0.063,0.204 0.126,0.407 0.189,0.615l0.527,1.608 -1.665,-0.286c-0.561,-0.101 -1.135,-0.18 -1.729,-0.241 -0.493,-0.06 -1.001,-0.082 -1.509,-0.082 -5.633,-0 -11.663,3.585 -16.128,9.592 -3.451,4.641 -7.588,12.849 -7.735,25.601 -0.114,9.573 0.906,18.401 3.038,26.228 1.581,5.795 3.326,9.329 4.004,10.577l13.306,24.94 6.096,-27.619c2.454,-11.09 4.864,-15.262 7.725,-18.111l0.561,-0.563 0.679,0.411c6.605,3.977 14.466,6.084 22.73,6.084 9.286,-0 18.965,-2.682 27.259,-7.551 5.38,-3.16 9.974,-7.036 13.649,-11.531l0.45,-0.369 0.85,-0.02c2.156,-0.068 5.16,-1.164 8.222,-3.004 2.6,-1.555 6.543,-4.428 10.501,-9.262 3.997,-4.884 7.274,-10.854 9.716,-17.734 2.876,-8.073 4.625,-17.489 5.204,-28.004 0.689,-9.668 -0.434,-17.641 -3.327,-23.704"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="nonZero"/>
|
||||
<path
|
||||
android:pathData="m180.026,98.414c-1.67,-2.596 -3.771,-4.206 -5.475,-4.206 -0.313,-0 -0.613,0.051 -0.895,0.161 -0.911,0.361 -2.356,4.532 -1.714,7.566 0.434,2.066 2.938,9.04 4.151,12.394 0.456,1.281 0.68,1.91 0.754,2.142 0.064,0.183 0.145,0.448 0.256,0.774 0.97,2.971 3.467,10.586 4.206,16.761 1.549,-6.579 2.424,-14.512 2.085,-23.997C183.235,105.662 182.04,101.538 180.026,98.414"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="nonZero"/>
|
||||
<path
|
||||
android:pathData="M168.088,142.604C169.896,142.111 171.33,141.705 172.398,141.395 170.213,139.874 167.689,137.979 164.247,135.304c-8.418,-6.546 -17.449,-9.87 -26.839,-9.87 -5.135,-0 -9.611,0.991 -13.156,2.186 0.882,-0.05 1.779,-0.079 2.7,-0.079 1.1,-0 2.247,0.04 3.411,0.119 3.652,0.246 13.061,1.901 21.565,12.047 1.714,2.039 3.559,3.73 8.794,3.73 1.873,-0 4.051,-0.207 6.662,-0.645C167.544,142.751 167.793,142.678 168.088,142.604"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="nonZero"/>
|
||||
<path
|
||||
android:pathData="m164.3,147.583c-0.122,1.563 -0.376,4.509 -0.782,6.76 -0.495,2.719 -1.31,5.02 -1.791,6.226 0.85,0.786 1.694,1.553 2.247,2.043 2.214,-1.447 9.47,-6.96 14.483,-19.474C176.847,144.229 174.59,145.178 171.671,146.018 168.701,146.861 165.82,147.357 164.3,147.583"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"
|
||||
android:fillType="nonZero"/>
|
||||
</group>
|
||||
</vector>
|
||||
11
android/app/src/main/res/layout/launch_screen.xml
Normal file
11
android/app/src/main/res/layout/launch_screen.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/colorPrimary">
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:src="@drawable/ic_jitsi_logosvg"/>
|
||||
</RelativeLayout>
|
||||
5
android/app/src/main/res/values/colors.xml
Normal file
5
android/app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#17A0DB</color>
|
||||
<color name="colorPrimaryDark">#1081B2</color>
|
||||
</resources>
|
||||
@@ -2,6 +2,6 @@
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="android:navigationBarColor">#1081B2</item>
|
||||
<item name="android:navigationBarColor">@color/colorPrimaryDark</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import groovy.json.JsonSlurper
|
||||
import org.gradle.util.VersionNumber
|
||||
|
||||
// Top-level build file where you can add configuration options common to all
|
||||
// sub-projects/modules.
|
||||
@@ -9,7 +10,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.0.1'
|
||||
classpath 'com.android.tools.build:gradle:4.0.2'
|
||||
classpath 'com.google.gms:google-services:4.3.3'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.3.0'
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryErro
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
# This one fixes a weird WebRTC runtime problem on some devices.
|
||||
# https://github.com/jitsi/jitsi-meet/issues/7911#issuecomment-714323255
|
||||
android.enableDexingArtifactTransform.desugaring=false
|
||||
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
|
||||
@@ -89,7 +89,9 @@ fi
|
||||
# Now build and publish the Jitsi Meet SDK and its dependencies
|
||||
echo "Building and publishing the Jitsi Meet SDK"
|
||||
pushd ${THIS_DIR}/../
|
||||
./gradlew clean assembleRelease publish
|
||||
./gradlew clean
|
||||
./gradlew assembleRelease
|
||||
./gradlew publish
|
||||
popd
|
||||
|
||||
if [[ $DO_GIT_TAG == 1 ]]; then
|
||||
|
||||
@@ -71,6 +71,7 @@ dependencies {
|
||||
implementation project(':react-native-svg')
|
||||
implementation project(':react-native-webrtc')
|
||||
implementation project(':react-native-webview')
|
||||
implementation project(':react-native-splash-screen')
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00020000"
|
||||
@@ -34,8 +34,7 @@
|
||||
android:launchMode="singleTask"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
</activity>
|
||||
android:windowSoftInputMode="adjustResize"></activity>
|
||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
||||
|
||||
<service
|
||||
@@ -46,7 +45,9 @@
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service android:name="org.jitsi.meet.sdk.JitsiMeetOngoingConferenceService" />
|
||||
<service
|
||||
android:name="org.jitsi.meet.sdk.JitsiMeetOngoingConferenceService"
|
||||
android:foregroundServiceType="mediaProjection" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
* Copyright @ 2018-present 8x8, Inc.
|
||||
* Copyright @ 2017-2018 Atlassian Pty Ltd
|
||||
* Copyright @ 2017-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,12 +15,16 @@
|
||||
*/
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
|
||||
import org.devio.rn.splashscreen.SplashScreen;
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
public class JitsiMeet {
|
||||
|
||||
/**
|
||||
@@ -81,4 +84,17 @@ public class JitsiMeet {
|
||||
String value = preferences.getString("isCrashReportingDisabled", "");
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to show the SplashScreen.
|
||||
*
|
||||
* @param activity - The activity on which to show the SplashScreen {@link Activity}.
|
||||
*/
|
||||
public static void showSplashScreen(Activity activity) {
|
||||
try {
|
||||
SplashScreen.show(activity);
|
||||
} catch (Exception e) {
|
||||
JitsiMeetLogger.e(e, "Failed to show splash screen");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,7 @@ class PictureInPictureModule extends ReactContextBaseJavaModule {
|
||||
private static final String TAG = NAME;
|
||||
|
||||
private static boolean isSupported;
|
||||
private boolean isDisabled;
|
||||
|
||||
public PictureInPictureModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
@@ -83,6 +84,10 @@ class PictureInPictureModule extends ReactContextBaseJavaModule {
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
public void enterPictureInPicture() {
|
||||
if (isDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isSupported) {
|
||||
throw new IllegalStateException("Picture-in-Picture not supported");
|
||||
}
|
||||
@@ -126,6 +131,11 @@ class PictureInPictureModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setPictureInPictureDisabled(Boolean disabled) {
|
||||
this.isDisabled = disabled;
|
||||
}
|
||||
|
||||
public boolean isPictureInPictureSupported() {
|
||||
return isSupported;
|
||||
}
|
||||
|
||||
@@ -23,19 +23,18 @@ import androidx.annotation.Nullable;
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.common.LifecycleState;
|
||||
import com.facebook.react.devsupport.DevInternalSettings;
|
||||
import com.facebook.react.jscexecutor.JSCExecutorFactory;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
import com.oney.WebRTCModule.RTCVideoViewManager;
|
||||
import com.oney.WebRTCModule.WebRTCModule;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
import org.devio.rn.splashscreen.SplashScreenModule;
|
||||
import org.webrtc.SoftwareVideoDecoderFactory;
|
||||
import org.webrtc.SoftwareVideoEncoderFactory;
|
||||
import org.webrtc.audio.AudioDeviceModule;
|
||||
@@ -69,6 +68,7 @@ class ReactInstanceManagerHolder {
|
||||
new JavaScriptSandboxModule(reactContext),
|
||||
new LocaleDetector(reactContext),
|
||||
new LogBridgeModule(reactContext),
|
||||
new SplashScreenModule(reactContext),
|
||||
new PictureInPictureModule(reactContext),
|
||||
new ProximityModule(reactContext),
|
||||
new WiFiStatsModule(reactContext),
|
||||
|
||||
@@ -21,6 +21,8 @@ include ':react-native-linear-gradient'
|
||||
project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android')
|
||||
include ':react-native-sound'
|
||||
project(':react-native-sound').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sound/android')
|
||||
include ':react-native-splash-screen'
|
||||
project(':react-native-splash-screen').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-splash-screen/android')
|
||||
include ':react-native-svg'
|
||||
project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-svg/android')
|
||||
include ':react-native-webrtc'
|
||||
|
||||
2
app.js
2
app.js
@@ -6,6 +6,8 @@ import 'jQuery-Impromptu';
|
||||
|
||||
import 'olm';
|
||||
|
||||
import 'focus-visible';
|
||||
|
||||
// We need to setup the jitsi-local-storage as early as possible so that we can start using it.
|
||||
// NOTE: If jitsi-local-storage is used before the initial setup is performed this will break the use case when we use
|
||||
// the local storage from the parent page when the localStorage is disabled. Also the setup is relying that
|
||||
|
||||
146
conference.js
146
conference.js
@@ -24,7 +24,6 @@ import {
|
||||
reloadWithStoredParams
|
||||
} from './react/features/app/actions';
|
||||
import {
|
||||
AVATAR_ID_COMMAND,
|
||||
AVATAR_URL_COMMAND,
|
||||
EMAIL_COMMAND,
|
||||
authStatusChanged,
|
||||
@@ -42,8 +41,7 @@ import {
|
||||
lockStateChanged,
|
||||
onStartMutedPolicyChanged,
|
||||
p2pStatusChanged,
|
||||
sendLocalParticipant,
|
||||
setDesktopSharingEnabled
|
||||
sendLocalParticipant
|
||||
} from './react/features/base/conference';
|
||||
import {
|
||||
checkAndNotifyForNewDevice,
|
||||
@@ -66,6 +64,8 @@ import {
|
||||
JitsiTrackEvents
|
||||
} from './react/features/base/lib-jitsi-meet';
|
||||
import {
|
||||
getStartWithAudioMuted,
|
||||
getStartWithVideoMuted,
|
||||
isVideoMutedByUser,
|
||||
MEDIA_TYPE,
|
||||
setAudioAvailable,
|
||||
@@ -97,18 +97,15 @@ import {
|
||||
destroyLocalTracks,
|
||||
getLocalJitsiAudioTrack,
|
||||
getLocalJitsiVideoTrack,
|
||||
isLocalVideoTrackMuted,
|
||||
isLocalCameraTrackMuted,
|
||||
isLocalTrackMuted,
|
||||
isUserInteractionRequiredForUnmute,
|
||||
replaceLocalTrack,
|
||||
trackAdded,
|
||||
trackRemoved
|
||||
} from './react/features/base/tracks';
|
||||
import {
|
||||
getBackendSafePath,
|
||||
getJitsiMeetGlobalNS
|
||||
} from './react/features/base/util';
|
||||
import { downloadJSON } from './react/features/base/util/downloadJSON';
|
||||
import { getConferenceOptions } from './react/features/conference/functions';
|
||||
import { showDesktopPicker } from './react/features/desktop-picker';
|
||||
import { appendSuffix } from './react/features/display-name';
|
||||
import {
|
||||
@@ -124,7 +121,6 @@ import {
|
||||
isPrejoinPageVisible,
|
||||
makePrecallTest
|
||||
} from './react/features/prejoin';
|
||||
import { createRnnoiseProcessorPromise } from './react/features/rnnoise';
|
||||
import { toggleScreenshotCaptureEffect } from './react/features/screenshot-capture';
|
||||
import { setSharedVideoStatus } from './react/features/shared-video';
|
||||
import { AudioMixerEffect } from './react/features/stream-effects/audio-mixer/AudioMixerEffect';
|
||||
@@ -173,7 +169,6 @@ window.JitsiMeetScreenObtainer = {
|
||||
* Known custom conference commands.
|
||||
*/
|
||||
const commands = {
|
||||
AVATAR_ID: AVATAR_ID_COMMAND,
|
||||
AVATAR_URL: AVATAR_URL_COMMAND,
|
||||
CUSTOM_ROLE: 'custom-role',
|
||||
EMAIL: EMAIL_COMMAND,
|
||||
@@ -445,17 +440,8 @@ export default {
|
||||
* the tracks won't exist).
|
||||
*/
|
||||
_localTracksInitialized: false,
|
||||
isSharingScreen: false,
|
||||
|
||||
/**
|
||||
* Indicates if the desktop sharing functionality has been enabled.
|
||||
* It takes into consideration the status returned by
|
||||
* {@link JitsiMeetJS.isDesktopSharingEnabled()}. The latter can be false
|
||||
* either if the desktop sharing is not supported by the current browser
|
||||
* or if it was disabled through lib-jitsi-meet specific options (check
|
||||
* config.js for listed options).
|
||||
*/
|
||||
isDesktopSharingEnabled: false,
|
||||
isSharingScreen: false,
|
||||
|
||||
/**
|
||||
* The local audio track (if any).
|
||||
@@ -683,14 +669,6 @@ export default {
|
||||
con.addEventListener(JitsiConnectionEvents.CONNECTION_FAILED, _connectionFailedHandler);
|
||||
APP.connection = connection = con;
|
||||
|
||||
// Desktop sharing related stuff:
|
||||
this.isDesktopSharingEnabled
|
||||
= JitsiMeetJS.isDesktopSharingEnabled();
|
||||
eventEmitter.emit(JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED, this.isDesktopSharingEnabled);
|
||||
|
||||
APP.store.dispatch(
|
||||
setDesktopSharingEnabled(this.isDesktopSharingEnabled));
|
||||
|
||||
this._createRoom(tracks);
|
||||
APP.remoteControl.init();
|
||||
|
||||
@@ -737,10 +715,10 @@ export default {
|
||||
const initialOptions = {
|
||||
startAudioOnly: config.startAudioOnly,
|
||||
startScreenSharing: config.startScreenSharing,
|
||||
startWithAudioMuted: config.startWithAudioMuted
|
||||
startWithAudioMuted: getStartWithAudioMuted(APP.store.getState())
|
||||
|| config.startSilent
|
||||
|| isUserInteractionRequiredForUnmute(APP.store.getState()),
|
||||
startWithVideoMuted: config.startWithVideoMuted
|
||||
startWithVideoMuted: getStartWithVideoMuted(APP.store.getState())
|
||||
|| isUserInteractionRequiredForUnmute(APP.store.getState())
|
||||
};
|
||||
|
||||
@@ -815,7 +793,7 @@ export default {
|
||||
isLocalVideoMuted() {
|
||||
// If the tracks are not ready, read from base/media state
|
||||
return this._localTracksInitialized
|
||||
? isLocalVideoTrackMuted(
|
||||
? isLocalCameraTrackMuted(
|
||||
APP.store.getState()['features/base/tracks'])
|
||||
: isVideoMutedByUser(APP.store);
|
||||
},
|
||||
@@ -1138,20 +1116,6 @@ export default {
|
||||
return room ? room.getParticipantById(id) : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get participant connection status for the participant.
|
||||
*
|
||||
* @param {string} id participant's identifier(MUC nickname)
|
||||
*
|
||||
* @returns {ParticipantConnectionStatus|null} the status of the participant
|
||||
* or null if no such participant is found or participant is the local user.
|
||||
*/
|
||||
getParticipantConnectionStatus(id) {
|
||||
const participant = this.getParticipantById(id);
|
||||
|
||||
return participant ? participant.getConnectionStatus() : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the display name foe the <tt>JitsiParticipant</tt> identified by
|
||||
* the given <tt>id</tt>.
|
||||
@@ -1319,53 +1283,7 @@ export default {
|
||||
},
|
||||
|
||||
_getConferenceOptions() {
|
||||
const options = config;
|
||||
const { email, name: nick } = getLocalParticipant(APP.store.getState());
|
||||
|
||||
const state = APP.store.getState();
|
||||
const { locationURL } = state['features/base/connection'];
|
||||
const { tenant } = state['features/base/jwt'];
|
||||
|
||||
if (tenant) {
|
||||
options.siteID = tenant;
|
||||
}
|
||||
|
||||
if (options.enableDisplayNameInStats && nick) {
|
||||
options.statisticsDisplayName = nick;
|
||||
}
|
||||
|
||||
if (options.enableEmailInStats && email) {
|
||||
options.statisticsId = email;
|
||||
}
|
||||
|
||||
options.applicationName = interfaceConfig.APP_NAME;
|
||||
options.getWiFiStatsMethod = this._getWiFiStatsMethod;
|
||||
options.confID = `${locationURL.host}${getBackendSafePath(locationURL.pathname)}`;
|
||||
options.createVADProcessor = createRnnoiseProcessorPromise;
|
||||
|
||||
// Disable CallStats, if requessted.
|
||||
if (options.disableThirdPartyRequests) {
|
||||
delete options.callStatsID;
|
||||
delete options.callStatsSecret;
|
||||
delete options.getWiFiStatsMethod;
|
||||
}
|
||||
|
||||
return options;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the result of getWiFiStats from the global NS or does nothing
|
||||
* (returns empty result).
|
||||
* Fixes a concurrency problem where we need to pass a function when creating
|
||||
* JitsiConference, but that method is added to the context later.
|
||||
*
|
||||
* @returns {Promise}
|
||||
* @private
|
||||
*/
|
||||
_getWiFiStatsMethod() {
|
||||
const gloabalNS = getJitsiMeetGlobalNS();
|
||||
|
||||
return gloabalNS.getWiFiStats ? gloabalNS.getWiFiStats() : Promise.resolve('{}');
|
||||
return getConferenceOptions(APP.store.getState());
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -1596,9 +1514,8 @@ export default {
|
||||
if (this.videoSwitchInProgress) {
|
||||
return Promise.reject('Switch in progress.');
|
||||
}
|
||||
if (!this.isDesktopSharingEnabled) {
|
||||
return Promise.reject(
|
||||
'Cannot toggle screen sharing: not supported.');
|
||||
if (!JitsiMeetJS.isDesktopSharingEnabled()) {
|
||||
return Promise.reject('Cannot toggle screen sharing: not supported.');
|
||||
}
|
||||
|
||||
if (this.isAudioOnly()) {
|
||||
@@ -2075,7 +1992,6 @@ export default {
|
||||
formattedDisplayName
|
||||
|| interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME)
|
||||
});
|
||||
APP.UI.changeDisplayName(id, formattedDisplayName);
|
||||
}
|
||||
);
|
||||
room.on(
|
||||
@@ -2138,10 +2054,7 @@ export default {
|
||||
});
|
||||
|
||||
room.on(JitsiConferenceEvents.KICKED, participant => {
|
||||
APP.UI.hideStats();
|
||||
APP.store.dispatch(kickedOut(room, participant));
|
||||
|
||||
// FIXME close
|
||||
});
|
||||
|
||||
room.on(JitsiConferenceEvents.PARTICIPANT_KICKED, (kicker, kicked) => {
|
||||
@@ -2186,16 +2099,6 @@ export default {
|
||||
}));
|
||||
});
|
||||
|
||||
room.addCommandListener(this.commands.defaults.AVATAR_ID,
|
||||
(data, from) => {
|
||||
APP.store.dispatch(
|
||||
participantUpdated({
|
||||
conference: room,
|
||||
id: from,
|
||||
avatarID: data.value
|
||||
}));
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.NICKNAME_CHANGED,
|
||||
this.changeLocalDisplayName.bind(this));
|
||||
|
||||
@@ -2484,11 +2387,6 @@ export default {
|
||||
APP.keyboardshortcut.init();
|
||||
|
||||
APP.store.dispatch(conferenceJoined(room));
|
||||
|
||||
const displayName
|
||||
= APP.store.getState()['features/base/settings'].displayName;
|
||||
|
||||
APP.UI.changeDisplayName('localVideoContainer', displayName);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -2664,6 +2562,20 @@ export default {
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=997689
|
||||
const hasDefaultMicChanged = newDevices.audioinput === 'default';
|
||||
|
||||
// This is the case when the local video is muted and a preferred device is connected.
|
||||
if (requestedInput.video && this.isLocalVideoMuted()) {
|
||||
// We want to avoid creating a new video track in order to prevent turning on the camera.
|
||||
requestedInput.video = false;
|
||||
APP.store.dispatch(updateSettings({ // Update the current selected camera for the device selection dialog.
|
||||
cameraDeviceId: newDevices.videoinput
|
||||
}));
|
||||
delete newDevices.videoinput;
|
||||
|
||||
// Removing the current video track in order to force the unmute to select the preferred device.
|
||||
this.useVideoStream(null);
|
||||
|
||||
}
|
||||
|
||||
promises.push(
|
||||
mediaDeviceHelper.createLocalTracksAfterDeviceListChanged(
|
||||
createLocalTracksF,
|
||||
@@ -2972,10 +2884,6 @@ export default {
|
||||
APP.store.dispatch(updateSettings({
|
||||
displayName: formattedNickname
|
||||
}));
|
||||
|
||||
if (room) {
|
||||
APP.UI.changeDisplayName(id, formattedNickname);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -3085,7 +2993,7 @@ export default {
|
||||
* @param {boolean} muted - New muted status.
|
||||
*/
|
||||
setVideoMuteStatus(muted) {
|
||||
APP.UI.setVideoMuted(this.getMyUserId(), muted);
|
||||
APP.UI.setVideoMuted(this.getMyUserId());
|
||||
APP.API.notifyVideoMutedStatusChanged(muted);
|
||||
},
|
||||
|
||||
|
||||
@@ -323,10 +323,6 @@ var config = {
|
||||
// is set in Jicofo and set to 2).
|
||||
// minParticipants: 2,
|
||||
|
||||
// Use the TURN servers discovered via XEP-0215 for the jitsi-videobridge
|
||||
// connection
|
||||
// useStunTurn: true,
|
||||
|
||||
// Use TURN/UDP servers for the jitsi-videobridge connection (by default
|
||||
// we filter out TURN/UDP because it is usually not needed since the
|
||||
// bridge itself is reachable via UDP)
|
||||
@@ -442,9 +438,6 @@ var config = {
|
||||
// connection.
|
||||
enabled: true,
|
||||
|
||||
// Use XEP-0215 to fetch STUN and TURN servers.
|
||||
// useStunTurn: true,
|
||||
|
||||
// The STUN servers that will be used in the peer to peer connections
|
||||
stunServers: [
|
||||
|
||||
|
||||
@@ -33,6 +33,14 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will hide the focus indicator if an element receives focus via the mouse,
|
||||
* but it will still show up on keyboard focus, thus preserving accessibility.
|
||||
*/
|
||||
.js-focus-visible :focus:not(.focus-visible) {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* AtlasKit sets a default margin on the rendered modals, so
|
||||
* when the shift-right class is set when the chat opens, we
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
.con-status {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
top: 24px;
|
||||
width: 100%;
|
||||
z-index: $toolbarZ + 3;
|
||||
|
||||
&-container {
|
||||
background: rgba(28, 32, 37, .5);
|
||||
border-radius: 3px;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
line-height: 13px;
|
||||
margin: 0 auto;
|
||||
width: 304px;
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
&-header {
|
||||
background: rgba(28, 32, 37, .5);
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
&-circle {
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
padding: 4px;
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
&--good {
|
||||
@@ -40,6 +40,16 @@
|
||||
}
|
||||
|
||||
&-arrow {
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
border-radius: 3px;
|
||||
margin-left: 8px;
|
||||
margin-right: 2px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background-color 0.16s ease-out;
|
||||
|
||||
&--up {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
@@ -47,6 +57,10 @@
|
||||
&>svg {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(1,1,1, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
&-text {
|
||||
@@ -54,7 +68,17 @@
|
||||
}
|
||||
|
||||
&-details {
|
||||
background: rgba(28, 32, 37, .5);
|
||||
border-top: 1px solid #5E6D7A;
|
||||
padding: 16px;
|
||||
transition: opacity 0.16s ease-out;
|
||||
|
||||
&-visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&-hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,19 +14,6 @@
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.form {
|
||||
align-items: stretch;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
.participant-info {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,19 +87,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
align-self: stretch;
|
||||
background-color: transparent;
|
||||
border: 1px solid #B8C7E0;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
padding: 12px 8px;
|
||||
|
||||
&:focus {
|
||||
border-color: rgb(3, 118, 218);
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
align-self: stretch;
|
||||
margin: 8px 0;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
&-input-area {
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
&-title {
|
||||
@@ -42,9 +41,11 @@
|
||||
|
||||
&-error {
|
||||
color: white;
|
||||
background-color: rgba(229, 75, 75, 0.5);
|
||||
background-color: rgba(225, 45, 45, 0.6);
|
||||
border-radius: 3px;
|
||||
width: 100%;
|
||||
padding: 3px;
|
||||
padding: 2px;
|
||||
box-sizing: border-box;
|
||||
margin-top: 4px;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
@@ -58,84 +59,18 @@
|
||||
}
|
||||
|
||||
.prejoin-preview {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
|
||||
&--no-video {
|
||||
background: radial-gradient(50% 50% at 50% 50%, #5B6F80 0%, #365067 100%), #FFFFFF;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&-video {
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-name {
|
||||
color: #fff;
|
||||
font-size: 19px;
|
||||
line-height: 28px;
|
||||
|
||||
&--editable {
|
||||
background: none;
|
||||
border: 0;
|
||||
border-bottom: 1px solid #D1DBE8;
|
||||
margin: 24px 0 16px 0;
|
||||
outline: none;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
|
||||
&::-webkit-input-placeholder {
|
||||
@include name-placeholder;
|
||||
}
|
||||
&::-moz-placeholder {
|
||||
@include name-placeholder;
|
||||
}
|
||||
&:-ms-input-placeholder {
|
||||
@include name-placeholder;
|
||||
}
|
||||
}
|
||||
|
||||
&--text {
|
||||
margin: 16px 0;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-avatar.avatar {
|
||||
background: #A4B8D1;
|
||||
margin: 200px auto 0 auto;
|
||||
}
|
||||
|
||||
&-overlay {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
background: linear-gradient(0deg, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.3));
|
||||
}
|
||||
|
||||
&-bottom-overlay {
|
||||
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.9) 100%);
|
||||
bottom: 0;
|
||||
height: 50%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&-status {
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
bottom: 0;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
font-size: 13px;
|
||||
min-height: 24px;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
|
||||
&--warning {
|
||||
|
||||
@@ -12,12 +12,23 @@
|
||||
|
||||
.premeeting-screen {
|
||||
align-items: stretch;
|
||||
background: radial-gradient(50% 50% at 50% 50%, #5D95C7 0%, #376288 100%), #FFFFFF;
|
||||
background: radial-gradient(50% 50% at 50% 50%, #2A3A4B 20.83%, #1E2A36 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 1.3em;
|
||||
z-index: $toolbarZ + 1;
|
||||
|
||||
&-avatar {
|
||||
background-color: #A4B8D1;
|
||||
margin-bottom: 24px;
|
||||
|
||||
text {
|
||||
fill: black;
|
||||
font-size: 26px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
border-radius: 3px;
|
||||
color: #fff;
|
||||
@@ -59,22 +70,26 @@
|
||||
fill: #AFB6BC;
|
||||
}
|
||||
}
|
||||
|
||||
.options {
|
||||
border-left: 1px solid #AFB6BC;
|
||||
}
|
||||
}
|
||||
|
||||
.options {
|
||||
border-radius: 3px;
|
||||
align-items: center;
|
||||
border-left: 1px solid #fff;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 40px;
|
||||
width: 36px;
|
||||
|
||||
&:hover {
|
||||
background-color: #0262B6;
|
||||
}
|
||||
|
||||
svg {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +104,7 @@
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
padding-bottom: 24px;
|
||||
z-index: $toolbarZ + 2;
|
||||
|
||||
.title {
|
||||
@@ -111,12 +127,14 @@
|
||||
margin-bottom: 16px;
|
||||
|
||||
.url {
|
||||
background: rgba(28, 32, 37, 0.5);
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
padding: 8px 10px;
|
||||
transition: background 0.16s ease-out;
|
||||
|
||||
&:hover {
|
||||
background: #1C2025;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&.done {
|
||||
@@ -149,20 +167,23 @@
|
||||
}
|
||||
|
||||
input.field {
|
||||
background-color: transparent;
|
||||
border: 1px solid transparent;
|
||||
color: white;
|
||||
outline-width: 0;
|
||||
background-color: white;
|
||||
border: none;
|
||||
outline: none;
|
||||
border-radius: 3px;
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
color: #1C2025;
|
||||
padding: 8px 0;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
width: 320px;
|
||||
|
||||
&.focused {
|
||||
border-bottom: 1px solid white;
|
||||
&.error {
|
||||
box-shadow: 0px 0px 4px 3px rgba(225, 45, 45, 0.4);
|
||||
}
|
||||
|
||||
&.error::placeholder {
|
||||
color: $defaultWarningColor;
|
||||
&.focused {
|
||||
box-shadow: 0px 0px 4px 3px #0376DA;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,7 +191,7 @@
|
||||
.media-btn-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 32px 0;
|
||||
margin: 24px 0 16px 0;
|
||||
width: 100%;
|
||||
|
||||
&> div {
|
||||
@@ -233,6 +254,7 @@
|
||||
font-size: 13px;
|
||||
height: 40px;
|
||||
margin: 0 auto;
|
||||
transition: background 0.16s ease-out;
|
||||
width: 320px;
|
||||
|
||||
@include flex-centered();
|
||||
@@ -242,7 +264,7 @@
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #1C2025;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
|
||||
@include icon-container(#A4B8D1, #1C2025);
|
||||
}
|
||||
@@ -261,14 +283,6 @@
|
||||
}
|
||||
|
||||
&--toggled {
|
||||
background: #75757A;
|
||||
|
||||
&:hover {
|
||||
background: #75757A;
|
||||
|
||||
@include icon-container(#A4B8D1, #75757A);
|
||||
}
|
||||
|
||||
@include icon-container(#A4B8D1, #75757A);
|
||||
@include icon-container(white, #1C2025);
|
||||
}
|
||||
}
|
||||
|
||||
5
debian/jitsi-meet-turnserver.postinst
vendored
5
debian/jitsi-meet-turnserver.postinst
vendored
@@ -150,11 +150,6 @@ denied-peer-ip=240.0.0.0-255.255.255.255" >> $TURN_CONFIG
|
||||
echo "------------------------------------------------"
|
||||
fi
|
||||
|
||||
# Enable turn server in config.js
|
||||
if [ -f $JITSI_MEET_CONFIG ] ; then
|
||||
sed -i "s/\/\/ useStunTurn: true/useStunTurn: true/g" $JITSI_MEET_CONFIG
|
||||
fi
|
||||
|
||||
# and we're done with debconf
|
||||
db_stop
|
||||
;;
|
||||
|
||||
2
debian/jitsi-meet-web.install
vendored
2
debian/jitsi-meet-web.install
vendored
@@ -13,3 +13,5 @@ lang /usr/share/jitsi-meet/
|
||||
connection_optimization /usr/share/jitsi-meet/
|
||||
resources/robots.txt /usr/share/jitsi-meet/
|
||||
resources/*.sh /usr/share/jitsi-meet/scripts/
|
||||
pwa-worker.js /usr/share/jitsi-meet/
|
||||
manifest.json /usr/share/jitsi-meet/
|
||||
|
||||
13
flow-typed/npm/react-redux_v7.x.x.js
vendored
13
flow-typed/npm/react-redux_v7.x.x.js
vendored
@@ -1,5 +1,5 @@
|
||||
// flow-typed signature: d2ddacbbca9700881249a9435381e689
|
||||
// flow-typed version: c6154227d1/react-redux_v7.x.x/flow_>=v0.89.x <=v0.103.x
|
||||
// flow-typed signature: 8da1e134b3de1d6f6bf9ba1cc7e2dc7e
|
||||
// flow-typed version: 387a235736/react-redux_v7.x.x/flow_>=v0.104.x
|
||||
|
||||
/**
|
||||
The order of type arguments for connect() is as follows:
|
||||
@@ -219,6 +219,7 @@ declare module "react-redux" {
|
||||
declare export class Provider<Store> extends React$Component<{
|
||||
store: Store,
|
||||
children?: React$Node,
|
||||
...
|
||||
}> {}
|
||||
|
||||
declare export function createProvider(
|
||||
@@ -237,6 +238,7 @@ declare module "react-redux" {
|
||||
shouldHandleStateChanges?: boolean,
|
||||
storeKey?: string,
|
||||
forwardRef?: boolean,
|
||||
...
|
||||
};
|
||||
|
||||
declare type SelectorFactoryOptions<Com> = {
|
||||
@@ -249,6 +251,7 @@ declare module "react-redux" {
|
||||
displayName: string,
|
||||
wrappedComponentName: string,
|
||||
WrappedComponent: Com,
|
||||
...
|
||||
};
|
||||
|
||||
declare type MapStateToPropsEx<S: Object, SP: Object, RSP: Object> = (
|
||||
@@ -275,12 +278,14 @@ declare module "react-redux" {
|
||||
OP: Object,
|
||||
CP: Object,
|
||||
EFO: Object,
|
||||
ST: { [_: $Keys<Com>]: any },
|
||||
ST: { [_: $Keys<Com>]: any, ... },
|
||||
>(
|
||||
selectorFactory: SelectorFactory<Com, D, S, OP, EFO, CP>,
|
||||
connectAdvancedOptions: ?(ConnectAdvancedOptions & EFO),
|
||||
): (component: Com) => React$ComponentType<OP> & $Shape<ST>;
|
||||
|
||||
declare export function batch(() => void): void
|
||||
|
||||
declare export default {
|
||||
Provider: typeof Provider,
|
||||
createProvider: typeof createProvider,
|
||||
@@ -289,5 +294,7 @@ declare module "react-redux" {
|
||||
useDispatch: typeof useDispatch,
|
||||
useSelector: typeof useSelector,
|
||||
useStore: typeof useStore,
|
||||
batch: typeof batch,
|
||||
...
|
||||
};
|
||||
}
|
||||
|
||||
26
index.html
26
index.html
@@ -4,11 +4,18 @@
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="theme-color" content="#2A3A4B">
|
||||
<!--#include virtual="base.html" -->
|
||||
|
||||
<link rel="apple-touch-icon" href="images/apple-touch-icon.png">
|
||||
<link rel="stylesheet" href="css/all.css">
|
||||
<link rel="manifest" id="manifest-placeholder">
|
||||
|
||||
<script>
|
||||
// Dynamically generate the manifest location URL. It must be served from the document origin, and we may have
|
||||
// the base pointing to the CDN. This way we can generate a full URL which will bypass the base.
|
||||
document.querySelector('#manifest-placeholder').setAttribute('href', window.location.origin + '/manifest.json');
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
if (!JitsiMeetJS.app) {
|
||||
return;
|
||||
@@ -17,7 +24,21 @@
|
||||
JitsiMeetJS.app.renderEntryPoint({
|
||||
Component: JitsiMeetJS.app.entryPoints.APP
|
||||
})
|
||||
})
|
||||
|
||||
const isElectron = navigator.userAgent.includes('Electron');
|
||||
const shouldRegisterWorker = !isElectron && 'serviceWorker' in navigator;
|
||||
|
||||
if (shouldRegisterWorker) {
|
||||
navigator.serviceWorker
|
||||
.register(window.location.origin + '/pwa-worker.js')
|
||||
.then(reg => {
|
||||
console.log('Service worker registered.', reg);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
// IE11 and earlier can be identified via their user agent and be
|
||||
@@ -164,6 +185,9 @@
|
||||
<!--#include virtual="static/settingsToolbarAdditionalContent.html" -->
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<div>JavaScript is disabled. </br>For this site to work you have to enable JavaScript.</div>
|
||||
</noscript>
|
||||
<!--#include virtual="body.html" -->
|
||||
<div id="react"></div>
|
||||
</body>
|
||||
|
||||
@@ -66,6 +66,7 @@ target 'JitsiMeet' do
|
||||
pod 'RNSVG', :path => '../node_modules/react-native-svg'
|
||||
pod 'RNWatch', :path => '../node_modules/react-native-watch-connectivity'
|
||||
pod 'RNDefaultPreference', :path => '../node_modules/react-native-default-preference'
|
||||
pod 'react-native-splash-screen', :path => '../node_modules/react-native-splash-screen'
|
||||
|
||||
# Native pod dependencies
|
||||
#
|
||||
|
||||
346
ios/Podfile.lock
346
ios/Podfile.lock
@@ -12,14 +12,14 @@ PODS:
|
||||
- CocoaLumberjack/Core (= 3.5.3)
|
||||
- CocoaLumberjack/Core (3.5.3)
|
||||
- DoubleConversion (1.1.6)
|
||||
- FBLazyVector (0.61.5-jitsi.1)
|
||||
- FBReactNativeSpec (0.61.5-jitsi.1):
|
||||
- FBLazyVector (0.61.5-jitsi.2)
|
||||
- FBReactNativeSpec (0.61.5-jitsi.2):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- RCTRequired (= 0.61.5-jitsi.1)
|
||||
- RCTTypeSafety (= 0.61.5-jitsi.1)
|
||||
- React-Core (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- ReactCommon/turbomodule/core (= 0.61.5-jitsi.1)
|
||||
- RCTRequired (= 0.61.5-jitsi.2)
|
||||
- RCTTypeSafety (= 0.61.5-jitsi.2)
|
||||
- React-Core (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- ReactCommon/turbomodule/core (= 0.61.5-jitsi.2)
|
||||
- Firebase/Analytics (6.33.0):
|
||||
- Firebase/Core
|
||||
- Firebase/Core (6.33.0):
|
||||
@@ -120,169 +120,169 @@ PODS:
|
||||
- nanopb/encode (1.30906.0)
|
||||
- ObjectiveDropboxOfficial (3.9.4)
|
||||
- PromisesObjC (1.2.10)
|
||||
- RCTRequired (0.61.5-jitsi.1)
|
||||
- RCTTypeSafety (0.61.5-jitsi.1):
|
||||
- FBLazyVector (= 0.61.5-jitsi.1)
|
||||
- RCTRequired (0.61.5-jitsi.2)
|
||||
- RCTTypeSafety (0.61.5-jitsi.2):
|
||||
- FBLazyVector (= 0.61.5-jitsi.2)
|
||||
- Folly (= 2018.10.22.00)
|
||||
- RCTRequired (= 0.61.5-jitsi.1)
|
||||
- React-Core (= 0.61.5-jitsi.1)
|
||||
- React (0.61.5-jitsi.1):
|
||||
- React-Core (= 0.61.5-jitsi.1)
|
||||
- React-Core/DevSupport (= 0.61.5-jitsi.1)
|
||||
- React-Core/RCTWebSocket (= 0.61.5-jitsi.1)
|
||||
- React-RCTActionSheet (= 0.61.5-jitsi.1)
|
||||
- React-RCTAnimation (= 0.61.5-jitsi.1)
|
||||
- React-RCTBlob (= 0.61.5-jitsi.1)
|
||||
- React-RCTImage (= 0.61.5-jitsi.1)
|
||||
- React-RCTLinking (= 0.61.5-jitsi.1)
|
||||
- React-RCTNetwork (= 0.61.5-jitsi.1)
|
||||
- React-RCTSettings (= 0.61.5-jitsi.1)
|
||||
- React-RCTText (= 0.61.5-jitsi.1)
|
||||
- React-RCTVibration (= 0.61.5-jitsi.1)
|
||||
- React-Core (0.61.5-jitsi.1):
|
||||
- RCTRequired (= 0.61.5-jitsi.2)
|
||||
- React-Core (= 0.61.5-jitsi.2)
|
||||
- React (0.61.5-jitsi.2):
|
||||
- React-Core (= 0.61.5-jitsi.2)
|
||||
- React-Core/DevSupport (= 0.61.5-jitsi.2)
|
||||
- React-Core/RCTWebSocket (= 0.61.5-jitsi.2)
|
||||
- React-RCTActionSheet (= 0.61.5-jitsi.2)
|
||||
- React-RCTAnimation (= 0.61.5-jitsi.2)
|
||||
- React-RCTBlob (= 0.61.5-jitsi.2)
|
||||
- React-RCTImage (= 0.61.5-jitsi.2)
|
||||
- React-RCTLinking (= 0.61.5-jitsi.2)
|
||||
- React-RCTNetwork (= 0.61.5-jitsi.2)
|
||||
- React-RCTSettings (= 0.61.5-jitsi.2)
|
||||
- React-RCTText (= 0.61.5-jitsi.2)
|
||||
- React-RCTVibration (= 0.61.5-jitsi.2)
|
||||
- React-Core (0.61.5-jitsi.2):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core/Default (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.1)
|
||||
- React-Core/Default (= 0.61.5-jitsi.2)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.2)
|
||||
- Yoga
|
||||
- React-Core/CoreModulesHeaders (0.61.5-jitsi.1):
|
||||
- React-Core/CoreModulesHeaders (0.61.5-jitsi.2):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.2)
|
||||
- Yoga
|
||||
- React-Core/Default (0.61.5-jitsi.1):
|
||||
- React-Core/Default (0.61.5-jitsi.2):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.2)
|
||||
- Yoga
|
||||
- React-Core/DevSupport (0.61.5-jitsi.1):
|
||||
- React-Core/DevSupport (0.61.5-jitsi.2):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core/Default (= 0.61.5-jitsi.1)
|
||||
- React-Core/RCTWebSocket (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.1)
|
||||
- React-jsinspector (= 0.61.5-jitsi.1)
|
||||
- React-Core/Default (= 0.61.5-jitsi.2)
|
||||
- React-Core/RCTWebSocket (= 0.61.5-jitsi.2)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.2)
|
||||
- React-jsinspector (= 0.61.5-jitsi.2)
|
||||
- Yoga
|
||||
- React-Core/RCTActionSheetHeaders (0.61.5-jitsi.1):
|
||||
- React-Core/RCTActionSheetHeaders (0.61.5-jitsi.2):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.2)
|
||||
- Yoga
|
||||
- React-Core/RCTAnimationHeaders (0.61.5-jitsi.1):
|
||||
- React-Core/RCTAnimationHeaders (0.61.5-jitsi.2):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.2)
|
||||
- Yoga
|
||||
- React-Core/RCTBlobHeaders (0.61.5-jitsi.1):
|
||||
- React-Core/RCTBlobHeaders (0.61.5-jitsi.2):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.2)
|
||||
- Yoga
|
||||
- React-Core/RCTImageHeaders (0.61.5-jitsi.1):
|
||||
- React-Core/RCTImageHeaders (0.61.5-jitsi.2):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.2)
|
||||
- Yoga
|
||||
- React-Core/RCTLinkingHeaders (0.61.5-jitsi.1):
|
||||
- React-Core/RCTLinkingHeaders (0.61.5-jitsi.2):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.2)
|
||||
- Yoga
|
||||
- React-Core/RCTNetworkHeaders (0.61.5-jitsi.1):
|
||||
- React-Core/RCTNetworkHeaders (0.61.5-jitsi.2):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.2)
|
||||
- Yoga
|
||||
- React-Core/RCTSettingsHeaders (0.61.5-jitsi.1):
|
||||
- React-Core/RCTSettingsHeaders (0.61.5-jitsi.2):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.2)
|
||||
- Yoga
|
||||
- React-Core/RCTTextHeaders (0.61.5-jitsi.1):
|
||||
- React-Core/RCTTextHeaders (0.61.5-jitsi.2):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.2)
|
||||
- Yoga
|
||||
- React-Core/RCTVibrationHeaders (0.61.5-jitsi.1):
|
||||
- React-Core/RCTVibrationHeaders (0.61.5-jitsi.2):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.2)
|
||||
- Yoga
|
||||
- React-Core/RCTWebSocket (0.61.5-jitsi.1):
|
||||
- React-Core/RCTWebSocket (0.61.5-jitsi.2):
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core/Default (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.1)
|
||||
- React-Core/Default (= 0.61.5-jitsi.2)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-jsiexecutor (= 0.61.5-jitsi.2)
|
||||
- Yoga
|
||||
- React-CoreModules (0.61.5-jitsi.1):
|
||||
- FBReactNativeSpec (= 0.61.5-jitsi.1)
|
||||
- React-CoreModules (0.61.5-jitsi.2):
|
||||
- FBReactNativeSpec (= 0.61.5-jitsi.2)
|
||||
- Folly (= 2018.10.22.00)
|
||||
- RCTTypeSafety (= 0.61.5-jitsi.1)
|
||||
- React-Core/CoreModulesHeaders (= 0.61.5-jitsi.1)
|
||||
- React-RCTImage (= 0.61.5-jitsi.1)
|
||||
- ReactCommon/turbomodule/core (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (0.61.5-jitsi.1):
|
||||
- RCTTypeSafety (= 0.61.5-jitsi.2)
|
||||
- React-Core/CoreModulesHeaders (= 0.61.5-jitsi.2)
|
||||
- React-RCTImage (= 0.61.5-jitsi.2)
|
||||
- ReactCommon/turbomodule/core (= 0.61.5-jitsi.2)
|
||||
- React-cxxreact (0.61.5-jitsi.2):
|
||||
- boost-for-react-native (= 1.63.0)
|
||||
- DoubleConversion
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-jsinspector (= 0.61.5-jitsi.1)
|
||||
- React-jsi (0.61.5-jitsi.1):
|
||||
- React-jsinspector (= 0.61.5-jitsi.2)
|
||||
- React-jsi (0.61.5-jitsi.2):
|
||||
- boost-for-react-native (= 1.63.0)
|
||||
- DoubleConversion
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-jsi/Default (= 0.61.5-jitsi.1)
|
||||
- React-jsi/Default (0.61.5-jitsi.1):
|
||||
- React-jsi/Default (= 0.61.5-jitsi.2)
|
||||
- React-jsi/Default (0.61.5-jitsi.2):
|
||||
- boost-for-react-native (= 1.63.0)
|
||||
- DoubleConversion
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-jsiexecutor (0.61.5-jitsi.1):
|
||||
- React-jsiexecutor (0.61.5-jitsi.2):
|
||||
- DoubleConversion
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-jsinspector (0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-jsinspector (0.61.5-jitsi.2)
|
||||
- react-native-background-timer (2.4.0):
|
||||
- React
|
||||
- react-native-calendar-events (2.0.0):
|
||||
@@ -291,64 +291,66 @@ PODS:
|
||||
- React
|
||||
- react-native-netinfo (4.1.5):
|
||||
- React
|
||||
- react-native-webrtc (1.84.0):
|
||||
- react-native-splash-screen (3.2.0):
|
||||
- React
|
||||
- react-native-webrtc (1.84.1):
|
||||
- React-Core
|
||||
- react-native-webview (10.9.0):
|
||||
- React
|
||||
- React-RCTActionSheet (0.61.5-jitsi.1):
|
||||
- React-Core/RCTActionSheetHeaders (= 0.61.5-jitsi.1)
|
||||
- React-RCTAnimation (0.61.5-jitsi.1):
|
||||
- React-Core/RCTAnimationHeaders (= 0.61.5-jitsi.1)
|
||||
- React-RCTBlob (0.61.5-jitsi.1):
|
||||
- React-Core/RCTBlobHeaders (= 0.61.5-jitsi.1)
|
||||
- React-Core/RCTWebSocket (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- React-RCTNetwork (= 0.61.5-jitsi.1)
|
||||
- React-RCTImage (0.61.5-jitsi.1):
|
||||
- React-Core/RCTImageHeaders (= 0.61.5-jitsi.1)
|
||||
- React-RCTNetwork (= 0.61.5-jitsi.1)
|
||||
- React-RCTLinking (0.61.5-jitsi.1):
|
||||
- React-Core/RCTLinkingHeaders (= 0.61.5-jitsi.1)
|
||||
- React-RCTNetwork (0.61.5-jitsi.1):
|
||||
- React-Core/RCTNetworkHeaders (= 0.61.5-jitsi.1)
|
||||
- React-RCTSettings (0.61.5-jitsi.1):
|
||||
- React-Core/RCTSettingsHeaders (= 0.61.5-jitsi.1)
|
||||
- React-RCTText (0.61.5-jitsi.1):
|
||||
- React-Core/RCTTextHeaders (= 0.61.5-jitsi.1)
|
||||
- React-RCTVibration (0.61.5-jitsi.1):
|
||||
- React-Core/RCTVibrationHeaders (= 0.61.5-jitsi.1)
|
||||
- ReactCommon/jscallinvoker (0.61.5-jitsi.1):
|
||||
- React-RCTActionSheet (0.61.5-jitsi.2):
|
||||
- React-Core/RCTActionSheetHeaders (= 0.61.5-jitsi.2)
|
||||
- React-RCTAnimation (0.61.5-jitsi.2):
|
||||
- React-Core/RCTAnimationHeaders (= 0.61.5-jitsi.2)
|
||||
- React-RCTBlob (0.61.5-jitsi.2):
|
||||
- React-Core/RCTBlobHeaders (= 0.61.5-jitsi.2)
|
||||
- React-Core/RCTWebSocket (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- React-RCTNetwork (= 0.61.5-jitsi.2)
|
||||
- React-RCTImage (0.61.5-jitsi.2):
|
||||
- React-Core/RCTImageHeaders (= 0.61.5-jitsi.2)
|
||||
- React-RCTNetwork (= 0.61.5-jitsi.2)
|
||||
- React-RCTLinking (0.61.5-jitsi.2):
|
||||
- React-Core/RCTLinkingHeaders (= 0.61.5-jitsi.2)
|
||||
- React-RCTNetwork (0.61.5-jitsi.2):
|
||||
- React-Core/RCTNetworkHeaders (= 0.61.5-jitsi.2)
|
||||
- React-RCTSettings (0.61.5-jitsi.2):
|
||||
- React-Core/RCTSettingsHeaders (= 0.61.5-jitsi.2)
|
||||
- React-RCTText (0.61.5-jitsi.2):
|
||||
- React-Core/RCTTextHeaders (= 0.61.5-jitsi.2)
|
||||
- React-RCTVibration (0.61.5-jitsi.2):
|
||||
- React-Core/RCTVibrationHeaders (= 0.61.5-jitsi.2)
|
||||
- ReactCommon/jscallinvoker (0.61.5-jitsi.2):
|
||||
- DoubleConversion
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- ReactCommon/turbomodule (0.61.5-jitsi.1):
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- ReactCommon/turbomodule (0.61.5-jitsi.2):
|
||||
- DoubleConversion
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- ReactCommon/jscallinvoker (= 0.61.5-jitsi.1)
|
||||
- ReactCommon/turbomodule/core (= 0.61.5-jitsi.1)
|
||||
- ReactCommon/turbomodule/samples (= 0.61.5-jitsi.1)
|
||||
- ReactCommon/turbomodule/core (0.61.5-jitsi.1):
|
||||
- React-Core (= 0.61.5-jitsi.2)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- ReactCommon/jscallinvoker (= 0.61.5-jitsi.2)
|
||||
- ReactCommon/turbomodule/core (= 0.61.5-jitsi.2)
|
||||
- ReactCommon/turbomodule/samples (= 0.61.5-jitsi.2)
|
||||
- ReactCommon/turbomodule/core (0.61.5-jitsi.2):
|
||||
- DoubleConversion
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- ReactCommon/jscallinvoker (= 0.61.5-jitsi.1)
|
||||
- ReactCommon/turbomodule/samples (0.61.5-jitsi.1):
|
||||
- React-Core (= 0.61.5-jitsi.2)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- ReactCommon/jscallinvoker (= 0.61.5-jitsi.2)
|
||||
- ReactCommon/turbomodule/samples (0.61.5-jitsi.2):
|
||||
- DoubleConversion
|
||||
- Folly (= 2018.10.22.00)
|
||||
- glog
|
||||
- React-Core (= 0.61.5-jitsi.1)
|
||||
- React-cxxreact (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- ReactCommon/jscallinvoker (= 0.61.5-jitsi.1)
|
||||
- ReactCommon/turbomodule/core (= 0.61.5-jitsi.1)
|
||||
- React-Core (= 0.61.5-jitsi.2)
|
||||
- React-cxxreact (= 0.61.5-jitsi.2)
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- ReactCommon/jscallinvoker (= 0.61.5-jitsi.2)
|
||||
- ReactCommon/turbomodule/core (= 0.61.5-jitsi.2)
|
||||
- RNCAsyncStorage (1.3.4):
|
||||
- React
|
||||
- RNDefaultPreference (1.4.2):
|
||||
@@ -361,7 +363,7 @@ PODS:
|
||||
- RNSound/Core (= 0.11.0)
|
||||
- RNSound/Core (0.11.0):
|
||||
- React
|
||||
- RNSVG (9.7.1):
|
||||
- RNSVG (10.1.0):
|
||||
- React
|
||||
- RNWatch (0.4.3):
|
||||
- React
|
||||
@@ -395,6 +397,7 @@ DEPENDENCIES:
|
||||
- react-native-calendar-events (from `../node_modules/react-native-calendar-events`)
|
||||
- react-native-keep-awake (from `../node_modules/react-native-keep-awake`)
|
||||
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
|
||||
- react-native-splash-screen (from `../node_modules/react-native-splash-screen`)
|
||||
- react-native-webrtc (from `../node_modules/react-native-webrtc`)
|
||||
- react-native-webview (from `../node_modules/react-native-webview`)
|
||||
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
|
||||
@@ -477,6 +480,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native-keep-awake"
|
||||
react-native-netinfo:
|
||||
:path: "../node_modules/@react-native-community/netinfo"
|
||||
react-native-splash-screen:
|
||||
:path: "../node_modules/react-native-splash-screen"
|
||||
react-native-webrtc:
|
||||
:path: "../node_modules/react-native-webrtc"
|
||||
react-native-webview:
|
||||
@@ -523,8 +528,8 @@ SPEC CHECKSUMS:
|
||||
BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872
|
||||
CocoaLumberjack: 2f44e60eb91c176d471fdba43b9e3eae6a721947
|
||||
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
|
||||
FBLazyVector: 4a5251159a3ed05dc11cc8b74cf937869935814b
|
||||
FBReactNativeSpec: 6fa602a20993212cc9877a81838578ffb0008bc9
|
||||
FBLazyVector: ca7f56c8ff6cd8590f7a673d7903b06019805581
|
||||
FBReactNativeSpec: 8136c3cf27de2bb310a69cffbb423c5643f5c1c4
|
||||
Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5
|
||||
FirebaseAnalytics: 5dd088bd2e67bb9d13dbf792d1164ceaf3052193
|
||||
FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd
|
||||
@@ -543,39 +548,40 @@ SPEC CHECKSUMS:
|
||||
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
|
||||
ObjectiveDropboxOfficial: a5afefc83f6467c42c45f2253f583f2ad1ffc701
|
||||
PromisesObjC: b14b1c6b68e306650688599de8a45e49fae81151
|
||||
RCTRequired: f63dd90a89a60602acdd44c42e5d2645ca60ab79
|
||||
RCTTypeSafety: 24a3c6d55684046ed550b1d0ef083a9bf71c8bd4
|
||||
React: 71c5a51135f291c3b32c0b558e167b858ae50e84
|
||||
React-Core: e82c03ff91062abf963f35bf99a357154e570285
|
||||
React-CoreModules: e236aeecd18cec37743c8c50562431db5302f668
|
||||
React-cxxreact: 526ec106aa1bf2b3f6aab2a7d528d1d23d5f59c2
|
||||
React-jsi: 4f35c1a2273d193a80c1c3831c808413840c260c
|
||||
React-jsiexecutor: de1c37cf59ae9adcbf2be82eea0e090dc3f3205e
|
||||
React-jsinspector: b76c4e84a7833bb4c90549d59ed53ec299ff912b
|
||||
RCTRequired: a686731276578c125dff205f08b6ec9cee6ede32
|
||||
RCTTypeSafety: 88e5500e801c00d16a3d1895e3470d13beed6584
|
||||
React: 8b2bcf6a93846e47a7a365a54ec6edeb78b37701
|
||||
React-Core: 3fbdbc87c18c4742b735ff9a0c02fa38c87e0fba
|
||||
React-CoreModules: f6f8a8212aec52a21251c0af58bdb037b57c70b3
|
||||
React-cxxreact: c6ad34143db06a5c3cb0e8e169c775475287ac9c
|
||||
React-jsi: ddb471a56185e4007835a1bba0882ecb5ce3dc0e
|
||||
React-jsiexecutor: 67106691c60030ec888d7cbbc4f48a3168e27a02
|
||||
React-jsinspector: 92ceee6c66dc19886289b52436ade7e020b89602
|
||||
react-native-background-timer: e0384ea2fa5a98f67f84f9c4dc274260ddd674ed
|
||||
react-native-calendar-events: 1442fad71a00388f933cfa25512588fec300fcf8
|
||||
react-native-keep-awake: eba3137546b10003361b37c761f6c429b59814ae
|
||||
react-native-netinfo: 8d8db463bcc5db66a8ac5c48a7d86beb3b92f61a
|
||||
react-native-webrtc: 9268ae9a2bc9730796b0968d012327e92c392adf
|
||||
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
|
||||
react-native-webrtc: edd689b0d5a462d7a6f6f52bca3f9414fc0ee11c
|
||||
react-native-webview: 6ee7868ca8eba635dbf7963986d1ab7959da0391
|
||||
React-RCTActionSheet: b72ddbfbe15b44ce691d128e4b582f4bb9abb540
|
||||
React-RCTAnimation: cfaefba5024499d336b76ab850e6bd33b232b5e3
|
||||
React-RCTBlob: c427e643bef82999deeab97489ba43298ecfbe24
|
||||
React-RCTImage: 79934bc96f3349da6a75b1d61cad594a932e4097
|
||||
React-RCTLinking: 12b153399567c30efac0b32bb00f9c064587dc26
|
||||
React-RCTNetwork: 603ad75778a54521b7797fd07c67dff562317526
|
||||
React-RCTSettings: 8d45fcf14513582539ea1ddea69391207de7f046
|
||||
React-RCTText: b4c29897c3df0c9f112e29aa3167fa6caf40b690
|
||||
React-RCTVibration: a1bcfcdc0b5a73a1b0829a34cee22bd0e95bacba
|
||||
ReactCommon: 675681aba4fecff5acbc0e440530cc422103c610
|
||||
React-RCTActionSheet: bcbc311dc3b47bc8efb2737ff0940239a45789a9
|
||||
React-RCTAnimation: 65f61080ce632f6dea23d52e354ffac9948396c6
|
||||
React-RCTBlob: 70d88f7b68b5c44953cdb286ac2e36a7a509a97e
|
||||
React-RCTImage: e0d25b620e42de91ed791ef129e2d3a0df1eb5ab
|
||||
React-RCTLinking: bc2287cfd9e56403ecea5dafdbdac8c57fa1ac36
|
||||
React-RCTNetwork: cd8ae8fc787c02ed5152fe9cbf7521ee70c1bce7
|
||||
React-RCTSettings: f6667271ccd8876a934134b73002b5a2714e1525
|
||||
React-RCTText: 4f1b99f228278d2a5e9008eced8dc9c974c4a270
|
||||
React-RCTVibration: c1041024893fdfdb8371e7c720c437751b711676
|
||||
ReactCommon: 18014e1d98dbeb9141e935cfe35fc93bd511ffb6
|
||||
RNCAsyncStorage: 8e31405a9f12fbf42c2bb330e4560bfd79c18323
|
||||
RNDefaultPreference: 56a405ce61033ac77b95004dccd7ac54c2eb50d1
|
||||
RNGoogleSignin: 39336070b35fc4cea6a98cf111e00480317be0ae
|
||||
RNSound: c980916b596cc15c8dcd2f6ecd3b13c4881dbe20
|
||||
RNSVG: aac12785382e8fd4f28d072fe640612e34914631
|
||||
RNSVG: 069864be08c9fe065a2cf7e63656a34c78653c99
|
||||
RNWatch: a5320c959c75e72845c07985f3e935e58998f1d3
|
||||
Yoga: 7b4209fda2441f99d54dd6cf4c82b094409bb68f
|
||||
Yoga: 96b469c5e81ff51b917b92e8c3390642d4ded30c
|
||||
|
||||
PODFILE CHECKSUM: 224e84629bf45ae487c4ebc66faf33ec8304fb67
|
||||
PODFILE CHECKSUM: f2400f8e5a52c4d91697cbacba6956569efc5ab8
|
||||
|
||||
COCOAPODS: 1.9.3
|
||||
|
||||
@@ -53,6 +53,9 @@
|
||||
[[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:![jitsiMeet isCrashReportingDisabled]];
|
||||
}
|
||||
|
||||
ViewController *rootController = (ViewController *)self.window.rootViewController;
|
||||
[jitsiMeet showSplashScreen:rootController.view];
|
||||
|
||||
[jitsiMeet application:application didFinishLaunchingWithOptions:launchOptions];
|
||||
|
||||
return YES;
|
||||
|
||||
@@ -67,4 +67,6 @@
|
||||
|
||||
- (BOOL)isCrashReportingDisabled;
|
||||
|
||||
- (void)showSplashScreen:(UIView * _Nonnull) rootView;
|
||||
|
||||
@end
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#import "JitsiMeetView+Private.h"
|
||||
#import "RCTBridgeWrapper.h"
|
||||
#import "ReactUtils.h"
|
||||
#import "RNSplashScreen.h"
|
||||
|
||||
#import <RNGoogleSignin/RNGoogleSignin.h>
|
||||
#import <WebRTC/RTCLogging.h>
|
||||
@@ -183,6 +184,10 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)showSplashScreen:(UIView*)rootView {
|
||||
[RNSplashScreen showSplash:@"LaunchScreen" inRootView:rootView];
|
||||
}
|
||||
|
||||
#pragma mark - Property getter / setters
|
||||
|
||||
- (NSArray<NSString *> *)universalLinkDomains {
|
||||
|
||||
@@ -730,7 +730,7 @@
|
||||
"stopScreenSharing": "Arrêter le partage d'écran",
|
||||
"stopSubtitles": "Désactiver les sous-titres",
|
||||
"stopSharedVideo": "Arrêter la vidéo YouTube",
|
||||
"talkWhileMutedPopup": "Vous voulez parler ? Vôtre micro est coupé.",
|
||||
"talkWhileMutedPopup": "Vous voulez parler ? Votre micro est coupé.",
|
||||
"tileViewToggle": "Activer/désactiver la vue mosaïque",
|
||||
"toggleCamera": "Changer de caméra",
|
||||
"videomute": "Démarrer / Arrêter la caméra",
|
||||
@@ -769,7 +769,7 @@
|
||||
"errorAlreadyInvited": "{{displayName}} est déjà invité(e)",
|
||||
"errorInvite": "La conférence n'est pas encore établie. Veuillez réessayer plus tard.",
|
||||
"errorInviteFailed": "Nous tentons de résoudre le problème. Veuillez réessayer plus tard.",
|
||||
"errorInviteFailedTitle": "l'invitation de {{displayName}} a échoué",
|
||||
"errorInviteFailedTitle": "L'invitation de {{displayName}} a échoué",
|
||||
"errorInviteTitle": "Erreur lors de l'invitation",
|
||||
"pending": "{{displayName}} a été invité(e)"
|
||||
},
|
||||
@@ -809,7 +809,7 @@
|
||||
"join": "Touchez pour rejoindre",
|
||||
"roomname": "Saisissez un nom de salle"
|
||||
},
|
||||
"appDescription": "Foncez tchater en vidéo avec toute le monde. En fait, vous pouvez inviter tout ceux que vous connaissez. {{app}} est une solution de visioconférence entièrement chiffrée et 100% libre que vous pouvez utiliser en permanence, chaque jours, et sans aucun compte requis.",
|
||||
"appDescription": "Foncez tchater en vidéo avec toute le monde. En fait, vous pouvez inviter tout ceux que vous connaissez. {{app}} est une solution de visioconférence entièrement chiffrée et 100% libre que vous pouvez utiliser en permanence, chaque jour, et sans aucun compte requis.",
|
||||
"audioVideoSwitch": {
|
||||
"audio": "Voix",
|
||||
"video": "Vidéo"
|
||||
@@ -847,10 +847,10 @@
|
||||
"allow": "Autoriser",
|
||||
"backToKnockModeButton": "Aucun mot de passe, demander à rejoindre plutôt",
|
||||
"dialogTitle": "Mode lobby",
|
||||
"disableDialogContent": "Le mode lobby est actuellement activé. Cette fonctionnalité garantit que les participants indésirables ne peuvent pas rejoindre votre réunion. Souhaitez-vous la désactiver?",
|
||||
"disableDialogContent": "Le mode lobby est actuellement activé. Cette fonctionnalité garantit que les participants indésirables ne peuvent pas rejoindre votre réunion. Souhaitez-vous la désactiver ?",
|
||||
"disableDialogSubmit": "Désactiver",
|
||||
"emailField": "Saisissez votre adresse email",
|
||||
"enableDialogPasswordField": "Définir le mot de passe (optionel)",
|
||||
"enableDialogPasswordField": "Définir le mot de passe (optionnel)",
|
||||
"enableDialogSubmit": "Activer",
|
||||
"enableDialogText": "Le mode lobby vous permet de protéger votre réunion en autorisant les personnes à entrer qu'après l'approbation formelle d'un modérateur.",
|
||||
"enterPasswordButton": "Saisissez un mot de passe de réunion",
|
||||
|
||||
@@ -512,6 +512,12 @@
|
||||
"sectionList": {
|
||||
"pullToRefresh": "Puxe para atualizar"
|
||||
},
|
||||
"security": {
|
||||
"about": "Voce pode adicionar uma $t(lockRoomPassword) em sua reunião. Participantes irão precisar informar a $t(lockRoomPassword) antes de se juntarem na reunião.",
|
||||
"aboutReadOnly": "Moderadores podem adicionar uma $t(lockRoomPassword) na reunião. Participantes irão precisar informar a $t(lockRoomPassword) antes de se juntarem na reunião",
|
||||
"insecureRoomNameWarning": "Essa sala não está protegida. Participantes indesejados poderão entrar na sua reunião. Considere configurar a segurança da sua reunião utilizando o botão de segurança.",
|
||||
"securityOptions": "Opções de segurança"
|
||||
},
|
||||
"settings": {
|
||||
"calendar": {
|
||||
"about": "A integração do calendário {{appName}} é usada para acessar com segurança o seu calendário para que ele possa ler os próximos eventos.",
|
||||
|
||||
@@ -366,7 +366,7 @@
|
||||
"password": "$t(lockRoomPasswordUppercase):",
|
||||
"title": "Share",
|
||||
"tooltip": "Share link and dial-in info for this meeting",
|
||||
"label": "Meeting info"
|
||||
"label": "Dial-in info"
|
||||
},
|
||||
"inviteDialog": {
|
||||
"alertText": "Failed to invite some participants.",
|
||||
@@ -536,7 +536,7 @@
|
||||
"dialInMeeting": "Dial into the meeting",
|
||||
"dialInPin": "Dial into the meeting and enter PIN code:",
|
||||
"dialing": "Dialing",
|
||||
"doNotShow": "Don't show this again",
|
||||
"doNotShow": "Don't show this screen again",
|
||||
"errorDialOut": "Could not dial out",
|
||||
"errorDialOutDisconnected": "Could not dial out. Disconnected",
|
||||
"errorDialOutFailed": "Could not dial out. Call failed",
|
||||
@@ -876,12 +876,12 @@
|
||||
"getHelp": "Get help",
|
||||
"go": "GO",
|
||||
"goSmall": "GO",
|
||||
"info": "Info",
|
||||
"info": "Dial-in info",
|
||||
"join": "CREATE / JOIN",
|
||||
"moderatedMessage": "Or <a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">book a meeting URL</a> in advance where you are the only moderator.",
|
||||
"privacy": "Privacy",
|
||||
"recentList": "Recent",
|
||||
"recentListDelete": "Delete",
|
||||
"recentListDelete": "Delete entry",
|
||||
"recentListEmpty": "Your recent list is currently empty. Chat with your team and you will find all your recent meetings here.",
|
||||
"reducedUIText": "Welcome to {{app}}!",
|
||||
"roomNameAllowedChars": "Meeting name should not contain any of these characters: ?, &, :, ', \", %, #.",
|
||||
|
||||
36
manifest.json
Normal file
36
manifest.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"android_package_name": "org.jitsi.meet",
|
||||
"prefer_related_applications": true,
|
||||
"related_applications": [
|
||||
{
|
||||
"id": "org.jitsi.meet",
|
||||
"platform": "chromeos_play"
|
||||
}
|
||||
],
|
||||
"short_name": "Jitsi Meet",
|
||||
"name": "Jitsi Meet",
|
||||
"icons": [
|
||||
{
|
||||
"src": "static/pwa/icons/icon192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "static/pwa/icons/icon512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
},
|
||||
{
|
||||
"src": "static/pwa/icons/iconMask.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
}
|
||||
],
|
||||
"start_url": "/",
|
||||
"background_color": "#17A0DB",
|
||||
"display": "standalone",
|
||||
"scope": "/",
|
||||
"theme_color": "#17A0DB"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import Logger from 'jitsi-meet-logger';
|
||||
|
||||
import * as JitsiMeetConferenceEvents from '../../ConferenceEvents';
|
||||
import {
|
||||
createApiEvent,
|
||||
sendAnalytics
|
||||
@@ -14,7 +13,7 @@ import {
|
||||
setSubject
|
||||
} from '../../react/features/base/conference';
|
||||
import { parseJWTFromURLParams } from '../../react/features/base/jwt';
|
||||
import { JitsiRecordingConstants } from '../../react/features/base/lib-jitsi-meet';
|
||||
import JitsiMeetJS, { JitsiRecordingConstants } from '../../react/features/base/lib-jitsi-meet';
|
||||
import { pinParticipant } from '../../react/features/base/participants';
|
||||
import {
|
||||
processExternalDeviceRequest
|
||||
@@ -46,14 +45,6 @@ declare var APP: Object;
|
||||
*/
|
||||
let commands = {};
|
||||
|
||||
/**
|
||||
* The state of screen sharing(started/stopped) before the screen sharing is
|
||||
* enabled and initialized.
|
||||
* NOTE: This flag help us to cache the state and use it if toggle-share-screen
|
||||
* was received before the initialization.
|
||||
*/
|
||||
let initialScreenSharingState = false;
|
||||
|
||||
/**
|
||||
* The transport instance used for communication with external apps.
|
||||
*
|
||||
@@ -223,7 +214,8 @@ function initCommands() {
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts a file recording or streaming depending on the passed on params.
|
||||
* Starts a file recording or streaming session depending on the passed on params.
|
||||
* For RTMP streams, `rtmpStreamKey` must be passed on. `rtmpBroadcastID` is optional.
|
||||
* For youtube streams, `youtubeStreamKey` must be passed on. `youtubeBroadcastID` is optional.
|
||||
* For dropbox recording, recording `mode` should be `file` and a dropbox oauth2 token must be provided.
|
||||
* For file recording, recording `mode` should be `file` and optionally `shouldShare` could be passed on.
|
||||
@@ -231,13 +223,23 @@ function initCommands() {
|
||||
*
|
||||
* @param { string } arg.mode - Recording mode, either `file` or `stream`.
|
||||
* @param { string } arg.dropboxToken - Dropbox oauth2 token.
|
||||
* @param { string } arg.rtmpStreamKey - The RTMP stream key.
|
||||
* @param { string } arg.rtmpBroadcastID - The RTMP braodcast ID.
|
||||
* @param { boolean } arg.shouldShare - Whether the recording should be shared with the participants or not.
|
||||
* Only applies to certain jitsi meet deploys.
|
||||
* @param { string } arg.youtubeStreamKey - The youtube stream key.
|
||||
* @param { string } arg.youtubeBroadcastID - The youtube broacast ID.
|
||||
* @returns {void}
|
||||
*/
|
||||
'start-recording': ({ mode, dropboxToken, shouldShare, youtubeStreamKey, youtubeBroadcastID }) => {
|
||||
'start-recording': ({
|
||||
mode,
|
||||
dropboxToken,
|
||||
shouldShare,
|
||||
rtmpStreamKey,
|
||||
rtmpBroadcastID,
|
||||
youtubeStreamKey,
|
||||
youtubeBroadcastID
|
||||
}) => {
|
||||
const state = APP.store.getState();
|
||||
const conference = getCurrentConference(state);
|
||||
|
||||
@@ -253,8 +255,8 @@ function initCommands() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode === JitsiRecordingConstants.mode.STREAM && !youtubeStreamKey) {
|
||||
logger.error('Failed starting recording: missing youtube stream key');
|
||||
if (mode === JitsiRecordingConstants.mode.STREAM && !(youtubeStreamKey || rtmpStreamKey)) {
|
||||
logger.error('Failed starting recording: missing youtube or RTMP stream key');
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -286,9 +288,9 @@ function initCommands() {
|
||||
}
|
||||
} else if (mode === JitsiRecordingConstants.mode.STREAM) {
|
||||
recordingConfig = {
|
||||
broadcastId: youtubeBroadcastID,
|
||||
broadcastId: youtubeBroadcastID || rtmpBroadcastID,
|
||||
mode: JitsiRecordingConstants.mode.STREAM,
|
||||
streamId: youtubeStreamKey
|
||||
streamId: youtubeStreamKey || rtmpStreamKey
|
||||
};
|
||||
} else {
|
||||
logger.error('Invalid recording mode provided');
|
||||
@@ -419,19 +421,6 @@ function initCommands() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for desktop/screen sharing enabled events and toggles the screen
|
||||
* sharing if needed.
|
||||
*
|
||||
* @param {boolean} enabled - Current screen sharing enabled status.
|
||||
* @returns {void}
|
||||
*/
|
||||
function onDesktopSharingEnabledChanged(enabled = false) {
|
||||
if (enabled && initialScreenSharingState) {
|
||||
toggleScreenSharing();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the API should be enabled or not.
|
||||
*
|
||||
@@ -459,12 +448,10 @@ function shouldBeEnabled() {
|
||||
* @returns {void}
|
||||
*/
|
||||
function toggleScreenSharing(enable) {
|
||||
if (APP.conference.isDesktopSharingEnabled) {
|
||||
|
||||
// eslint-disable-next-line no-empty-function
|
||||
APP.conference.toggleScreenSharing(enable).catch(() => {});
|
||||
} else {
|
||||
initialScreenSharingState = !initialScreenSharingState;
|
||||
if (JitsiMeetJS.isDesktopSharingEnabled()) {
|
||||
APP.conference.toggleScreenSharing(enable).catch(() => {
|
||||
logger.warn('Failed to toggle screen-sharing');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,10 +484,6 @@ class API {
|
||||
*/
|
||||
this._enabled = true;
|
||||
|
||||
APP.conference.addListener(
|
||||
JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED,
|
||||
onDesktopSharingEnabledChanged);
|
||||
|
||||
initCommands();
|
||||
}
|
||||
|
||||
@@ -1047,9 +1030,6 @@ class API {
|
||||
dispose() {
|
||||
if (this._enabled) {
|
||||
this._enabled = false;
|
||||
APP.conference.removeListener(
|
||||
JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED,
|
||||
onDesktopSharingEnabledChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
33
modules/API/external/external_api.js
vendored
33
modules/API/external/external_api.js
vendored
@@ -1047,6 +1047,39 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
return setVideoInputDevice(this._transport, label, deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a file recording or streaming session depending on the passed on params.
|
||||
* For RTMP streams, `rtmpStreamKey` must be passed on. `rtmpBroadcastID` is optional.
|
||||
* For youtube streams, `youtubeStreamKey` must be passed on. `youtubeBroadcastID` is optional.
|
||||
* For dropbox recording, recording `mode` should be `file` and a dropbox oauth2 token must be provided.
|
||||
* For file recording, recording `mode` should be `file` and optionally `shouldShare` could be passed on.
|
||||
* No other params should be passed.
|
||||
*
|
||||
* @param {Object} options - An object with config options to pass along.
|
||||
* @param { string } options.mode - Recording mode, either `file` or `stream`.
|
||||
* @param { string } options.dropboxToken - Dropbox oauth2 token.
|
||||
* @param { boolean } options.shouldShare - Whether the recording should be shared with the participants or not.
|
||||
* Only applies to certain jitsi meet deploys.
|
||||
* @param { string } options.rtmpStreamKey - The RTMP stream key.
|
||||
* @param { string } options.rtmpBroadcastID - The RTMP broacast ID.
|
||||
* @param { string } options.youtubeStreamKey - The youtube stream key.
|
||||
* @param { string } options.youtubeBroadcastID - The youtube broacast ID.
|
||||
* @returns {void}
|
||||
*/
|
||||
startRecording(options) {
|
||||
this.executeCommand('startRecording', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops a recording or streaming session that is in progress.
|
||||
*
|
||||
* @param {string} mode - `file` or `stream`.
|
||||
* @returns {void}
|
||||
*/
|
||||
stopRecording(mode) {
|
||||
this.executeCommand('startRecording', mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuration for electron for the windows that are open
|
||||
* from Jitsi Meet.
|
||||
|
||||
@@ -7,7 +7,6 @@ import EventEmitter from 'events';
|
||||
import Logger from 'jitsi-meet-logger';
|
||||
|
||||
import { isMobileBrowser } from '../../react/features/base/environment/utils';
|
||||
import { getLocalParticipant } from '../../react/features/base/participants';
|
||||
import { toggleChat } from '../../react/features/chat';
|
||||
import { setDocumentUrl } from '../../react/features/etherpad';
|
||||
import { setFilmstripVisible } from '../../react/features/filmstrip';
|
||||
@@ -99,29 +98,11 @@ UI.notifyReservationError = function(code, msg) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Change nickname for the user.
|
||||
* @param {string} id user id
|
||||
* @param {string} displayName new nickname
|
||||
*/
|
||||
UI.changeDisplayName = function(id, displayName) {
|
||||
VideoLayout.onDisplayNameChanged(id, displayName);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize conference UI.
|
||||
*/
|
||||
UI.initConference = function() {
|
||||
const { getState } = APP.store;
|
||||
const { id, name } = getLocalParticipant(getState);
|
||||
|
||||
UI.showToolbar();
|
||||
|
||||
const displayName = config.displayJids ? id : name;
|
||||
|
||||
if (displayName) {
|
||||
UI.changeDisplayName('localVideoContainer', displayName);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -247,19 +228,12 @@ UI.getSharedDocumentManager = () => etherpadManager;
|
||||
* @param {JitsiParticipant} user
|
||||
*/
|
||||
UI.addUser = function(user) {
|
||||
const id = user.getId();
|
||||
const displayName = user.getDisplayName();
|
||||
const status = user.getStatus();
|
||||
|
||||
if (status) {
|
||||
// FIXME: move updateUserStatus in participantPresenceChanged action
|
||||
UI.updateUserStatus(user, status);
|
||||
}
|
||||
|
||||
// set initial display name
|
||||
if (displayName) {
|
||||
UI.changeDisplayName(id, displayName);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -356,8 +330,8 @@ UI.askForNickname = function() {
|
||||
/**
|
||||
* Sets muted audio state for participant
|
||||
*/
|
||||
UI.setAudioMuted = function(id, muted) {
|
||||
VideoLayout.onAudioMute(id, muted);
|
||||
UI.setAudioMuted = function(id) {
|
||||
// FIXME: Maybe this can be removed!
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
APP.conference.updateAudioIconEnabled();
|
||||
}
|
||||
@@ -366,8 +340,8 @@ UI.setAudioMuted = function(id, muted) {
|
||||
/**
|
||||
* Sets muted video state for participant
|
||||
*/
|
||||
UI.setVideoMuted = function(id, muted) {
|
||||
VideoLayout.onVideoMute(id, muted);
|
||||
UI.setVideoMuted = function(id) {
|
||||
VideoLayout.onVideoMute(id);
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
APP.conference.updateVideoIconEnabled();
|
||||
}
|
||||
@@ -494,14 +468,6 @@ UI.handleLastNEndpoints = function(leavingIds, enteringIds) {
|
||||
*/
|
||||
UI.setAudioLevel = (id, lvl) => VideoLayout.setAudioLevel(id, lvl);
|
||||
|
||||
/**
|
||||
* Hide connection quality statistics from UI.
|
||||
*/
|
||||
UI.hideStats = function() {
|
||||
VideoLayout.hideStats();
|
||||
};
|
||||
|
||||
|
||||
UI.notifyTokenAuthFailed = function() {
|
||||
messageHandler.showError({
|
||||
descriptionKey: 'dialog.tokenAuthFailed',
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
/* global $ */
|
||||
/* global $, APP */
|
||||
|
||||
import Logger from 'jitsi-meet-logger';
|
||||
/* eslint-disable no-unused-vars */
|
||||
import React, { Component } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { I18nextProvider } from 'react-i18next';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { i18next } from '../../../react/features/base/i18n';
|
||||
import Thumbnail from '../../../react/features/filmstrip/components/web/Thumbnail';
|
||||
import SmallVideo from '../videolayout/SmallVideo';
|
||||
|
||||
const logger = Logger.getLogger(__filename);
|
||||
/* eslint-enable no-unused-vars */
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -24,18 +29,12 @@ export default class SharedVideoThumb extends SmallVideo {
|
||||
this.videoSpanId = 'sharedVideoContainer';
|
||||
this.container = this.createContainer(this.videoSpanId);
|
||||
this.$container = $(this.container);
|
||||
this.renderThumbnail();
|
||||
this._setThumbnailSize();
|
||||
this.bindHoverHandler();
|
||||
this.isVideoMuted = true;
|
||||
this.updateDisplayName();
|
||||
this.container.onclick = this._onContainerClick;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
initializeAvatar() {} // eslint-disable-line no-empty-function
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} spanId
|
||||
@@ -46,18 +45,6 @@ export default class SharedVideoThumb extends SmallVideo {
|
||||
container.id = spanId;
|
||||
container.className = 'videocontainer';
|
||||
|
||||
// add the avatar
|
||||
const avatar = document.createElement('img');
|
||||
|
||||
avatar.className = 'sharedVideoAvatar';
|
||||
avatar.src = `https://img.youtube.com/vi/${this.url}/0.jpg`;
|
||||
container.appendChild(avatar);
|
||||
|
||||
const displayNameContainer = document.createElement('div');
|
||||
|
||||
displayNameContainer.className = 'displayNameContainer';
|
||||
container.appendChild(displayNameContainer);
|
||||
|
||||
const remoteVideosContainer
|
||||
= document.getElementById('filmstripRemoteVideosContainer');
|
||||
const localVideoContainer
|
||||
@@ -69,21 +56,14 @@ export default class SharedVideoThumb extends SmallVideo {
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers re-rendering of the display name using current instance state.
|
||||
*
|
||||
* @returns {void}
|
||||
* Renders the thumbnail.
|
||||
*/
|
||||
updateDisplayName() {
|
||||
if (!this.container) {
|
||||
logger.warn(`Unable to set displayName - ${this.videoSpanId
|
||||
} does not exist`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this._renderDisplayName({
|
||||
elementID: `${this.videoSpanId}_name`,
|
||||
participantID: this.id
|
||||
});
|
||||
renderThumbnail(isHovered = false) {
|
||||
ReactDOM.render(
|
||||
<Provider store = { APP.store }>
|
||||
<I18nextProvider i18n = { i18next }>
|
||||
<Thumbnail participantID = { this.id } isHovered = { isHovered } />
|
||||
</I18nextProvider>
|
||||
</Provider>, this.container);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ const Filmstrip = {
|
||||
*/
|
||||
resizeThumbnailsForTileView(width, height, forceUpdate = false) {
|
||||
const thumbs = this._getThumbs(!forceUpdate);
|
||||
const avatarSize = height / 2;
|
||||
|
||||
if (thumbs.localThumb) {
|
||||
thumbs.localThumb.css({
|
||||
@@ -58,11 +57,6 @@ const Filmstrip = {
|
||||
width: `${width}px`
|
||||
});
|
||||
}
|
||||
|
||||
$('.avatar-container').css({
|
||||
height: `${avatarSize}px`,
|
||||
width: `${avatarSize}px`
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -77,7 +71,6 @@ const Filmstrip = {
|
||||
|
||||
if (thumbs.localThumb) {
|
||||
const { height, width } = local;
|
||||
const avatarSize = height / 2;
|
||||
|
||||
thumbs.localThumb.css({
|
||||
height: `${height}px`,
|
||||
@@ -85,15 +78,10 @@ const Filmstrip = {
|
||||
'min-width': `${width}px`,
|
||||
width: `${width}px`
|
||||
});
|
||||
$('#localVideoContainer > .avatar-container').css({
|
||||
height: `${avatarSize}px`,
|
||||
width: `${avatarSize}px`
|
||||
});
|
||||
}
|
||||
|
||||
if (thumbs.remoteThumbs) {
|
||||
const { height, width } = remote;
|
||||
const avatarSize = height / 2;
|
||||
|
||||
thumbs.remoteThumbs.css({
|
||||
height: `${height}px`,
|
||||
@@ -101,10 +89,6 @@ const Filmstrip = {
|
||||
'min-width': `${width}px`,
|
||||
width: `${width}px`
|
||||
});
|
||||
$('#filmstripRemoteVideosContainer > span > .avatar-container').css({
|
||||
height: `${avatarSize}px`,
|
||||
width: `${avatarSize}px`
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -126,10 +110,6 @@ const Filmstrip = {
|
||||
'min-width': '',
|
||||
'min-height': ''
|
||||
});
|
||||
$('#localVideoContainer > .avatar-container').css({
|
||||
height: '50%',
|
||||
width: `${heightToWidthPercent / 2}%`
|
||||
});
|
||||
}
|
||||
|
||||
if (thumbs.remoteThumbs) {
|
||||
@@ -142,10 +122,6 @@ const Filmstrip = {
|
||||
'min-width': '',
|
||||
'min-height': ''
|
||||
});
|
||||
$('#filmstripRemoteVideosContainer > span > .avatar-container').css({
|
||||
height: '50%',
|
||||
width: `${heightToWidthPercent / 2}%`
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
JitsiParticipantConnectionStatus
|
||||
} from '../../../react/features/base/lib-jitsi-meet';
|
||||
import { VIDEO_TYPE } from '../../../react/features/base/media';
|
||||
import { getParticipantById } from '../../../react/features/base/participants';
|
||||
import { CHAT_SIZE } from '../../../react/features/chat';
|
||||
import {
|
||||
updateKnownLargeVideoResolution
|
||||
@@ -224,9 +225,8 @@ export default class LargeVideoManager {
|
||||
const wasUsersImageCached
|
||||
= !isUserSwitch && container.wasVideoRendered;
|
||||
const isVideoMuted = !stream || stream.isMuted();
|
||||
|
||||
const connectionStatus
|
||||
= APP.conference.getParticipantConnectionStatus(id);
|
||||
const participant = getParticipantById(APP.store.getState(), id);
|
||||
const connectionStatus = participant?.connectionStatus;
|
||||
const isVideoRenderable
|
||||
= !isVideoMuted
|
||||
&& (APP.conference.isLocalId(id)
|
||||
@@ -356,17 +356,12 @@ export default class LargeVideoManager {
|
||||
let widthToUse = this.preferredWidth || window.innerWidth;
|
||||
const { isOpen } = APP.store.getState()['features/chat'];
|
||||
|
||||
/**
|
||||
* If chat state is open, we re-compute the container width by subtracting the default width of
|
||||
* the chat. We re-compute the width again after the chat window is closed. This is needed when
|
||||
* custom styling is configured on the large video container through the iFrame API.
|
||||
*/
|
||||
if (isOpen && !this.resizedForChat) {
|
||||
if (isOpen) {
|
||||
/**
|
||||
* If chat state is open, we re-compute the container width
|
||||
* by subtracting the default width of the chat.
|
||||
*/
|
||||
widthToUse -= CHAT_SIZE;
|
||||
this.resizedForChat = true;
|
||||
} else if (this.resizedForChat) {
|
||||
this.resizedForChat = false;
|
||||
widthToUse += CHAT_SIZE;
|
||||
}
|
||||
|
||||
this.width = widthToUse;
|
||||
@@ -484,8 +479,8 @@ export default class LargeVideoManager {
|
||||
*/
|
||||
showRemoteConnectionMessage(show) {
|
||||
if (typeof show !== 'boolean') {
|
||||
const connStatus
|
||||
= APP.conference.getParticipantConnectionStatus(this.id);
|
||||
const participant = getParticipantById(APP.store.getState(), this.id);
|
||||
const connStatus = participant?.connectionStatus;
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
show = !APP.conference.isLocalId(this.id)
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
/* global $, config, interfaceConfig, APP */
|
||||
/* global $, config, APP */
|
||||
|
||||
import Logger from 'jitsi-meet-logger';
|
||||
/* eslint-disable no-unused-vars */
|
||||
import React, { Component } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { I18nextProvider } from 'react-i18next';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { i18next } from '../../../react/features/base/i18n';
|
||||
import { JitsiTrackEvents } from '../../../react/features/base/lib-jitsi-meet';
|
||||
import { VideoTrack } from '../../../react/features/base/media';
|
||||
import { updateSettings } from '../../../react/features/base/settings';
|
||||
import { getLocalVideoTrack } from '../../../react/features/base/tracks';
|
||||
import Thumbnail from '../../../react/features/filmstrip/components/web/Thumbnail';
|
||||
import { shouldDisplayTileView } from '../../../react/features/video-layout';
|
||||
/* eslint-enable no-unused-vars */
|
||||
import UIEvents from '../../../service/UI/UIEvents';
|
||||
|
||||
import SmallVideo from './SmallVideo';
|
||||
|
||||
const logger = Logger.getLogger(__filename);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -37,6 +37,7 @@ export default class LocalVideo extends SmallVideo {
|
||||
this.isLocal = true;
|
||||
this._setThumbnailSize();
|
||||
this.updateDOMLocation();
|
||||
this.renderThumbnail();
|
||||
|
||||
this.localVideoId = null;
|
||||
this.bindHoverHandler();
|
||||
@@ -44,7 +45,6 @@ export default class LocalVideo extends SmallVideo {
|
||||
this._buildContextMenu();
|
||||
}
|
||||
this.emitter = emitter;
|
||||
this.statsPopoverLocation = interfaceConfig.VERTICAL_FILMSTRIP ? 'left top' : 'top center';
|
||||
|
||||
Object.defineProperty(this, 'id', {
|
||||
get() {
|
||||
@@ -53,17 +53,6 @@ export default class LocalVideo extends SmallVideo {
|
||||
});
|
||||
this.initBrowserSpecificProperties();
|
||||
|
||||
// Set default display name.
|
||||
this.updateDisplayName();
|
||||
|
||||
// Initialize the avatar display with an avatar url selected from the redux
|
||||
// state. Redux stores the local user with a hardcoded participant id of
|
||||
// 'local' if no id has been assigned yet.
|
||||
this.initializeAvatar();
|
||||
|
||||
this.addAudioLevelIndicator();
|
||||
this.updateIndicators();
|
||||
|
||||
this.container.onclick = this._onContainerClick;
|
||||
}
|
||||
|
||||
@@ -76,38 +65,19 @@ export default class LocalVideo extends SmallVideo {
|
||||
containerSpan.classList.add('videocontainer');
|
||||
containerSpan.id = this.videoSpanId;
|
||||
|
||||
containerSpan.innerHTML = `
|
||||
<div class = 'videocontainer__background'></div>
|
||||
<span id = 'localVideoWrapper'></span>
|
||||
<div class = 'videocontainer__toolbar'></div>
|
||||
<div class = 'videocontainer__toptoolbar'></div>
|
||||
<div class = 'videocontainer__hoverOverlay'></div>
|
||||
<div class = 'displayNameContainer'></div>
|
||||
<div class = 'avatar-container'></div>`;
|
||||
|
||||
return containerSpan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers re-rendering of the display name using current instance state.
|
||||
*
|
||||
* @returns {void}
|
||||
* Renders the thumbnail.
|
||||
*/
|
||||
updateDisplayName() {
|
||||
if (!this.container) {
|
||||
logger.warn(
|
||||
`Unable to set displayName - ${this.videoSpanId
|
||||
} does not exist`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this._renderDisplayName({
|
||||
allowEditing: APP.store.getState()['features/base/jwt'].isGuest,
|
||||
displayNameSuffix: interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME,
|
||||
elementID: 'localDisplayName',
|
||||
participantID: this.id
|
||||
});
|
||||
renderThumbnail(isHovered = false) {
|
||||
ReactDOM.render(
|
||||
<Provider store = { APP.store }>
|
||||
<I18nextProvider i18n = { i18next }>
|
||||
<Thumbnail participantID = { this.id } isHovered = { isHovered } />
|
||||
</I18nextProvider>
|
||||
</Provider>, this.container);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,7 +87,6 @@ export default class LocalVideo extends SmallVideo {
|
||||
changeVideo(stream) {
|
||||
this.videoStream = stream;
|
||||
this.localVideoId = `localVideo_${stream.getId()}`;
|
||||
this._updateVideoElement();
|
||||
|
||||
// eslint-disable-next-line eqeqeq
|
||||
const isVideo = stream.videoType != 'desktop';
|
||||
@@ -127,17 +96,6 @@ export default class LocalVideo extends SmallVideo {
|
||||
this.setFlipX(isVideo ? settings.localFlipX : false);
|
||||
|
||||
const endedHandler = () => {
|
||||
const localVideoContainer
|
||||
= document.getElementById('localVideoWrapper');
|
||||
|
||||
// Only remove if there is no video and not a transition state.
|
||||
// Previous non-react logic created a new video element with each track
|
||||
// removal whereas react reuses the video component so it could be the
|
||||
// stream ended but a new one is being used.
|
||||
if (localVideoContainer && this.videoStream.isEnded()) {
|
||||
ReactDOM.unmountComponentAtNode(localVideoContainer);
|
||||
}
|
||||
|
||||
this._notifyOfStreamEnded();
|
||||
stream.off(JitsiTrackEvents.LOCAL_TRACK_STOPPED, endedHandler);
|
||||
};
|
||||
@@ -253,35 +211,5 @@ export default class LocalVideo extends SmallVideo {
|
||||
: document.getElementById('filmstripLocalVideoThumbnail');
|
||||
|
||||
appendTarget && appendTarget.appendChild(this.container);
|
||||
this._updateVideoElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the React Element for displaying video in {@code LocalVideo}.
|
||||
*
|
||||
*/
|
||||
_updateVideoElement() {
|
||||
const localVideoContainer = document.getElementById('localVideoWrapper');
|
||||
const videoTrack
|
||||
= getLocalVideoTrack(APP.store.getState()['features/base/tracks']);
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store = { APP.store }>
|
||||
<VideoTrack
|
||||
id = 'localVideo_container'
|
||||
videoTrack = { videoTrack } />
|
||||
</Provider>,
|
||||
localVideoContainer
|
||||
);
|
||||
|
||||
// Ensure the video gets play() called on it. This may be necessary in the
|
||||
// case where the local video container was moved and re-attached, in which
|
||||
// case video does not autoplay. Also, set the playsinline attribute on the
|
||||
// video element so that local video doesn't open in full screen by default
|
||||
// in Safari browser on iOS.
|
||||
const video = this.container.querySelector('video');
|
||||
|
||||
video && video.setAttribute('playsinline', 'true');
|
||||
video && !config.testing?.noAutoPlayVideo && video.play();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,14 @@ import { i18next } from '../../../react/features/base/i18n';
|
||||
import {
|
||||
JitsiParticipantConnectionStatus
|
||||
} from '../../../react/features/base/lib-jitsi-meet';
|
||||
import { MEDIA_TYPE } from '../../../react/features/base/media';
|
||||
import {
|
||||
getParticipantById,
|
||||
getPinnedParticipant,
|
||||
pinParticipant
|
||||
} from '../../../react/features/base/participants';
|
||||
import { isRemoteTrackMuted } from '../../../react/features/base/tracks';
|
||||
import Thumbnail from '../../../react/features/filmstrip/components/web/Thumbnail';
|
||||
import { PresenceLabel } from '../../../react/features/presence-status';
|
||||
import {
|
||||
REMOTE_CONTROL_MENU_STATES,
|
||||
@@ -39,16 +43,6 @@ function createContainer(spanId) {
|
||||
container.id = spanId;
|
||||
container.className = 'videocontainer';
|
||||
|
||||
container.innerHTML = `
|
||||
<div class = 'videocontainer__background'></div>
|
||||
<div class = 'videocontainer__toptoolbar'></div>
|
||||
<div class = 'videocontainer__toolbar'></div>
|
||||
<div class = 'videocontainer__hoverOverlay'></div>
|
||||
<div class = 'displayNameContainer'></div>
|
||||
<div class = 'avatar-container'></div>
|
||||
<div class ='presence-label-container'></div>
|
||||
<span class = 'remotevideomenu'></span>`;
|
||||
|
||||
const remoteVideosContainer
|
||||
= document.getElementById('filmstripRemoteVideosContainer');
|
||||
const localVideoContainer
|
||||
@@ -79,14 +73,10 @@ export default class RemoteVideo extends SmallVideo {
|
||||
|
||||
this._audioStreamElement = null;
|
||||
this._supportsRemoteControl = false;
|
||||
this.statsPopoverLocation = interfaceConfig.VERTICAL_FILMSTRIP ? 'left bottom' : 'top center';
|
||||
this.addRemoteVideoContainer();
|
||||
this.updateIndicators();
|
||||
this.updateDisplayName();
|
||||
this.bindHoverHandler();
|
||||
this.flipX = false;
|
||||
this.isLocal = false;
|
||||
this.popupMenuIsHovered = false;
|
||||
this._isRemoteControlSessionActive = false;
|
||||
|
||||
/**
|
||||
@@ -98,17 +88,6 @@ export default class RemoteVideo extends SmallVideo {
|
||||
*/
|
||||
this._canPlayEventReceived = false;
|
||||
|
||||
/**
|
||||
* The flag is set to <tt>true</tt> if remote participant's video gets muted
|
||||
* during his media connection disruption. This is to prevent black video
|
||||
* being render on the thumbnail, because even though once the video has
|
||||
* been played the image usually remains on the video element it seems that
|
||||
* after longer period of the video element being hidden this image can be
|
||||
* lost.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.mutedWhileDisconnected = false;
|
||||
|
||||
// Bind event handlers so they are only bound once for every instance.
|
||||
// TODO The event handlers should be turned into actions so changes can be
|
||||
// handled through reducers and middleware.
|
||||
@@ -126,26 +105,24 @@ export default class RemoteVideo extends SmallVideo {
|
||||
addRemoteVideoContainer() {
|
||||
this.container = createContainer(this.videoSpanId);
|
||||
this.$container = $(this.container);
|
||||
this.initializeAvatar();
|
||||
this.renderThumbnail();
|
||||
this._setThumbnailSize();
|
||||
this.initBrowserSpecificProperties();
|
||||
this.updateRemoteVideoMenu();
|
||||
this.updateStatusBar();
|
||||
this.addAudioLevelIndicator();
|
||||
this.addPresenceLabel();
|
||||
|
||||
return this.container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether current video is considered hovered. Currently it is hovered
|
||||
* if the mouse is over the video, or if the connection indicator or the popup
|
||||
* menu is shown(hovered).
|
||||
* @private
|
||||
* NOTE: extends SmallVideo's method
|
||||
* Renders the thumbnail.
|
||||
*/
|
||||
_isHovered() {
|
||||
return super._isHovered() || this.popupMenuIsHovered;
|
||||
renderThumbnail(isHovered = false) {
|
||||
ReactDOM.render(
|
||||
<Provider store = { APP.store }>
|
||||
<I18nextProvider i18n = { i18next }>
|
||||
<Thumbnail participantID = { this.id } isHovered = { isHovered } />
|
||||
</I18nextProvider>
|
||||
</Provider>, this.container);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,7 +184,6 @@ export default class RemoteVideo extends SmallVideo {
|
||||
<AtlasKitThemeProvider mode = 'dark'>
|
||||
<RemoteVideoMenuTriggerButton
|
||||
initialVolumeValue = { initialVolumeValue }
|
||||
isAudioMuted = { this.isAudioMuted }
|
||||
menuPosition = { remoteMenuPosition }
|
||||
onMenuDisplay
|
||||
= {this._onRemoteVideoMenuDisplay.bind(this)}
|
||||
@@ -311,43 +287,11 @@ export default class RemoteVideo extends SmallVideo {
|
||||
|
||||
/**
|
||||
* Updates the remote video menu.
|
||||
*
|
||||
* @param isMuted the new muted state to update to
|
||||
*/
|
||||
updateRemoteVideoMenu(isMuted) {
|
||||
if (typeof isMuted !== 'undefined') {
|
||||
this.isAudioMuted = isMuted;
|
||||
}
|
||||
updateRemoteVideoMenu() {
|
||||
this._generatePopupContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @override
|
||||
*/
|
||||
setVideoMutedView(isMuted) {
|
||||
super.setVideoMutedView(isMuted);
|
||||
|
||||
// Update 'mutedWhileDisconnected' flag
|
||||
this._figureOutMutedWhileDisconnected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Figures out the value of {@link #mutedWhileDisconnected} flag by taking into
|
||||
* account remote participant's network connectivity and video muted status.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_figureOutMutedWhileDisconnected() {
|
||||
const isActive = this.isConnectionActive();
|
||||
|
||||
if (!isActive && this.isVideoMuted) {
|
||||
this.mutedWhileDisconnected = true;
|
||||
} else if (isActive && !this.isVideoMuted) {
|
||||
this.mutedWhileDisconnected = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the remote stream element corresponding to the given stream and
|
||||
* parent container.
|
||||
@@ -378,17 +322,6 @@ export default class RemoteVideo extends SmallVideo {
|
||||
this.updateView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the remote user associated with this <tt>RemoteVideo</tt>
|
||||
* has connectivity issues.
|
||||
*
|
||||
* @return {boolean} <tt>true</tt> if the user's connection is fine or
|
||||
* <tt>false</tt> otherwise.
|
||||
*/
|
||||
isConnectionActive() {
|
||||
return this.user.getConnectionStatus() === JitsiParticipantConnectionStatus.ACTIVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* The remote video is considered "playable" once the can play event has been received. It will be allowed to
|
||||
* display video also in {@link JitsiParticipantConnectionStatus.INTERRUPTED} if the video has received the canplay
|
||||
@@ -400,12 +333,13 @@ export default class RemoteVideo extends SmallVideo {
|
||||
* @override
|
||||
*/
|
||||
isVideoPlayable() {
|
||||
const connectionState = APP.conference.getParticipantConnectionStatus(this.id);
|
||||
const participant = getParticipantById(APP.store.getState(), this.id);
|
||||
const { connectionStatus, mutedWhileDisconnected } = participant || {};
|
||||
|
||||
return super.isVideoPlayable()
|
||||
&& this._canPlayEventReceived
|
||||
&& (connectionState === JitsiParticipantConnectionStatus.ACTIVE
|
||||
|| (connectionState === JitsiParticipantConnectionStatus.INTERRUPTED && !this.mutedWhileDisconnected));
|
||||
&& (connectionStatus === JitsiParticipantConnectionStatus.ACTIVE
|
||||
|| (connectionStatus === JitsiParticipantConnectionStatus.INTERRUPTED && !mutedWhileDisconnected));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -413,34 +347,16 @@ export default class RemoteVideo extends SmallVideo {
|
||||
*/
|
||||
updateView() {
|
||||
this.$container.toggleClass('audio-only', APP.conference.isAudioOnly());
|
||||
this.updateConnectionStatusIndicator();
|
||||
|
||||
// This must be called after 'updateConnectionStatusIndicator' because it
|
||||
// affects the display mode by modifying 'mutedWhileDisconnected' flag
|
||||
super.updateView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the UI to reflect user's connectivity status.
|
||||
*/
|
||||
updateConnectionStatusIndicator() {
|
||||
const connectionStatus = this.user.getConnectionStatus();
|
||||
|
||||
logger.debug(`${this.id} thumbnail connection status: ${connectionStatus}`);
|
||||
|
||||
// FIXME rename 'mutedWhileDisconnected' to 'mutedWhileNotRendering'
|
||||
// Update 'mutedWhileDisconnected' flag
|
||||
this._figureOutMutedWhileDisconnected();
|
||||
this.updateConnectionStatus(connectionStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes RemoteVideo from the page.
|
||||
*/
|
||||
remove() {
|
||||
super.remove();
|
||||
this.removePresenceLabel();
|
||||
this.removeRemoteVideoMenu();
|
||||
ReactDOM.unmountComponentAtNode(this.container);
|
||||
super.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -513,24 +429,6 @@ export default class RemoteVideo extends SmallVideo {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers re-rendering of the display name using current instance state.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
updateDisplayName() {
|
||||
if (!this.container) {
|
||||
logger.warn(`Unable to set displayName - ${this.videoSpanId} does not exist`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this._renderDisplayName({
|
||||
elementID: `${this.videoSpanId}_name`,
|
||||
participantID: this.id
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes remote video menu element from video element identified by
|
||||
* given <tt>videoElementId</tt>.
|
||||
@@ -545,39 +443,4 @@ export default class RemoteVideo extends SmallVideo {
|
||||
menuSpan.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mounts the {@code PresenceLabel} for displaying the participant's current
|
||||
* presence status.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
addPresenceLabel() {
|
||||
const presenceLabelContainer = this.container.querySelector('.presence-label-container');
|
||||
|
||||
if (presenceLabelContainer) {
|
||||
ReactDOM.render(
|
||||
<Provider store = { APP.store }>
|
||||
<I18nextProvider i18n = { i18next }>
|
||||
<PresenceLabel
|
||||
participantID = { this.id }
|
||||
className = 'presence-label' />
|
||||
</I18nextProvider>
|
||||
</Provider>,
|
||||
presenceLabelContainer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmounts the {@code PresenceLabel} component.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
removePresenceLabel() {
|
||||
const presenceLabelContainer = this.container.querySelector('.presence-label-container');
|
||||
|
||||
if (presenceLabelContainer) {
|
||||
ReactDOM.unmountComponentAtNode(presenceLabelContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,19 @@ import { Provider } from 'react-redux';
|
||||
import { AudioLevelIndicator } from '../../../react/features/audio-level-indicator';
|
||||
import { Avatar as AvatarDisplay } from '../../../react/features/base/avatar';
|
||||
import { i18next } from '../../../react/features/base/i18n';
|
||||
import { MEDIA_TYPE } from '../../../react/features/base/media';
|
||||
import {
|
||||
getLocalParticipant,
|
||||
getParticipantById,
|
||||
getParticipantCount,
|
||||
getPinnedParticipant,
|
||||
pinParticipant
|
||||
} from '../../../react/features/base/participants';
|
||||
import {
|
||||
getTrackByMediaTypeAndParticipant,
|
||||
isLocalTrackMuted,
|
||||
isRemoteTrackMuted
|
||||
} from '../../../react/features/base/tracks';
|
||||
import { ConnectionIndicator } from '../../../react/features/connection-indicator';
|
||||
import { DisplayName } from '../../../react/features/display-name';
|
||||
import {
|
||||
@@ -81,60 +89,13 @@ export default class SmallVideo {
|
||||
* Constructor.
|
||||
*/
|
||||
constructor(VideoLayout) {
|
||||
this.isAudioMuted = false;
|
||||
this.isVideoMuted = false;
|
||||
this.isScreenSharing = false;
|
||||
this.videoStream = null;
|
||||
this.audioStream = null;
|
||||
this.VideoLayout = VideoLayout;
|
||||
this.videoIsHovered = false;
|
||||
this.videoType = undefined;
|
||||
|
||||
/**
|
||||
* The current state of the user's bridge connection. The value should be
|
||||
* a string as enumerated in the library's participantConnectionStatus
|
||||
* constants.
|
||||
*
|
||||
* @private
|
||||
* @type {string|null}
|
||||
*/
|
||||
this._connectionStatus = null;
|
||||
|
||||
/**
|
||||
* Whether or not the ConnectionIndicator's popover is hovered. Modifies
|
||||
* how the video overlays display based on hover state.
|
||||
*
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this._popoverIsHovered = false;
|
||||
|
||||
/**
|
||||
* Whether or not the connection indicator should be displayed.
|
||||
*
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this._showConnectionIndicator = !interfaceConfig.CONNECTION_INDICATOR_DISABLED;
|
||||
|
||||
/**
|
||||
* Whether or not the dominant speaker indicator should be displayed.
|
||||
*
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this._showDominantSpeaker = false;
|
||||
|
||||
/**
|
||||
* Whether or not the raised hand indicator should be displayed.
|
||||
*
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this._showRaisedHand = false;
|
||||
|
||||
// Bind event handlers so they are only bound once for every instance.
|
||||
this._onPopoverHover = this._onPopoverHover.bind(this);
|
||||
this.updateView = this.updateView.bind(this);
|
||||
|
||||
this._onContainerClick = this._onContainerClick.bind(this);
|
||||
@@ -194,156 +155,22 @@ export default class SmallVideo {
|
||||
this.$container.hover(
|
||||
() => {
|
||||
this.videoIsHovered = true;
|
||||
this.renderThumbnail(true);
|
||||
this.updateView();
|
||||
this.updateIndicators();
|
||||
},
|
||||
() => {
|
||||
this.videoIsHovered = false;
|
||||
this.renderThumbnail(false);
|
||||
this.updateView();
|
||||
this.updateIndicators();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmounts the ConnectionIndicator component.
|
||||
|
||||
* @returns {void}
|
||||
*/
|
||||
removeConnectionIndicator() {
|
||||
this._showConnectionIndicator = false;
|
||||
this.updateIndicators();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the connectionStatus stat which displays in the ConnectionIndicator.
|
||||
|
||||
* @returns {void}
|
||||
*/
|
||||
updateConnectionStatus(connectionStatus) {
|
||||
this._connectionStatus = connectionStatus;
|
||||
this.updateIndicators();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows / hides the audio muted indicator over small videos.
|
||||
*
|
||||
* @param {boolean} isMuted indicates if the muted element should be shown
|
||||
* or hidden
|
||||
* Renders the thumbnail.
|
||||
*/
|
||||
showAudioIndicator(isMuted) {
|
||||
this.isAudioMuted = isMuted;
|
||||
this.updateStatusBar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows / hides the screen-share indicator over small videos.
|
||||
*
|
||||
* @param {boolean} isScreenSharing indicates if the screen-share element should be shown
|
||||
* or hidden
|
||||
*/
|
||||
setScreenSharing(isScreenSharing) {
|
||||
if (isScreenSharing === this.isScreenSharing) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isScreenSharing = isScreenSharing;
|
||||
this.updateView();
|
||||
this.updateStatusBar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows video muted indicator over small videos and disables/enables avatar
|
||||
* if video muted.
|
||||
*
|
||||
* @param {boolean} isMuted indicates if we should set the view to muted view
|
||||
* or not
|
||||
*/
|
||||
setVideoMutedView(isMuted) {
|
||||
this.isVideoMuted = isMuted;
|
||||
this.updateView();
|
||||
this.updateStatusBar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or updates the ReactElement for displaying status indicators about
|
||||
* audio mute, video mute, and moderator status.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
updateStatusBar() {
|
||||
const statusBarContainer = this.container.querySelector('.videocontainer__toolbar');
|
||||
|
||||
if (!statusBarContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store = { APP.store }>
|
||||
<I18nextProvider i18n = { i18next }>
|
||||
<StatusIndicators
|
||||
showAudioMutedIndicator = { this.isAudioMuted }
|
||||
showScreenShareIndicator = { this.isScreenSharing }
|
||||
showVideoMutedIndicator = { this.isVideoMuted }
|
||||
participantID = { this.id } />
|
||||
</I18nextProvider>
|
||||
</Provider>,
|
||||
statusBarContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the element indicating the audio level of the participant.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
addAudioLevelIndicator() {
|
||||
let audioLevelContainer = this._getAudioLevelContainer();
|
||||
|
||||
if (audioLevelContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
audioLevelContainer = document.createElement('span');
|
||||
audioLevelContainer.className = 'audioindicator-container';
|
||||
this.container.appendChild(audioLevelContainer);
|
||||
this.updateAudioLevelIndicator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the element indicating the audio level of the participant.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
removeAudioLevelIndicator() {
|
||||
const audioLevelContainer = this._getAudioLevelContainer();
|
||||
|
||||
if (audioLevelContainer) {
|
||||
ReactDOM.unmountComponentAtNode(audioLevelContainer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the audio level for this small video.
|
||||
*
|
||||
* @param lvl the new audio level to set
|
||||
* @returns {void}
|
||||
*/
|
||||
updateAudioLevelIndicator(lvl = 0) {
|
||||
const audioLevelContainer = this._getAudioLevelContainer();
|
||||
|
||||
if (audioLevelContainer) {
|
||||
ReactDOM.render(<AudioLevelIndicator audioLevel = { lvl }/>, audioLevelContainer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the component's DOM for the element that should be the parent to the
|
||||
* AudioLevelIndicator.
|
||||
*
|
||||
* @returns {HTMLElement} The DOM element that holds the AudioLevelIndicator.
|
||||
*/
|
||||
_getAudioLevelContainer() {
|
||||
return this.container.querySelector('.audioindicator-container');
|
||||
renderThumbnail() {
|
||||
// Should be implemented by in subclasses.
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -360,62 +187,6 @@ export default class SmallVideo {
|
||||
return $($(this.container).find('video')[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the HTML image element which displays user's avatar.
|
||||
*
|
||||
* @return {jQuery|HTMLElement} a jQuery selector pointing to the HTML image
|
||||
* element which displays the user's avatar.
|
||||
*/
|
||||
$avatar() {
|
||||
return this.$container.find('.avatar-container');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the display name element, which appears on the video thumbnail.
|
||||
*
|
||||
* @return {jQuery} a jQuery selector pointing to the display name element of
|
||||
* the video thumbnail
|
||||
*/
|
||||
$displayName() {
|
||||
return this.$container.find('.displayNameContainer');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or updates the participant's display name that is shown over the
|
||||
* video preview.
|
||||
*
|
||||
* @param {Object} props - The React {@code Component} props to pass into the
|
||||
* {@code DisplayName} component.
|
||||
* @returns {void}
|
||||
*/
|
||||
_renderDisplayName(props) {
|
||||
const displayNameContainer = this.container.querySelector('.displayNameContainer');
|
||||
|
||||
if (displayNameContainer) {
|
||||
ReactDOM.render(
|
||||
<Provider store = { APP.store }>
|
||||
<I18nextProvider i18n = { i18next }>
|
||||
<DisplayName { ...props } />
|
||||
</I18nextProvider>
|
||||
</Provider>,
|
||||
displayNameContainer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the component responsible for showing the participant's display name,
|
||||
* if its container is present.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
removeDisplayName() {
|
||||
const displayNameContainer = this.container.querySelector('.displayNameContainer');
|
||||
|
||||
if (displayNameContainer) {
|
||||
ReactDOM.unmountComponentAtNode(displayNameContainer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables / disables the css responsible for focusing/pinning a video
|
||||
* thumbnail.
|
||||
@@ -459,7 +230,18 @@ export default class SmallVideo {
|
||||
* or <tt>false</tt> otherwise.
|
||||
*/
|
||||
isVideoPlayable() {
|
||||
return this.videoStream && !this.isVideoMuted && !APP.conference.isAudioOnly();
|
||||
const state = APP.store.getState();
|
||||
const tracks = state['features/base/tracks'];
|
||||
const participant = this.id ? getParticipantById(state, this.id) : getLocalParticipant(state);
|
||||
let isVideoMuted = true;
|
||||
|
||||
if (participant?.local) {
|
||||
isVideoMuted = isLocalTrackMuted(tracks, MEDIA_TYPE.VIDEO);
|
||||
} else if (!participant?.isFakeParticipant) { // remote participants excluding shared video
|
||||
isVideoMuted = isRemoteTrackMuted(tracks, MEDIA_TYPE.VIDEO, this.id);
|
||||
}
|
||||
|
||||
return this.videoStream && !isVideoMuted && !APP.conference.isAudioOnly();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -489,19 +271,32 @@ export default class SmallVideo {
|
||||
* @returns {Object}
|
||||
*/
|
||||
computeDisplayModeInput() {
|
||||
let isScreenSharing = false;
|
||||
let connectionStatus, mutedWhileDisconnected;
|
||||
const state = APP.store.getState();
|
||||
const participant = getParticipantById(state, this.id);
|
||||
|
||||
if (typeof participant !== 'undefined' && !participant.isFakeParticipant && !participant.local) {
|
||||
const tracks = state['features/base/tracks'];
|
||||
const track = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, this.id);
|
||||
|
||||
isScreenSharing = typeof track !== 'undefined' && track.videoType === 'desktop';
|
||||
connectionStatus = participant.connectionStatus;
|
||||
mutedWhileDisconnected = participant.mutedWhileDisconnected;
|
||||
}
|
||||
|
||||
return {
|
||||
isCurrentlyOnLargeVideo: this.isCurrentlyOnLargeVideo(),
|
||||
isHovered: this._isHovered(),
|
||||
isAudioOnly: APP.conference.isAudioOnly(),
|
||||
tileViewActive: shouldDisplayTileView(APP.store.getState()),
|
||||
tileViewActive: shouldDisplayTileView(state),
|
||||
isVideoPlayable: this.isVideoPlayable(),
|
||||
hasVideo: Boolean(this.selectVideoElement().length),
|
||||
connectionStatus: APP.conference.getParticipantConnectionStatus(this.id),
|
||||
mutedWhileDisconnected: this.mutedWhileDisconnected,
|
||||
connectionStatus,
|
||||
mutedWhileDisconnected,
|
||||
canPlayEventReceived: this._canPlayEventReceived,
|
||||
videoStream: Boolean(this.videoStream),
|
||||
isVideoMuted: this.isVideoMuted,
|
||||
isScreenSharing: this.isScreenSharing,
|
||||
isScreenSharing,
|
||||
videoStreamMuted: this.videoStream ? this.videoStream.isMuted() : 'no stream'
|
||||
};
|
||||
}
|
||||
@@ -513,7 +308,7 @@ export default class SmallVideo {
|
||||
* @private
|
||||
*/
|
||||
_isHovered() {
|
||||
return this.videoIsHovered || this._popoverIsHovered;
|
||||
return this.videoIsHovered;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -560,43 +355,6 @@ export default class SmallVideo {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the react component displaying the avatar with the passed in avatar
|
||||
* url.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
initializeAvatar() {
|
||||
const thumbnail = this.$avatar().get(0);
|
||||
|
||||
if (thumbnail) {
|
||||
// Maybe add a special case for local participant, as on init of
|
||||
// LocalVideo.js the id is set to "local" but will get updated later.
|
||||
ReactDOM.render(
|
||||
<Provider store = { APP.store }>
|
||||
<AvatarDisplay
|
||||
className = 'userAvatar'
|
||||
participantId = { this.id } />
|
||||
</Provider>,
|
||||
thumbnail
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmounts any attached react components (particular the avatar image) from
|
||||
* the avatar container.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
removeAvatar() {
|
||||
const thumbnail = this.$avatar().get(0);
|
||||
|
||||
if (thumbnail) {
|
||||
ReactDOM.unmountComponentAtNode(thumbnail);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows or hides the dominant speaker indicator.
|
||||
* @param show whether to show or hide.
|
||||
@@ -613,30 +371,8 @@ export default class SmallVideo {
|
||||
|
||||
return;
|
||||
}
|
||||
if (this._showDominantSpeaker === show) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._showDominantSpeaker = show;
|
||||
this.$container.toggleClass('active-speaker', this._showDominantSpeaker);
|
||||
this.updateIndicators();
|
||||
this.updateView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows or hides the raised hand indicator.
|
||||
* @param show whether to show or hide.
|
||||
*/
|
||||
showRaisedHandIndicator(show) {
|
||||
if (!this.container) {
|
||||
logger.warn(`Unable to raised hand indication - ${
|
||||
this.videoSpanId} does not exist`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this._showRaisedHand = show;
|
||||
this.updateIndicators();
|
||||
this.$container.toggleClass('active-speaker', show);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -667,19 +403,7 @@ export default class SmallVideo {
|
||||
*/
|
||||
remove() {
|
||||
logger.log('Remove thumbnail', this.id);
|
||||
this.removeAudioLevelIndicator();
|
||||
|
||||
const toolbarContainer
|
||||
= this.container.querySelector('.videocontainer__toolbar');
|
||||
|
||||
if (toolbarContainer) {
|
||||
ReactDOM.unmountComponentAtNode(toolbarContainer);
|
||||
}
|
||||
|
||||
this.removeConnectionIndicator();
|
||||
this.removeDisplayName();
|
||||
this.removeAvatar();
|
||||
this._unmountIndicators();
|
||||
this._unmountThumbnail();
|
||||
|
||||
// Remove whole container
|
||||
if (this.container.parentNode) {
|
||||
@@ -694,77 +418,9 @@ export default class SmallVideo {
|
||||
* @returns {void}
|
||||
*/
|
||||
rerender() {
|
||||
this.updateIndicators();
|
||||
this.updateStatusBar();
|
||||
this.updateView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the React element responsible for showing connection status, dominant
|
||||
* speaker, and raised hand icons. Uses instance variables to get the necessary
|
||||
* state to display. Will create the React element if not already created.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
updateIndicators() {
|
||||
const indicatorToolbar = this.container.querySelector('.videocontainer__toptoolbar');
|
||||
|
||||
if (!indicatorToolbar) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { NORMAL = 8 } = interfaceConfig.INDICATOR_FONT_SIZES || {};
|
||||
const iconSize = NORMAL;
|
||||
const showConnectionIndicator = this.videoIsHovered || !interfaceConfig.CONNECTION_INDICATOR_AUTO_HIDE_ENABLED;
|
||||
const state = APP.store.getState();
|
||||
const currentLayout = getCurrentLayout(state);
|
||||
const participantCount = getParticipantCount(state);
|
||||
let statsPopoverPosition, tooltipPosition;
|
||||
|
||||
if (currentLayout === LAYOUTS.TILE_VIEW) {
|
||||
statsPopoverPosition = 'right top';
|
||||
tooltipPosition = 'right';
|
||||
} else if (currentLayout === LAYOUTS.VERTICAL_FILMSTRIP_VIEW) {
|
||||
statsPopoverPosition = this.statsPopoverLocation;
|
||||
tooltipPosition = 'left';
|
||||
} else {
|
||||
statsPopoverPosition = this.statsPopoverLocation;
|
||||
tooltipPosition = 'top';
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store = { APP.store }>
|
||||
<I18nextProvider i18n = { i18next }>
|
||||
<div>
|
||||
<AtlasKitThemeProvider mode = 'dark'>
|
||||
{ this._showConnectionIndicator
|
||||
? <ConnectionIndicator
|
||||
alwaysVisible = { showConnectionIndicator }
|
||||
connectionStatus = { this._connectionStatus }
|
||||
iconSize = { iconSize }
|
||||
isLocalVideo = { this.isLocal }
|
||||
enableStatsDisplay = { !interfaceConfig.filmStripOnly }
|
||||
participantId = { this.id }
|
||||
statsPopoverPosition = { statsPopoverPosition } />
|
||||
: null }
|
||||
<RaisedHandIndicator
|
||||
iconSize = { iconSize }
|
||||
participantId = { this.id }
|
||||
tooltipPosition = { tooltipPosition } />
|
||||
{ this._showDominantSpeaker && participantCount > 2
|
||||
? <DominantSpeakerIndicator
|
||||
iconSize = { iconSize }
|
||||
tooltipPosition = { tooltipPosition } />
|
||||
: null }
|
||||
</AtlasKitThemeProvider>
|
||||
</div>
|
||||
</I18nextProvider>
|
||||
</Provider>,
|
||||
indicatorToolbar
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when the thumbnail is clicked and potentially trigger
|
||||
* pinning of the participant.
|
||||
@@ -822,31 +478,10 @@ export default class SmallVideo {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the React element responsible for showing connection status, dominant
|
||||
* speaker, and raised hand icons.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
* Unmounts the thumbnail.
|
||||
*/
|
||||
_unmountIndicators() {
|
||||
const indicatorToolbar = this.container.querySelector('.videocontainer__toptoolbar');
|
||||
|
||||
if (indicatorToolbar) {
|
||||
ReactDOM.unmountComponentAtNode(indicatorToolbar);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current state of the connection indicator popover being hovered.
|
||||
* If hovered, display the small video as if it is hovered.
|
||||
*
|
||||
* @param {boolean} popoverIsHovered - Whether or not the mouse cursor is
|
||||
* currently over the connection indicator popover.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onPopoverHover(popoverIsHovered) {
|
||||
this._popoverIsHovered = popoverIsHovered;
|
||||
this.updateView();
|
||||
_unmountThumbnail() {
|
||||
ReactDOM.unmountComponentAtNode(this.container);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -860,10 +495,6 @@ export default class SmallVideo {
|
||||
switch (layout) {
|
||||
case LAYOUTS.VERTICAL_FILMSTRIP_VIEW: {
|
||||
this.$container.css('padding-top', `${heightToWidthPercent}%`);
|
||||
this.$avatar().css({
|
||||
height: '50%',
|
||||
width: `${heightToWidthPercent / 2}%`
|
||||
});
|
||||
break;
|
||||
}
|
||||
case LAYOUTS.HORIZONTAL_FILMSTRIP_VIEW: {
|
||||
@@ -873,7 +504,6 @@ export default class SmallVideo {
|
||||
|
||||
if (typeof size !== 'undefined') {
|
||||
const { height, width } = size;
|
||||
const avatarSize = height / 2;
|
||||
|
||||
this.$container.css({
|
||||
height: `${height}px`,
|
||||
@@ -881,10 +511,6 @@ export default class SmallVideo {
|
||||
'min-width': `${width}px`,
|
||||
width: `${width}px`
|
||||
});
|
||||
this.$avatar().css({
|
||||
height: `${avatarSize}px`,
|
||||
width: `${avatarSize}px`
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -894,7 +520,6 @@ export default class SmallVideo {
|
||||
|
||||
if (typeof thumbnailSize !== 'undefined') {
|
||||
const { height, width } = thumbnailSize;
|
||||
const avatarSize = height / 2;
|
||||
|
||||
this.$container.css({
|
||||
height: `${height}px`,
|
||||
@@ -902,10 +527,6 @@ export default class SmallVideo {
|
||||
'min-width': `${width}px`,
|
||||
width: `${width}px`
|
||||
});
|
||||
this.$avatar().css({
|
||||
height: `${avatarSize}px`,
|
||||
width: `${avatarSize}px`
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ function onLocalFlipXChanged(val) {
|
||||
*/
|
||||
function getAllThumbnails() {
|
||||
return [
|
||||
localVideoThumbnail,
|
||||
...localVideoThumbnail ? [ localVideoThumbnail ] : [],
|
||||
...Object.values(remoteVideos)
|
||||
];
|
||||
}
|
||||
@@ -116,12 +116,6 @@ const VideoLayout = {
|
||||
* @param lvl the new audio level to update to
|
||||
*/
|
||||
setAudioLevel(id, lvl) {
|
||||
const smallVideo = this.getSmallVideo(id);
|
||||
|
||||
if (smallVideo) {
|
||||
smallVideo.updateAudioLevelIndicator(lvl);
|
||||
}
|
||||
|
||||
if (largeVideo && id === largeVideo.id) {
|
||||
largeVideo.updateLargeVideoAudioLevel(lvl);
|
||||
}
|
||||
@@ -137,19 +131,6 @@ const VideoLayout = {
|
||||
this._updateLargeVideoIfDisplayed(localId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get's the localID of the conference and set it to the local video
|
||||
* (small one). This needs to be called as early as possible, when muc is
|
||||
* actually joined. Otherwise events can come with information like email
|
||||
* and setting them assume the id is already set.
|
||||
*/
|
||||
mucJoined() {
|
||||
// FIXME: replace this call with a generic update call once SmallVideo
|
||||
// only contains a ReactElement. Then remove this call once the
|
||||
// Filmstrip is fully in React.
|
||||
localVideoThumbnail.updateIndicators();
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows/hides local video.
|
||||
* @param {boolean} true to make the local video visible, false - otherwise
|
||||
@@ -173,11 +154,9 @@ const VideoLayout = {
|
||||
remoteVideo.addRemoteStreamElement(stream);
|
||||
|
||||
// Make sure track's muted state is reflected
|
||||
if (stream.getType() === 'audio') {
|
||||
this.onAudioMute(id, stream.isMuted());
|
||||
} else {
|
||||
this.onVideoMute(id, stream.isMuted());
|
||||
remoteVideo.setScreenSharing(stream.videoType === 'desktop');
|
||||
if (stream.getType() !== 'audio') {
|
||||
this.onVideoMute(id);
|
||||
remoteVideo.updateView();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -189,7 +168,7 @@ const VideoLayout = {
|
||||
|
||||
if (remoteVideo) {
|
||||
remoteVideo.removeRemoteStreamElement(stream);
|
||||
remoteVideo.setScreenSharing(false);
|
||||
remoteVideo.updateView();
|
||||
}
|
||||
|
||||
this.updateMutedForNoTracks(id, stream.getType());
|
||||
@@ -210,7 +189,7 @@ const VideoLayout = {
|
||||
if (mediaType === 'audio') {
|
||||
APP.UI.setAudioMuted(participantId, true);
|
||||
} else if (mediaType === 'video') {
|
||||
APP.UI.setVideoMuted(participantId, true);
|
||||
APP.UI.setVideoMuted(participantId);
|
||||
} else {
|
||||
logger.error(`Unsupported media type: ${mediaType}`);
|
||||
}
|
||||
@@ -329,35 +308,17 @@ const VideoLayout = {
|
||||
this._updateLargeVideoIfDisplayed(resourceJid, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* On audio muted event.
|
||||
*/
|
||||
onAudioMute(id, isMuted) {
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
localVideoThumbnail.showAudioIndicator(isMuted);
|
||||
} else {
|
||||
const remoteVideo = remoteVideos[id];
|
||||
|
||||
if (!remoteVideo) {
|
||||
return;
|
||||
}
|
||||
|
||||
remoteVideo.showAudioIndicator(isMuted);
|
||||
remoteVideo.updateRemoteVideoMenu();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* On video muted event.
|
||||
*/
|
||||
onVideoMute(id, value) {
|
||||
onVideoMute(id) {
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
localVideoThumbnail && localVideoThumbnail.setVideoMutedView(value);
|
||||
localVideoThumbnail && localVideoThumbnail.updateView();
|
||||
} else {
|
||||
const remoteVideo = remoteVideos[id];
|
||||
|
||||
if (remoteVideo) {
|
||||
remoteVideo.setVideoMutedView(value);
|
||||
remoteVideo.updateView();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,22 +326,6 @@ const VideoLayout = {
|
||||
this._updateLargeVideoIfDisplayed(id, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Display name changed.
|
||||
*/
|
||||
onDisplayNameChanged(id) {
|
||||
if (id === 'localVideoContainer'
|
||||
|| APP.conference.isLocalId(id)) {
|
||||
localVideoThumbnail.updateDisplayName();
|
||||
} else {
|
||||
const remoteVideo = remoteVideos[id];
|
||||
|
||||
if (remoteVideo) {
|
||||
remoteVideo.updateDisplayName();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* On dominant speaker changed event.
|
||||
*
|
||||
@@ -411,12 +356,6 @@ const VideoLayout = {
|
||||
const remoteVideo = remoteVideos[id];
|
||||
|
||||
if (remoteVideo) {
|
||||
// Updating only connection status indicator is not enough, because
|
||||
// when we the connection is restored while the avatar was displayed
|
||||
// (due to 'muted while disconnected' condition) we may want to show
|
||||
// the video stream again and in order to do that the display mode
|
||||
// must be updated.
|
||||
// remoteVideo.updateConnectionStatusIndicator(isActive);
|
||||
remoteVideo.updateView();
|
||||
}
|
||||
},
|
||||
@@ -453,20 +392,6 @@ const VideoLayout = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Hides all the indicators
|
||||
*/
|
||||
hideStats() {
|
||||
for (const video in remoteVideos) { // eslint-disable-line guard-for-in
|
||||
const remoteVideo = remoteVideos[video];
|
||||
|
||||
if (remoteVideo) {
|
||||
remoteVideo.removeConnectionIndicator();
|
||||
}
|
||||
}
|
||||
localVideoThumbnail.removeConnectionIndicator();
|
||||
},
|
||||
|
||||
removeParticipantContainer(id) {
|
||||
// Unlock large video
|
||||
if (this.getPinnedId() === id) {
|
||||
@@ -494,7 +419,7 @@ const VideoLayout = {
|
||||
}
|
||||
|
||||
logger.info('Peer video type changed: ', id, newVideoType);
|
||||
remoteVideo.setScreenSharing(newVideoType === 'desktop');
|
||||
remoteVideo.updateView();
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -517,15 +442,6 @@ const VideoLayout = {
|
||||
},
|
||||
|
||||
changeUserAvatar(id, avatarUrl) {
|
||||
const smallVideo = VideoLayout.getSmallVideo(id);
|
||||
|
||||
if (smallVideo) {
|
||||
smallVideo.initializeAvatar();
|
||||
} else {
|
||||
logger.warn(
|
||||
`Missed avatar update - no small video yet for ${id}`
|
||||
);
|
||||
}
|
||||
if (this.isCurrentlyOnLarge(id)) {
|
||||
largeVideo.updateAvatar(avatarUrl);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import EventEmitter from 'events';
|
||||
import { getLogger } from 'jitsi-meet-logger';
|
||||
|
||||
import JitsiMeetJS from '../../react/features/base/lib-jitsi-meet';
|
||||
import { DISCO_REMOTE_CONTROL_FEATURE }
|
||||
from '../../service/remotecontrol/Constants';
|
||||
import * as RemoteControlEvents
|
||||
@@ -68,9 +69,7 @@ class RemoteControl extends EventEmitter {
|
||||
* @returns {void}
|
||||
*/
|
||||
init() {
|
||||
if (config.disableRemoteControl
|
||||
|| this._initialized
|
||||
|| !APP.conference.isDesktopSharingEnabled) {
|
||||
if (config.disableRemoteControl || this._initialized || !JitsiMeetJS.isDesktopSharingEnabled()) {
|
||||
return;
|
||||
}
|
||||
logger.log('Initializing remote control.');
|
||||
|
||||
397
package-lock.json
generated
397
package-lock.json
generated
@@ -4833,11 +4833,6 @@
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
"@webcomponents/url": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@webcomponents/url/-/url-0.7.1.tgz",
|
||||
"integrity": "sha512-9oFDpuZ+tAogjPYQPhNEX86Npzb73A4kv9DOPsSO9aWoWgoevoP6eKx+TKMwO8BJxtTpSM9nKenHQTJ56SP2Cw=="
|
||||
},
|
||||
"@xtuc/ieee754": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
|
||||
@@ -4927,9 +4922,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"amplitude-js": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/amplitude-js/-/amplitude-js-7.1.1.tgz",
|
||||
"integrity": "sha512-grEQf0p4V/q4aIcGYdGEJ6EquBXu91R/RorsYTQvh9O6sxjpwHf5vSDICQJq7twEElBrSHoSF77GUvC9ZTBj4A==",
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/amplitude-js/-/amplitude-js-7.3.1.tgz",
|
||||
"integrity": "sha512-dsJU9MdtDDAOtKnbHrJuVBgsL5UGxD1P2B7doGdAQ1hxxT/5mFrmJTFzi1tKe+2ir3QtcRa9B0qvH8TMsGw22A==",
|
||||
"requires": {
|
||||
"@amplitude/ua-parser-js": "0.7.24",
|
||||
"blueimp-md5": "^2.10.0",
|
||||
@@ -6410,8 +6405,7 @@
|
||||
"chownr": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
|
||||
},
|
||||
"chrome-trace-event": {
|
||||
"version": "1.0.2",
|
||||
@@ -7150,6 +7144,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"css-select": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz",
|
||||
"integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==",
|
||||
"requires": {
|
||||
"boolbase": "^1.0.0",
|
||||
"css-what": "^3.2.1",
|
||||
"domutils": "^1.7.0",
|
||||
"nth-check": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"css-to-react-native": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-2.3.2.tgz",
|
||||
@@ -7160,6 +7165,27 @@
|
||||
"postcss-value-parser": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"css-tree": {
|
||||
"version": "1.0.0-alpha.39",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.39.tgz",
|
||||
"integrity": "sha512-7UvkEYgBAHRG9Nt980lYxjsTrCyHFN53ky3wVsDkiMdVqylqRt+Zc+jm5qw7/qyOvN2dHSYtX0e4MbCCExSvnA==",
|
||||
"requires": {
|
||||
"mdn-data": "2.0.6",
|
||||
"source-map": "^0.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"mdn-data": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.6.tgz",
|
||||
"integrity": "sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"css-what": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz",
|
||||
@@ -8145,6 +8171,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||
},
|
||||
"esquery": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
|
||||
@@ -8735,6 +8766,11 @@
|
||||
"resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-0.6.3.tgz",
|
||||
"integrity": "sha512-EU6ePgEauhWrzJEN5RtG1d1ayrWXhEnfzTjnieHj+jG9tNHDEhKTAnCn1TN3gs9h6XWCDH6cpeX1VXY/lzLwZg=="
|
||||
},
|
||||
"focus-visible": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/focus-visible/-/focus-visible-5.1.0.tgz",
|
||||
"integrity": "sha512-nPer0rjtzdZ7csVIu233P2cUm/ks/4aVSI+5KUkYrYpgA7ujgC3p6J7FtFU+AIMWwnwYQOB/yeiOITxFeYIXiw=="
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz",
|
||||
@@ -8818,6 +8854,15 @@
|
||||
"universalify": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"fs-minipass": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
|
||||
"integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minipass": "^2.6.0"
|
||||
}
|
||||
},
|
||||
"fs-write-stream-atomic": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
|
||||
@@ -8889,12 +8934,6 @@
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"chownr": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
|
||||
"optional": true
|
||||
},
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"resolved": false,
|
||||
@@ -8946,15 +8985,6 @@
|
||||
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
|
||||
"optional": true
|
||||
},
|
||||
"fs-minipass": {
|
||||
"version": "1.2.5",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minipass": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
@@ -9061,38 +9091,13 @@
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.3.5",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"minizlib": {
|
||||
"version": "1.2.1",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minipass": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
@@ -9236,9 +9241,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
@@ -9338,21 +9343,6 @@
|
||||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
|
||||
"optional": true
|
||||
},
|
||||
"tar": {
|
||||
"version": "4.4.8",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"chownr": "^1.1.1",
|
||||
"fs-minipass": "^1.2.5",
|
||||
"minipass": "^2.3.4",
|
||||
"minizlib": "^1.1.1",
|
||||
"mkdirp": "^0.5.0",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
@@ -9373,12 +9363,6 @@
|
||||
"resolved": false,
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -10637,6 +10621,15 @@
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
|
||||
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.14.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
|
||||
"integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"jsc-android": {
|
||||
"version": "245459.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsc-android/-/jsc-android-245459.0.0.tgz",
|
||||
@@ -10778,8 +10771,8 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "github:jitsi/lib-jitsi-meet#0cffc064e644ad87ff381cc6c4df1c1a9f2c73ff",
|
||||
"from": "github:jitsi/lib-jitsi-meet#0cffc064e644ad87ff381cc6c4df1c1a9f2c73ff",
|
||||
"version": "github:jitsi/lib-jitsi-meet#6bb0b86c0a7dd22bb5798236d9b80ca578b28d21",
|
||||
"from": "github:jitsi/lib-jitsi-meet#6bb0b86c0a7dd22bb5798236d9b80ca578b28d21",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "1.0.2",
|
||||
"@jitsi/sdp-interop": "1.0.3",
|
||||
@@ -11886,6 +11879,39 @@
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
|
||||
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"minizlib": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
|
||||
"integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minipass": "^2.9.0"
|
||||
}
|
||||
},
|
||||
"mississippi": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
|
||||
@@ -12099,9 +12125,9 @@
|
||||
}
|
||||
},
|
||||
"node-forge": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz",
|
||||
"integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==",
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
|
||||
"integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==",
|
||||
"dev": true
|
||||
},
|
||||
"node-int64": {
|
||||
@@ -12559,8 +12585,8 @@
|
||||
"dev": true
|
||||
},
|
||||
"olm": {
|
||||
"version": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz",
|
||||
"integrity": "sha512-kumW7B+xWMdiGSU0BrECOd+9GnhvsnnHP6qTHGPIcHTL2F0m8sYlP08hkEpN7uX/TlnHCwqpkaZXPQ0GYtVe8A=="
|
||||
"version": "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz",
|
||||
"integrity": "sha512-B87bTpGIGieuV2FNauChjjQtVltwTGagQFoHm+3Dcse4amKAAGJB/I54dnP/JtbHZ+RYVoApM2OQ46Z4VH6eNg=="
|
||||
},
|
||||
"on-finished": {
|
||||
"version": "2.3.0",
|
||||
@@ -12883,8 +12909,7 @@
|
||||
"path-dirname": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
|
||||
"integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
|
||||
"dev": true
|
||||
"integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA="
|
||||
},
|
||||
"path-exists": {
|
||||
"version": "3.0.0",
|
||||
@@ -12939,11 +12964,6 @@
|
||||
"sha.js": "^2.4.8"
|
||||
}
|
||||
},
|
||||
"performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
|
||||
@@ -13458,14 +13478,6 @@
|
||||
"integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==",
|
||||
"dev": true
|
||||
},
|
||||
"raf": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.0.tgz",
|
||||
"integrity": "sha512-pDP/NMRAXoTfrhCfyfSEwJAKLaxBU9eApMeBPB1TkDouZmvPerIClV8lTAd+uF8ZiTaVl69e1FCxQrAd/VTjGw==",
|
||||
"requires": {
|
||||
"performance-now": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"raf-schd": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-2.1.2.tgz",
|
||||
@@ -13726,8 +13738,8 @@
|
||||
}
|
||||
},
|
||||
"react-native": {
|
||||
"version": "github:jitsi/react-native#efd2aff5661d75a230e36406b698cfe0ee545be2",
|
||||
"from": "github:jitsi/react-native#efd2aff5661d75a230e36406b698cfe0ee545be2",
|
||||
"version": "github:jitsi/react-native#891986ec5ecaef65d1c8a7fe472f86cf84fe7551",
|
||||
"from": "github:jitsi/react-native#891986ec5ecaef65d1c8a7fe472f86cf84fe7551",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"@react-native-community/cli": "^3.0.0",
|
||||
@@ -14146,20 +14158,92 @@
|
||||
"version": "github:jitsi/react-native-sound#3fe5480fce935e888d5089d94a191c7c7e3aa190",
|
||||
"from": "github:jitsi/react-native-sound#3fe5480fce935e888d5089d94a191c7c7e3aa190"
|
||||
},
|
||||
"react-native-splash-screen": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-splash-screen/-/react-native-splash-screen-3.2.0.tgz",
|
||||
"integrity": "sha512-Ls9qiNZzW/OLFoI25wfjjAcrf2DZ975hn2vr6U9gyuxi2nooVbzQeFoQS5vQcbCt9QX5NY8ASEEAtlLdIa6KVg=="
|
||||
},
|
||||
"react-native-svg": {
|
||||
"version": "9.7.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-9.7.1.tgz",
|
||||
"integrity": "sha512-Yr54SyLPCdovLCJ08V7syJUe1iKrTYG9V5wB08z6lh/9FdC2R9CtBnMyz83GDLKfzUONqqH9nN1l+o61CgD3tg=="
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-10.1.0.tgz",
|
||||
"integrity": "sha512-mgo6CshQIQrDDBVUPqJK/iOsJEdlagk7N4q8fyo1sqCiSUP2efpt+AQ1IRXZtHXut210/7TliAamvM59NV0Bzg==",
|
||||
"requires": {
|
||||
"css-select": "^2.1.0",
|
||||
"css-tree": "^1.0.0-alpha.39"
|
||||
}
|
||||
},
|
||||
"react-native-svg-transformer": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-svg-transformer/-/react-native-svg-transformer-0.13.0.tgz",
|
||||
"integrity": "sha512-tfcnIDC2Q6FN8+g/BXPootZtb+sWLzKJde3o5jSuUJdXSmKwwSazAbk+V808n/Ez5kd2arzsuPTKONT66qx5Xw==",
|
||||
"version": "0.14.3",
|
||||
"resolved": "https://registry.npmjs.org/react-native-svg-transformer/-/react-native-svg-transformer-0.14.3.tgz",
|
||||
"integrity": "sha512-agDGdMeeBAsWEgg/u7mjtR2Z3c8smGCLep/n3svwifut9dpswZCP+bSIrU8ekg6RNtxAJL+eGJbWjJ38vWxw6g==",
|
||||
"requires": {
|
||||
"@svgr/core": "^4.1.0",
|
||||
"@svgr/core": "^4.3.3",
|
||||
"@svgr/plugin-svgo": "^4.3.1",
|
||||
"path-dirname": "^1.0.2",
|
||||
"semver": "^5.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@svgr/babel-plugin-svg-dynamic-title": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-4.3.3.tgz",
|
||||
"integrity": "sha512-w3Be6xUNdwgParsvxkkeZb545VhXEwjGMwExMVBIdPQJeyMQHqm9Msnb2a1teHBqUYL66qtwfhNkbj1iarCG7w=="
|
||||
},
|
||||
"@svgr/babel-preset": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-4.3.3.tgz",
|
||||
"integrity": "sha512-6PG80tdz4eAlYUN3g5GZiUjg2FMcp+Wn6rtnz5WJG9ITGEF1pmFdzq02597Hn0OmnQuCVaBYQE1OVFAnwOl+0A==",
|
||||
"requires": {
|
||||
"@svgr/babel-plugin-add-jsx-attribute": "^4.2.0",
|
||||
"@svgr/babel-plugin-remove-jsx-attribute": "^4.2.0",
|
||||
"@svgr/babel-plugin-remove-jsx-empty-expression": "^4.2.0",
|
||||
"@svgr/babel-plugin-replace-jsx-attribute-value": "^4.2.0",
|
||||
"@svgr/babel-plugin-svg-dynamic-title": "^4.3.3",
|
||||
"@svgr/babel-plugin-svg-em-dimensions": "^4.2.0",
|
||||
"@svgr/babel-plugin-transform-react-native-svg": "^4.2.0",
|
||||
"@svgr/babel-plugin-transform-svg-component": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"@svgr/core": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@svgr/core/-/core-4.3.3.tgz",
|
||||
"integrity": "sha512-qNuGF1QON1626UCaZamWt5yedpgOytvLj5BQZe2j1k1B8DUG4OyugZyfEwBeXozCUwhLEpsrgPrE+eCu4fY17w==",
|
||||
"requires": {
|
||||
"@svgr/plugin-jsx": "^4.3.3",
|
||||
"camelcase": "^5.3.1",
|
||||
"cosmiconfig": "^5.2.1"
|
||||
}
|
||||
},
|
||||
"@svgr/plugin-jsx": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-4.3.3.tgz",
|
||||
"integrity": "sha512-cLOCSpNWQnDB1/v+SUENHH7a0XY09bfuMKdq9+gYvtuwzC2rU4I0wKGFEp1i24holdQdwodCtDQdFtJiTCWc+w==",
|
||||
"requires": {
|
||||
"@babel/core": "^7.4.5",
|
||||
"@svgr/babel-preset": "^4.3.3",
|
||||
"@svgr/hast-util-to-babel-ast": "^4.3.2",
|
||||
"svg-parser": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"cosmiconfig": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
|
||||
"integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
|
||||
"requires": {
|
||||
"import-fresh": "^2.0.0",
|
||||
"is-directory": "^0.3.1",
|
||||
"js-yaml": "^3.13.1",
|
||||
"parse-json": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"parse-json": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
||||
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
|
||||
"requires": {
|
||||
"error-ex": "^1.3.1",
|
||||
"json-parse-better-errors": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
@@ -14167,14 +14251,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-native-swipeout": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/react-native-swipeout/-/react-native-swipeout-2.3.6.tgz",
|
||||
"integrity": "sha512-t9suUCspzck4vp2pWggWe0frS/QOtX6yYCawHnEes75A7dZCEE74bxX2A1bQzGH9cUMjq6xsdfC94RbiDKIkJg==",
|
||||
"react-native-url-polyfill": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-url-polyfill/-/react-native-url-polyfill-1.2.0.tgz",
|
||||
"integrity": "sha512-hpLZ8RyS3oGVyTOe/HjoqVoCOSkeJvrCoEB3bJsY7t9uh7kpQDV6kgvdlECEafYpxe3RzMrKLVcmWRbPU7CuAw==",
|
||||
"requires": {
|
||||
"create-react-class": "^15.6.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react-tween-state": "^0.1.5"
|
||||
"whatwg-url-without-unicode": "8.0.0-3"
|
||||
}
|
||||
},
|
||||
"react-native-watch-connectivity": {
|
||||
@@ -14183,9 +14265,9 @@
|
||||
"integrity": "sha512-iqdJ1KpZbR4XGahgVmaeibB7kDhyMT7wrylINgJaYBY38IAiI0LF32VX1umO4pko6n21YF5I/kSeNQ+OXGqqow=="
|
||||
},
|
||||
"react-native-webrtc": {
|
||||
"version": "1.84.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.84.0.tgz",
|
||||
"integrity": "sha512-xPOFbrcehuBzLnFy3keCM2HyMsyCVDQjQNAn8SIHKH/PA8Q7kZ4spuytc2E1hBTr7zH/vQ2Px+DWqu7on12jag==",
|
||||
"version": "1.84.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.84.1.tgz",
|
||||
"integrity": "sha512-ewZBgKE+YhLaivo9Wh6aiaEp8ZRvFMqblrkDl1nptQiNNH6CungoAzSOxGDnHWAxepRfiUrW5qnADrsYKmaNeQ==",
|
||||
"requires": {
|
||||
"base64-js": "^1.1.2",
|
||||
"event-target-shim": "^1.0.5",
|
||||
@@ -14351,15 +14433,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-tween-state": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/react-tween-state/-/react-tween-state-0.1.5.tgz",
|
||||
"integrity": "sha1-6YsGZVHvuTy5LdG+FJlcLj3q4zk=",
|
||||
"requires": {
|
||||
"raf": "^3.1.0",
|
||||
"tween-functions": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"react-uid": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-uid/-/react-uid-2.2.0.tgz",
|
||||
@@ -14940,12 +15013,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"selfsigned": {
|
||||
"version": "1.10.7",
|
||||
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz",
|
||||
"integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==",
|
||||
"version": "1.10.8",
|
||||
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz",
|
||||
"integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"node-forge": "0.9.0"
|
||||
"node-forge": "^0.10.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
@@ -16264,6 +16337,35 @@
|
||||
"integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
|
||||
"dev": true
|
||||
},
|
||||
"tar": {
|
||||
"version": "4.4.13",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz",
|
||||
"integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"chownr": "^1.1.1",
|
||||
"fs-minipass": "^1.2.5",
|
||||
"minipass": "^2.8.6",
|
||||
"minizlib": "^1.2.1",
|
||||
"mkdirp": "^0.5.0",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"temp": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz",
|
||||
@@ -16655,11 +16757,6 @@
|
||||
"integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
|
||||
"dev": true
|
||||
},
|
||||
"tween-functions": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz",
|
||||
"integrity": "sha1-GuOlDnxguz3vd06scHrLynO7w/8="
|
||||
},
|
||||
"type-check": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
|
||||
@@ -17135,6 +17232,11 @@
|
||||
"defaults": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
|
||||
"integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="
|
||||
},
|
||||
"webpack": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.43.0.tgz",
|
||||
@@ -18447,6 +18549,27 @@
|
||||
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz",
|
||||
"integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ="
|
||||
},
|
||||
"whatwg-url-without-unicode": {
|
||||
"version": "8.0.0-3",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url-without-unicode/-/whatwg-url-without-unicode-8.0.0-3.tgz",
|
||||
"integrity": "sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==",
|
||||
"requires": {
|
||||
"buffer": "^5.4.3",
|
||||
"punycode": "^2.1.1",
|
||||
"webidl-conversions": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"buffer": {
|
||||
"version": "5.6.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz",
|
||||
"integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==",
|
||||
"requires": {
|
||||
"base64-js": "^1.0.2",
|
||||
"ieee754": "^1.1.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"which": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
|
||||
|
||||
21
package.json
21
package.json
@@ -40,11 +40,11 @@
|
||||
"@svgr/webpack": "4.3.2",
|
||||
"@tensorflow-models/body-pix": "2.0.4",
|
||||
"@tensorflow/tfjs": "1.5.1",
|
||||
"@webcomponents/url": "0.7.1",
|
||||
"amplitude-js": "7.1.1",
|
||||
"amplitude-js": "7.3.1",
|
||||
"base64-js": "1.3.1",
|
||||
"bc-css-flags": "3.0.0",
|
||||
"dropbox": "4.0.9",
|
||||
"focus-visible": "5.1.0",
|
||||
"i18n-iso-countries": "3.7.8",
|
||||
"i18next": "17.0.6",
|
||||
"i18next-browser-languagedetector": "3.0.1",
|
||||
@@ -56,12 +56,12 @@
|
||||
"jquery-i18next": "1.2.1",
|
||||
"js-md5": "0.6.1",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#0cffc064e644ad87ff381cc6c4df1c1a9f2c73ff",
|
||||
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#6bb0b86c0a7dd22bb5798236d9b80ca578b28d21",
|
||||
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
|
||||
"lodash": "4.17.19",
|
||||
"moment": "2.19.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
"olm": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz",
|
||||
"olm": "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz",
|
||||
"pixelmatch": "5.1.0",
|
||||
"punycode": "2.1.1",
|
||||
"react": "16.9",
|
||||
@@ -69,7 +69,7 @@
|
||||
"react-emoji-render": "1.2.4",
|
||||
"react-i18next": "10.11.4",
|
||||
"react-linkify": "1.0.0-alpha",
|
||||
"react-native": "github:jitsi/react-native#efd2aff5661d75a230e36406b698cfe0ee545be2",
|
||||
"react-native": "github:jitsi/react-native#891986ec5ecaef65d1c8a7fe472f86cf84fe7551",
|
||||
"react-native-background-timer": "2.4.0",
|
||||
"react-native-calendar-events": "github:jitsi/react-native-calendar-events#df48ecdc4e1e90c5352f803ddbab1fa7269b74a7",
|
||||
"react-native-callstats": "3.61.0",
|
||||
@@ -79,11 +79,12 @@
|
||||
"react-native-keep-awake": "4.0.0",
|
||||
"react-native-linear-gradient": "2.5.6",
|
||||
"react-native-sound": "github:jitsi/react-native-sound#3fe5480fce935e888d5089d94a191c7c7e3aa190",
|
||||
"react-native-svg": "9.7.1",
|
||||
"react-native-svg-transformer": "0.13.0",
|
||||
"react-native-swipeout": "2.3.6",
|
||||
"react-native-splash-screen": "3.2.0",
|
||||
"react-native-svg": "10.1.0",
|
||||
"react-native-svg-transformer": "0.14.3",
|
||||
"react-native-url-polyfill": "1.2.0",
|
||||
"react-native-watch-connectivity": "0.4.3",
|
||||
"react-native-webrtc": "1.84.0",
|
||||
"react-native-webrtc": "1.84.1",
|
||||
"react-native-webview": "10.9.0",
|
||||
"react-native-youtube-iframe": "1.2.3",
|
||||
"react-redux": "7.1.0",
|
||||
@@ -91,7 +92,7 @@
|
||||
"react-transition-group": "2.4.0",
|
||||
"redux": "4.0.4",
|
||||
"redux-thunk": "2.2.0",
|
||||
"rnnoise-wasm": "github:jitsi/rnnoise-wasm.git#566a16885897704d6e6d67a1d5ac5d39781db2af",
|
||||
"rnnoise-wasm": "github:jitsi/rnnoise-wasm#566a16885897704d6e6d67a1d5ac5d39781db2af",
|
||||
"rtcstats": "github:jitsi/rtcstats#v6.2.0",
|
||||
"stackblur-canvas": "2.3.0",
|
||||
"styled-components": "3.4.9",
|
||||
|
||||
88
pwa-worker.js
Normal file
88
pwa-worker.js
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright 2015, 2019, 2020 Google LLC. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
const CACHE_NAME = 'offline';
|
||||
|
||||
// Customize this with a different URL if needed.
|
||||
const OFFLINE_URL = 'static/offline.html';
|
||||
|
||||
self.addEventListener('install', event => {
|
||||
event.waitUntil(
|
||||
(async () => {
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
|
||||
|
||||
// Setting {cache: 'reload'} in the new request will ensure that the
|
||||
// response isn't fulfilled from the HTTP cache; i.e., it will be from
|
||||
// the network.
|
||||
await cache.add(new Request(OFFLINE_URL, { cache: 'reload' }));
|
||||
})()
|
||||
);
|
||||
|
||||
// Force the waiting service worker to become the active service worker.
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener('activate', event => {
|
||||
event.waitUntil(
|
||||
(async () => {
|
||||
// Enable navigation preload if it's supported.
|
||||
// See https://developers.google.com/web/updates/2017/02/navigation-preload
|
||||
if ('navigationPreload' in self.registration) {
|
||||
await self.registration.navigationPreload.enable();
|
||||
}
|
||||
})()
|
||||
);
|
||||
|
||||
// Tell the active service worker to take control of the page immediately.
|
||||
self.clients.claim();
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', event => {
|
||||
// We only want to call event.respondWith() if this is a navigation request
|
||||
// for an HTML page.
|
||||
if (event.request.mode === 'navigate') {
|
||||
event.respondWith((async () => {
|
||||
try {
|
||||
// First, try to use the navigation preload response if it's supported.
|
||||
const preloadResponse = await event.preloadResponse;
|
||||
|
||||
if (preloadResponse) {
|
||||
return preloadResponse;
|
||||
}
|
||||
|
||||
// Always try the network first.
|
||||
const networkResponse = await fetch(event.request);
|
||||
|
||||
return networkResponse;
|
||||
} catch (error) {
|
||||
// catch is only triggered if an exception is thrown, which is likely
|
||||
// due to a network error.
|
||||
// If fetch() returns a valid HTTP response with a response code in
|
||||
// the 4xx or 5xx range, the catch() will NOT be called.
|
||||
console.log('Fetch failed; returning offline page instead.', error);
|
||||
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
const cachedResponse = await cache.match(OFFLINE_URL);
|
||||
|
||||
return cachedResponse;
|
||||
}
|
||||
})());
|
||||
}
|
||||
|
||||
// If our if() condition is false, then this fetch handler won't intercept the
|
||||
// request. If there are any other fetch handlers registered, they will get a
|
||||
// chance to call event.respondWith(). If no fetch handlers call
|
||||
// event.respondWith(), the request will be handled by the browser as if there
|
||||
// were no service worker involvement.
|
||||
});
|
||||
@@ -772,6 +772,22 @@ export function createTrackMutedEvent(mediaType, reason, muted = true) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event for joining a vpaas conference.
|
||||
*
|
||||
* @param {string} tenant - The conference tenant.
|
||||
* @returns {Object} The event in a format suitable for sending via
|
||||
* sendAnalytics.
|
||||
*/
|
||||
export function createVpaasConferenceJoinedEvent(tenant) {
|
||||
return {
|
||||
action: 'vpaas.conference.joined',
|
||||
attributes: {
|
||||
tenant
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event for an action on the welcome page.
|
||||
*
|
||||
|
||||
@@ -16,7 +16,7 @@ import { connect, disconnect, setLocationURL } from '../base/connection';
|
||||
import { loadConfig } from '../base/lib-jitsi-meet';
|
||||
import { MEDIA_TYPE } from '../base/media';
|
||||
import { toState } from '../base/redux';
|
||||
import { createDesiredLocalTracks, isLocalVideoTrackMuted, isLocalTrackMuted } from '../base/tracks';
|
||||
import { createDesiredLocalTracks, isLocalCameraTrackMuted, isLocalTrackMuted } from '../base/tracks';
|
||||
import {
|
||||
addHashParamsToURL,
|
||||
getBackendSafeRoomName,
|
||||
@@ -232,7 +232,7 @@ export function reloadNow() {
|
||||
function addTrackStateToURL(url, stateful) {
|
||||
const state = toState(stateful);
|
||||
const tracks = state['features/base/tracks'];
|
||||
const isVideoMuted = isLocalVideoTrackMuted(tracks);
|
||||
const isVideoMuted = isLocalCameraTrackMuted(tracks);
|
||||
const isAudioMuted = isLocalTrackMuted(tracks, MEDIA_TYPE.AUDIO);
|
||||
|
||||
return addHashParamsToURL(new URL(url), { // use new URL object in order to not pollute the passed parameter.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import SplashScreen from 'react-native-splash-screen';
|
||||
|
||||
import { setColorScheme } from '../../base/color-scheme';
|
||||
import { DialogContainer } from '../../base/dialog';
|
||||
@@ -84,6 +85,8 @@ export class App extends AbstractApp {
|
||||
componentDidMount() {
|
||||
super.componentDidMount();
|
||||
|
||||
SplashScreen.hide();
|
||||
|
||||
this._init.then(() => {
|
||||
const { dispatch, getState } = this.state.store;
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import '../base/sounds/reducer';
|
||||
import '../base/testing/reducer';
|
||||
import '../base/tracks/reducer';
|
||||
import '../base/user-interaction/reducer';
|
||||
import '../billing-counter/reducer';
|
||||
import '../blur/reducer';
|
||||
import '../calendar-sync/reducer';
|
||||
import '../chat/reducer';
|
||||
|
||||
@@ -37,6 +37,11 @@ export type Props = {
|
||||
*/
|
||||
displayName?: string,
|
||||
|
||||
/**
|
||||
* Whether or not to update the background color of the avatar
|
||||
*/
|
||||
dynamicColor?: Boolean,
|
||||
|
||||
/**
|
||||
* ID of the element, if any.
|
||||
*/
|
||||
@@ -78,6 +83,15 @@ export const DEFAULT_SIZE = 65;
|
||||
* Implements a class to render avatars in the app.
|
||||
*/
|
||||
class Avatar<P: Props> extends PureComponent<P, State> {
|
||||
/**
|
||||
* Default values for {@code Avatar} component's properties.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static defaultProps = {
|
||||
dynamicColor: true
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiates a new {@code Component}.
|
||||
*
|
||||
@@ -123,6 +137,7 @@ class Avatar<P: Props> extends PureComponent<P, State> {
|
||||
_loadableAvatarUrl,
|
||||
className,
|
||||
colorBase,
|
||||
dynamicColor,
|
||||
id,
|
||||
size,
|
||||
status,
|
||||
@@ -156,7 +171,10 @@ class Avatar<P: Props> extends PureComponent<P, State> {
|
||||
const initials = getInitials(_initialsBase);
|
||||
|
||||
if (initials) {
|
||||
avatarProps.color = getAvatarColor(colorBase || _initialsBase);
|
||||
if (dynamicColor) {
|
||||
avatarProps.color = getAvatarColor(colorBase || _initialsBase);
|
||||
}
|
||||
|
||||
avatarProps.initials = initials;
|
||||
}
|
||||
|
||||
|
||||
@@ -140,18 +140,6 @@ export const P2P_STATUS_CHANGED = 'P2P_STATUS_CHANGED';
|
||||
*/
|
||||
export const SEND_TONES = 'SEND_TONES';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which sets the desktop sharing enabled flag for
|
||||
* the current conference.
|
||||
*
|
||||
* {
|
||||
* type: SET_DESKTOP_SHARING_ENABLED,
|
||||
* desktopSharingEnabled: boolean
|
||||
* }
|
||||
*/
|
||||
export const SET_DESKTOP_SHARING_ENABLED
|
||||
= 'SET_DESKTOP_SHARING_ENABLED';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which updates the current known status of the
|
||||
* Follow Me feature.
|
||||
|
||||
@@ -43,7 +43,6 @@ import {
|
||||
LOCK_STATE_CHANGED,
|
||||
P2P_STATUS_CHANGED,
|
||||
SEND_TONES,
|
||||
SET_DESKTOP_SHARING_ENABLED,
|
||||
SET_FOLLOW_ME,
|
||||
SET_PASSWORD,
|
||||
SET_PASSWORD_FAILED,
|
||||
@@ -52,7 +51,6 @@ import {
|
||||
SET_START_MUTED_POLICY
|
||||
} from './actionTypes';
|
||||
import {
|
||||
AVATAR_ID_COMMAND,
|
||||
AVATAR_URL_COMMAND,
|
||||
EMAIL_COMMAND,
|
||||
JITSI_CONFERENCE_URL_KEY
|
||||
@@ -198,13 +196,6 @@ function _addConferenceListeners(conference, dispatch) {
|
||||
botType
|
||||
})));
|
||||
|
||||
conference.addCommandListener(
|
||||
AVATAR_ID_COMMAND,
|
||||
(data, id) => dispatch(participantUpdated({
|
||||
conference,
|
||||
id,
|
||||
avatarID: data.value
|
||||
})));
|
||||
conference.addCommandListener(
|
||||
AVATAR_URL_COMMAND,
|
||||
(data, id) => dispatch(participantUpdated({
|
||||
@@ -581,22 +572,6 @@ export function sendTones(tones: string, duration: number, pause: number) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag for indicating if desktop sharing is enabled.
|
||||
*
|
||||
* @param {boolean} desktopSharingEnabled - True if desktop sharing is enabled.
|
||||
* @returns {{
|
||||
* type: SET_DESKTOP_SHARING_ENABLED,
|
||||
* desktopSharingEnabled: boolean
|
||||
* }}
|
||||
*/
|
||||
export function setDesktopSharingEnabled(desktopSharingEnabled: boolean) {
|
||||
return {
|
||||
type: SET_DESKTOP_SHARING_ENABLED,
|
||||
desktopSharingEnabled
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the Follow Me feature.
|
||||
*
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
/**
|
||||
* The command type for updating a participant's avatar ID.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
export const AVATAR_ID_COMMAND = 'avatar-id';
|
||||
|
||||
/**
|
||||
* The command type for updating a participant's avatar URL.
|
||||
*
|
||||
|
||||
@@ -14,7 +14,6 @@ import { toState } from '../redux';
|
||||
import { safeDecodeURIComponent } from '../util';
|
||||
|
||||
import {
|
||||
AVATAR_ID_COMMAND,
|
||||
AVATAR_URL_COMMAND,
|
||||
EMAIL_COMMAND,
|
||||
JITSI_CONFERENCE_URL_KEY
|
||||
@@ -74,6 +73,7 @@ export function commonUserJoinedHandling(
|
||||
} else {
|
||||
dispatch(participantJoined({
|
||||
botType: user.getBotType(),
|
||||
connectionStatus: user.getConnectionStatus(),
|
||||
conference,
|
||||
id,
|
||||
name: displayName,
|
||||
@@ -316,16 +316,12 @@ export function sendLocalParticipant(
|
||||
setDisplayName: Function,
|
||||
setLocalParticipantProperty: Function }) {
|
||||
const {
|
||||
avatarID,
|
||||
avatarURL,
|
||||
email,
|
||||
features,
|
||||
name
|
||||
} = getLocalParticipant(stateful);
|
||||
|
||||
avatarID && conference.sendCommand(AVATAR_ID_COMMAND, {
|
||||
value: avatarID
|
||||
});
|
||||
avatarURL && conference.sendCommand(AVATAR_URL_COMMAND, {
|
||||
value: avatarURL
|
||||
});
|
||||
|
||||
@@ -128,9 +128,6 @@ function _conferenceFailed({ dispatch, getState }, next, action) {
|
||||
titleKey: 'dialog.sessTerminated'
|
||||
}));
|
||||
|
||||
if (typeof APP !== 'undefined') {
|
||||
APP.UI.hideStats();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JitsiConferenceErrors.CONNECTION_ERROR: {
|
||||
74
react/features/base/conference/middleware.native.js
Normal file
74
react/features/base/conference/middleware.native.js
Normal file
@@ -0,0 +1,74 @@
|
||||
// @flow
|
||||
|
||||
import { setPictureInPictureDisabled } from '../../mobile/picture-in-picture/functions';
|
||||
import { setAudioOnly } from '../audio-only';
|
||||
import JitsiMeetJS from '../lib-jitsi-meet';
|
||||
import { MiddlewareRegistry } from '../redux';
|
||||
import { TOGGLE_SCREENSHARING } from '../tracks/actionTypes';
|
||||
import { destroyLocalDesktopTrackIfExists, replaceLocalTrack } from '../tracks/actions';
|
||||
import { getLocalVideoTrack, isLocalVideoTrackDesktop } from '../tracks/functions';
|
||||
|
||||
import './middleware.any';
|
||||
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
switch (action.type) {
|
||||
case TOGGLE_SCREENSHARING: {
|
||||
_toggleScreenSharing(store);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return next(action);
|
||||
});
|
||||
|
||||
/**
|
||||
* Toggles screen sharing.
|
||||
*
|
||||
* @private
|
||||
* @param {Store} store - The redux.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _toggleScreenSharing(store) {
|
||||
const { dispatch, getState } = store;
|
||||
const state = getState();
|
||||
|
||||
const isSharing = isLocalVideoTrackDesktop(state);
|
||||
|
||||
if (isSharing) {
|
||||
dispatch(destroyLocalDesktopTrackIfExists());
|
||||
} else {
|
||||
_startScreenSharing(dispatch, state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates desktop track and replaces the local one.
|
||||
*
|
||||
* @private
|
||||
* @param {Dispatch} dispatch - The redux {@code dispatch} function.
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _startScreenSharing(dispatch, state) {
|
||||
setPictureInPictureDisabled(true);
|
||||
|
||||
JitsiMeetJS.createLocalTracks({ devices: [ 'desktop' ] })
|
||||
.then(tracks => {
|
||||
const track = tracks[0];
|
||||
const currentLocalTrack = getLocalVideoTrack(state['features/base/tracks']);
|
||||
const currentJitsiTrack = currentLocalTrack && currentLocalTrack.jitsiTrack;
|
||||
|
||||
dispatch(replaceLocalTrack(currentJitsiTrack, track));
|
||||
|
||||
const { enabled: audioOnly } = state['features/base/audio-only'];
|
||||
|
||||
if (audioOnly) {
|
||||
dispatch(setAudioOnly(false));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('ERROR creating ScreeSharing stream ', error);
|
||||
|
||||
setPictureInPictureDisabled(false);
|
||||
});
|
||||
}
|
||||
23
react/features/base/conference/middleware.web.js
Normal file
23
react/features/base/conference/middleware.web.js
Normal file
@@ -0,0 +1,23 @@
|
||||
// @flow
|
||||
|
||||
import UIEvents from '../../../../service/UI/UIEvents';
|
||||
import { MiddlewareRegistry } from '../redux';
|
||||
import { TOGGLE_SCREENSHARING } from '../tracks/actionTypes';
|
||||
|
||||
import './middleware.any';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
MiddlewareRegistry.register((/* store */) => next => action => {
|
||||
switch (action.type) {
|
||||
case TOGGLE_SCREENSHARING: {
|
||||
if (typeof APP === 'object') {
|
||||
APP.UI.emitEvent(UIEvents.TOGGLE_SCREENSHARING);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return next(action);
|
||||
});
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
CONFERENCE_WILL_LEAVE,
|
||||
LOCK_STATE_CHANGED,
|
||||
P2P_STATUS_CHANGED,
|
||||
SET_DESKTOP_SHARING_ENABLED,
|
||||
SET_FOLLOW_ME,
|
||||
SET_PASSWORD,
|
||||
SET_PENDING_SUBJECT_CHANGE,
|
||||
@@ -76,9 +75,6 @@ ReducerRegistry.register(
|
||||
case P2P_STATUS_CHANGED:
|
||||
return _p2pStatusChanged(state, action);
|
||||
|
||||
case SET_DESKTOP_SHARING_ENABLED:
|
||||
return _setDesktopSharingEnabled(state, action);
|
||||
|
||||
case SET_FOLLOW_ME:
|
||||
return set(state, 'followMeEnabled', action.enabled);
|
||||
|
||||
@@ -343,21 +339,6 @@ function _p2pStatusChanged(state, action) {
|
||||
return set(state, 'p2p', action.p2p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces a specific Redux action SET_DESKTOP_SHARING_ENABLED of the feature
|
||||
* base/conference.
|
||||
*
|
||||
* @param {Object} state - The Redux state of the feature base/conference.
|
||||
* @param {Action} action - The Redux action SET_DESKTOP_SHARING_ENABLED to
|
||||
* reduce.
|
||||
* @private
|
||||
* @returns {Object} The new state of the feature base/conference after the
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _setDesktopSharingEnabled(state, action) {
|
||||
return set(state, 'desktopSharingEnabled', action.desktopSharingEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces a specific Redux action SET_PASSWORD of the feature base/conference.
|
||||
*
|
||||
|
||||
@@ -3,7 +3,7 @@ import extraConfigWhitelist from './extraConfigWhitelist';
|
||||
/**
|
||||
* The config keys to whitelist, the keys that can be overridden.
|
||||
* Currently we can only whitelist the first part of the properties, like
|
||||
* 'p2p.useStunTurn' and 'p2p.enabled' we whitelist all p2p options.
|
||||
* 'p2p.enabled' we whitelist all p2p options.
|
||||
* The whitelist is used only for config.js.
|
||||
*
|
||||
* @type Array
|
||||
@@ -91,7 +91,6 @@ export default [
|
||||
'disableSimulcast',
|
||||
'disableSuspendVideo',
|
||||
'disableThirdPartyRequests',
|
||||
'displayJids',
|
||||
'doNotStoreRoom',
|
||||
'e2eping',
|
||||
'enableDisplayNameInStats',
|
||||
@@ -149,7 +148,6 @@ export default [
|
||||
'stereo',
|
||||
'subject',
|
||||
'testing',
|
||||
'useStunTurn',
|
||||
'useTurnUdp',
|
||||
'videoQuality.persist',
|
||||
'webrtcIceTcpDisable',
|
||||
|
||||
@@ -59,7 +59,7 @@ export function getInviteURL(stateOrGetState: Function | Object): string {
|
||||
|
||||
if (inviteDomain) {
|
||||
const meetingId
|
||||
= state['features/base/config'].brandingRoomAlias || urlWithoutParams.pathname;
|
||||
= state['features/base/config'].brandingRoomAlias || urlWithoutParams.pathname.replace('/', '');
|
||||
|
||||
return `${inviteDomain}/${meetingId}`;
|
||||
}
|
||||
|
||||
@@ -172,9 +172,7 @@ ColorSchemeRegistry.register('BottomSheet', {
|
||||
},
|
||||
|
||||
expandIcon: {
|
||||
color: schemeColor('icon'),
|
||||
fontSize: 48,
|
||||
opacity: 0.8
|
||||
color: schemeColor('icon')
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,6 +49,12 @@ export const INVITE_ENABLED = 'invite.enabled';
|
||||
*/
|
||||
export const IOS_RECORDING_ENABLED = 'ios.recording.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if kickout is enabled.
|
||||
* Default: enabled (true).
|
||||
*/
|
||||
export const KICK_OUT_ENABLED = 'kick-out.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if live-streaming should be enabled.
|
||||
* Default: auto-detected.
|
||||
|
||||
3
react/features/base/icons/svg/arrow_up.svg
Normal file
3
react/features/base/icons/svg/arrow_up.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.41115 6.05746C8.71903 6.39955 9.24594 6.42729 9.58803 6.1194C9.93012 5.81152 9.95786 5.28461 9.64997 4.94252L5.72917 0.562752C5.39813 0.194935 4.82138 0.194935 4.49034 0.562752L0.63061 4.94252C0.322728 5.28461 0.35046 5.81152 0.692552 6.1194C1.03464 6.42729 1.56155 6.39955 1.86943 6.05746L5.10975 2.36593L8.41115 6.05746Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 492 B |
@@ -1,11 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24">
|
||||
<path
|
||||
d="m 5.6875,10.59375 h 12.625 c 0.779062,0 1.40625,0.627187 1.40625,1.40625 0,0.779062 -0.627188,1.40625 -1.40625,1.40625 H 5.6875 c -0.7790625,0 -1.40625,-0.627188 -1.40625,-1.40625 0,-0.779063 0.6271875,-1.40625 1.40625,-1.40625 z"
|
||||
id="rect3711" />
|
||||
width="128"
|
||||
height="32"
|
||||
viewBox="0 0 128 32">
|
||||
<path
|
||||
d="m 19.431133,13.973662 h 90.198887 c 4.85877,0 4.20737,0.903746 4.20737,2.026338 0,1.122591 0.33306,2.026338 -4.52571,2.026338 H 19.218901 c -4.858774,0 -4.844061,-0.903747 -4.844061,-2.026338 0,-1.122592 0.197519,-2.026338 5.056293,-2.026338 z" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 474 B After Width: | Height: | Size: 424 B |
@@ -5,6 +5,7 @@ export { default as IconAddPeople } from './link.svg';
|
||||
export { default as IconArrowBack } from './arrow_back.svg';
|
||||
export { default as IconArrowDown } from './arrow_down.svg';
|
||||
export { default as IconArrowDownSmall } from './arrow-down-small.svg';
|
||||
export { default as IconArrowUp } from './arrow_up.svg';
|
||||
export { default as IconArrowLeft } from './arrow-left.svg';
|
||||
export { default as IconAudioOnly } from './visibility.svg';
|
||||
export { default as IconAudioOnlyOff } from './visibility-off.svg';
|
||||
@@ -90,6 +91,7 @@ export { default as IconShareVideo } from './shared-video.svg';
|
||||
export { default as IconSwitchCamera } from './switch-camera.svg';
|
||||
export { default as IconTileView } from './tiles-many.svg';
|
||||
export { default as IconToggleRecording } from './camera-take-picture.svg';
|
||||
export { default as IconTrash } from './trash.svg';
|
||||
export { default as IconVideoQualityAudioOnly } from './AUD.svg';
|
||||
export { default as IconVideoQualityHD } from './HD.svg';
|
||||
export { default as IconVideoQualityLD } from './LD.svg';
|
||||
|
||||
1
react/features/base/icons/svg/trash.svg
Normal file
1
react/features/base/icons/svg/trash.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="trash-alt" class="svg-inline--fa fa-trash-alt fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M32 464a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128H32zm272-256a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zM432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z"></path></svg>
|
||||
|
After Width: | Height: | Size: 577 B |
@@ -1,5 +1,7 @@
|
||||
/* @flow */
|
||||
|
||||
import jwtDecode from 'jwt-decode';
|
||||
|
||||
import { parseURLParams } from '../util';
|
||||
|
||||
/**
|
||||
@@ -14,3 +16,15 @@ import { parseURLParams } from '../util';
|
||||
export function parseJWTFromURLParams(url: URL = window.location) {
|
||||
return parseURLParams(url, true, 'search').jwt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user name after decoding the jwt.
|
||||
*
|
||||
* @param {Object} state - The app state.
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getJwtName(state: Object) {
|
||||
const jwtData = jwtDecode(state['features/base/jwt'].jwt);
|
||||
|
||||
return jwtData?.context?.user?.name || '';
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import { SET_FILMSTRIP_ENABLED } from '../../filmstrip/actionTypes';
|
||||
import { SELECT_LARGE_VIDEO_PARTICIPANT } from '../../large-video/actionTypes';
|
||||
import { APP_STATE_CHANGED } from '../../mobile/background/actionTypes';
|
||||
import { SCREEN_SHARE_PARTICIPANTS_UPDATED, SET_TILE_VIEW } from '../../video-layout/actionTypes';
|
||||
import { shouldDisplayTileView } from '../../video-layout/functions';
|
||||
import { SET_AUDIO_ONLY } from '../audio-only/actionTypes';
|
||||
import { CONFERENCE_JOINED } from '../conference/actionTypes';
|
||||
import {
|
||||
@@ -17,6 +16,7 @@ import {
|
||||
getParticipantCount
|
||||
} from '../participants/functions';
|
||||
import { MiddlewareRegistry } from '../redux';
|
||||
import { isLocalVideoTrackDesktop } from '../tracks/functions';
|
||||
|
||||
import { limitLastN } from './functions';
|
||||
import logger from './logger';
|
||||
@@ -79,14 +79,16 @@ function _updateLastN({ getState }) {
|
||||
}
|
||||
|
||||
if (typeof appState !== 'undefined' && appState !== 'active') {
|
||||
lastN = 0;
|
||||
lastN = isLocalVideoTrackDesktop(state) ? 1 : 0;
|
||||
} else if (audioOnly) {
|
||||
const { screenShares } = state['features/video-layout'];
|
||||
const tileViewEnabled = shouldDisplayTileView(state);
|
||||
const { screenShares, tileViewEnabled } = state['features/video-layout'];
|
||||
const largeVideoParticipantId = state['features/large-video'].participantId;
|
||||
const largeVideoParticipant
|
||||
= largeVideoParticipantId ? getParticipantById(state, largeVideoParticipantId) : undefined;
|
||||
|
||||
// Use tileViewEnabled state from redux here instead of determining if client should be in tile
|
||||
// view since we make an exception only for screenshare when in audio-only mode. If the user unpins
|
||||
// the screenshare, lastN will be set to 0 here. It will be set to 1 if screenshare has been auto pinned.
|
||||
if (!tileViewEnabled && largeVideoParticipant && !largeVideoParticipant.local) {
|
||||
lastN = (screenShares || []).includes(largeVideoParticipantId) ? 1 : 0;
|
||||
} else {
|
||||
|
||||
@@ -104,8 +104,10 @@ function _setErrorHandlers() {
|
||||
|
||||
// eslint-disable-next-line max-params
|
||||
window.onerror = (message, source, lineno, colno, error) => {
|
||||
JitsiMeetJS.getGlobalOnErrorHandler(
|
||||
message, source, lineno, colno, error);
|
||||
const errMsg = message || (error && error.message);
|
||||
const stack = error && error.stack;
|
||||
|
||||
JitsiMeetJS.getGlobalOnErrorHandler(errMsg, source, lineno, colno, stack);
|
||||
|
||||
if (oldOnErrorHandler) {
|
||||
oldOnErrorHandler(message, source, lineno, colno, error);
|
||||
@@ -115,8 +117,14 @@ function _setErrorHandlers() {
|
||||
const oldOnUnhandledRejection = window.onunhandledrejection;
|
||||
|
||||
window.onunhandledrejection = function(event) {
|
||||
JitsiMeetJS.getGlobalOnErrorHandler(
|
||||
null, null, null, null, event.reason);
|
||||
let message = event.reason;
|
||||
let stack = 'n/a';
|
||||
|
||||
if (event.reason instanceof Error) {
|
||||
({ message, stack } = event.reason);
|
||||
}
|
||||
|
||||
JitsiMeetJS.getGlobalOnErrorHandler(message, null, null, null, stack);
|
||||
|
||||
if (oldOnUnhandledRejection) {
|
||||
oldOnUnhandledRejection(event);
|
||||
|
||||
@@ -99,6 +99,13 @@ class Video extends Component<Props> {
|
||||
}
|
||||
|
||||
this._attachTrack(this.props.videoTrack);
|
||||
|
||||
if (this._videoElement && this.props.autoPlay) {
|
||||
// Ensure the video gets play() called on it. This may be necessary in the
|
||||
// case where the local video container was moved and re-attached, in which
|
||||
// case video does not autoplay.
|
||||
this._videoElement.play();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,6 +149,8 @@ class Video extends Component<Props> {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
// NOTE: Maybe we should render null if we don't have video track or if the video track has ended.
|
||||
|
||||
return (
|
||||
<video
|
||||
autoPlay = { this.props.autoPlay }
|
||||
|
||||
@@ -1,9 +1,30 @@
|
||||
/* @flow */
|
||||
|
||||
import { toState } from '../redux';
|
||||
import { getPropertyValue } from '../settings';
|
||||
|
||||
import { VIDEO_MUTISM_AUTHORITY } from './constants';
|
||||
|
||||
|
||||
// XXX The configurations/preferences/settings startWithAudioMuted and startWithVideoMuted were introduced for
|
||||
// conferences/meetings. So it makes sense for these to not be considered outside of conferences/meetings
|
||||
// (e.g. WelcomePage). Later on, though, we introduced a "Video <-> Voice" toggle on the WelcomePage which utilizes
|
||||
// startAudioOnly outside of conferences/meetings so that particular configuration/preference/setting employs slightly
|
||||
// exclusive logic.
|
||||
const START_WITH_AUDIO_VIDEO_MUTED_SOURCES = {
|
||||
// We have startWithAudioMuted and startWithVideoMuted here:
|
||||
config: true,
|
||||
settings: true,
|
||||
|
||||
// XXX We've already overwritten base/config with urlParams. However,
|
||||
// settings are more important than the server-side config.
|
||||
// Consequently, we need to read from urlParams anyway:
|
||||
urlParams: true,
|
||||
|
||||
// We don't have startWithAudioMuted and startWithVideoMuted here:
|
||||
jwt: false
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines whether audio is currently muted.
|
||||
*
|
||||
@@ -47,6 +68,26 @@ function _isVideoMutedByAuthority(
|
||||
return Boolean(muted & videoMutismAuthority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the startWithAudioMuted by retrieving its values from config, URL and settings.
|
||||
*
|
||||
* @param {Object|Function} stateful - The redux state object or {@code getState} function.
|
||||
* @returns {boolean} - The computed startWithAudioMuted value that will be used.
|
||||
*/
|
||||
export function getStartWithAudioMuted(stateful: Object | Function) {
|
||||
return Boolean(getPropertyValue(stateful, 'startWithAudioMuted', START_WITH_AUDIO_VIDEO_MUTED_SOURCES));
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the startWithAudioMuted by retrieving its values from config, URL and settings.
|
||||
*
|
||||
* @param {Object|Function} stateful - The redux state object or {@code getState} function.
|
||||
* @returns {boolean} - The computed startWithAudioMuted value that will be used.
|
||||
*/
|
||||
export function getStartWithVideoMuted(stateful: Object | Function) {
|
||||
return Boolean(getPropertyValue(stateful, 'startWithVideoMuted', START_WITH_AUDIO_VIDEO_MUTED_SOURCES));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether video is currently muted by the user authority.
|
||||
*
|
||||
|
||||
@@ -13,7 +13,7 @@ import { isRoomValid, SET_ROOM } from '../conference';
|
||||
import JitsiMeetJS from '../lib-jitsi-meet';
|
||||
import { MiddlewareRegistry } from '../redux';
|
||||
import { getPropertyValue } from '../settings';
|
||||
import { setTrackMuted, TRACK_ADDED } from '../tracks';
|
||||
import { isLocalVideoTrackDesktop, setTrackMuted, TRACK_ADDED } from '../tracks';
|
||||
|
||||
import { setAudioMuted, setCameraFacingMode, setVideoMuted } from './actions';
|
||||
import {
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
MEDIA_TYPE,
|
||||
VIDEO_MUTISM_AUTHORITY
|
||||
} from './constants';
|
||||
import { getStartWithAudioMuted, getStartWithVideoMuted } from './functions';
|
||||
import logger from './logger';
|
||||
import {
|
||||
_AUDIO_INITIAL_MEDIA_STATE,
|
||||
@@ -72,13 +73,15 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
* @private
|
||||
* @returns {Object} The value returned by {@code next(action)}.
|
||||
*/
|
||||
function _appStateChanged({ dispatch }, next, action) {
|
||||
const { appState } = action;
|
||||
const mute = appState !== 'active'; // Note that 'background' and 'inactive' are treated equal.
|
||||
function _appStateChanged({ dispatch, getState }, next, action) {
|
||||
if (navigator.product === 'ReactNative') {
|
||||
const { appState } = action;
|
||||
const mute = appState !== 'active' && !isLocalVideoTrackDesktop(getState());
|
||||
|
||||
sendAnalytics(createTrackMutedEvent('video', 'background mode', mute));
|
||||
sendAnalytics(createTrackMutedEvent('video', 'background mode', mute));
|
||||
|
||||
dispatch(setVideoMuted(mute, MEDIA_TYPE.VIDEO, VIDEO_MUTISM_AUTHORITY.BACKGROUND));
|
||||
dispatch(setVideoMuted(mute, MEDIA_TYPE.VIDEO, VIDEO_MUTISM_AUTHORITY.BACKGROUND));
|
||||
}
|
||||
|
||||
return next(action);
|
||||
}
|
||||
@@ -133,37 +136,8 @@ function _setRoom({ dispatch, getState }, next, action) {
|
||||
const state = getState();
|
||||
const { room } = action;
|
||||
const roomIsValid = isRoomValid(room);
|
||||
|
||||
// XXX The configurations/preferences/settings startWithAudioMuted,
|
||||
// startWithVideoMuted, and startAudioOnly were introduced for
|
||||
// conferences/meetings. So it makes sense for these to not be considered
|
||||
// outside of conferences/meetings (e.g. WelcomePage). Later on, though, we
|
||||
// introduced a "Video <-> Voice" toggle on the WelcomePage which utilizes
|
||||
// startAudioOnly outside of conferences/meetings so that particular
|
||||
// configuration/preference/setting employs slightly exclusive logic.
|
||||
const mutedSources = {
|
||||
// We have startWithAudioMuted and startWithVideoMuted here:
|
||||
config: true,
|
||||
settings: true,
|
||||
|
||||
// XXX We've already overwritten base/config with urlParams. However,
|
||||
// settings are more important than the server-side config.
|
||||
// Consequently, we need to read from urlParams anyway:
|
||||
urlParams: true,
|
||||
|
||||
// We don't have startWithAudioMuted and startWithVideoMuted here:
|
||||
jwt: false
|
||||
};
|
||||
const audioMuted
|
||||
= roomIsValid
|
||||
? Boolean(
|
||||
getPropertyValue(state, 'startWithAudioMuted', mutedSources))
|
||||
: _AUDIO_INITIAL_MEDIA_STATE.muted;
|
||||
const videoMuted
|
||||
= roomIsValid
|
||||
? Boolean(
|
||||
getPropertyValue(state, 'startWithVideoMuted', mutedSources))
|
||||
: _VIDEO_INITIAL_MEDIA_STATE.muted;
|
||||
const audioMuted = roomIsValid ? getStartWithAudioMuted(state) : _AUDIO_INITIAL_MEDIA_STATE.muted;
|
||||
const videoMuted = roomIsValid ? getStartWithVideoMuted(state) : _VIDEO_INITIAL_MEDIA_STATE.muted;
|
||||
|
||||
sendAnalytics(
|
||||
createStartMutedConfigurationEvent('local', audioMuted, videoMuted));
|
||||
|
||||
@@ -19,7 +19,8 @@ import {
|
||||
import {
|
||||
getLocalParticipant,
|
||||
getNormalizedDisplayName,
|
||||
getParticipantDisplayName
|
||||
getParticipantDisplayName,
|
||||
figureOutMutedWhileDisconnectedStatus
|
||||
} from './functions';
|
||||
|
||||
/**
|
||||
@@ -216,12 +217,15 @@ export function muteRemoteParticipant(id) {
|
||||
* }}
|
||||
*/
|
||||
export function participantConnectionStatusChanged(id, connectionStatus) {
|
||||
return {
|
||||
type: PARTICIPANT_UPDATED,
|
||||
participant: {
|
||||
connectionStatus,
|
||||
id
|
||||
}
|
||||
return (dispatch, getState) => {
|
||||
return {
|
||||
type: PARTICIPANT_UPDATED,
|
||||
participant: {
|
||||
connectionStatus,
|
||||
id,
|
||||
mutedWhileDisconnected: figureOutMutedWhileDisconnectedStatus(getState(), id, connectionStatus)
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { getGravatarURL } from '@jitsi/js-utils/avatar';
|
||||
import { JitsiParticipantConnectionStatus } from '../lib-jitsi-meet';
|
||||
import { MEDIA_TYPE, shouldRenderVideoTrack } from '../media';
|
||||
import { toState } from '../redux';
|
||||
import { getTrackByMediaTypeAndParticipant } from '../tracks';
|
||||
import { getTrackByMediaTypeAndParticipant, isRemoteTrackMuted } from '../tracks';
|
||||
import { createDeferred } from '../util';
|
||||
|
||||
import {
|
||||
@@ -366,6 +366,45 @@ export function shouldRenderParticipantVideo(stateful: Object | Function, id: st
|
||||
return participantIsInLargeVideoWithScreen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Figures out the value of mutedWhileDisconnected status by taking into
|
||||
* account remote participant's network connectivity and video muted status.
|
||||
* The flag is set to <tt>true</tt> if remote participant's video gets muted
|
||||
* during his media connection disruption. This is to prevent black video
|
||||
* being render on the thumbnail, because even though once the video has
|
||||
* been played the image usually remains on the video element it seems that
|
||||
* after longer period of the video element being hidden this image can be
|
||||
* lost.
|
||||
*
|
||||
* @param {Object|Function} stateful - Object or function that can be resolved
|
||||
* to the Redux state.
|
||||
* @param {string} participantID - The ID of the participant.
|
||||
* @param {string} [connectionStatus] - A connection status to be used.
|
||||
* @returns {boolean} - The mutedWhileDisconnected value.
|
||||
*/
|
||||
export function figureOutMutedWhileDisconnectedStatus(
|
||||
stateful: Function | Object, participantID: string, connectionStatus: ?string) {
|
||||
const state = toState(stateful);
|
||||
const participant = getParticipantById(state, participantID);
|
||||
|
||||
if (!participant || participant.local) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const isActive = (connectionStatus || participant.connectionStatus) === JitsiParticipantConnectionStatus.ACTIVE;
|
||||
const isVideoMuted = isRemoteTrackMuted(state['features/base/tracks'], MEDIA_TYPE.VIDEO, participantID);
|
||||
let mutedWhileDisconnected = participant.mutedWhileDisconnected || false;
|
||||
|
||||
if (!isActive && isVideoMuted) {
|
||||
mutedWhileDisconnected = true;
|
||||
} else if (isActive && !isVideoMuted) {
|
||||
mutedWhileDisconnected = false;
|
||||
}
|
||||
|
||||
return mutedWhileDisconnected;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolves the first loadable avatar URL for a participant.
|
||||
*
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
import { JitsiConferenceEvents } from '../lib-jitsi-meet';
|
||||
import { MiddlewareRegistry, StateListenerRegistry } from '../redux';
|
||||
import { playSound, registerSound, unregisterSound } from '../sounds';
|
||||
import { getTrackByJitsiTrack, TRACK_ADDED, TRACK_REMOVED, TRACK_UPDATED } from '../tracks';
|
||||
|
||||
import {
|
||||
DOMINANT_SPEAKER_CHANGED,
|
||||
@@ -41,7 +42,8 @@ import {
|
||||
getLocalParticipant,
|
||||
getParticipantById,
|
||||
getParticipantCount,
|
||||
getParticipantDisplayName
|
||||
getParticipantDisplayName,
|
||||
figureOutMutedWhileDisconnectedStatus
|
||||
} from './functions';
|
||||
import { PARTICIPANT_JOINED_FILE, PARTICIPANT_LEFT_FILE } from './sounds';
|
||||
|
||||
@@ -134,6 +136,11 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
|
||||
case PARTICIPANT_UPDATED:
|
||||
return _participantJoinedOrUpdated(store, next, action);
|
||||
|
||||
case TRACK_ADDED:
|
||||
case TRACK_REMOVED:
|
||||
case TRACK_UPDATED:
|
||||
return _trackChanged(store, next, action);
|
||||
}
|
||||
|
||||
return next(action);
|
||||
@@ -283,7 +290,6 @@ function _localParticipantJoined({ getState, dispatch }, next, action) {
|
||||
const settings = getState()['features/base/settings'];
|
||||
|
||||
dispatch(localParticipantJoined({
|
||||
avatarID: settings.avatarID,
|
||||
avatarURL: settings.avatarURL,
|
||||
email: settings.email,
|
||||
name: settings.displayName
|
||||
@@ -453,6 +459,55 @@ function _registerSounds({ dispatch }) {
|
||||
dispatch(registerSound(PARTICIPANT_LEFT_SOUND_ID, PARTICIPANT_LEFT_FILE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the feature base/participants that the action there has been a change in the tracks of the participants.
|
||||
*
|
||||
* @param {Store} store - The redux store in which the specified {@code action} is being dispatched.
|
||||
* @param {Dispatch} next - The redux {@code dispatch} function to dispatch the specified {@code action} in the
|
||||
* specified {@code store}.
|
||||
* @param {Action} action - The redux action {@code PARTICIPANT_JOINED} or {@code PARTICIPANT_UPDATED} which is being
|
||||
* dispatched in the specified {@code store}.
|
||||
* @private
|
||||
* @returns {Object} The value returned by {@code next(action)}.
|
||||
*/
|
||||
function _trackChanged({ dispatch, getState }, next, action) {
|
||||
const { jitsiTrack } = action.track;
|
||||
let track;
|
||||
|
||||
if (action.type === TRACK_REMOVED) {
|
||||
track = getTrackByJitsiTrack(getState()['features/base/tracks'], jitsiTrack);
|
||||
}
|
||||
|
||||
const result = next(action);
|
||||
|
||||
if (action.type !== TRACK_REMOVED) {
|
||||
track = getTrackByJitsiTrack(getState()['features/base/tracks'], jitsiTrack);
|
||||
}
|
||||
|
||||
if (typeof track === 'undefined' || track.local) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const { participantId } = track;
|
||||
const state = getState();
|
||||
const participant = getParticipantById(state, participantId);
|
||||
|
||||
if (!participant) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const mutedWhileDisconnected = figureOutMutedWhileDisconnectedStatus(state, participantId);
|
||||
|
||||
if (participant.mutedWhileDisconnected !== mutedWhileDisconnected) {
|
||||
dispatch(participantUpdated({
|
||||
id: participantId,
|
||||
mutedWhileDisconnected
|
||||
}));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters sounds related with the participants feature.
|
||||
*
|
||||
|
||||
@@ -15,10 +15,16 @@ export function preloadImage(src: string | Object): Promise<string> {
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const image = document.createElement('img');
|
||||
|
||||
image.onload = () => resolve(src);
|
||||
image.onerror = reject;
|
||||
image.src = src;
|
||||
fetch(src, { referrer: '' })
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
resolve(src);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
reject(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -181,7 +181,6 @@ function _participant(state: Object = {}, action) {
|
||||
*/
|
||||
function _participantJoined({ participant }) {
|
||||
const {
|
||||
avatarID,
|
||||
avatarURL,
|
||||
botType,
|
||||
connectionStatus,
|
||||
@@ -211,7 +210,6 @@ function _participantJoined({ participant }) {
|
||||
}
|
||||
|
||||
return {
|
||||
avatarID,
|
||||
avatarURL,
|
||||
botType,
|
||||
conference,
|
||||
@@ -223,6 +221,7 @@ function _participantJoined({ participant }) {
|
||||
isJigasi,
|
||||
loadableAvatarUrl,
|
||||
local: local || false,
|
||||
mutedWhileDisconnected: local ? undefined : false,
|
||||
name,
|
||||
pinned: pinned || false,
|
||||
presence,
|
||||
|
||||
@@ -26,6 +26,11 @@ type Props = {
|
||||
*/
|
||||
hasOptions?: boolean,
|
||||
|
||||
/**
|
||||
* Icon to display in the options section.
|
||||
*/
|
||||
OptionsIcon?: React$Node,
|
||||
|
||||
/**
|
||||
* TestId of the button. Can be used to locate element when testing UI.
|
||||
*/
|
||||
@@ -57,6 +62,7 @@ function ActionButton({
|
||||
className = '',
|
||||
disabled,
|
||||
hasOptions,
|
||||
OptionsIcon = IconArrowDown,
|
||||
testId,
|
||||
type = 'primary',
|
||||
onClick,
|
||||
@@ -75,7 +81,7 @@ function ActionButton({
|
||||
<Icon
|
||||
className = 'icon'
|
||||
size = { 14 }
|
||||
src = { IconArrowDown } />
|
||||
src = { OptionsIcon } />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Avatar } from '../../../avatar';
|
||||
import { connect } from '../../../redux';
|
||||
import { calculateAvatarDimensions } from '../../functions';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The height of the window.
|
||||
*/
|
||||
height: number,
|
||||
|
||||
/**
|
||||
* The name of the participant (if any).
|
||||
*/
|
||||
name: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Component displaying the avatar for the premeeting screen.
|
||||
*
|
||||
* @param {Props} props - The props of the component.
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
function PremeetingAvatar({ height, name }: Props) {
|
||||
const { marginTop, size } = calculateAvatarDimensions(height);
|
||||
|
||||
if (size <= 5) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div style = {{ marginTop }}>
|
||||
<Avatar
|
||||
className = 'preview-avatar'
|
||||
displayName = { name }
|
||||
participantId = 'local'
|
||||
size = { size } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to the React {@code Component} props.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {{
|
||||
* height: number
|
||||
* }}
|
||||
*/
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
height: state['features/base/responsive-ui'].clientHeight
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(PremeetingAvatar);
|
||||
@@ -61,6 +61,9 @@ function ConnectionStatus({ connectionDetails, t, connectionType }: Props) {
|
||||
? 'con-status-arrow con-status-arrow--up'
|
||||
: 'con-status-arrow';
|
||||
const detailsText = connectionDetails.map(t).join(' ');
|
||||
const detailsClassName = showDetails
|
||||
? 'con-status-details-visible'
|
||||
: 'con-status-details-hidden';
|
||||
|
||||
return (
|
||||
<div className = 'con-status'>
|
||||
@@ -79,8 +82,7 @@ function ConnectionStatus({ connectionDetails, t, connectionType }: Props) {
|
||||
size = { 24 }
|
||||
src = { IconArrowDownSmall } />
|
||||
</div>
|
||||
{ showDetails
|
||||
&& <div className = 'con-status-details'>{detailsText}</div> }
|
||||
<div className = { `con-status-details ${detailsClassName}` }>{detailsText}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import { AudioSettingsButton, VideoSettingsButton } from '../../../../toolbox/components/web';
|
||||
import { Avatar } from '../../../avatar';
|
||||
|
||||
import ConnectionStatus from './ConnectionStatus';
|
||||
import CopyMeetingUrl from './CopyMeetingUrl';
|
||||
@@ -85,12 +86,18 @@ export default class PreMeetingScreen extends PureComponent<Props> {
|
||||
id = 'lobby-screen'>
|
||||
<ConnectionStatus />
|
||||
<Preview
|
||||
name = { name }
|
||||
showAvatar = { showAvatar }
|
||||
videoMuted = { videoMuted }
|
||||
videoTrack = { videoTrack } />
|
||||
{!videoMuted && <div className = 'preview-overlay' />}
|
||||
<div className = 'content'>
|
||||
{showAvatar && videoMuted && (
|
||||
<Avatar
|
||||
className = 'premeeting-screen-avatar'
|
||||
displayName = { name }
|
||||
dynamicColor = { false }
|
||||
participantId = 'local'
|
||||
size = { 80 } />
|
||||
)}
|
||||
{showConferenceInfo && (
|
||||
<>
|
||||
<div className = 'title'>
|
||||
|
||||
@@ -6,20 +6,8 @@ import { Video } from '../../../media';
|
||||
import { connect } from '../../../redux';
|
||||
import { getLocalVideoTrack } from '../../../tracks';
|
||||
|
||||
import PreviewAvatar from './Avatar';
|
||||
|
||||
export type Props = {
|
||||
|
||||
/**
|
||||
* The name of the user that is about to join.
|
||||
*/
|
||||
name: string,
|
||||
|
||||
/**
|
||||
* Indicates whether the avatar should be shown when video is off
|
||||
*/
|
||||
showAvatar: boolean,
|
||||
|
||||
/**
|
||||
* Flag signaling the visibility of camera preview.
|
||||
*/
|
||||
@@ -38,7 +26,7 @@ export type Props = {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
function Preview(props: Props) {
|
||||
const { name, showAvatar, videoMuted, videoTrack } = props;
|
||||
const { videoMuted, videoTrack } = props;
|
||||
|
||||
if (!videoMuted && videoTrack) {
|
||||
return (
|
||||
@@ -50,23 +38,9 @@ function Preview(props: Props) {
|
||||
);
|
||||
}
|
||||
|
||||
if (showAvatar) {
|
||||
return (
|
||||
<div
|
||||
className = 'no-video'
|
||||
id = 'preview'>
|
||||
<PreviewAvatar name = { name } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Preview.defaultProps = {
|
||||
showAvatar: true
|
||||
};
|
||||
|
||||
/**
|
||||
* Maps part of the Redux state to the props of this component.
|
||||
*
|
||||
|
||||
@@ -20,6 +20,11 @@ type Props = {
|
||||
*/
|
||||
disabled: boolean,
|
||||
|
||||
/**
|
||||
* Function to be invoked when an item is long pressed. The item is passed.
|
||||
*/
|
||||
onLongPress: Function,
|
||||
|
||||
/**
|
||||
* Function to be invoked when an item is pressed. The item's URL is passed.
|
||||
*/
|
||||
@@ -44,13 +49,7 @@ type Props = {
|
||||
/**
|
||||
* An array of sections
|
||||
*/
|
||||
sections: Array<Section>,
|
||||
|
||||
/**
|
||||
* Optional array of on-slide actions this list should support. For details
|
||||
* see https://github.com/dancormier/react-native-swipeout.
|
||||
*/
|
||||
slideActions?: Array<Object>
|
||||
sections: Array<Section>
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -83,11 +82,11 @@ class NavigateSectionList extends Component<Props> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this._getItemKey = this._getItemKey.bind(this);
|
||||
this._onLongPress = this._onLongPress.bind(this);
|
||||
this._onPress = this._onPress.bind(this);
|
||||
this._onRefresh = this._onRefresh.bind(this);
|
||||
this._renderItem = this._renderItem.bind(this);
|
||||
this._renderListEmptyComponent
|
||||
= this._renderListEmptyComponent.bind(this);
|
||||
this._renderListEmptyComponent = this._renderListEmptyComponent.bind(this);
|
||||
this._renderSectionHeader = this._renderSectionHeader.bind(this);
|
||||
}
|
||||
|
||||
@@ -131,6 +130,25 @@ class NavigateSectionList extends Component<Props> {
|
||||
return `${index}-${item.key}`;
|
||||
}
|
||||
|
||||
_onLongPress: string => Function;
|
||||
|
||||
/**
|
||||
* Returns a function that is used in the onLongPress callback of the items.
|
||||
*
|
||||
* @param {Object} item - The item that was long-pressed.
|
||||
* @private
|
||||
* @returns {Function}
|
||||
*/
|
||||
_onLongPress(item) {
|
||||
const { disabled, onLongPress } = this.props;
|
||||
|
||||
if (!disabled && typeof onLongPress === 'function') {
|
||||
return () => onLongPress(item);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
_onPress: string => Function;
|
||||
|
||||
/**
|
||||
@@ -210,10 +228,10 @@ class NavigateSectionList extends Component<Props> {
|
||||
<NavigateSectionListItem
|
||||
item = { item }
|
||||
key = { key }
|
||||
onLongPress = { url ? this._onLongPress(item) : undefined }
|
||||
onPress = { url ? this._onPress(url) : undefined }
|
||||
secondaryAction = {
|
||||
url ? undefined : this._onSecondaryAction(id) }
|
||||
slideActions = { this.props.slideActions } />
|
||||
url ? undefined : this._onSecondaryAction(id) } />
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,11 @@ type Props = {
|
||||
*/
|
||||
linesStyle?: StyleType,
|
||||
|
||||
/**
|
||||
* Function to invoke on long press.
|
||||
*/
|
||||
onLongPress: ?Function,
|
||||
|
||||
/**
|
||||
* Function to invoke on press.
|
||||
*/
|
||||
@@ -88,13 +93,16 @@ export default class AvatarListItem extends Component<Props> {
|
||||
avatarOnly,
|
||||
avatarSize = AVATAR_SIZE,
|
||||
avatarStatus,
|
||||
avatarStyle
|
||||
avatarStyle,
|
||||
onLongPress,
|
||||
onPress
|
||||
} = this.props;
|
||||
const { avatar, colorBase, lines, title } = this.props.item;
|
||||
|
||||
return (
|
||||
<Container
|
||||
onClick = { this.props.onPress }
|
||||
onClick = { onPress }
|
||||
onLongPress = { onLongPress }
|
||||
style = { styles.listItem }
|
||||
underlayColor = { UNDERLAY_COLOR }>
|
||||
<Avatar
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import Swipeout from 'react-native-swipeout';
|
||||
|
||||
import { ColorPalette } from '../../../styles';
|
||||
import type { Item } from '../../Types';
|
||||
|
||||
import AvatarListItem from './AvatarListItem';
|
||||
@@ -18,6 +16,11 @@ type Props = {
|
||||
*/
|
||||
item: Item,
|
||||
|
||||
/**
|
||||
* Function to be invoked when an item is long pressed. The item is passed.
|
||||
*/
|
||||
onLongPress: ?Function,
|
||||
|
||||
/**
|
||||
* Function to be invoked when an Item is pressed. The Item's URL is passed.
|
||||
*/
|
||||
@@ -26,13 +29,7 @@ type Props = {
|
||||
/**
|
||||
* Function to be invoked when secondary action was performed on an Item.
|
||||
*/
|
||||
secondaryAction: ?Function,
|
||||
|
||||
/**
|
||||
* Optional array of on-slide actions this list should support. For details
|
||||
* see https://github.com/dancormier/react-native-swipeout.
|
||||
*/
|
||||
slideActions?: Array<Object>
|
||||
secondaryAction: ?Function
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,37 +113,15 @@ export default class NavigateSectionListItem extends Component<Props> {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { item, slideActions } = this.props;
|
||||
const { id } = item;
|
||||
let right;
|
||||
|
||||
// NOTE: The {@code Swipeout} component has an onPress prop encapsulated
|
||||
// in the {@code right} array, but we need to bind it to the ID of the
|
||||
// item too.
|
||||
|
||||
if (slideActions) {
|
||||
right = [];
|
||||
for (const slideAction of slideActions) {
|
||||
right.push({
|
||||
backgroundColor: slideAction.backgroundColor,
|
||||
onPress: slideAction.onPress.bind(undefined, id),
|
||||
text: slideAction.text
|
||||
});
|
||||
}
|
||||
}
|
||||
const { item, onLongPress, onPress, secondaryAction } = this.props;
|
||||
|
||||
return (
|
||||
<Swipeout
|
||||
autoClose = { true }
|
||||
backgroundColor = { ColorPalette.transparent }
|
||||
right = { right }>
|
||||
<AvatarListItem
|
||||
item = { item }
|
||||
onPress = { this.props.onPress } >
|
||||
{ this.props.secondaryAction
|
||||
&& this._renderSecondaryAction() }
|
||||
</AvatarListItem>
|
||||
</Swipeout>
|
||||
<AvatarListItem
|
||||
item = { item }
|
||||
onLongPress = { onLongPress }
|
||||
onPress = { onPress } >
|
||||
{ secondaryAction && this._renderSecondaryAction() }
|
||||
</AvatarListItem>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* type: SETTINGS_UPDATED,
|
||||
* settings: {
|
||||
* audioOutputDeviceId: string,
|
||||
* avatarID: string,
|
||||
* avatarURL: string,
|
||||
* cameraDeviceId: string,
|
||||
* displayName: string,
|
||||
|
||||
@@ -8,7 +8,6 @@ import { SETTINGS_UPDATED } from './actionTypes';
|
||||
* type: SETTINGS_UPDATED,
|
||||
* settings: {
|
||||
* audioOutputDeviceId: string,
|
||||
* avatarID: string,
|
||||
* avatarURL: string,
|
||||
* cameraDeviceId: string,
|
||||
* displayName: string,
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// @flow
|
||||
import _ from 'lodash';
|
||||
|
||||
import { PREJOIN_INITIALIZED } from '../../prejoin/actionTypes';
|
||||
import { APP_WILL_MOUNT } from '../app';
|
||||
import { setAudioOnly } from '../audio-only';
|
||||
import { SET_LOCATION_URL } from '../connection/actionTypes'; // minimize imports to avoid circular imports
|
||||
import { getJwtName } from '../jwt/functions';
|
||||
import { getLocalParticipant, participantUpdated } from '../participants';
|
||||
import { MiddlewareRegistry } from '../redux';
|
||||
import { parseURLParams } from '../util';
|
||||
@@ -27,6 +29,10 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
case APP_WILL_MOUNT:
|
||||
_initializeCallIntegration(store);
|
||||
break;
|
||||
case PREJOIN_INITIALIZED: {
|
||||
_maybeUpdateDisplayName(store);
|
||||
break;
|
||||
}
|
||||
case SETTINGS_UPDATED:
|
||||
_maybeHandleCallIntegrationChange(action);
|
||||
_maybeSetAudioOnly(store, action);
|
||||
@@ -115,6 +121,26 @@ function _maybeSetAudioOnly(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the display name to the one in JWT if there is one.
|
||||
*
|
||||
* @param {Store} store - The redux store.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
function _maybeUpdateDisplayName({ dispatch, getState }) {
|
||||
const state = getState();
|
||||
const hasJwt = Boolean(state['features/base/jwt'].jwt);
|
||||
|
||||
if (hasJwt) {
|
||||
const displayName = getJwtName(state);
|
||||
|
||||
dispatch(updateSettings({
|
||||
displayName
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the local participant according to settings changes.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import { jitsiLocalStorage } from '@jitsi/js-utils';
|
||||
import { randomHexString } from '@jitsi/js-utils/random';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { APP_WILL_MOUNT } from '../app/actionTypes';
|
||||
@@ -19,7 +18,6 @@ import logger from './logger';
|
||||
*/
|
||||
const DEFAULT_STATE = {
|
||||
audioOutputDeviceId: undefined,
|
||||
avatarID: undefined,
|
||||
avatarURL: undefined,
|
||||
cameraDeviceId: undefined,
|
||||
disableCallIntegration: undefined,
|
||||
@@ -126,24 +124,16 @@ function _initSettings(featureState) {
|
||||
// jibri, and remove the old settings.js values.
|
||||
const savedDisplayName = jitsiLocalStorage.getItem('displayname');
|
||||
const savedEmail = jitsiLocalStorage.getItem('email');
|
||||
let avatarID = _.escape(jitsiLocalStorage.getItem('avatarId'));
|
||||
|
||||
// The helper _.escape will convert null to an empty strings. The empty
|
||||
// string will be saved in settings. On app re-load, because an empty string
|
||||
// is a defined value, it will override any value found in local storage.
|
||||
// The workaround is sidestepping _.escape when the value is not set in
|
||||
// local storage.
|
||||
const displayName
|
||||
= savedDisplayName === null ? undefined : _.escape(savedDisplayName);
|
||||
const displayName = savedDisplayName === null ? undefined : _.escape(savedDisplayName);
|
||||
const email = savedEmail === null ? undefined : _.escape(savedEmail);
|
||||
|
||||
if (!avatarID) {
|
||||
// if there is no avatar id, we generate a unique one and use it forever
|
||||
avatarID = randomHexString(32);
|
||||
}
|
||||
|
||||
settings = assignIfDefined({
|
||||
avatarID,
|
||||
displayName,
|
||||
email
|
||||
}, settings);
|
||||
|
||||
@@ -9,7 +9,8 @@ import {
|
||||
MEDIA_TYPE,
|
||||
setAudioMuted,
|
||||
setVideoMuted,
|
||||
VIDEO_MUTISM_AUTHORITY
|
||||
VIDEO_MUTISM_AUTHORITY,
|
||||
VIDEO_TYPE
|
||||
} from '../media';
|
||||
import { getLocalParticipant } from '../participants';
|
||||
|
||||
@@ -24,7 +25,13 @@ import {
|
||||
TRACK_UPDATED,
|
||||
TRACK_WILL_CREATE
|
||||
} from './actionTypes';
|
||||
import { createLocalTracksF, getLocalTrack, getLocalTracks, getTrackByJitsiTrack } from './functions';
|
||||
import {
|
||||
createLocalTracksF,
|
||||
getLocalTrack,
|
||||
getLocalTracks,
|
||||
getLocalVideoTrack,
|
||||
getTrackByJitsiTrack
|
||||
} from './functions';
|
||||
import logger from './logger';
|
||||
|
||||
/**
|
||||
@@ -40,6 +47,8 @@ export function createDesiredLocalTracks(...desiredTypes) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
|
||||
dispatch(destroyLocalDesktopTrackIfExists());
|
||||
|
||||
if (desiredTypes.length === 0) {
|
||||
const { audio, video } = state['features/base/media'];
|
||||
|
||||
@@ -663,6 +672,22 @@ function _trackCreateCanceled(mediaType) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* If thee local track if of type Desktop, it calls _disposeAndRemoveTracks) on it.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function destroyLocalDesktopTrackIfExists() {
|
||||
return (dispatch, getState) => {
|
||||
const videoTrack = getLocalVideoTrack(getState()['features/base/tracks']);
|
||||
const isDesktopTrack = videoTrack && videoTrack.videoType === VIDEO_TYPE.DESKTOP;
|
||||
|
||||
if (isDesktopTrack) {
|
||||
dispatch(_disposeAndRemoveTracks([ videoTrack.jitsiTrack ]));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets UID of the displayed no data from source notification. Used to track
|
||||
* if the notification was previously displayed in this context.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* global APP */
|
||||
|
||||
import JitsiMeetJS, { JitsiTrackErrors, browser } from '../lib-jitsi-meet';
|
||||
import { MEDIA_TYPE, setAudioMuted } from '../media';
|
||||
import { MEDIA_TYPE, VIDEO_TYPE, setAudioMuted } from '../media';
|
||||
import {
|
||||
getUserSelectedCameraDeviceId,
|
||||
getUserSelectedMicDeviceId
|
||||
@@ -346,12 +346,12 @@ export function getTracksByMediaType(tracks, mediaType) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the local video track in the given set of tracks is muted.
|
||||
* Checks if the local video camera track in the given set of tracks is muted.
|
||||
*
|
||||
* @param {Track[]} tracks - List of all tracks.
|
||||
* @returns {Track[]}
|
||||
*/
|
||||
export function isLocalVideoTrackMuted(tracks) {
|
||||
export function isLocalCameraTrackMuted(tracks) {
|
||||
const presenterTrack = getLocalTrack(tracks, MEDIA_TYPE.PRESENTER);
|
||||
const videoTrack = getLocalTrack(tracks, MEDIA_TYPE.VIDEO);
|
||||
|
||||
@@ -383,6 +383,19 @@ export function isLocalTrackMuted(tracks, mediaType) {
|
||||
return !track || track.muted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the local video track is of type DESKtOP.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isLocalVideoTrackDesktop(state) {
|
||||
const videoTrack = getLocalVideoTrack(state['features/base/tracks']);
|
||||
|
||||
return videoTrack && videoTrack.videoType === VIDEO_TYPE.DESKTOP;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the remote track of the given media type and the given
|
||||
* participant is muted, false otherwise.
|
||||
|
||||
@@ -159,7 +159,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
} else if (jitsiTrack.isLocal()) {
|
||||
APP.conference.setVideoMuteStatus(muted);
|
||||
} else {
|
||||
APP.UI.setVideoMuted(participantID, muted);
|
||||
APP.UI.setVideoMuted(participantID);
|
||||
}
|
||||
APP.UI.onPeerVideoTypeChanged(participantID, jitsiTrack.videoType);
|
||||
} else if (jitsiTrack.isLocal()) {
|
||||
|
||||
@@ -2,3 +2,8 @@
|
||||
* Action used to store the billing id.
|
||||
*/
|
||||
export const SET_BILLING_ID = 'SET_BILLING_ID';
|
||||
|
||||
/**
|
||||
* Action used to store the flag signaling the endpoint has been counted.
|
||||
*/
|
||||
export const SET_ENDPOINT_COUNTED = 'SET_ENDPOINT_COUNTED';
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user