mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-01-02 12:52:28 +00:00
Compare commits
186 Commits
4385
...
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 | ||
|
|
b5310573fc | ||
|
|
aa488cb75c | ||
|
|
de8e62ac51 | ||
|
|
f6d375f565 | ||
|
|
c54fed78c8 | ||
|
|
3d7ea52416 | ||
|
|
0c4d649459 | ||
|
|
af416ad487 | ||
|
|
1cd6f2b4da | ||
|
|
1fb37a0216 | ||
|
|
c261682a29 | ||
|
|
49548ba564 | ||
|
|
dc6d3daef7 | ||
|
|
014f3b615f | ||
|
|
25271d7eec | ||
|
|
7ef4de9c1c | ||
|
|
e6e088d197 | ||
|
|
0e034a686f | ||
|
|
d9f85c70f1 | ||
|
|
de8079cc98 | ||
|
|
2a9805f9b1 | ||
|
|
00ec0f03a6 | ||
|
|
91f636a813 | ||
|
|
fa4df19733 | ||
|
|
1d17cc91e0 | ||
|
|
93f4098dc0 | ||
|
|
11ae187ece | ||
|
|
0f9e01a7cf | ||
|
|
ddbd3f292a | ||
|
|
b153bf2fb8 | ||
|
|
919be21912 | ||
|
|
1a339100ab | ||
|
|
ce4ef96941 | ||
|
|
993ded9936 | ||
|
|
a8b9ae2b12 | ||
|
|
812af33a4d | ||
|
|
7f17c2eceb | ||
|
|
09124ad7e9 | ||
|
|
7a9a6855b7 | ||
|
|
8dcf04897a | ||
|
|
69b7301b9d | ||
|
|
794713b930 | ||
|
|
89cd6e8e3e | ||
|
|
7a7937c072 | ||
|
|
4765ab9d63 | ||
|
|
1d5decc14f | ||
|
|
119b79fd84 | ||
|
|
188771751d | ||
|
|
d2ec0ea6f3 | ||
|
|
ed6e75b241 | ||
|
|
dedd3f4ef0 | ||
|
|
bbb4fbd5f8 | ||
|
|
92235ae535 | ||
|
|
ebb1b8d76b | ||
|
|
42d559de93 | ||
|
|
2838aefccc | ||
|
|
ca306f47b6 | ||
|
|
56da400f19 | ||
|
|
ab21e3cd5e | ||
|
|
2c026754ef | ||
|
|
8dbe3e37b9 | ||
|
|
7f67f78db6 | ||
|
|
312949eef6 | ||
|
|
41ea94c0c2 | ||
|
|
e70adef2ef | ||
|
|
57bbe3f75a | ||
|
|
e2731ce73e | ||
|
|
d5dae945a8 | ||
|
|
4d1dba937f | ||
|
|
b6792db65f | ||
|
|
9815b633fc | ||
|
|
b4bf82429c | ||
|
|
53d485b397 | ||
|
|
0354dbe889 | ||
|
|
7cafa205ee | ||
|
|
2b4f33bef8 | ||
|
|
31dee0bb68 | ||
|
|
fc75d45c6c | ||
|
|
25839b18d2 | ||
|
|
43f36c8cfd | ||
|
|
b02d96231c | ||
|
|
651d713206 | ||
|
|
9e5f469e0c | ||
|
|
493ce8249e | ||
|
|
fdffb688c1 | ||
|
|
4807badac8 | ||
|
|
5e3bd746e9 | ||
|
|
8fa41bebb7 | ||
|
|
cb7c280da6 |
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';
|
||||
|
||||
13
Makefile
13
Makefile
@@ -3,8 +3,9 @@ CLEANCSS = ./node_modules/.bin/cleancss
|
||||
DEPLOY_DIR = libs
|
||||
LIBJITSIMEET_DIR = node_modules/lib-jitsi-meet/
|
||||
LIBFLAC_DIR = node_modules/libflacjs/dist/min/
|
||||
OLM_DIR = node_modules/olm
|
||||
RNNOISE_WASM_DIR = node_modules/rnnoise-wasm/dist/
|
||||
NODE_SASS = ./node_modules/.bin/node-sass
|
||||
NODE_SASS = ./node_modules/.bin/sass
|
||||
NPM = npm
|
||||
OUTPUT_DIR = .
|
||||
STYLES_BUNDLE = css/all.bundle.css
|
||||
@@ -22,7 +23,7 @@ clean:
|
||||
rm -fr $(BUILD_DIR)
|
||||
|
||||
.NOTPARALLEL:
|
||||
deploy: deploy-init deploy-appbundle deploy-rnnoise-binary deploy-lib-jitsi-meet deploy-libflac deploy-css deploy-local
|
||||
deploy: deploy-init deploy-appbundle deploy-rnnoise-binary deploy-lib-jitsi-meet deploy-libflac deploy-olm deploy-css deploy-local
|
||||
|
||||
deploy-init:
|
||||
rm -fr $(DEPLOY_DIR)
|
||||
@@ -59,6 +60,7 @@ deploy-lib-jitsi-meet:
|
||||
cp \
|
||||
$(LIBJITSIMEET_DIR)/lib-jitsi-meet.min.js \
|
||||
$(LIBJITSIMEET_DIR)/lib-jitsi-meet.min.map \
|
||||
$(LIBJITSIMEET_DIR)/lib-jitsi-meet.e2ee-worker.js \
|
||||
$(LIBJITSIMEET_DIR)/connection_optimization/external_connect.js \
|
||||
$(LIBJITSIMEET_DIR)/modules/browser/capabilities.json \
|
||||
$(DEPLOY_DIR)
|
||||
@@ -69,6 +71,11 @@ deploy-libflac:
|
||||
$(LIBFLAC_DIR)/libflac4-1.3.2.min.js.mem \
|
||||
$(DEPLOY_DIR)
|
||||
|
||||
deploy-olm:
|
||||
cp \
|
||||
$(OLM_DIR)/olm.wasm \
|
||||
$(DEPLOY_DIR)
|
||||
|
||||
deploy-rnnoise-binary:
|
||||
cp \
|
||||
$(RNNOISE_WASM_DIR)/rnnoise.wasm \
|
||||
@@ -83,7 +90,7 @@ deploy-local:
|
||||
([ ! -x deploy-local.sh ] || ./deploy-local.sh)
|
||||
|
||||
.NOTPARALLEL:
|
||||
dev: deploy-init deploy-css deploy-rnnoise-binary deploy-lib-jitsi-meet deploy-libflac
|
||||
dev: deploy-init deploy-css deploy-rnnoise-binary deploy-lib-jitsi-meet deploy-libflac deploy-olm
|
||||
$(WEBPACK_DEV_SERVER) --detect-circular-deps
|
||||
|
||||
source-package:
|
||||
|
||||
@@ -3,7 +3,7 @@ apply plugin: 'com.android.application'
|
||||
// Crashlytics integration is done as part of Firebase now, so it gets
|
||||
// automagically activated with google-services.json
|
||||
if (googleServicesEnabled) {
|
||||
apply plugin: 'io.fabric'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
}
|
||||
|
||||
// Use the number of seconds/10 since Jan 1 2019 as the versionCode.
|
||||
@@ -16,6 +16,10 @@ android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
packagingOptions {
|
||||
exclude 'lib/*/libhermes*.so'
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'org.jitsi.meet'
|
||||
versionCode vcode
|
||||
@@ -70,16 +74,11 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url 'https://maven.fabric.io/public' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-beta-5'
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.2'
|
||||
|
||||
if (!rootProject.ext.libreBuild) {
|
||||
implementation 'com.google.android.gms:play-services-auth:16.0.1'
|
||||
@@ -87,9 +86,9 @@ dependencies {
|
||||
// Firebase
|
||||
// - Crashlytics
|
||||
// - Dynamic Links
|
||||
implementation 'com.google.firebase:firebase-core:16.0.6'
|
||||
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.8'
|
||||
implementation 'com.google.firebase:firebase-dynamic-links:16.1.5'
|
||||
implementation 'com.google.firebase:firebase-analytics:17.5.0'
|
||||
implementation 'com.google.firebase:firebase-crashlytics:17.2.1'
|
||||
implementation 'com.google.firebase:firebase-dynamic-links:19.1.0'
|
||||
}
|
||||
|
||||
implementation project(':sdk')
|
||||
|
||||
6
android/app/proguard-rules.pro
vendored
6
android/app/proguard-rules.pro
vendored
@@ -85,8 +85,4 @@
|
||||
# ^^^ We added the above when we switched minifyEnabled on.
|
||||
|
||||
# Rule to avoid build errors related to SVGs.
|
||||
-keep public class com.horcrux.svg.** {*;}
|
||||
|
||||
# Hermes
|
||||
-keep class com.facebook.hermes.unicode.** { *; }
|
||||
|
||||
-keep public class com.horcrux.svg.** {*;}
|
||||
@@ -3,9 +3,8 @@ package org.jitsi.meet;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import com.crashlytics.android.Crashlytics;
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics;
|
||||
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks;
|
||||
import io.fabric.sdk.android.Fabric;
|
||||
|
||||
import org.jitsi.meet.sdk.JitsiMeet;
|
||||
import org.jitsi.meet.sdk.JitsiMeetActivity;
|
||||
@@ -22,10 +21,7 @@ final class GoogleServicesHelper {
|
||||
if (BuildConfig.GOOGLE_SERVICES_ENABLED) {
|
||||
Log.d(activity.getClass().getSimpleName(), "Initializing Google Services");
|
||||
|
||||
if (!JitsiMeet.isCrashReportingDisabled(activity)) {
|
||||
Fabric.with(activity, new Crashlytics());
|
||||
}
|
||||
|
||||
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(!JitsiMeet.isCrashReportingDisabled(activity));
|
||||
FirebaseDynamicLinks.getInstance().getDynamicLink(activity.getIntent())
|
||||
.addOnSuccessListener(activity, pendingDynamicLinkData -> {
|
||||
Uri dynamicLink = null;
|
||||
|
||||
@@ -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.
|
||||
@@ -7,26 +8,46 @@ buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
repositories {
|
||||
maven { url 'https://maven.fabric.io/public' }
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.3.2'
|
||||
classpath 'com.android.tools.build:gradle:4.0.2'
|
||||
classpath 'com.google.gms:google-services:4.3.3'
|
||||
classpath 'io.fabric.tools:gradle:1.28.1'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files.
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.3.0'
|
||||
}
|
||||
}
|
||||
|
||||
ext {
|
||||
buildToolsVersion = "29.0.3"
|
||||
compileSdkVersion = 29
|
||||
minSdkVersion = 23
|
||||
targetSdkVersion = 29
|
||||
supportLibVersion = "28.0.0"
|
||||
|
||||
// The Maven artifact groupdId of the third-party react-native modules which
|
||||
// Jitsi Meet SDK for Android depends on and which are not available in
|
||||
// third-party Maven repositories so we have to deploy to a Maven repository
|
||||
// of ours.
|
||||
moduleGroupId = 'com.facebook.react'
|
||||
|
||||
// Maven repo where artifacts will be published
|
||||
mavenRepo = System.env.MVN_REPO ?: ""
|
||||
mavenUser = System.env.MVN_USER ?: ""
|
||||
mavenPassword = System.env.MVN_PASSWORD ?: ""
|
||||
|
||||
// Libre build
|
||||
libreBuild = (System.env.LIBRE_BUILD ?: "false").toBoolean()
|
||||
|
||||
googleServicesEnabled = project.file('app/google-services.json').exists() && !libreBuild
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
// React Native (JS, Obj-C sources, Android binaries) is installed from npm.
|
||||
maven { url "$rootDir/../node_modules/react-native/android" }
|
||||
// Android JSC is installed from npm.
|
||||
maven { url("$rootDir/../node_modules/jsc-android/dist") }
|
||||
}
|
||||
|
||||
// Make sure we use the react-native version in node_modules and not the one
|
||||
@@ -141,30 +162,6 @@ allprojects {
|
||||
}
|
||||
}
|
||||
|
||||
ext {
|
||||
buildToolsVersion = "29.0.3"
|
||||
compileSdkVersion = 29
|
||||
minSdkVersion = 23
|
||||
targetSdkVersion = 29
|
||||
supportLibVersion = "28.0.0"
|
||||
|
||||
// The Maven artifact groupdId of the third-party react-native modules which
|
||||
// Jitsi Meet SDK for Android depends on and which are not available in
|
||||
// third-party Maven repositories so we have to deploy to a Maven repository
|
||||
// of ours.
|
||||
moduleGroupId = 'com.facebook.react'
|
||||
|
||||
// Maven repo where artifacts will be published
|
||||
mavenRepo = System.env.MVN_REPO ?: ""
|
||||
mavenUser = System.env.MVN_USER ?: ""
|
||||
mavenPassword = System.env.MVN_PASSWORD ?: ""
|
||||
|
||||
// Libre build
|
||||
libreBuild = (System.env.LIBRE_BUILD ?: "false").toBoolean()
|
||||
|
||||
googleServicesEnabled = project.file('app/google-services.json').exists() && !libreBuild
|
||||
}
|
||||
|
||||
// Force the version of the Android build tools we have chosen on all
|
||||
// subprojects. The forcing was introduced for react-native and the third-party
|
||||
// modules that we utilize such as react-native-background-timer.
|
||||
|
||||
@@ -10,15 +10,20 @@
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
# Default value: -Xmx10248m -XX:MaxPermSize=256m
|
||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
|
||||
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# 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
|
||||
|
||||
appVersion=20.4.0
|
||||
sdkVersion=2.10.0
|
||||
appVersion=20.5.0
|
||||
sdkVersion=2.11.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#Fri Mar 08 13:36:51 CET 2019
|
||||
#Wed Sep 23 11:48:00 EEST 2020
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
|
||||
|
||||
@@ -10,7 +10,7 @@ MVN_HTTP=0
|
||||
DEFAULT_SDK_VERSION=$(grep sdkVersion ${THIS_DIR}/../gradle.properties | cut -d"=" -f2)
|
||||
SDK_VERSION=${OVERRIDE_SDK_VERSION:-${DEFAULT_SDK_VERSION}}
|
||||
RN_VERSION=$(jq -r '.version' ${THIS_DIR}/../../node_modules/react-native/package.json)
|
||||
HERMES_VERSION=$(jq -r '.dependencies."hermes-engine"' ${THIS_DIR}/../../node_modules/react-native/package.json | cut -c 2-)
|
||||
JSC_VERSION="r"$(jq -r '.dependencies."jsc-android"' ${THIS_DIR}/../../node_modules/react-native/package.json | cut -d . -f 1 | cut -c 2-)
|
||||
DO_GIT_TAG=${GIT_TAG:-0}
|
||||
|
||||
if [[ $THE_MVN_REPO == http* ]]; then
|
||||
@@ -38,19 +38,17 @@ if [[ $MVN_HTTP == 1 ]]; then
|
||||
-DgeneratePom=false \
|
||||
-DpomFile=react-native-${RN_VERSION}.pom || true
|
||||
popd
|
||||
# Push Hermes
|
||||
echo "Pushing Hermes ${HERMES_VERSION} to the Maven repo"
|
||||
pushd ${THIS_DIR}/../../node_modules/hermes-engine/android/
|
||||
# Push JSC
|
||||
echo "Pushing JSC ${JSC_VERSION} to the Maven repo"
|
||||
pushd ${THIS_DIR}/../../node_modules/jsc-android/dist/org/webkit/android-jsc/${JSC_VERSION}
|
||||
mvn \
|
||||
deploy:deploy-file \
|
||||
-Durl=${MVN_REPO} \
|
||||
-DrepositoryId=${MVN_REPO_ID} \
|
||||
-Dfile=hermes-release.aar \
|
||||
-Dfile=android-jsc-${JSC_VERSION}.aar \
|
||||
-Dpackaging=aar \
|
||||
-DgroupId=com.facebook \
|
||||
-DartifactId=hermes \
|
||||
-Dversion=${HERMES_VERSION} \
|
||||
-DgeneratePom=true || true
|
||||
-DgeneratePom=false \
|
||||
-DpomFile=android-jsc-${JSC_VERSION}.pom || true
|
||||
popd
|
||||
else
|
||||
# Push React Native, if necessary
|
||||
@@ -67,19 +65,17 @@ else
|
||||
popd
|
||||
fi
|
||||
|
||||
# Push Hermes, if necessary
|
||||
if [[ ! -d ${MVN_REPO}/com/facebook/hermes/${HERMES_VERSION} ]]; then
|
||||
echo "Pushing Hermes ${HERMES_VERSION} to the Maven repo"
|
||||
pushd ${THIS_DIR}/../../node_modules/hermes-engine/android/
|
||||
# Push JSC, if necessary
|
||||
if [[ ! -d ${MVN_REPO}/org/webkit/android-jsc/${JSC_VERSION} ]]; then
|
||||
echo "Pushing JSC ${JSC_VERSION} to the Maven repo"
|
||||
pushd ${THIS_DIR}/../../node_modules/jsc-android/dist/org/webkit/android-jsc/${JSC_VERSION}
|
||||
mvn \
|
||||
deploy:deploy-file \
|
||||
-Durl=${MVN_REPO} \
|
||||
-Dfile=hermes-release.aar \
|
||||
-Dfile=android-jsc-${JSC_VERSION}.aar \
|
||||
-Dpackaging=aar \
|
||||
-DgroupId=com.facebook \
|
||||
-DartifactId=hermes \
|
||||
-Dversion=${HERMES_VERSION} \
|
||||
-DgeneratePom=true
|
||||
-DgeneratePom=false \
|
||||
-DpomFile=android-jsc-${JSC_VERSION}.pom
|
||||
popd
|
||||
fi
|
||||
|
||||
@@ -93,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
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
@@ -35,26 +33,19 @@ android {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
pickFirst '**/libc++_shared.so'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.fragment:fragment:1.2.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.fragment:fragment:1.2.5'
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
|
||||
//noinspection GradleDynamicVersion
|
||||
api 'com.facebook.react:react-native:+'
|
||||
|
||||
// Hermes JS engine
|
||||
def hermesPath = "../../node_modules/hermes-engine/android/"
|
||||
debugImplementation files(hermesPath + "hermes-debug.aar")
|
||||
releaseImplementation files(hermesPath + "hermes-release.aar")
|
||||
//noinspection GradleDynamicVersion
|
||||
implementation 'org.webkit:android-jsc:+'
|
||||
|
||||
implementation 'com.dropbox.core:dropbox-core-sdk:3.0.8'
|
||||
implementation 'com.jakewharton.timber:timber:4.7.1'
|
||||
@@ -80,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'
|
||||
}
|
||||
@@ -153,7 +145,7 @@ android.libraryVariants.all { def variant ->
|
||||
mergeResourcesTask.dependsOn(currentBundleTask)
|
||||
|
||||
mergeAssetsTask.doLast {
|
||||
def assetsDir = mergeAssetsTask.outputDir
|
||||
def assetsDir = mergeAssetsTask.outputDir.get()
|
||||
|
||||
// Bundle sounds
|
||||
//
|
||||
@@ -187,7 +179,7 @@ android.libraryVariants.all { def variant ->
|
||||
if (currentBundleTask.enabled) {
|
||||
copy {
|
||||
from(resourcesDir)
|
||||
into(mergeResourcesTask.outputDir)
|
||||
into(mergeResourcesTask.outputDir.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -227,14 +219,6 @@ publishing {
|
||||
dependency.appendNode('artifactId', artifactId)
|
||||
dependency.appendNode('version', it.moduleVersion)
|
||||
}
|
||||
|
||||
// Add Hermes dependency.
|
||||
def hermesPkg = new File("$rootDir/../node_modules/hermes-engine/package.json")
|
||||
def hermesVersion = new JsonSlurper().parseText(hermesPkg.text).version
|
||||
def hermesDependency = dependencies.appendNode('dependency')
|
||||
hermesDependency.appendNode('groupId', "com.facebook")
|
||||
hermesDependency.appendNode('artifactId', "hermes")
|
||||
hermesDependency.appendNode('version', hermesVersion)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@ import com.facebook.react.bridge.Callback;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.modules.core.PermissionListener;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
/**
|
||||
* Helper class to encapsulate the work which needs to be done on
|
||||
* {@link Activity} lifecycle methods in order for the React side to be aware of
|
||||
@@ -177,6 +179,16 @@ public class JitsiMeetActivityDelegate {
|
||||
|
||||
public static void requestPermissions(Activity activity, String[] permissions, int requestCode, PermissionListener listener) {
|
||||
permissionListener = listener;
|
||||
activity.requestPermissions(permissions, requestCode);
|
||||
|
||||
// The RN Permissions module calls this in a non-UI thread. What we observe is a crash in ViewGroup.dispatchCancelPendingInputEvents,
|
||||
// which is called on the calling (ie, non-UI) thread. This doesn't look very safe, so try to avoid a crash by pretending the permission
|
||||
// was denied.
|
||||
|
||||
try {
|
||||
activity.requestPermissions(permissions, requestCode);
|
||||
} catch (Exception e) {
|
||||
JitsiMeetLogger.e(e, "Error requesting permissions");
|
||||
onRequestPermissionsResult(requestCode, permissions, new int[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -20,21 +20,21 @@ import android.app.Activity;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.facebook.hermes.reactexecutor.HermesExecutorFactory;
|
||||
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.devio.rn.splashscreen.SplashScreenModule;
|
||||
import org.webrtc.SoftwareVideoDecoderFactory;
|
||||
import org.webrtc.SoftwareVideoEncoderFactory;
|
||||
import org.webrtc.audio.AudioDeviceModule;
|
||||
@@ -68,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),
|
||||
@@ -216,8 +217,9 @@ class ReactInstanceManagerHolder {
|
||||
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
|
||||
}
|
||||
|
||||
// Use the Hermes JavaScript engine.
|
||||
HermesExecutorFactory jsFactory = new HermesExecutorFactory();
|
||||
// Keep on using JSC, the jury is out on Hermes.
|
||||
JSCExecutorFactory jsFactory
|
||||
= new JSCExecutorFactory("", "");
|
||||
|
||||
reactInstanceManager
|
||||
= ReactInstanceManager.builder()
|
||||
|
||||
@@ -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'
|
||||
|
||||
17
app.js
17
app.js
@@ -4,6 +4,15 @@ import 'jquery';
|
||||
import 'jquery-contextmenu';
|
||||
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
|
||||
// window.location is not changed and still has all URL parameters.
|
||||
import './react/features/base/jitsi-local-storage/setup';
|
||||
import conference from './conference';
|
||||
import API from './modules/API';
|
||||
import UI from './modules/UI/UI';
|
||||
@@ -11,6 +20,14 @@ import keyboardshortcut from './modules/keyboardshortcut/keyboardshortcut';
|
||||
import remoteControl from './modules/remotecontrol/RemoteControl';
|
||||
import translation from './modules/translation/translation';
|
||||
|
||||
// Initialize Olm as early as possible.
|
||||
if (window.Olm) {
|
||||
window.Olm.init().catch(e => {
|
||||
console.error('Failed to initialize Olm, E2EE will be disabled', e);
|
||||
delete window.Olm;
|
||||
});
|
||||
}
|
||||
|
||||
window.APP = {
|
||||
API,
|
||||
conference,
|
||||
|
||||
191
conference.js
191
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,20 +97,17 @@ 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 { setE2EEKey } from './react/features/e2ee';
|
||||
import {
|
||||
maybeOpenFeedbackDialog,
|
||||
submitFeedback
|
||||
@@ -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,17 +715,15 @@ 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())
|
||||
};
|
||||
|
||||
this.roomName = roomName;
|
||||
|
||||
window.addEventListener('hashchange', this.onHashChange.bind(this), false);
|
||||
|
||||
try {
|
||||
// Initialize the device list first. This way, when creating tracks
|
||||
// based on preferred devices, loose label matching can be done in
|
||||
@@ -817,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);
|
||||
},
|
||||
@@ -1140,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>.
|
||||
@@ -1224,47 +1186,8 @@ export default {
|
||||
// this can be called from console and will not have reference to this
|
||||
// that's why we reference the global var
|
||||
const logs = APP.connection.getLogs();
|
||||
const data = encodeURIComponent(JSON.stringify(logs, null, ' '));
|
||||
|
||||
const elem = document.createElement('a');
|
||||
|
||||
elem.download = filename;
|
||||
elem.href = `data:application/json;charset=utf-8,\n${data}`;
|
||||
elem.dataset.downloadurl
|
||||
= [ 'text/json', elem.download, elem.href ].join(':');
|
||||
elem.dispatchEvent(new MouseEvent('click', {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handled location hash change events.
|
||||
*/
|
||||
onHashChange() {
|
||||
const items = {};
|
||||
const parts = window.location.hash.substr(1).split('&');
|
||||
|
||||
for (const part of parts) {
|
||||
const param = part.split('=');
|
||||
const key = param[0];
|
||||
|
||||
if (!key) {
|
||||
continue; // eslint-disable-line no-continue
|
||||
}
|
||||
|
||||
items[key] = param[1];
|
||||
}
|
||||
|
||||
if (typeof items.e2eekey !== 'undefined') {
|
||||
APP.store.dispatch(setE2EEKey(items.e2eekey));
|
||||
|
||||
// Clean URL in browser history.
|
||||
const cleanUrl = window.location.href.split('#')[0];
|
||||
|
||||
history.replaceState(history.state, document.title, cleanUrl);
|
||||
}
|
||||
downloadJSON(logs, filename);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -1360,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());
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -1637,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()) {
|
||||
@@ -2116,7 +1992,6 @@ export default {
|
||||
formattedDisplayName
|
||||
|| interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME)
|
||||
});
|
||||
APP.UI.changeDisplayName(id, formattedDisplayName);
|
||||
}
|
||||
);
|
||||
room.on(
|
||||
@@ -2179,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) => {
|
||||
@@ -2227,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));
|
||||
|
||||
@@ -2525,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);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -2705,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,
|
||||
@@ -3013,10 +2884,6 @@ export default {
|
||||
APP.store.dispatch(updateSettings({
|
||||
displayName: formattedNickname
|
||||
}));
|
||||
|
||||
if (room) {
|
||||
APP.UI.changeDisplayName(id, formattedNickname);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -3126,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);
|
||||
},
|
||||
|
||||
|
||||
23
config.js
23
config.js
@@ -14,9 +14,6 @@ var config = {
|
||||
// Domain for authenticated users. Defaults to <domain>.
|
||||
// authdomain: 'jitsi-meet.example.com',
|
||||
|
||||
// Jirecon recording component domain.
|
||||
// jirecon: 'jirecon.jitsi-meet.example.com',
|
||||
|
||||
// Call control component (Jigasi).
|
||||
// call_control: 'callcontrol.jitsi-meet.example.com',
|
||||
|
||||
@@ -67,6 +64,11 @@ var config = {
|
||||
// adjusted to 2.5 Mbps. This takes a value between 0 and 1 which determines
|
||||
// the probability for this to be enabled.
|
||||
// capScreenshareBitrate: 1 // 0 to disable
|
||||
|
||||
// Enable callstats only for a percentage of users.
|
||||
// This takes a value between 0 and 100 which determines the probability for
|
||||
// the callstats to be enabled.
|
||||
// callStatsThreshold: 5 // enable callstats for 5% of the users.
|
||||
},
|
||||
|
||||
// Disables ICE/UDP by filtering out local and remote UDP candidates in
|
||||
@@ -128,7 +130,7 @@ var config = {
|
||||
|
||||
// How many participants while in the tile view mode, before the receiving video quality is reduced from HD to SD.
|
||||
// Use -1 to disable.
|
||||
// maxFullResolutionParticipants: 2
|
||||
// maxFullResolutionParticipants: 2,
|
||||
|
||||
// w3c spec-compliant video constraints to use for video capture. Currently
|
||||
// used by browsers that return true from lib-jitsi-meet's
|
||||
@@ -321,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)
|
||||
@@ -335,6 +333,7 @@ var config = {
|
||||
// 'datachannel'), undefined (treat it as 'datachannel') and false (don't
|
||||
// open any channel).
|
||||
// openBridgeChannel: true,
|
||||
openBridgeChannel: 'websocket',
|
||||
|
||||
|
||||
// UI
|
||||
@@ -439,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: [
|
||||
|
||||
@@ -510,6 +506,9 @@ var config = {
|
||||
// ],
|
||||
},
|
||||
|
||||
// Logs that should go be passed through the 'log' event if a handler is defined for it
|
||||
// apiLogLevels: ['warn', 'log', 'error', 'info', 'debug'],
|
||||
|
||||
// Information about the jitsi-meet instance we are connecting to, including
|
||||
// the user region as seen by the server.
|
||||
deploymentInfo: {
|
||||
@@ -632,8 +631,6 @@ var config = {
|
||||
// List of undocumented settings used in jitsi-meet
|
||||
/**
|
||||
_immediateReloadThreshold
|
||||
autoRecord
|
||||
autoRecordToken
|
||||
debug
|
||||
debugAudioLevels
|
||||
deploymentInfo
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -45,10 +45,8 @@
|
||||
@extend .connection-info__icon;
|
||||
}
|
||||
|
||||
.showmore {
|
||||
display: block;
|
||||
.connection-actions {
|
||||
margin: 10px auto;
|
||||
text-align: center;
|
||||
width: 90px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#e2ee-section {
|
||||
.title {
|
||||
font-weight: 700;
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.description {
|
||||
font-size: 13px;
|
||||
@@ -13,29 +12,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
.key-field {
|
||||
align-items: center;
|
||||
.control-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
margin-top: 15px;
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
input {
|
||||
background-color: inherit;
|
||||
border: none;
|
||||
color: inherit;
|
||||
flex: 1;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #6FB1EA;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
8
debian/jitsi-meet-prosody.postrm
vendored
8
debian/jitsi-meet-prosody.postrm
vendored
@@ -45,8 +45,12 @@ case "$1" in
|
||||
rm -rf /var/lib/prosody/$JICOFO_AUTH_DOMAIN.*
|
||||
rm -rf /var/lib/prosody/$JVB_HOSTNAME.*
|
||||
|
||||
# clean created users
|
||||
rm -rf /var/lib/prosody/`echo $JICOFO_AUTH_DOMAIN | sed -e "s/\./%2e/g"`
|
||||
# clean created users, replace '.' with '%2e', replace '-' with '%2d'
|
||||
rm -rf /var/lib/prosody/`echo $JICOFO_AUTH_DOMAIN | sed -e "s/\./%2e/g"| sed -e "s/-/%2d/g"`
|
||||
|
||||
# clean the prosody cert from the trust store
|
||||
rm -rf /usr/local/share/ca-certificates/$JICOFO_AUTH_DOMAIN.*
|
||||
update-ca-certificates -f
|
||||
fi
|
||||
|
||||
# Clear the debconf variable
|
||||
|
||||
55
debian/jitsi-meet-turnserver.postinst
vendored
55
debian/jitsi-meet-turnserver.postinst
vendored
@@ -36,26 +36,6 @@ case "$1" in
|
||||
NGINX_CONFIG="/etc/nginx/sites-available/$JVB_HOSTNAME.conf"
|
||||
JITSI_MEET_CONFIG="/etc/jitsi/meet/$JVB_HOSTNAME-config.js"
|
||||
|
||||
NGINX_SITES_ENABLED="/etc/nginx/sites-enabled/"
|
||||
NGINX_CONFIG_ENABLED="${NGINX_SITES_ENABLED}${JVB_HOSTNAME}.conf"
|
||||
NGINX_MULTIPLEXING="true"
|
||||
for site in ${NGINX_SITES_ENABLED}*; do
|
||||
# if it is not a file continue
|
||||
[ -f "${site}" ] || continue
|
||||
# if it is our config skip
|
||||
[ "${site}" != "${NGINX_CONFIG_ENABLED}" ] || continue
|
||||
# check whether other enabled hosts has listen 443
|
||||
if cat ${site} | grep -v "^[[:space:]]*#" | grep listen | grep -q "^.*[[:space:]:]443[;[:space:]].*" ; then
|
||||
# nothing to do
|
||||
echo "------------------------------------------------"
|
||||
echo ""
|
||||
echo "turnserver is listening on tcp 5349 as other nginx sites use port 443"
|
||||
echo ""
|
||||
echo "------------------------------------------------"
|
||||
NGINX_MULTIPLEXING="false"
|
||||
fi
|
||||
done
|
||||
|
||||
# if there was a turn config backup it so we can configure
|
||||
# we cannot recognize at the moment is this a user config or default config when installing coturn
|
||||
if [[ -f $TURN_CONFIG ]] && ! grep -q "jitsi-meet coturn config" "$TURN_CONFIG" ; then
|
||||
@@ -133,19 +113,9 @@ denied-peer-ip=240.0.0.0-255.255.255.255" >> $TURN_CONFIG
|
||||
TURN_SECRET="$RET"
|
||||
|
||||
# no turn config exists, lt's copy template and fill it in
|
||||
PUBLIC_IP=$(dig -4 +short myip.opendns.com a @resolver1.opendns.com) || true
|
||||
if [ -z "$PUBLIC_IP" ] ; then
|
||||
PUBLIC_IP="127.0.0.1"
|
||||
echo "------------------------------------------------"
|
||||
echo "Warning! Could not resolve your external ip address! Error:^"
|
||||
echo "Your turn server will not work till you edit your $TURN_CONFIG config file."
|
||||
echo "You need to set your external ip address in external-ip and restart coturn service."
|
||||
echo "------------------------------------------------"
|
||||
fi
|
||||
cp /usr/share/jitsi-meet-turnserver/turnserver.conf $TURN_CONFIG
|
||||
sed -i "s/jitsi-meet.example.com/$JVB_HOSTNAME/g" $TURN_CONFIG
|
||||
sed -i "s/__turnSecret__/$TURN_SECRET/g" $TURN_CONFIG
|
||||
sed -i "s/__external_ip_address__/$PUBLIC_IP/g" $TURN_CONFIG
|
||||
|
||||
# SSL for nginx
|
||||
db_get jitsi-meet/cert-choice
|
||||
@@ -170,23 +140,14 @@ denied-peer-ip=240.0.0.0-255.255.255.255" >> $TURN_CONFIG
|
||||
invoke-rc.d coturn restart || true
|
||||
|
||||
NGINX_STREAM_CONFIG="/etc/nginx/modules-enabled/60-jitsi-meet.conf"
|
||||
if [ $NGINX_MULTIPLEXING = "true" ] && [ ! -f $NGINX_STREAM_CONFIG ] && [ -f $NGINX_CONFIG ] ; then
|
||||
ln -s /usr/share/jitsi-meet-turnserver/jitsi-meet.conf $NGINX_STREAM_CONFIG
|
||||
sed -i "s/listen 443 ssl/listen 4444 ssl http2/g" $NGINX_CONFIG
|
||||
sed -i "s/listen \[\:\:\]\:443 ssl/listen \[\:\:\]\:4444 ssl http2/g" $NGINX_CONFIG
|
||||
invoke-rc.d nginx reload || true
|
||||
else
|
||||
PROSODY_HOST_CONFIG="/etc/prosody/conf.avail/$JVB_HOSTNAME.cfg.lua"
|
||||
if [ -f $PROSODY_HOST_CONFIG ] ; then
|
||||
# If we are not multiplexing we need to change the port in prosody config
|
||||
sed -i 's/"443"/"5349"/g' $PROSODY_HOST_CONFIG
|
||||
invoke-rc.d prosody restart || true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Enable turn server in config.js
|
||||
if [ -f $JITSI_MEET_CONFIG ] ; then
|
||||
sed -i "s/\/\/ useStunTurn: true/useStunTurn: true/g" $JITSI_MEET_CONFIG
|
||||
if [ -f $NGINX_STREAM_CONFIG ] ; then
|
||||
echo "------------------------------------------------"
|
||||
echo ""
|
||||
echo "You have multiplexing enabled, it is recommended to disable it and migrate to using websockets for the bridge channel."
|
||||
echo "The support for sctp data channels is deprecated and will be dropped at some point."
|
||||
echo "How to do it at: https://jitsi.org/multiplexing-to-bridge-ws-howto"
|
||||
echo ""
|
||||
echo "------------------------------------------------"
|
||||
fi
|
||||
|
||||
# and we're done with debconf
|
||||
|
||||
2
debian/jitsi-meet-turnserver.postrm
vendored
2
debian/jitsi-meet-turnserver.postrm
vendored
@@ -24,7 +24,6 @@ set -e
|
||||
|
||||
case "$1" in
|
||||
remove)
|
||||
rm -rf /etc/nginx/modules-enabled/60-jitsi-meet.conf
|
||||
if [ -x "/etc/init.d/nginx" ]; then
|
||||
invoke-rc.d nginx reload || true
|
||||
fi
|
||||
@@ -33,7 +32,6 @@ case "$1" in
|
||||
fi
|
||||
;;
|
||||
purge)
|
||||
rm -rf /etc/nginx/modules-enabled/60-jitsi-meet.conf
|
||||
rm -rf /etc/turnserver.conf
|
||||
if [ -x "/etc/init.d/nginx" ]; then
|
||||
invoke-rc.d nginx reload || true
|
||||
|
||||
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/
|
||||
|
||||
@@ -8,7 +8,7 @@ turncredentials_secret = "__turnSecret__";
|
||||
turncredentials = {
|
||||
{ type = "stun", host = "jitmeet.example.com", port = "3478" },
|
||||
{ type = "turn", host = "jitmeet.example.com", port = "3478", transport = "udp" },
|
||||
{ type = "turns", host = "jitmeet.example.com", port = "443", transport = "tcp" }
|
||||
{ type = "turns", host = "jitmeet.example.com", port = "5349", transport = "tcp" }
|
||||
};
|
||||
|
||||
cross_domain_bosh = false;
|
||||
|
||||
@@ -12,7 +12,6 @@ no-tcp-relay
|
||||
no-tcp
|
||||
listening-port=3478
|
||||
tls-listening-port=5349
|
||||
external-ip=__external_ip_address__
|
||||
no-tlsv1
|
||||
no-tlsv1_1
|
||||
# https://ssl-config.mozilla.org/#server=haproxy&version=2.1&config=intermediate&openssl=1.1.0g&guideline=5.4
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
# this is jitsi-meet nginx module configuration
|
||||
# this forward all http traffic to the nginx virtual host port
|
||||
# and the rest to the turn server
|
||||
|
||||
#
|
||||
# Multiplexing based on ALPN is DEPRECATED. ALPN does not play well with websockets on some browsers and reverse proxies.
|
||||
# To migrate away from using it read: https://jitsi.org/multiplexing-to-bridge-ws-howto
|
||||
# This file will be removed at some point and if deployment is still using it, will break.
|
||||
#
|
||||
stream {
|
||||
upstream web {
|
||||
server 127.0.0.1:4444;
|
||||
|
||||
@@ -87,6 +87,15 @@ server {
|
||||
tcp_nodelay on;
|
||||
}
|
||||
|
||||
# colibri (JVB) websockets for jvb1
|
||||
location ~ ^/colibri-ws/default-id/(.*) {
|
||||
proxy_pass http://127.0.0.1:9090/colibri-ws/default-id/$1$is_args$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
tcp_nodelay on;
|
||||
}
|
||||
|
||||
location ~ ^/([^/?&:'"]+)$ {
|
||||
try_files $uri @root_path;
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
@@ -5,10 +5,9 @@ require_relative '../node_modules/@react-native-community/cli-platform-ios/nativ
|
||||
target 'jitsi-meet' do
|
||||
project 'app/app.xcodeproj'
|
||||
|
||||
pod 'Crashlytics', '~> 3.14.0'
|
||||
pod 'Fabric', '~> 1.10.2'
|
||||
pod 'Firebase/Core', '~> 6.16.0'
|
||||
pod 'Firebase/DynamicLinks', '~> 6.16.0'
|
||||
pod 'Firebase/Analytics', '~> 6.33.0'
|
||||
pod 'Firebase/Crashlytics', '~> 6.33.0'
|
||||
pod 'Firebase/DynamicLinks', '~> 6.33.0'
|
||||
end
|
||||
|
||||
target 'JitsiMeet' do
|
||||
@@ -67,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
|
||||
#
|
||||
|
||||
529
ios/Podfile.lock
529
ios/Podfile.lock
@@ -11,60 +11,59 @@ PODS:
|
||||
- CocoaLumberjack (3.5.3):
|
||||
- CocoaLumberjack/Core (= 3.5.3)
|
||||
- CocoaLumberjack/Core (3.5.3)
|
||||
- Crashlytics (3.14.0):
|
||||
- Fabric (~> 1.10.2)
|
||||
- DoubleConversion (1.1.6)
|
||||
- Fabric (1.10.2)
|
||||
- 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)
|
||||
- Firebase/Core (6.16.0):
|
||||
- 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):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseAnalytics (= 6.2.2)
|
||||
- Firebase/CoreOnly (6.16.0):
|
||||
- FirebaseCore (= 6.6.1)
|
||||
- Firebase/DynamicLinks (6.16.0):
|
||||
- FirebaseAnalytics (= 6.8.3)
|
||||
- Firebase/CoreOnly (6.33.0):
|
||||
- FirebaseCore (= 6.10.3)
|
||||
- Firebase/Crashlytics (6.33.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseDynamicLinks (~> 4.0.6)
|
||||
- FirebaseAnalytics (6.2.2):
|
||||
- FirebaseCore (~> 6.6)
|
||||
- FirebaseInstanceID (~> 4.3)
|
||||
- GoogleAppMeasurement (= 6.2.2)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
||||
- GoogleUtilities/Network (~> 6.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
||||
- nanopb (= 0.3.9011)
|
||||
- FirebaseAnalyticsInterop (1.5.0)
|
||||
- FirebaseCore (6.6.1):
|
||||
- FirebaseCoreDiagnostics (~> 1.2)
|
||||
- FirebaseCoreDiagnosticsInterop (~> 1.2)
|
||||
- GoogleUtilities/Environment (~> 6.5)
|
||||
- GoogleUtilities/Logger (~> 6.5)
|
||||
- FirebaseCoreDiagnostics (1.2.2):
|
||||
- FirebaseCoreDiagnosticsInterop (~> 1.2)
|
||||
- GoogleDataTransportCCTSupport (~> 2.0)
|
||||
- GoogleUtilities/Environment (~> 6.5)
|
||||
- GoogleUtilities/Logger (~> 6.5)
|
||||
- nanopb (~> 0.3.901)
|
||||
- FirebaseCoreDiagnosticsInterop (1.2.0)
|
||||
- FirebaseDynamicLinks (4.0.8):
|
||||
- FirebaseAnalyticsInterop (~> 1.3)
|
||||
- FirebaseCore (~> 6.2)
|
||||
- FirebaseInstallations (1.1.1):
|
||||
- FirebaseCore (~> 6.6)
|
||||
- GoogleUtilities/UserDefaults (~> 6.5)
|
||||
- FirebaseCrashlytics (~> 4.6.1)
|
||||
- Firebase/DynamicLinks (6.33.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseDynamicLinks (~> 4.3.1)
|
||||
- FirebaseAnalytics (6.8.3):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- FirebaseInstallations (~> 1.6)
|
||||
- GoogleAppMeasurement (= 6.8.3)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.7)
|
||||
- GoogleUtilities/MethodSwizzler (~> 6.7)
|
||||
- GoogleUtilities/Network (~> 6.7)
|
||||
- "GoogleUtilities/NSData+zlib (~> 6.7)"
|
||||
- nanopb (~> 1.30906.0)
|
||||
- FirebaseCore (6.10.3):
|
||||
- FirebaseCoreDiagnostics (~> 1.6)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/Logger (~> 6.7)
|
||||
- FirebaseCoreDiagnostics (1.7.0):
|
||||
- GoogleDataTransport (~> 7.4)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/Logger (~> 6.7)
|
||||
- nanopb (~> 1.30906.0)
|
||||
- FirebaseCrashlytics (4.6.1):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- FirebaseInstallations (~> 1.6)
|
||||
- GoogleDataTransport (~> 7.2)
|
||||
- nanopb (~> 1.30906.0)
|
||||
- PromisesObjC (~> 1.2)
|
||||
- FirebaseDynamicLinks (4.3.1):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- FirebaseInstallations (1.7.0):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/UserDefaults (~> 6.7)
|
||||
- PromisesObjC (~> 1.2)
|
||||
- FirebaseInstanceID (4.3.2):
|
||||
- FirebaseCore (~> 6.6)
|
||||
- FirebaseInstallations (~> 1.0)
|
||||
- GoogleUtilities/Environment (~> 6.5)
|
||||
- GoogleUtilities/UserDefaults (~> 6.5)
|
||||
- Folly (2018.10.22.00):
|
||||
- boost-for-react-native
|
||||
- DoubleConversion
|
||||
@@ -75,37 +74,36 @@ PODS:
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- glog (0.3.5)
|
||||
- GoogleAppMeasurement (6.2.2):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
||||
- GoogleUtilities/Network (~> 6.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
||||
- nanopb (= 0.3.9011)
|
||||
- GoogleDataTransport (5.1.0)
|
||||
- GoogleDataTransportCCTSupport (2.0.1):
|
||||
- GoogleDataTransport (~> 5.1)
|
||||
- nanopb (~> 0.3.901)
|
||||
- GoogleAppMeasurement (6.8.3):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.7)
|
||||
- GoogleUtilities/MethodSwizzler (~> 6.7)
|
||||
- GoogleUtilities/Network (~> 6.7)
|
||||
- "GoogleUtilities/NSData+zlib (~> 6.7)"
|
||||
- nanopb (~> 1.30906.0)
|
||||
- GoogleDataTransport (7.4.0):
|
||||
- nanopb (~> 1.30906.0)
|
||||
- GoogleSignIn (5.0.1):
|
||||
- AppAuth (~> 1.2)
|
||||
- GTMAppAuth (~> 1.0)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
- GoogleUtilities/AppDelegateSwizzler (6.5.2):
|
||||
- GoogleUtilities/AppDelegateSwizzler (6.7.2):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Environment (6.5.2)
|
||||
- GoogleUtilities/Logger (6.5.2):
|
||||
- GoogleUtilities/Environment (6.7.2):
|
||||
- PromisesObjC (~> 1.2)
|
||||
- GoogleUtilities/Logger (6.7.2):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/MethodSwizzler (6.5.2):
|
||||
- GoogleUtilities/MethodSwizzler (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network (6.5.2):
|
||||
- GoogleUtilities/Network (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (6.5.2)"
|
||||
- GoogleUtilities/Reachability (6.5.2):
|
||||
- "GoogleUtilities/NSData+zlib (6.7.2)"
|
||||
- GoogleUtilities/Reachability (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/UserDefaults (6.5.2):
|
||||
- GoogleUtilities/UserDefaults (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GTMAppAuth (1.0.0):
|
||||
- AppAuth/Core (~> 1.0)
|
||||
@@ -115,177 +113,177 @@ PODS:
|
||||
- GTMSessionFetcher/Core (1.2.2)
|
||||
- GTMSessionFetcher/Full (1.2.2):
|
||||
- GTMSessionFetcher/Core (= 1.2.2)
|
||||
- nanopb (0.3.9011):
|
||||
- nanopb/decode (= 0.3.9011)
|
||||
- nanopb/encode (= 0.3.9011)
|
||||
- nanopb/decode (0.3.9011)
|
||||
- nanopb/encode (0.3.9011)
|
||||
- nanopb (1.30906.0):
|
||||
- nanopb/decode (= 1.30906.0)
|
||||
- nanopb/encode (= 1.30906.0)
|
||||
- nanopb/decode (1.30906.0)
|
||||
- nanopb/encode (1.30906.0)
|
||||
- ObjectiveDropboxOfficial (3.9.4)
|
||||
- PromisesObjC (1.2.8)
|
||||
- RCTRequired (0.61.5-jitsi.1)
|
||||
- RCTTypeSafety (0.61.5-jitsi.1):
|
||||
- FBLazyVector (= 0.61.5-jitsi.1)
|
||||
- PromisesObjC (1.2.10)
|
||||
- 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-native-background-timer (2.1.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):
|
||||
- React
|
||||
@@ -293,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-webview (7.4.1):
|
||||
- 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):
|
||||
@@ -363,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
|
||||
@@ -373,13 +373,12 @@ DEPENDENCIES:
|
||||
- Amplitude-iOS (~> 4.0.4)
|
||||
- BVLinearGradient (from `../node_modules/react-native-linear-gradient`)
|
||||
- CocoaLumberjack (~> 3.5.3)
|
||||
- Crashlytics (~> 3.14.0)
|
||||
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||
- Fabric (~> 1.10.2)
|
||||
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector/`)
|
||||
- FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec/`)
|
||||
- Firebase/Core (~> 6.16.0)
|
||||
- Firebase/DynamicLinks (~> 6.16.0)
|
||||
- Firebase/Analytics (~> 6.33.0)
|
||||
- Firebase/Crashlytics (~> 6.33.0)
|
||||
- Firebase/DynamicLinks (~> 6.33.0)
|
||||
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
|
||||
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
||||
- ObjectiveDropboxOfficial (~> 3.9.4)
|
||||
@@ -398,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`)
|
||||
@@ -424,20 +424,15 @@ SPEC REPOS:
|
||||
- AppAuth
|
||||
- boost-for-react-native
|
||||
- CocoaLumberjack
|
||||
- Crashlytics
|
||||
- Fabric
|
||||
- Firebase
|
||||
- FirebaseAnalytics
|
||||
- FirebaseAnalyticsInterop
|
||||
- FirebaseCore
|
||||
- FirebaseCoreDiagnostics
|
||||
- FirebaseCoreDiagnosticsInterop
|
||||
- FirebaseCrashlytics
|
||||
- FirebaseDynamicLinks
|
||||
- FirebaseInstallations
|
||||
- FirebaseInstanceID
|
||||
- GoogleAppMeasurement
|
||||
- GoogleDataTransport
|
||||
- GoogleDataTransportCCTSupport
|
||||
- GoogleSignIn
|
||||
- GoogleUtilities
|
||||
- GTMAppAuth
|
||||
@@ -485,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:
|
||||
@@ -530,65 +527,61 @@ SPEC CHECKSUMS:
|
||||
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
|
||||
BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872
|
||||
CocoaLumberjack: 2f44e60eb91c176d471fdba43b9e3eae6a721947
|
||||
Crashlytics: 540b7e5f5da5a042647227a5e3ac51d85eed06df
|
||||
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
|
||||
Fabric: 706c8b8098fff96c33c0db69cbf81f9c551d0d74
|
||||
FBLazyVector: 4a5251159a3ed05dc11cc8b74cf937869935814b
|
||||
FBReactNativeSpec: 6fa602a20993212cc9877a81838578ffb0008bc9
|
||||
Firebase: 497158b816d0a86fc31babbd05546fcd7e6083ff
|
||||
FirebaseAnalytics: cf95d3aab897612783020fbd98401d5366f135ee
|
||||
FirebaseAnalyticsInterop: 3f86269c38ae41f47afeb43ebf32a001f58fcdae
|
||||
FirebaseCore: 85064903ed6c28e47fec9c7bd149d94ba1b6b6e7
|
||||
FirebaseCoreDiagnostics: e9b4cd8ba60dee0f2d13347332e4b7898cca5b61
|
||||
FirebaseCoreDiagnosticsInterop: 296e2c5f5314500a850ad0b83e9e7c10b011a850
|
||||
FirebaseDynamicLinks: 417dc6dbb6013233c77558290d73296f429656a6
|
||||
FirebaseInstallations: acb3216eb9784d3b1d2d2d635ff74fa892cc0c44
|
||||
FirebaseInstanceID: 7ee0d6777013bb952f377b41965bf132b6a075be
|
||||
FBLazyVector: ca7f56c8ff6cd8590f7a673d7903b06019805581
|
||||
FBReactNativeSpec: 8136c3cf27de2bb310a69cffbb423c5643f5c1c4
|
||||
Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5
|
||||
FirebaseAnalytics: 5dd088bd2e67bb9d13dbf792d1164ceaf3052193
|
||||
FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd
|
||||
FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1
|
||||
FirebaseCrashlytics: 5777d3462fb8c3ab9e80a2473bd7d667a2e8411c
|
||||
FirebaseDynamicLinks: 6eac37d86910382eafb6315d952cc44c9e176094
|
||||
FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2
|
||||
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
|
||||
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
|
||||
GoogleAppMeasurement: d0560d915abf15e692e8538ba1d58442217b6aff
|
||||
GoogleDataTransport: b29a21d813e906014ca16c00897827e40e4a24ab
|
||||
GoogleDataTransportCCTSupport: 6f15a89b0ca35d6fa523e1f752ef818588885988
|
||||
GoogleAppMeasurement: 966e88df9d19c15715137bb2ddaf52373f111436
|
||||
GoogleDataTransport: b7f406340a291370045a270c599e53c6fa6ec20f
|
||||
GoogleSignIn: 3a51b9bb8e48b635fd7f4272cee06ca260345b86
|
||||
GoogleUtilities: ad0f3b691c67909d03a3327cc205222ab8f42e0e
|
||||
GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
|
||||
GTMAppAuth: 4deac854479704f348309e7b66189e604cf5e01e
|
||||
GTMSessionFetcher: 61bb0f61a4cb560030f1222021178008a5727a23
|
||||
nanopb: 18003b5e52dab79db540fe93fe9579f399bd1ccd
|
||||
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
|
||||
ObjectiveDropboxOfficial: a5afefc83f6467c42c45f2253f583f2ad1ffc701
|
||||
PromisesObjC: c119f3cd559f50b7ae681fa59dc1acd19173b7e6
|
||||
RCTRequired: f63dd90a89a60602acdd44c42e5d2645ca60ab79
|
||||
RCTTypeSafety: 24a3c6d55684046ed550b1d0ef083a9bf71c8bd4
|
||||
React: 71c5a51135f291c3b32c0b558e167b858ae50e84
|
||||
React-Core: e82c03ff91062abf963f35bf99a357154e570285
|
||||
React-CoreModules: e236aeecd18cec37743c8c50562431db5302f668
|
||||
React-cxxreact: 526ec106aa1bf2b3f6aab2a7d528d1d23d5f59c2
|
||||
React-jsi: 4f35c1a2273d193a80c1c3831c808413840c260c
|
||||
React-jsiexecutor: de1c37cf59ae9adcbf2be82eea0e090dc3f3205e
|
||||
React-jsinspector: b76c4e84a7833bb4c90549d59ed53ec299ff912b
|
||||
react-native-background-timer: 0d34748e53a972507c66963490c775321a88f6f2
|
||||
PromisesObjC: b14b1c6b68e306650688599de8a45e49fae81151
|
||||
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-webview: 4dbc1d2a4a6b9c5e9e723c62651917aa2b5e579e
|
||||
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-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
|
||||
react-native-webrtc: edd689b0d5a462d7a6f6f52bca3f9414fc0ee11c
|
||||
react-native-webview: 6ee7868ca8eba635dbf7963986d1ab7959da0391
|
||||
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: 082858daebbe170e7a490de433e7f2a99e0c3701
|
||||
PODFILE CHECKSUM: f2400f8e5a52c4d91697cbacba6956569efc5ab8
|
||||
|
||||
COCOAPODS: 1.9.1
|
||||
COCOAPODS: 1.9.3
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
#import "Types.h"
|
||||
#import "ViewController.h"
|
||||
|
||||
@import Crashlytics;
|
||||
@import Fabric;
|
||||
@import Firebase;
|
||||
@import JitsiMeet;
|
||||
|
||||
@@ -48,12 +46,16 @@
|
||||
}];
|
||||
|
||||
// Initialize Crashlytics and Firebase if a valid GoogleService-Info.plist file was provided.
|
||||
if ([FIRUtilities appContainsRealServiceInfoPlist] && ![jitsiMeet isCrashReportingDisabled]) {
|
||||
NSLog(@"Enabling Crashlytics and Firebase");
|
||||
if ([FIRUtilities appContainsRealServiceInfoPlist]) {
|
||||
NSLog(@"Enabling Firebase");
|
||||
[FIRApp configure];
|
||||
[Fabric with:@[[Crashlytics class]]];
|
||||
// Crashlytics defaults to disabled wirth the FirebaseCrashlyticsCollectionEnabled Info.plist key.
|
||||
[[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:![jitsiMeet isCrashReportingDisabled]];
|
||||
}
|
||||
|
||||
ViewController *rootController = (ViewController *)self.window.rootViewController;
|
||||
[jitsiMeet showSplashScreen:rootController.view];
|
||||
|
||||
[jitsiMeet application:application didFinishLaunchingWithOptions:launchOptions];
|
||||
|
||||
return YES;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>20.4.0</string>
|
||||
<string>20.5.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
@@ -66,10 +66,10 @@
|
||||
<string>See your scheduled meetings in the app.</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Participate in meetings with video.</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string></string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Participate in meetings with voice.</string>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>Local network is used for establishing Peer-to-Peer connections.</string>
|
||||
<key>NSUserActivityTypes</key>
|
||||
<array>
|
||||
<string>org.jitsi.JitsiMeet.ios.conference</string>
|
||||
@@ -99,7 +99,7 @@
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>firebase_crashlytics_collection_enabled</key>
|
||||
<key>FirebaseCrashlyticsCollectionEnabled</key>
|
||||
<string>false</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>20.4.0</string>
|
||||
<string>20.5.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>20.4.0</string>
|
||||
<string>20.5.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>CLKComplicationPrincipalClass</key>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.10.0</string>
|
||||
<string>2.11.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"ru": "Russisch",
|
||||
"sk": "Slowakisch",
|
||||
"sl": "Slowenisch",
|
||||
"sr": "Serbish",
|
||||
"sv": "Schwedisch",
|
||||
"tr": "Türkisch",
|
||||
"vi": "Vietnamesisch",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"ru": "Russian",
|
||||
"sk": "",
|
||||
"sl": "Slovenian",
|
||||
"sr": "Serbian",
|
||||
"sv": "Swedish",
|
||||
"tr": "Turkish",
|
||||
"vi": "Vietnamese",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"ru": "Ruski",
|
||||
"sk": "Slovački",
|
||||
"sl": "Slovenski",
|
||||
"sr": "Srpski",
|
||||
"sv": "Švedski",
|
||||
"tr": "Turski",
|
||||
"vi": "Vijetnamski",
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"pl": "Польский",
|
||||
"ptBR": "Португальский (Бразилия)",
|
||||
"ru": "Русский",
|
||||
"sr": "Сербский",
|
||||
"sv": "Шведский",
|
||||
"tr": "Турецкий",
|
||||
"vi": "Вьетнамский",
|
||||
|
||||
@@ -1,34 +1,39 @@
|
||||
{
|
||||
"en": "",
|
||||
"af": "",
|
||||
"bg": "",
|
||||
"ca": "",
|
||||
"cs": "",
|
||||
"da": "",
|
||||
"de": "",
|
||||
"el": "",
|
||||
"enGB": "",
|
||||
"eo": "",
|
||||
"es": "",
|
||||
"esUS": "",
|
||||
"et": "",
|
||||
"fi": "",
|
||||
"fr": "",
|
||||
"frCA": "",
|
||||
"hr": "",
|
||||
"hu": "",
|
||||
"hy": "",
|
||||
"it": "",
|
||||
"ja": "",
|
||||
"ko": "",
|
||||
"nl": "",
|
||||
"oc": "",
|
||||
"pl": "",
|
||||
"ptBR": "",
|
||||
"ru": "",
|
||||
"sv": "",
|
||||
"tr": "",
|
||||
"vi": "",
|
||||
"zhCN": "",
|
||||
"zhTW": ""
|
||||
"en": "Енглески",
|
||||
"af": "Африкански",
|
||||
"az": "Азербејџански",
|
||||
"bg": "Бугарски",
|
||||
"cs": "Чешки",
|
||||
"de": "Њемачки",
|
||||
"el": "Грчки",
|
||||
"eo": "Есперанто",
|
||||
"es": "Шпански",
|
||||
"fr": "Француски",
|
||||
"hy": "Јерменски",
|
||||
"it": "Италијански",
|
||||
"ja": "Јапански",
|
||||
"ko": "Корејски",
|
||||
"nb": "Норвешки Бокал",
|
||||
"oc": "Окцитански",
|
||||
"pl": "Пољски",
|
||||
"ptBR": "Португалски (Бразил)",
|
||||
"ru": "Руски",
|
||||
"sk": "Словачки",
|
||||
"sl": "Словенски",
|
||||
"sr": "Српски",
|
||||
"sv": "Шведски",
|
||||
"tr": "Турски",
|
||||
"vi": "Вијетнамски",
|
||||
"zhCN": "Кинески (Кина)",
|
||||
"zhTW": "Кинески (Тајван)",
|
||||
"nl": "Холандски",
|
||||
"hu": "Мађарски",
|
||||
"hr": "Хрватски",
|
||||
"frCA": "Француски (Канада)",
|
||||
"fi": "Фински",
|
||||
"et": "Естонски",
|
||||
"esUS": "Шпански (Латинска Америка)",
|
||||
"enGB": "Енглески (Велика Британија)",
|
||||
"da": "Дански",
|
||||
"ca": "Каталонски"
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"sc": "Sardinian",
|
||||
"sk": "Slovak",
|
||||
"sl": "Slovenian",
|
||||
"sr": "Serbian",
|
||||
"sv": "Swedish",
|
||||
"th": "Thailand",
|
||||
"tr": "Turkish",
|
||||
|
||||
@@ -234,7 +234,7 @@
|
||||
"micPermissionDeniedError": "Die Berechtigung zur Verwendung des Mikrofons wurde nicht erteilt. Sie können trotzdem an der Konferenz teilnehmen, aber die anderen Teilnehmer können Sie nicht hören. Verwenden Sie die Kamera-Schaltfläche in der Adressleiste, um die Berechtigungen zu erteilen.",
|
||||
"micUnknownError": "Das Mikrofon kann aus einem unbekannten Grund nicht verwendet werden.",
|
||||
"muteEveryoneElseDialog": "Einmal stummgeschaltet, können Sie deren Stummschaltung nicht mehr beenden, aber sie können ihre Stummschaltung jederzeit selbst beenden.",
|
||||
"muteEveryoneElseTitle": "Alle außer {{whom}} stummschaten?",
|
||||
"muteEveryoneElseTitle": "Alle außer {{whom}} stummschalten?",
|
||||
"muteEveryoneDialog": "Wollen Sie wirklich alle stummschalten? Sie können deren Stummschaltung nicht mehr beenden, aber sie können ihre Stummschaltung jederzeit selbst beenden.",
|
||||
"muteEveryoneTitle": "Alle stummschalten?",
|
||||
"muteEveryoneSelf": "sich selbst",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"addContacts": "Inviter vos contacts",
|
||||
"copyInvite": "Copier l'invitation à la réunion",
|
||||
"copyLink": "Copier le lien de la réunion",
|
||||
"copyStream": "Copier le lien de diffision en direct",
|
||||
"copyStream": "Copier le lien de diffusion en direct",
|
||||
"countryNotSupported": "Cette destination n'est pas actuellement supportée.",
|
||||
"countryReminder": "Appel hors des États-Unis ? Veuillez débuter par le code du pays !",
|
||||
"defaultEmail": "Votre email par défaut",
|
||||
@@ -139,6 +139,9 @@
|
||||
"description": "Rien ne s'est passé ? Nous avons essayé de lancer votre réunion dans l'application de bureau {{app}}. Essayez à nouveau ou lancez-la dans l'application web {{app}}.",
|
||||
"descriptionWithoutWeb": "Rien ne s'est passé ? Nous avons essayé de démarrer votre réunion dans l'application bureau {{app}}.",
|
||||
"downloadApp": "Télécharger l'application",
|
||||
"ifDoNotHaveApp": "Si vous n'avez pas encore l'application:",
|
||||
"ifHaveApp": "Si vous avez déjà installé l'application:",
|
||||
"joinInApp": "Rejoindre la réunion en utilisant l'application",
|
||||
"launchWebButton": "Lancer dans le navigateur",
|
||||
"openApp": "Continuer vers l'application",
|
||||
"title": "Lancement de votre réunion dans {{app}} en cours...",
|
||||
@@ -194,7 +197,7 @@
|
||||
"done": "Terminé",
|
||||
"enterDisplayName": "Merci de saisir votre nom ici",
|
||||
"error": "Erreur",
|
||||
"grantModeratorDialog": "Êtes vous sûr de vouloir rendre ce participant modérateur?",
|
||||
"grantModeratorDialog": "Êtes-vous sûr de vouloir rendre ce participant modérateur?",
|
||||
"grantModeratorTitle": "Nommer modérateur",
|
||||
"externalInstallationMsg": "Vous devez installer notre extension de partage de bureau.",
|
||||
"externalInstallationTitle": "Extension requise",
|
||||
@@ -230,7 +233,7 @@
|
||||
"micUnknownError": "Vous ne pouvez pas utiliser le microphone pour une raison inconnue.",
|
||||
"muteEveryoneElseDialog": "Une fois leur micro coupé, vous ne pourrez plus le réactiver, mais ils pourront l'activer par eux-mêmes à tout moment.",
|
||||
"muteEveryoneElseTitle": "Couper le micro de tout le monde sauf de {{whom}} ?",
|
||||
"muteEveryoneDialog": "Etes-vous sûr de vouloir couper les micros de tout le monde ? Vous ne pourrez plus réactiver leur micro, mais ils pourront l'activer par eux-mêmes à tout moment.",
|
||||
"muteEveryoneDialog": "Êtes-vous sûr de vouloir couper les micros de tout le monde ? Vous ne pourrez plus réactiver leur micro, mais ils pourront l'activer par eux-mêmes à tout moment.",
|
||||
"muteEveryoneTitle": "Couper le micro de tout le monde ?",
|
||||
"muteEveryoneSelf": "vous",
|
||||
"muteEveryoneStartMuted": "Tout le monde démarre avec le micro coupé",
|
||||
@@ -697,6 +700,8 @@
|
||||
"hangup": "Quitter",
|
||||
"help": "Aide",
|
||||
"invite": "Inviter des participants",
|
||||
"lobbyButtonDisable": "Désactiver le contrôle des participant·e·s",
|
||||
"lobbyButtonEnable": "Activer le contrôle des participant·e·s",
|
||||
"login": "Connexion",
|
||||
"logout": "Déconnexion",
|
||||
"lowerYourHand": "Baisser la main",
|
||||
@@ -725,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",
|
||||
@@ -764,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)"
|
||||
},
|
||||
@@ -804,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"
|
||||
@@ -842,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",
|
||||
|
||||
1025
lang/main-kab.json
1025
lang/main-kab.json
File diff suppressed because it is too large
Load Diff
@@ -1,60 +1,86 @@
|
||||
{
|
||||
"addPeople": {
|
||||
"add": "초대",
|
||||
"countryNotSupported": "아직 해당 지역을 지원하지 않습니다",
|
||||
"addContacts": "연락처로 초대하세요",
|
||||
"copyInvite": "호의 초대 복사",
|
||||
"copyLink": "회의 링크 복사",
|
||||
"copyStream": "라이브 스트리밍 링크 복사",
|
||||
"countryNotSupported": "아직 해당 지역을 지원하지 않습니다.",
|
||||
"countryReminder": "미국 이외의 지역으로 전화하시겠습니까? 국가 번호로 시작해야합니다!",
|
||||
"disabled": "사람들을 초대 할 수 없습니다",
|
||||
"failedToAdd": "",
|
||||
"footerText": "",
|
||||
"defaultEmail": "기본 이메일",
|
||||
"disabled": "사람들을 초대 할 수 없습니다.",
|
||||
"failedToAdd": "참가자를 추가하지 못했습니다.",
|
||||
"footerText": "전화 걸기가 비활성화되었습니다.",
|
||||
"googleEmail": "Google 이메일",
|
||||
"inviteMoreHeader": "회의에 혼자 참여하고 있습니다.",
|
||||
"inviteMoreMailSubject": "{{appName}} 회의에 참여하세요",
|
||||
"inviteMorePrompt": "더 많은 사람을 초대하세요",
|
||||
"linkCopied": "링크가 클립보드에 복사되었습니다.",
|
||||
"loading": "사람 및 전화번호 검색",
|
||||
"loadingNumber": "전화번호 확인 중",
|
||||
"loadingPeople": "초대할 사람 찾기",
|
||||
"noResults": "일치하는 검색 결과 없음",
|
||||
"noValidNumbers": "전화 번호를 입력하십시오.",
|
||||
"outlookEmail": "Outlook 이메일",
|
||||
"searchNumbers": "전화번호 추가",
|
||||
"searchPeople": "인명 검색",
|
||||
"searchPeopleAndNumbers": "인명 검색 또는 전화번호 추가",
|
||||
"shareInvite": "회의 초대 공유",
|
||||
"shareLink": "다른 사람을 초대하려면 회의 링크를 공유하세요.",
|
||||
"shareStream": "라이브 스트리밍 링크 공유",
|
||||
"telephone": "전화: {{number}}",
|
||||
"title": "이 회의에 사람들을 초대하십시오"
|
||||
"title": "이 회의에 사람들을 초대하십시오",
|
||||
"yahooEmail": "Yahoo 이메일"
|
||||
},
|
||||
"audioDevices": {
|
||||
"bluetooth": "블루투스",
|
||||
"headphones": "헤드폰",
|
||||
"phone": "폰",
|
||||
"speaker": "스피커"
|
||||
"speaker": "스피커",
|
||||
"none": "사용 가능한 오디오 장치가 없습니다."
|
||||
},
|
||||
"audioOnly": {
|
||||
"audioOnly": "음성 전용"
|
||||
},
|
||||
"calendarSync": {
|
||||
"addMeetingURL": "",
|
||||
"confirmAddLink": "",
|
||||
"addMeetingURL": "회의 링크 추가",
|
||||
"confirmAddLink": "이 이벤트에 Jitsi 링크를 추가 하시겠습니까?",
|
||||
"error": {
|
||||
"appConfiguration": "",
|
||||
"generic": "",
|
||||
"notSignedIn": ""
|
||||
"appConfiguration": "캘린더가 제대로 구성되지 않았습니다.",
|
||||
"generic": "오류가 발생했습니다. 캘린더 설정을 확인하거나 캘린더를 새로 고침 해보세요.",
|
||||
"notSignedIn": "캘린더 이벤트를 보기 위해 인증하는 동안 오류가 발생했습니다. 캘린더 설정을 확인하고 다시 로그인하십시오."
|
||||
},
|
||||
"join": "",
|
||||
"joinTooltip": "",
|
||||
"join": "참여",
|
||||
"joinTooltip": "회의에 참여하세요",
|
||||
"nextMeeting": "다음 회의",
|
||||
"noEvents": "",
|
||||
"ongoingMeeting": "",
|
||||
"noEvents": "예정된 예정된 이벤트가 없습니다.",
|
||||
"ongoingMeeting": "진행중인 회의",
|
||||
"permissionButton": "설정 열기",
|
||||
"permissionMessage": "앱에 회의를 나열하려면 캘린더 권한이 필요합니다",
|
||||
"refresh": "",
|
||||
"today": ""
|
||||
"refresh": "달력 새로고침",
|
||||
"today": "오늘"
|
||||
},
|
||||
"chat": {
|
||||
"error": "",
|
||||
"messagebox": "",
|
||||
"error": "오류 : 메시지가 전송되지 않았습니다. 이유 : {{error}}",
|
||||
"fieldPlaceHolder": "메세지를 여기에 입력하세요",
|
||||
"messagebox": "메시지 입력",
|
||||
"messageTo": "{{recipient}}에게 보내는 비공개 메시지",
|
||||
"noMessagesMessage": "아직 회의에 메시지가 없습니다. 여기서 대화를 시작하세요!",
|
||||
"nickname": {
|
||||
"popover": "닉네임을 선택하세요",
|
||||
"title": ""
|
||||
"title": "채팅에서 사용할 닉네임을 입력하세요"
|
||||
},
|
||||
"title": ""
|
||||
"privateNotice": "{{recipient}}에게 보내는 비공개 메시지",
|
||||
"title": "채팅",
|
||||
"you": "당신"
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
"installExtensionText": "Google 캘린더 및 Office 365 확장 프로그램을 설치합니다.",
|
||||
"buttonText": "Chrome 확장 프로그램을 설치합니다.",
|
||||
"dontShowAgain": "다시 보지 않기"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
"joiningRoom": ""
|
||||
"joiningRoom": "회의에 연결 중 ..."
|
||||
},
|
||||
"connection": {
|
||||
"ATTACHED": "첨부",
|
||||
@@ -66,7 +92,10 @@
|
||||
"DISCONNECTED": "연결 끊김",
|
||||
"DISCONNECTING": "연결 종료 중",
|
||||
"ERROR": "에러",
|
||||
"RECONNECTING": "네트워크 문제가 발생했습니다. 다시 연결 중..."
|
||||
"RECONNECTING": "네트워크 문제가 발생했습니다. 다시 연결 중...",
|
||||
"GET_SESSION_ID_ERROR": "세션 ID 가져 오기 오류 : {{code}}",
|
||||
"GOT_SESSION_ID": "세션 ID를 가져 오는 중 ... 완료",
|
||||
"LOW_BANDWIDTH": "대역폭을 절약하기 위해 {{displayName}}의 동영상이 중지되었습니다."
|
||||
},
|
||||
"connectionindicator": {
|
||||
"address": "주소:",
|
||||
@@ -95,15 +124,18 @@
|
||||
"turn": " (turn)"
|
||||
},
|
||||
"dateUtils": {
|
||||
"earlier": "",
|
||||
"today": "",
|
||||
"yesterday": ""
|
||||
"earlier": "일찍이",
|
||||
"today": "오늘",
|
||||
"yesterday": "어제"
|
||||
},
|
||||
"deepLinking": {
|
||||
"appNotInstalled": "중계 서비스에 참여하려면 모바일 앱 설치가 필요합니다",
|
||||
"appNotInstalled": "회의에 참여하려면 모바일 앱 설치가 필요합니다",
|
||||
"description": "{{app}} 데스크톱 앱에서 회의를 시작했습니다. {{app}} 웹 응용 프로그램에서 다시 시도하거나 실행하십시오.",
|
||||
"descriptionWithoutWeb": "",
|
||||
"downloadApp": "앱 다운로드",
|
||||
"ifDoNotHaveApp": "앱이 설치되지 않은 경우:",
|
||||
"ifHaveApp": "앱이 설치되어 있는 경우:",
|
||||
"joinInApp": "앱을 사용하여 회의에 참여하세요.",
|
||||
"launchWebButton": "웹에서 실행",
|
||||
"openApp": "방으로 이동하기",
|
||||
"title": "{{app}}에서 회의 시작…",
|
||||
@@ -126,8 +158,9 @@
|
||||
"accessibilityLabel": {
|
||||
"liveStreaming": "실시간 스트리밍:"
|
||||
},
|
||||
"add": "추가",
|
||||
"allow": "허락",
|
||||
"alreadySharedVideoMsg": "",
|
||||
"alreadySharedVideoMsg": "다른 참가자가 이미 비디오를 공유하고 있습니다. 이 회의는 한 번에 하나의 공유 비디오 만 허용합니다.",
|
||||
"alreadySharedVideoTitle": "한 번에 하나의 공유 비디오 만 허용됩니다",
|
||||
"applicationWindow": "응용 프로그램 창",
|
||||
"Back": "뒤로가기",
|
||||
@@ -145,64 +178,64 @@
|
||||
"conferenceReloadMsg": "문제를 해결하려고 노력하고 있습니다. {{seconds}} 초 안에 다시 연결중입니다.",
|
||||
"conferenceReloadTitle": "불행하게도 문제가 발생했습니다",
|
||||
"confirm": "확인",
|
||||
"confirmNo": "",
|
||||
"confirmYes": "",
|
||||
"confirmNo": "아니요",
|
||||
"confirmYes": "예",
|
||||
"connectError": "죄송합니다. 문제가 발생하여 회의에 연결할 수 없습니다",
|
||||
"connectErrorWithMsg": "죄송합니다. 뭔가 잘못되어 회의에 연결할 수 없습니다: {{msg}}",
|
||||
"connecting": "연결 중",
|
||||
"contactSupport": "지원 연락처",
|
||||
"copy": "복사",
|
||||
"dismiss": "",
|
||||
"displayNameRequired": "",
|
||||
"displayNameRequired": "당신의 이름은 무엇입니까?",
|
||||
"done": "완료",
|
||||
"enterDisplayName": "",
|
||||
"enterDisplayName": "당신의 이름을 입력해주세요.",
|
||||
"error": "에러",
|
||||
"externalInstallationMsg": "데스크톱 공유 확장 프로그램을 설치해야합니다",
|
||||
"externalInstallationTitle": "확장 프로그램이 필요합니다",
|
||||
"goToStore": "웹 스토어로 이동",
|
||||
"gracefulShutdown": "서비스는 현재 유지 관리를 위해 중단되었습니다. 나중에 다시 시도 해주십시오.",
|
||||
"IamHost": "내가 호스트",
|
||||
"incorrectRoomLockPassword": "",
|
||||
"incorrectRoomLockPassword": "잘못된 비밀번호",
|
||||
"incorrectPassword": "잘못된 사용자 이름 또는 비밀번호",
|
||||
"inlineInstallationMsg": "데스크톱 공유 확장 프로그램을 설치해야합니다",
|
||||
"inlineInstallExtension": "지금 설치",
|
||||
"internalError": "죄송합니다. 뭔가 잘못 됐습니다. 다음 오류가 발생했습니다: {{error}}",
|
||||
"internalErrorTitle": "내부 에러",
|
||||
"kickMessage": "",
|
||||
"kickParticipantButton": "",
|
||||
"kickParticipantDialog": "",
|
||||
"kickParticipantTitle": "",
|
||||
"kickTitle": "",
|
||||
"kickMessage": "자세한 내용은 {{participantDisplayName}}에 문의하세요.",
|
||||
"kickParticipantButton": "추방",
|
||||
"kickParticipantDialog": "이 참가자를 정말 추방 하시겠습니까?",
|
||||
"kickParticipantTitle": "이 참가자를 추방 하시겠습니까?",
|
||||
"kickTitle": "{{participantDisplayName}} 님이 회의에서 퇴장했습니다.",
|
||||
"liveStreaming": "실시간 스트리밍",
|
||||
"liveStreamingDisabledForGuestTooltip": "",
|
||||
"liveStreamingDisabledTooltip": "",
|
||||
"liveStreamingDisabledForGuestTooltip": "게스트는 라이브 스트리밍을 시작할 수 없습니다.",
|
||||
"liveStreamingDisabledTooltip": "라이브 스트림 시작이 비활성화되었습니다.",
|
||||
"lockMessage": "회의를 비공개하지 못했습니다",
|
||||
"lockRoom": "",
|
||||
"lockRoom": "회의 추가 $t(lockRoomPasswordUppercase)",
|
||||
"lockTitle": "비공개 실패",
|
||||
"logoutQuestion": "로그 아웃하고 컨퍼런스를 중지하시겠습니까?",
|
||||
"logoutTitle": "로그아웃",
|
||||
"maxUsersLimitReached": "",
|
||||
"maxUsersLimitReachedTitle": "",
|
||||
"maxUsersLimitReached": "회의의 최대 참가자 수에 도달했습니다. 회의 소유자에게 연락하거나 나중에 다시 시도하십시오!",
|
||||
"maxUsersLimitReachedTitle": "최대 참가자 수에 도달했습니다.",
|
||||
"micConstraintFailedError": "마이크가 필요한 제약 조건 중 일부를 충족하지 못합니다",
|
||||
"micNotFoundError": "마이크를 찾을 수 없습니다",
|
||||
"micNotSendingData": "",
|
||||
"micNotSendingDataTitle": "",
|
||||
"micNotSendingData": "컴퓨터의 설정으로 이동하여 마이크 음소거를 해제하고 레벨을 조정하세요.",
|
||||
"micNotSendingDataTitle": "시스템 설정에 의해 마이크가 음소거되었습니다.",
|
||||
"micPermissionDeniedError": "마이크를 사용할 수있는 권한을 부여하지 않았습니다. 회의에 계속 참여할 수는 있지만 다른 사람들은 듣지 않습니다. 검색 주소창의 카메라 버튼을 사용하여 문제를 해결하십시오.",
|
||||
"micUnknownError": "알 수 없는 이유로 마이크를 사용할 수 없습니다",
|
||||
"muteParticipantBody": "당신이 다른 사람들의 음소거를 해제 할 수는 없지만 언제든지 다른 사람들은 스스로 음소거를 해제할 수 있습니다.",
|
||||
"muteParticipantButton": "음소거",
|
||||
"muteParticipantDialog": "",
|
||||
"muteParticipantTitle": "",
|
||||
"muteParticipantTitle": "이 참가자를 음소거 하시겠습니까?",
|
||||
"Ok": "확인",
|
||||
"passwordLabel": "",
|
||||
"passwordNotSupported": "미팅 비밀번호 설정은 지원되지 않습니다",
|
||||
"passwordNotSupportedTitle": "",
|
||||
"passwordRequired": "",
|
||||
"passwordLabel": "잠긴 회의 입니다. 회의에 참여하려면 비밀번호를 입력하세요.",
|
||||
"passwordNotSupported": "회의 비밀번호 설정은 지원되지 않습니다",
|
||||
"passwordNotSupportedTitle": "비밀번호 미지원",
|
||||
"passwordRequired": "비밀번호 필수",
|
||||
"popupError": "브라우저가이 사이트의 팝업 창을 차단하고 있습니다. 브라우저의 보안 설정에서 팝업을 활성화하고 다시 시도하십시오.",
|
||||
"popupErrorTitle": "팝업 차단됨",
|
||||
"recording": "레코딩",
|
||||
"recordingDisabledForGuestTooltip": "",
|
||||
"recordingDisabledTooltip": "",
|
||||
"recordingDisabledForGuestTooltip": "게스트는 녹음을 시작할 수 없습니다.",
|
||||
"recordingDisabledTooltip": "녹화이 비활성화 되었습니다.",
|
||||
"rejoinNow": "지금 재가입",
|
||||
"remoteControlAllowedMessage": "{{user}}이(가) 원격 제어 요청을 수락했습니다",
|
||||
"remoteControlDeniedMessage": "{{user}}이(가) 원격 제어 요청을 거부했습니다",
|
||||
@@ -212,25 +245,30 @@
|
||||
"remoteControlStopMessage": "원격 제어 세션이 종료되었습니다",
|
||||
"remoteControlTitle": "원격 데스크탑 컨트롤",
|
||||
"Remove": "제거",
|
||||
"removePassword": "",
|
||||
"removePassword": "비밀번호 제거",
|
||||
"removeSharedVideoMsg": "공유한 동영상을 삭제하시겠습니까?",
|
||||
"removeSharedVideoTitle": "공유된 동영상 삭제",
|
||||
"reservationError": "예약 시스템 오류",
|
||||
"reservationErrorMsg": "오류 코드: {{code}}, 메시지: {{msg}}",
|
||||
"retry": "재시도",
|
||||
"screenSharingAudio": "오디오 공유",
|
||||
"screenSharingFailedToInstall": "죄송합니다. 화면 공유 확장 프로그램을 설치하지 못했습니다.",
|
||||
"screenSharingFailedToInstallTitle": "화면 공유 확장 프로그램을 설치하지 못했습니다",
|
||||
"screenSharingFirefoxPermissionDeniedError": "화면을 공유하는 동안 문제가 발생했습니다. 그렇게 할 수 있는 권한을 부여했는지 확인하십시오.",
|
||||
"screenSharingFirefoxPermissionDeniedTitle": "죄송합니다. 화면 공유를 시작할 수 없었습니다!",
|
||||
"screenSharingPermissionDeniedError": "죄송합니다. 화면 공유 확장 권한으로 문제가 발생했습니다. 다시 로드하고 재시도하십시오.",
|
||||
"sendPrivateMessage": "최근에 비공개 메시지를 받았습니다. 비공개로 답장을 보내시겠습니까, 아니면 그룹에 메시지를 보내시겠습니까?",
|
||||
"sendPrivateMessageCancel": "그룹에 보내기",
|
||||
"sendPrivateMessageOk": "비공개로 보내기",
|
||||
"sendPrivateMessageTitle": "비공개로 보낼까요?",
|
||||
"serviceUnavailable": "서비스를 사용할 수 없음",
|
||||
"sessTerminated": "통화 종료",
|
||||
"Share": "공유",
|
||||
"shareVideoLinkError": "올바른 YouTube 링크를 제공하십시오",
|
||||
"shareVideoTitle": "비디오 공유",
|
||||
"shareYourScreen": "화면공유",
|
||||
"shareYourScreenDisabled": "",
|
||||
"shareYourScreenDisabledForGuest": "",
|
||||
"shareYourScreenDisabled": "화면 공유가 비활성화 되었습니다.",
|
||||
"shareYourScreenDisabledForGuest": "게스트는 화면을 공유 할 수 없습니다.",
|
||||
"startLiveStreaming": "라이브 스트리밍 시작",
|
||||
"startRecording": "레코딩 시작",
|
||||
"startRemoteControlErrorMessage": "원격 제어 세션을 시작하는 동안 오류가 발생했습니다",
|
||||
@@ -245,17 +283,20 @@
|
||||
"tokenAuthFailed": "죄송합니다. 통화에 참여하실 수 없습니다.",
|
||||
"tokenAuthFailedTitle": "인증 실패",
|
||||
"transcribing": "",
|
||||
"unlockRoom": "",
|
||||
"unlockRoom": "회의 비밀번호 제거",
|
||||
"userPassword": "사용자 비밀번호",
|
||||
"WaitForHostMsg": "",
|
||||
"WaitForHostMsgWOk": "",
|
||||
"WaitForHostMsg": "<b>{{room}}</b> 회의가 시작되지 않았습니다. 호스트 인 경우 인증하십시오. 그렇지 않으면 호스트가 도착할 때까지 기다리십시오.",
|
||||
"WaitForHostMsgWOk": "<b>{{room}}</b> 회의가 아직 시작되지 않았습니다. 호스트 인 경우 확인을 눌러 인증하십시오. 그렇지 않으면 호스트가 도착할 때까지 기다리십시오.",
|
||||
"WaitingForHost": "호스트를 기다리는 중입니다…",
|
||||
"Yes": "",
|
||||
"Yes": "예",
|
||||
"yourEntireScreen": "전체 화면"
|
||||
},
|
||||
"dialOut": {
|
||||
"statusMessage": "지금은 {{status}}입니다"
|
||||
},
|
||||
"documentSharing": {
|
||||
"title": "문서 공유"
|
||||
},
|
||||
"feedback": {
|
||||
"average": "보통",
|
||||
"bad": "나쁨",
|
||||
@@ -266,49 +307,49 @@
|
||||
"veryGood": "매우 좋음"
|
||||
},
|
||||
"incomingCall": {
|
||||
"answer": "",
|
||||
"audioCallTitle": "",
|
||||
"decline": "",
|
||||
"productLabel": "",
|
||||
"videoCallTitle": ""
|
||||
"answer": "응답",
|
||||
"audioCallTitle": "수신 전화",
|
||||
"decline": "거절",
|
||||
"productLabel": "Jitsi Meet에서",
|
||||
"videoCallTitle": "수신 화상 전화"
|
||||
},
|
||||
"info": {
|
||||
"accessibilityLabel": "",
|
||||
"addPassword": "",
|
||||
"cancelPassword": "",
|
||||
"accessibilityLabel": "정보 보기",
|
||||
"addPassword": "$t(lockRoomPassword) 추가",
|
||||
"cancelPassword": "$t(lockRoomPassword) 취소",
|
||||
"conferenceURL": "링크:",
|
||||
"country": "지역",
|
||||
"dialANumber": "",
|
||||
"dialANumber": "회의에 참여하려면이 번호 중 하나를 누른 다음 PIN을 입력하십시오.",
|
||||
"dialInConferenceID": "PIN:",
|
||||
"dialInNotSupported": "죄송합니다. 현재 전화를 걸 수 없습니다.",
|
||||
"dialInNumber": "Dial-in:",
|
||||
"dialInSummaryError": "",
|
||||
"dialInSummaryError": "지금 전화 접속 정보를 가져 오는 중에 오류가 발생했습니다. 나중에 다시 시도하십시오.",
|
||||
"dialInTollFree": "",
|
||||
"genericError": "일반적인 오류가 발생했습니다",
|
||||
"inviteLiveStream": "이 회의의 실시간 스트림을 보려면이 링크를 클릭하십시오: {{url}}",
|
||||
"invitePhone": "",
|
||||
"invitePhoneAlternatives": "",
|
||||
"inviteURLFirstPartGeneral": "",
|
||||
"inviteURLFirstPartPersonal": "",
|
||||
"inviteURLSecondPart": "",
|
||||
"inviteURLFirstPartGeneral": "회의에 초대되었습니다.",
|
||||
"inviteURLFirstPartPersonal": "{{name}}이 회의에 초대하였습니다.\n",
|
||||
"inviteURLSecondPart": "\n회의에 참여하기:\n{{url}}\n",
|
||||
"liveStreamURL": "실시간 스트리밍:",
|
||||
"moreNumbers": "더 많은 번호",
|
||||
"noNumbers": "전화 접속 번호 없음",
|
||||
"noPassword": "없음",
|
||||
"noRoom": "전화 접속이 가능한 방을 지정하지 않았습니다",
|
||||
"numbers": "전화 접속 번호",
|
||||
"password": "",
|
||||
"password": "비밀번호",
|
||||
"title": "공유",
|
||||
"tooltip": "링크 공유 및 회의에 대한 정보",
|
||||
"label": ""
|
||||
"label": "회의 정보"
|
||||
},
|
||||
"inviteDialog": {
|
||||
"alertText": "",
|
||||
"alertText": "일부 참가자를 초대하지 못했습니다.",
|
||||
"header": "초대",
|
||||
"searchCallOnlyPlaceholder": "",
|
||||
"searchPeopleOnlyPlaceholder": "",
|
||||
"searchPlaceholder": "",
|
||||
"send": ""
|
||||
"searchCallOnlyPlaceholder": "전화 번호 입력",
|
||||
"searchPeopleOnlyPlaceholder": "참가자 검색",
|
||||
"searchPlaceholder": "참가자 또는 전화 번호",
|
||||
"send": "전송"
|
||||
},
|
||||
"inlineDialogFailure": {
|
||||
"msg": "약간의 문제가 있습니다",
|
||||
@@ -321,7 +362,7 @@
|
||||
"focusRemote": "다른 발신자의 동영상에 포커스",
|
||||
"fullScreen": "전체화면 표시 또는 종료",
|
||||
"keyboardShortcuts": "키보드 단축키",
|
||||
"localRecording": "",
|
||||
"localRecording": "로컬 녹음 컨트롤 표시 또는 숨기기",
|
||||
"mute": "마이크 음소거 또는 음소거 해제",
|
||||
"pushToTalk": "대화 요청",
|
||||
"raiseHand": "말하기 요청/해제",
|
||||
@@ -341,24 +382,26 @@
|
||||
"enterStreamKey": "YouTube 실시간 스트리밍 키를 입력하십시오",
|
||||
"error": "실시간 스트리밍에 실패했습니다. 다시 시도하십시오.",
|
||||
"errorAPI": "YouTube 방송에 액세스하는 중에 오류가 발생했습니다. 다시 로그인하십시오.",
|
||||
"errorLiveStreamNotEnabled": "",
|
||||
"expandedOff": "",
|
||||
"expandedOn": "",
|
||||
"expandedPending": "",
|
||||
"errorLiveStreamNotEnabled": "{{email}}에 의해 라이브 스트리밍이 활성화되지 않았습니다. 라이브 스트리밍을 활성화하거나 라이브 스트리밍이 활성화 된 계정으로 로그인하십시오.",
|
||||
"expandedOff": "라이브 스트리밍이 중지되었습니다",
|
||||
"expandedOn": "현재 회의가 YouTube로 스트리밍되고 있습니다.",
|
||||
"expandedPending": "라이브 스트리밍이 시작됩니다 ...",
|
||||
"failedToStart": "실시간 스트리밍 시작 실패",
|
||||
"getStreamKeyManually": "",
|
||||
"invalidStreamKey": "",
|
||||
"getStreamKeyManually": "실시간 스트림을 가져올 수 없습니다. YouTube에서 실시간 스트림 키를 받아보세요.",
|
||||
"invalidStreamKey": "라이브 스트림 키가 잘못되었을 수 있습니다.",
|
||||
"off": "실시간 스트리밍이 중지됨",
|
||||
"on": "실시간 스트리밍",
|
||||
"pending": "실시간 스트리밍 시작…",
|
||||
"serviceName": "실시간 스트리밍 서비스",
|
||||
"signedInAs": "",
|
||||
"signedInAs": "현재 다음 계정으로 로그인되어 있습니다.",
|
||||
"signIn": "Google로 로그인",
|
||||
"signInCTA": "YouTube에서 로그인하거나 실시간 스트리밍 키를 입력하십시오",
|
||||
"signOut": "",
|
||||
"signOut": "로그아웃",
|
||||
"start": "실시간 스트리밍 시작",
|
||||
"streamIdHelp": "도움말?",
|
||||
"unavailableTitle": "실시간 스트리밍을 사용할 수 없음"
|
||||
"unavailableTitle": "실시간 스트리밍을 사용할 수 없음",
|
||||
"youtubeTerms": "YouTube 서비스 약관",
|
||||
"googlePrivacyPolicy": "Google 개인 정보 보호 정책"
|
||||
},
|
||||
"localRecording": {
|
||||
"clientState": {
|
||||
@@ -381,50 +424,50 @@
|
||||
"notModerator": ""
|
||||
},
|
||||
"moderator": "",
|
||||
"no": "",
|
||||
"no": "아니요",
|
||||
"participant": "",
|
||||
"participantStats": "",
|
||||
"sessionToken": "",
|
||||
"start": "레코딩 시작",
|
||||
"stop": "레코딩 종료",
|
||||
"yes": ""
|
||||
"yes": "예"
|
||||
},
|
||||
"lockRoomPassword": "패스워드",
|
||||
"lockRoomPasswordUppercase": "패스워드",
|
||||
"me": "Me",
|
||||
"lockRoomPassword": "비밀번호",
|
||||
"lockRoomPasswordUppercase": "비밀번호",
|
||||
"me": "나",
|
||||
"notify": {
|
||||
"connectedOneMember": "",
|
||||
"connectedThreePlusMembers": "",
|
||||
"connectedTwoMembers": "",
|
||||
"connectedOneMember": "{{name}}님이 회의에 참여했습니다.",
|
||||
"connectedThreePlusMembers": "{{name}}님 외 {{count}}명이 회의에 참여했습니다.",
|
||||
"connectedTwoMembers": "{{first}}님과 {{second}}님이 회의에 참여했습니다.",
|
||||
"disconnected": "연결이 끊김",
|
||||
"focus": "컨퍼런스 포커스",
|
||||
"focusFail": "{{component}}을 사용할 수 없음 - {{ms}} 초 후에 다시 시도하십시오",
|
||||
"grantedTo": "{{to}}에게 방장 권한이 부여되었습니다!",
|
||||
"invitedOneMember": "",
|
||||
"invitedThreePlusMembers": "",
|
||||
"invitedTwoMembers": "",
|
||||
"kickParticipant": "",
|
||||
"me": "",
|
||||
"invitedOneMember": "{{name}}님이 초대되었습니다.",
|
||||
"invitedThreePlusMembers": "{{name}}님 외 {{count}}명이 초대되었습니다.",
|
||||
"invitedTwoMembers": "{{first}}님과 {{second}}님이 초대되었습니다.",
|
||||
"kickParticipant": "{{kicker}}님이 {{kicked}}님을 추방했습니다.",
|
||||
"me": "나",
|
||||
"moderator": "방장 권한이 부여되었습니다!",
|
||||
"muted": "음소거로 대화가 시작되었습니다",
|
||||
"mutedTitle": "음소거 상태입니다!",
|
||||
"mutedRemotelyTitle": "",
|
||||
"mutedRemotelyDescription": "",
|
||||
"passwordRemovedRemotely": "",
|
||||
"passwordSetRemotely": "",
|
||||
"raisedHand": "",
|
||||
"mutedRemotelyTitle": "{{participantDisplayName}}에 의해 음소거되었습니다!",
|
||||
"mutedRemotelyDescription": "말할 준비가되면 언제든지 음소거를 해제 할 수 있습니다.",
|
||||
"passwordRemovedRemotely": "다른 참가자가 $t(lockRoomPasswordUppercase)를 제거했습니다.",
|
||||
"passwordSetRemotely": "다른 참가자가 $t(lockRoomPasswordUppercase)를 설정했습니다.",
|
||||
"raisedHand": "{{name}}님이 말하고 싶어합니다.",
|
||||
"somebody": "누군가",
|
||||
"startSilentTitle": "",
|
||||
"startSilentDescription": "",
|
||||
"startSilentTitle": "오디오 출력없이 참여했습니다!",
|
||||
"startSilentDescription": "오디오를 사용하려면 회의에 다시 참여하세요.",
|
||||
"suboptimalExperienceDescription": "{{appName}}에 대한 귀하의 경험이 없으시다면 <a href='{{recommendedBrowserPageLink}}' target='_blank'>완벽하게 지원되는 브라우저</a> 중 하나를 사용해보십시오.",
|
||||
"suboptimalExperienceTitle": "브라우저 경고",
|
||||
"unmute": "",
|
||||
"newDeviceCameraTitle": "",
|
||||
"newDeviceAudioTitle": "",
|
||||
"newDeviceAction": ""
|
||||
"unmute": "음소거 해제",
|
||||
"newDeviceCameraTitle": "새 카메라 감지",
|
||||
"newDeviceAudioTitle": "새 오디오 장치 감지",
|
||||
"newDeviceAction": "사용"
|
||||
},
|
||||
"passwordSetRemotely": "",
|
||||
"passwordDigitsOnly": "",
|
||||
"passwordSetRemotely": "다른 참가자가 설정",
|
||||
"passwordDigitsOnly": "최대 {{number}} 자리",
|
||||
"poweredby": "powered by",
|
||||
"presenceStatus": {
|
||||
"busy": "바쁨",
|
||||
@@ -447,27 +490,27 @@
|
||||
"title": "프로필"
|
||||
},
|
||||
"recording": {
|
||||
"authDropboxText": "",
|
||||
"availableSpace": "",
|
||||
"authDropboxText": "Dropbox에 업로드",
|
||||
"availableSpace": "사용 가능한 공간 : {{spaceLeft}}MB (약 {{duration}}분 녹화)",
|
||||
"beta": "베타",
|
||||
"busy": "레코딩 자원을 확보하고 있습니다. 몇 분 후에 다시 시도하십시오.",
|
||||
"busyTitle": "모든 레코더가 현재 사용 중입니다",
|
||||
"error": "레코딩이 실패했습니다. 다시 시도하십시오.",
|
||||
"expandedOff": "레코딩이 중지됨",
|
||||
"expandedOn": "",
|
||||
"expandedPending": "",
|
||||
"expandedOn": "회의가 현재 녹화 중입니다.",
|
||||
"expandedPending": "녹화가 시작됩니다 ...",
|
||||
"failedToStart": "레코딩을 시작하지 못했습니다",
|
||||
"fileSharingdescription": "",
|
||||
"fileSharingdescription": "회의 참가자와 녹음 공유",
|
||||
"live": "라이브",
|
||||
"loggedIn": "",
|
||||
"loggedIn": "{{userName}}으로 로그인했습니다.",
|
||||
"off": "레코딩이 중지됨",
|
||||
"on": "레코딩",
|
||||
"pending": "참석할 멤버를 기다리는 중입니다…",
|
||||
"rec": "REC",
|
||||
"serviceDescription": "",
|
||||
"rec": "녹음",
|
||||
"serviceDescription": "녹음은 녹음 서비스에 의해 저장됩니다.",
|
||||
"serviceName": "레코딩 서비스",
|
||||
"signIn": "",
|
||||
"signOut": "",
|
||||
"signIn": "로그인",
|
||||
"signOut": "로그아웃",
|
||||
"unavailable": "죄송합니다. {{serviceName}}은 현재 사용할 수 없습니다. 저희는 문제를 해결하기 위해 노력하고 있습니다. 나중에 다시 시도 해주십시오.",
|
||||
"unavailableTitle": "레코딩을 사용할 수 없습니다"
|
||||
},
|
||||
@@ -476,18 +519,18 @@
|
||||
},
|
||||
"settings": {
|
||||
"calendar": {
|
||||
"about": "",
|
||||
"about": "{{appName}} 캘린더 통합은 예정된 일정을 읽을 수 있도록 캘린더에 안전하게 액세스하는 데 사용됩니다.",
|
||||
"disconnect": "연결 끊김",
|
||||
"microsoftSignIn": "",
|
||||
"signedIn": "",
|
||||
"title": ""
|
||||
"microsoftSignIn": "Microsoft로 로그인",
|
||||
"signedIn": "현재 {{email}}의 캘린더 일정에 액세스하고 있습니다. 캘린더 이벤트 액세스를 중지하려면 아래 연결 해제 버튼을 클릭하세요.",
|
||||
"title": "캘린더"
|
||||
},
|
||||
"devices": "",
|
||||
"devices": "장치",
|
||||
"followMe": "모두 나와 같은 설정 상태로",
|
||||
"language": "",
|
||||
"loggedIn": "",
|
||||
"moderator": "",
|
||||
"more": "",
|
||||
"language": "언어",
|
||||
"loggedIn": "{{name}}으로 로그인",
|
||||
"moderator": "마이크",
|
||||
"more": "더보기",
|
||||
"name": "이름",
|
||||
"noDevice": "없음",
|
||||
"selectAudioOutput": "오디오 출력",
|
||||
@@ -495,26 +538,28 @@
|
||||
"selectMic": "오디오",
|
||||
"startAudioMuted": "모두가 음소거를 시작합니다",
|
||||
"startVideoMuted": "모두가 비디오 비활성화로 시작합니다",
|
||||
"title": "세티"
|
||||
"title": "설정"
|
||||
},
|
||||
"settingsView": {
|
||||
"advanced": "고급",
|
||||
"alertOk": "확인",
|
||||
"alertCancel": "취소",
|
||||
"alertTitle": "경고",
|
||||
"alertURLText": "입력된 서버 URL이 잘못되었습니다",
|
||||
"buildInfoSection": "",
|
||||
"buildInfoSection": "빌드 정보",
|
||||
"conferenceSection": "회의",
|
||||
"displayName": "유저이름",
|
||||
"email": "이메일",
|
||||
"header": "세티",
|
||||
"header": "설정",
|
||||
"profileSection": "프로필",
|
||||
"serverURL": "서버 URL",
|
||||
"startWithAudioMuted": "오디오 음소거 상태로 시작",
|
||||
"startWithVideoMuted": "비디오 비활성화 상태로 시작",
|
||||
"version": ""
|
||||
"version": "버전"
|
||||
},
|
||||
"share": {
|
||||
"dialInfoText": "",
|
||||
"mainText": ""
|
||||
"mainText": "회의에 참여하려면 다음 링크를 클릭하십시오.\n{{roomUrl}}"
|
||||
},
|
||||
"speaker": "스피커",
|
||||
"speakerStats": {
|
||||
@@ -561,11 +606,11 @@
|
||||
"sharedvideo": "",
|
||||
"shareRoom": "",
|
||||
"shareYourScreen": "",
|
||||
"shortcuts": "단축키 토그",
|
||||
"shortcuts": "단축키 전환",
|
||||
"show": "",
|
||||
"speakerStats": "",
|
||||
"tileView": "",
|
||||
"toggleCamera": "카메라 토ㄱ",
|
||||
"toggleCamera": "카메라 전환",
|
||||
"videomute": "",
|
||||
"videoblur": ""
|
||||
},
|
||||
@@ -575,54 +620,58 @@
|
||||
"audioRoute": "음성 장비 선택하기",
|
||||
"authenticate": "인증 중",
|
||||
"callQuality": "품질 설정하기",
|
||||
"chat": "",
|
||||
"closeChat": "",
|
||||
"documentClose": "",
|
||||
"documentOpen": "",
|
||||
"chat": "대화 열기/닫기",
|
||||
"closeChat": "대화 닫기",
|
||||
"documentClose": "문서 공유 닫기",
|
||||
"documentOpen": "문서 공유 열기",
|
||||
"download": "앱 다운로드",
|
||||
"enterFullScreen": "전체화면 보기",
|
||||
"enterTileView": "",
|
||||
"enterTileView": "타일보기 시작",
|
||||
"exitFullScreen": "전체화면 취소",
|
||||
"exitTileView": "",
|
||||
"exitTileView": "타일보기 종료",
|
||||
"feedback": "피드백 남기기",
|
||||
"hangup": "",
|
||||
"invite": "",
|
||||
"login": "",
|
||||
"hangup": "떠나기",
|
||||
"invite": "초대",
|
||||
"login": "로그인",
|
||||
"logout": "로그아웃",
|
||||
"lowerYourHand": "",
|
||||
"lowerYourHand": "손을 내려주세요",
|
||||
"moreActions": "추가 액션",
|
||||
"mute": "마이크",
|
||||
"openChat": "",
|
||||
"moreOptions": "옵션 더보기",
|
||||
"mute": "음소거 설정/해제",
|
||||
"muteEveryone": "모두 음소거",
|
||||
"openChat": "대화 열기",
|
||||
"pip": "",
|
||||
"profile": "",
|
||||
"privateMessage": "비공개 메시지 보내기",
|
||||
"profile": "프로필 수정",
|
||||
"raiseHand": "말하기 요청/해제",
|
||||
"raiseYourHand": "",
|
||||
"Settings": "세티",
|
||||
"sharedvideo": "",
|
||||
"shareRoom": "",
|
||||
"shortcuts": "",
|
||||
"raiseYourHand": "손 들어주세요",
|
||||
"Settings": "설정",
|
||||
"sharedvideo": "YouTube 비디오 공유",
|
||||
"shareRoom": "초대하기",
|
||||
"shortcuts": "단축키보기",
|
||||
"speakerStats": "접속자 통계",
|
||||
"startScreenSharing": "",
|
||||
"startSubtitles": "",
|
||||
"stopScreenSharing": "",
|
||||
"stopSubtitles": "",
|
||||
"stopSharedVideo": "",
|
||||
"talkWhileMutedPopup": "",
|
||||
"tileViewToggle": "",
|
||||
"toggleCamera": "카메라 토ㄱ",
|
||||
"videomute": "",
|
||||
"startvideoblur": "",
|
||||
"stopvideoblur": ""
|
||||
"startScreenSharing": "화면 공유 시작",
|
||||
"startSubtitles": "자막 시작",
|
||||
"stopScreenSharing": "화면 공유 중지",
|
||||
"stopSubtitles": "자막 중지",
|
||||
"stopSharedVideo": "UouTube 비디오 공유 중지",
|
||||
"talkWhileMutedPopup": "음소거 상태입니다.",
|
||||
"tileViewToggle": "타일뷰 전환",
|
||||
"toggleCamera": "카메라 전환",
|
||||
"videomute": "카메라 시작/중지",
|
||||
"startvideoblur": "내 배경을 흐리게",
|
||||
"stopvideoblur": "배경 흐림 비활성화"
|
||||
},
|
||||
"transcribing": {
|
||||
"ccButtonTooltip": "",
|
||||
"ccButtonTooltip": "자막 시작/종료",
|
||||
"error": "레코딩이 실패했습니다. 다시 시도하십시오.",
|
||||
"expandedLabel": "",
|
||||
"failedToStart": "",
|
||||
"labelToolTip": "",
|
||||
"off": "",
|
||||
"expandedLabel": "현재 스크립트 작성 중",
|
||||
"failedToStart": "스크립트 작성을 시작하지 못했습니다.",
|
||||
"labelToolTip": "회의가 기록되고 있습니다.",
|
||||
"off": "스크립트 작성이 중지되었습니다.",
|
||||
"pending": "참석할 멤버를 기다리는 중입니다…",
|
||||
"start": "",
|
||||
"stop": "",
|
||||
"start": "자막 표시 시작",
|
||||
"stop": "자막 표시 중지",
|
||||
"tr": ""
|
||||
},
|
||||
"userMedia": {
|
||||
@@ -649,8 +698,8 @@
|
||||
},
|
||||
"videoStatus": {
|
||||
"audioOnly": "오디오 전용",
|
||||
"audioOnlyExpanded": "",
|
||||
"callQuality": "",
|
||||
"audioOnlyExpanded": "낮은 대역폭 모드에 있습니다. 이 모드에서는 오디오 및 화면 공유 만 수신합니다.",
|
||||
"callQuality": "비디오 품질",
|
||||
"hd": "HD",
|
||||
"highDefinition": "고해상도",
|
||||
"labelTooiltipNoVideo": "비디오 없음",
|
||||
@@ -666,12 +715,12 @@
|
||||
"domute": "음소거",
|
||||
"flip": "플립",
|
||||
"kick": "내보내기",
|
||||
"moderator": "",
|
||||
"mute": "",
|
||||
"moderator": "중재자",
|
||||
"mute": "참가자 음소거",
|
||||
"muted": "음소거됨",
|
||||
"remoteControl": "원격 제어",
|
||||
"show": "",
|
||||
"videomute": ""
|
||||
"show": "화면에 표시",
|
||||
"videomute": "참가자가 카메라를 중지했습니다."
|
||||
},
|
||||
"welcomepage": {
|
||||
"accessibilityLabel": {
|
||||
@@ -683,22 +732,33 @@
|
||||
"audio": "음성",
|
||||
"video": "비디오"
|
||||
},
|
||||
"calendar": "",
|
||||
"connectCalendarButton": "",
|
||||
"connectCalendarText": "",
|
||||
"enterRoomTitle": "",
|
||||
"calendar": "캘린더",
|
||||
"connectCalendarButton": "캘린더를 연결하세요",
|
||||
"connectCalendarText": "{{app}}에서 모든 회의를 보려면 캘린더를 연결하세요. 또한 캘린더에 {{provider}} 회의를 추가하고 클릭 한 번으로 시작하세요.",
|
||||
"enterRoomTitle": "새 회의 시작",
|
||||
"getHelp": "도움 받기",
|
||||
"roomNameAllowedChars": "회의 이름은 이러한 문자를 포함 할 수 없습니다.: ?, &, :, ', \", %, #.",
|
||||
"go": "계속",
|
||||
"goSmall": "계속",
|
||||
"join": "가입",
|
||||
"info": "",
|
||||
"info": "정보",
|
||||
"privacy": "개인정보",
|
||||
"recentList": "",
|
||||
"recentListDelete": "",
|
||||
"recentListEmpty": "",
|
||||
"reducedUIText": "",
|
||||
"recentList": "최근",
|
||||
"recentListDelete": "삭제",
|
||||
"recentListEmpty": "최근 목록이 현재 비어 있습니다. 팀과 채팅하면 여기에서 최근 회의를 모두 찾을 수 있습니다.",
|
||||
"reducedUIText": "{{app}}에 오신 것을 환영합니다!",
|
||||
"roomname": "방 이름 입력",
|
||||
"roomnameHint": "",
|
||||
"sendFeedback": "",
|
||||
"roomnameHint": "참여하려는 방의 이름 또는 URL을 입력하십시오. 이름을 정하고 만나는 사람들에게 같은 이름을 입력하도록 알리면됩니다.",
|
||||
"sendFeedback": "피드백 보내기",
|
||||
"terms": "이용약관",
|
||||
"title": ""
|
||||
"title": "안전하고 모든 기능을 갖춘 완전 무료 화상 회의"
|
||||
},
|
||||
"lonelyMeetingExperience": {
|
||||
"button": "초대하기",
|
||||
"youAreAlone": "회의에 참여자가 없습니다."
|
||||
},
|
||||
"helpView": {
|
||||
"header": "지원 센터"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
"kickParticipantButton": "Verwijderen",
|
||||
"kickParticipantDialog": "Weet u zeker dat u deze deelnemer wilt verwijderen?",
|
||||
"kickParticipantTitle": "Deze deelnemer verwijderen?",
|
||||
"kickTitle": "Oei! {{ParticipantDisplayName}} heeft u uit de vergadering verwijderd",
|
||||
"kickTitle": "Oei! {{participantDisplayName}} heeft u uit de vergadering verwijderd",
|
||||
"liveStreaming": "Livestreamen",
|
||||
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "Niet mogelijk tijdens opnemen",
|
||||
"liveStreamingDisabledForGuestTooltip": "Gasten kunnen geen livestream starten.",
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -1,62 +1,77 @@
|
||||
{
|
||||
"addPeople": {
|
||||
"add": "Pozvať",
|
||||
"addContacts": "Pozvať kontakty",
|
||||
"copyInvite": "Skopírovať pozvánku",
|
||||
"copyLink": "Skopírovať odkaz na konferenciu",
|
||||
"copyStream": "Skopírovať odkaz na živé vysielanie",
|
||||
"countryNotSupported": "Zatiaľ nepodporujeme túto krajinu.",
|
||||
"countryReminder": "Medzinárodný hovor? Prosím skontrolujte, či telefónne číslo začína smerovým číslo krajiny.",
|
||||
"disabled": "Nemôžete pozvať ďalších účastníkov.",
|
||||
"defaultEmail": "Predvolený email",
|
||||
"disabled": "Nemôžete pozvať ďalších ľudí.",
|
||||
"failedToAdd": "Nepodarilo sa pridať účastníka.",
|
||||
"footerText": "Odchádzajúce hovory sú zablokované.",
|
||||
"loading": "Hľadanie účastníkov a telefónnych čísiel",
|
||||
"googleEmail": "Google email",
|
||||
"inviteMoreHeader": "Ste sám v tejto konferencii",
|
||||
"inviteMoreMailSubject": "Pozvánka do konferencie {{appName}}",
|
||||
"inviteMorePrompt": "Pozvať ľudí",
|
||||
"linkCopied": "Odkaz skopírovaný do schránky",
|
||||
"loading": "Hľadanie ľudí a telefónnych čísiel",
|
||||
"loadingNumber": "Kontrola telefónneho čísla",
|
||||
"loadingPeople": "Hľadanie účastníkov na pozvanie",
|
||||
"loadingPeople": "Hľadanie ľudí na pozvanie",
|
||||
"noResults": "Žiadne výsledky hľadania",
|
||||
"noValidNumbers": "Prosím zadajte telefónne číslo",
|
||||
"outlookEmail": "Outlook email",
|
||||
"searchNumbers": "Zadajte telefónne čísla",
|
||||
"searchPeople": "Hľadanie účastníkov",
|
||||
"searchPeopleAndNumbers": "Hľadanie účastníkov alebo pridávanie telefónny čísel",
|
||||
"searchPeople": "Hľadanie ľudí",
|
||||
"searchPeopleAndNumbers": "Hľadať ľudí alebo pridať ich telefónne čísla",
|
||||
"shareInvite": "Zdieľať pozvánku do konferencie",
|
||||
"shareLink": "Zdieľať odkaz na pozvanie",
|
||||
"shareStream": "Zdieľať odkaz na živé vysielanie",
|
||||
"telephone": "Telefón: {{number}}",
|
||||
"title": "Pozvať účastníkov do tejto konferencie"
|
||||
"title": "Pozvať ľudí do tejto konferencie",
|
||||
"yahooEmail": "Yahoo email"
|
||||
},
|
||||
"audioDevices": {
|
||||
"bluetooth": "Bluetooth",
|
||||
"headphones": "Sluchátka",
|
||||
"headphones": "Slúchadlá",
|
||||
"phone": "Telefón",
|
||||
"speaker": "Rečník",
|
||||
"speaker": "Reproduktor",
|
||||
"none": "Žiadne zvukové zariadenia"
|
||||
},
|
||||
"audioOnly": {
|
||||
"audioOnly": "Iba zvuk"
|
||||
},
|
||||
"calendarSync": {
|
||||
"addMeetingURL": "Pridať odkaz na stretnutie",
|
||||
"addMeetingURL": "Pridať odkaz na konferenciu",
|
||||
"confirmAddLink": "Chcete pridal Jitsi odkaz do tejto udalosti?",
|
||||
"error": {
|
||||
"appConfiguration": "Integrácia s kalendárom nie je správne nastavená.",
|
||||
"generic": "Stala sa chyba. Skontrolujte si nastavenia kalendáru a skúste aktualizovať kalendár. ",
|
||||
"notSignedIn": "Stala sa chyba počas autentifikácie pre zobrazovanie kaledárových udalosti. Skontrolujte si nastavenia kalendáru a skúste sa znovu prihlásiť."
|
||||
"generic": "Stala sa chyba. Skontrolujte nastavenia kalendára a skúste obnoviť kalendár.",
|
||||
"notSignedIn": "Stala sa chyba počas autentifikácie pre zobrazenie kaledárových udalosti. Skontrolujte nastavenia kalendára a skúste sa znovu prihlásiť."
|
||||
},
|
||||
"join": "Zúčastniť sa",
|
||||
"joinTooltip": "Zúčastniť sa stretnutia",
|
||||
"nextMeeting": "nasledujúce stretnutie",
|
||||
"noEvents": "Niesú naplánované žiadne ďalšie udalosti.",
|
||||
"ongoingMeeting": "prebiehajúce stretnutie",
|
||||
"joinTooltip": "Zúčastniť sa konferencie",
|
||||
"nextMeeting": "nasledujúca konferencia",
|
||||
"noEvents": "Nie sú naplánované žiadne ďalšie udalosti.",
|
||||
"ongoingMeeting": "prebiehajúca konferencia",
|
||||
"permissionButton": "Otvoriť nastavenia",
|
||||
"permissionMessage": "Aplikácia potrebuje kalendárové oprávnenie pre zobranie termínov a stretnutí ",
|
||||
"refresh": "Aktualizovať kalendár",
|
||||
"permissionMessage": "Aplikácia potrebuje kalendárové oprávnenie pre zobranie termínov a stretnutí.",
|
||||
"refresh": "Obnoviť kalendár",
|
||||
"today": "Dnes"
|
||||
},
|
||||
"chat": {
|
||||
"error": "Chyba: vaša správa \"{{originalText}}\" nebola poslaná. Dôvod: {{error}}",
|
||||
"fieldPlaceHolder": "Zadajte sem vašu správu",
|
||||
"messagebox": "Napíšte správu",
|
||||
"messageTo": "Správa pre {{recipient}}",
|
||||
"noMessagesMessage": "V tejto konferencií ešte nie je žiadna správa. Začnite tu vašu diskusiu!",
|
||||
"messageTo": "Súkromná správa pre {{recipient}}",
|
||||
"noMessagesMessage": "V tejto konferencii ešte nie je žiadna správa. Začnite tu vašu diskusiu!",
|
||||
"nickname": {
|
||||
"popover": "Zvoľte meno",
|
||||
"title": "Zadajte sem vašu prezývku"
|
||||
"title": "Zadajte vašu prezývku"
|
||||
},
|
||||
"privateNotice": "Súkromná správa pre {{recipient}}",
|
||||
"title": "Písanie",
|
||||
"title": "Chat",
|
||||
"you": "Vy"
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
@@ -65,54 +80,54 @@
|
||||
"dontShowAgain": "Upozornenie viac nezobrazovať"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
"joiningRoom": "Vytvára sa spojenie do vašej konferencie…"
|
||||
"joiningRoom": "Pripájanie do konferencie..."
|
||||
},
|
||||
"connection": {
|
||||
"ATTACHED": "Priložený",
|
||||
"AUTHENTICATING": "Overujem",
|
||||
"AUTHENTICATING": "Overovanie",
|
||||
"AUTHFAIL": "Overenie zlyhalo",
|
||||
"CONNECTED": "Pripojený",
|
||||
"CONNECTING": "Pripájam",
|
||||
"CONNECTING": "Pripájanie",
|
||||
"CONNFAIL": "Spojenie zlyhalo",
|
||||
"DISCONNECTED": "Odpojený",
|
||||
"DISCONNECTING": "Odpájam",
|
||||
"DISCONNECTING": "Odpájanie",
|
||||
"ERROR": "Chyba",
|
||||
"RECONNECTING": "Chyba siete. Skúšam sa znova pripojiť ...",
|
||||
"FETCH_SESSION_ID": "Získavanie session-id...",
|
||||
"GET_SESSION_ID_ERROR": "Chyba pri získavaní session-id: {{code}}",
|
||||
"GOT_SESSION_ID": "Získavanie session-id... Hotovo",
|
||||
"LOW_BANDWIDTH": "Video pre {{displayName}} bolo vypnuté, aby sa ušetrila prenosová kapacita"
|
||||
},
|
||||
"connectionindicator": {
|
||||
"address": "Adresa:",
|
||||
"bandwidth": "Predpokladaný dat. tok:",
|
||||
"bitrate": "Prenos. rýchlosť",
|
||||
"bridgeCount": "Počet serverov:",
|
||||
"bandwidth": "Dátový tok:",
|
||||
"bitrate": "Prenos. rýchlosť:",
|
||||
"bridgeCount": "Počet serverov: ",
|
||||
"connectedTo": "Spojenie s:",
|
||||
"e2e_rtt": "E2E RTT:",
|
||||
"framerate": "Rýchlosť snímkovania:",
|
||||
"less": "Zobraz menej",
|
||||
"localaddress_0": "Lokálna adresa:",
|
||||
"localaddress_1": "Lokálne adresy:",
|
||||
"localaddress_2": "",
|
||||
"localport_0": "Lokálny port:",
|
||||
"localport_1": "Lokálne porty:",
|
||||
"localport_2": "",
|
||||
"more": "Zobraz viac",
|
||||
"packetloss": "Strata packetov:",
|
||||
"less": "Zobraziť menej",
|
||||
"localaddress": "Lokálna adresa:",
|
||||
"localaddress_plural": "Lokálne adresy:",
|
||||
"localport": "Lokálny port:",
|
||||
"localport_plural": "Lokálne porty:",
|
||||
"maxEnabledResolution": "send max",
|
||||
"more": "Zobraziť viac",
|
||||
"packetloss": "Strata paketov:",
|
||||
"quality": {
|
||||
"good": "Dobré",
|
||||
"inactive": "Neaktívne",
|
||||
"lost": "Stratené",
|
||||
"nonoptimal": "Nie je optimálne",
|
||||
"nonoptimal": "Neoptimálne",
|
||||
"poor": "Slabé"
|
||||
},
|
||||
"remoteaddress_0": "Vzdialená adresa:",
|
||||
"remoteaddress_1": "Vzdialené adresy:",
|
||||
"remoteaddress_2": "",
|
||||
"remoteport_0": "Vzdialený port:",
|
||||
"remoteport_1": "Vzdialené porty:",
|
||||
"remoteport_2": "",
|
||||
"remoteaddress": "Vzdialená adresa:",
|
||||
"remoteaddress_plural": "Vzdialené adresy:",
|
||||
"remoteport": "Vzdialený port:",
|
||||
"remoteport_plural": "Vzdialené porty:",
|
||||
"resolution": "Rozlíšenie:",
|
||||
"status": "Spojenie:",
|
||||
"transport": "Prenos:"
|
||||
"transport": "Prenos:",
|
||||
"transport_plural": "Prenosy:"
|
||||
},
|
||||
"dateUtils": {
|
||||
"earlier": "Skôr",
|
||||
@@ -121,16 +136,18 @@
|
||||
},
|
||||
"deepLinking": {
|
||||
"appNotInstalled": "Potrebujete aplikáciu {{app}}, aby ste sa mohli pripojiť do tejto konferencie na vašom telefóne.",
|
||||
"description": "Nič sa nestalo? Snažili sme sa otvoriť konferenciu v {{app}}. Skúste to znovu, alebo sa pripojte na konferenciu v {{app}} cez Web.",
|
||||
"descriptionWithoutWeb": "Nič sa nestalo? Snažili sme sa spustiť váš rozhovor v desktopovej aplikácií {{app}}.",
|
||||
"description": "Nič sa nestalo? Snažili sme sa otvoriť konferenciu v {{app}}. Skúste to znovu, alebo sa pripojte na konferenciu v {{app}} cez web.",
|
||||
"descriptionWithoutWeb": "Nič sa nestalo? Snažili sme sa spustiť konferenciu v desktopovej aplikácií {{app}}.",
|
||||
"downloadApp": "Stiahnutie aplikácie",
|
||||
"ifDoNotHaveApp": "Ak nemáte aplikáciu:",
|
||||
"ifHaveApp": "Ak máte aplikáciu:",
|
||||
"joinInApp": "Vstúpiť do konferencie cez aplikáciu",
|
||||
"launchWebButton": "Otvoriť na webe",
|
||||
"openApp": "Pokračovať na aplikáciu",
|
||||
"title": "Konferencia sa otvára v {{app}}...",
|
||||
"tryAgainButton": "Skúsiť znova s natívnou aplikáciou"
|
||||
},
|
||||
"defaultLink": "napr. {{url}}",
|
||||
"defaultNickname": "napr. Jane Pink",
|
||||
"defaultNickname": "napr. Ján Kováč",
|
||||
"deviceError": {
|
||||
"cameraError": "Chyba pri prístupe ku kamere",
|
||||
"cameraPermission": "Aplikácia nemá oprávnenie pristupovať ku kamere",
|
||||
@@ -140,79 +157,84 @@
|
||||
"deviceSelection": {
|
||||
"noPermission": "Oprávnenie nie je poskytnuté",
|
||||
"previewUnavailable": "Náhľad nie je dostupný",
|
||||
"selectADevice": "Vyberte zvukové zariadenie",
|
||||
"selectADevice": "Vybrať zariadenie",
|
||||
"testAudio": "Vyskúšať zvuk"
|
||||
},
|
||||
"dialog": {
|
||||
"accessibilityLabel": {
|
||||
"liveStreaming": "Živé vysielanie"
|
||||
},
|
||||
"add": "Pridať",
|
||||
"allow": "Povoliť",
|
||||
"alreadySharedVideoMsg": "Iný účastník už poskytuje video. Pri tejto konferencií môže poskytovať súčasne iba jeden účastník.",
|
||||
"alreadySharedVideoTitle": "Naraz sa dá poskytovať iba jedno video",
|
||||
"alreadySharedVideoMsg": "Iný účastník už zdieľa video. Pri tejto konferencií môže zdieľať video iba jeden účastník.",
|
||||
"alreadySharedVideoTitle": "Je možné zdieľať iba jedno video",
|
||||
"applicationWindow": "Okno aplikácie",
|
||||
"Back": "Späť",
|
||||
"cameraConstraintFailedError": "Vaša kamera nespĺňa potrebné požiadavky.",
|
||||
"cameraNotFoundError": "Kamera nebola nájdená.",
|
||||
"cameraNotSendingData": "Kamera nie je dostupná. Skontrolujte či iná aplikácia používa kameru, vyberte inú kameru v nastaveniach ale znovu spustite aplikáciu.",
|
||||
"cameraNotSendingData": "Kamera nie je dostupná. Skontrolujte či iná aplikácia používa kameru, vyberte inú kameru v nastaveniach alebo znovu spustite aplikáciu.",
|
||||
"cameraNotSendingDataTitle": "Prístup na kameru nie je možný.",
|
||||
"cameraPermissionDeniedError": "Nebolo udelené oprávnenie používať kameru. Napriek tomu sa môže zúčastniť na konferencií, ale ostatný účastníci vás nebudu vidieť. Pre pridelenie oprávnenia môžete použiť ikonu kamery na adresnej lište.",
|
||||
"cameraPermissionDeniedError": "Nebolo udelené oprávnenie používať kameru. Napriek tomu sa môže zúčastniť na konferencií, ale ostatní účastníci vás nebudu vidieť. Pre pridelenie oprávnenia môžete použiť ikonu kamery na adresnej lište.",
|
||||
"cameraUnknownError": "Z neznámeho dôvodu sa kamera nedá použiť.",
|
||||
"cameraUnsupportedResolutionError": "Táto kamera nepodporuje požadované rozlíšenie.",
|
||||
"cameraUnsupportedResolutionError": "Kamera nepodporuje požadované rozlíšenie.",
|
||||
"Cancel": "Zrušiť",
|
||||
"close": "Zatvoriť",
|
||||
"conferenceDisconnectMsg": "Skontrolujte prípadne vaše sieťové pripojenie. Pripájam znovu o {{seconds}} sekúnd...",
|
||||
"conferenceDisconnectTitle": "Vaše spojenie bolo prerušené.",
|
||||
"conferenceReloadMsg": "Snažíme sa to napraviť. Pripájam znovu o {{seconds}} sekund...",
|
||||
"conferenceReloadTitle": "Žiaľ niečo sa nepodarilo.",
|
||||
"conferenceReloadTitle": "Spojenie sa prerušilo.",
|
||||
"confirm": "Potvrdiť",
|
||||
"confirmNo": "Nie",
|
||||
"confirmYes": "Áno",
|
||||
"connectError": "Oops! Niečo je zle a nemôžem sa pripojiť do konferencie.",
|
||||
"connectErrorWithMsg": "Oops! Niečo je zle a nemôžem sa pripojiť do konferencie. Správa: {{msg}}",
|
||||
"connectError": "Niečo je zle a nemôžem sa pripojiť do konferencie.",
|
||||
"connectErrorWithMsg": "Niečo je zle a nemôžem sa pripojiť do konferencie. Správa: {{msg}}",
|
||||
"connecting": "Pripájam",
|
||||
"contactSupport": "Spojiť sa s podporou",
|
||||
"copy": "Kopírovať",
|
||||
"dismiss": "Zavrieť",
|
||||
"displayNameRequired": "Ahoj! Ako sa voláš?",
|
||||
"done": "Hotovo",
|
||||
"e2eeDescription": "Koncové šifrovanie (End-to-End Encryption, E2EE) je momentálne EXPERIMENTÁLNE. Zapnutie koncového šifrovania znemožní použitie serverových služieb ako: nahrávanie, živé vysielanie a účasť cez telefón. Do konferencie je možné vstúpiť len s prehliadačom, ktorý podporuje vložiteľné prúdy (insertable streams).",
|
||||
"e2eeLabel": "E2EE kľúč",
|
||||
"e2eeNoKey": "žiadny",
|
||||
"e2eeToggleSet": "Nastaviť kľúč",
|
||||
"e2eeSet": "Nastaviť",
|
||||
"e2eeWarning": "VAROVANIE: NIektorí účastníci nemajú podporu pre koncové šifrovanie. Ak ho zapnete, nebudú Vás vidieť ani počuť.",
|
||||
"enterDisplayName": "Prosím zadajte sem vaše meno",
|
||||
"error": "Chyba",
|
||||
"externalInstallationMsg": "Zlyhanie pri inštalácií rozšírenia pre zdieľanie prac. plochy",
|
||||
"externalInstallationTitle": "Potrebné rozšírenie:",
|
||||
"goToStore": "",
|
||||
"gracefulShutdown": "Naša služba je momentálne vypnutá pre údržbu. Skúste to neskor.",
|
||||
"gracefulShutdown": "Služba je momentálne vypnutá pre údržbu. Skúste to neskor.",
|
||||
"grantModeratorDialog": "Chcete naozaj tohoto účastníka urobiť moderatorom?",
|
||||
"grantModeratorTitle": "Urobiť moderatorom",
|
||||
"IamHost": "Ja som hostiteľ",
|
||||
"incorrectRoomLockPassword": "Nesprávne heslo",
|
||||
"incorrectPassword": "Používateľské meno alebo heslo je nesprávne",
|
||||
"inlineInstallationMsg": "Musí byť nainštalované rozšírenie pre zdieľanie pracovnej prochy.",
|
||||
"inlineInstallExtension": "Teraz inštalovať",
|
||||
"internalError": "Ups! Niečo nefunguje. Vyskytla sa nasledujúca chyba: {{error}}",
|
||||
"internalErrorTitle": "Interná chyba",
|
||||
"kickMessage": "Pre podrobnosti sa môžete spojiť s {{participantDisplayName}}.",
|
||||
"kickParticipantButton": "Odstrániť",
|
||||
"kickParticipantDialog": "Skutočne chcete odstrániť tohto účastnika?",
|
||||
"kickParticipantTitle": "Odstrániť účastníka?",
|
||||
"kickTitle": "Ouch! {{participantDisplayName}} vás odstránil zo stretnutia.",
|
||||
"kickTitle": "{{participantDisplayName}} vás odstránil z konferencie.",
|
||||
"liveStreaming": "Živé vysielanie",
|
||||
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "Nie je možné keď je aktívne nahrávanie",
|
||||
"liveStreamingDisabledForGuestTooltip": "Hostia nemôžu začať živé vysielanie.",
|
||||
"liveStreamingDisabledTooltip": "Štartovanie živého vysielania je vypnuté.",
|
||||
"liveStreamingDisabledTooltip": "Spustenie živého vysielania je zakázané.",
|
||||
"lockMessage": "Zlyhanie pri pokuse o zabezpečenie konferencie.",
|
||||
"lockRoom": "Pridať stretnutie $t(lockRoomPasswordUppercase)",
|
||||
"lockRoom": "Pridať $t(lockRoomPassword)",
|
||||
"lockTitle": "Zabezpečenie zlyhalo",
|
||||
"logoutQuestion": "Ste si istý, že sa chcete odhlásiť a skončiť konferenciu?",
|
||||
"logoutTitle": "Odhlásiť",
|
||||
"maxUsersLimitReached": "Bol dosiahnutý maximálny počet účastníkov. Konferencia je plná. Spojte sa prosím s organizátorom stretnutia, alebo to skúste neskôr.",
|
||||
"maxUsersLimitReached": "Bol dosiahnutý maximálny počet účastníkov. Konferencia je plná. Spojte sa prosím s organizátorom konferencie, alebo to skúste neskôr.",
|
||||
"maxUsersLimitReachedTitle": "Dosiahnutý maximálny počet účastníkov",
|
||||
"micConstraintFailedError": "Váš mikrofón nespĺňa potrebné požiadavky.",
|
||||
"micNotFoundError": "Mikrofón nebol nájdený.",
|
||||
"micNotSendingData": "Choďte do nastavení vašeho počítača, aby ste odblokovali stlmenie vášho mikrofónu a upravte jeho úroveň.",
|
||||
"micNotSendingDataTitle": "Mikrofón je stlmený vašimi systémovými nastaveniami.",
|
||||
"micPermissionDeniedError": "Nebolo udelené oprávnenie používať mikrofón. Napriek tomu sa môže zúčastniť na konferencií, ale ostatný účastníci vás nebudú počuť. Pre pridelenie oprávnenia môžete použiť ikonu kamery na adresnej lište.",
|
||||
"micPermissionDeniedError": "Nebolo udelené oprávnenie používať mikrofón. Napriek tomu sa môže zúčastniť na konferencií, ale ostatní účastníci vás nebudú počuť. Pre pridelenie oprávnenia môžete použiť ikonu kamery na adresnej lište.",
|
||||
"micUnknownError": "Mikrofón sa nedá použiť z neznámeho dôvodu.",
|
||||
"muteEveryoneElseDialog": "Keď všetkým vypnete mikrofón, nedokážete spať zapnuť mikrofóny. Účastníci si ale môžu zapnúť mikrofóny sami.",
|
||||
"muteEveryoneElseDialog": "Keď všetkým vypnete mikrofóny, nedokážete ich späť zapnúť. Účastníci si ale môžu zapnúť mikrofóny sami.",
|
||||
"muteEveryoneElseTitle": "Vypnúť mikrofón všetkým okrem {{whom}}?",
|
||||
"muteEveryoneDialog": "Chcete naozaj všetkým vypnúť mikrofón. Keď všetkým vypnete mikrofón, nedokážete spať zapnúť mikrofóny. Účastníci si ale môžu zapnúť mikrofóny sami.",
|
||||
"muteEveryoneDialog": "Chcete naozaj všetkým vypnúť mikrofón. Keď všetkým vypnete mikrofóny, nedokážete ich späť zapnúť. Účastníci si ale môžu zapnúť mikrofóny sami.",
|
||||
"muteEveryoneTitle": "Všetkým vypnúť mikrofón?",
|
||||
"muteEveryoneSelf": "seba samého",
|
||||
"muteEveryoneStartMuted": "Všetci odteraz začínajú s vypnutým mikrofónom",
|
||||
@@ -222,33 +244,34 @@
|
||||
"muteParticipantTitle": "Vypnúť účastníkovi mikrofón?",
|
||||
"Ok": "Ok",
|
||||
"passwordLabel": "$t(lockRoomPasswordUppercase)",
|
||||
"passwordNotSupported": "Nastavovanie $t(lockRoomPassword) nie je podporované.",
|
||||
"passwordNotSupported": "$t(lockRoomPasswordUppercase) nie je podporované.",
|
||||
"passwordNotSupportedTitle": "$t(lockRoomPasswordUppercase) nie je podporované",
|
||||
"passwordRequired": "$t(lockRoomPasswordUppercase) je potrebné",
|
||||
"popupError": "Váš prehliadať blokuje vyskakovacie okná tejto stránky. Prosím aktivujte vyskakovacie okná v bezpečnostných nastaveniach vašeho prehliadača a skúste znovu.",
|
||||
"passwordRequired": "Prihlásenie",
|
||||
"popupError": "Váš prehliadač blokuje vyskakovacie okná tejto stránky. Prosím aktivujte vyskakovacie okná v bezpečnostných nastaveniach vašeho prehliadača a skúste znovu.",
|
||||
"popupErrorTitle": "Vyskakovacie okná sú zablokované",
|
||||
"readMore": "viac",
|
||||
"recording": "Nahrávanie",
|
||||
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Nie je možné keď je aktívny živý prenos",
|
||||
"recordingDisabledForGuestTooltip": "Hostia nemôžu začať nahrávanie.",
|
||||
"recordingDisabledTooltip": "Štartovanie nahrávania je vypnuté.",
|
||||
"rejoinNow": "Teraz sa znovu pridať.",
|
||||
"recordingDisabledTooltip": "Spustenie nahrávania je zakázané.",
|
||||
"rejoinNow": "Pripojiť hneď",
|
||||
"remoteControlAllowedMessage": "{{user}} prijal požiadavku o vzdialené ovládanie.",
|
||||
"remoteControlDeniedMessage": "{{user}} odmietol prijal požiadavku o vzdialené ovládanie.",
|
||||
"remoteControlDeniedMessage": "{{user}} odmietol požiadavku o vzdialené ovládanie.",
|
||||
"remoteControlErrorMessage": "Stala sa chyba počas žiadania o vzdialené ovládanie od {{user}}",
|
||||
"remoteControlRequestMessage": "Povolíte {{user}} ovládať vášu pracovnú plochu?",
|
||||
"remoteControlShareScreenWarning": "Pozor, keď povolíte požiadavku budete zdielať vašu obrazovku!",
|
||||
"remoteControlStopMessage": "Vzdialené ovládanie bolo ukončené.",
|
||||
"remoteControlTitle": "Vzdialené ovládanie",
|
||||
"Remove": "Odstrániť",
|
||||
"removePassword": "$t(lockRoomPassword) odstránené",
|
||||
"removeSharedVideoMsg": "Ste si istý že chcete odstrániť zdielané video?",
|
||||
"removeSharedVideoTitle": "Odstrániť zdielané video",
|
||||
"removePassword": "$t(lockRoomPasswordUppercase) odstránené",
|
||||
"removeSharedVideoMsg": "Naozaj chcete odstrániť zdieľané video?",
|
||||
"removeSharedVideoTitle": "Odstrániť zdieľané video",
|
||||
"reservationError": "Systémová chyba rezervácie",
|
||||
"reservationErrorMsg": "Chyba: {{code}}, správa: {{msg}}",
|
||||
"retry": "Skúsiť znovu",
|
||||
"screenSharingFailedToInstall": "Ups! Nepodarilo sa nainštalovať rozšírenie pre zdieľanie obrazovky.",
|
||||
"screenSharingFailedToInstallTitle": "Chyba v inštalácii rozšírenie pre zdieľanie obrazovky",
|
||||
"screenSharingFirefoxPermissionDeniedError": "Niečo sa nepodarilo pri pokuse o zdielanie obrazovky. Skontrolujte prosím či ste dali oprávnenie v prehliadači.",
|
||||
"screenSharingFirefoxPermissionDeniedTitle": "Nepodarilo sa zdielať obrazovku",
|
||||
"screenSharingAudio": "Zdieľať zvuk",
|
||||
"screenSharingFailed": "Nie je možné spustiť zdieľanie obrazovky!",
|
||||
"screenSharingFailedTitle": "Zdieľanie obrazovky zlyhalo!",
|
||||
"screenSharingPermissionDeniedError": "Ups! Niečo sa nepodarilo pri žiadaní o oprávnenie zdielať obrazovku. Prosím aktualizovať a skúsiť znovu.",
|
||||
"sendPrivateMessage": "Dostali ste súkromnú správu. Chceli ste na ňu odpovedať súkromne, alebo chcete poslať správu skupine?",
|
||||
"sendPrivateMessageCancel": "Poslať skupine",
|
||||
@@ -258,26 +281,26 @@
|
||||
"sessTerminated": "Volanie ukončené",
|
||||
"Share": "Zdieľať",
|
||||
"shareVideoLinkError": "Prosím, zadajte správny Youtube odkaz.",
|
||||
"shareVideoTitle": "Zdielať video",
|
||||
"shareVideoTitle": "Zdieľať video",
|
||||
"shareYourScreen": "Zdielať obrazovku",
|
||||
"shareYourScreenDisabled": "Zdieľanie obrazovky vypnuté.",
|
||||
"shareYourScreenDisabledForGuest": "Hostia nemôžu zdielať obrazovku.",
|
||||
"startLiveStreaming": "Spustiť priamy prenos",
|
||||
"startLiveStreaming": "Spustiť živý prenos",
|
||||
"startRecording": "Začať záznam",
|
||||
"startRemoteControlErrorMessage": "Chyba pri pokuse o začatie vzdialeného riadenia!",
|
||||
"stopLiveStreaming": "Prerušiť priamy prenos",
|
||||
"startRemoteControlErrorMessage": "Chyba pri pokuse o začatie vzdialeného ovládania!",
|
||||
"stopLiveStreaming": "Zastaviť živý prenos",
|
||||
"stopRecording": "Zastaviť záznam",
|
||||
"stopRecordingWarning": "Chcete zastaviť záznam?",
|
||||
"stopStreamingWarning": "Chcete prerušiť priamy prenos",
|
||||
"streamKey": "Klúč živého vysielania",
|
||||
"stopStreamingWarning": "Chcete zastaviť priamy prenos?",
|
||||
"streamKey": "Kľúč živého vysielania",
|
||||
"Submit": "OK",
|
||||
"thankYou": "Ďakujeme vám za používanie {{appName}}!",
|
||||
"thankYou": "Ďakujeme za používanie {{appName}}!",
|
||||
"token": "token",
|
||||
"tokenAuthFailed": "Prepáčte, nie ste oprávnený zúčastniť tejto sa konferencie.",
|
||||
"tokenAuthFailedTitle": "Overenie zlyhalo",
|
||||
"transcribing": "",
|
||||
"unlockRoom": "Odstrániť stretnutie $t(lockRoomPassword)",
|
||||
"userPassword": "užívateľské heslo",
|
||||
"unlockRoom": "Odstrániť $t(lockRoomPassword)",
|
||||
"userPassword": "heslo",
|
||||
"WaitForHostMsg": "Konferencia <b>{{room}}</b> sa ešte nezačala. Autorizujte sa prosím ak ste hostiteľ. V opačnom prípade čakajte na hostiteľa.",
|
||||
"WaitForHostMsgWOk": "Konferencia <b>{{room}}</b> sa ešte nezačala. Ak ste hostiteľ autorizujte sa stlačením Ok. V opačnom prípade čakajte na hostiteľa.",
|
||||
"WaitingForHost": "Čakám na hostiteľa ...",
|
||||
@@ -288,7 +311,10 @@
|
||||
"statusMessage": "je teraz {{status}}"
|
||||
},
|
||||
"documentSharing": {
|
||||
"title": "Zdielaný dokument"
|
||||
"title": "Zdieľaný dokument"
|
||||
},
|
||||
"e2ee": {
|
||||
"labelToolTip": "Zvuková a obrazová komunikácia je koncovo šifrovaná"
|
||||
},
|
||||
"feedback": {
|
||||
"average": "Priemerný",
|
||||
@@ -308,8 +334,8 @@
|
||||
},
|
||||
"info": {
|
||||
"accessibilityLabel": "Zobraziť informácie",
|
||||
"addPassword": "$t(lockRoomPassword) pridať",
|
||||
"cancelPassword": "$t(lockRoomPassword) zmazať",
|
||||
"addPassword": "Nastaviť $t(lockRoomPassword)",
|
||||
"cancelPassword": "Zrušiť $t(lockRoomPassword)",
|
||||
"conferenceURL": "Odkaz:",
|
||||
"country": "Krajina",
|
||||
"dialANumber": "Aby ste sa zúčastnili stretnutia, zavolajte jedno z týchto čísel a zadajte pin.",
|
||||
@@ -322,9 +348,9 @@
|
||||
"inviteLiveStream": "Kliknite túto linku {{url}}, pre zobrazenie živého vysielania z tohto stretnutia.",
|
||||
"invitePhone": "Keď sa chcete pripojiť cez telefón, klikni na: {{number}},,{{conferenceID}}#\n",
|
||||
"invitePhoneAlternatives": "Hľadáte iné pripojovacie číslo? Pripojovacie čísla pre konferenciu: {{{url}}\n\n\n\nTaktiež pokiaľ sa telefonicky pripájate cez konferenčný celomiestnostný telefón pripojte sa bez prenosu zvuku {{silentUrl}}",
|
||||
"inviteURLFirstPartGeneral": "Ste pozývaný pripojiť sa na stretnutie.",
|
||||
"inviteURLFirstPartPersonal": "{{name}} vás pozýva na stretnutie.",
|
||||
"inviteURLSecondPart": "\n Zúčastniť sa stretnutia:\n{{url}}\n",
|
||||
"inviteURLFirstPartGeneral": "Ste pozvaný do konferencie.",
|
||||
"inviteURLFirstPartPersonal": "{{name}} vás pozýva do konferencie.\n",
|
||||
"inviteURLSecondPart": "\nVstúpiť do konferencie:\n{{url}}\n",
|
||||
"liveStreamURL": "Živý prenos:",
|
||||
"moreNumbers": "Ďalšie telefónne čísla",
|
||||
"noNumbers": "Žiadne pripojovacie telefónne čísla.",
|
||||
@@ -368,6 +394,8 @@
|
||||
"videoQuality": "Nastavenie kvality volania"
|
||||
},
|
||||
"liveStreaming": {
|
||||
"limitNotificationDescriptionWeb": "Živé vysielanie je obmedzené na {{limit}} minút. Pre neobmedzené vysielanie skúste <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"limitNotificationDescriptionNative": "Živé vysielanie je obmedzené na {{limit}} minút. Pre neobmedzené vysielanie skúste {{app}}.",
|
||||
"busy": "Chystajú sa zdroje pre vysielanie. Skúste znova za pár minút.",
|
||||
"busyTitle": "Všetky vysielacie inštancie sú obsadené",
|
||||
"changeSignIn": "Prepnúť konto",
|
||||
@@ -375,19 +403,19 @@
|
||||
"chooseCTA": "Vyberte vysielaciu možnosť. Ste prihlásený ako {{email}}",
|
||||
"enterStreamKey": "Zadajte meno/heslo pre YouTube vysielanie.",
|
||||
"error": "Živé vysielanie zlyhalo. Prosím skúste to znovu.",
|
||||
"errorAPI": "Došlo chybe pri prístupe k vašemu YouTube vysielaniu. Prosím skúste sa znovu prihlásiť.",
|
||||
"errorAPI": "Došlo k chybe pri prístupe k vašemu YouTube vysielaniu. Prosím skúste sa znovu prihlásiť.",
|
||||
"errorLiveStreamNotEnabled": "Živé vysielanie pre {{email}} nie je aktivované. Aktivujte živé vysielanie, alebo sa prihláste pomocou konta s aktivovaným živým vysielaním.",
|
||||
"expandedOff": "Živé vysielanie bolo zastavené",
|
||||
"expandedOn": "Stretnutie je momentálne vysielané na YouTube.",
|
||||
"expandedPending": "Spúšťa živé vysielanie...",
|
||||
"failedToStart": "Nepodarilo sa naštartovať živé vysielanie",
|
||||
"failedToStart": "Nepodarilo sa spustiť živé vysielanie",
|
||||
"getStreamKeyManually": "Nepodarilo sa získať žiadne živé vysielania. Skúste získať kľúč pre živé vysielanie z YouTube.",
|
||||
"invalidStreamKey": "Kľúč pre živé vysielanie je nesprávny.",
|
||||
"off": "Živé vysielanie ukončené",
|
||||
"offBy": "{{name}} ukončil živé vysielanie",
|
||||
"on": "Živé vysielanie",
|
||||
"onBy": "{{name}} začal živé vysielanie",
|
||||
"pending": "Štartuje sa živé vysielanie...",
|
||||
"pending": "Spúšťa sa živé vysielanie...",
|
||||
"serviceName": "Služba pre živé vysielanie",
|
||||
"signedInAs": "Ste prihlásený ako:",
|
||||
"signIn": "Prihlásiť sa pomocou Google",
|
||||
@@ -395,7 +423,9 @@
|
||||
"signOut": "Odhlásiť",
|
||||
"start": "Začať živé vysielanie",
|
||||
"streamIdHelp": "Čo je to?",
|
||||
"unavailableTitle": "Živé vysielanie nie je k dispozícií"
|
||||
"unavailableTitle": "Živé vysielanie nie je k dispozícií",
|
||||
"youtubeTerms": "Podmienky poskytovania služby YouTube",
|
||||
"googlePrivacyPolicy": "Pravidlá ochrany súkromia Google"
|
||||
},
|
||||
"localRecording": {
|
||||
"clientState": {
|
||||
@@ -403,19 +433,19 @@
|
||||
"on": "Zapnutý",
|
||||
"unknown": "Neznámy"
|
||||
},
|
||||
"dialogTitle": "Lokálne ovládacie prvky nahrávania",
|
||||
"dialogTitle": "Ovládacie prvky lokálneho nahrávania",
|
||||
"duration": "Dĺžka",
|
||||
"durationNA": "neznáma",
|
||||
"encoding": "Kódovanie",
|
||||
"label": "",
|
||||
"labelToolTip": "Lokálny nahrávanie je aktivovaný",
|
||||
"labelToolTip": "Lokálne nahrávanie je aktivovaný",
|
||||
"localRecording": "Lokálne nahrávanie",
|
||||
"me": "Ja",
|
||||
"messages": {
|
||||
"engaged": "Lokálne nahrávanie je spustené",
|
||||
"finished": "Nahrávanie sedenia {{token}} je ukončené. Prosím pošlite nahratý súbor moderátorovi.",
|
||||
"finishedModerator": "Nahrávanie sedenia {{token}} je ukončené. Bola uložená nahrávka lokálnej stopy. Poproste ostatných účastníkov, aby vám poslali ich nahrávky.",
|
||||
"notModerator": "Nieste moderátor. Nemôže začať, alebo skončiť lokálne nahrávanie."
|
||||
"notModerator": "Nie ste moderátor. Nemôže začať, alebo skončiť lokálne nahrávanie."
|
||||
},
|
||||
"moderator": "Moderátor",
|
||||
"no": "Nie",
|
||||
@@ -438,17 +468,17 @@
|
||||
"focusFail": "{{component}} je nedostupný - skúste znova za {{ms}} sek",
|
||||
"grantedTo": "Práva moderátora boli udelené {{to}}!",
|
||||
"invitedOneMember": "{{displayName}} bol pozvaný",
|
||||
"invitedThreePlusMembers": "{{name}} a {{count}} ďalší boli pozvaný",
|
||||
"invitedTwoMembers": "{{first}} a {{second}} boli pozvaný",
|
||||
"kickParticipant": "Pre ďalšie podrobnosti sa môže obrátiť na {{participantDisplayName}}",
|
||||
"invitedThreePlusMembers": "{{name}} a {{count}} ďalší boli pozvaní",
|
||||
"invitedTwoMembers": "{{first}} a {{second}} boli pozvaní",
|
||||
"kickParticipant": "{{kicked}} bol odstránený účastníkom {{kicker}}",
|
||||
"me": "Ja",
|
||||
"moderator": "Boli vám udelené práva moderátora!",
|
||||
"muted": "Začali ste rozhovor s vypnutým mikrofónom.",
|
||||
"mutedTitle": "Boli ste stíšený!",
|
||||
"mutedRemotelyTitle": "{{participantDisplayName}} vás stíšil",
|
||||
"mutedRemotelyTitle": "{{participantDisplayName}} vám vypol mikrofón",
|
||||
"mutedRemotelyDescription": "Kedykoľvek môžete stíšenie zrušiť, keď ste prichystaný rozprávať. Keď skončite môžete sa znova stíšiť, aby ste znížili hluk na stretnutí.",
|
||||
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) bolo odstránené iným účastníkom",
|
||||
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) bolo nastavené iným účastníkom",
|
||||
"passwordRemovedRemotely": "Iný účastník odstránil $t(lockRoomPassword)",
|
||||
"passwordSetRemotely": "Iný účastník nastavil $t(lockRoomPassword)",
|
||||
"raisedHand": "{{name}} chce hovoriť",
|
||||
"somebody": "Niekto",
|
||||
"startSilentTitle": "Pripojili ste sa bez zvukového výstupu!",
|
||||
@@ -458,11 +488,49 @@
|
||||
"unmute": "Zapnúť mikrofón",
|
||||
"newDeviceCameraTitle": "Bola zistená nová kamera",
|
||||
"newDeviceAudioTitle": "Bolo zistené nové audio zariadenie",
|
||||
"newDeviceAction": "Použiť"
|
||||
"newDeviceAction": "Použiť",
|
||||
"OldElectronAPPTitle": "Bezpečnostná hrozba!",
|
||||
"oldElectronClientDescription1": "Používate starú verziu klienta Jitsi Meet, ktorá má známe zraniteľnosti. Aktualizujte na ",
|
||||
"oldElectronClientDescription2": "najnovšiu verziu",
|
||||
"oldElectronClientDescription3": " teraz!"
|
||||
},
|
||||
"passwordSetRemotely": "nastavené iným účastníkom",
|
||||
"passwordDigitsOnly": "až {{number}} číslic",
|
||||
"poweredby": "založené na",
|
||||
"prejoin": {
|
||||
"audioAndVideoError": "Chyba zvuku a videa:",
|
||||
"audioOnlyError": "Chyba zvuku:",
|
||||
"audioTrackError": "Nemôžem vytvoriť zvukovú stopu.",
|
||||
"callMe": "Zavolať mi",
|
||||
"callMeAtNumber": "Zavolajte mi na toto číslo:",
|
||||
"configuringDevices": "Konfigurácia zariedení...",
|
||||
"connectedWithAudioQ": "Ste pripojení so zvukom?",
|
||||
"copyAndShare": "Kopírovať a zdieľať odkaz",
|
||||
"dialInMeeting": "Volanie dnu do konferencie",
|
||||
"dialInPin": "Volajte dnu do konferencie a zadajte PIN kód:",
|
||||
"dialing": "Vytáčanie",
|
||||
"doNotShow": "Viac nezobrazovať",
|
||||
"errorDialOut": "Nemôžem volať von",
|
||||
"errorDialOutDisconnected": "Nemôžem volať von. Odpojené",
|
||||
"errorDialOutFailed": "Nemôžem volať von. Volanie zlyhalo",
|
||||
"errorDialOutStatus": "Chyba pri získavaní stavu volania",
|
||||
"errorStatusCode": "Chyba volania von, kód: {{status}}",
|
||||
"errorValidation": "Overenie čísla zlyhalo",
|
||||
"iWantToDialIn": "Chcem volať dnu",
|
||||
"joinAudioByPhone": "Vstúpiť so zvukom cez telefón",
|
||||
"joinMeeting": "Vstúpiť do konferencie",
|
||||
"joinWithoutAudio": "Vstúpiť bez zvuku",
|
||||
"initiated": "Hovor začatý",
|
||||
"linkCopied": "Odkaz skopírovaný do schránky",
|
||||
"lookGood": "Váš mikrofón funguje správne",
|
||||
"or": "alebo",
|
||||
"calling": "Volanie",
|
||||
"startWithPhone": "Začať so zvukom cez telefón",
|
||||
"screenSharingError": "Chyba pri zdieľaní obrazovky:",
|
||||
"videoOnlyError": "Chyba videa:",
|
||||
"videoTrackError": "Nemôžem vytvoriť video stopu.",
|
||||
"viewAllNumbers": "zobraziť všetky čísla"
|
||||
},
|
||||
"presenceStatus": {
|
||||
"busy": "Obsadený",
|
||||
"calling": "Je volaný",
|
||||
@@ -485,6 +553,8 @@
|
||||
},
|
||||
"raisedHand": "Chcel by som hovoriť",
|
||||
"recording": {
|
||||
"limitNotificationDescriptionWeb": "Nahrávanie je obmedzené na {{limit}} minút. Pre neobmedzené nahrávanie skúste <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"limitNotificationDescriptionNative": "Nahrávanie je obmedzené na {{limit}} minút. Pre neobmedzené nahrávanie skúste <3>{{app}}</3>.",
|
||||
"authDropboxText": "Nahrať na Dropbox",
|
||||
"availableSpace": "Dostupná kapacita {{spaceLeft}} MB (ca. {{duration}} minút nahrávania)",
|
||||
"beta": "BETA",
|
||||
@@ -514,6 +584,12 @@
|
||||
"sectionList": {
|
||||
"pullToRefresh": "Potiahnuť pre aktualizáciu"
|
||||
},
|
||||
"security": {
|
||||
"about": "Môžete nastaviť $t(lockRoomPassword) pre konferenciu. Účastníci budú musieť zadať $t(lockRoomPassword), aby mohli vstúpiť.",
|
||||
"aboutReadOnly": "Moderátor može nastaviť $t(lockRoomPassword) pre konferenciu. Účastníci budú musieť zadať $t(lockRoomPassword), aby mohli vstúpiť.",
|
||||
"insecureRoomNameWarning": "Názov konferencie nie je bezpečný. Môžu do nej vstúpiť neželaní účastníci. Zvážte zabezpečenie konferencie tlačidlom.",
|
||||
"securityOptions": "Nastavenie zabezpečenia"
|
||||
},
|
||||
"settings": {
|
||||
"calendar": {
|
||||
"about": "Používa sa kalendárová integrácia {{appName}} pre zabezpečený prístup ku vašemu kalendáru.",
|
||||
@@ -526,6 +602,7 @@
|
||||
"followMe": "Všetci sledujú mňa",
|
||||
"language": "Jazyk",
|
||||
"loggedIn": "Prihlásený ako {{name}}",
|
||||
"microphones": "Mikrofóny",
|
||||
"moderator": "Moderátor",
|
||||
"more": "Viac",
|
||||
"name": "Meno",
|
||||
@@ -533,6 +610,7 @@
|
||||
"selectAudioOutput": "Zvukový výstup",
|
||||
"selectCamera": "Kamera",
|
||||
"selectMic": "Mikrofón",
|
||||
"speakers": "Reproduktory",
|
||||
"startAudioMuted": "Pri pripojení všetkým stlmiť zvuk",
|
||||
"startVideoMuted": "Pri pripojení všetkým vypnúť video",
|
||||
"title": "Nastavenia"
|
||||
@@ -540,12 +618,15 @@
|
||||
"settingsView": {
|
||||
"advanced": "Rozšírené",
|
||||
"alertOk": "OK",
|
||||
"alertCancel": "Zrušiť",
|
||||
"alertTitle": "Upozornenie",
|
||||
"alertURLText": "Zadaná serverový URL je neplatná",
|
||||
"alertURLText": "Zadaná serverová URL je neplatná",
|
||||
"buildInfoSection": "informácie o kompilácií",
|
||||
"conferenceSection": "Konferencia",
|
||||
"disableCallIntegration": "Deaktivovať integráciu s natívnymi volaniami",
|
||||
"disableP2P": "Deaktivovať mód s koncovými zariadeniami",
|
||||
"disableCrashReporting": "Vypnúť oznamovanie pádov",
|
||||
"disableCrashReportingWarning": "Naozak chcete vypnúť oznamovanie pádov? Nastavenie bude aktívne po reštartovaní aplikácie.",
|
||||
"displayName": "Ukázať",
|
||||
"email": "E-mail",
|
||||
"header": "Nastavenia",
|
||||
@@ -562,10 +643,10 @@
|
||||
},
|
||||
"speaker": "Rečník",
|
||||
"speakerStats": {
|
||||
"hours": "",
|
||||
"minutes": "",
|
||||
"hours": "{{count}}h",
|
||||
"minutes": "{{count}}m",
|
||||
"name": "Meno",
|
||||
"seconds": "",
|
||||
"seconds": "{{count}}s",
|
||||
"speakerStats": "Štatistiky rečníka",
|
||||
"speakerTime": "Čas rečníka"
|
||||
},
|
||||
@@ -576,7 +657,7 @@
|
||||
"suspendedoverlay": {
|
||||
"rejoinKeyTitle": "Znovu pripojiť",
|
||||
"text": "Stlačte tlačidlo <i>Znovu pripojiť</i> na opätovné spojenie.",
|
||||
"title": "Konferencia sa prerušila lebo váš počítač bol uspaní."
|
||||
"title": "Konferencia sa prerušila lebo váš počítač bol uspaný."
|
||||
},
|
||||
"toolbar": {
|
||||
"accessibilityLabel": {
|
||||
@@ -587,14 +668,17 @@
|
||||
"chat": "Zapnúť/vypnúť textovú diskusiu",
|
||||
"document": "Zatvoriť zdielaný dokument",
|
||||
"download": "Stiahnuť našu aplikáciu",
|
||||
"e2ee": "Koncové šifrovanie",
|
||||
"feedback": "Zanechať spätnú väzbu",
|
||||
"fullScreen": "Zapnúť/vypnúť zobrazenie na celú obrazovku",
|
||||
"grantModerator": "Urobiť moderátorom",
|
||||
"hangup": "Ukončiť volanie",
|
||||
"help": "Pomoc",
|
||||
"invite": "Pozvať účastníka",
|
||||
"kick": "Odstrániť účastníka",
|
||||
"lobbyButton": "Zapnúť/vypnúť čakáreň",
|
||||
"localRecording": "Zapnúť/vypnúť ovládanie lokálneho nahrávania",
|
||||
"lockRoom": "Zapnúť/vypnúť heslo pre stretnutie",
|
||||
"lockRoom": "Zapnúť/vypnúť heslo",
|
||||
"moreActions": "Menu „Ďalšie akcie“ zapnúť/vypnúť",
|
||||
"moreActionsMenu": "Menu „Ďalšie akcie“",
|
||||
"moreOptions": "Zobraz viac možností",
|
||||
@@ -606,6 +690,7 @@
|
||||
"raiseHand": "„Ohlásiť sa“ zapnúť/vypnúť",
|
||||
"recording": "Nahrávanie zapnúť/vypnúť",
|
||||
"remoteMute": "Účastníka stlmiť",
|
||||
"security": "Nastavenie zabezpečenia",
|
||||
"Settings": "Nastavenia zapnúť/vypnúť",
|
||||
"sharedvideo": "Zdieľanie YouTube videa zapnúť/vypnúť",
|
||||
"shareRoom": "Pozvať osobu",
|
||||
@@ -615,6 +700,7 @@
|
||||
"speakerStats": "Štatistiky rečníka zobraziť/skryť",
|
||||
"tileView": "Prepnúť dlaždicové zobrazenie",
|
||||
"toggleCamera": "Zmeniť kameru",
|
||||
"toggleFilmstrip": "Zapnúť/vypnúť video náhľady",
|
||||
"videomute": "„Video odpojiť“ zapnúť/vypnúť",
|
||||
"videoblur": "Rozmazanie pozadia zapnúť/vypnúť"
|
||||
},
|
||||
@@ -622,21 +708,24 @@
|
||||
"audioOnlyOff": "Mód „Iba zvuk“ deaktivovať",
|
||||
"audioOnlyOn": "Mód „Iba zvuk“ aktivovať",
|
||||
"audioRoute": "Vybrať zvukové zariadenie",
|
||||
"authenticate": "Overiť",
|
||||
"authenticate": "Autentifikácia",
|
||||
"callQuality": "Spravovať kvalitu videa",
|
||||
"chat": "Otvoriť / Zatvoriť chat",
|
||||
"closeChat": "Chat zatvoriť",
|
||||
"documentClose": "Zdielaný dokument zatvoriť",
|
||||
"documentOpen": "Zdielaný dokument otvoriť",
|
||||
"documentClose": "Zatvoriť zdieľaný dokument",
|
||||
"documentOpen": "Otvoriť zdieľaný dokument",
|
||||
"download": "Stiahnuť našu aplikáciu",
|
||||
"e2ee": "Koncové šifrovanie",
|
||||
"enterFullScreen": "Zobraziť na celú obrazovku",
|
||||
"enterTileView": "Kachličkové zobrazenie",
|
||||
"enterTileView": "Dlaždicové zobrazenie",
|
||||
"exitFullScreen": "Opustiť celú obrazovku",
|
||||
"exitTileView": "Kachličkové zobrazenie vypnúť",
|
||||
"exitTileView": "Zrušiť dlaždicové zobrazenie",
|
||||
"feedback": "Nechať spätnú väzbu",
|
||||
"hangup": "Odísť",
|
||||
"help": "Pomoc",
|
||||
"invite": "Pozvať účastníkov",
|
||||
"invite": "Pozvať ľudí",
|
||||
"lobbyButtonDisable": "Vypnúť čakáreň",
|
||||
"lobbyButtonEnable": "Zapnúť čakáreň",
|
||||
"login": "Prihlásiť",
|
||||
"logout": "Odhlásiť",
|
||||
"lowerYourHand": "Dať dole ruku",
|
||||
@@ -645,10 +734,10 @@
|
||||
"mute": "Vypnúť / Zapnúť mikrofón",
|
||||
"muteEveryone": "Všetkých stlmiť",
|
||||
"noAudioSignalTitle": "Neprichádza žiaden vstup z vašeho mikrofónu!",
|
||||
"noAudioSignalDesc": "Pokiaľ ste zámerne nestlmili váš mikrofón v systémových nastavenia alebo hardvery, pouvažujte nad prepnutím zariadenia.",
|
||||
"noAudioSignalDescSuggestion": "Pokiaľ ste zámerne nestlmili váš mikrofón v systémových nastavenia alebo hardvery, pouvažujte nad prepnutím na odporúčané zariadenie.",
|
||||
"noAudioSignalDesc": "Pokiaľ ste zámerne nestlmili váš mikrofón v systémových nastaveniach alebo hardvéri, pouvažujte nad prepnutím zariadenia.",
|
||||
"noAudioSignalDescSuggestion": "Pokiaľ ste zámerne nestlmili váš mikrofón v systémových nastaveniach alebo hardvéri, pouvažujte nad prepnutím na odporúčané zariadenie.",
|
||||
"noAudioSignalDialInDesc": "Môže zavolať pomocou:",
|
||||
"noAudioSignalDialInLinkDesc" : "Pripojovacie telefónne čísla",
|
||||
"noAudioSignalDialInLinkDesc": "Pripojovacie telefónne čísla",
|
||||
"noisyAudioInputTitle": "Váš mikrofón vyzerá byť zašumený!",
|
||||
"noisyAudioInputDesc": "Vyzerá, že váš mikrofón je zašumený, skúste ho vypnuť, alebo zmeňte zariadenie.",
|
||||
"openChat": "Otvoriť chat",
|
||||
@@ -657,6 +746,7 @@
|
||||
"profile": "Úprava profilu",
|
||||
"raiseHand": "Prihlásiť / Odhlásiť sa o slovo",
|
||||
"raiseYourHand": "Prihlásiť sa o slovo",
|
||||
"security": "Nastavenie zabezpečenia",
|
||||
"Settings": "Nastavenia",
|
||||
"sharedvideo": "Zdielať YouTube video",
|
||||
"shareRoom": "Pozvať niekoho",
|
||||
@@ -684,7 +774,7 @@
|
||||
"pending": "Pripravuje sa prepisovanie stretnutia...",
|
||||
"start": "Začni zobrazovať titulky",
|
||||
"stop": "Skonči zobrazovať titulky",
|
||||
"tr": ""
|
||||
"tr": "TR"
|
||||
},
|
||||
"userMedia": {
|
||||
"androidGrantPermissions": "Vyberte <b><i>Povoliť</i></b> keď sa prehliadač bude pýtať na povolenie.",
|
||||
@@ -699,14 +789,14 @@
|
||||
"safariGrantPermissions": "Vyberte <b><i>OK</i></b> keď sa prehliadač bude pýtať na povolenie."
|
||||
},
|
||||
"videoSIPGW": {
|
||||
"busy": "",
|
||||
"busyTitle": "",
|
||||
"errorAlreadyInvited": "",
|
||||
"errorInvite": "",
|
||||
"errorInviteFailed": "",
|
||||
"errorInviteFailedTitle": "",
|
||||
"errorInviteTitle": "",
|
||||
"pending": ""
|
||||
"busy": "Všetky zdroje sú obsadené, skúste znovu o pár minút.",
|
||||
"busyTitle": "Služba je obsadená",
|
||||
"errorAlreadyInvited": "{{displayName}} už bol pozvaný",
|
||||
"errorInvite": "Konferencia sa ešte nezačala, skúste neskôr.",
|
||||
"errorInviteFailed": "Skúste znovu neskôr.",
|
||||
"errorInviteFailedTitle": "Pozývanie {{displayName}} zlyhalo",
|
||||
"errorInviteTitle": "Chyba pozývania",
|
||||
"pending": "{{displayName}} bol pozvaný"
|
||||
},
|
||||
"videoStatus": {
|
||||
"audioOnly": "AUD",
|
||||
@@ -728,8 +818,10 @@
|
||||
},
|
||||
"videothumbnail": {
|
||||
"domute": "Vypnúť mikrofón",
|
||||
"domuteOthers": "Vypnúť mikrofóny ostatným",
|
||||
"flip": "Prevrátiť",
|
||||
"kick": "Vyhodiť",
|
||||
"grantModerator": "Urobiť moderátorom",
|
||||
"kick": "Odstrániť",
|
||||
"moderator": "Moderátor",
|
||||
"mute": "Účastník s vypnutým mikrofónom",
|
||||
"muted": "Vypnutý mikrofón",
|
||||
@@ -751,20 +843,62 @@
|
||||
"connectCalendarButton": "Pripojte váš kalendár",
|
||||
"connectCalendarText": "",
|
||||
"enterRoomTitle": "Začať nové stretnutie",
|
||||
"roomNameAllowedChars": "Meno stretnutia by nemalo obsahovať žiaden z týchto znakov: ?, &, :, ', \", %, #.",
|
||||
"getHelp": "Získať pomoc",
|
||||
"go": "Začať",
|
||||
"goSmall": "Začať",
|
||||
"join": "Pripojiť",
|
||||
"info": "Info",
|
||||
"join": "Pripojiť",
|
||||
"moderatedMessage": "Alebo si <a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">rezervujte vopred URL</a> pre konferenciu, kde budete jediný moderátor.",
|
||||
"privacy": "Súkromie",
|
||||
"recentList": "Posledné",
|
||||
"recentListDelete": "Vymazať",
|
||||
"recentListEmpty": "Váš zoznam posledných hovorov je prázdny. Spojte sa s kolegami z Vášho tímu a potom tu nájdete všetky vaše stretnutia.",
|
||||
"reducedUIText": "Vítajte v {{app}}!",
|
||||
"reducedUIText": "Vitajte v {{app}}!",
|
||||
"roomNameAllowedChars": "Názov miestnosti by nemal obsahovať žiaden z týchto znakov: ?, &, :, ', \", %, #.",
|
||||
"roomname": "Zadajte názov miestnosti",
|
||||
"roomnameHint": "Zadajte názov alebo URL odkaz miestnosti ku ktorej sa chcete pripojiť. Pokial ste miestnosť vytvorili, uistite sa, že ostatný účastníci schôdzky zadajú rovnaké meno ako vy.",
|
||||
"roomnameHint": "Zadajte názov alebo URL odkaz miestnosti ku ktorej sa chcete pripojiť. Názov si môžete vymyslieť - dajte ho vedieť ostatným účastníkom konferencie, ktorí ho sem zadajú.",
|
||||
"sendFeedback": "Odoslať spätnú väzbu",
|
||||
"terms": "Podmienky používania",
|
||||
"title": "Zabezpečené, plnohodnotné a úplne bezplatné videokonferencie"
|
||||
},
|
||||
"lonelyMeetingExperience": {
|
||||
"button": "Pozvať ďalších",
|
||||
"youAreAlone": "Ste sám v tejto konferencii"
|
||||
},
|
||||
"helpView": {
|
||||
"header": "Centrum pomoci"
|
||||
},
|
||||
"lobby": {
|
||||
"knockingParticipantList": "Zoznam čakajúcich účastníkov",
|
||||
"allow": "Povoliť",
|
||||
"backToKnockModeButton": "Žiadne heslo, požiadať o vstup",
|
||||
"dialogTitle": "Čakáreň",
|
||||
"disableDialogContent": "Čakáreň je zapnutá. Táto funkcia zabezpečuje, že do konferencie nemôžu vstúpiť neželaní účastníci. Chcete ju vypnúť?",
|
||||
"disableDialogSubmit": "Vypnúť",
|
||||
"emailField": "Zadajte vašu e-mailovú adresu",
|
||||
"enableDialogPasswordField": "Nastaviť heslo (voliteľné)",
|
||||
"enableDialogSubmit": "Zapnúť",
|
||||
"enableDialogText": "Čakáreň umožňuje zabezpečiť konferenciu tým, že účastníci môžu do konferencie vstúpiť len po schválení moderátorom.",
|
||||
"enterPasswordButton": "Zadať heslo do konferencie",
|
||||
"enterPasswordTitle": "Zadajte heslo pre vstup do konferencie",
|
||||
"invalidPassword": "Nesprávne heslo",
|
||||
"joiningMessage": "Vstúpite do konferencie, keď niekto schváli vašu žiadosť",
|
||||
"joinWithPasswordMessage": "Vstupujem s heslom...",
|
||||
"joinRejectedMessage": "Vaša žiadosť bola zamietnutá moderátorom.",
|
||||
"joinTitle": "Vstup do konferencie",
|
||||
"joiningTitle": "Žiadam o vstup do konferencie...",
|
||||
"joiningWithPasswordTitle": "Vstupujem s heslom...",
|
||||
"knockButton": "Požiadať o vstup",
|
||||
"knockTitle": "Niekto žiada o vstup do konferencie",
|
||||
"nameField": "Zadajte vaše meno",
|
||||
"notificationLobbyAccessDenied": "Žiadosť {{targetParticipantName}} o vstup bola zamietnutá účastníkom {{originParticipantName}}",
|
||||
"notificationLobbyAccessGranted": "Žiadosť {{targetParticipantName}} o vstup bola povolená účastníkom {{originParticipantName}}",
|
||||
"notificationLobbyDisabled": "Účastník {{originParticipantName}} vypol čakáreň",
|
||||
"notificationLobbyEnabled": "Účastník {{originParticipantName}} zapol čakáreň",
|
||||
"notificationTitle": "Čakáreň",
|
||||
"passwordField": "Zadajte heslo do konferencie",
|
||||
"passwordJoinButton": "Vstúpiť",
|
||||
"reject": "Odmietnuť",
|
||||
"toggleLabel": "Zapnúť čakáreň"
|
||||
}
|
||||
}
|
||||
|
||||
1520
lang/main-sr.json
1520
lang/main-sr.json
File diff suppressed because it is too large
Load Diff
@@ -579,7 +579,7 @@
|
||||
},
|
||||
|
||||
"security": {
|
||||
"about": "Toplantınıza bir şifre ekleyebilirsiniz. Katılımcıların toplantıya katılmasına izin verilmeden önce şifreyi girmeleri gerekecektir.",
|
||||
"about": "Toplantınıza bir parola ekleyebilirsiniz. Katılımcıların toplantıya katılmasına izin verilmeden önce parolayı girmeleri gerekecektir.",
|
||||
"insecureRoomNameWarning": "Toplantı odası güvenli değil. Konferansınıza istenmeyen katılımcılar katılabilir.",
|
||||
"securityOptions": "Güvenlik Seçenekleri"
|
||||
},
|
||||
@@ -819,7 +819,7 @@
|
||||
"join": "Katılmak için dokunun",
|
||||
"roomname": "Oda adı girin"
|
||||
},
|
||||
"appDescription": "Durma ve tüm ekiple görüntülü sohbet et. Hatta tanıdığın herkesi davet et. {{app}} tüm gün, her gün ücretsiz olarak kullanabileceğiniz, hesap gerektirmeden kullanbilieceğiniz tamamen şifrelenmiş, % 100 özgür bir video konferans çözümüdür.",
|
||||
"appDescription": "Durma ve tüm ekiple görüntülü sohbet et. Hatta tanıdığın herkesi davet et. {{app}} tüm gün, her gün ücretsiz olarak ve hesap gerektirmeden kullanabileceğiniz tamamen şifrelenmiş, % 100 özgür bir video konferans çözümüdür.",
|
||||
"audioVideoSwitch": {
|
||||
"audio": "Ses",
|
||||
"video": "Görüntü"
|
||||
@@ -865,27 +865,27 @@
|
||||
|
||||
"lobby": {
|
||||
"allow": "İzin ver",
|
||||
"backToKnockModeButton": "Şifre yok, bunun yerine katılmayı isteyin",
|
||||
"backToKnockModeButton": "Parola yok, bunun yerine katılmayı isteyin",
|
||||
"dialogTitle": "Lobi modu",
|
||||
"disableDialogContent": "Lobi modu şu anda etkin. Bu özellik, istenmeyen katılımcıların toplantınıza katılamamasını sağlar. Devre dışı bırakmak istiyor musunuz?",
|
||||
"disableDialogSubmit": "Devre Dışı",
|
||||
"emailField": "E-posta adresinizi giriniz",
|
||||
"enableDialogPasswordField": "Şifre belirleyin (isteğe bağlı)",
|
||||
"enableDialogPasswordField": "Parola belirleyin (isteğe bağlı)",
|
||||
"enableDialogSubmit": "Etkin",
|
||||
"enableDialogText": "Lobi modu, toplantınızı yalnızca kişilerin bir moderatör tarafından resmi olarak onaylandıktan sonra girmelerine izin vererek korumanıza izin verir.",
|
||||
"enterPasswordButton": "Toplantı şifresini girin",
|
||||
"enterPasswordTitle": "Toplantıya katılmak için şifre girin",
|
||||
"invalidPassword": "Geçersiz şifre",
|
||||
"enterPasswordButton": "Toplantı parolasını girin",
|
||||
"enterPasswordTitle": "Toplantıya katılmak için parola girin",
|
||||
"invalidPassword": "Geçersiz parola",
|
||||
"joiningMessage": "Birisi isteğinizi kabul eder etmez toplantıya katılacaksınız",
|
||||
"joinWithPasswordMessage": "Şifre ile katılmaya çalışıyorsunuz lütfen bekleyin...",
|
||||
"joinWithPasswordMessage": "Parola ile katılmaya çalışıyorsunuz lütfen bekleyin...",
|
||||
"joinRejectedMessage": "Katılma isteğiniz bir moderatör tarafından reddedildi.",
|
||||
"joinTitle": "Toplantıya katıl",
|
||||
"joiningTitle": "Toplantıya katılma isteniyor...",
|
||||
"joiningWithPasswordTitle": "Şifre ile katılıyor...",
|
||||
"joiningWithPasswordTitle": "Parola ile katılıyor...",
|
||||
"knockButton": "Katılmak için sor",
|
||||
"knockTitle": "Birisi toplantıya katılmak istiyor",
|
||||
"nameField": "Adınızı giriniz",
|
||||
"passwordField": "Toplantı şifresini giriniz",
|
||||
"passwordField": "Toplantı parolasını giriniz",
|
||||
"passwordJoinButton": "Katıl",
|
||||
"reject": "Reddet",
|
||||
"toggleLabel": "Lobiyi etkinleştir"
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
},
|
||||
"connectionindicator": {
|
||||
"address": "Address:",
|
||||
"audio_ssrc": "Audio SSRC:",
|
||||
"bandwidth": "Estimated bandwidth:",
|
||||
"bitrate": "Bitrate:",
|
||||
"bridgeCount": "Server count: ",
|
||||
@@ -126,9 +127,12 @@
|
||||
"remoteport": "Remote port:",
|
||||
"remoteport_plural": "Remote ports:",
|
||||
"resolution": "Resolution:",
|
||||
"savelogs": "Save logs",
|
||||
"participant_id": "Participant id:",
|
||||
"status": "Connection:",
|
||||
"transport": "Transport:",
|
||||
"transport_plural": "Transports:"
|
||||
"transport_plural": "Transports:",
|
||||
"video_ssrc": "Video SSRC:"
|
||||
},
|
||||
"dateUtils": {
|
||||
"earlier": "Earlier",
|
||||
@@ -197,10 +201,7 @@
|
||||
"displayNameRequired": "Hi! What’s your name?",
|
||||
"done": "Done",
|
||||
"e2eeDescription": "End-to-End Encryption is currently EXPERIMENTAL. Please keep in mind that turning on end-to-end encryption will effectively disable server-side provided services such as: recording, live streaming and phone participation. Also keep in mind that the meeting will only work for people joining from browsers with support for insertable streams.",
|
||||
"e2eeLabel": "E2EE key",
|
||||
"e2eeNoKey": "None",
|
||||
"e2eeToggleSet": "Set key",
|
||||
"e2eeSet": "Set",
|
||||
"e2eeLabel": "Enable End-to-End Encryption",
|
||||
"e2eeWarning": "WARNING: Not all participants in this meeting seem to have support for End-to-End encryption. If you enable it they won't be able to see nor hear you.",
|
||||
"enterDisplayName": "Please enter your name here",
|
||||
"error": "Error",
|
||||
@@ -365,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.",
|
||||
@@ -535,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",
|
||||
@@ -697,7 +698,6 @@
|
||||
"document": "Toggle shared document",
|
||||
"download": "Download our apps",
|
||||
"embedMeeting": "Embed meeting",
|
||||
"e2ee": "End-to-End Encryption",
|
||||
"feedback": "Leave feedback",
|
||||
"fullScreen": "Toggle full screen",
|
||||
"grantModerator": "Grant Moderator",
|
||||
@@ -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,13 +13,19 @@ 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
|
||||
} from '../../react/features/device-selection/functions';
|
||||
import { isEnabled as isDropboxEnabled } from '../../react/features/dropbox';
|
||||
import { setE2EEKey } from '../../react/features/e2ee';
|
||||
import { toggleE2EE } from '../../react/features/e2ee/actions';
|
||||
import { invite } from '../../react/features/invite';
|
||||
import {
|
||||
captureLargeVideoScreenshot,
|
||||
resizeLargeVideo,
|
||||
selectParticipantInLargeVideo
|
||||
} from '../../react/features/large-video/actions';
|
||||
import { toggleLobbyMode } from '../../react/features/lobby/actions.web';
|
||||
import { RECORDING_TYPES } from '../../react/features/recording/constants';
|
||||
import { getActiveSession } from '../../react/features/recording/functions';
|
||||
@@ -40,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.
|
||||
*
|
||||
@@ -115,14 +112,29 @@ function initCommands() {
|
||||
));
|
||||
}
|
||||
},
|
||||
'pin-participant': id => {
|
||||
logger.debug('Pin participant command received');
|
||||
sendAnalytics(createApiEvent('participant.pinned'));
|
||||
APP.store.dispatch(pinParticipant(id));
|
||||
},
|
||||
'proxy-connection-event': event => {
|
||||
APP.conference.onProxyConnectionEvent(event);
|
||||
},
|
||||
'resize-large-video': (width, height) => {
|
||||
logger.debug('Resize large video command received');
|
||||
sendAnalytics(createApiEvent('largevideo.resized'));
|
||||
APP.store.dispatch(resizeLargeVideo(width, height));
|
||||
},
|
||||
'send-tones': (options = {}) => {
|
||||
const { duration, tones, pause } = options;
|
||||
|
||||
APP.store.dispatch(sendTones(tones, duration, pause));
|
||||
},
|
||||
'set-large-video-participant': participantId => {
|
||||
logger.debug('Set large video participant command received');
|
||||
sendAnalytics(createApiEvent('largevideo.participant.set'));
|
||||
APP.store.dispatch(selectParticipantInLargeVideo(participantId));
|
||||
},
|
||||
'subject': subject => {
|
||||
sendAnalytics(createApiEvent('subject.changed'));
|
||||
APP.store.dispatch(setSubject(subject));
|
||||
@@ -191,9 +203,9 @@ function initCommands() {
|
||||
logger.error('Failed sending endpoint text message', err);
|
||||
}
|
||||
},
|
||||
'e2ee-key': key => {
|
||||
logger.debug('Set E2EE key command received');
|
||||
APP.store.dispatch(setE2EEKey(key));
|
||||
'toggle-e2ee': enabled => {
|
||||
logger.debug('Toggle E2EE key command received');
|
||||
APP.store.dispatch(toggleE2EE(enabled));
|
||||
},
|
||||
'set-video-quality': frameHeight => {
|
||||
logger.debug('Set video quality command received');
|
||||
@@ -202,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.
|
||||
@@ -210,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);
|
||||
|
||||
@@ -232,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;
|
||||
}
|
||||
@@ -265,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');
|
||||
@@ -328,6 +351,21 @@ function initCommands() {
|
||||
const { name } = request;
|
||||
|
||||
switch (name) {
|
||||
case 'capture-largevideo-screenshot' :
|
||||
APP.store.dispatch(captureLargeVideoScreenshot())
|
||||
.then(dataURL => {
|
||||
let error;
|
||||
|
||||
if (!dataURL) {
|
||||
error = new Error('No large video found!');
|
||||
}
|
||||
|
||||
callback({
|
||||
error,
|
||||
dataURL
|
||||
});
|
||||
});
|
||||
break;
|
||||
case 'invite': {
|
||||
const { invitees } = request;
|
||||
|
||||
@@ -383,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.
|
||||
*
|
||||
@@ -423,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');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,10 +484,6 @@ class API {
|
||||
*/
|
||||
this._enabled = true;
|
||||
|
||||
APP.conference.addListener(
|
||||
JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED,
|
||||
onDesktopSharingEnabledChanged);
|
||||
|
||||
initCommands();
|
||||
}
|
||||
|
||||
@@ -524,6 +543,19 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application that the video quality setting has changed.
|
||||
*
|
||||
* @param {number} videoQuality - The video quality. The number represents the maximum height of the video streams.
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyVideoQualityChanged(videoQuality: number) {
|
||||
this._sendEvent({
|
||||
name: 'video-quality-changed',
|
||||
videoQuality
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that message was
|
||||
* received.
|
||||
@@ -677,6 +709,21 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that the an error has been logged.
|
||||
*
|
||||
* @param {string} logLevel - The message log level.
|
||||
* @param {Array} args - Array of strings composing the log message.
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyLog(logLevel: string, args: Array<string>) {
|
||||
this._sendEvent({
|
||||
name: 'log',
|
||||
logLevel,
|
||||
args
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that the conference has
|
||||
* been joined.
|
||||
@@ -697,8 +744,7 @@ class API {
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that user changed their
|
||||
* nickname.
|
||||
* Notify external application (if API is enabled) that local user has left the conference.
|
||||
*
|
||||
* @param {string} roomName - User id.
|
||||
* @returns {void}
|
||||
@@ -963,6 +1009,19 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that the localStorage has changed.
|
||||
*
|
||||
* @param {string} localStorageContent - The new localStorageContent.
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyLocalStorageChanged(localStorageContent: string) {
|
||||
this._sendEvent({
|
||||
name: 'local-storage-changed',
|
||||
localStorageContent
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the allocated resources.
|
||||
*
|
||||
@@ -971,9 +1030,6 @@ class API {
|
||||
dispose() {
|
||||
if (this._enabled) {
|
||||
this._enabled = false;
|
||||
APP.conference.removeListener(
|
||||
JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED,
|
||||
onDesktopSharingEnabledChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
162
modules/API/external/external_api.js
vendored
162
modules/API/external/external_api.js
vendored
@@ -1,3 +1,4 @@
|
||||
import { jitsiLocalStorage } from '@jitsi/js-utils/jitsi-local-storage';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
import { urlObjectToString } from '../../../react/features/base/util/uri';
|
||||
@@ -35,8 +36,11 @@ const commands = {
|
||||
hangup: 'video-hangup',
|
||||
muteEveryone: 'mute-everyone',
|
||||
password: 'password',
|
||||
pinParticipant: 'pin-participant',
|
||||
resizeLargeVideo: 'resize-large-video',
|
||||
sendEndpointTextMessage: 'send-endpoint-text-message',
|
||||
sendTones: 'send-tones',
|
||||
setLargeVideoParticipant: 'set-large-video-participant',
|
||||
setVideoQuality: 'set-video-quality',
|
||||
startRecording: 'start-recording',
|
||||
stopRecording: 'stop-recording',
|
||||
@@ -67,6 +71,7 @@ const events = {
|
||||
'feedback-prompt-displayed': 'feedbackPromptDisplayed',
|
||||
'filmstrip-display-changed': 'filmstripDisplayChanged',
|
||||
'incoming-message': 'incomingMessage',
|
||||
'log': 'log',
|
||||
'mic-error': 'micError',
|
||||
'outgoing-message': 'outgoingMessage',
|
||||
'participant-joined': 'participantJoined',
|
||||
@@ -80,6 +85,7 @@ const events = {
|
||||
'video-conference-left': 'videoConferenceLeft',
|
||||
'video-availability-changed': 'videoAvailabilityChanged',
|
||||
'video-mute-status-changed': 'videoMuteStatusChanged',
|
||||
'video-quality-changed': 'videoQualityChanged',
|
||||
'screen-sharing-status-changed': 'screenSharingStatusChanged',
|
||||
'dominant-speaker-changed': 'dominantSpeakerChanged',
|
||||
'subject-change': 'subjectChange',
|
||||
@@ -263,6 +269,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
userInfo,
|
||||
e2eeKey
|
||||
} = parseArguments(args);
|
||||
const localStorageContent = jitsiLocalStorage.getItem('jitsiLocalStorage');
|
||||
|
||||
this._parentNode = parentNode;
|
||||
this._url = generateURL(domain, {
|
||||
@@ -272,7 +279,10 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
noSSL,
|
||||
roomName,
|
||||
devices,
|
||||
userInfo
|
||||
userInfo,
|
||||
appData: {
|
||||
localStorageContent
|
||||
}
|
||||
});
|
||||
this._createIFrame(height, width, onload);
|
||||
this._transport = new Transport({
|
||||
@@ -355,6 +365,19 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatted display name of a participant.
|
||||
*
|
||||
* @param {string} participantId - The id of the participant.
|
||||
* @returns {string} The formatted display name.
|
||||
*/
|
||||
_getFormattedDisplayName(participantId) {
|
||||
const { formattedDisplayName }
|
||||
= this._participants[participantId] || {};
|
||||
|
||||
return formattedDisplayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the on stage participant.
|
||||
*
|
||||
@@ -421,10 +444,12 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
const parsedWidth = parseSizeParam(width);
|
||||
|
||||
if (parsedHeight !== undefined) {
|
||||
this._height = height;
|
||||
this._frame.style.height = parsedHeight;
|
||||
}
|
||||
|
||||
if (parsedWidth !== undefined) {
|
||||
this._width = width;
|
||||
this._frame.style.width = parsedWidth;
|
||||
}
|
||||
}
|
||||
@@ -503,6 +528,14 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
changeParticipantNumber(this, -1);
|
||||
delete this._participants[this._myUserID];
|
||||
break;
|
||||
case 'video-quality-changed':
|
||||
this._videoQuality = data.videoQuality;
|
||||
break;
|
||||
case 'local-storage-changed':
|
||||
jitsiLocalStorage.setItem('jitsiLocalStorage', data.localStorageContent);
|
||||
|
||||
// Since this is internal event we don't need to emit it to the consumer of the API.
|
||||
return true;
|
||||
}
|
||||
|
||||
const eventName = events[name];
|
||||
@@ -538,6 +571,13 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
* the event and value - the listener.
|
||||
* Currently we support the following
|
||||
* events:
|
||||
* {@code log} - receives event notifications whenever information has
|
||||
* been logged and has a log level specified within {@code config.apiLogLevels}.
|
||||
* The listener will receive object with the following structure:
|
||||
* {{
|
||||
* logLevel: the message log level
|
||||
* arguments: an array of strings that compose the actual log message
|
||||
* }}
|
||||
* {@code incomingMessage} - receives event notifications about incoming
|
||||
* messages. The listener will receive object with the following structure:
|
||||
* {{
|
||||
@@ -607,6 +647,18 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures the screenshot of the large video.
|
||||
*
|
||||
* @returns {Promise<string>} - Resolves with a base64 encoded image data of the screenshot
|
||||
* if large video is detected, an error otherwise.
|
||||
*/
|
||||
captureLargeVideoScreenshot() {
|
||||
return this._transport.sendRequest({
|
||||
name: 'capture-largevideo-screenshot'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the listeners and removes the Jitsi Meet frame.
|
||||
*
|
||||
@@ -689,6 +741,32 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
return getCurrentDevices(this._transport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the conference participants information.
|
||||
*
|
||||
* @returns {Array<Object>} - Returns an array containing participants
|
||||
* information like participant id, display name, avatar URL and email.
|
||||
*/
|
||||
getParticipantsInfo() {
|
||||
const participantIds = Object.keys(this._participants);
|
||||
const participantsInfo = Object.values(this._participants);
|
||||
|
||||
participantsInfo.forEach((participant, idx) => {
|
||||
participant.participantId = participantIds[idx];
|
||||
});
|
||||
|
||||
return participantsInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current video quality setting.
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
getVideoQuality() {
|
||||
return this._videoQuality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the audio is available.
|
||||
*
|
||||
@@ -809,19 +887,6 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
return email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatted display name of a participant.
|
||||
*
|
||||
* @param {string} participantId - The id of the participant.
|
||||
* @returns {string} The formatted display name.
|
||||
*/
|
||||
_getFormattedDisplayName(participantId) {
|
||||
const { formattedDisplayName }
|
||||
= this._participants[participantId] || {};
|
||||
|
||||
return formattedDisplayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the iframe that loads Jitsi Meet.
|
||||
*
|
||||
@@ -865,6 +930,17 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Pins a participant's video on to the stage view.
|
||||
*
|
||||
* @param {string} participantId - Participant id (JID) of the participant
|
||||
* that needs to be pinned on the stage view.
|
||||
* @returns {void}
|
||||
*/
|
||||
pinParticipant(participantId) {
|
||||
this.executeCommand('pinParticipant', participantId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes event listener.
|
||||
*
|
||||
@@ -891,6 +967,19 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
eventList.forEach(event => this.removeEventListener(event));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes the large video container as per the dimensions provided.
|
||||
*
|
||||
* @param {number} width - Width that needs to be applied on the large video container.
|
||||
* @param {number} height - Height that needs to be applied on the large video container.
|
||||
* @returns {void}
|
||||
*/
|
||||
resizeLargeVideo(width, height) {
|
||||
if (width <= this._width && height <= this._height) {
|
||||
this.executeCommand('resizeLargeVideo', width, height);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes an event along to the local conference participant to establish
|
||||
* or update a direct peer connection. This is currently used for developing
|
||||
@@ -934,6 +1023,18 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
return setAudioOutputDevice(this._transport, label, deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the given participant on the large video. If no participant id is specified,
|
||||
* dominant and pinned speakers will be taken into consideration while selecting the
|
||||
* the large video participant.
|
||||
*
|
||||
* @param {string} participantId - Jid of the participant to be displayed on the large video.
|
||||
* @returns {void}
|
||||
*/
|
||||
setLargeVideoParticipant(participantId) {
|
||||
this.executeCommand('setLargeVideoParticipant', participantId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the video input device to the one with the label or id that is
|
||||
* passed.
|
||||
@@ -946,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,6 @@
|
||||
*/
|
||||
const UIUtil = {
|
||||
|
||||
/**
|
||||
* Returns the available video width.
|
||||
*/
|
||||
getAvailableVideoWidth() {
|
||||
return window.innerWidth;
|
||||
},
|
||||
|
||||
/**
|
||||
* Escapes the given text.
|
||||
*/
|
||||
|
||||
@@ -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,16 +12,16 @@ 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
|
||||
} from '../../../react/features/large-video';
|
||||
} from '../../../react/features/large-video/actions';
|
||||
import { PresenceLabel } from '../../../react/features/presence-status';
|
||||
/* eslint-enable no-unused-vars */
|
||||
import UIEvents from '../../../service/UI/UIEvents';
|
||||
import { createDeferred } from '../../util/helpers';
|
||||
import AudioLevels from '../audio_levels/AudioLevels';
|
||||
import UIUtil from '../util/UIUtil';
|
||||
|
||||
import { VideoContainer, VIDEO_CONTAINER_TYPE } from './VideoContainer';
|
||||
|
||||
@@ -68,7 +68,30 @@ export default class LargeVideoManager {
|
||||
// use the same video container to handle desktop tracks
|
||||
this.addContainer(DESKTOP_CONTAINER_TYPE, this.videoContainer);
|
||||
|
||||
/**
|
||||
* The preferred width passed as an argument to {@link updateContainerSize}.
|
||||
*
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.preferredWidth = undefined;
|
||||
|
||||
/**
|
||||
* The preferred height passed as an argument to {@link updateContainerSize}.
|
||||
*
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.preferredHeight = undefined;
|
||||
|
||||
/**
|
||||
* The calculated width that will be used for the large video.
|
||||
* @type {number}
|
||||
*/
|
||||
this.width = 0;
|
||||
|
||||
/**
|
||||
* The calculated height that will be used for the large video.
|
||||
* @type {number}
|
||||
*/
|
||||
this.height = 0;
|
||||
|
||||
/**
|
||||
@@ -202,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)
|
||||
@@ -323,8 +345,15 @@ export default class LargeVideoManager {
|
||||
/**
|
||||
* Update container size.
|
||||
*/
|
||||
updateContainerSize() {
|
||||
let widthToUse = UIUtil.getAvailableVideoWidth();
|
||||
updateContainerSize(width, height) {
|
||||
if (typeof width === 'number') {
|
||||
this.preferredWidth = width;
|
||||
}
|
||||
if (typeof height === 'number') {
|
||||
this.preferredHeight = height;
|
||||
}
|
||||
|
||||
let widthToUse = this.preferredWidth || window.innerWidth;
|
||||
const { isOpen } = APP.store.getState()['features/chat'];
|
||||
|
||||
if (isOpen) {
|
||||
@@ -336,7 +365,7 @@ export default class LargeVideoManager {
|
||||
}
|
||||
|
||||
this.width = widthToUse;
|
||||
this.height = window.innerHeight;
|
||||
this.height = this.preferredHeight || window.innerHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -450,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();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -481,7 +397,11 @@ export default class RemoteVideo extends SmallVideo {
|
||||
|
||||
const isVideo = stream.isVideoTrack();
|
||||
|
||||
isVideo ? this.videoStream = stream : this.audioStream = stream;
|
||||
if (isVideo) {
|
||||
this.videoStream = stream;
|
||||
} else {
|
||||
this.audioStream = stream;
|
||||
}
|
||||
|
||||
if (!stream.getOriginalStream()) {
|
||||
logger.debug('Remote video stream has no original stream');
|
||||
@@ -509,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>.
|
||||
@@ -541,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,58 +89,13 @@ export default class SmallVideo {
|
||||
* Constructor.
|
||||
*/
|
||||
constructor(VideoLayout) {
|
||||
this.isAudioMuted = false;
|
||||
this.isVideoMuted = false;
|
||||
this.videoStream = null;
|
||||
this.audioStream = null;
|
||||
this.VideoLayout = VideoLayout;
|
||||
this.videoIsHovered = false;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
this.videoType = undefined;
|
||||
|
||||
// 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);
|
||||
@@ -192,139 +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 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 }
|
||||
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.
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -341,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.
|
||||
@@ -440,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();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -450,8 +251,10 @@ export default class SmallVideo {
|
||||
* or <tt>DISPLAY_BLACKNESS_WITH_NAME</tt>.
|
||||
*/
|
||||
selectDisplayMode(input) {
|
||||
// Display name is always and only displayed when user is on the stage
|
||||
if (input.isCurrentlyOnLargeVideo && !input.tileViewActive) {
|
||||
if (!input.tileViewActive && input.isScreenSharing) {
|
||||
return input.isHovered ? DISPLAY_AVATAR_WITH_NAME : DISPLAY_AVATAR;
|
||||
} else if (input.isCurrentlyOnLargeVideo && !input.tileViewActive) {
|
||||
// Display name is always and only displayed when user is on the stage
|
||||
return input.isVideoPlayable && !input.isAudioOnly ? DISPLAY_BLACKNESS_WITH_NAME : DISPLAY_AVATAR_WITH_NAME;
|
||||
} else if (input.isVideoPlayable && input.hasVideo && !input.isAudioOnly) {
|
||||
// check hovering and change state to video with name
|
||||
@@ -468,18 +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,
|
||||
videoStreamMuted: this.videoStream ? this.videoStream.isMuted() : 'no stream'
|
||||
};
|
||||
}
|
||||
@@ -491,7 +308,7 @@ export default class SmallVideo {
|
||||
* @private
|
||||
*/
|
||||
_isHovered() {
|
||||
return this.videoIsHovered || this._popoverIsHovered;
|
||||
return this.videoIsHovered;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -538,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.
|
||||
@@ -591,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -645,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) {
|
||||
@@ -672,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.
|
||||
@@ -800,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -838,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: {
|
||||
@@ -851,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`,
|
||||
@@ -859,10 +511,6 @@ export default class SmallVideo {
|
||||
'min-width': `${width}px`,
|
||||
width: `${width}px`
|
||||
});
|
||||
this.$avatar().css({
|
||||
height: `${avatarSize}px`,
|
||||
width: `${avatarSize}px`
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -872,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`,
|
||||
@@ -880,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,10 +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());
|
||||
if (stream.getType() !== 'audio') {
|
||||
this.onVideoMute(id);
|
||||
remoteVideo.updateView();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -188,6 +168,7 @@ const VideoLayout = {
|
||||
|
||||
if (remoteVideo) {
|
||||
remoteVideo.removeRemoteStreamElement(stream);
|
||||
remoteVideo.updateView();
|
||||
}
|
||||
|
||||
this.updateMutedForNoTracks(id, stream.getType());
|
||||
@@ -208,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}`);
|
||||
}
|
||||
@@ -327,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,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.
|
||||
*
|
||||
@@ -409,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();
|
||||
}
|
||||
},
|
||||
@@ -451,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) {
|
||||
@@ -485,13 +412,14 @@ const VideoLayout = {
|
||||
},
|
||||
|
||||
onVideoTypeChanged(id, newVideoType) {
|
||||
if (VideoLayout.getRemoteVideoType(id) === newVideoType) {
|
||||
const remoteVideo = remoteVideos[id];
|
||||
|
||||
if (!remoteVideo) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info('Peer video type changed: ', id, newVideoType);
|
||||
|
||||
this._updateLargeVideoIfDisplayed(id, true);
|
||||
remoteVideo.updateView();
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -514,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);
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ export default {
|
||||
})
|
||||
.catch(err => {
|
||||
audioTrackError = err;
|
||||
showError && APP.store.disptach(notifyMicError(err));
|
||||
showError && APP.store.dispatch(notifyMicError(err));
|
||||
|
||||
return [];
|
||||
}));
|
||||
|
||||
@@ -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.');
|
||||
|
||||
2398
package-lock.json
generated
2398
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
32
package.json
32
package.json
@@ -32,7 +32,7 @@
|
||||
"@atlaskit/theme": "7.0.2",
|
||||
"@atlaskit/toggle": "5.0.14",
|
||||
"@atlaskit/tooltip": "12.1.13",
|
||||
"@jitsi/js-utils": "1.0.1",
|
||||
"@jitsi/js-utils": "1.0.2",
|
||||
"@microsoft/microsoft-graph-client": "1.1.0",
|
||||
"@react-native-community/async-storage": "1.3.4",
|
||||
"@react-native-community/google-signin": "3.0.1",
|
||||
@@ -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": "4.5.2",
|
||||
"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,20 +56,22 @@
|
||||
"jquery-i18next": "1.2.1",
|
||||
"js-md5": "0.6.1",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#65df5b1da6bb6934e9d42f50d95aae0df6a5fd90",
|
||||
"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.2.1.tgz",
|
||||
"pixelmatch": "5.1.0",
|
||||
"punycode": "2.1.1",
|
||||
"react": "16.9",
|
||||
"react-dom": "16.9",
|
||||
"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-background-timer": "2.1.1",
|
||||
"react-native-calendar-events": "github:jitsi/react-native-calendar-events#928a80e2ffef0d7e84936d7e7e0acc4f53ee8470",
|
||||
"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",
|
||||
"react-native-collapsible": "1.5.1",
|
||||
"react-native-default-preference": "1.4.2",
|
||||
@@ -77,20 +79,22 @@
|
||||
"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-webview": "7.4.1",
|
||||
"react-native-webrtc": "1.84.1",
|
||||
"react-native-webview": "10.9.0",
|
||||
"react-native-youtube-iframe": "1.2.3",
|
||||
"react-redux": "7.1.0",
|
||||
"react-textarea-autosize": "7.1.0",
|
||||
"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",
|
||||
"util": "0.12.1",
|
||||
"uuid": "3.1.0",
|
||||
@@ -127,7 +131,7 @@
|
||||
"imports-loader": "0.7.1",
|
||||
"jetifier": "1.6.4",
|
||||
"metro-react-native-babel-preset": "0.56.0",
|
||||
"node-sass": "4.14.1",
|
||||
"sass": "1.26.8",
|
||||
"string-replace-loader": "2.1.1",
|
||||
"style-loader": "0.19.0",
|
||||
"unorm": "1.6.0",
|
||||
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -57,12 +57,15 @@ export function resetAnalytics() {
|
||||
* @param {Store} store - The redux store in which the specified {@code action} is being dispatched.
|
||||
* @returns {Promise} Resolves with the handlers that have been successfully loaded.
|
||||
*/
|
||||
export function createHandlers({ getState }: { getState: Function }) {
|
||||
export async function createHandlers({ getState }: { getState: Function }) {
|
||||
getJitsiMeetGlobalNS().analyticsHandlers = [];
|
||||
window.analyticsHandlers = []; // Legacy support.
|
||||
|
||||
if (!isAnalyticsEnabled(getState)) {
|
||||
return Promise.resolve([]);
|
||||
// Avoid all analytics processing if there are no handlers, since no event would be sent.
|
||||
analytics.dispose();
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
const state = getState();
|
||||
@@ -100,43 +103,47 @@ export function createHandlers({ getState }: { getState: Function }) {
|
||||
};
|
||||
const handlers = [];
|
||||
|
||||
try {
|
||||
const amplitude = new AmplitudeHandler(handlerConstructorOptions);
|
||||
if (amplitudeAPPKey) {
|
||||
try {
|
||||
const amplitude = new AmplitudeHandler(handlerConstructorOptions);
|
||||
|
||||
analytics.amplitudeIdentityProps = amplitude.getIdentityProps();
|
||||
analytics.amplitudeIdentityProps = amplitude.getIdentityProps();
|
||||
|
||||
handlers.push(amplitude);
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (e) {}
|
||||
handlers.push(amplitude);
|
||||
} catch (e) {
|
||||
logger.error('Failed to initialize Amplitude handler', e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const matomo = new MatomoHandler(handlerConstructorOptions);
|
||||
if (matomoEndpoint && matomoSiteID) {
|
||||
try {
|
||||
const matomo = new MatomoHandler(handlerConstructorOptions);
|
||||
|
||||
handlers.push(matomo);
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (e) {}
|
||||
handlers.push(matomo);
|
||||
} catch (e) {
|
||||
logger.error('Failed to initialize Matomo handler', e);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
_loadHandlers(scriptURLs, handlerConstructorOptions)
|
||||
.then(externalHandlers => {
|
||||
handlers.push(...externalHandlers);
|
||||
if (handlers.length === 0) {
|
||||
// Throwing an error in order to dispose the analytics in the catch clause due to the lack of any
|
||||
// analytics handlers.
|
||||
throw new Error('No analytics handlers created!');
|
||||
}
|
||||
if (Array.isArray(scriptURLs) && scriptURLs.length > 0) {
|
||||
let externalHandlers;
|
||||
|
||||
return handlers;
|
||||
})
|
||||
.catch(e => {
|
||||
analytics.dispose();
|
||||
if (handlers.length !== 0) {
|
||||
logger.error(e);
|
||||
}
|
||||
try {
|
||||
externalHandlers = await _loadHandlers(scriptURLs, handlerConstructorOptions);
|
||||
handlers.push(...externalHandlers);
|
||||
} catch (e) {
|
||||
logger.error('Failed to initialize external analytics handlers', e);
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}));
|
||||
// Avoid all analytics processing if there are no handlers, since no event would be sent.
|
||||
if (handlers.length === 0) {
|
||||
analytics.dispose();
|
||||
}
|
||||
|
||||
logger.info(`Initialized ${handlers.length} analytics handlers`);
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,7 +235,7 @@ function _inIframe() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to load the scripts for the analytics handlers and creates them.
|
||||
* Tries to load the scripts for the external analytics handlers and creates them.
|
||||
*
|
||||
* @param {Array} scriptURLs - The array of script urls to load.
|
||||
* @param {Object} handlerConstructorOptions - The default options to pass when creating handlers.
|
||||
@@ -279,7 +286,7 @@ function _loadHandlers(scriptURLs = [], handlerConstructorOptions) {
|
||||
logger.warn(`Error creating analytics handler: ${error}`);
|
||||
}
|
||||
}
|
||||
logger.debug(`Loaded ${handlers.length} analytics handlers`);
|
||||
logger.debug(`Loaded ${handlers.length} external analytics handlers`);
|
||||
|
||||
return handlers;
|
||||
});
|
||||
|
||||
@@ -72,6 +72,11 @@ export default class AmplitudeHandler extends AbstractHandler {
|
||||
* @returns {Object}
|
||||
*/
|
||||
getIdentityProps() {
|
||||
// TODO: Remove when web and native Aplitude implementations are unified.
|
||||
if (navigator.product === 'ReactNative') {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
sessionId: amplitude.getInstance(this._amplitudeOptions).getSessionId(),
|
||||
deviceId: amplitude.getInstance(this._amplitudeOptions).options.deviceId,
|
||||
|
||||
@@ -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.
|
||||
@@ -294,6 +294,8 @@ export function maybeRedirectToWelcomePage(options: Object = {}) {
|
||||
if (enableClosePage) {
|
||||
if (isVpaasMeeting(getState())) {
|
||||
redirectToStaticPage('/');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const { isGuest, jwt } = getState()['features/base/jwt'];
|
||||
|
||||
@@ -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,12 +24,14 @@ 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';
|
||||
import '../deep-linking/reducer';
|
||||
import '../device-selection/reducer';
|
||||
import '../dropbox/reducer';
|
||||
import '../dynamic-branding/reducer';
|
||||
import '../etherpad/reducer';
|
||||
import '../filmstrip/reducer';
|
||||
import '../follow-me/reducer';
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import { IconShareDesktop } from '../../icons';
|
||||
import { getParticipantById } from '../../participants';
|
||||
import { connect } from '../../redux';
|
||||
import { getAvatarColor, getInitials } from '../functions';
|
||||
@@ -38,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.
|
||||
*/
|
||||
@@ -79,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}.
|
||||
*
|
||||
@@ -124,6 +137,7 @@ class Avatar<P: Props> extends PureComponent<P, State> {
|
||||
_loadableAvatarUrl,
|
||||
className,
|
||||
colorBase,
|
||||
dynamicColor,
|
||||
id,
|
||||
size,
|
||||
status,
|
||||
@@ -157,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;
|
||||
}
|
||||
|
||||
@@ -192,17 +209,10 @@ export function _mapStateToProps(state: Object, ownProps: Props) {
|
||||
const { colorBase, displayName, participantId } = ownProps;
|
||||
const _participant: ?Object = participantId && getParticipantById(state, participantId);
|
||||
const _initialsBase = _participant?.name ?? displayName;
|
||||
const screenShares = state['features/video-layout'].screenShares || [];
|
||||
|
||||
let _loadableAvatarUrl = _participant?.loadableAvatarUrl;
|
||||
|
||||
if (participantId && screenShares.includes(participantId)) {
|
||||
_loadableAvatarUrl = IconShareDesktop;
|
||||
}
|
||||
|
||||
return {
|
||||
_initialsBase,
|
||||
_loadableAvatarUrl,
|
||||
_loadableAvatarUrl: _participant?.loadableAvatarUrl,
|
||||
colorBase: !colorBase && _participant ? _participant.id : colorBase
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -163,19 +151,6 @@ export const SET_DESKTOP_SHARING_ENABLED
|
||||
*/
|
||||
export const SET_FOLLOW_ME = 'SET_FOLLOW_ME';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which sets the maximum video height that should be
|
||||
* received from remote participants, even if the user prefers a larger video
|
||||
* height.
|
||||
*
|
||||
* {
|
||||
* type: SET_MAX_RECEIVER_VIDEO_QUALITY,
|
||||
* maxReceiverVideoQuality: number
|
||||
* }
|
||||
*/
|
||||
export const SET_MAX_RECEIVER_VIDEO_QUALITY
|
||||
= 'SET_MAX_RECEIVER_VIDEO_QUALITY';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which sets the password to join or lock a specific
|
||||
* {@code JitsiConference}.
|
||||
@@ -210,17 +185,6 @@ export const SET_PASSWORD_FAILED = 'SET_PASSWORD_FAILED';
|
||||
*/
|
||||
export const SET_PENDING_SUBJECT_CHANGE = 'SET_PENDING_SUBJECT_CHANGE';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which sets the preferred maximum video height that
|
||||
* should be sent to and received from remote participants.
|
||||
*
|
||||
* {
|
||||
* type: SET_PREFERRED_VIDEO_QUALITY,
|
||||
* preferredVideoQuality: number
|
||||
* }
|
||||
*/
|
||||
export const SET_PREFERRED_VIDEO_QUALITY = 'SET_PREFERRED_VIDEO_QUALITY';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which sets the name of the room of the
|
||||
* conference to be joined.
|
||||
|
||||
@@ -43,18 +43,14 @@ import {
|
||||
LOCK_STATE_CHANGED,
|
||||
P2P_STATUS_CHANGED,
|
||||
SEND_TONES,
|
||||
SET_DESKTOP_SHARING_ENABLED,
|
||||
SET_FOLLOW_ME,
|
||||
SET_MAX_RECEIVER_VIDEO_QUALITY,
|
||||
SET_PASSWORD,
|
||||
SET_PASSWORD_FAILED,
|
||||
SET_PREFERRED_VIDEO_QUALITY,
|
||||
SET_ROOM,
|
||||
SET_PENDING_SUBJECT_CHANGE,
|
||||
SET_START_MUTED_POLICY
|
||||
} from './actionTypes';
|
||||
import {
|
||||
AVATAR_ID_COMMAND,
|
||||
AVATAR_URL_COMMAND,
|
||||
EMAIL_COMMAND,
|
||||
JITSI_CONFERENCE_URL_KEY
|
||||
@@ -200,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({
|
||||
@@ -583,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.
|
||||
*
|
||||
@@ -615,23 +588,6 @@ export function setFollowMe(enabled: boolean) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the max frame height that should be received from remote videos.
|
||||
*
|
||||
* @param {number} maxReceiverVideoQuality - The max video frame height to
|
||||
* receive.
|
||||
* @returns {{
|
||||
* type: SET_MAX_RECEIVER_VIDEO_QUALITY,
|
||||
* maxReceiverVideoQuality: number
|
||||
* }}
|
||||
*/
|
||||
export function setMaxReceiverVideoQuality(maxReceiverVideoQuality: number) {
|
||||
return {
|
||||
type: SET_MAX_RECEIVER_VIDEO_QUALITY,
|
||||
maxReceiverVideoQuality
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password to join or lock a specific JitsiConference.
|
||||
*
|
||||
@@ -698,24 +654,6 @@ export function setPassword(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the max frame height the user prefers to send and receive from the
|
||||
* remote participants.
|
||||
*
|
||||
* @param {number} preferredVideoQuality - The max video resolution to send and
|
||||
* receive.
|
||||
* @returns {{
|
||||
* type: SET_PREFERRED_VIDEO_QUALITY,
|
||||
* preferredVideoQuality: number
|
||||
* }}
|
||||
*/
|
||||
export function setPreferredVideoQuality(preferredVideoQuality: number) {
|
||||
return {
|
||||
type: SET_PREFERRED_VIDEO_QUALITY,
|
||||
preferredVideoQuality
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (the name of) the room of the conference to be joined.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -34,15 +27,3 @@ export const EMAIL_COMMAND = 'email';
|
||||
* from the outside is not cool but it should suffice for now.
|
||||
*/
|
||||
export const JITSI_CONFERENCE_URL_KEY = Symbol('url');
|
||||
|
||||
/**
|
||||
* The supported remote video resolutions. The values are currently based on
|
||||
* available simulcast layers.
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
export const VIDEO_QUALITY_LEVELS = {
|
||||
HIGH: 720,
|
||||
STANDARD: 360,
|
||||
LOW: 180
|
||||
};
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
PARTICIPANT_UPDATED,
|
||||
PIN_PARTICIPANT
|
||||
} from '../participants';
|
||||
import { MiddlewareRegistry, StateListenerRegistry } from '../redux';
|
||||
import { MiddlewareRegistry } from '../redux';
|
||||
import { TRACK_ADDED, TRACK_REMOVED } from '../tracks';
|
||||
|
||||
import {
|
||||
@@ -28,7 +28,6 @@ import {
|
||||
CONFERENCE_JOINED,
|
||||
CONFERENCE_SUBJECT_CHANGED,
|
||||
CONFERENCE_WILL_LEAVE,
|
||||
DATA_CHANNEL_OPENED,
|
||||
SEND_TONES,
|
||||
SET_PENDING_SUBJECT_CHANGE,
|
||||
SET_ROOM
|
||||
@@ -81,9 +80,6 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
_conferenceWillLeave();
|
||||
break;
|
||||
|
||||
case DATA_CHANNEL_OPENED:
|
||||
return _syncReceiveVideoQuality(store, next, action);
|
||||
|
||||
case PARTICIPANT_UPDATED:
|
||||
return _updateLocalParticipantInConference(store, next, action);
|
||||
|
||||
@@ -104,31 +100,6 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
return next(action);
|
||||
});
|
||||
|
||||
/**
|
||||
* Registers a change handler for state['features/base/conference'] to update
|
||||
* the preferred video quality levels based on user preferred and internal
|
||||
* settings.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
/* selector */ state => state['features/base/conference'],
|
||||
/* listener */ (currentState, store, previousState = {}) => {
|
||||
const {
|
||||
conference,
|
||||
maxReceiverVideoQuality,
|
||||
preferredVideoQuality
|
||||
} = currentState;
|
||||
const changedConference = conference !== previousState.conference;
|
||||
const changedPreferredVideoQuality
|
||||
= preferredVideoQuality !== previousState.preferredVideoQuality;
|
||||
const changedMaxVideoQuality = maxReceiverVideoQuality !== previousState.maxReceiverVideoQuality;
|
||||
|
||||
if (changedConference || changedPreferredVideoQuality || changedMaxVideoQuality) {
|
||||
_setReceiverVideoConstraint(conference, preferredVideoQuality, maxReceiverVideoQuality);
|
||||
}
|
||||
if (changedConference || changedPreferredVideoQuality) {
|
||||
_setSenderVideoConstraint(conference, preferredVideoQuality);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Makes sure to leave a failed conference in order to release any allocated
|
||||
@@ -157,9 +128,6 @@ function _conferenceFailed({ dispatch, getState }, next, action) {
|
||||
titleKey: 'dialog.sessTerminated'
|
||||
}));
|
||||
|
||||
if (typeof APP !== 'undefined') {
|
||||
APP.UI.hideStats();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JitsiConferenceErrors.CONNECTION_ERROR: {
|
||||
@@ -448,44 +416,6 @@ function _sendTones({ getState }, next, action) {
|
||||
return next(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for updating the preferred receiver video constraint, based
|
||||
* on the user preference and the internal maximum.
|
||||
*
|
||||
* @param {JitsiConference} conference - The JitsiConference instance for the
|
||||
* current call.
|
||||
* @param {number} preferred - The user preferred max frame height.
|
||||
* @param {number} max - The maximum frame height the application should
|
||||
* receive.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _setReceiverVideoConstraint(conference, preferred, max) {
|
||||
if (conference) {
|
||||
const value = Math.min(preferred, max);
|
||||
|
||||
conference.setReceiverVideoConstraint(value);
|
||||
logger.info(`setReceiverVideoConstraint: ${value}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for updating the preferred sender video constraint, based
|
||||
* on the user preference.
|
||||
*
|
||||
* @param {JitsiConference} conference - The JitsiConference instance for the
|
||||
* current call.
|
||||
* @param {number} preferred - The user preferred max frame height.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _setSenderVideoConstraint(conference, preferred) {
|
||||
if (conference) {
|
||||
conference.setSenderVideoConstraint(preferred)
|
||||
.catch(err => {
|
||||
logger.error(`Changing sender resolution to ${preferred} failed - ${err} `);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the feature base/conference that the action
|
||||
* {@code SET_ROOM} is being dispatched within a specific
|
||||
@@ -539,33 +469,6 @@ function _syncConferenceLocalTracksWithState({ getState }, action) {
|
||||
return promise || Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum receive video quality.
|
||||
*
|
||||
* @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} to the specified {@code store}.
|
||||
* @param {Action} action - The redux action {@code DATA_CHANNEL_STATUS_CHANGED}
|
||||
* which is being dispatched in the specified {@code store}.
|
||||
* @private
|
||||
* @returns {Object} The value returned by {@code next(action)}.
|
||||
*/
|
||||
function _syncReceiveVideoQuality({ getState }, next, action) {
|
||||
const {
|
||||
conference,
|
||||
maxReceiverVideoQuality,
|
||||
preferredVideoQuality
|
||||
} = getState()['features/base/conference'];
|
||||
|
||||
_setReceiverVideoConstraint(
|
||||
conference,
|
||||
preferredVideoQuality,
|
||||
maxReceiverVideoQuality);
|
||||
|
||||
return next(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the feature base/conference that the action {@code TRACK_ADDED}
|
||||
* or {@code TRACK_REMOVED} is being dispatched within a specific redux store.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user