mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-05-30 12:27:47 +00:00
Compare commits
159 Commits
6147
...
new-mobile
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5916cdb3a | ||
|
|
9a99c517ab | ||
|
|
40a6240444 | ||
|
|
4d6ca4383f | ||
|
|
ddce2e6bec | ||
|
|
7dca91a50a | ||
|
|
31348179d4 | ||
|
|
e77679d025 | ||
|
|
44a9363f5b | ||
|
|
bb76090bce | ||
|
|
d0790736db | ||
|
|
0308ba71b1 | ||
|
|
f7d1a5ec80 | ||
|
|
d61fe58fcf | ||
|
|
b428ce2dcd | ||
|
|
d1c9720033 | ||
|
|
c29e8bbdd1 | ||
|
|
3fb3be9727 | ||
|
|
517ec29d85 | ||
|
|
6ad279f029 | ||
|
|
0e98f90205 | ||
|
|
2c5b132483 | ||
|
|
4d8f29d4fe | ||
|
|
22be96d838 | ||
|
|
ccc1157df5 | ||
|
|
f613126776 | ||
|
|
38b21e986d | ||
|
|
38abca8a65 | ||
|
|
f3c6b54ffa | ||
|
|
7dd85bb6ad | ||
|
|
624f88e069 | ||
|
|
fbf693b2dc | ||
|
|
dbf7bf4750 | ||
|
|
d31eb3b248 | ||
|
|
9b75fc98c1 | ||
|
|
1ee9f6a7e5 | ||
|
|
06d0cbd418 | ||
|
|
066dd71afb | ||
|
|
d573bd41b4 | ||
|
|
d06d190229 | ||
|
|
d3b650c741 | ||
|
|
4a04b8b5ee | ||
|
|
6718ba7423 | ||
|
|
e662433c2a | ||
|
|
08bb957672 | ||
|
|
78d8176cc8 | ||
|
|
59ee984e09 | ||
|
|
f6fab051ce | ||
|
|
f0ff6a9f1c | ||
|
|
dfa761b963 | ||
|
|
ad8cdcd81b | ||
|
|
98ef0e74d6 | ||
|
|
746fde7c10 | ||
|
|
bedddd4760 | ||
|
|
7ea78e9845 | ||
|
|
9383942cb9 | ||
|
|
2f1fe637ca | ||
|
|
15d453de1d | ||
|
|
a272995b8c | ||
|
|
10b800e57f | ||
|
|
ca77563bf1 | ||
|
|
44ff1aac11 | ||
|
|
79e648867d | ||
|
|
fc725c07e9 | ||
|
|
d49c86bd5f | ||
|
|
aee94ad6fb | ||
|
|
38011e537a | ||
|
|
13194ddfba | ||
|
|
7895abb9ea | ||
|
|
9060bebca9 | ||
|
|
38724458e3 | ||
|
|
1bce1524db | ||
|
|
def3c76e10 | ||
|
|
5be770cad1 | ||
|
|
dd867b2a92 | ||
|
|
958ffb3076 | ||
|
|
bab3c4abc4 | ||
|
|
1f342b79a8 | ||
|
|
3af782f894 | ||
|
|
e27069447b | ||
|
|
7ac573d628 | ||
|
|
b3db9ce6cf | ||
|
|
1397b9ac80 | ||
|
|
de294cae92 | ||
|
|
5cef3dc1ba | ||
|
|
1dce802031 | ||
|
|
11d61d6d7d | ||
|
|
b5f3cd14c2 | ||
|
|
f87ce0defe | ||
|
|
201ff8f1da | ||
|
|
0c44b9a478 | ||
|
|
9dba1d30b0 | ||
|
|
ad70f12cb4 | ||
|
|
6ea7ab2b46 | ||
|
|
0ef71f4368 | ||
|
|
ae565aaac6 | ||
|
|
7e942173aa | ||
|
|
e1b87c48bc | ||
|
|
8cd259c43f | ||
|
|
d2d2507e86 | ||
|
|
f3f9cd3d05 | ||
|
|
543f273792 | ||
|
|
d9eedb0dad | ||
|
|
7f2fec756d | ||
|
|
607021a890 | ||
|
|
b4febf728d | ||
|
|
769f0a8452 | ||
|
|
f5004a2a0c | ||
|
|
a707022d0b | ||
|
|
43b0118ff8 | ||
|
|
97ca3fb622 | ||
|
|
ffa55cca1e | ||
|
|
0098091a37 | ||
|
|
6c1cb5d4be | ||
|
|
8240c3703e | ||
|
|
35572700bf | ||
|
|
5df774c569 | ||
|
|
8a503e7b40 | ||
|
|
4f49cde73e | ||
|
|
ea5ce3f72f | ||
|
|
5152638529 | ||
|
|
e4b50ba419 | ||
|
|
05127467c2 | ||
|
|
420c7c87e3 | ||
|
|
c23d38807a | ||
|
|
fb6f38800b | ||
|
|
4fb698ea04 | ||
|
|
ebe81e2835 | ||
|
|
c4106b8d89 | ||
|
|
4a350df695 | ||
|
|
0638d9d303 | ||
|
|
0fe7383154 | ||
|
|
9d7b6cafc5 | ||
|
|
39d30ea0b4 | ||
|
|
1400b6ff0a | ||
|
|
3fc3a217eb | ||
|
|
6068a30488 | ||
|
|
36578696bb | ||
|
|
64d44f0ac2 | ||
|
|
5f2147f40f | ||
|
|
084f911699 | ||
|
|
01bd18b86a | ||
|
|
e6ce5fd75f | ||
|
|
0c021868b5 | ||
|
|
adef5095da | ||
|
|
61abf0d882 | ||
|
|
e628d99544 | ||
|
|
f34dde3376 | ||
|
|
94e39e19b2 | ||
|
|
d1ac4ea637 | ||
|
|
0b57bcb20b | ||
|
|
a7abe84479 | ||
|
|
bb0d3b4c66 | ||
|
|
5b86182f94 | ||
|
|
3ab47ff96c | ||
|
|
e1706e7868 | ||
|
|
8434dda6e5 | ||
|
|
346aadc23d | ||
|
|
b872ea855e |
@@ -3,11 +3,9 @@ build/*
|
||||
|
||||
# Third-party source code which we (1) do not want to modify or (2) try to
|
||||
# modify as little as possible.
|
||||
flow-typed/*
|
||||
libs/*
|
||||
resources/*
|
||||
react/features/stream-effects/virtual-background/vendor/*
|
||||
load-test/*
|
||||
react/features/face-landmarks/resources/*
|
||||
|
||||
# ESLint will by default ignore its own configuration file. However, there does
|
||||
|
||||
15
Makefile
15
Makefile
@@ -7,7 +7,7 @@ TF_WASM_DIR = node_modules/@tensorflow/tfjs-backend-wasm/dist/
|
||||
RNNOISE_WASM_DIR = node_modules/rnnoise-wasm/dist
|
||||
TFLITE_WASM = react/features/stream-effects/virtual-background/vendor/tflite
|
||||
MEET_MODELS_DIR = react/features/stream-effects/virtual-background/vendor/models
|
||||
FACE_MODELS_DIR = node_modules/@vladmandic/face-api/model
|
||||
FACE_MODELS_DIR = node_modules/@vladmandic/human-models/models
|
||||
NODE_SASS = ./node_modules/.bin/sass
|
||||
NPM = npm
|
||||
OUTPUT_DIR = .
|
||||
@@ -19,12 +19,9 @@ WEBPACK_DEV_SERVER = ./node_modules/.bin/webpack serve --mode development
|
||||
|
||||
all: compile deploy clean
|
||||
|
||||
compile: compile-load-test
|
||||
compile:
|
||||
$(WEBPACK)
|
||||
|
||||
compile-load-test:
|
||||
${NPM} install --prefix resources/load-test && ${NPM} run build --prefix resources/load-test
|
||||
|
||||
clean:
|
||||
rm -fr $(BUILD_DIR)
|
||||
|
||||
@@ -94,10 +91,10 @@ deploy-meet-models:
|
||||
|
||||
deploy-face-landmarks:
|
||||
cp \
|
||||
$(FACE_MODELS_DIR)/tiny_face_detector_model-weights_manifest.json \
|
||||
$(FACE_MODELS_DIR)/tiny_face_detector_model.bin \
|
||||
$(FACE_MODELS_DIR)/face_expression_model-weights_manifest.json \
|
||||
$(FACE_MODELS_DIR)/face_expression_model.bin \
|
||||
$(FACE_MODELS_DIR)/blazeface-front.bin \
|
||||
$(FACE_MODELS_DIR)/blazeface-front.json \
|
||||
$(FACE_MODELS_DIR)/emotion.bin \
|
||||
$(FACE_MODELS_DIR)/emotion.json \
|
||||
$(DEPLOY_DIR)
|
||||
|
||||
deploy-css:
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<resources>
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:navigationBarColor">@color/colorPrimaryDark</item>
|
||||
<item name="android:windowDisablePreview">true</item>
|
||||
</style>
|
||||
|
||||
@@ -26,5 +26,5 @@ android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
android.bundle.enableUncompressedNativeLibs=false
|
||||
|
||||
appVersion=22.2.0
|
||||
sdkVersion=5.1.0
|
||||
appVersion=22.3.0
|
||||
sdkVersion=5.2.0
|
||||
|
||||
@@ -76,7 +76,8 @@ public class BroadcastAction {
|
||||
OPEN_CHAT("org.jitsi.meet.OPEN_CHAT"),
|
||||
CLOSE_CHAT("org.jitsi.meet.CLOSE_CHAT"),
|
||||
SEND_CHAT_MESSAGE("org.jitsi.meet.SEND_CHAT_MESSAGE"),
|
||||
SET_VIDEO_MUTED("org.jitsi.meet.SET_VIDEO_MUTED");
|
||||
SET_VIDEO_MUTED("org.jitsi.meet.SET_VIDEO_MUTED"),
|
||||
SET_CLOSED_CAPTIONS_ENABLED("org.jitsi.meet.SET_CLOSED_CAPTIONS_ENABLED");
|
||||
|
||||
private final String action;
|
||||
|
||||
|
||||
@@ -48,4 +48,10 @@ public class BroadcastIntentHelper {
|
||||
intent.putExtra("muted", muted);
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static Intent buildSetClosedCaptionsEnabledIntent(boolean enabled) {
|
||||
Intent intent = new Intent(BroadcastAction.Type.SET_CLOSED_CAPTIONS_ENABLED.getAction());
|
||||
intent.putExtra("enabled", enabled);
|
||||
return intent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ class ExternalAPIModule extends ReactContextBaseJavaModule {
|
||||
constants.put("CLOSE_CHAT", BroadcastAction.Type.CLOSE_CHAT.getAction());
|
||||
constants.put("SEND_CHAT_MESSAGE", BroadcastAction.Type.SEND_CHAT_MESSAGE.getAction());
|
||||
constants.put("SET_VIDEO_MUTED", BroadcastAction.Type.SET_VIDEO_MUTED.getAction());
|
||||
constants.put("SET_CLOSED_CAPTIONS_ENABLED", BroadcastAction.Type.SET_CLOSED_CAPTIONS_ENABLED.getAction());
|
||||
|
||||
return constants;
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ public class JitsiMeetActivity extends AppCompatActivity
|
||||
protected void onConferenceJoined(HashMap<String, Object> extraData) {
|
||||
JitsiMeetLogger.i("Conference joined: " + extraData);
|
||||
// Launch the service for the ongoing notification.
|
||||
JitsiMeetOngoingConferenceService.launch(this);
|
||||
JitsiMeetOngoingConferenceService.launch(this, extraData);
|
||||
}
|
||||
|
||||
protected void onConferenceTerminated(HashMap<String, Object> extraData) {
|
||||
|
||||
@@ -17,18 +17,22 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* This class implements an Android {@link Service}, a foreground one specifically, and it's
|
||||
* responsible for presenting an ongoing notification when a conference is in progress.
|
||||
@@ -39,16 +43,22 @@ import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
public class JitsiMeetOngoingConferenceService extends Service
|
||||
implements OngoingConferenceTracker.OngoingConferenceListener {
|
||||
private static final String TAG = JitsiMeetOngoingConferenceService.class.getSimpleName();
|
||||
private static final String EXTRA_DATA_KEY = "extraDataKey";
|
||||
private static final String EXTRA_DATA_BUNDLE_KEY = "extraDataBundleKey";
|
||||
private static final String IS_AUDIO_MUTED_KEY = "isAudioMuted";
|
||||
|
||||
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver();
|
||||
|
||||
private boolean isAudioMuted;
|
||||
|
||||
static void launch(Context context) {
|
||||
static void launch(Context context, HashMap<String, Object> extraData) {
|
||||
OngoingNotification.createOngoingConferenceNotificationChannel();
|
||||
|
||||
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
|
||||
intent.setAction(Action.START.getName());
|
||||
|
||||
Bundle extraDataBundle = new Bundle();
|
||||
extraDataBundle.putSerializable(EXTRA_DATA_KEY, extraData);
|
||||
intent.putExtra(EXTRA_DATA_BUNDLE_KEY, extraDataBundle);
|
||||
|
||||
ComponentName componentName;
|
||||
|
||||
@@ -79,6 +89,15 @@ public class JitsiMeetOngoingConferenceService extends Service
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
Notification notification = OngoingNotification.buildOngoingConferenceNotification(isAudioMuted);
|
||||
if (notification == null) {
|
||||
stopSelf();
|
||||
JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null");
|
||||
} else {
|
||||
startForeground(OngoingNotification.NOTIFICATION_ID, notification);
|
||||
JitsiMeetLogger.i(TAG + " Service started");
|
||||
}
|
||||
|
||||
OngoingConferenceTracker.getInstance().addListener(this);
|
||||
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
@@ -101,37 +120,45 @@ public class JitsiMeetOngoingConferenceService extends Service
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
|
||||
Boolean isAudioMuted = tryParseIsAudioMuted(intent);
|
||||
|
||||
if (isAudioMuted != null) {
|
||||
this.isAudioMuted = Boolean.parseBoolean(intent.getStringExtra("muted"));
|
||||
|
||||
Notification notification = OngoingNotification.buildOngoingConferenceNotification(isAudioMuted);
|
||||
if (notification == null) {
|
||||
stopSelf();
|
||||
JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null");
|
||||
} else {
|
||||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify(OngoingNotification.NOTIFICATION_ID, notification);
|
||||
}
|
||||
}
|
||||
|
||||
final String actionName = intent.getAction();
|
||||
final Action action = Action.fromName(actionName);
|
||||
|
||||
switch (action) {
|
||||
case UNMUTE:
|
||||
case MUTE:
|
||||
Intent muteBroadcastIntent = BroadcastIntentHelper.buildSetAudioMutedIntent(action == Action.MUTE);
|
||||
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(muteBroadcastIntent);
|
||||
break;
|
||||
case START:
|
||||
Notification notification = OngoingNotification.buildOngoingConferenceNotification(isAudioMuted);
|
||||
if (notification == null) {
|
||||
// When starting the service, there is no action passed in the intent
|
||||
if (action != null) {
|
||||
switch (action) {
|
||||
case UNMUTE:
|
||||
case MUTE:
|
||||
Intent muteBroadcastIntent = BroadcastIntentHelper.buildSetAudioMutedIntent(action == Action.MUTE);
|
||||
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(muteBroadcastIntent);
|
||||
break;
|
||||
case HANGUP:
|
||||
JitsiMeetLogger.i(TAG + " Hangup requested");
|
||||
|
||||
Intent hangupBroadcastIntent = BroadcastIntentHelper.buildHangUpIntent();
|
||||
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(hangupBroadcastIntent);
|
||||
|
||||
stopSelf();
|
||||
JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null");
|
||||
} else {
|
||||
startForeground(OngoingNotification.NOTIFICATION_ID, notification);
|
||||
JitsiMeetLogger.i(TAG + " Service started");
|
||||
}
|
||||
break;
|
||||
case HANGUP:
|
||||
JitsiMeetLogger.i(TAG + " Hangup requested");
|
||||
|
||||
Intent hangupBroadcastIntent = BroadcastIntentHelper.buildHangUpIntent();
|
||||
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(hangupBroadcastIntent);
|
||||
|
||||
stopSelf();
|
||||
break;
|
||||
default:
|
||||
JitsiMeetLogger.w(TAG + " Unknown action received: " + action);
|
||||
stopSelf();
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
JitsiMeetLogger.w(TAG + " Unknown action received: " + action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return START_NOT_STICKY;
|
||||
@@ -147,7 +174,6 @@ public class JitsiMeetOngoingConferenceService extends Service
|
||||
}
|
||||
|
||||
public enum Action {
|
||||
START(TAG + ":START"),
|
||||
HANGUP(TAG + ":HANGUP"),
|
||||
MUTE(TAG + ":MUTE"),
|
||||
UNMUTE(TAG + ":UNMUTE");
|
||||
@@ -172,6 +198,15 @@ public class JitsiMeetOngoingConferenceService extends Service
|
||||
}
|
||||
}
|
||||
|
||||
private Boolean tryParseIsAudioMuted(Intent intent) {
|
||||
try {
|
||||
HashMap<String, Object> extraData = (HashMap<String, Object>) intent.getBundleExtra(EXTRA_DATA_BUNDLE_KEY).getSerializable(EXTRA_DATA_KEY);
|
||||
return Boolean.parseBoolean((String) extraData.get(IS_AUDIO_MUTED_KEY));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private class BroadcastReceiver extends android.content.BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
@@ -180,10 +215,12 @@ public class JitsiMeetOngoingConferenceService extends Service
|
||||
Notification notification = OngoingNotification.buildOngoingConferenceNotification(isAudioMuted);
|
||||
if (notification == null) {
|
||||
stopSelf();
|
||||
JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null");
|
||||
JitsiMeetLogger.w(TAG + " Couldn't update service, notification is null");
|
||||
} else {
|
||||
startForeground(OngoingNotification.NOTIFICATION_ID, notification);
|
||||
JitsiMeetLogger.i(TAG + " Service started");
|
||||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify(OngoingNotification.NOTIFICATION_ID, notification);
|
||||
|
||||
JitsiMeetLogger.i(TAG + " audio muted changed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.oney.WebRTCModule.WebRTCModule;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
@@ -125,18 +126,14 @@ public class JitsiMeetView extends BaseReactView<JitsiMeetViewListener>
|
||||
* page.
|
||||
*/
|
||||
public void enterPictureInPicture() {
|
||||
PictureInPictureModule pipModule
|
||||
= ReactInstanceManagerHolder.getNativeModule(
|
||||
PictureInPictureModule.class);
|
||||
if (pipModule != null
|
||||
&& pipModule.isPictureInPictureSupported()
|
||||
&& !JitsiMeetActivityDelegate.arePermissionsBeingRequested()
|
||||
&& this.url != null) {
|
||||
try {
|
||||
pipModule.enterPictureInPicture();
|
||||
} catch (RuntimeException re) {
|
||||
JitsiMeetLogger.e(re, "Failed to enter PiP mode");
|
||||
}
|
||||
try {
|
||||
WebRTCModule pipModule
|
||||
= ReactInstanceManagerHolder.getNativeModule(
|
||||
WebRTCModule.class);
|
||||
pipModule.addDecryptors();
|
||||
}
|
||||
catch (Exception e) {
|
||||
int a = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
import com.oney.WebRTCModule.WebRTCModule;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
@@ -43,7 +44,7 @@ class PictureInPictureModule extends ReactContextBaseJavaModule {
|
||||
private static final String TAG = NAME;
|
||||
|
||||
private static boolean isSupported;
|
||||
private boolean isDisabled;
|
||||
private boolean isEnabled;
|
||||
|
||||
public PictureInPictureModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
@@ -84,34 +85,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");
|
||||
}
|
||||
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
|
||||
if (currentActivity == null) {
|
||||
throw new IllegalStateException("No current Activity!");
|
||||
}
|
||||
|
||||
JitsiMeetLogger.i(TAG + " Entering Picture-in-Picture");
|
||||
|
||||
PictureInPictureParams.Builder builder
|
||||
= new PictureInPictureParams.Builder()
|
||||
.setAspectRatio(new Rational(1, 1));
|
||||
|
||||
// https://developer.android.com/reference/android/app/Activity.html#enterPictureInPictureMode(android.app.PictureInPictureParams)
|
||||
//
|
||||
// The system may disallow entering picture-in-picture in various cases,
|
||||
// including when the activity is not visible, if the screen is locked
|
||||
// or if the user has an activity pinned.
|
||||
if (!currentActivity.enterPictureInPictureMode(builder.build())) {
|
||||
throw new RuntimeException("Failed to enter Picture-in-Picture");
|
||||
}
|
||||
WebRTCModule pipModule
|
||||
= ReactInstanceManagerHolder.getNativeModule(
|
||||
WebRTCModule.class);
|
||||
pipModule.addDecryptors();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,17 +100,15 @@ class PictureInPictureModule extends ReactContextBaseJavaModule {
|
||||
*/
|
||||
@ReactMethod
|
||||
public void enterPictureInPicture(Promise promise) {
|
||||
try {
|
||||
enterPictureInPicture();
|
||||
promise.resolve(null);
|
||||
} catch (RuntimeException re) {
|
||||
promise.reject(re);
|
||||
}
|
||||
WebRTCModule pipModule
|
||||
= ReactInstanceManagerHolder.getNativeModule(
|
||||
WebRTCModule.class);
|
||||
pipModule.addDecryptors();
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setPictureInPictureDisabled(Boolean disabled) {
|
||||
this.isDisabled = disabled;
|
||||
public void setPictureInPictureEnabled(Boolean enabled) {
|
||||
this.isEnabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isPictureInPictureSupported() {
|
||||
|
||||
@@ -35,6 +35,8 @@ import com.oney.WebRTCModule.RTCVideoViewManager;
|
||||
import com.oney.WebRTCModule.WebRTCModule;
|
||||
|
||||
import org.devio.rn.splashscreen.SplashScreenModule;
|
||||
import org.webrtc.Loggable;
|
||||
import org.webrtc.Logging;
|
||||
import org.webrtc.SoftwareVideoDecoderFactory;
|
||||
import org.webrtc.SoftwareVideoEncoderFactory;
|
||||
import org.webrtc.audio.AudioDeviceModule;
|
||||
@@ -57,6 +59,13 @@ class ReactInstanceManagerHolder {
|
||||
*/
|
||||
private static ReactInstanceManager reactInstanceManager;
|
||||
|
||||
private static Loggable webrtcLogger = new Loggable() {
|
||||
@Override
|
||||
public void onLogMessage(String message, Logging.Severity severity, String tag) {
|
||||
Log.d(tag,message);
|
||||
}
|
||||
};
|
||||
|
||||
private static List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
||||
List<NativeModule> nativeModules
|
||||
= new ArrayList<>(Arrays.<NativeModule>asList(
|
||||
@@ -88,6 +97,8 @@ class ReactInstanceManagerHolder {
|
||||
|
||||
options.setVideoDecoderFactory(new SoftwareVideoDecoderFactory());
|
||||
options.setVideoEncoderFactory(new SoftwareVideoEncoderFactory());
|
||||
options.setInjectableLogger(webrtcLogger);
|
||||
options.setLoggingSeverity(Logging.Severity.LS_VERBOSE);
|
||||
|
||||
nativeModules.add(new WebRTCModule(reactContext, options));
|
||||
|
||||
|
||||
@@ -923,6 +923,35 @@ export default {
|
||||
: isVideoMutedByUser(APP.store);
|
||||
},
|
||||
|
||||
/**
|
||||
* Verify if there is an ongoing system audio sharing session and apply to the provided track
|
||||
* as a AudioMixer effect.
|
||||
*
|
||||
* @param {*} localAudioTrack - track to which system audio track will be applied as an effect, most likely
|
||||
* microphone local audio track.
|
||||
*/
|
||||
async _maybeApplyAudioMixerEffect(localAudioTrack) {
|
||||
|
||||
// At the time of writing this comment there were two separate flows for toggling screen-sharing
|
||||
// and system audio sharing, the first is the legacy method using the functionality from conference.js
|
||||
// the second is used when both sendMultipleVideoStreams and sourceNameSignaling flags are set to true.
|
||||
// The second flow uses functionality from base/conference/middleware.web.js.
|
||||
// We check if system audio sharing was done using the first flow by verifying this._desktopAudioStream and
|
||||
// for the second by checking 'features/screen-share' state.
|
||||
const { desktopAudioTrack } = APP.store.getState()['features/screen-share'];
|
||||
const currentDesktopAudioTrack = this._desktopAudioStream || desktopAudioTrack;
|
||||
|
||||
// If system audio is already being sent, mix it with the provided audio track.
|
||||
if (currentDesktopAudioTrack) {
|
||||
// In case system audio sharing was done in the absence of an initial mic audio track, there is no
|
||||
// AudioMixerEffect so we have to remove system audio track from the room before setting it as an effect.
|
||||
await room.replaceTrack(currentDesktopAudioTrack, null);
|
||||
this._mixerEffect = new AudioMixerEffect(currentDesktopAudioTrack);
|
||||
logger.debug('Mixing new audio track with existing screen audio track.');
|
||||
await localAudioTrack.setEffect(this._mixerEffect);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Simulates toolbar button click for audio mute. Used by shortcuts and API.
|
||||
* @param {boolean} mute true for mute and false for unmute.
|
||||
@@ -976,7 +1005,11 @@ export default {
|
||||
// Rollback the audio muted status by using null track
|
||||
return null;
|
||||
})
|
||||
.then(audioTrack => this.useAudioStream(audioTrack));
|
||||
.then(async audioTrack => {
|
||||
await this._maybeApplyAudioMixerEffect(audioTrack);
|
||||
|
||||
this.useAudioStream(audioTrack);
|
||||
});
|
||||
} else {
|
||||
muteLocalAudio(mute);
|
||||
}
|
||||
@@ -1617,12 +1650,26 @@ export default {
|
||||
let promise = _prevMutePresenterVideo = _prevMutePresenterVideo.then(() => {
|
||||
// mute the presenter track if it exists.
|
||||
if (this.localPresenterVideo) {
|
||||
APP.store.dispatch(setVideoMuted(true, MEDIA_TYPE.PRESENTER));
|
||||
return (
|
||||
this.localPresenterVideo.dispose().then(() => {
|
||||
APP.store.dispatch(trackRemoved(this.localPresenterVideo));
|
||||
this.localPresenterVideo = null;
|
||||
})
|
||||
.then(() => {
|
||||
|
||||
return this.localPresenterVideo.dispose().then(() => {
|
||||
APP.store.dispatch(trackRemoved(this.localPresenterVideo));
|
||||
this.localPresenterVideo = null;
|
||||
});
|
||||
// This is needed only for setting the correct muted state in features/base/media.
|
||||
// NOTE: It is important to be executed after we have disposed and removed the presenter track.
|
||||
// This way all the side effects won't be executed and we won't start additional O/A cycle for
|
||||
// replacing the track with video with the one without video. This O/A cycle is not needed since
|
||||
// we are trying to destroy all tracks. Also due to the current async nature of muting the
|
||||
// presenter, the final removal of the screen sharing track (see the code at the end of the
|
||||
// function) can be executed between the removal of the stream with video and adding the
|
||||
// original screen sharing stream to the peer connection. This will lead to a failure to remove
|
||||
// the screen sharing track, compromising the screen sharing state in jitsi-meet and the user
|
||||
// won't be able to turn off the screen sharing.
|
||||
APP.store.dispatch(setVideoMuted(true, MEDIA_TYPE.PRESENTER));
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1712,12 +1759,12 @@ export default {
|
||||
return Promise.reject('Cannot toggle screen sharing: not supported.');
|
||||
}
|
||||
|
||||
if (this.isAudioOnly()) {
|
||||
APP.store.dispatch(setAudioOnly(false));
|
||||
}
|
||||
if (toggle) {
|
||||
try {
|
||||
await this._switchToScreenSharing(options);
|
||||
if (this.isAudioOnly()) {
|
||||
APP.store.dispatch(setAudioOnly(false));
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (err) {
|
||||
@@ -2572,13 +2619,7 @@ export default {
|
||||
return stream;
|
||||
})
|
||||
.then(async stream => {
|
||||
// In case screen sharing audio is also shared we mix it with new input stream. The old _mixerEffect
|
||||
// will be cleaned up when the existing track is replaced.
|
||||
if (this._mixerEffect) {
|
||||
this._mixerEffect = new AudioMixerEffect(this._desktopAudioStream);
|
||||
|
||||
await stream.setEffect(this._mixerEffect);
|
||||
}
|
||||
await this._maybeApplyAudioMixerEffect(stream);
|
||||
|
||||
return this.useAudioStream(stream);
|
||||
})
|
||||
@@ -2612,13 +2653,9 @@ export default {
|
||||
// muteVideo logic in such case.
|
||||
const tracks = APP.store.getState()['features/base/tracks'];
|
||||
const isTrackInRedux
|
||||
= Boolean(
|
||||
tracks.find(
|
||||
track => track.jitsiTrack
|
||||
&& track.jitsiTrack.getType() === 'video'));
|
||||
= Boolean(tracks.find(track => track.jitsiTrack && track.jitsiTrack.getType() === MEDIA_TYPE.VIDEO));
|
||||
|
||||
|
||||
if (isTrackInRedux) {
|
||||
if (isTrackInRedux && !this.isSharingScreen) {
|
||||
this.muteVideo(audioOnly);
|
||||
}
|
||||
|
||||
|
||||
108
config.js
108
config.js
@@ -295,6 +295,14 @@ var config = {
|
||||
// Whether to enable live streaming or not.
|
||||
// liveStreamingEnabled: false,
|
||||
|
||||
// Local recording configuration.
|
||||
// localRecording: {
|
||||
// // Whether to disable local recording or not.
|
||||
// disable: false,
|
||||
// // Whether to notify all participants when a participant is recording locally.
|
||||
// notifyAllParticipants: false
|
||||
// },
|
||||
|
||||
// Transcription (in interface_config,
|
||||
// subtitles and buttons can be configured)
|
||||
// transcribingEnabled: false,
|
||||
@@ -559,6 +567,10 @@ var config = {
|
||||
// // When 'true', it shows an intermediate page before joining, where the user can configure their devices.
|
||||
// // This replaces `prejoinPageEnabled`.
|
||||
// enabled: true,
|
||||
// // Hides the participant name editing field in the prejoin screen.
|
||||
// // If requireDisplayName is also set as true, a name should still be provided through
|
||||
// // either the jwt or the userInfo from the iframe api init object in order for this to have an effect.
|
||||
// hideDisplayName: false,
|
||||
// // List of buttons to hide from the extra join options dropdown.
|
||||
// hideExtraJoinButtons: ['no-audio', 'by-phone']
|
||||
// },
|
||||
@@ -586,8 +598,17 @@ var config = {
|
||||
// Array with avatar URL prefixes that need to use CORS.
|
||||
// corsAvatarURLs: [ 'https://www.gravatar.com/avatar/' ],
|
||||
|
||||
// Base URL for a Gravatar-compatible service. Defaults to libravatar.
|
||||
// gravatarBaseURL: 'https://seccdn.libravatar.org/avatar/',
|
||||
// Base URL for a Gravatar-compatible service. Defaults to Gravatar.
|
||||
// DEPRECATED! Use `gravatar.baseUrl` instead.
|
||||
// gravatarBaseURL: 'https://www.gravatar.com/avatar/',
|
||||
|
||||
// Setup for Gravatar-compatible services.
|
||||
// gravatar: {
|
||||
// // Defaults to Gravatar.
|
||||
// baseUrl: 'https://www.gravatar.com/avatar/',
|
||||
// // True if Gravatar should be disabled.
|
||||
// disabled: false
|
||||
// },
|
||||
|
||||
// App name to be displayed in the invitation email subject, as an alternative to
|
||||
// interfaceConfig.APP_NAME.
|
||||
@@ -609,6 +630,7 @@ var config = {
|
||||
// 'chat',
|
||||
// 'closedcaptions',
|
||||
// 'desktop',
|
||||
// 'dock-iframe'
|
||||
// 'download',
|
||||
// 'embedmeeting',
|
||||
// 'etherpad',
|
||||
@@ -622,8 +644,6 @@ var config = {
|
||||
// 'linktosalesforce',
|
||||
// 'livestreaming',
|
||||
// 'microphone',
|
||||
// 'mute-everyone',
|
||||
// 'mute-video-everyone',
|
||||
// 'participants-pane',
|
||||
// 'profile',
|
||||
// 'raisehand',
|
||||
@@ -637,6 +657,7 @@ var config = {
|
||||
// 'stats',
|
||||
// 'tileview',
|
||||
// 'toggle-camera',
|
||||
// 'undock-iframe',
|
||||
// 'videoquality',
|
||||
// '__end'
|
||||
// ],
|
||||
@@ -763,7 +784,7 @@ var config = {
|
||||
// enableEmailInStats: false,
|
||||
|
||||
// faceLandmarks: {
|
||||
// // Enables sharing your face cordinates. Used for centering faces within a video.
|
||||
// // Enables sharing your face coordinates. Used for centering faces within a video.
|
||||
// enableFaceCentering: false,
|
||||
|
||||
// // Enables detecting face expressions and sharing data with other participants
|
||||
@@ -772,11 +793,14 @@ var config = {
|
||||
// // Enables displaying face expressions in speaker stats
|
||||
// enableDisplayFaceExpressions: false,
|
||||
|
||||
// // Enable rtc stats for face landmarks
|
||||
// enableRTCStats: false,
|
||||
|
||||
// // Minimum required face movement percentage threshold for sending new face centering coordinates data.
|
||||
// faceCenteringThreshold: 10,
|
||||
|
||||
// // Miliseconds for processing a new image capture in order to detect face coordinates if they exist.
|
||||
// captureInterval: 100
|
||||
// // Milliseconds for processing a new image capture in order to detect face coordinates if they exist.
|
||||
// captureInterval: 1000
|
||||
// },
|
||||
|
||||
// Controls the percentage of automatic feedback shown to participants when callstats is enabled.
|
||||
@@ -856,6 +880,10 @@ var config = {
|
||||
// The Amplitude APP Key:
|
||||
// amplitudeAPPKey: '<APP_KEY>'
|
||||
|
||||
// Obfuscates room name sent to analytics (amplitude, rtcstats)
|
||||
// Default value is false.
|
||||
// obfuscateRoomName: false,
|
||||
|
||||
// Configuration for the rtcstats server:
|
||||
// By enabling rtcstats server every time a conference is joined the rtcstats
|
||||
// module connects to the provided rtcstatsEndpoint and sends statistics regarding
|
||||
@@ -930,33 +958,22 @@ var config = {
|
||||
// chromeExtensionBanner: {
|
||||
// // The chrome extension to be installed address
|
||||
// url: 'https://chrome.google.com/webstore/detail/jitsi-meetings/kglhbbefdnlheedjiejgomgmfplipfeb',
|
||||
// edgeUrl: 'https://microsoftedge.microsoft.com/addons/detail/jitsi-meetings/eeecajlpbgjppibfledfihobcabccihn',
|
||||
|
||||
// // Extensions info which allows checking if they are installed or not
|
||||
// chromeExtensionsInfo: [
|
||||
// {
|
||||
// id: 'kglhbbefdnlheedjiejgomgmfplipfeb',
|
||||
// path: 'jitsi-logo-48x48.png'
|
||||
// },
|
||||
// // Edge extension info
|
||||
// {
|
||||
// id: 'eeecajlpbgjppibfledfihobcabccihn',
|
||||
// path: 'jitsi-logo-48x48.png'
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
|
||||
// Local Recording
|
||||
//
|
||||
|
||||
// localRecording: {
|
||||
// Enables local recording.
|
||||
// Additionally, 'localrecording' (all lowercase) needs to be added to
|
||||
// the `toolbarButtons`-array for the Local Recording button to show up
|
||||
// on the toolbar.
|
||||
//
|
||||
// enabled: true,
|
||||
//
|
||||
|
||||
// The recording format, can be one of 'ogg', 'flac' or 'wav'.
|
||||
// format: 'flac'
|
||||
//
|
||||
|
||||
// },
|
||||
// e2ee: {
|
||||
// labels,
|
||||
// externallyManagedKey: false
|
||||
@@ -1002,7 +1019,8 @@ var config = {
|
||||
// Disables all invite functions from the app (share, invite, dial out...etc)
|
||||
// disableInviteFunctions: true,
|
||||
|
||||
// Disables storing the room name to the recents list
|
||||
// Disables storing the room name to the recents list. When in an iframe this is ignored and
|
||||
// the room is never stored in the recents list.
|
||||
// doNotStoreRoom: true,
|
||||
|
||||
// Deployment specific URLs.
|
||||
@@ -1099,16 +1117,8 @@ var config = {
|
||||
*/
|
||||
// dynamicBrandingUrl: '',
|
||||
|
||||
// Options related to the breakout rooms feature.
|
||||
// breakoutRooms: {
|
||||
// // Hides the add breakout room button. This replaces `hideAddRoomButton`.
|
||||
// hideAddRoomButton: false,
|
||||
// // Hides the auto assign participants button.
|
||||
// hideAutoAssignButton: false,
|
||||
// // Hides the participants pane footer menu.
|
||||
// hideFooterMenu: false,
|
||||
// // Hides the join breakout room button.
|
||||
// hideJoinRoomButton: false,
|
||||
// Options related to the participants pane.
|
||||
// participantsPane: {
|
||||
// // Hides the moderator settings tab.
|
||||
// hideModeratorSettingsTab: false,
|
||||
// // Hides the more actions button.
|
||||
@@ -1117,6 +1127,16 @@ var config = {
|
||||
// hideMuteAllButton: false
|
||||
// },
|
||||
|
||||
// Options related to the breakout rooms feature.
|
||||
// breakoutRooms: {
|
||||
// // Hides the add breakout room button. This replaces `hideAddRoomButton`.
|
||||
// hideAddRoomButton: false,
|
||||
// // Hides the auto assign participants button.
|
||||
// hideAutoAssignButton: false,
|
||||
// // Hides the join breakout room button.
|
||||
// hideJoinRoomButton: false
|
||||
// },
|
||||
|
||||
// When true the user cannot add more images to be used as virtual background.
|
||||
// Only the default ones from will be available.
|
||||
// disableAddingBackgroundImages: false,
|
||||
@@ -1187,14 +1207,24 @@ var config = {
|
||||
// will open an etherpad document.
|
||||
// etherpad_base: 'https://your-etherpad-installati.on/p/',
|
||||
|
||||
// To enable information about dial-in access to meetings you need to provide
|
||||
// dialInNumbersUrl and dialInConfCodeUrl.
|
||||
// dialInNumbersUrl returns a json array of numbers that can be used for dial-in.
|
||||
// {"countryCode":"US","tollFree":false,"formattedNumber":"+1 123-456-7890"}
|
||||
// dialInConfCodeUrl is the conference mapper converting a meeting id to a PIN used for dial-in
|
||||
// or the other way around (more info in resources/cloud-api.swagger)
|
||||
//
|
||||
// For JaaS customers the default values are:
|
||||
// dialInNumbersUrl: 'https://conference-mapper.jitsi.net/v1/access/dids',
|
||||
// dialInConfCodeUrl: 'https://conference-mapper.jitsi.net/v1/access',
|
||||
//
|
||||
|
||||
// List of undocumented settings used in jitsi-meet
|
||||
/**
|
||||
_immediateReloadThreshold
|
||||
debug
|
||||
debugAudioLevels
|
||||
deploymentInfo
|
||||
dialInConfCodeUrl
|
||||
dialInNumbersUrl
|
||||
dialOutAuthUrl
|
||||
dialOutCodesUrl
|
||||
disableRemoteControl
|
||||
@@ -1279,7 +1309,6 @@ var config = {
|
||||
// 'liveStreaming.unavailableTitle', // shown when livestreaming service is not reachable
|
||||
// 'lobby.joinRejectedMessage', // shown when while in a lobby, user's request to join is rejected
|
||||
// 'lobby.notificationTitle', // shown when lobby is toggled and when join requests are allowed / denied
|
||||
// 'localRecording.localRecording', // shown when a local recording is started
|
||||
// 'notify.chatMessages', // shown when receiving chat messages while the chat window is closed
|
||||
// 'notify.disconnected', // shown when a participant has left
|
||||
// 'notify.connectedOneMember', // show when a participant joined
|
||||
@@ -1325,6 +1354,9 @@ var config = {
|
||||
// 'transcribing.failedToStart' // shown when transcribing fails to start
|
||||
// ],
|
||||
|
||||
// List of notifications to be disabled. Works in tandem with the above setting.
|
||||
// disabledNotifications: [],
|
||||
|
||||
// Prevent the filmstrip from autohiding when screen width is under a certain threshold
|
||||
// disableFilmstripAutohiding: false,
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ import { LoginDialog } from './react/features/authentication/components';
|
||||
import { isTokenAuthEnabled } from './react/features/authentication/functions';
|
||||
import {
|
||||
connectionEstablished,
|
||||
connectionFailed
|
||||
connectionFailed,
|
||||
constructOptions
|
||||
} from './react/features/base/connection/actions';
|
||||
import { openDialog } from './react/features/base/dialog/actions';
|
||||
import { setJWT } from './react/features/base/jwt';
|
||||
@@ -19,7 +20,10 @@ import {
|
||||
import { isFatalJitsiConnectionError } from './react/features/base/lib-jitsi-meet/functions';
|
||||
import { getCustomerDetails } from './react/features/jaas/actions.any';
|
||||
import { isVpaasMeeting, getJaasJWT } from './react/features/jaas/functions';
|
||||
import { setPrejoinDisplayNameRequired } from './react/features/prejoin/actions';
|
||||
import {
|
||||
setPrejoinDisplayNameRequired,
|
||||
setPrejoinPageVisibility
|
||||
} from './react/features/prejoin/actions';
|
||||
const logger = Logger.getLogger(__filename);
|
||||
|
||||
/**
|
||||
@@ -81,12 +85,10 @@ function checkForAttachParametersAndConnect(id, password, connection) {
|
||||
* Try to open connection using provided credentials.
|
||||
* @param {string} [id]
|
||||
* @param {string} [password]
|
||||
* @param {string} [roomName]
|
||||
* @returns {Promise<JitsiConnection>} connection if
|
||||
* everything is ok, else error.
|
||||
*/
|
||||
export async function connect(id, password, roomName) {
|
||||
const connectionConfig = Object.assign({}, config);
|
||||
export async function connect(id, password) {
|
||||
const state = APP.store.getState();
|
||||
let { jwt } = state['features/base/jwt'];
|
||||
const { iAmRecorder, iAmSipGateway } = state['features/base/config'];
|
||||
@@ -100,19 +102,7 @@ export async function connect(id, password, roomName) {
|
||||
}
|
||||
}
|
||||
|
||||
// Use Websocket URL for the web app if configured. Note that there is no 'isWeb' check, because there's assumption
|
||||
// that this code executes only on web browsers/electron. This needs to be changed when mobile and web are unified.
|
||||
let serviceUrl = connectionConfig.websocket || connectionConfig.bosh;
|
||||
|
||||
serviceUrl += `?room=${roomName}`;
|
||||
|
||||
connectionConfig.serviceUrl = serviceUrl;
|
||||
|
||||
if (connectionConfig.websocketKeepAliveUrl) {
|
||||
connectionConfig.websocketKeepAliveUrl += `?room=${roomName}`;
|
||||
}
|
||||
|
||||
const connection = new JitsiMeetJS.JitsiConnection(null, jwt, connectionConfig);
|
||||
const connection = new JitsiMeetJS.JitsiConnection(null, jwt, constructOptions(state));
|
||||
|
||||
if (config.iAmRecorder) {
|
||||
connection.addFeature(DISCO_JIBRI_FEATURE);
|
||||
@@ -257,6 +247,7 @@ function requestAuth(roomName) {
|
||||
resolve(connection);
|
||||
};
|
||||
|
||||
APP.store.dispatch(setPrejoinPageVisibility(false));
|
||||
APP.store.dispatch(
|
||||
openDialog(LoginDialog, { onSuccess,
|
||||
roomName })
|
||||
|
||||
@@ -23,7 +23,26 @@
|
||||
|
||||
.recording-header-line {
|
||||
border-top: 1px solid #5e6d7a;
|
||||
padding-top: 32px;
|
||||
padding-top: 16px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.local-recording-warning {
|
||||
margin-top: 8px;
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
padding: 8px 16px;
|
||||
|
||||
&.text {
|
||||
color: #fff;
|
||||
background-color: #3D3D3D;
|
||||
}
|
||||
|
||||
&.notification {
|
||||
color: #040404;
|
||||
background-color: #F8AE1A;
|
||||
}
|
||||
}
|
||||
|
||||
.recording-switch-disabled {
|
||||
@@ -40,7 +59,7 @@
|
||||
border-radius: 4px;
|
||||
height: 40px;
|
||||
justify-content: center;
|
||||
width: 56px;
|
||||
width: 42px;
|
||||
}
|
||||
|
||||
.cloud-content-recording-icon-container {
|
||||
@@ -52,7 +71,7 @@
|
||||
}
|
||||
|
||||
.jitsi-recording-header {
|
||||
margin-bottom: 32px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.jitsi-content-recording-icon-container-with-switch {
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
.remote-videos {
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
@import 'lobby';
|
||||
@import 'premeeting-screens';
|
||||
@import 'prejoin';
|
||||
@import 'prejoin-dialog';
|
||||
@import 'prejoin-third-party';
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
.prejoin-dialog {
|
||||
background: #1C2025;
|
||||
box-shadow: 0px 2px 20px rgba(0, 0, 0, 0.5);
|
||||
border-radius: 5px;
|
||||
color: #fff;
|
||||
height: 400px;
|
||||
width: 375px;
|
||||
|
||||
&--small {
|
||||
height: 300;
|
||||
width: 400;
|
||||
}
|
||||
|
||||
&-label {
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
|
||||
&-num {
|
||||
background: #2b3b4b;
|
||||
border: 1px solid #A4B8D1;
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
height: 24px;
|
||||
margin-right: 8px;
|
||||
width: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
&-container {
|
||||
align-items: center;
|
||||
background: rgba(0,0,0,0.6);
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
justify-content: center;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100vw;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
&-flag {
|
||||
display: inline-block;
|
||||
margin-right: 8px;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
&-title {
|
||||
display: inline-block;
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
&-icon {
|
||||
cursor: pointer;
|
||||
|
||||
> svg {
|
||||
fill: #A4B8D1;
|
||||
}
|
||||
}
|
||||
|
||||
&-btn {
|
||||
width: 309px;
|
||||
}
|
||||
|
||||
&-dialin-container {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&-delimiter {
|
||||
background: #5f6266;
|
||||
border: 0;
|
||||
height: 1px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
|
||||
&-container {
|
||||
margin: 16px 0 24px 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&-txt-container {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
top: -8px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-txt {
|
||||
background: #1C2025;
|
||||
color: #5f6266;
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
padding: 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.prejoin-dialog-btn.primary,
|
||||
.action-btn.prejoin-dialog-btn.text {
|
||||
width: 310px;
|
||||
}
|
||||
}
|
||||
|
||||
.prejoin-dialog-callout {
|
||||
padding: 16px;
|
||||
|
||||
&-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
&-picker {
|
||||
margin: 8px 0 16px 0;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,25 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-avatar {
|
||||
margin: 8px auto 16px;
|
||||
|
||||
&-name {
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 26px;
|
||||
margin-bottom: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&-container {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
&-error {
|
||||
background-color: #E04757;
|
||||
border-radius: 6px;
|
||||
|
||||
4
debian/control
vendored
4
debian/control
vendored
@@ -33,7 +33,7 @@ Description: Configuration for web serving of Jitsi Meet
|
||||
|
||||
Package: jitsi-meet-prosody
|
||||
Architecture: all
|
||||
Depends: openssl, prosody (>= 0.11.0) | prosody-trunk | prosody-0.12 | prosody-0.11, lua-sec
|
||||
Depends: openssl, prosody (>= 0.11.0) | prosody-trunk | prosody-0.12 | prosody-0.11, lua-sec, lua-basexx, lua-luaossl, lua-cjson
|
||||
Replaces: jitsi-meet-tokens
|
||||
Description: Prosody configuration for Jitsi Meet
|
||||
Jitsi Meet is a WebRTC JavaScript application that uses Jitsi
|
||||
@@ -47,7 +47,7 @@ Description: Prosody configuration for Jitsi Meet
|
||||
|
||||
Package: jitsi-meet-tokens
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, prosody-trunk | prosody-0.11 | prosody-0.12 | prosody (>= 0.11.2), libssl-dev, luarocks, jitsi-meet-prosody, git, lua-basexx
|
||||
Depends: ${misc:Depends}, prosody-trunk | prosody-0.11 | prosody-0.12 | prosody (>= 0.11.2), jitsi-meet-prosody
|
||||
Description: Prosody token authentication plugin for Jitsi Meet
|
||||
|
||||
Package: jitsi-meet-turnserver
|
||||
|
||||
5
debian/jitsi-meet-tokens.postinst
vendored
5
debian/jitsi-meet-tokens.postinst
vendored
@@ -48,11 +48,6 @@ case "$1" in
|
||||
db_stop
|
||||
|
||||
if [ -f "$PROSODY_HOST_CONFIG" ] ; then
|
||||
# Install luajwt (also on update, to make sure we get the latest version).
|
||||
if ! luarocks install luajwtjitsi 3.0-0; then
|
||||
echo "Failed to install luajwtjitsi - try installing it manually"
|
||||
fi
|
||||
|
||||
# search for the token auth, if this is not enabled this is the
|
||||
# first time we install tokens package and needs a config change
|
||||
if ! egrep -q '^\s*authentication\s*=\s*"token"' "$PROSODY_HOST_CONFIG"; then
|
||||
|
||||
2
debian/jitsi-meet-web.install
vendored
2
debian/jitsi-meet-web.install
vendored
@@ -14,5 +14,3 @@ 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/
|
||||
resources/load-test/*.html /usr/share/jitsi-meet/load-test/
|
||||
resources/load-test/libs /usr/share/jitsi-meet/load-test/
|
||||
|
||||
@@ -137,3 +137,18 @@ Component "lobby.jitmeet.example.com" "muc"
|
||||
"muc_rate_limit";
|
||||
"polls";
|
||||
}
|
||||
|
||||
-- Enables dial-in for Jitsi meet components customers
|
||||
-- Note: make sure you have the following packages installed: lua-basexx, liblua5.3-dev, libssl-dev, luarocks
|
||||
-- and execute $ sudo luarocks install luajwtjitsi 3.0-0
|
||||
VirtualHost "jigasi.meet.jitsi"
|
||||
enabled = false -- Jitsi meet components customers remove this line
|
||||
modules_enabled = {
|
||||
"ping";
|
||||
"bosh";
|
||||
}
|
||||
authentication = "token"
|
||||
app_id = "jitsi";
|
||||
asap_key_server = "https://jaas-public-keys.jitsi.net/jitsi-components/prod-8x8"
|
||||
asap_accepted_issuers = { "jaas-components" }
|
||||
asap_accepted_audiences = { "jigasi.jitmeet.example.com" }
|
||||
|
||||
BIN
images/downloadLocalRecording.png
Normal file
BIN
images/downloadLocalRecording.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 490 B |
@@ -353,7 +353,7 @@ PODS:
|
||||
- react-native-video/Video (= 5.2.0)
|
||||
- react-native-video/Video (5.2.0):
|
||||
- React-Core
|
||||
- react-native-webrtc (1.100.0):
|
||||
- react-native-webrtc (1.100.1):
|
||||
- React-Core
|
||||
- react-native-webview (11.15.1):
|
||||
- React-Core
|
||||
@@ -718,7 +718,7 @@ SPEC CHECKSUMS:
|
||||
react-native-slider: 6e9b86e76cce4b9e35b3403193a6432ed07e0c81
|
||||
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
|
||||
react-native-video: a4c2635d0802f983594b7057e1bce8f442f0ad28
|
||||
react-native-webrtc: b8f2769386d51a6a8c89778478618fe311226bc3
|
||||
react-native-webrtc: 206a0ac12a5633d2ec4605174d7c9f12f0d674b2
|
||||
react-native-webview: ea4899a1056c782afa96dd082179a66cbebf5504
|
||||
React-perflogger: 30ab8d6db10e175626069e742eead3ebe8f24fd5
|
||||
React-RCTActionSheet: 4b45da334a175b24dabe75f856b98fed3dfd6201
|
||||
@@ -749,4 +749,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: bef1335067eaa4e8c558b1248f8ab3948de855bc
|
||||
|
||||
COCOAPODS: 1.11.2
|
||||
COCOAPODS: 1.11.3
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>22.2.0</string>
|
||||
<string>22.3.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSExtension</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>22.2.0</string>
|
||||
<string>22.3.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>22.2.0</string>
|
||||
<string>22.3.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>22.2.0</string>
|
||||
<string>22.3.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>CLKComplicationPrincipalClass</key>
|
||||
|
||||
@@ -12,6 +12,8 @@ DO_GIT_TAG=${GIT_TAG:-0}
|
||||
|
||||
echo "Releasing Jitsi Meet SDK ${SDK_VERSION}"
|
||||
|
||||
${THIS_DIR}/../../node_modules/react-native-webrtc/tools/downloadBitcode.sh
|
||||
|
||||
pushd ${RELEASE_REPO}
|
||||
|
||||
# Generate podspec file
|
||||
|
||||
@@ -248,6 +248,8 @@ RCT_EXPORT_METHOD(updateDeviceList) {
|
||||
- (void)audioSessionDidChangeRoute:(RTCAudioSession *)session
|
||||
reason:(AVAudioSessionRouteChangeReason)reason
|
||||
previousRoute:(AVAudioSessionRouteDescription *)previousRoute {
|
||||
DDLogInfo(@"[AudioMode] Route changed, reason: %lu", (unsigned long)reason);
|
||||
|
||||
// Update JS about the changes.
|
||||
[self notifyDevicesChanged];
|
||||
|
||||
@@ -259,16 +261,12 @@ RCT_EXPORT_METHOD(updateDeviceList) {
|
||||
self->forceSpeaker = NO;
|
||||
self->forceEarpiece = NO;
|
||||
break;
|
||||
case AVAudioSessionRouteChangeReasonCategoryChange: {
|
||||
// The category has changed. Check if it's the one we want and adjust as
|
||||
// needed.
|
||||
RTCAudioSessionConfiguration *currentConfig = [self configForMode:self->activeMode];
|
||||
if ([session.category isEqualToString:currentConfig.category]) {
|
||||
// We are in the desired category, nothing to do here.
|
||||
return;
|
||||
}
|
||||
case AVAudioSessionRouteChangeReasonCategoryChange:
|
||||
// The category has changed, re-apply our config.
|
||||
// NB: It's tempting to doa category check here and skip the processing,
|
||||
// but that won't work. If the config changes but the category remains
|
||||
// the same we'll still find ourselves here.
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -27,5 +27,6 @@
|
||||
- (void)closeChat;
|
||||
- (void)sendChatMessage:(NSString*)message :(NSString*)to ;
|
||||
- (void)sendSetVideoMuted:(BOOL)muted;
|
||||
- (void)sendSetClosedCaptionsEnabled:(BOOL)enabled;
|
||||
|
||||
@end
|
||||
|
||||
@@ -27,6 +27,7 @@ static NSString * const openChatAction = @"org.jitsi.meet.OPEN_CHAT";
|
||||
static NSString * const closeChatAction = @"org.jitsi.meet.CLOSE_CHAT";
|
||||
static NSString * const sendChatMessageAction = @"org.jitsi.meet.SEND_CHAT_MESSAGE";
|
||||
static NSString * const setVideoMutedAction = @"org.jitsi.meet.SET_VIDEO_MUTED";
|
||||
static NSString * const setClosedCaptionsEnabledAction = @"org.jitsi.meet.SET_CLOSED_CAPTIONS_ENABLED";
|
||||
|
||||
@implementation ExternalAPI
|
||||
|
||||
@@ -49,7 +50,8 @@ RCT_EXPORT_MODULE();
|
||||
@"OPEN_CHAT": openChatAction,
|
||||
@"CLOSE_CHAT": closeChatAction,
|
||||
@"SEND_CHAT_MESSAGE": sendChatMessageAction,
|
||||
@"SET_VIDEO_MUTED" : setVideoMutedAction
|
||||
@"SET_VIDEO_MUTED" : setVideoMutedAction,
|
||||
@"SET_CLOSED_CAPTIONS_ENABLED": setClosedCaptionsEnabledAction
|
||||
};
|
||||
};
|
||||
|
||||
@@ -73,7 +75,8 @@ RCT_EXPORT_MODULE();
|
||||
openChatAction,
|
||||
closeChatAction,
|
||||
sendChatMessageAction,
|
||||
setVideoMutedAction
|
||||
setVideoMutedAction,
|
||||
setClosedCaptionsEnabledAction
|
||||
];
|
||||
}
|
||||
|
||||
@@ -205,5 +208,10 @@ RCT_EXPORT_METHOD(sendEvent:(NSString *)name
|
||||
[self sendEventWithName:setVideoMutedAction body:data];
|
||||
}
|
||||
|
||||
- (void)sendSetClosedCaptionsEnabled:(BOOL)enabled {
|
||||
NSDictionary *data = @{ @"enabled": [NSNumber numberWithBool:enabled]};
|
||||
|
||||
[self sendEventWithName:setClosedCaptionsEnabledAction body:data];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.1.0</string>
|
||||
<string>5.2.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -45,5 +45,6 @@
|
||||
- (void)closeChat;
|
||||
- (void)sendChatMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to;
|
||||
- (void)setVideoMuted:(BOOL)muted;
|
||||
- (void)setClosedCaptionsEnabled:(BOOL)enabled;
|
||||
|
||||
@end
|
||||
|
||||
@@ -160,6 +160,11 @@ static void initializeViewsMap() {
|
||||
[externalAPI sendSetVideoMuted:muted];
|
||||
}
|
||||
|
||||
- (void)setClosedCaptionsEnabled:(BOOL)enabled {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI sendSetClosedCaptionsEnabled:enabled];
|
||||
}
|
||||
|
||||
#pragma mark Private methods
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
import UIKit
|
||||
|
||||
final class DragGestureController {
|
||||
|
||||
var insets: UIEdgeInsets = UIEdgeInsets.zero
|
||||
var currentPosition: PiPViewCoordinator.Position? = nil
|
||||
|
||||
private var frameBeforeDragging: CGRect = CGRect.zero
|
||||
private weak var view: UIView?
|
||||
private lazy var panGesture: UIPanGestureRecognizer = {
|
||||
return UIPanGestureRecognizer(target: self,
|
||||
action: #selector(handlePan(gesture:)))
|
||||
UIPanGestureRecognizer(target: self,
|
||||
action: #selector(handlePan(gesture:)))
|
||||
}()
|
||||
|
||||
func startDragListener(inView view: UIView) {
|
||||
@@ -40,7 +40,7 @@ final class DragGestureController {
|
||||
}
|
||||
|
||||
@objc private func handlePan(gesture: UIPanGestureRecognizer) {
|
||||
guard let view = self.view else { return }
|
||||
guard let view = view else { return }
|
||||
|
||||
let translation = gesture.translation(in: view.superview)
|
||||
let velocity = gesture.velocity(in: view.superview)
|
||||
@@ -65,7 +65,7 @@ final class DragGestureController {
|
||||
let velocityMagnitude = magnitude(vector: velocity)
|
||||
let animationDuration = 0.5
|
||||
let initialSpringVelocity =
|
||||
velocityMagnitude / distanceMagnitude / CGFloat(animationDuration)
|
||||
velocityMagnitude / distanceMagnitude / CGFloat(animationDuration)
|
||||
|
||||
frame.origin = CGPoint(x: finalPos.x, y: finalPos.y)
|
||||
|
||||
@@ -75,8 +75,7 @@ final class DragGestureController {
|
||||
initialSpringVelocity: initialSpringVelocity,
|
||||
options: .curveLinear,
|
||||
animations: {
|
||||
view.frame = frame
|
||||
}, completion: nil)
|
||||
view.frame = frame })
|
||||
|
||||
default:
|
||||
break
|
||||
@@ -85,9 +84,11 @@ final class DragGestureController {
|
||||
|
||||
private func calculateFinalPosition() -> CGPoint {
|
||||
guard
|
||||
let view = self.view,
|
||||
let view = view,
|
||||
let bounds = view.superview?.frame
|
||||
else { return CGPoint.zero }
|
||||
else {
|
||||
return CGPoint.zero
|
||||
}
|
||||
|
||||
let currentSize = view.frame.size
|
||||
let adjustedBounds = bounds.inset(by: insets)
|
||||
@@ -109,19 +110,26 @@ final class DragGestureController {
|
||||
goUp = location.y < bounds.midY
|
||||
}
|
||||
|
||||
let finalPosX: CGFloat =
|
||||
goLeft
|
||||
? adjustedBounds.origin.x
|
||||
: bounds.size.width - insets.right - currentSize.width
|
||||
let finalPosY: CGFloat =
|
||||
goUp
|
||||
? adjustedBounds.origin.y
|
||||
: bounds.size.height - insets.bottom - currentSize.height
|
||||
if (goLeft && goUp) {
|
||||
currentPosition = .upperLeftCorner
|
||||
}
|
||||
|
||||
return CGPoint(x: finalPosX, y: finalPosY)
|
||||
if (!goLeft && goUp) {
|
||||
currentPosition = .upperRightCorner
|
||||
}
|
||||
|
||||
if (!goLeft && !goUp) {
|
||||
currentPosition = .lowerRightCorner
|
||||
}
|
||||
|
||||
if (goLeft && !goUp) {
|
||||
currentPosition = .lowerLeftCorner
|
||||
}
|
||||
|
||||
return currentPosition!.getOriginIn(bounds: adjustedBounds, size: currentSize)
|
||||
}
|
||||
|
||||
private func magnitude(vector: CGPoint) -> CGFloat {
|
||||
return sqrt(pow(vector.x, 2) + pow(vector.y, 2))
|
||||
sqrt(pow(vector.x, 2) + pow(vector.y, 2))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,16 +19,23 @@ import UIKit
|
||||
public typealias AnimationCompletion = (Bool) -> Void
|
||||
|
||||
public protocol PiPViewCoordinatorDelegate: class {
|
||||
|
||||
|
||||
func exitPictureInPicture()
|
||||
}
|
||||
|
||||
/// Coordinates the view state of a specified view to allow
|
||||
/// to be presented in full screen or in a custom Picture in Picture mode.
|
||||
/// This object will also provide the drag and tap interactions of the view
|
||||
/// when is presented in Picure in Picture mode.
|
||||
/// when is presented in Picture in Picture mode.
|
||||
public class PiPViewCoordinator {
|
||||
|
||||
|
||||
public enum Position {
|
||||
case lowerRightCorner
|
||||
case upperRightCorner
|
||||
case lowerLeftCorner
|
||||
case upperLeftCorner
|
||||
}
|
||||
|
||||
/// Limits the boundaries of view position on screen when minimized
|
||||
public var dragBoundInsets: UIEdgeInsets = UIEdgeInsets(top: 25,
|
||||
left: 5,
|
||||
@@ -39,23 +46,15 @@ public class PiPViewCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
public enum Position {
|
||||
case lowerRightCorner
|
||||
case upperRightCorner
|
||||
case lowerLeftCorner
|
||||
case upperLeftCorner
|
||||
}
|
||||
|
||||
public var initialPositionInSuperview = Position.lowerRightCorner
|
||||
|
||||
public let initialPositionInSuperView: Position = .lowerRightCorner
|
||||
|
||||
// Unused. Remove on the next major release.
|
||||
@available(*, deprecated, message: "The PiP window size is now fixed to 150px.")
|
||||
public var c: CGFloat = 0.0
|
||||
|
||||
|
||||
public weak var delegate: PiPViewCoordinatorDelegate?
|
||||
|
||||
private(set) var isInPiP: Bool = false // true if view is in PiP mode
|
||||
|
||||
private(set) var view: UIView
|
||||
private var currentBounds: CGRect = CGRect.zero
|
||||
|
||||
@@ -66,6 +65,13 @@ public class PiPViewCoordinator {
|
||||
|
||||
public init(withView view: UIView) {
|
||||
self.view = view
|
||||
// Required because otherwise the view will not rotate correctly.
|
||||
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
|
||||
// Otherwise the enter/exit pip animation looks odd
|
||||
// when pip window is bottom left, top left or top right,
|
||||
// because the jitsi view content does not animate, but jumps to the new size immediately.
|
||||
view.clipsToBounds = true
|
||||
}
|
||||
|
||||
/// Configure the view to be always on top of all the contents
|
||||
@@ -74,7 +80,9 @@ public class PiPViewCoordinator {
|
||||
public func configureAsStickyView(withParentView parentView: UIView? = nil) {
|
||||
guard
|
||||
let parentView = parentView ?? UIApplication.shared.keyWindow
|
||||
else { return }
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
parentView.addSubview(view)
|
||||
currentBounds = parentView.bounds
|
||||
@@ -109,6 +117,9 @@ public class PiPViewCoordinator {
|
||||
/// around screen, and add a button of top of the view to be able to exit mode
|
||||
public func enterPictureInPicture() {
|
||||
isInPiP = true
|
||||
// Resizing is done by hand when in pip.
|
||||
view.autoresizingMask = []
|
||||
|
||||
animateViewChange()
|
||||
dragController.startDragListener(inView: view)
|
||||
dragController.insets = dragBoundInsets
|
||||
@@ -125,6 +136,9 @@ public class PiPViewCoordinator {
|
||||
/// exit pip button, and disable the drag gesture
|
||||
@objc public func exitPictureInPicture() {
|
||||
isInPiP = false
|
||||
// Enable autoresizing again, which got disabled for pip.
|
||||
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
|
||||
animateViewChange()
|
||||
dragController.stopDragListener()
|
||||
|
||||
@@ -136,7 +150,7 @@ public class PiPViewCoordinator {
|
||||
let exitSelector = #selector(toggleExitPiP)
|
||||
tapGestureRecognizer?.removeTarget(self, action: exitSelector)
|
||||
tapGestureRecognizer = nil
|
||||
|
||||
|
||||
delegate?.exitPictureInPicture()
|
||||
}
|
||||
|
||||
@@ -144,6 +158,12 @@ public class PiPViewCoordinator {
|
||||
/// screen size changes
|
||||
public func resetBounds(bounds: CGRect) {
|
||||
currentBounds = bounds
|
||||
|
||||
// Is required because otherwise the pip window is buggy when rotating the device.
|
||||
// When not in pip then autoresize will do the job.
|
||||
if (isInPiP) {
|
||||
view.frame = changeViewRect()
|
||||
}
|
||||
}
|
||||
|
||||
/// Stop the dragging gesture of the root view
|
||||
@@ -169,7 +189,6 @@ public class PiPViewCoordinator {
|
||||
}
|
||||
|
||||
// MARK: - Interactions
|
||||
|
||||
@objc private func toggleExitPiP() {
|
||||
if exitPiPButton == nil {
|
||||
// show button
|
||||
@@ -186,44 +205,28 @@ public class PiPViewCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Size calculation
|
||||
|
||||
private func animateViewChange() {
|
||||
func animateViewChange() {
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
self.view.frame = self.changeViewRect()
|
||||
self.view.setNeedsLayout()
|
||||
}
|
||||
}
|
||||
|
||||
private func changeViewRect() -> CGRect {
|
||||
let bounds = currentBounds
|
||||
|
||||
guard isInPiP else {
|
||||
if !isInPiP {
|
||||
return bounds
|
||||
}
|
||||
|
||||
// resize to suggested ratio and position to the bottom right
|
||||
let adjustedBounds = bounds.inset(by: dragBoundInsets)
|
||||
let size = CGSize(width: 150, height: 150)
|
||||
let origin = initialPositionFor(pipSize: size, bounds: adjustedBounds)
|
||||
let origin = (dragController.currentPosition ?? initialPositionInSuperView).getOriginIn(bounds: adjustedBounds, size: size)
|
||||
|
||||
return CGRect(x: origin.x, y: origin.y, width: size.width, height: size.height)
|
||||
}
|
||||
|
||||
private func initialPositionFor(pipSize size: CGSize, bounds: CGRect) -> CGPoint {
|
||||
switch initialPositionInSuperview {
|
||||
case .lowerLeftCorner:
|
||||
return CGPoint(x: bounds.minX, y: bounds.maxY - size.height)
|
||||
case .lowerRightCorner:
|
||||
return CGPoint(x: bounds.maxX - size.width, y: bounds.maxY - size.height)
|
||||
case .upperLeftCorner:
|
||||
return CGPoint(x: bounds.minX, y: bounds.minY)
|
||||
case .upperRightCorner:
|
||||
return CGPoint(x: bounds.maxX - size.width, y: bounds.minY)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Animation helpers
|
||||
|
||||
private func animateTransition(animations: @escaping () -> Void,
|
||||
completion: AnimationCompletion?) {
|
||||
UIView.animate(withDuration: 0.1,
|
||||
@@ -234,3 +237,19 @@ public class PiPViewCoordinator {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
extension PiPViewCoordinator.Position {
|
||||
func getOriginIn(bounds: CGRect, size: CGSize) -> CGPoint {
|
||||
switch self {
|
||||
case .lowerLeftCorner:
|
||||
return CGPoint(x: bounds.minX, y: bounds.maxY - size.height)
|
||||
case .lowerRightCorner:
|
||||
return CGPoint(x: bounds.maxX - size.width, y: bounds.maxY - size.height)
|
||||
case .upperLeftCorner:
|
||||
return CGPoint(x: bounds.minX, y: bounds.minY)
|
||||
case .upperRightCorner:
|
||||
return CGPoint(x: bounds.maxX - size.width, y: bounds.minY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,17 @@
|
||||
"refresh": "حدِّث الرزنامة",
|
||||
"today": "اليوم"
|
||||
},
|
||||
"carmode": {
|
||||
"actions": {
|
||||
"leaveMeeting": "اترك الاجتماع",
|
||||
"selectSoundDevice": "حدد جهاز الصوت"
|
||||
},
|
||||
"labels": {
|
||||
"buttonLabel": "وضع السيارة",
|
||||
"title": "وضع القيادة الآمنة",
|
||||
"videoStopped": "تم إيقاف الفيديو الخاص بك"
|
||||
}
|
||||
},
|
||||
"chat": {
|
||||
"enter": "أدخل الغرفة",
|
||||
"error": "خطأ: لم تُرسَل رسالتك. السبب: {{error}}",
|
||||
@@ -105,6 +116,7 @@
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
"buttonText": "نزِّل إضافة متصفح كروم",
|
||||
"buttonTextEdge": "قم بتثبيت ملحق Edge",
|
||||
"close": "إغلق",
|
||||
"dontShowAgain": "لا ترني هذه مرة أخرى",
|
||||
"installExtensionText": "نزِّل الإضافة للدمج مع رزنامة غوغل ورزنامة أوفيس 365"
|
||||
@@ -196,6 +208,9 @@
|
||||
"selectADevice": "اختر جهازًا",
|
||||
"testAudio": "اختبر الصوت"
|
||||
},
|
||||
"dialIn": {
|
||||
"screenTitle": "ملخص الطلب"
|
||||
},
|
||||
"dialOut": {
|
||||
"statusMessage": "{{status}} الآن"
|
||||
},
|
||||
@@ -646,6 +661,8 @@
|
||||
"linkToSalesforceKey": "ربط هذا المُلتقى",
|
||||
"linkToSalesforceProgress": "جارٍ ربط الاجتماع بـ Salesforce ...",
|
||||
"linkToSalesforceSuccess": "تم ربط الاجتماع بـ Salesforce",
|
||||
"localRecordingStarted": "بدأ {{name}} تسجيلًا محليًا.",
|
||||
"localRecordingStopped": "أوقف {{name}} التسجيل المحلي.",
|
||||
"me": "أنا",
|
||||
"moderationInEffectCSDescription": "يرجى رفع اليد إذا كنت تريد مشاركة شاشتك.",
|
||||
"moderationInEffectCSTitle": "تم حظر مشاركة الشاشة من قبل المشرف",
|
||||
@@ -801,6 +818,7 @@
|
||||
"initiated": "بدأ الاتصال",
|
||||
"joinAudioByPhone": "انضم مع صوت من الجوال",
|
||||
"joinMeeting": "انضم للمُلتقى",
|
||||
"joinMeetingInLowBandwidthMode": "الانضمام في وضع النطاق الترددي المنخفض",
|
||||
"joinWithoutAudio": "انضم دون صوت",
|
||||
"keyboardShortcuts": "تفعيل اختصارات لوحة المفاتيح",
|
||||
"linkCopied": "نُسِخ الرابط",
|
||||
@@ -876,6 +894,7 @@
|
||||
"limitNotificationDescriptionWeb": "نظرًا للضغط الكبير، سيقيَّد التسجيل إلى {{limit}} د، ولكن إن أردت التسجيل لمدة مفتوحة، جرِّب <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"linkGenerated": "لقد أنشأنا رابطًا لتسجيلك.",
|
||||
"live": "مباشر",
|
||||
"localRecordingWarning": "تأكد من تحديد علامة التبويب الحالية لاستخدام الفيديو والصوت الصحيحين. التسجيل محدود حاليًا بـ 1 كيغابايت ، أي حوالي 100 دقيقة.",
|
||||
"loggedIn": "مُسجَّل باسم {{userName}}",
|
||||
"off": "أوقِف التسجيل",
|
||||
"offBy": "أوقَف {{name}} التسجيل",
|
||||
@@ -883,6 +902,7 @@
|
||||
"onBy": "بدأ {{name}} التسجيل",
|
||||
"pending": "التحضير لتسجيل المُلتقى...",
|
||||
"rec": "تسجيل",
|
||||
"saveLocalRecording": "حفظ ملف التسجيل محليا",
|
||||
"serviceDescription": "ستحفظ خدمة التسجيل الفيديو المستجل",
|
||||
"serviceDescriptionCloud": "تسجيل سحابي",
|
||||
"serviceDescriptionCloudInfo": "يتم مسح المُلتقيات المسجلة تلقائيًا بعد 24 ساعة من وقت التسجيل.",
|
||||
@@ -890,10 +910,12 @@
|
||||
"sessionAlreadyActive": "هذه الجلسة قيد التسجيل أو البث المباشر.",
|
||||
"signIn": "دخول",
|
||||
"signOut": "خروج",
|
||||
"surfaceError": "الرجاء تحديد علامة التبويب الحالية.",
|
||||
"unavailable": "عجبًا! {{serviceName}} غير متاحة حاليًا. نعمل على حل المشكلة. حاول مرة أخرى لاحقًا.",
|
||||
"unavailableTitle": "التسجيل غير متاح",
|
||||
"uploadToCloud": "تحميل إلى السحابة"
|
||||
},
|
||||
"screenshareDisplayName": "شاشة {{name}}",
|
||||
"sectionList": {
|
||||
"pullToRefresh": "اسحب للتحديث"
|
||||
},
|
||||
@@ -931,6 +953,7 @@
|
||||
"playSounds": "تشغيل الصوت عند:",
|
||||
"reactions": "ردود فعل المُلتقى",
|
||||
"sameAsSystem": "مثل النظام ({{label}})",
|
||||
"screenTitle": "إعدادات",
|
||||
"selectAudioOutput": "خرج الصوت",
|
||||
"selectCamera": "الكاميرا",
|
||||
"selectMic": "المجهار (المايكروفون)",
|
||||
@@ -956,6 +979,7 @@
|
||||
"disableCrashReportingWarning": "أمتأكد من تعطيل تقارير الأعطال التقنية؟ ستسري الإعدادات الجديدة بعد إعادة تشغيل التطبيق",
|
||||
"disableP2P": "تعطيل وضع واحد شخص-لشخص",
|
||||
"displayName": "عرض الاسم",
|
||||
"displayNamePlaceholderText": "على سبيل المثال: علي الحيدري",
|
||||
"email": "البريد الإلكتروني",
|
||||
"header": "الإعدادات",
|
||||
"profileSection": "الملف الشخصي",
|
||||
@@ -1009,10 +1033,12 @@
|
||||
"boo": "Boo",
|
||||
"breakoutRoom": "الانضمام / مغادرة غرفة فرعية",
|
||||
"callQuality": "اضبط دقة الفيديو",
|
||||
"carmode": "وضع السيارة",
|
||||
"cc": "اظهِر/اخفِ الترجمة",
|
||||
"chat": "اظهِر/اخفِ نافذة الدردشة",
|
||||
"clap": "تصفيق",
|
||||
"collapse": "قلّص",
|
||||
"dock": "إرساء في النافذة الرئيسية",
|
||||
"document": "اظهِر/اخفِ الملف المشارك",
|
||||
"download": "نزِّل التطبيق",
|
||||
"embedMeeting": "ضمِّن المُلتقى",
|
||||
@@ -1063,6 +1089,7 @@
|
||||
"tileView": "اظهِر/اخفِ عرض العنوان",
|
||||
"toggleCamera": "بدِّل الكاميرا",
|
||||
"toggleFilmstrip": "بدِّل وضع الشريط السينمائي (filmstrip)",
|
||||
"undock": "فك في نافذة منفصلة",
|
||||
"videoblur": "استعمل/اخرج من وضع تغبيش خلفية الفيديو",
|
||||
"videomute": "بدِّل وضع اخفاء الفيديو"
|
||||
},
|
||||
@@ -1079,6 +1106,7 @@
|
||||
"closeChat": "أغلق الدردشة",
|
||||
"closeReactionsMenu": "إغلاق قائمة ردود الفعل",
|
||||
"disableReactionSounds": "يمكنك تعطيل أصوات ردود الفعل لهذا المُلتقى",
|
||||
"dock": "إرساء في النافذة الرئيسية",
|
||||
"documentClose": "أغلق الملف المشارك",
|
||||
"documentOpen": "افتح الملف المشارك",
|
||||
"download": "نزِّل التطبيق",
|
||||
@@ -1147,6 +1175,7 @@
|
||||
"talkWhileMutedPopup": "أتحاول التحدث؟ المجهار مكتوم لديك.",
|
||||
"tileViewToggle": "بدِّل عنوان العرض",
|
||||
"toggleCamera": "بدِّل الكاميرا",
|
||||
"undock": "فك في نافذة منفصلة",
|
||||
"videoSettings": "اعدادات الفيديو",
|
||||
"videomute": "استعمل / أوقف الكاميرا"
|
||||
},
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
},
|
||||
"audioDevices": {
|
||||
"bluetooth": "Bluetooth",
|
||||
"car": "Àudio del cotxe",
|
||||
"headphones": "Auriculars",
|
||||
"none": "No hi ha disponible cap aparell d'àudio",
|
||||
"phone": "Telèfon",
|
||||
@@ -39,9 +40,6 @@
|
||||
"audioOnly": {
|
||||
"audioOnly": "Poca amplada de banda"
|
||||
},
|
||||
"blankPage": {
|
||||
"meetingEnded": "La reunió ha acabat"
|
||||
},
|
||||
"breakoutRooms": {
|
||||
"actions": {
|
||||
"add": "Afegeix una sala de descans",
|
||||
@@ -79,10 +77,22 @@
|
||||
"refresh": "Actualitza l'agenda",
|
||||
"today": "Avui"
|
||||
},
|
||||
"carmode": {
|
||||
"actions": {
|
||||
"leaveMeeting": "Abandona la reunió",
|
||||
"selectSoundDevice": "Seleccioneu l'aparell d'àudio"
|
||||
},
|
||||
"labels": {
|
||||
"buttonLabel": "Mode cotxe",
|
||||
"title": "Mode conducció segura",
|
||||
"videoStopped": "El vídeo està aturat"
|
||||
}
|
||||
},
|
||||
"chat": {
|
||||
"enter": "Entra a la sala",
|
||||
"error": "Error: no s'ha enviat el missatge. Raó: {{error}}",
|
||||
"fieldPlaceHolder": "Escriviu aquí el missatge",
|
||||
"lobbyChatMessageTo": "Envia un missatge en la sala d'espera a {{recipient}}",
|
||||
"message": "Missatge",
|
||||
"messageAccessibleTitle": "{{user}} diu:",
|
||||
"messageAccessibleTitleMe": "jo dic:",
|
||||
@@ -208,13 +218,15 @@
|
||||
"Remove": "Elimina",
|
||||
"Share": "Comparteix",
|
||||
"Submit": "Tramet",
|
||||
"WaitForHostMsg": "La conferència encara no ha començat. Si en sou l'amfitrió autentiqueu-vos. Altrament, espereu que arribi l'amfitrió.",
|
||||
"WaitForHostMsg": "La conferència encara no ha començat. Si en sou l'amfitrió, autentiqueu-vos. Altrament, espereu que arribi l'amfitrió.",
|
||||
"WaitingForHostTitle": "S'està esperant l'amfitrió...",
|
||||
"Yes": "Sí",
|
||||
"accessibilityLabel": {
|
||||
"liveStreaming": "Transmissió en directe"
|
||||
},
|
||||
"add": "Afegeix",
|
||||
"addMeetingNote": "Afegiu una nota sobre aquesta reunió",
|
||||
"addOptionalNote": "Afegeix una nota (opcional):",
|
||||
"allow": "Permet",
|
||||
"alreadySharedVideoMsg": "Un altre participant està compartint un vídeo. Aquesta conferència només permet compartir un vídeo a la vegada.",
|
||||
"alreadySharedVideoTitle": "Només es permet un vídeo compartit a la vegada",
|
||||
@@ -266,6 +278,8 @@
|
||||
"kickParticipantDialog": "Esteu segur que voleu expulsar aquest participant?",
|
||||
"kickParticipantTitle": "Voleu expulsar aquest participant?",
|
||||
"kickTitle": "Ep! {{participantDisplayName}} us ha expulsat de la reunió",
|
||||
"linkMeeting": "Enllaça la reunió",
|
||||
"linkMeetingTitle": "Enllaça la reunió a Salesforce",
|
||||
"liveStreaming": "Transmissió en directe",
|
||||
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "No és possible mentre l'enregistrament estigui actiu",
|
||||
"liveStreamingDisabledTooltip": "No es pot iniciar la transmissió en directe.",
|
||||
@@ -320,6 +334,7 @@
|
||||
"popupError": "El vostre navegador bloca les finestres emergents d'aquest lloc. Habiliteu les finestres emergents a la configuració de seguretat del navegador i torneu-ho a intentar.",
|
||||
"popupErrorTitle": "Finestres emergents blocades",
|
||||
"readMore": "més",
|
||||
"recentlyUsedObjects": "Els objectes que heu usat recentment",
|
||||
"recording": "Enregistrament",
|
||||
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "No és possible mentre hi ha una transmissió en directe activa",
|
||||
"recordingDisabledTooltip": "No es pot enregistrar.",
|
||||
@@ -342,6 +357,12 @@
|
||||
"screenSharingFailed": "Ep! Alguna cosa ha anat malament, no hem pogut iniciar la compartició de pantalla!",
|
||||
"screenSharingFailedTitle": "La compartició de pantalla ha fallat!",
|
||||
"screenSharingPermissionDeniedError": "Ep! Alguna cosa ha anat malament amb els permisos de compartició de pantalla. Torna a carregar-la i prova-ho una altra vegada.",
|
||||
"searchInSalesforce": "Cerca a Salesforce",
|
||||
"searchResults": "Resultats de la cerca({{count}})",
|
||||
"searchResultsDetailsError": "Alguna cosa ha anat malament en recuperar les dades del propietari.",
|
||||
"searchResultsError": "Alguna cosa ha anat malament en recuperar les dades.",
|
||||
"searchResultsNotFound": "No s'ha trobat cap resultat.",
|
||||
"searchResultsTryAgain": "Proveu usant paraules clau alternatives.",
|
||||
"sendPrivateMessage": "Fa poc que heu rebut un missatge privat. Voleu respondre'l de forma privada, o voleu enviar el missatge al grup?",
|
||||
"sendPrivateMessageCancel": "Envia'l al grup",
|
||||
"sendPrivateMessageOk": "Envia'l en privat",
|
||||
@@ -351,20 +372,22 @@
|
||||
"sessionRestarted": "La trucada s'ha reiniciat a causa d'un problema de connexió.",
|
||||
"shareAudio": "Continua",
|
||||
"shareAudioTitle": "Com compartir l'àudio",
|
||||
"shareAudioWarningD1": "heu d'aturar la compartició de pantalla abans de compartir l'àudio.",
|
||||
"shareAudioWarningD2": "heu de reiniciar la compartició de pantalla i marcar l'opció «Comparteix l'àudio».",
|
||||
"shareAudioWarningD1": "cal que atureu la compartició de pantalla abans de compartir l'àudio.",
|
||||
"shareAudioWarningD2": "cal que reinicieu la compartició de pantalla i marqueu l'opció «Comparteix l'àudio».",
|
||||
"shareAudioWarningH1": "Si voleu compartir només l'àudio:",
|
||||
"shareAudioWarningTitle": "Heu d'aturar la compartició de pantalla abans de compartir l'àudio",
|
||||
"shareAudioWarningTitle": "Cal que atureu la compartició de pantalla abans de compartir l'àudio",
|
||||
"shareMediaWarningGenericH2": "Si voleu compartir la pantalla i l'àudio",
|
||||
"shareScreenWarningD1": "heu d'aturar l'ús compartit d'àudio abans de compartir la pantalla.",
|
||||
"shareScreenWarningD2": "heu d'aturar l'ús compartit d'àudio, iniciar l'ús compartit de la pantalla i marcar l'opció «Comparteix l'àudio».",
|
||||
"shareScreenWarningH1": "Si només voleu compartir la pantalla:",
|
||||
"shareScreenWarningTitle": "Heu d'aturar l'ús compartit d'àudio abans de compartir la pantalla",
|
||||
"shareScreenWarningTitle": "Cal que atureu l'ús compartit d'àudio abans de compartir la pantalla",
|
||||
"shareVideoLinkError": "Proporcioneu un enllaç de vídeo correcte.",
|
||||
"shareVideoTitle": "Comparteix el vídeo",
|
||||
"shareYourScreen": "Comparteix la pantalla",
|
||||
"shareYourScreenDisabled": "S'ha inhabilitat la compartició de pantalla.",
|
||||
"sharedVideoDialogError": "Error: URL no vàlid",
|
||||
"sharedVideoLinkPlaceholder": "Enllaç de YouTube o enllaç directe del vídeo",
|
||||
"start": "Inicia",
|
||||
"startLiveStreaming": "Inicia la transmissió en directe",
|
||||
"startRecording": "Inicia l'enregistrament",
|
||||
"startRemoteControlErrorMessage": "S'ha produït un error en intentar iniciar la sessió de control remot!",
|
||||
@@ -407,6 +430,10 @@
|
||||
"veryBad": "Molt dolenta",
|
||||
"veryGood": "Molt bona"
|
||||
},
|
||||
"giphy": {
|
||||
"noResults": "No s'ha trobat cap resultat :(",
|
||||
"search": "Cerca a GIPHY"
|
||||
},
|
||||
"helpView": {
|
||||
"header": "Centre d'ajuda"
|
||||
},
|
||||
@@ -473,6 +500,7 @@
|
||||
"focusLocal": "Focus al vostre vídeo",
|
||||
"focusRemote": "Focus en el vídeo d'una altra persona",
|
||||
"fullScreen": "Entra o surt de la pantalla completa",
|
||||
"giphyMenu": "Mostra o amaga el menú GIPHY",
|
||||
"keyboardShortcuts": "Dreceres de teclat",
|
||||
"localRecording": "Mostra o amaga els controls d'enregistrament local",
|
||||
"mute": "Silencia o activa el so",
|
||||
@@ -527,6 +555,7 @@
|
||||
"admitAll": "Admet tothom",
|
||||
"allow": "Permet",
|
||||
"backToKnockModeButton": "Demaneu per a unir-vos",
|
||||
"chat": "Xat",
|
||||
"dialogTitle": "Mode de sala d'espera",
|
||||
"disableDialogContent": "El mode de sala d'espera es troba activat. Aquesta funcionalitat evita que els participants no desitjats puguin unir-se a la reunió. Voleu desactivar-ho?",
|
||||
"disableDialogSubmit": "Desactiva",
|
||||
@@ -539,6 +568,7 @@
|
||||
"errorMissingPassword": "Introduïu la contrasenya de la reunió",
|
||||
"invalidPassword": "La contrasenya no és vàlida",
|
||||
"joinRejectedMessage": "La vostra sol·licitud ha estat rebutjada per un moderador.",
|
||||
"joinRejectedTitle": "S'ha rebutjat la petició d'unir-s'hi.",
|
||||
"joinTitle": "Entra a la reunió",
|
||||
"joinWithPasswordMessage": "S'està intentant unir-s'hi amb contrasenya, espereu...",
|
||||
"joiningMessage": "Us unireu a la reunió de seguida que algú accepti la sol·licitud",
|
||||
@@ -547,6 +577,8 @@
|
||||
"knockButton": "Demana d'unir-se",
|
||||
"knockTitle": "Algú vol unir-se a la reunió",
|
||||
"knockingParticipantList": "Llista de participants que piquen per a entrar",
|
||||
"lobbyChatStartedNotification": "{{moderator}} ha començat un xat en la sala d'espera amb {{attendee}}",
|
||||
"lobbyChatStartedTitle": "{{moderator}} ha començat un xat en la sala d'espera amb vós.",
|
||||
"nameField": "Introduïu el vostre nom",
|
||||
"notificationLobbyAccessDenied": "{{originParticipantName}} ha rebutjat l'entrada de {{targetParticipantName}}",
|
||||
"notificationLobbyAccessGranted": "{{originParticipantName}} ha acceptat l'entrada de {{targetParticipantName}}",
|
||||
@@ -609,6 +641,7 @@
|
||||
"displayNotifications": "Mostra les notificacions sobre",
|
||||
"focus": "Focus de la conferència",
|
||||
"focusFail": "{{component}} no és disponible, torneu a intentar en {{ms}} segons",
|
||||
"gifsMenu": "GIPHY",
|
||||
"groupTitle": "Notificacions",
|
||||
"hostAskedUnmute": "El moderador vol que parleu",
|
||||
"invitedOneMember": "S'ha convidat {{name}}",
|
||||
@@ -618,6 +651,12 @@
|
||||
"leftOneMember": "{{name}} ha sortit de la reunió",
|
||||
"leftThreePlusMembers": "{{name}} i molts d'altres han sortit de la reunió",
|
||||
"leftTwoMembers": "{{first}} i {{second}} han sortit de la reunió",
|
||||
"linkToSalesforce": "Enllaç a Salesforce",
|
||||
"linkToSalesforceDescription": "Podeu enllaçar el resum de la reunió a un objecte Salesforce.",
|
||||
"linkToSalesforceError": "No s'ha pogut enllaçar la reunió a Salesforce",
|
||||
"linkToSalesforceKey": "Enllaça aquesta reunió",
|
||||
"linkToSalesforceProgress": "S'està enllaçant la reunió a Salesforce...",
|
||||
"linkToSalesforceSuccess": "La reunió s'ha enllaçat a Salesforce",
|
||||
"me": "Jo",
|
||||
"moderationInEffectCSDescription": "Aixequeu la mà si voleu compartir la pantalla.",
|
||||
"moderationInEffectCSTitle": "El moderador ha blocat la compartició de pantalla",
|
||||
@@ -641,6 +680,8 @@
|
||||
"oldElectronClientDescription1": "Sembla que useu una versió antiga del client Jitsi Meet, que té vulnerabilitats de seguretat conegudes. Assegureu-vos d'actualitzar-lo",
|
||||
"oldElectronClientDescription2": "última construcció",
|
||||
"oldElectronClientDescription3": "ara!",
|
||||
"participantWantsToJoin": "Vol unir-se a la reunió",
|
||||
"participantsWantToJoin": "Volen unir-se a la reunió",
|
||||
"passwordRemovedRemotely": "Un altre participant ha eliminat $t(lockRoomPasswordUppercase)",
|
||||
"passwordSetRemotely": "Un altre participant ha establert la $t(lockRoomPassword)",
|
||||
"raiseHandAction": "Aixeca la mà",
|
||||
@@ -648,7 +689,7 @@
|
||||
"raisedHands": "{{participantName}} i {{raisedHands}} persones més",
|
||||
"reactionSounds": "Desactiva el so",
|
||||
"reactionSoundsForAll": "Desactiva el so per a tothom",
|
||||
"screenShareNoAudio": "La casella Comparteix l'àudio no s'ha marcat a la pantalla de selecció de la finestra.",
|
||||
"screenShareNoAudio": "No s'ha marcat la compartició d'àudio en la pantalla de selecció de la finestra.",
|
||||
"screenShareNoAudioTitle": "No s'ha pogut compartir l'àudio del sistema!",
|
||||
"selfViewTitle": "Sempre podeu activar la vista pròpia des de la configuració",
|
||||
"somebody": "Algú",
|
||||
@@ -660,7 +701,9 @@
|
||||
"videoMutedRemotelyDescription": "Sempre la podeu activar de nou.",
|
||||
"videoMutedRemotelyTitle": "{{participantDisplayName}} us ha apagat el vídeo",
|
||||
"videoUnmuteBlockedDescription": "L'activació de la càmera i la compartició d'escriptori s'han blocat temporalment per limitacions del sistema.",
|
||||
"videoUnmuteBlockedTitle": "L'activació de la càmera i la compartició d'escriptori estan blocades!"
|
||||
"videoUnmuteBlockedTitle": "L'activació de la càmera i la compartició d'escriptori estan blocades!",
|
||||
"viewLobby": "Mostra la sala d'espera",
|
||||
"waitingParticipants": "{{waitingParticipants}} persones"
|
||||
},
|
||||
"participantsPane": {
|
||||
"actions": {
|
||||
@@ -692,6 +735,7 @@
|
||||
},
|
||||
"passwordDigitsOnly": "Fins a {{number}} dígits",
|
||||
"passwordSetRemotely": "Establerta per un altre participant",
|
||||
"pinnedParticipant": "El participant està fixat",
|
||||
"polls": {
|
||||
"answer": {
|
||||
"skip": "Omet",
|
||||
@@ -748,7 +792,7 @@
|
||||
"veryPoorConnection": "És esperable que la qualitat de la trucada sigui realment terrible.",
|
||||
"videoFreezing": "És esperable que el vídeo es congeli, passi a negre i aparegui pixelat.",
|
||||
"videoHighQuality": "És esperable que el vídeo tingui una bona qualitat.",
|
||||
"videoLowQuality": "És esperable que el vídeo sigui de poca qualitat en termes de marcs per segon i resolució.",
|
||||
"videoLowQuality": "És esperable que el vídeo sigui de poca qualitat en termes de fotogrames per segon i resolució.",
|
||||
"videoTearing": "És esperable que el vídeo aparegui pixelat o amb defectes visuals."
|
||||
},
|
||||
"copyAndShare": "Copia i comparteix l'enllaç de la reunió",
|
||||
@@ -807,6 +851,18 @@
|
||||
},
|
||||
"raisedHand": "Vull parlar",
|
||||
"raisedHandsLabel": "Nombre de mans aixecades",
|
||||
"record": {
|
||||
"already": {
|
||||
"linked": "La reunió ja està enllaçada amb aquest objecte de Salesforce."
|
||||
},
|
||||
"type": {
|
||||
"account": "Compte",
|
||||
"contact": "Contacte",
|
||||
"lead": "Principal",
|
||||
"opportunity": "Oportunitat",
|
||||
"owner": "Propietari"
|
||||
}
|
||||
},
|
||||
"recording": {
|
||||
"authDropboxText": "Puja a Dropbox",
|
||||
"availableSpace": "Espai disponible: {{spaceLeft}} MB (aproximadament {{duration}} minuts d'enregistrament)",
|
||||
@@ -820,7 +876,12 @@
|
||||
"expandedOn": "S'està enregistrant la reunió.",
|
||||
"expandedPending": "S'ha iniciat l'enregistrament...",
|
||||
"failedToStart": "No s'ha pogut iniciar l'enregistrament",
|
||||
"fileSharingdescription": "Comparteix l'enregistrament amb els participants de la reunió",
|
||||
"fileSharingdescription": "Compartiu l'enllaç de l'enregistrament de la reunió amb els participants",
|
||||
"highlight": "Destaca",
|
||||
"highlightMoment": "Destaca el moment",
|
||||
"highlightMomentDisabled": "Podeu destacar moment en iniciar-se l'enregistrament",
|
||||
"highlightMomentSuccess": "Moment destacat",
|
||||
"highlightMomentSucessDescription": "S'ha afegit el moment destacat al resum de la reunió.",
|
||||
"inProgress": "L'enregistrament o la transmissió en directe és en progrés",
|
||||
"limitNotificationDescriptionNative": "A causa de la gran demanda, el vostre enregistrament es limitarà a {{limit}} min. Per a enregistraments il·limitats, proveu <3>{{app}}</3>.",
|
||||
"limitNotificationDescriptionWeb": "A causa de la gran demanda, l'enregistrament es limitarà a {{limit}} min. Per a enregistraments il·limitats, proveu <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
@@ -835,6 +896,7 @@
|
||||
"rec": "ENREG",
|
||||
"serviceDescription": "El servei d'enregistrament desarà el vostre enregistrament",
|
||||
"serviceDescriptionCloud": "Enregistrament al núvol",
|
||||
"serviceDescriptionCloudInfo": "Les reunions enregistrades s'esborren automàticament 24 hores després de l'enregistrament.",
|
||||
"serviceName": "Servei d'enregistrament",
|
||||
"sessionAlreadyActive": "Aquesta sessió ja s'està enregistrant o emetent en directe.",
|
||||
"signIn": "Inicia la sessió",
|
||||
@@ -843,6 +905,7 @@
|
||||
"unavailableTitle": "L'enregistrament no és disponible",
|
||||
"uploadToCloud": "Puja al núvol"
|
||||
},
|
||||
"screenshareDisplayName": "Pantalla de: {{name}}",
|
||||
"sectionList": {
|
||||
"pullToRefresh": "Estireu per a actualitzar"
|
||||
},
|
||||
@@ -862,13 +925,14 @@
|
||||
},
|
||||
"desktopShareFramerate": "Velocitat de fotogrames en la compartició d'escriptori",
|
||||
"desktopShareHighFpsWarning": "Una velocitat de fotogrames més alta per a compartir escriptori pot afectar l'amplada de banda. Heu de reiniciar la compartició de pantalla perquè la nova configuració tingui efecte.",
|
||||
"desktopShareWarning": "Heu de reiniciar la compartició de pantalla perquè la nova configuració tingui efecte.",
|
||||
"desktopShareWarning": "Cal que reinicieu la compartició de pantalla perquè la nova configuració tingui efecte.",
|
||||
"devices": "Aparells",
|
||||
"followMe": "Tothom que em segueix",
|
||||
"framesPerSecond": "marcs per segon",
|
||||
"framesPerSecond": "fotogrames per segon",
|
||||
"incomingMessage": "Missatge entrant",
|
||||
"language": "Llengua",
|
||||
"loggedIn": "Sessió iniciada com a {{name}}",
|
||||
"maxStageParticipants": "El nombre màxim de participants que es poden fixar en la escena principal",
|
||||
"microphones": "Micròfons",
|
||||
"moderator": "Moderador",
|
||||
"more": "Més",
|
||||
@@ -921,6 +985,7 @@
|
||||
"speakerStats": {
|
||||
"angry": "Enuig",
|
||||
"disgusted": "Disgust",
|
||||
"displayEmotions": "Mostra les emocions",
|
||||
"fearful": "Temor",
|
||||
"happy": "Felicitat",
|
||||
"hours": "{{count}}h",
|
||||
@@ -955,16 +1020,19 @@
|
||||
"boo": "Esbroncada",
|
||||
"breakoutRoom": "Entra o surt de la sala de descans",
|
||||
"callQuality": "Gestiona la qualitat de la trucada",
|
||||
"carmode": "Mode cotxe",
|
||||
"cc": "Activa o desactiva els subtítols",
|
||||
"chat": "Obre o tanca el xat",
|
||||
"clap": "Picament de mans",
|
||||
"collapse": "Col·lapsa",
|
||||
"dock": "Acobla a la finestra principal",
|
||||
"document": "Activa o desactiva el document compartit",
|
||||
"download": "Baixeu les nostres aplicacions",
|
||||
"embedMeeting": "Insereix la reunió",
|
||||
"expand": "Expandeix",
|
||||
"feedback": "Deixa comentaris",
|
||||
"fullScreen": "Activa o desactiva la pantalla completa",
|
||||
"giphy": "Mostra o amaga el menú GIPHY",
|
||||
"grantModerator": "Concedir drets de moderador",
|
||||
"hangup": "Surt de la reunió",
|
||||
"help": "Ajuda",
|
||||
@@ -972,6 +1040,7 @@
|
||||
"kick": "Expulsa el participant",
|
||||
"laugh": "Riure",
|
||||
"like": "Polzes amunt",
|
||||
"linkToSalesforce": "Enllaç a Salesforce",
|
||||
"lobbyButton": "Activa o desactiva la sala d'espera",
|
||||
"localRecording": "Activa o desactiva els controls d'enregistrament local",
|
||||
"lockRoom": "Activa o desactiva la contrasenya de la reunió",
|
||||
@@ -994,10 +1063,11 @@
|
||||
"remoteVideoMute": "Desactiva la càmera del participant",
|
||||
"security": "Opcions de seguretat",
|
||||
"selectBackground": "Trieu un fons",
|
||||
"selfView": "Mostra o amaga la visualització d'un mateix",
|
||||
"shareRoom": "Convida-hi algú",
|
||||
"shareYourScreen": "Inicia o atura la compartició de pantalla",
|
||||
"shareaudio": "Comparteix l'àudio",
|
||||
"sharedvideo": "Activa o desactiva la compartició de vídeo",
|
||||
"sharedvideo": "Mostra o amaga la compartició de vídeo",
|
||||
"shortcuts": "Activa o desactiva les dreceres",
|
||||
"show": "Mostra-ho en l'escena",
|
||||
"silence": "Silenci",
|
||||
@@ -1006,6 +1076,7 @@
|
||||
"tileView": "Activa o desactiva el mode mosaic",
|
||||
"toggleCamera": "Activa o desactiva la càmera",
|
||||
"toggleFilmstrip": "Mostra o amaga la cinta",
|
||||
"undock": "Desacobla en una finestra separada",
|
||||
"videoblur": "Activa o desactiva el desenfocament del vídeo",
|
||||
"videomute": "Activa o desactiva la càmera"
|
||||
},
|
||||
@@ -1022,6 +1093,7 @@
|
||||
"closeChat": "Tanca el xat",
|
||||
"closeReactionsMenu": "Tanca el menú de reaccions",
|
||||
"disableReactionSounds": "Podeu desactivar els sons de reacció per a aquesta reunió",
|
||||
"dock": "Acobla en la finestra principal",
|
||||
"documentClose": "Tanca el document compartit",
|
||||
"documentOpen": "Obre el document compartit",
|
||||
"download": "Baixeu les nostres aplicacions",
|
||||
@@ -1032,6 +1104,7 @@
|
||||
"exitFullScreen": "Surt de la pantalla completa",
|
||||
"exitTileView": "Surt del mode mosaic",
|
||||
"feedback": "Deixa comentaris",
|
||||
"giphy": "Mostra o amaga el menú GIPHY",
|
||||
"hangup": "Surt la reunió",
|
||||
"help": "Ajuda",
|
||||
"invite": "Convida-hi persones",
|
||||
@@ -1039,6 +1112,7 @@
|
||||
"laugh": "Riure",
|
||||
"leaveBreakoutRoom": "Surt de la sala de descans",
|
||||
"like": "Polzes amunt",
|
||||
"linkToSalesforce": "Enllaç a Salesforce",
|
||||
"lobbyButtonDisable": "Desactiva el mode de sala d'espera",
|
||||
"lobbyButtonEnable": "Activa el mode de sala d'espera",
|
||||
"login": "Inicia sessió",
|
||||
@@ -1088,6 +1162,7 @@
|
||||
"talkWhileMutedPopup": "Intenteu parlar? Esteu silenciat.",
|
||||
"tileViewToggle": "Activa o desactiva el mode mosaic",
|
||||
"toggleCamera": "Activa o desactiva la càmera",
|
||||
"undock": "Desacobla en una finestra principal",
|
||||
"videoSettings": "Paràmetres de vídeo",
|
||||
"videomute": "Inicia o atura la càmera"
|
||||
},
|
||||
@@ -1158,8 +1233,12 @@
|
||||
"moderator": "Moderador",
|
||||
"mute": "El participant està silenciat",
|
||||
"muted": "Silenciat",
|
||||
"pinToStage": "Fixa a l'escena",
|
||||
"remoteControl": "Inicia o atura el control remot",
|
||||
"screenSharing": "El participant està compartint la pantalla",
|
||||
"show": "Mostra-ho en l'escena",
|
||||
"showSelfView": "Mostra la visualització d'un mateix",
|
||||
"unpinFromStage": "Deixa de fixar",
|
||||
"videoMuted": "La càmera està desactivada",
|
||||
"videomute": "El participant ha aturat la càmera"
|
||||
},
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
"countryNotSupported": "Non supportiamo ancora questa destinazione.",
|
||||
"countryReminder": "Stai chiamando fuori dagli Stati Uniti? Assicurati d'inserire il prefisso internazionale!",
|
||||
"defaultEmail": "Tua email di default",
|
||||
"disabled": "Non puoi invitare persone.",
|
||||
"failedToAdd": "L'aggiunta di nuove persone è fallita",
|
||||
"disabled": "Non puoi invitare partecipanti.",
|
||||
"failedToAdd": "L'aggiunta di nuovi partecipanti è fallita",
|
||||
"footerText": "La chiamata all'esterno è disabilitata.",
|
||||
"googleEmail": "Email Google",
|
||||
"inviteMoreHeader": "Sei l'unico presente nella riunione",
|
||||
"inviteMoreMailSubject": "Unisciti alla riunione {{appName}}",
|
||||
"inviteMorePrompt": "Invita altre persone",
|
||||
"inviteMorePrompt": "Invita altri partecipanti",
|
||||
"linkCopied": "Collegamento copiato negli appunti",
|
||||
"noResults": "Nessun risultato corrispondente",
|
||||
"outlookEmail": "Email Outlook",
|
||||
@@ -26,7 +26,7 @@
|
||||
"shareStream": "Condividi il collegamento alla diretta",
|
||||
"sipAddresses": "indirizzi SIP",
|
||||
"telephone": "Telefono: {{number}}",
|
||||
"title": "Invita persone a questa riunione",
|
||||
"title": "Invita partecipanti a questa riunione",
|
||||
"yahooEmail": "Email Yahoo"
|
||||
},
|
||||
"audioDevices": {
|
||||
@@ -77,6 +77,17 @@
|
||||
"refresh": "Aggiorna calendario",
|
||||
"today": "Oggi"
|
||||
},
|
||||
"carmode": {
|
||||
"actions": {
|
||||
"leaveMeeting": " Lascia riunione",
|
||||
"selectSoundDevice": "Scegli audio"
|
||||
},
|
||||
"labels": {
|
||||
"buttonLabel": "Modalità in auto",
|
||||
"title": "Modalità guida sicura",
|
||||
"videoStopped": "Il tuo video è fermo"
|
||||
}
|
||||
},
|
||||
"chat": {
|
||||
"enter": "Entra nella conversazione",
|
||||
"error": "Errore: il tuo messaggio non è stato inviato. Motivo: {{error}}",
|
||||
@@ -101,7 +112,7 @@
|
||||
},
|
||||
"title": "Conversazione",
|
||||
"titleWithPolls": "Conversazione",
|
||||
"you": "tu"
|
||||
"you": "te"
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
"buttonText": "Installa l'estensione Chrome",
|
||||
@@ -304,10 +315,10 @@
|
||||
"muteEveryonesVideoDialogOk": "Spegni",
|
||||
"muteEveryonesVideoTitle": "Vuoi spegnere le videocamere di tutti?",
|
||||
"muteParticipantBody": "Non sarai in grado di riattivare il loro microfono, ma loro potranno riattivarlo in qualsiasi momento.",
|
||||
"muteParticipantButton": "Spegni microfono",
|
||||
"muteParticipantButton": "Spegni audio",
|
||||
"muteParticipantsVideoBody": "Una volta spenta la videocamera non potrai riaccenderla, ma lui potrà riattivarla in qualsiasi momento.",
|
||||
"muteParticipantsVideoBodyModerationOn": "Non potrai riaccendere le videocamere, né potranno loro.",
|
||||
"muteParticipantsVideoButton": "Spegni videocamera",
|
||||
"muteParticipantsVideoButton": "Spegni video",
|
||||
"muteParticipantsVideoDialog": "Sei sicuro di voler spegnere la videocamera di questo partecipante? Lui potrà riattivarla in ogni momento.",
|
||||
"muteParticipantsVideoDialogModerationOn": "Are you sure you want to turn off this participant's camera? You won't be able to turn the camera back on and neither will they.",
|
||||
"muteParticipantsVideoTitle": "Vuoi spegnere la videocamera di questo partecipante?",
|
||||
@@ -463,10 +474,10 @@
|
||||
"moreNumbers": "Più numeri",
|
||||
"noNumbers": "Nessun numero da chiamare.",
|
||||
"noPassword": "Nessuna",
|
||||
"noRoom": "Non è stata specificata nessuna stanza da chiamare.",
|
||||
"noRoom": "Non è stata specificata nessuna riunione da chiamare.",
|
||||
"numbers": "Numeri da chiamare",
|
||||
"password": "$t(lockRoomPasswordUppercase):",
|
||||
"sip": "SIP address",
|
||||
"sip": "Indirizzo SIP",
|
||||
"title": "Condividi",
|
||||
"tooltip": "Invia il collegamento e i numeri telefonici di questa riunione"
|
||||
},
|
||||
@@ -618,21 +629,21 @@
|
||||
"me": "io",
|
||||
"notify": {
|
||||
"OldElectronAPPTitle": "Falla di sicurezza!",
|
||||
"allowAction": "Permetti",
|
||||
"allowAction": "Autorizza",
|
||||
"allowedUnmute": "Puoi accendere il microfono, avviare la videocamera, o condividere il tuo schermo.",
|
||||
"audioUnmuteBlockedDescription": "Lo sblocco dei microfoni è stato temporaneament bloccato per limiti del sistema.",
|
||||
"audioUnmuteBlockedDescription": "Lo sblocco dei microfoni è stato temporaneamente bloccato per limiti del sistema.",
|
||||
"audioUnmuteBlockedTitle": "Riattivazione dei microfoni bloccata!",
|
||||
"chatMessages": "Messaggi delle conversazioni",
|
||||
"connectedOneMember": "{{name}} si è connesso",
|
||||
"connectedThreePlusMembers": "{{name}} e altri {{count}} si sono connessi",
|
||||
"connectedTwoMembers": "{{first}} e {{second}} si sono connessi",
|
||||
"connectedOneMember": "{{name}} è entrato in riunione",
|
||||
"connectedThreePlusMembers": "{{name}} e altri {{count}} sono entrati in riunione",
|
||||
"connectedTwoMembers": "{{first}} e {{second}} sono entrati in riunione",
|
||||
"disconnected": "disconnesso",
|
||||
"displayNotifications": "Mostra le notifiche per",
|
||||
"focus": "Focus su riunione",
|
||||
"focusFail": "{{component}} non disponibile - riprova in {{ms}} sec",
|
||||
"focusFail": "{{component}} non disponibile - riprovo tra {{ms}} sec",
|
||||
"gifsMenu": "GIPHY",
|
||||
"groupTitle": "Notifiche",
|
||||
"hostAskedUnmute": "Il moderatore vorrebbe che tu parlassi",
|
||||
"hostAskedUnmute": "Il moderatore ti dice di accendere il microfono",
|
||||
"invitedOneMember": "{{displayName}} è stato invitato",
|
||||
"invitedThreePlusMembers": "Hai invitato {{name}} e altri {{count}}",
|
||||
"invitedTwoMembers": "Hai invitato {{first}} e {{second}}",
|
||||
@@ -646,6 +657,8 @@
|
||||
"linkToSalesforceKey": "Link this meeting",
|
||||
"linkToSalesforceProgress": "Linking meeting to Salesforce...",
|
||||
"linkToSalesforceSuccess": "The meeting was linked to Salesforce",
|
||||
"localRecordingStarted": "{{name}} ha cominciato a registrare.",
|
||||
"localRecordingStopped": "{{name}} ha smesso di registrare.",
|
||||
"me": "Io",
|
||||
"moderationInEffectCSDescription": "Alza la mano, se vuoi condividere lo schermo, per favore.",
|
||||
"moderationInEffectCSTitle": "La condivisione schermo è stata bloccata dal moderatore",
|
||||
@@ -659,10 +672,10 @@
|
||||
"moderationStoppedTitle": "Moderazione interrotta",
|
||||
"moderationToggleDescription": "da {{participantDisplayName}}",
|
||||
"moderator": "Impostati i permessi di moderatore!",
|
||||
"muted": "Hai iniziato la conversazione con l'audio disattivato.",
|
||||
"muted": "Hai iniziato la conversazione con audio disattivato.",
|
||||
"mutedRemotelyDescription": "Puoi sempre attivare il microfono, quando vuoi parlare. Spegni il microfono quando hai finito, per non introdurre rumori di fondo nella riunione.",
|
||||
"mutedRemotelyTitle": "Ti è stato disattivato l'audio da {{participantDisplayName}}!",
|
||||
"mutedTitle": "Hai l'audio disattivato!",
|
||||
"mutedTitle": "Hai audio disattivato!",
|
||||
"newDeviceAction": "OK, usala",
|
||||
"newDeviceAudioTitle": "Trovata nuova origine audio",
|
||||
"newDeviceCameraTitle": "Trovata nuova videocamera",
|
||||
@@ -698,10 +711,10 @@
|
||||
"actions": {
|
||||
"allow": "Permetti ai partecipanti di:",
|
||||
"allowVideo": "Autorizza video",
|
||||
"askUnmute": "Chiedi di riattivare audio",
|
||||
"askUnmute": "Chiedi di accendere microfono",
|
||||
"audioModeration": "Riattivare audio",
|
||||
"blockEveryoneMicCamera": "Blocca audio e video a tutti",
|
||||
"invite": "Invita persone",
|
||||
"invite": "Invita partecipanti",
|
||||
"moreModerationActions": "Altre opzioni di moderazione",
|
||||
"moreModerationControls": "Altri controlli di moderazione",
|
||||
"moreParticipantOptions": "Altre opzioni partecipanti",
|
||||
@@ -714,7 +727,7 @@
|
||||
"videoModeration": "Riavviare videocamera"
|
||||
},
|
||||
"close": "Chiudi",
|
||||
"header": "Partecipanti",
|
||||
"header": "Partecipanti e sala d'attesa",
|
||||
"headings": {
|
||||
"lobby": "Sala d'attesa ({{count}})",
|
||||
"participantsList": "Partecipanti alla riunione ({{count}})",
|
||||
@@ -876,6 +889,7 @@
|
||||
"limitNotificationDescriptionWeb": "Data l'alta domanda la tua registrazione sarà limitata a {{limit}} minuti. Per registrazioni illimitate, prova <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"linkGenerated": "Abbiamo generato un collegamento alla tua registrazione.",
|
||||
"live": "DIRETTA",
|
||||
"localRecordingWarning": "Assicurati di aver selezionato la scheda corrente, per regitrare gli audio e video corretti. La registrazione è limitata ad 1GB, cioè circa 100 minuti.",
|
||||
"loggedIn": "Accesso effettuato come {{userName}}",
|
||||
"off": "Registrazione interrotta",
|
||||
"offBy": "{{name}} ha interrotto la registrazione",
|
||||
@@ -883,6 +897,7 @@
|
||||
"onBy": "Registrazione iniziata da {{name}}",
|
||||
"pending": "In preparazione alla registrazione della riunione",
|
||||
"rec": "REC",
|
||||
"saveLocalRecording": "Salva localmente il file della registrazione",
|
||||
"serviceDescription": "La tua registrazione verrà salvata dal servizio di registrazione che hai scelto",
|
||||
"serviceDescriptionCloud": "Registrazione in rete",
|
||||
"serviceDescriptionCloudInfo": "Le riunioni registrate vengono automaticamente cancellate 24 ore dopo la registrazione.",
|
||||
@@ -890,15 +905,17 @@
|
||||
"sessionAlreadyActive": "Questa sessione è già in corso di registrazione o trasmissione in diretta.",
|
||||
"signIn": "Entra",
|
||||
"signOut": "Esci",
|
||||
"surfaceError": "Selezionare la scheda corrente, per favore.",
|
||||
"unavailable": "Ops! Il {{serviceName}} non è al momento disponibile. Stiamo lavorando per risolvere il problema. Riprova più tardi.",
|
||||
"unavailableTitle": "Registrazione non disponibile",
|
||||
"uploadToCloud": "Carica in cloud"
|
||||
},
|
||||
"screenshareDisplayName": "Schermo di {{name}}",
|
||||
"sectionList": {
|
||||
"pullToRefresh": "Trascina per aggiornare"
|
||||
},
|
||||
"security": {
|
||||
"about": "Puoi aggiungere una $t(lockRoomPassword) alla riunione. I partecipanti dovranno fornire la $t(lockRoomPassword) per essere autorizzati a partecipare alla riunione.",
|
||||
"about": "Puoi aggiungere una $t(lockRoomPassword) alla riunione. I partecipanti dovranno fornire la $t(lockRoomPassword) per essere autorizzati a partecipare alla riunione.",
|
||||
"aboutReadOnly": "I moderatori della riunione possono aggiungere $t(lockRoomPassword). I partecipanti dovranno fornire la $t(lockRoomPassword) per essere autorizzati a partecipare alla riunione.",
|
||||
"insecureRoomNameWarning": "Il nome della riunione non è sicuro. Dei partecipanti indesiderati potrebbero unirsi alla riunione. Puoi proteggere l'accesso alla riunione col bottone sicurezza.",
|
||||
"securityOptions": "Impostazioni di sicurezza"
|
||||
@@ -930,7 +947,7 @@
|
||||
"participantLeft": "Partecipante Uscito",
|
||||
"playSounds": "Suoni attivati",
|
||||
"reactions": "Reazioni riunione",
|
||||
"sameAsSystem": "Come nel sistema ({{label}})",
|
||||
"sameAsSystem": "Stesso del computer ({{label}})",
|
||||
"selectAudioOutput": "Uscita audio",
|
||||
"selectCamera": "Videocamera",
|
||||
"selectMic": "Microfono",
|
||||
@@ -961,8 +978,8 @@
|
||||
"profileSection": "Profilo",
|
||||
"serverURL": "URL del server",
|
||||
"showAdvanced": "Impostazioni avanzate",
|
||||
"startWithAudioMuted": "Inizia con l'audio disattivato",
|
||||
"startWithVideoMuted": "Avvia con il video disattivato",
|
||||
"startWithAudioMuted": "Inizia con audio disattivato",
|
||||
"startWithVideoMuted": "Inizia con video disattivato",
|
||||
"version": "Versione"
|
||||
},
|
||||
"share": {
|
||||
@@ -1003,16 +1020,18 @@
|
||||
"toolbar": {
|
||||
"Settings": "Impostazioni",
|
||||
"accessibilityLabel": {
|
||||
"Settings": "Attiva/disattiva impostazioni",
|
||||
"Settings": "Attiva/Disattiva impostazioni",
|
||||
"audioOnly": "Spegni/Accendi audio",
|
||||
"audioRoute": "Scegli l'uscita audio",
|
||||
"boo": "Boo",
|
||||
"breakoutRoom": "Entra/Lascia sottogruppo",
|
||||
"callQuality": "Imposta qualità della chiamata",
|
||||
"carmode": "Modalità in auto",
|
||||
"cc": "Avvia/Ferma sottotitoli",
|
||||
"chat": "Entra/Esci da conversazione",
|
||||
"clap": "Applaudi",
|
||||
"collapse": "Riduci",
|
||||
"dock": "Aggancia alla finestra principale",
|
||||
"document": "Apri/Chiudi documenti condivisi",
|
||||
"download": "Scarica le nostre app",
|
||||
"embedMeeting": "Incorpora riunione altrove",
|
||||
@@ -1023,50 +1042,51 @@
|
||||
"grantModerator": "Autorizza moderatore",
|
||||
"hangup": "Lascia la riunione",
|
||||
"help": "Aiuto",
|
||||
"invite": "Invita persone",
|
||||
"invite": "Invita partecipanti",
|
||||
"kick": "Espelli partecipante",
|
||||
"laugh": "Ridi",
|
||||
"like": "Mi piace",
|
||||
"linkToSalesforce": "Collega a Salesforce",
|
||||
"lobbyButton": "Attiva/disattiva sala d'attesa",
|
||||
"localRecording": "Abilita/disattiva controlli di registrazione locale",
|
||||
"lobbyButton": "Attiva/Disattiva sala d'attesa",
|
||||
"localRecording": "Abilita/Disattiva controlli di registrazione locale",
|
||||
"lockRoom": "Attiva o disattiva password",
|
||||
"moreActions": "Attiva o disattiva menu avanzato",
|
||||
"moreActionsMenu": "Menu avanzato",
|
||||
"moreOptions": "Più opzioni",
|
||||
"mute": "Attiva/disattiva audio",
|
||||
"moreOptions": "Altre opzioni",
|
||||
"mute": "Attiva/Disattiva audio",
|
||||
"muteEveryone": "Spegni i microfoni a tutti",
|
||||
"muteEveryoneElse": "Spegni i microfoni di tutti gli altri",
|
||||
"muteEveryoneElsesVideo": "Spegni le videocamere di tutti gli altri",
|
||||
"muteEveryonesVideo": "Spegni le videocamere a tutti",
|
||||
"participants": "Partecipanti",
|
||||
"pip": "Attiva/disattiva immagine nell’immagine",
|
||||
"pip": "Attiva/Disattiva immagine nell’immagine",
|
||||
"privateMessage": "Invia messaggio privato",
|
||||
"profile": "Modifica profilo",
|
||||
"raiseHand": "Alza/Abbassa la mano",
|
||||
"reactionsMenu": "Apri/chiudi menù delle reaction",
|
||||
"recording": "Avvia/ferma registrazione",
|
||||
"reactionsMenu": "Apri/Chiudi menù delle reaction",
|
||||
"recording": "Avvia/Ferma registrazione",
|
||||
"remoteMute": "Spegni microfono al partecipante",
|
||||
"remoteVideoMute": "Spegni videocamera del partecipante",
|
||||
"security": "Impostazioni di sicurezza",
|
||||
"selectBackground": "Scegli sfondo",
|
||||
"selfView": "Mostra tua immagine",
|
||||
"shareRoom": "Invita qualcuno",
|
||||
"shareYourScreen": "Attiva/disattiva condivisione schermo",
|
||||
"shareYourScreen": "Attiva/Disattiva condivisione schermo",
|
||||
"shareaudio": "Condividi audio",
|
||||
"sharedvideo": "Attiva/disattiva condivisione",
|
||||
"shortcuts": "Attiva/disattiva scorciatoie",
|
||||
"sharedvideo": "Attiva/Disattiva condivisione",
|
||||
"shortcuts": "Attiva/Disattiva scorciatoie",
|
||||
"show": "Mostra in primo piano",
|
||||
"silence": "Silenzio",
|
||||
"speakerStats": "Attiva/disattiva statistiche relatore",
|
||||
"speakerStats": "Attiva/Disattiva statistiche relatore",
|
||||
"surprised": "Sorpreso",
|
||||
"tileView": "Vedi tutti i partecipanti insieme, o uno solo",
|
||||
"tileView": "Vedi tutti i partecipanti, o uno solo",
|
||||
"toggleCamera": "Cambia videocamera",
|
||||
"toggleFilmstrip": "Attiva/disattiva pellicola",
|
||||
"toggleFilmstrip": "Attiva/Disattiva pellicola",
|
||||
"undock": "Sgancia in una finestra separata",
|
||||
"videoblur": "Sfoca video",
|
||||
"videomute": "Attiva/disattiva videocamera"
|
||||
"videomute": "Attiva/Disattiva videocamera"
|
||||
},
|
||||
"addPeople": "Aggiungi persone alla chiamata",
|
||||
"addPeople": "Aggiungi partecipanti alla chiamata",
|
||||
"audioOnlyOff": "Disabilita modalità per banda limitata",
|
||||
"audioOnlyOn": "Abilita modalità per banda limitata",
|
||||
"audioRoute": "Scegli l'uscita audio",
|
||||
@@ -1074,11 +1094,12 @@
|
||||
"authenticate": "Autenticazione",
|
||||
"boo": "Boo",
|
||||
"callQuality": "Imposta qualità video",
|
||||
"chat": "Apri / Chiudi conversazione",
|
||||
"chat": "Apri/Chiudi conversazione",
|
||||
"clap": "Applaudi",
|
||||
"closeChat": "Chiudi conversazione",
|
||||
"closeReactionsMenu": "Chiudi il menù reazioni",
|
||||
"disableReactionSounds": "Puoi disattivare i suoni delle reaction, in questa riunione",
|
||||
"dock": "Aggancia nella finestra principale",
|
||||
"documentClose": "Chiudi documento condiviso",
|
||||
"documentOpen": "Apri documento condiviso",
|
||||
"download": "Scarica le nostre app",
|
||||
@@ -1092,7 +1113,7 @@
|
||||
"giphy": "Menù GIPHY",
|
||||
"hangup": "Butta giù",
|
||||
"help": "Aiuto",
|
||||
"invite": "Invita persone",
|
||||
"invite": "Invita partecipanti",
|
||||
"joinBreakoutRoom": "Entra in sottogruppo",
|
||||
"laugh": "Ridi",
|
||||
"leaveBreakoutRoom": "Lascia breakout room",
|
||||
@@ -1103,9 +1124,9 @@
|
||||
"login": "Accedi",
|
||||
"logout": "Scollegati",
|
||||
"lowerYourHand": "Abbassa la mano",
|
||||
"moreActions": "Più azioni",
|
||||
"moreOptions": "Più opzioni",
|
||||
"mute": "Attiva / Disattiva microfono",
|
||||
"moreActions": "Altre azioni",
|
||||
"moreOptions": "Altre opzioni",
|
||||
"mute": "Attiva/Disattiva microfono",
|
||||
"muteEveryone": "Spegni audio a tutti",
|
||||
"muteEveryonesVideo": "Spegni videocamera di tutti",
|
||||
"noAudioSignalDesc": "Se non l'hai disabilitato intenzionalmente nelle impostazioni, prova a cambiare dispositivo di input.",
|
||||
@@ -1121,7 +1142,7 @@
|
||||
"pip": "Abilita visualizzazione immagine nell'immagine",
|
||||
"privateMessage": "invia un messaggio privato",
|
||||
"profile": "Modifica profilo",
|
||||
"raiseHand": "Alza / Abbassa la mano",
|
||||
"raiseHand": "Alza/Abbassa la mano",
|
||||
"raiseYourHand": "Alza la mano",
|
||||
"reactionBoo": "Invia boo",
|
||||
"reactionClap": "Invia applauso",
|
||||
@@ -1147,11 +1168,12 @@
|
||||
"talkWhileMutedPopup": "Stai provando a parlare? Il microfono è disattivato.",
|
||||
"tileViewToggle": "Vedi tutti i partecipanti insieme, o uno solo",
|
||||
"toggleCamera": "Cambia videocamera",
|
||||
"undock": "Sgancia in una finestra separata",
|
||||
"videoSettings": "Impostazioni video",
|
||||
"videomute": "Attiva / Disattiva videocamera"
|
||||
"videomute": "Attiva/Disattiva videocamera"
|
||||
},
|
||||
"transcribing": {
|
||||
"ccButtonTooltip": "Inizia / Ferma i sottotitoli",
|
||||
"ccButtonTooltip": "Inizia/Ferma i sottotitoli",
|
||||
"error": "Trascrizione fallita. Prova di nuovo.",
|
||||
"expandedLabel": "La trascrizione della riunione è attiva",
|
||||
"failedToStart": "C'è stato un errore nell'avvio del servizio di trascrizione.",
|
||||
@@ -1176,12 +1198,12 @@
|
||||
},
|
||||
"videoSIPGW": {
|
||||
"busy": "Stiamo lavorando per liberare le risorse. Riprova tra qualche minuto.",
|
||||
"busyTitle": "Il servizio Stanza al momento è occupato",
|
||||
"busyTitle": "Il servizio Riunione al momento è occupato",
|
||||
"errorAlreadyInvited": "{{displayName}} già invitato",
|
||||
"errorInvite": "Riunione non ancora stabilita. Riprova più tardi.",
|
||||
"errorInviteFailed": "Stiamo lavorando per risolvere il problema. Riprova più tardi.",
|
||||
"errorInviteFailedTitle": "Invito a {{displayName}} fallito",
|
||||
"errorInviteTitle": "Errore nell'invito alla stanza",
|
||||
"errorInviteTitle": "Errore nell'invito alla riunione",
|
||||
"pending": "{{displayName}} è stato invitato"
|
||||
},
|
||||
"videoStatus": {
|
||||
@@ -1218,7 +1240,7 @@
|
||||
"mute": "Il partecipante ha il microfono spento",
|
||||
"muted": "Audio disattivato",
|
||||
"pinToStage": "Aggiungi agli oratori",
|
||||
"remoteControl": "Avvia/ferma il controllo remoto",
|
||||
"remoteControl": "Avvia/Ferma il controllo remoto",
|
||||
"screenSharing": "Il partecipante sta condividendo lo schermo",
|
||||
"show": "Mostra tra gli oratori",
|
||||
"showSelfView": "Mostra tua immagine",
|
||||
@@ -1237,7 +1259,7 @@
|
||||
"image1": "Spiaggia",
|
||||
"image2": "Parete neutra bianca",
|
||||
"image3": "Stanza bianca vuota",
|
||||
"image4": "Lampanda da pavimento nera",
|
||||
"image4": "Lampada da pavimento nera",
|
||||
"image5": "Montagna",
|
||||
"image6": "Foresta",
|
||||
"image7": "Alba",
|
||||
@@ -1248,13 +1270,13 @@
|
||||
"title": "Sfondi",
|
||||
"uploadedImage": "Carica immagine {{index}}",
|
||||
"webAssemblyWarning": "Il WebAssembly non è supportato",
|
||||
"webAssemblyWarningDescription": "Il WebAssembly è disabilitato o non è supportat da questo browser"
|
||||
"webAssemblyWarningDescription": "Il WebAssembly è disabilitato o non è supportato da questo browser"
|
||||
},
|
||||
"volumeSlider": "Sbarra volume",
|
||||
"welcomepage": {
|
||||
"accessibilityLabel": {
|
||||
"join": "Tocca per accedere",
|
||||
"roomname": "Inserisci nome stanza"
|
||||
"roomname": "Inserisci nome riunione"
|
||||
},
|
||||
"addMeetingName": "Aggiungi Nome riunione",
|
||||
"appDescription": "Avvia una videochiamata con tutto il team. Invita tutti quelli che conosci. {{app}} è una soluzione per effettuare videoconferenze totalmente crittografata, 100% open source, che puoi usare sempre, ogni giorno, gratuitamente – senza bisogno di un account.",
|
||||
@@ -1273,7 +1295,7 @@
|
||||
"headerTitle": "Jitsi Meet",
|
||||
"info": "Informazioni chiamata",
|
||||
"jitsiOnMobile": "Jitsi su mobile – scarica le nostre app e dai inizio ad una riunione dovunque tu sia",
|
||||
"join": "CREA / UNISCITI",
|
||||
"join": "CREA/UNISCITI",
|
||||
"logo": {
|
||||
"calendar": "Logo calendario",
|
||||
"desktopPreviewThumbnail": "Icona anteprima desktop",
|
||||
@@ -1289,11 +1311,11 @@
|
||||
"privacy": "Riservatezza",
|
||||
"recentList": "Recenti",
|
||||
"recentListDelete": "Cancella",
|
||||
"recentListEmpty": "La tua lista è vuota. Conversa con qualcuno del tuo team e lo vedrai apparire nella lista delle riunioni recenti.",
|
||||
"recentListEmpty": "La lista delle riunioni recenti è vuota. Partecipa almeno ad una riunione e potrai riavviarla in seguito.",
|
||||
"reducedUIText": "Benvenuto in {{app}}!",
|
||||
"roomNameAllowedChars": "Il nome della riunione non deve contenere questi caratteri: ?, &, :, ', \", %, #.",
|
||||
"roomname": "Inserisci il nome della stanza",
|
||||
"roomnameHint": "Inserisci il nome o l'URL della stanza alla quale vuoi accedere. Puoi anche inventarti un nome, assicurati solo che le persone che vuoi contattare lo conoscano, così che possano inserire lo stesso nome.",
|
||||
"roomname": "Inserisci il nome della riunione",
|
||||
"roomnameHint": "Inserisci il nome o l'URL della alla quale vuoi accedere. Puoi anche inventarti un nome, assicurati solo che le persone che vuoi contattare lo conoscano, così che possano inserire lo stesso nome.",
|
||||
"sendFeedback": "Invia feedback",
|
||||
"startMeeting": "Inizia riunione",
|
||||
"terms": "Termini di utilizzo",
|
||||
|
||||
@@ -77,6 +77,17 @@
|
||||
"refresh": "Atualizar calendário",
|
||||
"today": "Hoje"
|
||||
},
|
||||
"carmode": {
|
||||
"actions": {
|
||||
"leaveMeeting": " Deixar a reunião",
|
||||
"selectSoundDevice": "Seleccionar dispositivo de som"
|
||||
},
|
||||
"labels": {
|
||||
"buttonLabel": "Modo carro",
|
||||
"title": "Modo de condução segura",
|
||||
"videoStopped": "O seu vídeo está parado"
|
||||
}
|
||||
},
|
||||
"chat": {
|
||||
"enter": "Entrar na sala",
|
||||
"error": "Erro: a sua mensagem não foi enviada. Motivo: {{error}}",
|
||||
@@ -105,6 +116,7 @@
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
"buttonText": "Instalar extensão do Chrome",
|
||||
"buttonTextEdge": "Instalar extensão do Edge",
|
||||
"close": "Fechar",
|
||||
"dontShowAgain": "Não me mostre isto outra vez",
|
||||
"installExtensionText": "Instalar a extensão para a integração Google Calendar e Office 365"
|
||||
@@ -183,7 +195,7 @@
|
||||
"unsupportedBrowser": "Parece que está a usar um browser que não suportamos."
|
||||
},
|
||||
"defaultLink": "ex.: {{url}}",
|
||||
"defaultNickname": "ex.: João Pedro",
|
||||
"defaultNickname": "ex.: João Dias",
|
||||
"deviceError": {
|
||||
"cameraError": "Falha ao aceder à sua câmara",
|
||||
"cameraPermission": "Erro ao obter permissão para a câmara",
|
||||
@@ -196,6 +208,9 @@
|
||||
"selectADevice": "Selecione um dispositivo",
|
||||
"testAudio": "Tocar um som de teste"
|
||||
},
|
||||
"dialIn": {
|
||||
"screenTitle": "Resumo da marcação"
|
||||
},
|
||||
"dialOut": {
|
||||
"statusMessage": "está agora {{status}}"
|
||||
},
|
||||
@@ -277,7 +292,7 @@
|
||||
"lockRoom": "Adicionar reunião $t(lockRoomPassword)",
|
||||
"lockTitle": "Bloqueio falhado",
|
||||
"login": "Entrar",
|
||||
"logoutQuestion": "Tem a certeza de que quer terminar a sessão e interromper a conferência?",
|
||||
"logoutQuestion": "Tem a certeza de que quer terminar a sessão e sair da conferência?",
|
||||
"logoutTitle": "Sair",
|
||||
"maxUsersLimitReached": "O limite para o número máximo de participantes foi atingido. A conferência está cheia. Por favor contacte o proprietário da reunião ou tente novamente mais tarde!",
|
||||
"maxUsersLimitReachedTitle": "Limite máximo de participantes atingido",
|
||||
@@ -346,7 +361,7 @@
|
||||
"screenSharingFailed": "Oops! Algo correu mal, não fomos capazes de começar a partilhar o ecrã!",
|
||||
"screenSharingFailedTitle": "A partilha de ecrã falhou!",
|
||||
"screenSharingPermissionDeniedError": "Oops! Alguma coisa correu mal com as vossas permissões de partilha de ecrã. Por favor, volte a carregar e tente novamente.",
|
||||
"searchInSalesforce": "Pesquisar na Força de Vendas",
|
||||
"searchInSalesforce": "Pesquisar na Salesforce",
|
||||
"searchResults": "Resultados da pesquisa({{count}})",
|
||||
"searchResultsDetailsError": "Algo correu mal enquanto se recuperava os dados do proprietário.",
|
||||
"searchResultsError": "Alguma coisa correu mal durante a recuperação de dados.",
|
||||
@@ -640,12 +655,14 @@
|
||||
"leftOneMember": "{{name}} deixou a reunião",
|
||||
"leftThreePlusMembers": "{{name}} e muitos outros deixaram a reunião",
|
||||
"leftTwoMembers": "{{first}} e {{second}} deixaram a reunião",
|
||||
"linkToSalesforce": "Link para a Força de Vendas",
|
||||
"linkToSalesforceDescription": "Pode ligar o resumo da reunião a um objecto da Força de Vendas.",
|
||||
"linkToSalesforceError": "Falha na ligação da reunião à Força de Vendas",
|
||||
"linkToSalesforce": "Link para a Salesforce",
|
||||
"linkToSalesforceDescription": "Pode ligar o resumo da reunião a um objecto da Salesforce.",
|
||||
"linkToSalesforceError": "Falha na ligação da reunião à Salesforce",
|
||||
"linkToSalesforceKey": "Ligar esta reunião",
|
||||
"linkToSalesforceProgress": "A ligar a reunião à Força de Vendas...",
|
||||
"linkToSalesforceSuccess": "A reunião foi ligada à Força de Vendas",
|
||||
"linkToSalesforceProgress": "A ligar a reunião à Salesforce...",
|
||||
"linkToSalesforceSuccess": "A reunião foi ligada à Salesforce",
|
||||
"localRecordingStarted": "{{name}} iniciou uma gravação local.",
|
||||
"localRecordingStopped": "{{name}} parou uma gravação local.",
|
||||
"me": "Eu",
|
||||
"moderationInEffectCSDescription": "Por favor, levantem a mão se quiserem partilhar o vosso ecrã.",
|
||||
"moderationInEffectCSTitle": "A partilha de ecrã é bloqueada pelo moderador",
|
||||
@@ -801,6 +818,7 @@
|
||||
"initiated": "Chamada iniciada",
|
||||
"joinAudioByPhone": "Entrar com o áudio do telefone",
|
||||
"joinMeeting": "Entrar na reunião",
|
||||
"joinMeetingInLowBandwidthMode": "Entrar em modo de baixa largura de banda",
|
||||
"joinWithoutAudio": "Entrar sem áudio",
|
||||
"keyboardShortcuts": "Ativar os atalhos de teclado",
|
||||
"linkCopied": "Link copiado para a área de transferência",
|
||||
@@ -876,6 +894,7 @@
|
||||
"limitNotificationDescriptionWeb": "Devido à grande procura, a sua gravação será limitada a {{limit}} min. For unlimited recordings try <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"linkGenerated": "Gerámos um link para a sua gravação.",
|
||||
"live": "DIRETO",
|
||||
"localRecordingWarning": "Certifique-se de seleccionar o separador actual a fim de utilizar o vídeo e áudio correctos. A gravação está actualmente limitada a 1 GB, o que é cerca de 100 minutos.",
|
||||
"loggedIn": "Conectado como {{userName}}",
|
||||
"off": "Gravação parada",
|
||||
"offBy": "{{name}} parou a gravação",
|
||||
@@ -883,6 +902,7 @@
|
||||
"onBy": "{{name}} iniciou a gravação",
|
||||
"pending": "Preparando para gravar a reunião...",
|
||||
"rec": "REC",
|
||||
"saveLocalRecording": "Guardar ficheiro de gravação localmente",
|
||||
"serviceDescription": "Sua gravação será salva pelo serviço de gravação",
|
||||
"serviceDescriptionCloud": "Gravação na nuvem",
|
||||
"serviceDescriptionCloudInfo": "As reuniões gravadas são automaticamente apagadas 24h após a hora de gravação.",
|
||||
@@ -890,11 +910,12 @@
|
||||
"sessionAlreadyActive": "Esta sessão já está a ser gravada ou transmitida em direto.",
|
||||
"signIn": "Entrar",
|
||||
"signOut": "Sair",
|
||||
"surfaceError": "Por favor, seleccione o separador actual.",
|
||||
"unavailable": "Oops! O {{serviceName}} está indisponível. Estamos trabalhando para resolver o problema. Por favor, tente mais tarde.",
|
||||
"unavailableTitle": "Gravação indisponível",
|
||||
"uploadToCloud": "Enviar para a nuvem"
|
||||
},
|
||||
"screenshareDisplayName": "ecrã do {{name}}",
|
||||
"screenshareDisplayName": "Ecrã de {{name}}",
|
||||
"sectionList": {
|
||||
"pullToRefresh": "Puxe para atualizar"
|
||||
},
|
||||
@@ -932,6 +953,7 @@
|
||||
"playSounds": "Reproduzir som quando",
|
||||
"reactions": "Expressarem uma reação",
|
||||
"sameAsSystem": "O mesmo que o sistema ({{label}})",
|
||||
"screenTitle": "Definições",
|
||||
"selectAudioOutput": "Saída de áudio",
|
||||
"selectCamera": "Câmara",
|
||||
"selectMic": "Microfone",
|
||||
@@ -957,6 +979,7 @@
|
||||
"disableCrashReportingWarning": "Tem a certeza de que quer desativar o relatório de falhas? A configuração será aplicada depois de reiniciar a aplicação.",
|
||||
"disableP2P": "Desactivar o modo Peer-To-Peer",
|
||||
"displayName": "Nome de exibição",
|
||||
"displayNamePlaceholderText": "Ex: João Dias",
|
||||
"email": "Email",
|
||||
"header": "Configurações",
|
||||
"profileSection": "Perfil",
|
||||
@@ -1010,10 +1033,12 @@
|
||||
"boo": "Vaia",
|
||||
"breakoutRoom": "Entrar/Sair salas instantâneas",
|
||||
"callQuality": "Gerir a qualidade do vídeo",
|
||||
"carmode": "Modo carro",
|
||||
"cc": "Mudar legendas",
|
||||
"chat": "Abrir / Fechar chat",
|
||||
"clap": "Aplausos",
|
||||
"collapse": "Colapsar",
|
||||
"dock": "Encaixar na janela principal",
|
||||
"document": "Mudar para documento partilhado",
|
||||
"download": "Descarregar as nossas aplicações",
|
||||
"embedMeeting": "Reunião incorporada",
|
||||
@@ -1028,7 +1053,7 @@
|
||||
"kick": "Remover participante",
|
||||
"laugh": "Risos",
|
||||
"like": "Aprovado",
|
||||
"linkToSalesforce": "Link para a Força de Vendas",
|
||||
"linkToSalesforce": "Link para a Salesforce",
|
||||
"lobbyButton": "Ativar/desativar sala de espera",
|
||||
"localRecording": "Mudar os controlos locais de gravação",
|
||||
"lockRoom": "Mudar palavra-chave de reunião",
|
||||
@@ -1064,6 +1089,7 @@
|
||||
"tileView": "Mudar a vista em quadrícula",
|
||||
"toggleCamera": "Mudar a câmara",
|
||||
"toggleFilmstrip": "Mudar a película de filme",
|
||||
"undock": "Soltar numa janela separada",
|
||||
"videoblur": "Mudar o desfoque de vídeo",
|
||||
"videomute": "Iniciar / Parar câmara"
|
||||
},
|
||||
@@ -1080,6 +1106,7 @@
|
||||
"closeChat": "Fechar chat",
|
||||
"closeReactionsMenu": "Fechar menu de reações",
|
||||
"disableReactionSounds": "Pode desactivar os sons de reacção para esta reunião",
|
||||
"dock": "Encaixar na janela principal",
|
||||
"documentClose": "Fechar documento partilhado",
|
||||
"documentOpen": "Abrir documento partilhado",
|
||||
"download": "Descarregar as nossas aplicações",
|
||||
@@ -1098,7 +1125,7 @@
|
||||
"laugh": "Risos",
|
||||
"leaveBreakoutRoom": "Sair da sala",
|
||||
"like": "Aprovado",
|
||||
"linkToSalesforce": "Link para a Força de Vendas",
|
||||
"linkToSalesforce": "Link para a Salesforce",
|
||||
"lobbyButtonDisable": "Desativar sala de espera",
|
||||
"lobbyButtonEnable": "Ativar sala de espera",
|
||||
"login": "Iniciar sessão",
|
||||
@@ -1148,6 +1175,7 @@
|
||||
"talkWhileMutedPopup": "Está a tentar falar? Está com o microfone desativado.",
|
||||
"tileViewToggle": "Mudar para vista em quadrícula",
|
||||
"toggleCamera": "Mudar a câmara",
|
||||
"undock": "Soltar numa janela separada",
|
||||
"videoSettings": "Definições de vídeo",
|
||||
"videomute": "Iniciar / Parar câmara"
|
||||
},
|
||||
|
||||
@@ -77,6 +77,17 @@
|
||||
"refresh": "Refresh calendar",
|
||||
"today": "Today"
|
||||
},
|
||||
"carmode": {
|
||||
"actions": {
|
||||
"leaveMeeting": " Leave meeting",
|
||||
"selectSoundDevice": "Select sound device"
|
||||
},
|
||||
"labels": {
|
||||
"buttonLabel": "Car mode",
|
||||
"title": "Safe driving mode",
|
||||
"videoStopped": "Your video is stopped"
|
||||
}
|
||||
},
|
||||
"chat": {
|
||||
"enter": "Enter room",
|
||||
"error": "Error: your message was not sent. Reason: {{error}}",
|
||||
@@ -105,6 +116,7 @@
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
"buttonText": "Install Chrome Extension",
|
||||
"buttonTextEdge": "Install Edge Extension",
|
||||
"close": "Close",
|
||||
"dontShowAgain": "Don’t show me this again",
|
||||
"installExtensionText": "Install the extension for Google Calendar and Office 365 integration"
|
||||
@@ -196,6 +208,9 @@
|
||||
"selectADevice": "Select a device",
|
||||
"testAudio": "Play a test sound"
|
||||
},
|
||||
"dialIn": {
|
||||
"screenTitle": "Dial-in summary"
|
||||
},
|
||||
"dialOut": {
|
||||
"statusMessage": "is now {{status}}"
|
||||
},
|
||||
@@ -277,7 +292,7 @@
|
||||
"lockRoom": "Add meeting $t(lockRoomPassword)",
|
||||
"lockTitle": "Lock failed",
|
||||
"login": "Login",
|
||||
"logoutQuestion": "Are you sure you want to logout and stop the conference?",
|
||||
"logoutQuestion": "Are you sure you want to logout and leave the conference?",
|
||||
"logoutTitle": "Logout",
|
||||
"maxUsersLimitReached": "The limit for maximum number of participants has been reached. The conference is full. Please contact the meeting owner or try again later!",
|
||||
"maxUsersLimitReachedTitle": "Maximum participants limit reached",
|
||||
@@ -646,6 +661,8 @@
|
||||
"linkToSalesforceKey": "Link this meeting",
|
||||
"linkToSalesforceProgress": "Linking meeting to Salesforce...",
|
||||
"linkToSalesforceSuccess": "The meeting was linked to Salesforce",
|
||||
"localRecordingStarted": "{{name}} has started a local recording.",
|
||||
"localRecordingStopped": "{{name}} has stopped a local recording.",
|
||||
"me": "Me",
|
||||
"moderationInEffectCSDescription": "Please raise hand if you want to share your screen.",
|
||||
"moderationInEffectCSTitle": "Screen sharing is blocked by the moderator",
|
||||
@@ -801,6 +818,7 @@
|
||||
"initiated": "Call initiated",
|
||||
"joinAudioByPhone": "Join with phone audio",
|
||||
"joinMeeting": "Join meeting",
|
||||
"joinMeetingInLowBandwidthMode": "Join in low bandwidth mode",
|
||||
"joinWithoutAudio": "Join without audio",
|
||||
"keyboardShortcuts": "Enable Keyboard shortcuts",
|
||||
"linkCopied": "Link copied to clipboard",
|
||||
@@ -876,6 +894,8 @@
|
||||
"limitNotificationDescriptionWeb": "Due to high demand your recording will be limited to {{limit}} min. For unlimited recordings try <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"linkGenerated": "We have generated a link to your recording.",
|
||||
"live": "LIVE",
|
||||
"localRecordingNoNotificationWarning": "The recording will not be announced to other participants. You will need to let them know that the meeting is recorded.",
|
||||
"localRecordingWarning": "Make sure you select the current tab in order to use the right video and audio. The recording is currently limited to 1GB, which is around 100 minutes.",
|
||||
"loggedIn": "Logged in as {{userName}}",
|
||||
"off": "Recording stopped",
|
||||
"offBy": "{{name}} stopped the recording",
|
||||
@@ -883,6 +903,7 @@
|
||||
"onBy": "{{name}} started the recording",
|
||||
"pending": "Preparing to record the meeting...",
|
||||
"rec": "REC",
|
||||
"saveLocalRecording": "Save recording file locally",
|
||||
"serviceDescription": "Your recording will be saved by the recording service",
|
||||
"serviceDescriptionCloud": "Cloud recording",
|
||||
"serviceDescriptionCloudInfo": "Recorded meetings are automatically cleared 24h after their recording time.",
|
||||
@@ -890,6 +911,7 @@
|
||||
"sessionAlreadyActive": "This session is already being recorded or live streamed.",
|
||||
"signIn": "Sign in",
|
||||
"signOut": "Sign out",
|
||||
"surfaceError": "Please select the current tab.",
|
||||
"unavailable": "Oops! The {{serviceName}} is currently unavailable. We're working on resolving the issue. Please try again later.",
|
||||
"unavailableTitle": "Recording unavailable",
|
||||
"uploadToCloud": "Upload to the cloud"
|
||||
@@ -932,6 +954,7 @@
|
||||
"playSounds": "Play sound on",
|
||||
"reactions": "Meeting reactions",
|
||||
"sameAsSystem": "Same as system ({{label}})",
|
||||
"screenTitle": "Settings",
|
||||
"selectAudioOutput": "Audio output",
|
||||
"selectCamera": "Camera",
|
||||
"selectMic": "Microphone",
|
||||
@@ -957,6 +980,7 @@
|
||||
"disableCrashReportingWarning": "Are you sure you want to disable crash reporting? The setting will be applied after you restart the app.",
|
||||
"disableP2P": "Disable Peer-To-Peer mode",
|
||||
"displayName": "Display name",
|
||||
"displayNamePlaceholderText": "Eg: John Doe",
|
||||
"email": "Email",
|
||||
"header": "Settings",
|
||||
"profileSection": "Profile",
|
||||
@@ -1010,10 +1034,12 @@
|
||||
"boo": "Boo",
|
||||
"breakoutRoom": "Join/leave breakout room",
|
||||
"callQuality": "Manage video quality",
|
||||
"carmode": "Car Mode",
|
||||
"cc": "Toggle subtitles",
|
||||
"chat": "Open / Close chat",
|
||||
"clap": "Clap",
|
||||
"collapse": "Collapse",
|
||||
"dock": "Dock in main window",
|
||||
"document": "Toggle shared document",
|
||||
"download": "Download our apps",
|
||||
"embedMeeting": "Embed meeting",
|
||||
@@ -1064,6 +1090,7 @@
|
||||
"tileView": "Toggle tile view",
|
||||
"toggleCamera": "Toggle camera",
|
||||
"toggleFilmstrip": "Toggle filmstrip",
|
||||
"undock": "Undock into separate window",
|
||||
"videoblur": "Toggle video blur",
|
||||
"videomute": "Start / Stop camera"
|
||||
},
|
||||
@@ -1080,6 +1107,7 @@
|
||||
"closeChat": "Close chat",
|
||||
"closeReactionsMenu": "Close reactions menu",
|
||||
"disableReactionSounds": "You can disable reaction sounds for this meeting",
|
||||
"dock": "Dock in main window",
|
||||
"documentClose": "Close shared document",
|
||||
"documentOpen": "Open shared document",
|
||||
"download": "Download our apps",
|
||||
@@ -1148,6 +1176,7 @@
|
||||
"talkWhileMutedPopup": "Trying to speak? You are muted.",
|
||||
"tileViewToggle": "Toggle tile view",
|
||||
"toggleCamera": "Toggle camera",
|
||||
"undock": "Undock into separate window",
|
||||
"videoSettings": "Video settings",
|
||||
"videomute": "Start / Stop camera"
|
||||
},
|
||||
|
||||
@@ -40,7 +40,8 @@ import {
|
||||
isParticipantModerator,
|
||||
isLocalParticipantModerator,
|
||||
hasRaisedHand,
|
||||
grantModerator
|
||||
grantModerator,
|
||||
overwriteParticipantsNames
|
||||
} from '../../react/features/base/participants';
|
||||
import { updateSettings } from '../../react/features/base/settings';
|
||||
import { isToggleCameraEnabled, toggleCamera } from '../../react/features/base/tracks';
|
||||
@@ -428,6 +429,11 @@ function initCommands() {
|
||||
logger.error('Failed sending endpoint text message', err);
|
||||
}
|
||||
},
|
||||
'overwrite-names': participantList => {
|
||||
logger.debug('Overwrite names command received');
|
||||
|
||||
APP.store.dispatch(overwriteParticipantsNames(participantList));
|
||||
},
|
||||
'toggle-e2ee': enabled => {
|
||||
logger.debug('Toggle E2EE key command received');
|
||||
APP.store.dispatch(toggleE2EE(enabled));
|
||||
@@ -1455,6 +1461,22 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that the iframe
|
||||
* docked state has been changed. The responsibility for implementing
|
||||
* the dock / undock functionality lies with the external application.
|
||||
*
|
||||
* @param {boolean} docked - Whether or not the iframe has been set to
|
||||
* be docked or undocked.
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyIframeDockStateChanged(docked: boolean) {
|
||||
this._sendEvent({
|
||||
name: 'iframe-dock-state-changed',
|
||||
docked
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application of a participant, remote or local, being
|
||||
* removed from the conference by another participant.
|
||||
@@ -1660,6 +1682,32 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application that the breakout rooms changed.
|
||||
*
|
||||
* @param {Array} rooms - Array of breakout rooms.
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyBreakoutRoomsUpdated(rooms) {
|
||||
this._sendEvent({
|
||||
name: 'breakout-rooms-updated',
|
||||
rooms
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the external application that the state of the participants pane changed.
|
||||
*
|
||||
* @param {boolean} open - Wether the panel is open or not.
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyParticipantsPaneToggled(open) {
|
||||
this._sendEvent({
|
||||
name: 'participants-pane-toggled',
|
||||
open
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the allocated resources.
|
||||
*
|
||||
|
||||
11
modules/API/external/external_api.js
vendored
11
modules/API/external/external_api.js
vendored
@@ -46,6 +46,7 @@ const commands = {
|
||||
kickParticipant: 'kick-participant',
|
||||
muteEveryone: 'mute-everyone',
|
||||
overwriteConfig: 'overwrite-config',
|
||||
overwriteNames: 'overwrite-names',
|
||||
password: 'password',
|
||||
pinParticipant: 'pin-participant',
|
||||
rejectParticipant: 'reject-participant',
|
||||
@@ -94,6 +95,7 @@ const events = {
|
||||
'avatar-changed': 'avatarChanged',
|
||||
'audio-availability-changed': 'audioAvailabilityChanged',
|
||||
'audio-mute-status-changed': 'audioMuteStatusChanged',
|
||||
'breakout-rooms-updated': 'breakoutRoomsUpdated',
|
||||
'browser-support': 'browserSupport',
|
||||
'camera-error': 'cameraError',
|
||||
'chat-updated': 'chatUpdated',
|
||||
@@ -108,6 +110,7 @@ const events = {
|
||||
'feedback-submitted': 'feedbackSubmitted',
|
||||
'feedback-prompt-displayed': 'feedbackPromptDisplayed',
|
||||
'filmstrip-display-changed': 'filmstripDisplayChanged',
|
||||
'iframe-dock-state-changed': 'iframeDockStateChanged',
|
||||
'incoming-message': 'incomingMessage',
|
||||
'knocking-participant': 'knockingParticipant',
|
||||
'log': 'log',
|
||||
@@ -123,6 +126,7 @@ const events = {
|
||||
'participant-kicked-out': 'participantKickedOut',
|
||||
'participant-left': 'participantLeft',
|
||||
'participant-role-changed': 'participantRoleChanged',
|
||||
'participants-pane-toggled': 'participantsPaneToggled',
|
||||
'password-required': 'passwordRequired',
|
||||
'proxy-connection-event': 'proxyConnectionEvent',
|
||||
'raise-hand-updated': 'raiseHandUpdated',
|
||||
@@ -298,6 +302,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
* the participant opening the meeting.
|
||||
* @param {string} [options.e2eeKey] - The key used for End-to-End encryption.
|
||||
* THIS IS EXPERIMENTAL.
|
||||
* @param {string} [options.release] - The key used for specifying release if enabled on the backend.
|
||||
*/
|
||||
constructor(domain, ...args) {
|
||||
super();
|
||||
@@ -314,7 +319,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
invitees,
|
||||
devices,
|
||||
userInfo,
|
||||
e2eeKey
|
||||
e2eeKey,
|
||||
release
|
||||
} = parseArguments(args);
|
||||
const localStorageContent = jitsiLocalStorage.getItem('jitsiLocalStorage');
|
||||
|
||||
@@ -329,7 +335,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
userInfo,
|
||||
appData: {
|
||||
localStorageContent
|
||||
}
|
||||
},
|
||||
release
|
||||
});
|
||||
this._createIFrame(height, width, onload);
|
||||
this._transport = new Transport({
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
import { getReplaceParticipant } from '../../../react/features/base/config/functions';
|
||||
import { isDialogOpen } from '../../../react/features/base/dialog';
|
||||
import { setJWT } from '../../../react/features/base/jwt';
|
||||
import { setPrejoinPageVisibility } from '../../../react/features/prejoin';
|
||||
import UIUtil from '../util/UIUtil';
|
||||
|
||||
import ExternalLoginDialog from './LoginDialog';
|
||||
@@ -180,6 +181,7 @@ function authenticate(room: Object, lockPassword: string) {
|
||||
if (isTokenAuthEnabled(config) || room.isExternalAuthEnabled()) {
|
||||
doExternalAuth(room, lockPassword);
|
||||
} else {
|
||||
APP.store.dispatch(setPrejoinPageVisibility(false));
|
||||
APP.store.dispatch(openLoginDialog());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,6 +160,18 @@ export default class LargeVideoManager {
|
||||
this.videoContainer.removeResizeListener(
|
||||
this._onVideoResolutionUpdate);
|
||||
|
||||
if (getSourceNameSignalingFeatureFlag(APP.store.getState())) {
|
||||
// Remove track streaming status listener.
|
||||
// TODO: when this class is converted to a function react component,
|
||||
// use a custom hook to update a local track streaming status.
|
||||
if (this.videoTrack && !this.videoTrack.local) {
|
||||
this.videoTrack.jitsiTrack.off(JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED,
|
||||
this.handleTrackStreamingStatusChanged);
|
||||
APP.store.dispatch(trackStreamingStatusChanged(this.videoTrack.jitsiTrack,
|
||||
this.videoTrack.jitsiTrack.getTrackStreamingStatus()));
|
||||
}
|
||||
}
|
||||
|
||||
this.removePresenceLabel();
|
||||
|
||||
ReactDOM.unmountComponentAtNode(this._dominantSpeakerAvatarContainer);
|
||||
@@ -260,14 +272,16 @@ export default class LargeVideoManager {
|
||||
// TODO: when this class is converted to a function react component,
|
||||
// use a custom hook to update a local track streaming status.
|
||||
if (this.videoTrack?.jitsiTrack?.getSourceName() !== videoTrack?.jitsiTrack?.getSourceName()) {
|
||||
if (this.videoTrack) {
|
||||
if (this.videoTrack && !this.videoTrack.local) {
|
||||
this.videoTrack.jitsiTrack.off(JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED,
|
||||
this.handleTrackStreamingStatusChanged);
|
||||
APP.store.dispatch(trackStreamingStatusChanged(this.videoTrack.jitsiTrack,
|
||||
this.videoTrack.jitsiTrack.getTrackStreamingStatus()));
|
||||
}
|
||||
if (videoTrack && !videoTrack.local) {
|
||||
this.videoTrack = videoTrack;
|
||||
|
||||
this.videoTrack = videoTrack;
|
||||
|
||||
if (this.videoTrack && !this.videoTrack.local) {
|
||||
this.videoTrack.jitsiTrack.on(JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED,
|
||||
this.handleTrackStreamingStatusChanged);
|
||||
APP.store.dispatch(trackStreamingStatusChanged(this.videoTrack.jitsiTrack,
|
||||
|
||||
394
package-lock.json
generated
394
package-lock.json
generated
@@ -34,7 +34,7 @@
|
||||
"@hapi/bourne": "2.0.0",
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
"@jitsi/rtcstats": "9.0.1",
|
||||
"@jitsi/rtcstats": "9.2.0",
|
||||
"@material-ui/core": "4.11.3",
|
||||
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
|
||||
"@microsoft/microsoft-graph-client": "3.0.1",
|
||||
@@ -49,11 +49,12 @@
|
||||
"@react-navigation/elements": "1.2.1",
|
||||
"@react-navigation/material-top-tabs": "6.0.6",
|
||||
"@react-navigation/native": "6.0.6",
|
||||
"@react-navigation/stack": "6.0.11",
|
||||
"@react-navigation/native-stack": "6.6.2",
|
||||
"@svgr/webpack": "4.3.2",
|
||||
"@tensorflow/tfjs-backend-wasm": "3.13.0",
|
||||
"@tensorflow/tfjs-core": "3.13.0",
|
||||
"@vladmandic/face-api": "1.6.4",
|
||||
"@vladmandic/human": "2.6.5",
|
||||
"@vladmandic/human-models": "2.5.9",
|
||||
"@xmldom/xmldom": "0.7.5",
|
||||
"amplitude-js": "8.2.1",
|
||||
"base64-js": "1.3.1",
|
||||
@@ -71,8 +72,9 @@
|
||||
"jquery": "3.5.1",
|
||||
"jquery-i18next": "1.2.1",
|
||||
"js-md5": "0.6.1",
|
||||
"js-sha512": "0.8.0",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1431.0.0+742232c9/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1457.0.0+ad75454f/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.2",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -92,7 +94,7 @@
|
||||
"react-native-collapsible": "1.6.0",
|
||||
"react-native-default-preference": "1.4.4",
|
||||
"react-native-device-info": "8.4.8",
|
||||
"react-native-dialog": "9.2.1",
|
||||
"react-native-dialog": "https://github.com/jitsi/react-native-dialog/releases/download/v9.2.2-jitsi.1/react-native-dialog-9.2.2.tgz",
|
||||
"react-native-gesture-handler": "2.1.0",
|
||||
"react-native-get-random-values": "1.7.2",
|
||||
"react-native-immersive": "2.0.0",
|
||||
@@ -111,7 +113,7 @@
|
||||
"react-native-url-polyfill": "1.3.0",
|
||||
"react-native-video": "https://git@github.com/jitsi/react-native-video#4f6dad990d17ce42894df993780b5386a9c11b85",
|
||||
"react-native-watch-connectivity": "1.0.4",
|
||||
"react-native-webrtc": "1.100.0",
|
||||
"react-native-webrtc": "1.100.1",
|
||||
"react-native-webview": "11.15.1",
|
||||
"react-native-youtube-iframe": "2.2.1",
|
||||
"react-redux": "7.1.0",
|
||||
@@ -127,6 +129,7 @@
|
||||
"util": "0.12.1",
|
||||
"uuid": "8.3.2",
|
||||
"wasm-check": "2.0.1",
|
||||
"webm-duration-fix": "1.0.4",
|
||||
"windows-iana": "^3.1.0",
|
||||
"zxcvbn": "4.4.2"
|
||||
},
|
||||
@@ -139,7 +142,10 @@
|
||||
"@babel/preset-react": "7.16.0",
|
||||
"@babel/runtime": "7.16.0",
|
||||
"@jitsi/eslint-config": "4.0.0",
|
||||
"@types/react": "17.0.14",
|
||||
"@types/react-native": "0.67.6",
|
||||
"@types/react-redux": "7.1.24",
|
||||
"@types/uuid": "8.3.4",
|
||||
"babel-loader": "8.2.3",
|
||||
"babel-plugin-optional-require": "0.3.1",
|
||||
"circular-dependency-plugin": "5.2.0",
|
||||
@@ -162,7 +168,7 @@
|
||||
"style-loader": "0.19.0",
|
||||
"traverse": "0.6.6",
|
||||
"ts-loader": "9.2.6",
|
||||
"typescript": "4.3.5",
|
||||
"typescript": "4.6.4",
|
||||
"unorm": "1.6.0",
|
||||
"webpack": "5.57.1",
|
||||
"webpack-bundle-analyzer": "4.4.2",
|
||||
@@ -3545,37 +3551,13 @@
|
||||
"integrity": "sha512-QZE0NpI/GKRdZK0vhuyFYWr4XkCz4slihkSfy6RTszjj/YEHZKIV7yGJo6Hbs3kYI2h5v7apoy+h2WCOMumPJw=="
|
||||
},
|
||||
"node_modules/@jitsi/rtcstats": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.0.1.tgz",
|
||||
"integrity": "sha512-kImbDneVzU3pBDyY0vOruG96iYnMp2aOeHxYvnHgXGCTQfqF4dcPGtWMucSb5Dz7KEY6+U6G77Kay5C9p9lFjw==",
|
||||
"version": "9.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.2.0.tgz",
|
||||
"integrity": "sha512-bGQRLFio25++bi3s0em0xKD+WIqhDwg8OQ71K4BXZNOVL3eVX3R/bxbSEok6UYjFQxwoVjfdM4J8cHUu7RwrQw==",
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "1.0.0",
|
||||
"@jitsi/js-utils": "^2.0.0",
|
||||
"sdp": "^3.0.3",
|
||||
"uuid": "3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jitsi/rtcstats/node_modules/@jitsi/js-utils": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-1.0.0.tgz",
|
||||
"integrity": "sha512-at9GPMP7IL0v6QS1Gs9c5MbbiN2AT0uKzsgKM8qS2wqXxqvpfT3p4U3+LH2IUyXiHlkmvlBMcNM02MltBdyRmQ==",
|
||||
"dependencies": {
|
||||
"bowser": "2.7.0",
|
||||
"js-md5": "0.7.3",
|
||||
"postis": "2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jitsi/rtcstats/node_modules/js-md5": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.7.3.tgz",
|
||||
"integrity": "sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ=="
|
||||
},
|
||||
"node_modules/@jitsi/rtcstats/node_modules/uuid": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
|
||||
"integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@jitsi/sdp-interop": {
|
||||
@@ -5042,32 +5024,41 @@
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/routers": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.1.0.tgz",
|
||||
"integrity": "sha512-8xJL+djIzpFdRW/sGlKojQ06fWgFk1c5jER9501HYJ12LF5DIJFr/tqBI2TJ6bk+y+QFu0nbNyeRC80OjRlmkA==",
|
||||
"node_modules/@react-navigation/native-stack": {
|
||||
"version": "6.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.6.2.tgz",
|
||||
"integrity": "sha512-pFMuzhxbPml5MBvJVAzHWoaUkQaefAOKpuUnAs/AxNQuHQwwnxRmDit1PQLuIPo7g7DlfwFXagDHE1R0tbnS8Q==",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.1.23"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/stack": {
|
||||
"version": "6.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-6.0.11.tgz",
|
||||
"integrity": "sha512-Osc2mXi0Zh/u92HRCceDqVfVnypTa2sZgYMJDU+vDhHz38negtbCG+cjje6nApSjwC5WTVhYP4OoD5WBSh51+g==",
|
||||
"dependencies": {
|
||||
"@react-navigation/elements": "^1.2.1",
|
||||
"color": "^3.1.3",
|
||||
"@react-navigation/elements": "^1.3.3",
|
||||
"warn-once": "^0.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-navigation/native": "^6.0.0",
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-gesture-handler": ">= 1.0.0",
|
||||
"react-native-safe-area-context": ">= 3.0.0",
|
||||
"react-native-screens": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/native-stack/node_modules/@react-navigation/elements": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.3.tgz",
|
||||
"integrity": "sha512-Lv2lR7si5gNME8dRsqz57d54m4FJtrwHRjNQLOyQO546ZxO+g864cSvoLC6hQedQU0+IJnPTsZiEI2hHqfpEpw==",
|
||||
"peerDependencies": {
|
||||
"@react-navigation/native": "^6.0.0",
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-safe-area-context": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/routers": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.1.0.tgz",
|
||||
"integrity": "sha512-8xJL+djIzpFdRW/sGlKojQ06fWgFk1c5jER9501HYJ12LF5DIJFr/tqBI2TJ6bk+y+QFu0nbNyeRC80OjRlmkA==",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.1.23"
|
||||
}
|
||||
},
|
||||
"node_modules/@sideway/address": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
|
||||
@@ -5394,6 +5385,16 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.41.tgz",
|
||||
"integrity": "sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA=="
|
||||
},
|
||||
"node_modules/@types/hoist-non-react-statics": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
|
||||
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/react": "*",
|
||||
"hoist-non-react-statics": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/http-proxy": {
|
||||
"version": "1.17.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz",
|
||||
@@ -5490,9 +5491,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "17.0.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz",
|
||||
"integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==",
|
||||
"version": "17.0.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.14.tgz",
|
||||
"integrity": "sha512-0WwKHUbWuQWOce61UexYuWTGuGY/8JvtUe/dtQ6lR4sZ3UiylHotJeWpf3ArP9+DSGUoLY3wbU59VyMrJps5VQ==",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"@types/scheduler": "*",
|
||||
@@ -5508,6 +5509,18 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-redux": {
|
||||
"version": "7.1.24",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.24.tgz",
|
||||
"integrity": "sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/hoist-non-react-statics": "^3.3.0",
|
||||
"@types/react": "*",
|
||||
"hoist-non-react-statics": "^3.3.0",
|
||||
"redux": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-transition-group": {
|
||||
"version": "4.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz",
|
||||
@@ -5560,6 +5573,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/uuid": {
|
||||
"version": "8.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
|
||||
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/webgl-ext": {
|
||||
"version": "0.0.30",
|
||||
"resolved": "https://registry.npmjs.org/@types/webgl-ext/-/webgl-ext-0.0.30.tgz",
|
||||
@@ -5587,14 +5606,22 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz",
|
||||
"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
|
||||
},
|
||||
"node_modules/@vladmandic/face-api": {
|
||||
"version": "1.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@vladmandic/face-api/-/face-api-1.6.4.tgz",
|
||||
"integrity": "sha512-tVx8lCL1mKb44qeN5EEypJNXqxRYXh+7BcSzfY4iMaZIoF5Y+Jev20UiIn9JvxwGV2caWkdFIjpvw+OxsL/kdg==",
|
||||
"node_modules/@vladmandic/human": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/@vladmandic/human/-/human-2.6.5.tgz",
|
||||
"integrity": "sha512-5fG5lICkJw17d8fT9ZHtioAPLmOKsQlNN4rbuA1t21HlV7KL3M2EMbYeO+ZE0t6VLSioZZH/KoOFvW5A0JP0Hg==",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vladmandic/human-models": {
|
||||
"version": "2.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@vladmandic/human-models/-/human-models-2.5.9.tgz",
|
||||
"integrity": "sha512-WhV0RIeELsA73LGMpemYJvpIEuG0nkh6rP1x7JctKDQkNaARgWolTq9r1RUvWw++rQfzfZ82bYcAauJcaGW6bw==",
|
||||
"dependencies": {
|
||||
"@vladmandic/human": "^2.5.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/ast": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
|
||||
@@ -8314,6 +8341,11 @@
|
||||
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ebml-block": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ebml-block/-/ebml-block-1.1.2.tgz",
|
||||
"integrity": "sha512-HgNlIsRFP6D9VKU5atCeHRJY7XkJP8bOe8yEhd8NB7B3b4++VWTyauz6g650iiPmLfPLGlVpoJmGSgMfXDYusg=="
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@@ -10648,6 +10680,14 @@
|
||||
"css-in-js-utils": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/int64-buffer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-1.0.1.tgz",
|
||||
"integrity": "sha512-+3azY4pXrjAupJHU1V9uGERWlhoqNswJNji6aD/02xac7oxol508AsMC5lxKhEqyZeDFy3enq5OGWXF4u75hiw==",
|
||||
"engines": {
|
||||
"node": ">= 4.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/internal-slot": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
|
||||
@@ -11610,6 +11650,11 @@
|
||||
"resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.6.1.tgz",
|
||||
"integrity": "sha512-lyUTXOqMEaA9mm38mHxbTo83WsYAvMJm850kxJcRno3T2qL+e40B2G89E0/4r9TdAeB3jN0TdSVp/VHNI6/WyQ=="
|
||||
},
|
||||
"node_modules/js-sha512": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz",
|
||||
"integrity": "sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ=="
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@@ -12123,8 +12168,8 @@
|
||||
},
|
||||
"node_modules/lib-jitsi-meet": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1431.0.0+742232c9/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-M2tybHP1w4AXcsUH33aiTgPlr/I0uqcwfHYUo2/zpmhI7gaxas7KxAy7VU7cqJNZh3qTiT46eYZQEeMaNffuCw==",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1457.0.0+ad75454f/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-K+dJWt6nlAXtKE/WhR8pkf3vga+52tJSpTWX/fxOTKn8IJKTlj46gSC2CosAfwyG4P6ISzeFnTvVC3E+qbxbUg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
@@ -14788,11 +14833,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postis": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postis/-/postis-2.2.0.tgz",
|
||||
"integrity": "sha1-3F4yN2WYXd/cv9r8MUGpVprvdak="
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||
@@ -15382,9 +15422,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-dialog": {
|
||||
"version": "9.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-dialog/-/react-native-dialog-9.2.1.tgz",
|
||||
"integrity": "sha512-UNnGFTpH0cX16cJZLFq9/TAZH1+B2vzJrQL1mUaSqZjV+sFTpUB1WvghJZxPwi52v587kJpfKN7oPfWaXAu+YQ==",
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://github.com/jitsi/react-native-dialog/releases/download/v9.2.2-jitsi.1/react-native-dialog-9.2.2.tgz",
|
||||
"integrity": "sha512-MKbuBbovO8eGiAM9i6o0nrdBXivhRpzPQ+aVBXGJEPMH7RrCSNUKaCoEpkjfGHlTxjZimi6WjDCjjzCRSHlV1A==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react-native": ">=0.63.0"
|
||||
}
|
||||
@@ -16004,9 +16045,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-webrtc": {
|
||||
"version": "1.100.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.100.0.tgz",
|
||||
"integrity": "sha512-sBLl8Ihj3xfYn0NZJdDxelB/dZ422FWg/kcLdSw6Wk4eM3MeNW3iFwVsqg2dLzeDnuoQ06i7hOdtP7pGAiKsug==",
|
||||
"version": "1.100.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.100.1.tgz",
|
||||
"integrity": "sha512-2dF8HrZWdfrbm1NLso424xgNeGFf4WK5Jlqs7ecVDvCMWHTYVHVwyNt52zx1yiOMEqQWk4edOd4xhWJfUiOvMg==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"base64-js": "1.5.1",
|
||||
@@ -18634,9 +18675,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
|
||||
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
|
||||
"version": "4.6.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
|
||||
"integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
@@ -19114,6 +19155,40 @@
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||
},
|
||||
"node_modules/webm-duration-fix": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/webm-duration-fix/-/webm-duration-fix-1.0.4.tgz",
|
||||
"integrity": "sha512-kvhmSmEnuohtK+j+mJswqCCM2ViKb9W8Ch0oAxcaeUvpok5CsMORQLnea+CYKDXPG6JH12H0CbRK85qhfeZLew==",
|
||||
"dependencies": {
|
||||
"buffer": "^6.0.3",
|
||||
"ebml-block": "^1.1.2",
|
||||
"events": "^3.3.0",
|
||||
"int64-buffer": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/webm-duration-fix/node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.57.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.57.1.tgz",
|
||||
@@ -22619,35 +22694,13 @@
|
||||
"integrity": "sha512-QZE0NpI/GKRdZK0vhuyFYWr4XkCz4slihkSfy6RTszjj/YEHZKIV7yGJo6Hbs3kYI2h5v7apoy+h2WCOMumPJw=="
|
||||
},
|
||||
"@jitsi/rtcstats": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.0.1.tgz",
|
||||
"integrity": "sha512-kImbDneVzU3pBDyY0vOruG96iYnMp2aOeHxYvnHgXGCTQfqF4dcPGtWMucSb5Dz7KEY6+U6G77Kay5C9p9lFjw==",
|
||||
"version": "9.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.2.0.tgz",
|
||||
"integrity": "sha512-bGQRLFio25++bi3s0em0xKD+WIqhDwg8OQ71K4BXZNOVL3eVX3R/bxbSEok6UYjFQxwoVjfdM4J8cHUu7RwrQw==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "1.0.0",
|
||||
"@jitsi/js-utils": "^2.0.0",
|
||||
"sdp": "^3.0.3",
|
||||
"uuid": "3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-1.0.0.tgz",
|
||||
"integrity": "sha512-at9GPMP7IL0v6QS1Gs9c5MbbiN2AT0uKzsgKM8qS2wqXxqvpfT3p4U3+LH2IUyXiHlkmvlBMcNM02MltBdyRmQ==",
|
||||
"requires": {
|
||||
"bowser": "2.7.0",
|
||||
"js-md5": "0.7.3",
|
||||
"postis": "2.2.0"
|
||||
}
|
||||
},
|
||||
"js-md5": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.7.3.tgz",
|
||||
"integrity": "sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ=="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
|
||||
"integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g=="
|
||||
}
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"@jitsi/sdp-interop": {
|
||||
@@ -23700,6 +23753,22 @@
|
||||
"nanoid": "^3.1.23"
|
||||
}
|
||||
},
|
||||
"@react-navigation/native-stack": {
|
||||
"version": "6.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.6.2.tgz",
|
||||
"integrity": "sha512-pFMuzhxbPml5MBvJVAzHWoaUkQaefAOKpuUnAs/AxNQuHQwwnxRmDit1PQLuIPo7g7DlfwFXagDHE1R0tbnS8Q==",
|
||||
"requires": {
|
||||
"@react-navigation/elements": "^1.3.3",
|
||||
"warn-once": "^0.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/elements": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.3.tgz",
|
||||
"integrity": "sha512-Lv2lR7si5gNME8dRsqz57d54m4FJtrwHRjNQLOyQO546ZxO+g864cSvoLC6hQedQU0+IJnPTsZiEI2hHqfpEpw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@react-navigation/routers": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.1.0.tgz",
|
||||
@@ -23708,16 +23777,6 @@
|
||||
"nanoid": "^3.1.23"
|
||||
}
|
||||
},
|
||||
"@react-navigation/stack": {
|
||||
"version": "6.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-6.0.11.tgz",
|
||||
"integrity": "sha512-Osc2mXi0Zh/u92HRCceDqVfVnypTa2sZgYMJDU+vDhHz38negtbCG+cjje6nApSjwC5WTVhYP4OoD5WBSh51+g==",
|
||||
"requires": {
|
||||
"@react-navigation/elements": "^1.2.1",
|
||||
"color": "^3.1.3",
|
||||
"warn-once": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"@sideway/address": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
|
||||
@@ -23987,6 +24046,16 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.41.tgz",
|
||||
"integrity": "sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA=="
|
||||
},
|
||||
"@types/hoist-non-react-statics": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
|
||||
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*",
|
||||
"hoist-non-react-statics": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"@types/http-proxy": {
|
||||
"version": "1.17.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz",
|
||||
@@ -24083,9 +24152,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/react": {
|
||||
"version": "17.0.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz",
|
||||
"integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==",
|
||||
"version": "17.0.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.14.tgz",
|
||||
"integrity": "sha512-0WwKHUbWuQWOce61UexYuWTGuGY/8JvtUe/dtQ6lR4sZ3UiylHotJeWpf3ArP9+DSGUoLY3wbU59VyMrJps5VQ==",
|
||||
"requires": {
|
||||
"@types/prop-types": "*",
|
||||
"@types/scheduler": "*",
|
||||
@@ -24101,6 +24170,18 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-redux": {
|
||||
"version": "7.1.24",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.24.tgz",
|
||||
"integrity": "sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/hoist-non-react-statics": "^3.3.0",
|
||||
"@types/react": "*",
|
||||
"hoist-non-react-statics": "^3.3.0",
|
||||
"redux": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"@types/react-transition-group": {
|
||||
"version": "4.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz",
|
||||
@@ -24153,6 +24234,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/uuid": {
|
||||
"version": "8.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
|
||||
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/webgl-ext": {
|
||||
"version": "0.0.30",
|
||||
"resolved": "https://registry.npmjs.org/@types/webgl-ext/-/webgl-ext-0.0.30.tgz",
|
||||
@@ -24180,10 +24267,18 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz",
|
||||
"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
|
||||
},
|
||||
"@vladmandic/face-api": {
|
||||
"version": "1.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@vladmandic/face-api/-/face-api-1.6.4.tgz",
|
||||
"integrity": "sha512-tVx8lCL1mKb44qeN5EEypJNXqxRYXh+7BcSzfY4iMaZIoF5Y+Jev20UiIn9JvxwGV2caWkdFIjpvw+OxsL/kdg=="
|
||||
"@vladmandic/human": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/@vladmandic/human/-/human-2.6.5.tgz",
|
||||
"integrity": "sha512-5fG5lICkJw17d8fT9ZHtioAPLmOKsQlNN4rbuA1t21HlV7KL3M2EMbYeO+ZE0t6VLSioZZH/KoOFvW5A0JP0Hg=="
|
||||
},
|
||||
"@vladmandic/human-models": {
|
||||
"version": "2.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@vladmandic/human-models/-/human-models-2.5.9.tgz",
|
||||
"integrity": "sha512-WhV0RIeELsA73LGMpemYJvpIEuG0nkh6rP1x7JctKDQkNaARgWolTq9r1RUvWw++rQfzfZ82bYcAauJcaGW6bw==",
|
||||
"requires": {
|
||||
"@vladmandic/human": "^2.5.8"
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
"version": "1.11.1",
|
||||
@@ -26331,6 +26426,11 @@
|
||||
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
|
||||
"dev": true
|
||||
},
|
||||
"ebml-block": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ebml-block/-/ebml-block-1.1.2.tgz",
|
||||
"integrity": "sha512-HgNlIsRFP6D9VKU5atCeHRJY7XkJP8bOe8yEhd8NB7B3b4++VWTyauz6g650iiPmLfPLGlVpoJmGSgMfXDYusg=="
|
||||
},
|
||||
"ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@@ -28156,6 +28256,11 @@
|
||||
"css-in-js-utils": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"int64-buffer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-1.0.1.tgz",
|
||||
"integrity": "sha512-+3azY4pXrjAupJHU1V9uGERWlhoqNswJNji6aD/02xac7oxol508AsMC5lxKhEqyZeDFy3enq5OGWXF4u75hiw=="
|
||||
},
|
||||
"internal-slot": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
|
||||
@@ -28845,6 +28950,11 @@
|
||||
"resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.6.1.tgz",
|
||||
"integrity": "sha512-lyUTXOqMEaA9mm38mHxbTo83WsYAvMJm850kxJcRno3T2qL+e40B2G89E0/4r9TdAeB3jN0TdSVp/VHNI6/WyQ=="
|
||||
},
|
||||
"js-sha512": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz",
|
||||
"integrity": "sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ=="
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@@ -29259,8 +29369,8 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1431.0.0+742232c9/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-M2tybHP1w4AXcsUH33aiTgPlr/I0uqcwfHYUo2/zpmhI7gaxas7KxAy7VU7cqJNZh3qTiT46eYZQEeMaNffuCw==",
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1457.0.0+ad75454f/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-K+dJWt6nlAXtKE/WhR8pkf3vga+52tJSpTWX/fxOTKn8IJKTlj46gSC2CosAfwyG4P6ISzeFnTvVC3E+qbxbUg==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
@@ -31391,11 +31501,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"postis": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postis/-/postis-2.2.0.tgz",
|
||||
"integrity": "sha1-3F4yN2WYXd/cv9r8MUGpVprvdak="
|
||||
},
|
||||
"prelude-ls": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||
@@ -31836,9 +31941,8 @@
|
||||
"integrity": "sha512-92676ZWHZHsPM/EW1ulgb2MuVfjYfMWRTWMbLcrCsipkcMaZ9Traz5mpsnCS7KZpsOksnvUinzDIjsct2XGc6Q=="
|
||||
},
|
||||
"react-native-dialog": {
|
||||
"version": "9.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-dialog/-/react-native-dialog-9.2.1.tgz",
|
||||
"integrity": "sha512-UNnGFTpH0cX16cJZLFq9/TAZH1+B2vzJrQL1mUaSqZjV+sFTpUB1WvghJZxPwi52v587kJpfKN7oPfWaXAu+YQ=="
|
||||
"version": "https://github.com/jitsi/react-native-dialog/releases/download/v9.2.2-jitsi.1/react-native-dialog-9.2.2.tgz",
|
||||
"integrity": "sha512-MKbuBbovO8eGiAM9i6o0nrdBXivhRpzPQ+aVBXGJEPMH7RrCSNUKaCoEpkjfGHlTxjZimi6WjDCjjzCRSHlV1A=="
|
||||
},
|
||||
"react-native-gesture-handler": {
|
||||
"version": "2.1.0",
|
||||
@@ -32208,9 +32312,9 @@
|
||||
}
|
||||
},
|
||||
"react-native-webrtc": {
|
||||
"version": "1.100.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.100.0.tgz",
|
||||
"integrity": "sha512-sBLl8Ihj3xfYn0NZJdDxelB/dZ422FWg/kcLdSw6Wk4eM3MeNW3iFwVsqg2dLzeDnuoQ06i7hOdtP7pGAiKsug==",
|
||||
"version": "1.100.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.100.1.tgz",
|
||||
"integrity": "sha512-2dF8HrZWdfrbm1NLso424xgNeGFf4WK5Jlqs7ecVDvCMWHTYVHVwyNt52zx1yiOMEqQWk4edOd4xhWJfUiOvMg==",
|
||||
"requires": {
|
||||
"base64-js": "1.5.1",
|
||||
"event-target-shim": "6.0.2",
|
||||
@@ -34257,9 +34361,9 @@
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
|
||||
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
|
||||
"version": "4.6.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
|
||||
"integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
|
||||
"dev": true
|
||||
},
|
||||
"ua-parser-js": {
|
||||
@@ -34604,6 +34708,28 @@
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||
},
|
||||
"webm-duration-fix": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/webm-duration-fix/-/webm-duration-fix-1.0.4.tgz",
|
||||
"integrity": "sha512-kvhmSmEnuohtK+j+mJswqCCM2ViKb9W8Ch0oAxcaeUvpok5CsMORQLnea+CYKDXPG6JH12H0CbRK85qhfeZLew==",
|
||||
"requires": {
|
||||
"buffer": "^6.0.3",
|
||||
"ebml-block": "^1.1.2",
|
||||
"events": "^3.3.0",
|
||||
"int64-buffer": "^1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"requires": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"webpack": {
|
||||
"version": "5.57.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.57.1.tgz",
|
||||
|
||||
26
package.json
26
package.json
@@ -39,7 +39,7 @@
|
||||
"@hapi/bourne": "2.0.0",
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
"@jitsi/rtcstats": "9.0.1",
|
||||
"@jitsi/rtcstats": "9.2.0",
|
||||
"@material-ui/core": "4.11.3",
|
||||
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
|
||||
"@microsoft/microsoft-graph-client": "3.0.1",
|
||||
@@ -54,11 +54,12 @@
|
||||
"@react-navigation/elements": "1.2.1",
|
||||
"@react-navigation/material-top-tabs": "6.0.6",
|
||||
"@react-navigation/native": "6.0.6",
|
||||
"@react-navigation/stack": "6.0.11",
|
||||
"@react-navigation/native-stack": "6.6.2",
|
||||
"@svgr/webpack": "4.3.2",
|
||||
"@tensorflow/tfjs-backend-wasm": "3.13.0",
|
||||
"@tensorflow/tfjs-core": "3.13.0",
|
||||
"@vladmandic/face-api": "1.6.4",
|
||||
"@vladmandic/human": "2.6.5",
|
||||
"@vladmandic/human-models": "2.5.9",
|
||||
"@xmldom/xmldom": "0.7.5",
|
||||
"amplitude-js": "8.2.1",
|
||||
"base64-js": "1.3.1",
|
||||
@@ -76,8 +77,9 @@
|
||||
"jquery": "3.5.1",
|
||||
"jquery-i18next": "1.2.1",
|
||||
"js-md5": "0.6.1",
|
||||
"js-sha512": "0.8.0",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1431.0.0+742232c9/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1457.0.0+ad75454f/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.2",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -97,7 +99,7 @@
|
||||
"react-native-collapsible": "1.6.0",
|
||||
"react-native-default-preference": "1.4.4",
|
||||
"react-native-device-info": "8.4.8",
|
||||
"react-native-dialog": "9.2.1",
|
||||
"react-native-dialog": "https://github.com/jitsi/react-native-dialog/releases/download/v9.2.2-jitsi.1/react-native-dialog-9.2.2.tgz",
|
||||
"react-native-gesture-handler": "2.1.0",
|
||||
"react-native-get-random-values": "1.7.2",
|
||||
"react-native-immersive": "2.0.0",
|
||||
@@ -116,7 +118,7 @@
|
||||
"react-native-url-polyfill": "1.3.0",
|
||||
"react-native-video": "https://git@github.com/jitsi/react-native-video#4f6dad990d17ce42894df993780b5386a9c11b85",
|
||||
"react-native-watch-connectivity": "1.0.4",
|
||||
"react-native-webrtc": "1.100.0",
|
||||
"react-native-webrtc": "1.100.1",
|
||||
"react-native-webview": "11.15.1",
|
||||
"react-native-youtube-iframe": "2.2.1",
|
||||
"react-redux": "7.1.0",
|
||||
@@ -132,6 +134,7 @@
|
||||
"util": "0.12.1",
|
||||
"uuid": "8.3.2",
|
||||
"wasm-check": "2.0.1",
|
||||
"webm-duration-fix": "1.0.4",
|
||||
"windows-iana": "^3.1.0",
|
||||
"zxcvbn": "4.4.2"
|
||||
},
|
||||
@@ -144,7 +147,10 @@
|
||||
"@babel/preset-react": "7.16.0",
|
||||
"@babel/runtime": "7.16.0",
|
||||
"@jitsi/eslint-config": "4.0.0",
|
||||
"@types/react": "17.0.14",
|
||||
"@types/react-native": "0.67.6",
|
||||
"@types/react-redux": "7.1.24",
|
||||
"@types/uuid": "8.3.4",
|
||||
"babel-loader": "8.2.3",
|
||||
"babel-plugin-optional-require": "0.3.1",
|
||||
"circular-dependency-plugin": "5.2.0",
|
||||
@@ -167,7 +173,7 @@
|
||||
"style-loader": "0.19.0",
|
||||
"traverse": "0.6.6",
|
||||
"ts-loader": "9.2.6",
|
||||
"typescript": "4.3.5",
|
||||
"typescript": "4.6.4",
|
||||
"unorm": "1.6.0",
|
||||
"webpack": "5.57.1",
|
||||
"webpack-bundle-analyzer": "4.4.2",
|
||||
@@ -183,8 +189,12 @@
|
||||
"lint": "eslint --max-warnings 0 .",
|
||||
"lang-sort": "./resources/lang-sort.sh",
|
||||
"lint-fix": "eslint --max-warnings 0 --fix .",
|
||||
"postinstall": "patch-package && jetify",
|
||||
"postinstall": "patch-package --error-on-fail && jetify",
|
||||
"validate": "npm ls",
|
||||
"start": "make dev"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "17.0.14",
|
||||
"@types/react-dom": "17.0.14"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
diff --git a/node_modules/react-native-dialog/lib/Button.js b/node_modules/react-native-dialog/lib/Button.js
|
||||
index 19eeb22..b8a66f4 100644
|
||||
--- a/node_modules/react-native-dialog/lib/Button.js
|
||||
+++ b/node_modules/react-native-dialog/lib/Button.js
|
||||
@@ -50,7 +50,7 @@ const buildStyles = (isDark) => StyleSheet.create({
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
android: {
|
||||
- color: PlatformColor(`@android:color/${isDark ? "link_text_dark" : "link_text_dark_light"}`),
|
||||
+ color: isDark ? '#BFC7C7C7' : '#BF727272',
|
||||
textAlign: "center",
|
||||
backgroundColor: "transparent",
|
||||
padding: 8,
|
||||
diff --git a/node_modules/react-native-dialog/lib/CodeInput.js b/node_modules/react-native-dialog/lib/CodeInput.js
|
||||
index eceae56..cc4339d 100644
|
||||
--- a/node_modules/react-native-dialog/lib/CodeInput.js
|
||||
+++ b/node_modules/react-native-dialog/lib/CodeInput.js
|
||||
@@ -97,7 +97,7 @@ const buildStyles = (isDark) => StyleSheet.create({
|
||||
color: PlatformColor("label"),
|
||||
},
|
||||
android: {
|
||||
- color: PlatformColor(`@android:color/${isDark ? "primary_text_dark" : "primary_text_light"}`),
|
||||
+ color: isDark ? '#FAFAFA' : '#212121',
|
||||
fontSize: 20,
|
||||
},
|
||||
default: {},
|
||||
@@ -107,7 +107,7 @@ const buildStyles = (isDark) => StyleSheet.create({
|
||||
color: PlatformColor("label"),
|
||||
},
|
||||
android: {
|
||||
- color: PlatformColor(`@android:color/${isDark ? "primary_text_dark" : "primary_text_light"}`),
|
||||
+ color: isDark ? '#FAFAFA' : '#212121',
|
||||
fontSize: 14,
|
||||
},
|
||||
default: {},
|
||||
diff --git a/node_modules/react-native-dialog/lib/Container.js b/node_modules/react-native-dialog/lib/Container.js
|
||||
index 69e3764..d7569fb 100644
|
||||
--- a/node_modules/react-native-dialog/lib/Container.js
|
||||
+++ b/node_modules/react-native-dialog/lib/Container.js
|
||||
@@ -82,7 +82,7 @@ DialogContainer.propTypes = {
|
||||
useNativeDriver: PropTypes.bool,
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
-const buildStyles = () => StyleSheet.create({
|
||||
+const buildStyles = (isDark) => StyleSheet.create({
|
||||
centeredView: {
|
||||
marginTop: 22,
|
||||
},
|
||||
@@ -103,7 +103,7 @@ const buildStyles = () => StyleSheet.create({
|
||||
overflow: "hidden",
|
||||
},
|
||||
android: {
|
||||
- backgroundColor: PlatformColor("?attr/colorBackgroundFloating"),
|
||||
+ backgroundColor: isDark ? '#212121' : '#FFFFFF',
|
||||
flexDirection: "column",
|
||||
borderRadius: 3,
|
||||
padding: 16,
|
||||
diff --git a/node_modules/react-native-dialog/lib/Description.js b/node_modules/react-native-dialog/lib/Description.js
|
||||
index 2da9ed3..248ac2f 100644
|
||||
--- a/node_modules/react-native-dialog/lib/Description.js
|
||||
+++ b/node_modules/react-native-dialog/lib/Description.js
|
||||
@@ -28,7 +28,7 @@ const buildStyles = (isDark) => StyleSheet.create({
|
||||
marginTop: 4,
|
||||
},
|
||||
android: {
|
||||
- color: PlatformColor(`@android:color/${isDark ? "secondary_text_dark" : "secondary_text_light"}`),
|
||||
+ color: isDark ? '#C7C7C7' : '#727272',
|
||||
fontSize: 16,
|
||||
marginTop: 10,
|
||||
},
|
||||
diff --git a/node_modules/react-native-dialog/lib/Input.js b/node_modules/react-native-dialog/lib/Input.js
|
||||
index b33a1a0..063d7f8 100644
|
||||
--- a/node_modules/react-native-dialog/lib/Input.js
|
||||
+++ b/node_modules/react-native-dialog/lib/Input.js
|
||||
@@ -48,7 +48,7 @@ const buildStyles = (isDark) => StyleSheet.create({
|
||||
color: PlatformColor("label"),
|
||||
},
|
||||
android: {
|
||||
- color: PlatformColor(`@android:color/${isDark ? "primary_text_dark" : "primary_text_light"}`),
|
||||
+ color: isDark ? '#FAFAFA' : '#212121',
|
||||
fontSize: 14,
|
||||
},
|
||||
default: {},
|
||||
@@ -58,7 +58,7 @@ const buildStyles = (isDark) => StyleSheet.create({
|
||||
color: PlatformColor("label"),
|
||||
},
|
||||
android: {
|
||||
- color: PlatformColor(`@android:color/${isDark ? "primary_text_dark" : "primary_text_light"}`),
|
||||
+ color: isDark ? '#FAFAFA' : '#212121',
|
||||
marginLeft: -4,
|
||||
paddingLeft: 4,
|
||||
},
|
||||
diff --git a/node_modules/react-native-dialog/lib/Switch.js b/node_modules/react-native-dialog/lib/Switch.js
|
||||
index 26a05ca..05114fa 100644
|
||||
--- a/node_modules/react-native-dialog/lib/Switch.js
|
||||
+++ b/node_modules/react-native-dialog/lib/Switch.js
|
||||
@@ -52,7 +52,7 @@ const buildStyles = (isDark) => StyleSheet.create({
|
||||
flex: 1,
|
||||
paddingRight: 8,
|
||||
fontSize: 16,
|
||||
- color: PlatformColor(`@android:color/${isDark ? "primary_text_dark" : "primary_text_light"}`),
|
||||
+ color: isDark ? '#FAFAFA' : '#212121',
|
||||
},
|
||||
default: {},
|
||||
}),
|
||||
diff --git a/node_modules/react-native-dialog/lib/Title.js b/node_modules/react-native-dialog/lib/Title.js
|
||||
index 1c6fd87..b5511cc 100644
|
||||
--- a/node_modules/react-native-dialog/lib/Title.js
|
||||
+++ b/node_modules/react-native-dialog/lib/Title.js
|
||||
@@ -28,7 +28,7 @@ const buildStyles = (isDark) => StyleSheet.create({
|
||||
fontWeight: "600",
|
||||
},
|
||||
android: {
|
||||
- color: PlatformColor(`@android:color/${isDark ? "primary_text_dark" : "primary_text_light"}`),
|
||||
+ color: isDark ? '#FAFAFA' : '#212121',
|
||||
fontWeight: "500",
|
||||
fontSize: 18,
|
||||
},
|
||||
@@ -641,18 +641,20 @@ export function createSharedVideoEvent(action, attributes = {}) {
|
||||
* of ACTION_SHORTCUT_PRESSED, ACTION_SHORTCUT_RELEASED
|
||||
* or ACTION_SHORTCUT_TRIGGERED).
|
||||
* @param {Object} attributes - Attributes to attach to the event.
|
||||
* @param {string} source - The event's source.
|
||||
* @returns {Object} The event in a format suitable for sending via
|
||||
* sendAnalytics.
|
||||
*/
|
||||
export function createShortcutEvent(
|
||||
shortcut,
|
||||
action = ACTION_SHORTCUT_TRIGGERED,
|
||||
attributes = {}) {
|
||||
attributes = {},
|
||||
source = 'keyboard.shortcut') {
|
||||
return {
|
||||
action,
|
||||
actionSubjectId: shortcut,
|
||||
attributes,
|
||||
source: 'keyboard.shortcut',
|
||||
source,
|
||||
type: TYPE_UI
|
||||
};
|
||||
}
|
||||
@@ -901,7 +903,7 @@ export function createBreakoutRoomsEvent(actionSubject) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and event which indicates a GIF was sent.
|
||||
* Creates an event which indicates a GIF was sent.
|
||||
*
|
||||
* @returns {Object} The event in a format suitable for sending via
|
||||
* sendAnalytics.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { API_ID } from '../../../modules/API/constants';
|
||||
import { getName as getAppName } from '../app/functions';
|
||||
import { getAnalyticsRoomName } from '../base/conference';
|
||||
import {
|
||||
checkChromeExtensionsInstalled,
|
||||
isMobileBrowser
|
||||
@@ -12,6 +13,7 @@ import JitsiMeetJS, {
|
||||
} from '../base/lib-jitsi-meet';
|
||||
import { isAnalyticsEnabled } from '../base/lib-jitsi-meet/functions';
|
||||
import { getJitsiMeetGlobalNS, loadScript, parseURIString } from '../base/util';
|
||||
import { inIframe } from '../base/util/iframeUtils';
|
||||
|
||||
import { AmplitudeHandler, MatomoHandler } from './handlers';
|
||||
import logger from './logger';
|
||||
@@ -154,7 +156,9 @@ export async function createHandlers({ getState }: { getState: Function }) {
|
||||
* @param {Array<Object>} handlers - The analytics handlers.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function initAnalytics({ getState }: { getState: Function }, handlers: Array<Object>) {
|
||||
export function initAnalytics(store: Store, handlers: Array<Object>) {
|
||||
const { getState, dispatch } = store;
|
||||
|
||||
if (!isAnalyticsEnabled(getState) || handlers.length === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -165,7 +169,6 @@ export function initAnalytics({ getState }: { getState: Function }, handlers: Ar
|
||||
deploymentInfo
|
||||
} = config;
|
||||
const { group, server } = state['features/base/jwt'];
|
||||
const roomName = state['features/base/conference'].room;
|
||||
const { locationURL = {} } = state['features/base/connection'];
|
||||
const { tenant } = parseURIString(locationURL.href) || {};
|
||||
const permanentProperties = {};
|
||||
@@ -203,7 +206,7 @@ export function initAnalytics({ getState }: { getState: Function }, handlers: Ar
|
||||
}
|
||||
|
||||
analytics.addPermanentProperties(permanentProperties);
|
||||
analytics.setConferenceName(roomName);
|
||||
analytics.setConferenceName(getAnalyticsRoomName(state, dispatch));
|
||||
|
||||
// Set the handlers last, since this triggers emptying of the cache
|
||||
analytics.setAnalyticsHandlers(handlers);
|
||||
@@ -221,24 +224,6 @@ export function initAnalytics({ getState }: { getState: Function }, handlers: Ar
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether we are loaded in iframe.
|
||||
*
|
||||
* @returns {boolean} Returns {@code true} if loaded in iframe.
|
||||
* @private
|
||||
*/
|
||||
export function inIframe() {
|
||||
if (navigator.product === 'ReactNative') {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to load the scripts for the external analytics handlers and creates them.
|
||||
*
|
||||
|
||||
@@ -15,11 +15,17 @@ import { connect, disconnect, setLocationURL } from '../base/connection';
|
||||
import { loadConfig } from '../base/lib-jitsi-meet/functions.native';
|
||||
import { createDesiredLocalTracks } from '../base/tracks';
|
||||
import {
|
||||
appendURLParam,
|
||||
getBackendSafeRoomName,
|
||||
parseURIString,
|
||||
parseURLParams,
|
||||
toURLString
|
||||
} from '../base/util';
|
||||
import { navigateRoot } from '../mobile/navigation/rootNavigationContainerRef';
|
||||
import { isPrejoinPageEnabled } from '../mobile/navigation/functions';
|
||||
import {
|
||||
goBackToRoot,
|
||||
navigateRoot
|
||||
} from '../mobile/navigation/rootNavigationContainerRef';
|
||||
import { screen } from '../mobile/navigation/routes';
|
||||
import { setFatalError } from '../overlay';
|
||||
|
||||
@@ -86,7 +92,11 @@ export function appNavigate(uri: ?string) {
|
||||
let url = `${baseURL}config.js`;
|
||||
|
||||
// XXX In order to support multiple shards, tell the room to the deployment.
|
||||
room && (url += `?room=${getBackendSafeRoomName(room)}`);
|
||||
room && (url = appendURLParam(url, 'room', getBackendSafeRoomName(room)));
|
||||
|
||||
const { release } = parseURLParams(location, true, 'search');
|
||||
|
||||
release && (url = appendURLParam(url, 'release', release));
|
||||
|
||||
let config;
|
||||
|
||||
@@ -128,7 +138,15 @@ export function appNavigate(uri: ?string) {
|
||||
|
||||
if (room) {
|
||||
dispatch(createDesiredLocalTracks());
|
||||
dispatch(connect());
|
||||
|
||||
if (isPrejoinPageEnabled(getState())) {
|
||||
navigateRoot(screen.preJoin);
|
||||
} else {
|
||||
dispatch(connect());
|
||||
navigateRoot(screen.conference.root);
|
||||
}
|
||||
} else {
|
||||
goBackToRoot(getState(), dispatch);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,8 +15,10 @@ import {
|
||||
import { setLocationURL } from '../base/connection';
|
||||
import { loadConfig } from '../base/lib-jitsi-meet/functions.web';
|
||||
import {
|
||||
appendURLParam,
|
||||
getBackendSafeRoomName,
|
||||
parseURIString
|
||||
parseURIString,
|
||||
parseURLParams
|
||||
} from '../base/util';
|
||||
import { isVpaasMeeting } from '../jaas/functions';
|
||||
import {
|
||||
@@ -93,7 +95,11 @@ export function appNavigate(uri: ?string) {
|
||||
let url = `${baseURL}config.js`;
|
||||
|
||||
// XXX In order to support multiple shards, tell the room to the deployment.
|
||||
room && (url += `?room=${getBackendSafeRoomName(room)}`);
|
||||
room && (url = appendURLParam(url, 'room', getBackendSafeRoomName(room)));
|
||||
|
||||
const { release } = parseURLParams(location, true, 'search');
|
||||
|
||||
release && (url = appendURLParam(url, 'release', release));
|
||||
|
||||
let config;
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Platform, StyleSheet, View } from 'react-native';
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
import { FullWindowOverlay } from 'react-native-screens';
|
||||
import SplashScreen from 'react-native-splash-screen';
|
||||
|
||||
import { DialogContainer } from '../../base/dialog';
|
||||
import BottomSheetContainer from '../../base/dialog/components/native/BottomSheetContainer';
|
||||
import { updateFlags } from '../../base/flags/actions';
|
||||
import { CALL_INTEGRATION_ENABLED, SERVER_URL_CHANGE_ENABLED } from '../../base/flags/constants';
|
||||
import { getFeatureFlag } from '../../base/flags/functions';
|
||||
import { Platform } from '../../base/react';
|
||||
import { DimensionsDetector, clientResized } from '../../base/responsive-ui';
|
||||
import { DimensionsDetector, clientResized, setSafeAreaInsets } from '../../base/responsive-ui';
|
||||
import { updateSettings } from '../../base/settings';
|
||||
import { _getRouteToRender } from '../getRouteToRender.native';
|
||||
import logger from '../logger';
|
||||
@@ -22,16 +23,16 @@ import '../reducers';
|
||||
|
||||
declare var __DEV__;
|
||||
|
||||
const DialogContainerWrapper = Platform.select({
|
||||
ios: FullWindowOverlay,
|
||||
default: View
|
||||
});
|
||||
|
||||
/**
|
||||
* The type of React {@code Component} props of {@link App}.
|
||||
*/
|
||||
type Props = AbstractAppProps & {
|
||||
|
||||
/**
|
||||
* An object of colors that override the default colors of the app/sdk.
|
||||
*/
|
||||
colorScheme: ?Object,
|
||||
|
||||
/**
|
||||
* Identifier for this app on the native side.
|
||||
*/
|
||||
@@ -76,6 +77,7 @@ export class App extends AbstractApp {
|
||||
|
||||
// Bind event handler so it is only bound once per instance.
|
||||
this._onDimensionsChanged = this._onDimensionsChanged.bind(this);
|
||||
this._onSafeAreaInsetsChanged = this._onSafeAreaInsetsChanged.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,13 +100,31 @@ export class App extends AbstractApp {
|
||||
*/
|
||||
async _extraInit() {
|
||||
const { dispatch, getState } = this.state.store;
|
||||
|
||||
// We set these early enough so then we avoid any unnecessary re-renders.
|
||||
dispatch(updateFlags(this.props.flags));
|
||||
|
||||
const route = await _getRouteToRender();
|
||||
|
||||
// We need the root navigator to be set early.
|
||||
await this._navigate(route);
|
||||
|
||||
// We set these early enough so then we avoid any unnecessary re-renders.
|
||||
dispatch(updateFlags(this.props.flags));
|
||||
// HACK ALERT!
|
||||
// Wait until the root navigator is ready.
|
||||
// We really need to break the inheritance relationship between App,
|
||||
// AbstractApp and BaseApp, it's very inflexible and cumbersome right now.
|
||||
const rootNavigationReady = new Promise(resolve => {
|
||||
const i = setInterval(() => {
|
||||
const { ready } = getState()['features/app'] || {};
|
||||
|
||||
if (ready) {
|
||||
clearInterval(i);
|
||||
resolve();
|
||||
}
|
||||
}, 50);
|
||||
});
|
||||
|
||||
await rootNavigationReady;
|
||||
|
||||
// Check if serverURL is configured externally and not allowed to change.
|
||||
const serverURLChangeEnabled = getFeatureFlag(getState(), SERVER_URL_CHANGE_ENABLED, true);
|
||||
@@ -138,10 +158,13 @@ export class App extends AbstractApp {
|
||||
*/
|
||||
_createMainElement(component, props) {
|
||||
return (
|
||||
<DimensionsDetector
|
||||
onDimensionsChanged = { this._onDimensionsChanged }>
|
||||
{ super._createMainElement(component, props) }
|
||||
</DimensionsDetector>
|
||||
<SafeAreaProvider>
|
||||
<DimensionsDetector
|
||||
onDimensionsChanged = { this._onDimensionsChanged }
|
||||
onSafeAreaInsetsChanged = { this._onSafeAreaInsetsChanged }>
|
||||
{ super._createMainElement(component, props) }
|
||||
</DimensionsDetector>
|
||||
</SafeAreaProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -198,6 +221,23 @@ export class App extends AbstractApp {
|
||||
dispatch(clientResized(width, height));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the safe are insets values.
|
||||
*
|
||||
* @param {Object} insets - The insets.
|
||||
* @param {number} insets.top - The top inset.
|
||||
* @param {number} insets.right - The right inset.
|
||||
* @param {number} insets.bottom - The bottom inset.
|
||||
* @param {number} insets.left - The left inset.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onSafeAreaInsetsChanged(insets) {
|
||||
const { dispatch } = this.state.store;
|
||||
|
||||
dispatch(setSafeAreaInsets(insets));
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the platform specific dialog container.
|
||||
*
|
||||
@@ -205,7 +245,12 @@ export class App extends AbstractApp {
|
||||
*/
|
||||
_renderDialogContainer() {
|
||||
return (
|
||||
<DialogContainer />
|
||||
<DialogContainerWrapper
|
||||
pointerEvents = 'box-none'
|
||||
style = { StyleSheet.absoluteFill }>
|
||||
<BottomSheetContainer />
|
||||
<DialogContainer />
|
||||
</DialogContainerWrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ import { toState } from '../base/redux';
|
||||
import { Conference } from '../conference';
|
||||
import { getDeepLinkingPage } from '../deep-linking';
|
||||
import { UnsupportedDesktopBrowser } from '../unsupported-browser';
|
||||
import { BlankPage, isWelcomePageUserEnabled, WelcomePage } from '../welcome';
|
||||
import { BlankPage, WelcomePage } from '../welcome';
|
||||
import { isWelcomePageEnabled } from '../welcome/functions';
|
||||
|
||||
/**
|
||||
* Determines which route is to be rendered in order to depict a specific Redux
|
||||
@@ -72,7 +73,7 @@ function _getWebConferenceRoute(state) {
|
||||
function _getWebWelcomePageRoute(state) {
|
||||
const route = _getEmptyRoute();
|
||||
|
||||
if (isWelcomePageUserEnabled(state)) {
|
||||
if (isWelcomePageEnabled(state)) {
|
||||
if (isSupportedBrowser()) {
|
||||
route.component = WelcomePage;
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import {
|
||||
createConnectionEvent,
|
||||
inIframe,
|
||||
sendAnalytics
|
||||
} from '../analytics';
|
||||
import { SET_ROOM } from '../base/conference';
|
||||
@@ -12,6 +11,7 @@ import {
|
||||
getURLWithoutParams
|
||||
} from '../base/connection';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import { inIframe } from '../base/util/iframeUtils';
|
||||
|
||||
import { reloadNow } from './actions';
|
||||
import { _getRouteToRender } from './getRouteToRender';
|
||||
|
||||
@@ -36,6 +36,7 @@ import '../large-video/middleware';
|
||||
import '../lobby/middleware';
|
||||
import '../notifications/middleware';
|
||||
import '../overlay/middleware';
|
||||
import '../participants-pane/middleware';
|
||||
import '../polls/middleware';
|
||||
import '../reactions/middleware';
|
||||
import '../recent-list/middleware';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import '../authentication/middleware';
|
||||
import '../dynamic-branding/middleware';
|
||||
import '../gifs/middleware';
|
||||
import '../mobile/audio-mode/middleware';
|
||||
import '../mobile/background/middleware';
|
||||
|
||||
22
react/features/app/reducer.native.js
Normal file
22
react/features/app/reducer.native.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { ReducerRegistry } from '../base/redux';
|
||||
import { _ROOT_NAVIGATION_READY } from '../mobile/navigation/actionTypes';
|
||||
|
||||
/**
|
||||
* Listen for actions which changes the state of the app feature.
|
||||
*
|
||||
* @param {Object} state - The Redux state of the feature features/app.
|
||||
* @param {Object} action - Action object.
|
||||
* @param {string} action.type - Type of action.
|
||||
* @returns {Object}
|
||||
*/
|
||||
ReducerRegistry.register('features/app', (state = {}, action) => {
|
||||
switch (action.type) {
|
||||
case _ROOT_NAVIGATION_READY:
|
||||
return {
|
||||
...state,
|
||||
ready: action.ready
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
});
|
||||
@@ -8,4 +8,6 @@ import '../mobile/full-screen/reducer';
|
||||
import '../mobile/watchos/reducer';
|
||||
import '../shared-video/reducer';
|
||||
|
||||
import './reducer.native';
|
||||
|
||||
import './reducers.any';
|
||||
|
||||
4
react/features/app/types.ts
Normal file
4
react/features/app/types.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface IStore {
|
||||
getState: Function,
|
||||
dispatch: Function
|
||||
}
|
||||
@@ -29,14 +29,11 @@ export function authenticateAndUpgradeRole(
|
||||
id: string,
|
||||
password: string,
|
||||
conference: Object) {
|
||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||
const { password: roomPassword }
|
||||
= getState()['features/base/conference'];
|
||||
return (dispatch: Dispatch<any>) => {
|
||||
const process
|
||||
= conference.authenticateAndUpgradeRole({
|
||||
id,
|
||||
password,
|
||||
roomPassword,
|
||||
|
||||
onLoginSuccessful() {
|
||||
// When the login succeeds, the process has completed half
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
/* @flow */
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import Dialog from 'react-native-dialog';
|
||||
import { connect as reduxConnect } from 'react-redux';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||
import { toJid } from '../../../base/connection';
|
||||
import { connect } from '../../../base/connection/actions.native';
|
||||
import { _abstractMapStateToProps } from '../../../base/dialog';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { JitsiConnectionErrors } from '../../../base/lib-jitsi-meet';
|
||||
import type { StyleType } from '../../../base/styles';
|
||||
import { authenticateAndUpgradeRole, cancelLogin } from '../../actions.native';
|
||||
|
||||
// Register styles.
|
||||
import './styles';
|
||||
|
||||
/**
|
||||
* The type of the React {@link Component} props of {@link LoginDialog}.
|
||||
*/
|
||||
@@ -44,22 +36,12 @@ type Props = {
|
||||
*/
|
||||
_error: Object,
|
||||
|
||||
/**
|
||||
* Extra handler for cancel functionality.
|
||||
*/
|
||||
_onCancel: Function,
|
||||
|
||||
/**
|
||||
* The progress in the floating range between 0 and 1 of the authenticating
|
||||
* and upgrading the role of the local participant/user.
|
||||
*/
|
||||
_progress: number,
|
||||
|
||||
/**
|
||||
* The color-schemed stylesheet of this feature.
|
||||
*/
|
||||
_styles: StyleType,
|
||||
|
||||
/**
|
||||
* Redux store dispatch method.
|
||||
*/
|
||||
@@ -68,12 +50,7 @@ type Props = {
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: Function,
|
||||
|
||||
/**
|
||||
* Override the default visibility.
|
||||
*/
|
||||
visible: boolean
|
||||
t: Function
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -120,10 +97,6 @@ type State = {
|
||||
* of the configuration parameters.
|
||||
*/
|
||||
class LoginDialog extends Component<Props, State> {
|
||||
static defaultProps = {
|
||||
visible: true
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes a new LoginDialog instance.
|
||||
*
|
||||
@@ -154,42 +127,40 @@ class LoginDialog extends Component<Props, State> {
|
||||
render() {
|
||||
const {
|
||||
_connecting: connecting,
|
||||
t,
|
||||
visible
|
||||
t
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Dialog.Container
|
||||
visible = { visible }>
|
||||
<Dialog.Title>
|
||||
{ t('dialog.login') }
|
||||
</Dialog.Title>
|
||||
<Dialog.Input
|
||||
autoCapitalize = { 'none' }
|
||||
autoCorrect = { false }
|
||||
onChangeText = { this._onUsernameChange }
|
||||
placeholder = { 'user@domain.com' }
|
||||
spellCheck = { false }
|
||||
value = { this.state.username } />
|
||||
<Dialog.Input
|
||||
autoCapitalize = { 'none' }
|
||||
onChangeText = { this._onPasswordChange }
|
||||
placeholder = { t('dialog.userPassword') }
|
||||
secureTextEntry = { true }
|
||||
value = { this.state.password } />
|
||||
<Dialog.Description>
|
||||
{ this._renderMessage() }
|
||||
</Dialog.Description>
|
||||
<Dialog.Button
|
||||
label = { t('dialog.Cancel') }
|
||||
onPress = { this._onCancel } />
|
||||
<Dialog.Button
|
||||
disabled = { connecting }
|
||||
label = { t('dialog.Ok') }
|
||||
onPress = { this._onLogin } />
|
||||
</Dialog.Container>
|
||||
</View>
|
||||
<Dialog.Container
|
||||
coverScreen = { false }
|
||||
visible = { true }>
|
||||
<Dialog.Title>
|
||||
{ t('dialog.login') }
|
||||
</Dialog.Title>
|
||||
<Dialog.Input
|
||||
autoCapitalize = { 'none' }
|
||||
autoCorrect = { false }
|
||||
onChangeText = { this._onUsernameChange }
|
||||
placeholder = { 'user@domain.com' }
|
||||
spellCheck = { false }
|
||||
value = { this.state.username } />
|
||||
<Dialog.Input
|
||||
autoCapitalize = { 'none' }
|
||||
onChangeText = { this._onPasswordChange }
|
||||
placeholder = { t('dialog.userPassword') }
|
||||
secureTextEntry = { true }
|
||||
value = { this.state.password } />
|
||||
<Dialog.Description>
|
||||
{ this._renderMessage() }
|
||||
</Dialog.Description>
|
||||
<Dialog.Button
|
||||
label = { t('dialog.Cancel') }
|
||||
onPress = { this._onCancel } />
|
||||
<Dialog.Button
|
||||
disabled = { connecting }
|
||||
label = { t('dialog.Ok') }
|
||||
onPress = { this._onLogin } />
|
||||
</Dialog.Container>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -204,12 +175,10 @@ class LoginDialog extends Component<Props, State> {
|
||||
_connecting: connecting,
|
||||
_error: error,
|
||||
_progress: progress,
|
||||
_styles: styles,
|
||||
t
|
||||
} = this.props;
|
||||
|
||||
let messageKey;
|
||||
let messageIsError = false;
|
||||
const messageOptions = {};
|
||||
|
||||
if (progress && progress < 1) {
|
||||
@@ -230,34 +199,22 @@ class LoginDialog extends Component<Props, State> {
|
||||
this.props._configHosts)
|
||||
&& credentials.password === this.state.password) {
|
||||
messageKey = 'dialog.incorrectPassword';
|
||||
messageIsError = true;
|
||||
}
|
||||
} else if (name) {
|
||||
messageKey = 'dialog.connectErrorWithMsg';
|
||||
messageOptions.msg = `${name} ${error.message}`;
|
||||
messageIsError = true;
|
||||
}
|
||||
} else if (connecting) {
|
||||
messageKey = 'connection.CONNECTING';
|
||||
}
|
||||
|
||||
if (messageKey) {
|
||||
const message = t(messageKey, messageOptions);
|
||||
const messageStyles
|
||||
= messageIsError ? styles.errorMessage : styles.progressMessage;
|
||||
|
||||
return (
|
||||
<Text style = { messageStyles }>
|
||||
{ message }
|
||||
</Text>
|
||||
);
|
||||
return t(messageKey, messageOptions);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
_onUsernameChange: (string) => void;
|
||||
|
||||
/**
|
||||
* Called when user edits the username.
|
||||
*
|
||||
@@ -271,8 +228,6 @@ class LoginDialog extends Component<Props, State> {
|
||||
});
|
||||
}
|
||||
|
||||
_onPasswordChange: (string) => void;
|
||||
|
||||
/**
|
||||
* Called when user edits the password.
|
||||
*
|
||||
@@ -286,8 +241,6 @@ class LoginDialog extends Component<Props, State> {
|
||||
});
|
||||
}
|
||||
|
||||
_onCancel: () => void;
|
||||
|
||||
/**
|
||||
* Notifies this LoginDialog that it has been dismissed by cancel.
|
||||
*
|
||||
@@ -295,14 +248,9 @@ class LoginDialog extends Component<Props, State> {
|
||||
* @returns {void}
|
||||
*/
|
||||
_onCancel() {
|
||||
const { _onCancel, dispatch } = this.props;
|
||||
|
||||
_onCancel && _onCancel();
|
||||
dispatch(cancelLogin());
|
||||
this.props.dispatch(cancelLogin());
|
||||
}
|
||||
|
||||
_onLogin: () => void;
|
||||
|
||||
/**
|
||||
* Notifies this LoginDialog that the login button (OK) has been pressed by
|
||||
* the user.
|
||||
@@ -355,8 +303,7 @@ function _mapStateToProps(state) {
|
||||
_configHosts: configHosts,
|
||||
_connecting: Boolean(connecting) || Boolean(thenableWithCancel),
|
||||
_error: connectionError || authenticateAndUpgradeRoleError,
|
||||
_progress: progress,
|
||||
_styles: ColorSchemeRegistry.get(state, 'LoginDialog')
|
||||
_progress: progress
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { ConfirmDialog } from '../../../base/dialog';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { cancelWaitForOwner } from '../../actions.native';
|
||||
|
||||
import LoginDialog from './LoginDialog';
|
||||
import { openLoginDialog, cancelWaitForOwner } from '../../actions.native';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link WaitForOwnerDialog}.
|
||||
@@ -42,14 +38,9 @@ class WaitForOwnerDialog extends Component<Props> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
showLoginDialog: false
|
||||
};
|
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._onCancel = this._onCancel.bind(this);
|
||||
this._onLogin = this._onLogin.bind(this);
|
||||
this._onLoginDialogCancel = this._onLoginDialogCancel.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,17 +56,10 @@ class WaitForOwnerDialog extends Component<Props> {
|
||||
confirmLabel = 'dialog.IamHost'
|
||||
descriptionKey = 'dialog.WaitForHostMsg'
|
||||
onCancel = { this._onCancel }
|
||||
onSubmit = { this._onLogin }>
|
||||
<LoginDialog
|
||||
// eslint-disable-next-line react/jsx-handler-names
|
||||
_onCancel = { this._onLoginDialogCancel }
|
||||
visible = { this.state.showLoginDialog } />
|
||||
</ConfirmDialog>
|
||||
onSubmit = { this._onLogin } />
|
||||
);
|
||||
}
|
||||
|
||||
_onCancel: () => void;
|
||||
|
||||
/**
|
||||
* Called when the cancel button is clicked.
|
||||
*
|
||||
@@ -86,8 +70,6 @@ class WaitForOwnerDialog extends Component<Props> {
|
||||
this.props.dispatch(cancelWaitForOwner());
|
||||
}
|
||||
|
||||
_onLogin: () => void;
|
||||
|
||||
/**
|
||||
* Called when the OK button is clicked.
|
||||
*
|
||||
@@ -95,17 +77,7 @@ class WaitForOwnerDialog extends Component<Props> {
|
||||
* @returns {void}
|
||||
*/
|
||||
_onLogin() {
|
||||
this.setState({ showLoginDialog: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the nested login dialog is cancelled.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onLoginDialogCancel() {
|
||||
this.setState({ showLoginDialog: false });
|
||||
this.props.dispatch(openLoginDialog());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import { ColorSchemeRegistry, schemeColor } from '../../../base/color-scheme';
|
||||
import { BoxModel } from '../../../base/styles';
|
||||
|
||||
/**
|
||||
* The styles of the authentication feature.
|
||||
*/
|
||||
ColorSchemeRegistry.register('LoginDialog', {
|
||||
|
||||
/**
|
||||
* The style of {@code Text} rendered by the {@code Dialog}s of the
|
||||
* feature authentication.
|
||||
*/
|
||||
dialogText: {
|
||||
margin: BoxModel.margin,
|
||||
marginTop: BoxModel.margin * 2
|
||||
},
|
||||
|
||||
/**
|
||||
* The style used when an error message is rendered.
|
||||
*/
|
||||
errorMessage: {
|
||||
color: schemeColor('errorText')
|
||||
},
|
||||
|
||||
/**
|
||||
* The style of {@code LoginDialog}.
|
||||
*/
|
||||
loginDialog: {
|
||||
flex: 0,
|
||||
flexDirection: 'column',
|
||||
marginBottom: BoxModel.margin,
|
||||
marginTop: BoxModel.margin
|
||||
},
|
||||
|
||||
/**
|
||||
* The style used then a progress message is rendered.
|
||||
*/
|
||||
progressMessage: {
|
||||
color: schemeColor('text')
|
||||
}
|
||||
});
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
JitsiConnectionErrors
|
||||
} from '../base/lib-jitsi-meet';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import { setPrejoinPageVisibility } from '../prejoin';
|
||||
|
||||
import {
|
||||
CANCEL_LOGIN,
|
||||
@@ -120,6 +121,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
&& error.name === JitsiConnectionErrors.PASSWORD_REQUIRED
|
||||
&& typeof error.recoverable === 'undefined') {
|
||||
error.recoverable = true;
|
||||
store.dispatch(setPrejoinPageVisibility(false));
|
||||
store.dispatch(openLoginDialog());
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -51,9 +51,10 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
dispatch(hideLoginDialog());
|
||||
|
||||
const { authRequired, conference } = getState()['features/base/conference'];
|
||||
const { passwordRequired } = getState()['features/base/connection'];
|
||||
|
||||
// Only end the meeting if we are not already inside and trying to upgrade.
|
||||
if (authRequired && !conference) {
|
||||
if ((authRequired && !conference) || passwordRequired) {
|
||||
dispatch(maybeRedirectToWelcomePage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ export const MEDIA_TYPE_TO_PENDING_STORE_KEY: {[key: MediaType]: string} = {
|
||||
[MEDIA_TYPE.VIDEO]: 'pendingVideo'
|
||||
};
|
||||
|
||||
export const ASKED_TO_UNMUTE_NOTIFICATION_ID = 'asked-to-unmute';
|
||||
export const ASKED_TO_UNMUTE_SOUND_ID = 'ASKED_TO_UNMUTE_SOUND';
|
||||
|
||||
export const AUDIO_MODERATION_NOTIFICATION_ID = 'audio-moderation';
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { MEDIA_TYPE, type MediaType } from '../base/media/constants';
|
||||
import { isLocalParticipantModerator } from '../base/participants/functions';
|
||||
import { isInBreakoutRoom } from '../breakout-rooms/functions';
|
||||
|
||||
import { MEDIA_TYPE_TO_WHITELIST_STORE_KEY, MEDIA_TYPE_TO_PENDING_STORE_KEY } from './constants';
|
||||
|
||||
@@ -49,7 +50,7 @@ export const isEnabled = (mediaType: MediaType) => (state: Object) => isEnabledF
|
||||
export const isSupported = () => (state: Object) => {
|
||||
const { conference } = state['features/base/conference'];
|
||||
|
||||
return conference ? conference.isAVModerationSupported() : false;
|
||||
return Boolean(!isInBreakoutRoom(state) && conference?.isAVModerationSupported());
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,7 +48,9 @@ import {
|
||||
participantRejected
|
||||
} from './actions';
|
||||
import {
|
||||
ASKED_TO_UNMUTE_SOUND_ID, AUDIO_MODERATION_NOTIFICATION_ID,
|
||||
ASKED_TO_UNMUTE_NOTIFICATION_ID,
|
||||
ASKED_TO_UNMUTE_SOUND_ID,
|
||||
AUDIO_MODERATION_NOTIFICATION_ID,
|
||||
CS_MODERATION_NOTIFICATION_ID,
|
||||
VIDEO_MODERATION_NOTIFICATION_ID
|
||||
} from './constants';
|
||||
@@ -78,6 +80,8 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
let descriptionKey;
|
||||
let titleKey;
|
||||
let uid;
|
||||
const localParticipant = getLocalParticipant(getState);
|
||||
const raisedHand = hasRaisedHand(localParticipant);
|
||||
|
||||
switch (action.mediaType) {
|
||||
case MEDIA_TYPE.AUDIO: {
|
||||
@@ -100,7 +104,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
dispatch(showNotification({
|
||||
customActionNameKey: [ 'notify.raiseHandAction' ],
|
||||
customActionHandler: [ () => batch(() => {
|
||||
dispatch(raiseHand(true));
|
||||
!raisedHand && dispatch(raiseHand(true));
|
||||
dispatch(hideNotification(uid));
|
||||
}) ],
|
||||
descriptionKey,
|
||||
@@ -222,7 +226,8 @@ StateListenerRegistry.register(
|
||||
titleKey: 'notify.hostAskedUnmute',
|
||||
sticky: true,
|
||||
customActionNameKey: [ 'notify.unmute' ],
|
||||
customActionHandler: [ () => dispatch(muteLocal(false, MEDIA_TYPE.AUDIO)) ]
|
||||
customActionHandler: [ () => dispatch(muteLocal(false, MEDIA_TYPE.AUDIO)) ],
|
||||
uid: ASKED_TO_UNMUTE_NOTIFICATION_ID
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
|
||||
dispatch(playSound(ASKED_TO_UNMUTE_SOUND_ID));
|
||||
}
|
||||
|
||||
@@ -29,11 +29,7 @@ export default {
|
||||
inviteButtonBackground: 'rgb(0, 119, 225)',
|
||||
onVideoText: 'white'
|
||||
},
|
||||
'Dialog': {
|
||||
border: 'rgba(0, 3, 6, 0.6)',
|
||||
buttonBackground: ColorPalette.blue,
|
||||
buttonLabel: ColorPalette.white
|
||||
},
|
||||
'Dialog': {},
|
||||
'Header': {
|
||||
background: ColorPalette.blue,
|
||||
icon: ColorPalette.white,
|
||||
@@ -41,10 +37,6 @@ export default {
|
||||
statusBarContent: ColorPalette.white,
|
||||
text: ColorPalette.white
|
||||
},
|
||||
'Modal': {},
|
||||
'LargeVideo': {
|
||||
background: '#040404'
|
||||
},
|
||||
'Toolbox': {
|
||||
button: 'rgb(255, 255, 255)',
|
||||
buttonToggled: 'rgb(38, 58, 76)',
|
||||
|
||||
@@ -206,6 +206,16 @@ export const SEND_TONES = 'SEND_TONES';
|
||||
*/
|
||||
export const SET_FOLLOW_ME = 'SET_FOLLOW_ME';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which sets the obfuscated room name.
|
||||
*
|
||||
* {
|
||||
* type: SET_OBFUSCATED_ROOM,
|
||||
* obfuscatedRoom: string
|
||||
* }
|
||||
*/
|
||||
export const SET_OBFUSCATED_ROOM = 'SET_OBFUSCATED_ROOM';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which updates the current known status of the
|
||||
* Mute Reactions Sound feature.
|
||||
|
||||
@@ -56,6 +56,7 @@ import {
|
||||
P2P_STATUS_CHANGED,
|
||||
SEND_TONES,
|
||||
SET_FOLLOW_ME,
|
||||
SET_OBFUSCATED_ROOM,
|
||||
SET_PASSWORD,
|
||||
SET_PASSWORD_FAILED,
|
||||
SET_ROOM,
|
||||
@@ -804,6 +805,24 @@ export function setPassword(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the obfuscated room name of the conference to be joined.
|
||||
*
|
||||
* @param {(string)} obfuscatedRoom - Obfuscated room name.
|
||||
* @param {(string)} obfuscatedRoomSource - The room name that was obfuscated.
|
||||
* @returns {{
|
||||
* type: SET_OBFUSCATED_ROOM,
|
||||
* room: string
|
||||
* }}
|
||||
*/
|
||||
export function setObfuscatedRoom(obfuscatedRoom: string, obfuscatedRoomSource: string) {
|
||||
return {
|
||||
type: SET_OBFUSCATED_ROOM,
|
||||
obfuscatedRoom,
|
||||
obfuscatedRoomSource
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (the name of) the room of the conference to be joined.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import { sha512_256 as sha512 } from 'js-sha512';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { getName } from '../../app/functions';
|
||||
@@ -19,6 +20,7 @@ import {
|
||||
safeDecodeURIComponent
|
||||
} from '../util';
|
||||
|
||||
import { setObfuscatedRoom } from './actions';
|
||||
import {
|
||||
AVATAR_URL_COMMAND,
|
||||
EMAIL_COMMAND,
|
||||
@@ -298,6 +300,47 @@ export function getRoomName(state: Object): string {
|
||||
return getConferenceState(state).room;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an obfuscated room name or create and persist it if it doesn't exists.
|
||||
*
|
||||
* @param {Object} state - The current state of the app.
|
||||
* @param {Function} dispatch - The Redux dispatch function.
|
||||
* @returns {string} - Obfuscated room name.
|
||||
*/
|
||||
export function getOrCreateObfuscatedRoomName(state: Object, dispatch: Function) {
|
||||
let { obfuscatedRoom } = getConferenceState(state);
|
||||
const { obfuscatedRoomSource } = getConferenceState(state);
|
||||
const room = getRoomName(state);
|
||||
|
||||
// On native mobile the store doesn't clear when joining a new conference so we might have the obfuscatedRoom
|
||||
// stored even though a different room was joined.
|
||||
// Check if the obfuscatedRoom was already computed for the current room.
|
||||
if (!obfuscatedRoom || (obfuscatedRoomSource !== room)) {
|
||||
obfuscatedRoom = sha512(room);
|
||||
dispatch(setObfuscatedRoom(obfuscatedRoom, room));
|
||||
}
|
||||
|
||||
return obfuscatedRoom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analytics may require an obfuscated room name, this functions decides based on a config if the normal or
|
||||
* obfuscated room name should be returned.
|
||||
*
|
||||
* @param {Object} state - The current state of the app.
|
||||
* @param {Function} dispatch - The Redux dispatch function.
|
||||
* @returns {string} - Analytics room name.
|
||||
*/
|
||||
export function getAnalyticsRoomName(state: Object, dispatch: Function) {
|
||||
const { analysis: { obfuscateRoomName = false } = {} } = state['features/base/config'];
|
||||
|
||||
if (obfuscateRoomName) {
|
||||
return getOrCreateObfuscatedRoomName(state, dispatch);
|
||||
}
|
||||
|
||||
return getRoomName(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result of getWiFiStats from the global NS or does nothing
|
||||
* (returns empty result).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import { setPictureInPictureDisabled } from '../../mobile/picture-in-picture/functions';
|
||||
import { setPictureInPictureEnabled } from '../../mobile/picture-in-picture/functions';
|
||||
import { setAudioOnly } from '../audio-only';
|
||||
import JitsiMeetJS from '../lib-jitsi-meet';
|
||||
import { MiddlewareRegistry } from '../redux';
|
||||
@@ -41,7 +41,7 @@ function _toggleScreenSharing(enabled, store) {
|
||||
}
|
||||
} else {
|
||||
dispatch(destroyLocalDesktopTrackIfExists());
|
||||
setPictureInPictureDisabled(false);
|
||||
setPictureInPictureEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ function _toggleScreenSharing(enabled, store) {
|
||||
* @returns {void}
|
||||
*/
|
||||
function _startScreenSharing(dispatch, state) {
|
||||
setPictureInPictureDisabled(true);
|
||||
setPictureInPictureEnabled(false);
|
||||
|
||||
JitsiMeetJS.createLocalTracks({ devices: [ 'desktop' ] })
|
||||
.then(tracks => {
|
||||
@@ -73,6 +73,6 @@ function _startScreenSharing(dispatch, state) {
|
||||
.catch(error => {
|
||||
console.log('ERROR creating ScreeSharing stream ', error);
|
||||
|
||||
setPictureInPictureDisabled(false);
|
||||
setPictureInPictureEnabled(true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -44,9 +44,14 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
break;
|
||||
}
|
||||
case CONFERENCE_FAILED: {
|
||||
enableForcedReload
|
||||
&& action.error?.name === JitsiConferenceErrors.CONFERENCE_RESTARTED
|
||||
&& dispatch(setSkipPrejoinOnReload(true));
|
||||
const errorName = action.error?.name;
|
||||
|
||||
if (errorName === JitsiConferenceErrors.MEMBERS_ONLY_ERROR
|
||||
|| errorName === JitsiConferenceErrors.PASSWORD_REQUIRED) {
|
||||
dispatch(setPrejoinPageVisibility(false));
|
||||
} else if (enableForcedReload && errorName === JitsiConferenceErrors.CONFERENCE_RESTARTED) {
|
||||
dispatch(setSkipPrejoinOnReload(true));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
LOCK_STATE_CHANGED,
|
||||
P2P_STATUS_CHANGED,
|
||||
SET_FOLLOW_ME,
|
||||
SET_OBFUSCATED_ROOM,
|
||||
SET_PASSWORD,
|
||||
SET_PENDING_SUBJECT_CHANGE,
|
||||
SET_ROOM,
|
||||
@@ -88,6 +89,12 @@ ReducerRegistry.register(
|
||||
case SET_LOCATION_URL:
|
||||
return set(state, 'room', undefined);
|
||||
|
||||
case SET_OBFUSCATED_ROOM:
|
||||
return { ...state,
|
||||
obfuscatedRoom: action.obfuscatedRoom,
|
||||
obfuscatedRoomSource: action.obfuscatedRoomSource
|
||||
};
|
||||
|
||||
case SET_PASSWORD:
|
||||
return _setPassword(state, action);
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ export default [
|
||||
'debugAudioLevels',
|
||||
'defaultLocalDisplayName',
|
||||
'defaultRemoteDisplayName',
|
||||
'deploymentUrls',
|
||||
'desktopSharingFrameRate',
|
||||
'desktopSharingSources',
|
||||
'disable1On1Mode',
|
||||
@@ -94,6 +95,7 @@ export default [
|
||||
'disableBeforeUnloadHandlers',
|
||||
'disableChatSmileys',
|
||||
'disableDeepLinking',
|
||||
'disabledNotifications',
|
||||
'disabledSounds',
|
||||
'disableFilmstripAutohiding',
|
||||
'disableInitialGUM',
|
||||
@@ -163,6 +165,7 @@ export default [
|
||||
'gatherStats',
|
||||
'giphy',
|
||||
'googleApiApplicationClientID',
|
||||
'gravatar.disabled',
|
||||
'hiddenPremeetingButtons',
|
||||
'hideConferenceSubject',
|
||||
'hideDisplayName',
|
||||
@@ -190,6 +193,7 @@ export default [
|
||||
'openSharedDocumentOnJoin',
|
||||
'opusMaxAverageBitrate',
|
||||
'p2p',
|
||||
'participantsPane',
|
||||
'pcStatsInterval',
|
||||
'preferH264',
|
||||
'preferredCodec',
|
||||
|
||||
71
react/features/base/connection/actions.any.js
Normal file
71
react/features/base/connection/actions.any.js
Normal file
@@ -0,0 +1,71 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
import {
|
||||
appendURLParam,
|
||||
getBackendSafeRoomName,
|
||||
parseURIString
|
||||
} from '../util';
|
||||
|
||||
import logger from './logger';
|
||||
|
||||
/**
|
||||
* Constructs options to be passed to the constructor of {@code JitsiConnection}
|
||||
* based on the redux state.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {Object} The options to be passed to the constructor of
|
||||
* {@code JitsiConnection}.
|
||||
*/
|
||||
export function constructOptions(state) {
|
||||
// Deep clone the options to make sure we don't modify the object in the
|
||||
// redux store.
|
||||
const options = _.cloneDeep(state['features/base/config']);
|
||||
|
||||
let { bosh, websocket } = options;
|
||||
|
||||
// TESTING: Only enable WebSocket for some percentage of users.
|
||||
if (websocket && navigator.product === 'ReactNative') {
|
||||
if ((Math.random() * 100) >= (options?.testing?.mobileXmppWsThreshold ?? 0)) {
|
||||
websocket = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize the BOSH URL.
|
||||
if (bosh && !websocket) {
|
||||
const { locationURL } = state['features/base/connection'];
|
||||
|
||||
if (bosh.startsWith('//')) {
|
||||
// By default our config.js doesn't include the protocol.
|
||||
bosh = `${locationURL.protocol}${bosh}`;
|
||||
} else if (bosh.startsWith('/')) {
|
||||
// Handle relative URLs, which won't work on mobile.
|
||||
const {
|
||||
protocol,
|
||||
host,
|
||||
contextRoot
|
||||
} = parseURIString(locationURL.href);
|
||||
|
||||
bosh = `${protocol}//${host}${contextRoot || '/'}${bosh.substr(1)}`;
|
||||
}
|
||||
}
|
||||
|
||||
// WebSocket is preferred over BOSH.
|
||||
const serviceUrl = websocket || bosh;
|
||||
|
||||
logger.log(`Using service URL ${serviceUrl}`);
|
||||
|
||||
// Append room to the URL's search.
|
||||
const { room } = state['features/base/conference'];
|
||||
|
||||
if (serviceUrl && room) {
|
||||
const roomName = getBackendSafeRoomName(room);
|
||||
|
||||
options.serviceUrl = appendURLParam(serviceUrl, 'room', roomName);
|
||||
|
||||
if (options.websocketKeepAliveUrl) {
|
||||
options.websocketKeepAliveUrl = appendURLParam(options.websocketKeepAliveUrl, 'room', roomName);
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
@@ -1,15 +1,10 @@
|
||||
// @flow
|
||||
|
||||
import _ from 'lodash';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { conferenceLeft, conferenceWillLeave } from '../conference/actions';
|
||||
import { getCurrentConference } from '../conference/functions';
|
||||
import JitsiMeetJS, { JitsiConnectionEvents } from '../lib-jitsi-meet';
|
||||
import {
|
||||
getBackendSafeRoomName,
|
||||
parseURIString
|
||||
} from '../util';
|
||||
|
||||
import {
|
||||
CONNECTION_DISCONNECTED,
|
||||
@@ -18,9 +13,12 @@ import {
|
||||
CONNECTION_WILL_CONNECT,
|
||||
SET_LOCATION_URL
|
||||
} from './actionTypes';
|
||||
import { constructOptions } from './actions.any';
|
||||
import { JITSI_CONNECTION_URL_KEY } from './constants';
|
||||
import logger from './logger';
|
||||
|
||||
export * from './actions.any';
|
||||
|
||||
/**
|
||||
* The error structure passed to the {@link connectionFailed} action.
|
||||
*
|
||||
@@ -78,7 +76,7 @@ export type ConnectionFailedError = {
|
||||
export function connect(id: ?string, password: ?string) {
|
||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||
const state = getState();
|
||||
const options = _constructOptions(state);
|
||||
const options = constructOptions(state);
|
||||
const { locationURL } = state['features/base/connection'];
|
||||
const { jwt } = state['features/base/jwt'];
|
||||
const connection = new JitsiMeetJS.JitsiConnection(options.appId, jwt, options);
|
||||
@@ -262,69 +260,6 @@ function _connectionWillConnect(connection) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs options to be passed to the constructor of {@code JitsiConnection}
|
||||
* based on the redux state.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {Object} The options to be passed to the constructor of
|
||||
* {@code JitsiConnection}.
|
||||
*/
|
||||
function _constructOptions(state) {
|
||||
// Deep clone the options to make sure we don't modify the object in the
|
||||
// redux store.
|
||||
const options = _.cloneDeep(state['features/base/config']);
|
||||
|
||||
let { bosh, websocket } = options;
|
||||
|
||||
// TESTING: Only enable WebSocket for some percentage of users.
|
||||
if (websocket) {
|
||||
if ((Math.random() * 100) >= (options?.testing?.mobileXmppWsThreshold ?? 0)) {
|
||||
websocket = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize the BOSH URL.
|
||||
if (bosh && !websocket) {
|
||||
const { locationURL } = state['features/base/connection'];
|
||||
|
||||
if (bosh.startsWith('//')) {
|
||||
// By default our config.js doesn't include the protocol.
|
||||
bosh = `${locationURL.protocol}${bosh}`;
|
||||
} else if (bosh.startsWith('/')) {
|
||||
// Handle relative URLs, which won't work on mobile.
|
||||
const {
|
||||
protocol,
|
||||
host,
|
||||
contextRoot
|
||||
} = parseURIString(locationURL.href);
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
bosh = `${protocol}//${host}${contextRoot || '/'}${bosh.substr(1)}`;
|
||||
}
|
||||
}
|
||||
|
||||
// WebSocket is preferred over BOSH.
|
||||
const serviceUrl = websocket || bosh;
|
||||
|
||||
logger.log(`Using service URL ${serviceUrl}`);
|
||||
|
||||
// Append room to the URL's search.
|
||||
const { room } = state['features/base/conference'];
|
||||
|
||||
if (serviceUrl && room) {
|
||||
const roomName = getBackendSafeRoomName(room);
|
||||
|
||||
options.serviceUrl = `${serviceUrl}?room=${roomName}`;
|
||||
|
||||
if (options.websocketKeepAliveUrl) {
|
||||
options.websocketKeepAliveUrl += `?room=${roomName}`;
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes connection.
|
||||
*
|
||||
|
||||
@@ -16,6 +16,8 @@ export {
|
||||
} from './actions.native';
|
||||
import logger from './logger';
|
||||
|
||||
export * from './actions.any';
|
||||
|
||||
/**
|
||||
* Opens new connection.
|
||||
*
|
||||
|
||||
@@ -7,6 +7,15 @@
|
||||
*/
|
||||
export const HIDE_DIALOG = 'HIDE_DIALOG';
|
||||
|
||||
/**
|
||||
* The type of Redux action which closes a sheet.
|
||||
*
|
||||
* {
|
||||
* type: HIDE_SHEET
|
||||
* }
|
||||
*/
|
||||
export const HIDE_SHEET = 'HIDE_SHEET';
|
||||
|
||||
/**
|
||||
* The type of Redux action which begins a request to open a dialog.
|
||||
*
|
||||
@@ -18,3 +27,15 @@ export const HIDE_DIALOG = 'HIDE_DIALOG';
|
||||
*
|
||||
*/
|
||||
export const OPEN_DIALOG = 'OPEN_DIALOG';
|
||||
|
||||
/**
|
||||
* The type of Redux action which begins a request to open a sheet.
|
||||
*
|
||||
* {
|
||||
* type: OPEN_SHEET,
|
||||
* component: React.Component,
|
||||
* props: PropTypes
|
||||
* }
|
||||
*
|
||||
*/
|
||||
export const OPEN_SHEET = 'OPEN_SHEET';
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { HIDE_DIALOG, OPEN_DIALOG } from './actionTypes';
|
||||
import {
|
||||
HIDE_DIALOG,
|
||||
HIDE_SHEET,
|
||||
OPEN_DIALOG,
|
||||
OPEN_SHEET
|
||||
} from './actionTypes';
|
||||
import { isDialogOpen } from './functions';
|
||||
|
||||
/**
|
||||
@@ -24,6 +29,19 @@ export function hideDialog(component: ?Object) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the active sheet.
|
||||
*
|
||||
* @returns {{
|
||||
* type: HIDE_SHEET,
|
||||
* }}
|
||||
*/
|
||||
export function hideSheet() {
|
||||
return {
|
||||
type: HIDE_SHEET
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals Dialog to open dialog.
|
||||
*
|
||||
@@ -44,6 +62,26 @@ export function openDialog(component: Object, componentProps: ?Object) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the requested sheet.
|
||||
*
|
||||
* @param {Object} component - The component to display as a sheet.
|
||||
* @param {Object} [componentProps] - The React {@code Component} props of the
|
||||
* specified {@code component}.
|
||||
* @returns {{
|
||||
* type: OPEN_SHEET,
|
||||
* component: React.Component,
|
||||
* componentProps: (Object | undefined)
|
||||
* }}
|
||||
*/
|
||||
export function openSheet(component: Object, componentProps: ?Object) {
|
||||
return {
|
||||
type: OPEN_SHEET,
|
||||
component,
|
||||
componentProps
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals Dialog to open a dialog with the specified component if the component
|
||||
* is not already open. If it is open, then Dialog is signaled to close its
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import Dialog from 'react-native-dialog';
|
||||
|
||||
import { translate } from '../../../i18n';
|
||||
@@ -46,16 +43,16 @@ class AlertDialog extends AbstractDialog<Props> {
|
||||
: renderHTML(t(contentKey.key, contentKey.params));
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Dialog.Container visible = { true }>
|
||||
<Dialog.Description>
|
||||
{ content }
|
||||
</Dialog.Description>
|
||||
<Dialog.Button
|
||||
label = { t('dialog.Ok') }
|
||||
onPress = { this._onSubmit } />
|
||||
</Dialog.Container>
|
||||
</View>
|
||||
<Dialog.Container
|
||||
coverScreen = { false }
|
||||
visible = { true }>
|
||||
<Dialog.Description>
|
||||
{ content }
|
||||
</Dialog.Description>
|
||||
<Dialog.Button
|
||||
label = { t('dialog.Ok') }
|
||||
onPress = { this._onSubmit } />
|
||||
</Dialog.Container>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +1,17 @@
|
||||
// @flow
|
||||
|
||||
import React, { PureComponent, type Node } from 'react';
|
||||
import { PanResponder, SafeAreaView, ScrollView, View } from 'react-native';
|
||||
import { SafeAreaView, ScrollView, View } from 'react-native';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../color-scheme';
|
||||
import { SlidingView } from '../../../react';
|
||||
import { connect } from '../../../redux';
|
||||
import { StyleType } from '../../../styles';
|
||||
import { hideSheet } from '../../actions';
|
||||
|
||||
import { bottomSheetStyles as styles } from './styles';
|
||||
|
||||
/**
|
||||
* Minimal distance that needs to be moved by the finger to consider it a swipe.
|
||||
*/
|
||||
const GESTURE_DISTANCE_THRESHOLD = 5;
|
||||
|
||||
/**
|
||||
* The minimal speed needed to be achieved by the finger to consider it as a swipe.
|
||||
*/
|
||||
const GESTURE_SPEED_THRESHOLD = 0.2;
|
||||
|
||||
/**
|
||||
* The type of {@code BottomSheet}'s React {@code Component} prop types.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The height of the screen.
|
||||
*/
|
||||
_height: number,
|
||||
|
||||
/**
|
||||
* The color-schemed stylesheet of the feature.
|
||||
*/
|
||||
_styles: StyleType,
|
||||
|
||||
/**
|
||||
* Whether to add padding to scroll view.
|
||||
*/
|
||||
@@ -45,17 +22,17 @@ type Props = {
|
||||
*/
|
||||
children: Node,
|
||||
|
||||
/**
|
||||
* Redux Dispatch function.
|
||||
*/
|
||||
dispatch: Function,
|
||||
|
||||
/**
|
||||
* Handler for the cancel event, which happens when the user dismisses
|
||||
* the sheet.
|
||||
*/
|
||||
onCancel: ?Function,
|
||||
|
||||
/**
|
||||
* Callback to be attached to the custom swipe event of the BottomSheet.
|
||||
*/
|
||||
onSwipe?: Function,
|
||||
|
||||
/**
|
||||
* Function to render a bottom sheet header element, if necessary.
|
||||
*/
|
||||
@@ -81,8 +58,6 @@ type Props = {
|
||||
* A component emulating Android's BottomSheet.
|
||||
*/
|
||||
class BottomSheet extends PureComponent<Props> {
|
||||
panResponder: Object;
|
||||
|
||||
/**
|
||||
* Default values for {@code BottomSheet} component's properties.
|
||||
*
|
||||
@@ -94,18 +69,28 @@ class BottomSheet extends PureComponent<Props> {
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiates a new component.
|
||||
* Initializes a new instance.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @param {Props} props - The React {@code Component} props to initialize
|
||||
* the new instance with.
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.panResponder = PanResponder.create({
|
||||
onStartShouldSetPanResponder: this._onShouldSetResponder.bind(this),
|
||||
onMoveShouldSetPanResponder: this._onShouldSetResponder.bind(this),
|
||||
onPanResponderRelease: this._onGestureEnd.bind(this)
|
||||
});
|
||||
this._onCancel = this._onCancel.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the cancel event, when the user dismissed the sheet. By default we close it.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_onCancel() {
|
||||
if (this.props.onCancel) {
|
||||
this.props.onCancel();
|
||||
} else {
|
||||
this.props.dispatch(hideSheet());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,8 +101,6 @@ class BottomSheet extends PureComponent<Props> {
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
_height,
|
||||
_styles,
|
||||
addScrollViewPadding,
|
||||
renderHeader,
|
||||
renderFooter,
|
||||
@@ -129,7 +112,7 @@ class BottomSheet extends PureComponent<Props> {
|
||||
<SlidingView
|
||||
accessibilityRole = 'menu'
|
||||
accessibilityViewIsModal = { true }
|
||||
onHide = { this.props.onCancel }
|
||||
onHide = { this._onCancel }
|
||||
position = 'bottom'
|
||||
show = { showSlidingView }>
|
||||
<View
|
||||
@@ -143,20 +126,16 @@ class BottomSheet extends PureComponent<Props> {
|
||||
style = { [
|
||||
styles.sheetItemContainer,
|
||||
renderHeader
|
||||
? _styles.sheetHeader
|
||||
: _styles.sheet,
|
||||
renderFooter && _styles.sheetFooter,
|
||||
style,
|
||||
{
|
||||
maxHeight: _height - 100
|
||||
}
|
||||
] }
|
||||
{ ...this.panResponder.panHandlers }>
|
||||
? styles.sheetHeader
|
||||
: styles.sheet,
|
||||
renderFooter && styles.sheetFooter,
|
||||
style
|
||||
] }>
|
||||
<ScrollView
|
||||
bounces = { false }
|
||||
showsVerticalScrollIndicator = { false }
|
||||
style = { [
|
||||
renderFooter && _styles.sheet,
|
||||
renderFooter && styles.sheet,
|
||||
addScrollViewPadding && styles.scrollView
|
||||
] } >
|
||||
{ this.props.children }
|
||||
@@ -167,63 +146,6 @@ class BottomSheet extends PureComponent<Props> {
|
||||
</SlidingView>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to handle a gesture end event.
|
||||
*
|
||||
* @param {Object} evt - The native gesture event.
|
||||
* @param {Object} gestureState - The gesture state.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onGestureEnd(evt, gestureState) {
|
||||
const verticalSwipe = Math.abs(gestureState.vy) > Math.abs(gestureState.vx)
|
||||
&& Math.abs(gestureState.vy) > GESTURE_SPEED_THRESHOLD;
|
||||
|
||||
if (verticalSwipe) {
|
||||
const direction = gestureState.vy > 0 ? 'down' : 'up';
|
||||
const { onCancel, onSwipe } = this.props;
|
||||
let isSwipeHandled = false;
|
||||
|
||||
if (onSwipe) {
|
||||
isSwipeHandled = onSwipe(direction);
|
||||
}
|
||||
|
||||
if (direction === 'down' && !isSwipeHandled) {
|
||||
// Swipe down is a special gesture that can be used to close the
|
||||
// BottomSheet, so if the swipe is not handled by the parent
|
||||
// component, we consider it as a request to close.
|
||||
onCancel && onCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the pan responder should activate, false otherwise.
|
||||
*
|
||||
* @param {Object} evt - The native gesture event.
|
||||
* @param {Object} gestureState - The gesture state.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_onShouldSetResponder({ nativeEvent }, gestureState) {
|
||||
return nativeEvent.touches.length === 1
|
||||
&& Math.abs(gestureState.dx) > GESTURE_DISTANCE_THRESHOLD
|
||||
&& Math.abs(gestureState.dy) > GESTURE_DISTANCE_THRESHOLD;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps part of the Redux state to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {{
|
||||
* _styles: StyleType
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
return {
|
||||
_styles: ColorSchemeRegistry.get(state, 'BottomSheet'),
|
||||
_height: state['features/base/responsive-ui'].clientHeight
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(BottomSheet);
|
||||
export default connect()(BottomSheet);
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
|
||||
const BottomSheetContainer: () => JSX.Element = () => {
|
||||
const { sheet, sheetProps } = useSelector(state => state['features/base/dialog']);
|
||||
const { reducedUI } = useSelector(state => state['features/base/responsive-ui']);
|
||||
|
||||
if (!sheet || reducedUI) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{ React.createElement(sheet, sheetProps) }
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default BottomSheetContainer;
|
||||
@@ -1,7 +1,4 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import Dialog from 'react-native-dialog';
|
||||
|
||||
import { translate } from '../../../i18n';
|
||||
@@ -26,7 +23,7 @@ type Props = {
|
||||
/**
|
||||
* The React {@code Component} children.
|
||||
*/
|
||||
children?: React$Node,
|
||||
children?: Node,
|
||||
|
||||
/**
|
||||
* The i18n key of the text label for the confirm button.
|
||||
@@ -111,25 +108,25 @@ class ConfirmDialog extends AbstractDialog<Props> {
|
||||
? styles.destructiveDialogButton : styles.dialogButton;
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Dialog.Container visible = { true }>
|
||||
{
|
||||
title && <Dialog.Title>
|
||||
{ t(title) }
|
||||
</Dialog.Title>
|
||||
}
|
||||
{ this._renderDescription() }
|
||||
{ children }
|
||||
<Dialog.Button
|
||||
label = { t(cancelLabel || 'dialog.confirmNo') }
|
||||
onPress = { this._onCancel }
|
||||
style = { styles.dialogButton } />
|
||||
<Dialog.Button
|
||||
label = { t(confirmLabel || 'dialog.confirmYes') }
|
||||
onPress = { this._onSubmit }
|
||||
style = { dialogButtonStyle } />
|
||||
</Dialog.Container>
|
||||
</View>
|
||||
<Dialog.Container
|
||||
coverScreen = { false }
|
||||
visible = { true }>
|
||||
{
|
||||
title && <Dialog.Title>
|
||||
{ t(title) }
|
||||
</Dialog.Title>
|
||||
}
|
||||
{ this._renderDescription() }
|
||||
{ children }
|
||||
<Dialog.Button
|
||||
label = { t(cancelLabel || 'dialog.confirmNo') }
|
||||
onPress = { this._onCancel }
|
||||
style = { styles.dialogButton } />
|
||||
<Dialog.Button
|
||||
label = { t(confirmLabel || 'dialog.confirmYes') }
|
||||
onPress = { this._onSubmit }
|
||||
style = { dialogButtonStyle } />
|
||||
</Dialog.Container>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
import { ReactionEmoji } from '../../../../reactions/components';
|
||||
import { getReactionsQueue } from '../../../../reactions/functions.any';
|
||||
@@ -38,10 +38,12 @@ class DialogContainer extends AbstractDialogContainer {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
return (<React.Fragment>
|
||||
{this._renderReactions()}
|
||||
{this._renderDialogContent()}
|
||||
</React.Fragment>);
|
||||
return (
|
||||
<Fragment>
|
||||
{this._renderReactions()}
|
||||
{this._renderDialogContent()}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import Dialog from 'react-native-dialog';
|
||||
|
||||
import { translate } from '../../../i18n';
|
||||
@@ -95,40 +92,39 @@ class InputDialog<P: Props, S: State> extends AbstractDialog<P, S> {
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Dialog.Container
|
||||
visible = { true }>
|
||||
<Dialog.Title>
|
||||
{ t(titleKey) }
|
||||
</Dialog.Title>
|
||||
{
|
||||
descriptionKey && (
|
||||
<Dialog.Description>
|
||||
{ t(descriptionKey) }
|
||||
</Dialog.Description>
|
||||
)
|
||||
}
|
||||
<Dialog.Input
|
||||
autoFocus = { true }
|
||||
onChangeText = { this._onChangeText }
|
||||
value = { this.state.fieldValue }
|
||||
{ ...this.props.textInputProps } />
|
||||
{
|
||||
messageKey && (
|
||||
<Dialog.Description
|
||||
style = { styles.formMessage }>
|
||||
{ t(messageKey) }
|
||||
</Dialog.Description>
|
||||
)
|
||||
}
|
||||
<Dialog.Button
|
||||
label = { t('dialog.Cancel') }
|
||||
onPress = { this._onCancel } />
|
||||
<Dialog.Button
|
||||
label = { t('dialog.Ok') }
|
||||
onPress = { this._onSubmitValue } />
|
||||
</Dialog.Container>
|
||||
</View>
|
||||
<Dialog.Container
|
||||
coverScreen = { false }
|
||||
visible = { true }>
|
||||
<Dialog.Title>
|
||||
{ t(titleKey) }
|
||||
</Dialog.Title>
|
||||
{
|
||||
descriptionKey && (
|
||||
<Dialog.Description>
|
||||
{ t(descriptionKey) }
|
||||
</Dialog.Description>
|
||||
)
|
||||
}
|
||||
<Dialog.Input
|
||||
autoFocus = { true }
|
||||
onChangeText = { this._onChangeText }
|
||||
value = { this.state.fieldValue }
|
||||
{ ...this.props.textInputProps } />
|
||||
{
|
||||
messageKey && (
|
||||
<Dialog.Description
|
||||
style = { styles.formMessage }>
|
||||
{ t(messageKey) }
|
||||
</Dialog.Description>
|
||||
)
|
||||
}
|
||||
<Dialog.Button
|
||||
label = { t('dialog.Cancel') }
|
||||
onPress = { this._onCancel } />
|
||||
<Dialog.Button
|
||||
label = { t('dialog.Ok') }
|
||||
onPress = { this._onSubmitValue } />
|
||||
</Dialog.Container>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
import BaseTheme from '../../../../base/ui/components/BaseTheme.native';
|
||||
@@ -20,85 +18,6 @@ export const MD_FONT_SIZE = 16;
|
||||
export const MD_ITEM_HEIGHT = 48;
|
||||
export const MD_ITEM_MARGIN_PADDING = 16;
|
||||
|
||||
/**
|
||||
* The React {@code Component} styles of {@code BottomSheet}. These have
|
||||
* been implemented as per the Material Design guidelines:
|
||||
* {@link https://material.io/guidelines/components/bottom-sheets.html}.
|
||||
*/
|
||||
export const bottomSheetStyles = {
|
||||
sheetAreaCover: {
|
||||
backgroundColor: ColorPalette.transparent,
|
||||
flex: 1
|
||||
},
|
||||
|
||||
scrollView: {
|
||||
paddingHorizontal: 0
|
||||
},
|
||||
|
||||
/**
|
||||
* Style for the container of the sheet.
|
||||
*/
|
||||
sheetContainer: {
|
||||
alignItems: 'stretch',
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'flex-end',
|
||||
maxWidth: 500,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
width: '100%'
|
||||
},
|
||||
|
||||
sheetItemContainer: {
|
||||
flex: -1
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
dialogButton: {
|
||||
...BaseTheme.typography.labelButton
|
||||
},
|
||||
|
||||
destructiveDialogButton: {
|
||||
...BaseTheme.typography.labelButton,
|
||||
color: BaseTheme.palette.actionDanger
|
||||
}
|
||||
};
|
||||
|
||||
export const brandedDialog = {
|
||||
|
||||
/**
|
||||
* The style of bold {@code Text} rendered by the {@code Dialog}s of the
|
||||
* feature authentication.
|
||||
*/
|
||||
boldDialogText: {
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
|
||||
buttonFarRight: {
|
||||
borderBottomRightRadius: BORDER_RADIUS
|
||||
},
|
||||
|
||||
buttonWrapper: {
|
||||
alignItems: 'stretch',
|
||||
borderRadius: BORDER_RADIUS,
|
||||
flexDirection: 'row'
|
||||
},
|
||||
|
||||
mainWrapper: {
|
||||
alignSelf: 'stretch',
|
||||
padding: BoxModel.padding * 2,
|
||||
|
||||
// The added bottom padding is to compensate the empty space around the
|
||||
// close icon.
|
||||
paddingBottom: BoxModel.padding * 3
|
||||
},
|
||||
|
||||
overlayTouchable: {
|
||||
...StyleSheet.absoluteFillObject
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reusable (colored) style for text in any branded dialogs.
|
||||
*/
|
||||
@@ -136,12 +55,39 @@ export const inputDialog = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Default styles for the items of a {@code BottomSheet}-based menu.
|
||||
*
|
||||
* These have been implemented as per the Material Design guidelines:
|
||||
* The React {@code Component} styles of {@code BottomSheet}. These have
|
||||
* been implemented as per the Material Design guidelines:
|
||||
* {@link https://material.io/guidelines/components/bottom-sheets.html}.
|
||||
*/
|
||||
ColorSchemeRegistry.register('BottomSheet', {
|
||||
export const bottomSheetStyles = {
|
||||
sheetAreaCover: {
|
||||
backgroundColor: ColorPalette.transparent,
|
||||
flex: 1
|
||||
},
|
||||
|
||||
scrollView: {
|
||||
paddingHorizontal: 0
|
||||
},
|
||||
|
||||
/**
|
||||
* Style for the container of the sheet.
|
||||
*/
|
||||
sheetContainer: {
|
||||
alignItems: 'stretch',
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'flex-end',
|
||||
maxWidth: 500,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
width: '100%'
|
||||
},
|
||||
|
||||
sheetItemContainer: {
|
||||
flex: -1,
|
||||
maxHeight: '75%'
|
||||
},
|
||||
|
||||
buttons: {
|
||||
/**
|
||||
* Style for the {@code Icon} element in a generic item of the menu.
|
||||
@@ -194,7 +140,53 @@ ColorSchemeRegistry.register('BottomSheet', {
|
||||
sheetFooter: {
|
||||
backgroundColor: BaseTheme.palette.bottomSheet
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export default {
|
||||
dialogButton: {
|
||||
...BaseTheme.typography.labelButton
|
||||
},
|
||||
|
||||
destructiveDialogButton: {
|
||||
...BaseTheme.typography.labelButton,
|
||||
color: BaseTheme.palette.actionDanger
|
||||
}
|
||||
};
|
||||
|
||||
export const brandedDialog = {
|
||||
|
||||
/**
|
||||
* The style of bold {@code Text} rendered by the {@code Dialog}s of the
|
||||
* feature authentication.
|
||||
*/
|
||||
boldDialogText: {
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
|
||||
buttonFarRight: {
|
||||
borderBottomRightRadius: BORDER_RADIUS
|
||||
},
|
||||
|
||||
buttonWrapper: {
|
||||
alignItems: 'stretch',
|
||||
borderRadius: BORDER_RADIUS,
|
||||
flexDirection: 'row'
|
||||
},
|
||||
|
||||
mainWrapper: {
|
||||
alignSelf: 'stretch',
|
||||
padding: BoxModel.padding * 2,
|
||||
|
||||
// The added bottom padding is to compensate the empty space around the
|
||||
// close icon.
|
||||
paddingBottom: BoxModel.padding * 3
|
||||
},
|
||||
|
||||
overlayTouchable: {
|
||||
...StyleSheet.absoluteFillObject
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Color schemed styles for all the component based on the abstract dialog.
|
||||
@@ -272,28 +264,3 @@ ColorSchemeRegistry.register('Dialog', {
|
||||
borderTopWidth: 1
|
||||
}
|
||||
});
|
||||
|
||||
ColorSchemeRegistry.register('SecurityDialog', {
|
||||
/**
|
||||
* Field on an input dialog.
|
||||
*/
|
||||
field: {
|
||||
borderBottomWidth: 1,
|
||||
borderColor: schemeColor('border'),
|
||||
color: schemeColor('text'),
|
||||
fontSize: 14,
|
||||
paddingBottom: 8
|
||||
},
|
||||
|
||||
text: {
|
||||
color: schemeColor('text'),
|
||||
fontSize: 14,
|
||||
marginTop: 8
|
||||
},
|
||||
|
||||
title: {
|
||||
color: schemeColor('text'),
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
/* @flow */
|
||||
|
||||
import { assign, ReducerRegistry } from '../redux';
|
||||
|
||||
import { HIDE_DIALOG, OPEN_DIALOG } from './actionTypes';
|
||||
import {
|
||||
HIDE_DIALOG,
|
||||
HIDE_SHEET,
|
||||
OPEN_DIALOG,
|
||||
OPEN_SHEET
|
||||
} from './actionTypes';
|
||||
|
||||
/**
|
||||
* Reduces redux actions which show or hide dialogs.
|
||||
@@ -32,6 +35,18 @@ ReducerRegistry.register('features/base/dialog', (state = {}, action) => {
|
||||
component: action.component,
|
||||
componentProps: action.componentProps
|
||||
});
|
||||
|
||||
case HIDE_SHEET:
|
||||
return assign(state, {
|
||||
sheet: undefined,
|
||||
sheetProps: undefined
|
||||
});
|
||||
|
||||
case OPEN_SHEET:
|
||||
return assign(state, {
|
||||
sheet: action.component,
|
||||
sheetProps: action.componentProps
|
||||
});
|
||||
}
|
||||
|
||||
return state;
|
||||
|
||||
@@ -38,6 +38,12 @@ export const CALENDAR_ENABLED = 'calendar.enabled';
|
||||
*/
|
||||
export const CALL_INTEGRATION_ENABLED = 'call-integration.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if car mode should be enabled.
|
||||
* Default: enabled (true).
|
||||
*/
|
||||
export const CAR_MODE_ENABLED = 'car-mode.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if close captions should be enabled.
|
||||
* Default: enabled (true).
|
||||
@@ -154,6 +160,12 @@ export const OVERFLOW_MENU_ENABLED = 'overflow-menu.enabled';
|
||||
*/
|
||||
export const PIP_ENABLED = 'pip.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if the prejoin page should be enabled.
|
||||
* Default: enabled (true).
|
||||
*/
|
||||
export const PREJOIN_PAGE_ENABLED = 'prejoinpage.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if raise hand feature should be enabled.
|
||||
* Default: enabled.
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.44701 5H15.553C16.427 5 17.1997 5.56747 17.4613 6.40136L18.2765 9H18H6H5.7235L6.5387 6.40136C6.8003 5.56747 7.57305 5 8.44701 5ZM3.29779 10.0507L4.6304 5.80272C5.15358 4.13493 6.69908 3 8.44701 3H15.553C17.3009 3 18.8464 4.13494 19.3696 5.80272L20.7022 10.0507C21.4999 10.782 22 11.8326 22 13V17V18V21H20V18H4V21H2V18V17V13C2 11.8326 2.50012 10.782 3.29779 10.0507ZM6 11C4.89543 11 4 11.8954 4 13V16H20V13C20 11.8954 19.1046 11 18 11H6ZM9 13.5C9 14.3284 8.32843 15 7.5 15C6.67157 15 6 14.3284 6 13.5C6 12.6716 6.67157 12 7.5 12C8.32843 12 9 12.6716 9 13.5ZM16.5 15C17.3284 15 18 14.3284 18 13.5C18 12.6716 17.3284 12 16.5 12C15.6716 12 15 12.6716 15 13.5C15 14.3284 15.6716 15 16.5 15Z"/>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.50001 11.25C7.50001 11.9404 6.94036 12.5 6.25001 12.5C5.55965 12.5 5.00001 11.9404 5.00001 11.25C5.00001 10.5596 5.55965 10 6.25001 10C6.94036 10 7.50001 10.5596 7.50001 11.25Z" />
|
||||
<path d="M13.75 12.5C14.4404 12.5 15 11.9404 15 11.25C15 10.5596 14.4404 10 13.75 10C13.0596 10 12.5 10.5596 12.5 11.25C12.5 11.9404 13.0596 12.5 13.75 12.5Z" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.74816 8.3756L3.85867 4.8356C4.29466 3.44578 5.58258 2.5 7.03918 2.5H12.9608C14.4174 2.5 15.7054 3.44578 16.1413 4.8356L17.2518 8.3756C17.9166 8.98497 18.3333 9.86048 18.3333 10.8333V17.5H16.6667V15H3.33334V17.5H1.66667V10.8333C1.66667 9.86048 2.08344 8.98497 2.74816 8.3756ZM7.03918 4.16667H12.9608C13.6891 4.16667 14.3331 4.63956 14.5511 5.33447L15.2304 7.5H4.76959L5.44892 5.33447C5.66692 4.63956 6.31088 4.16667 7.03918 4.16667ZM5.00001 9.16667C4.07953 9.16667 3.33334 9.91286 3.33334 10.8333V13.3333H16.6667V10.8333C16.6667 9.91286 15.9205 9.16667 15 9.16667H5.00001Z" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 844 B After Width: | Height: | Size: 1.0 KiB |
3
react/features/base/icons/svg/circle.svg
Normal file
3
react/features/base/icons/svg/circle.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="12" cy="12" r="12"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 124 B |
3
react/features/base/icons/svg/dock.svg
Normal file
3
react/features/base/icons/svg/dock.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.3332 3.33329C18.3332 2.41282 17.587 1.66663 16.6665 1.66663H8.33317C7.4127 1.66663 6.6665 2.41282 6.6665 3.33329V4.99996H3.33317C2.4127 4.99996 1.6665 5.74615 1.6665 6.66663V16.6666C1.6665 17.5871 2.4127 18.3333 3.33317 18.3333H13.3332C14.2536 18.3333 14.9998 17.5871 14.9998 16.6666V15H16.6665C17.587 15 18.3332 14.2538 18.3332 13.3333V3.33329ZM8.33317 3.33329H16.6665L16.6665 13.3333H14.9998V6.66663C14.9998 5.74615 14.2536 4.99996 13.3332 4.99996H8.33317V3.33329ZM3.33317 6.66663V16.6666H13.3332V6.66663H3.33317ZM6.6665 12.1024V9.99996C6.6665 9.53972 6.29341 9.16663 5.83317 9.16663C5.37293 9.16663 4.99984 9.53972 4.99984 9.99996V14.1296V14.1666C4.99984 14.5693 5.28549 14.9053 5.66523 14.983C5.71947 14.9941 5.77564 15 5.83317 15L5.83356 14.9992C5.83397 14.9992 5.83439 14.9992 5.8348 14.9992L5.83445 15H5.87022H9.99984C10.4601 15 10.8332 14.6269 10.8332 14.1666C10.8332 13.7064 10.4601 13.3333 9.99984 13.3333H7.89741L11.4116 9.81913C11.7515 9.47922 11.7515 8.92813 11.4116 8.58822C11.0717 8.24832 10.5206 8.24832 10.1807 8.58822L6.6665 12.1024Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -28,6 +28,7 @@ export { default as IconChatSend } from './send.svg';
|
||||
export { default as IconChatUnread } from './chat-unread.svg';
|
||||
export { default as IconCheck } from './check.svg';
|
||||
export { default as IconCheckSolid } from './check-solid.svg';
|
||||
export { default as IconCircle } from './circle.svg';
|
||||
export { default as IconClose } from './close.svg';
|
||||
export { default as IconCloseCircle } from './close-circle.svg';
|
||||
export { default as IconCloseSolid } from './close-solid.svg';
|
||||
@@ -44,6 +45,7 @@ export { default as IconDeviceBluetooth } from './bluetooth.svg';
|
||||
export { default as IconDeviceEarpiece } from './phone-talk.svg';
|
||||
export { default as IconDeviceHeadphone } from './headset.svg';
|
||||
export { default as IconDeviceSpeaker } from './volume.svg';
|
||||
export { default as IconDock } from './dock.svg';
|
||||
export { default as IconDeviceDocument } from './document.svg';
|
||||
export { default as IconDominantSpeaker } from './dominant-speaker.svg';
|
||||
export { default as IconDownload } from './download.svg';
|
||||
@@ -130,6 +132,7 @@ export { default as IconSwitchCamera } from './switch-camera.svg';
|
||||
export { default as IconTileView } from './tiles-many.svg';
|
||||
export { default as IconToggleRecording } from './camera-take-picture.svg';
|
||||
export { default as IconTrash } from './trash.svg';
|
||||
export { default as IconUndock } from './undock.svg';
|
||||
export { default as IconUnpin } from './unpin.svg';
|
||||
export { default as IconVideoOff } from './video-off.svg';
|
||||
export { default as IconVideoQualityAudioOnly } from './AUD.svg';
|
||||
|
||||
3
react/features/base/icons/svg/undock.svg
Normal file
3
react/features/base/icons/svg/undock.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.6665 1.66663H6.6665C5.74603 1.66663 4.99984 2.41282 4.99984 3.33329V4.99996H3.33317C2.4127 4.99996 1.6665 5.74615 1.6665 6.66663V16.6666C1.6665 17.5871 2.4127 18.3333 3.33317 18.3333H13.3332C14.2536 18.3333 14.9998 17.5871 14.9998 16.6666V15H16.6665C17.587 15 18.3332 14.2538 18.3332 13.3333V3.33329C18.3332 2.41282 17.587 1.66663 16.6665 1.66663ZM13.3332 16.6666V15H6.6665C5.74603 15 4.99984 14.2538 4.99984 13.3333V6.66663H3.33317V16.6666H13.3332ZM6.6665 3.33329V13.3333H16.6665V3.33329H6.6665ZM9.99984 4.99996C9.5396 4.99996 9.1665 5.37306 9.1665 5.83329C9.1665 6.29353 9.5396 6.66663 9.99984 6.66663H12.1023L8.5881 10.1808C8.24819 10.5207 8.24819 11.0718 8.5881 11.4117C8.928 11.7516 9.4791 11.7516 9.819 11.4117L13.3332 7.89753V9.99996C13.3332 10.4602 13.7063 10.8333 14.1665 10.8333C14.6267 10.8333 14.9998 10.4602 14.9998 9.99996V5.83329C14.9998 5.37306 14.6267 4.99996 14.1665 4.99996H14.1295H9.99984Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -4,6 +4,7 @@ import Bourne from '@hapi/bourne';
|
||||
import { jitsiLocalStorage } from '@jitsi/js-utils/jitsi-local-storage';
|
||||
|
||||
import { browser } from '../lib-jitsi-meet';
|
||||
import { inIframe } from '../util/iframeUtils';
|
||||
import { parseURLParams } from '../util/parseURLParams';
|
||||
|
||||
import logger from './logger';
|
||||
@@ -11,19 +12,6 @@ import logger from './logger';
|
||||
declare var APP: Object;
|
||||
declare var config: Object;
|
||||
|
||||
/**
|
||||
* Checks whether we are loaded in an iframe.
|
||||
*
|
||||
* @returns {boolean} Returns {@code true} if loaded in iframe.
|
||||
* @private
|
||||
*/
|
||||
function _inIframe() {
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles changes of the fake local storage.
|
||||
@@ -55,7 +43,7 @@ function shouldUseHostPageLocalStorage(urlParams) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.isWebKitBased() && _inIframe()) {
|
||||
if (browser.isWebKitBased() && inIframe()) {
|
||||
// WebKit browsers don't persist local storage for third-party iframes.
|
||||
|
||||
return true;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user