mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-05-30 21:57:46 +00:00
Compare commits
87 Commits
6210
...
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 |
@@ -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));
|
||||
|
||||
|
||||
@@ -1650,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));
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1745,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) {
|
||||
@@ -2639,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);
|
||||
}
|
||||
|
||||
|
||||
54
config.js
54
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,
|
||||
@@ -495,11 +503,6 @@ var config = {
|
||||
// Hides add breakout room button
|
||||
// hideAddRoomButton: false,
|
||||
|
||||
// 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.
|
||||
// hidePrejoinDisplayName: false,
|
||||
|
||||
// Require users to always specify a display name.
|
||||
// requireDisplayName: true,
|
||||
|
||||
@@ -564,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']
|
||||
// },
|
||||
@@ -777,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
|
||||
@@ -786,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.
|
||||
@@ -870,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
|
||||
@@ -944,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
|
||||
@@ -1306,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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,12 @@
|
||||
margin-bottom: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&-container {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
&-error {
|
||||
|
||||
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), jitsi-meet-prosody, lua-basexx, lua-luaossl, lua-cjson
|
||||
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
|
||||
|
||||
@@ -138,11 +138,11 @@ Component "lobby.jitmeet.example.com" "muc"
|
||||
"polls";
|
||||
}
|
||||
|
||||
-- Enabled dial-in for JaaS customers
|
||||
-- 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 -- JaaS customers remove this line
|
||||
enabled = false -- Jitsi meet components customers remove this line
|
||||
modules_enabled = {
|
||||
"ping";
|
||||
"bosh";
|
||||
|
||||
BIN
images/downloadLocalRecording.png
Normal file
BIN
images/downloadLocalRecording.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 490 B |
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
/**
|
||||
|
||||
@@ -46,7 +46,7 @@ public class PiPViewCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
private let 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.")
|
||||
|
||||
@@ -116,6 +116,7 @@
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
"buttonText": "نزِّل إضافة متصفح كروم",
|
||||
"buttonTextEdge": "قم بتثبيت ملحق Edge",
|
||||
"close": "إغلق",
|
||||
"dontShowAgain": "لا ترني هذه مرة أخرى",
|
||||
"installExtensionText": "نزِّل الإضافة للدمج مع رزنامة غوغل ورزنامة أوفيس 365"
|
||||
@@ -207,6 +208,9 @@
|
||||
"selectADevice": "اختر جهازًا",
|
||||
"testAudio": "اختبر الصوت"
|
||||
},
|
||||
"dialIn": {
|
||||
"screenTitle": "ملخص الطلب"
|
||||
},
|
||||
"dialOut": {
|
||||
"statusMessage": "{{status}} الآن"
|
||||
},
|
||||
@@ -657,6 +661,8 @@
|
||||
"linkToSalesforceKey": "ربط هذا المُلتقى",
|
||||
"linkToSalesforceProgress": "جارٍ ربط الاجتماع بـ Salesforce ...",
|
||||
"linkToSalesforceSuccess": "تم ربط الاجتماع بـ Salesforce",
|
||||
"localRecordingStarted": "بدأ {{name}} تسجيلًا محليًا.",
|
||||
"localRecordingStopped": "أوقف {{name}} التسجيل المحلي.",
|
||||
"me": "أنا",
|
||||
"moderationInEffectCSDescription": "يرجى رفع اليد إذا كنت تريد مشاركة شاشتك.",
|
||||
"moderationInEffectCSTitle": "تم حظر مشاركة الشاشة من قبل المشرف",
|
||||
@@ -812,6 +818,7 @@
|
||||
"initiated": "بدأ الاتصال",
|
||||
"joinAudioByPhone": "انضم مع صوت من الجوال",
|
||||
"joinMeeting": "انضم للمُلتقى",
|
||||
"joinMeetingInLowBandwidthMode": "الانضمام في وضع النطاق الترددي المنخفض",
|
||||
"joinWithoutAudio": "انضم دون صوت",
|
||||
"keyboardShortcuts": "تفعيل اختصارات لوحة المفاتيح",
|
||||
"linkCopied": "نُسِخ الرابط",
|
||||
@@ -887,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}} التسجيل",
|
||||
@@ -894,6 +902,7 @@
|
||||
"onBy": "بدأ {{name}} التسجيل",
|
||||
"pending": "التحضير لتسجيل المُلتقى...",
|
||||
"rec": "تسجيل",
|
||||
"saveLocalRecording": "حفظ ملف التسجيل محليا",
|
||||
"serviceDescription": "ستحفظ خدمة التسجيل الفيديو المستجل",
|
||||
"serviceDescriptionCloud": "تسجيل سحابي",
|
||||
"serviceDescriptionCloudInfo": "يتم مسح المُلتقيات المسجلة تلقائيًا بعد 24 ساعة من وقت التسجيل.",
|
||||
@@ -901,6 +910,7 @@
|
||||
"sessionAlreadyActive": "هذه الجلسة قيد التسجيل أو البث المباشر.",
|
||||
"signIn": "دخول",
|
||||
"signOut": "خروج",
|
||||
"surfaceError": "الرجاء تحديد علامة التبويب الحالية.",
|
||||
"unavailable": "عجبًا! {{serviceName}} غير متاحة حاليًا. نعمل على حل المشكلة. حاول مرة أخرى لاحقًا.",
|
||||
"unavailableTitle": "التسجيل غير متاح",
|
||||
"uploadToCloud": "تحميل إلى السحابة"
|
||||
@@ -943,6 +953,7 @@
|
||||
"playSounds": "تشغيل الصوت عند:",
|
||||
"reactions": "ردود فعل المُلتقى",
|
||||
"sameAsSystem": "مثل النظام ({{label}})",
|
||||
"screenTitle": "إعدادات",
|
||||
"selectAudioOutput": "خرج الصوت",
|
||||
"selectCamera": "الكاميرا",
|
||||
"selectMic": "المجهار (المايكروفون)",
|
||||
@@ -968,6 +979,7 @@
|
||||
"disableCrashReportingWarning": "أمتأكد من تعطيل تقارير الأعطال التقنية؟ ستسري الإعدادات الجديدة بعد إعادة تشغيل التطبيق",
|
||||
"disableP2P": "تعطيل وضع واحد شخص-لشخص",
|
||||
"displayName": "عرض الاسم",
|
||||
"displayNamePlaceholderText": "على سبيل المثال: علي الحيدري",
|
||||
"email": "البريد الإلكتروني",
|
||||
"header": "الإعدادات",
|
||||
"profileSection": "الملف الشخصي",
|
||||
@@ -1026,6 +1038,7 @@
|
||||
"chat": "اظهِر/اخفِ نافذة الدردشة",
|
||||
"clap": "تصفيق",
|
||||
"collapse": "قلّص",
|
||||
"dock": "إرساء في النافذة الرئيسية",
|
||||
"document": "اظهِر/اخفِ الملف المشارك",
|
||||
"download": "نزِّل التطبيق",
|
||||
"embedMeeting": "ضمِّن المُلتقى",
|
||||
@@ -1076,6 +1089,7 @@
|
||||
"tileView": "اظهِر/اخفِ عرض العنوان",
|
||||
"toggleCamera": "بدِّل الكاميرا",
|
||||
"toggleFilmstrip": "بدِّل وضع الشريط السينمائي (filmstrip)",
|
||||
"undock": "فك في نافذة منفصلة",
|
||||
"videoblur": "استعمل/اخرج من وضع تغبيش خلفية الفيديو",
|
||||
"videomute": "بدِّل وضع اخفاء الفيديو"
|
||||
},
|
||||
@@ -1092,6 +1106,7 @@
|
||||
"closeChat": "أغلق الدردشة",
|
||||
"closeReactionsMenu": "إغلاق قائمة ردود الفعل",
|
||||
"disableReactionSounds": "يمكنك تعطيل أصوات ردود الفعل لهذا المُلتقى",
|
||||
"dock": "إرساء في النافذة الرئيسية",
|
||||
"documentClose": "أغلق الملف المشارك",
|
||||
"documentOpen": "افتح الملف المشارك",
|
||||
"download": "نزِّل التطبيق",
|
||||
@@ -1160,6 +1175,7 @@
|
||||
"talkWhileMutedPopup": "أتحاول التحدث؟ المجهار مكتوم لديك.",
|
||||
"tileViewToggle": "بدِّل عنوان العرض",
|
||||
"toggleCamera": "بدِّل الكاميرا",
|
||||
"undock": "فك في نافذة منفصلة",
|
||||
"videoSettings": "اعدادات الفيديو",
|
||||
"videomute": "استعمل / أوقف الكاميرا"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -116,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"
|
||||
@@ -207,6 +208,9 @@
|
||||
"selectADevice": "Select a device",
|
||||
"testAudio": "Play a test sound"
|
||||
},
|
||||
"dialIn": {
|
||||
"screenTitle": "Dial-in summary"
|
||||
},
|
||||
"dialOut": {
|
||||
"statusMessage": "is now {{status}}"
|
||||
},
|
||||
@@ -288,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",
|
||||
@@ -657,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",
|
||||
@@ -812,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",
|
||||
@@ -887,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",
|
||||
@@ -894,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.",
|
||||
@@ -901,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"
|
||||
@@ -943,6 +954,7 @@
|
||||
"playSounds": "Play sound on",
|
||||
"reactions": "Meeting reactions",
|
||||
"sameAsSystem": "Same as system ({{label}})",
|
||||
"screenTitle": "Settings",
|
||||
"selectAudioOutput": "Audio output",
|
||||
"selectCamera": "Camera",
|
||||
"selectMic": "Microphone",
|
||||
@@ -968,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",
|
||||
|
||||
@@ -1695,6 +1695,19 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
||||
8
modules/API/external/external_api.js
vendored
8
modules/API/external/external_api.js
vendored
@@ -126,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',
|
||||
@@ -301,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();
|
||||
@@ -317,7 +319,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
invitees,
|
||||
devices,
|
||||
userInfo,
|
||||
e2eeKey
|
||||
e2eeKey,
|
||||
release
|
||||
} = parseArguments(args);
|
||||
const localStorageContent = jitsiLocalStorage.getItem('jitsiLocalStorage');
|
||||
|
||||
@@ -332,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());
|
||||
}
|
||||
}
|
||||
|
||||
345
package-lock.json
generated
345
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,7 +49,7 @@
|
||||
"@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",
|
||||
@@ -72,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/v1439.0.0+42f5b4bf/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",
|
||||
@@ -93,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",
|
||||
@@ -128,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"
|
||||
},
|
||||
@@ -140,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",
|
||||
@@ -163,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",
|
||||
@@ -3546,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": {
|
||||
@@ -5043,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",
|
||||
@@ -5395,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",
|
||||
@@ -5491,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": "*",
|
||||
@@ -5509,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",
|
||||
@@ -5561,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",
|
||||
@@ -8323,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",
|
||||
@@ -10657,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",
|
||||
@@ -11619,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",
|
||||
@@ -12132,8 +12168,8 @@
|
||||
},
|
||||
"node_modules/lib-jitsi-meet": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1439.0.0+42f5b4bf/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-wkftHl4fNF/KdkxOkvHsxZX9jof3CDr6RraIeH/nzQBIrh2MTEfAPZBv4+zaGuPoKolbiNBbkSgB9pJ8cwh03Q==",
|
||||
"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",
|
||||
@@ -14797,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",
|
||||
@@ -15391,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"
|
||||
}
|
||||
@@ -18643,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",
|
||||
@@ -19123,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",
|
||||
@@ -22628,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": {
|
||||
@@ -23709,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",
|
||||
@@ -23717,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",
|
||||
@@ -23996,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",
|
||||
@@ -24092,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": "*",
|
||||
@@ -24110,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",
|
||||
@@ -24162,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",
|
||||
@@ -26348,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",
|
||||
@@ -28173,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",
|
||||
@@ -28862,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",
|
||||
@@ -29276,8 +29369,8 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1439.0.0+42f5b4bf/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-wkftHl4fNF/KdkxOkvHsxZX9jof3CDr6RraIeH/nzQBIrh2MTEfAPZBv4+zaGuPoKolbiNBbkSgB9pJ8cwh03Q==",
|
||||
"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",
|
||||
@@ -31408,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",
|
||||
@@ -31853,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",
|
||||
@@ -34274,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": {
|
||||
@@ -34621,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",
|
||||
|
||||
21
package.json
21
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,7 +54,7 @@
|
||||
"@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",
|
||||
@@ -77,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/v1439.0.0+42f5b4bf/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",
|
||||
@@ -98,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",
|
||||
@@ -133,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"
|
||||
},
|
||||
@@ -145,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",
|
||||
@@ -168,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",
|
||||
@@ -184,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,
|
||||
},
|
||||
@@ -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
|
||||
@@ -155,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;
|
||||
}
|
||||
@@ -166,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 = {};
|
||||
@@ -204,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);
|
||||
|
||||
@@ -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,14 @@
|
||||
// @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, setSafeAreaInsets } from '../../base/responsive-ui';
|
||||
import { updateSettings } from '../../base/settings';
|
||||
import { _getRouteToRender } from '../getRouteToRender.native';
|
||||
@@ -23,6 +23,11 @@ import '../reducers';
|
||||
|
||||
declare var __DEV__;
|
||||
|
||||
const DialogContainerWrapper = Platform.select({
|
||||
ios: FullWindowOverlay,
|
||||
default: View
|
||||
});
|
||||
|
||||
/**
|
||||
* The type of React {@code Component} props of {@link App}.
|
||||
*/
|
||||
@@ -240,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 {
|
||||
|
||||
@@ -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';
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
@@ -169,7 +170,6 @@ export default [
|
||||
'hideConferenceSubject',
|
||||
'hideDisplayName',
|
||||
'hideDominantSpeakerBadge',
|
||||
'hidePrejoinDisplayName',
|
||||
'hideRecordingLabel',
|
||||
'hideParticipantsStats',
|
||||
'hideConferenceTimer',
|
||||
|
||||
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;
|
||||
|
||||
@@ -160,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,13 +1,14 @@
|
||||
// @flow
|
||||
|
||||
import { useHeaderHeight } from '@react-navigation/elements';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { getDefaultHeaderHeight } from '@react-navigation/elements';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import {
|
||||
Keyboard,
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
StatusBar
|
||||
} from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { useSafeAreaFrame, useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
|
||||
import { StyleType } from '../../styles';
|
||||
|
||||
@@ -33,6 +34,11 @@ type Props = {
|
||||
*/
|
||||
hasTabNavigator: boolean,
|
||||
|
||||
/**
|
||||
* Is the screen presented as a modal?
|
||||
*/
|
||||
isModalPresentation: boolean,
|
||||
|
||||
/**
|
||||
* Additional style to be appended to the KeyboardAvoidingView.
|
||||
*/
|
||||
@@ -45,26 +51,37 @@ const JitsiKeyboardAvoidingView = (
|
||||
contentContainerStyle,
|
||||
hasTabNavigator,
|
||||
hasBottomTextInput,
|
||||
isModalPresentation,
|
||||
style
|
||||
}: Props) => {
|
||||
const headerHeight = useHeaderHeight();
|
||||
const frame = useSafeAreaFrame();
|
||||
const insets = useSafeAreaInsets();
|
||||
const [ bottomPadding, setBottomPadding ] = useState(insets.bottom);
|
||||
const [ topPadding, setTopPadding ] = useState(insets.top);
|
||||
|
||||
useEffect(() => {
|
||||
// This useEffect is needed because insets are undefined at first for some reason
|
||||
// https://github.com/th3rdwave/react-native-safe-area-context/issues/54
|
||||
setBottomPadding(insets.bottom);
|
||||
setTopPadding(insets.top);
|
||||
}, [ insets.bottom, insets.top ]);
|
||||
|
||||
}, [ insets.bottom ]);
|
||||
const headerHeight = getDefaultHeaderHeight(frame, isModalPresentation, topPadding);
|
||||
|
||||
// Notch devices have in general a header height between 103 and 106px
|
||||
const topNotchDevice = headerHeight > 100;
|
||||
const deviceHeight = topNotchDevice ? headerHeight - 50 : headerHeight;
|
||||
const tabNavigatorPadding
|
||||
= hasTabNavigator ? headerHeight : 0;
|
||||
= hasTabNavigator ? deviceHeight : 0;
|
||||
const noNotchDevicePadding = bottomPadding || 10;
|
||||
const iosVerticalOffset
|
||||
= headerHeight + noNotchDevicePadding + tabNavigatorPadding;
|
||||
= deviceHeight + noNotchDevicePadding + tabNavigatorPadding;
|
||||
const androidVerticalOffset = hasBottomTextInput
|
||||
? headerHeight + StatusBar.currentHeight : headerHeight;
|
||||
? deviceHeight + StatusBar.currentHeight : deviceHeight;
|
||||
|
||||
// Tells the view what to do with taps
|
||||
const shouldSetResponse = useCallback(() => true);
|
||||
const onRelease = useCallback(() => Keyboard.dismiss());
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
@@ -76,6 +93,8 @@ const JitsiKeyboardAvoidingView = (
|
||||
? iosVerticalOffset
|
||||
: androidVerticalOffset
|
||||
}
|
||||
onResponderRelease = { onRelease }
|
||||
onStartShouldSetResponder = { shouldSetResponse }
|
||||
style = { style }>
|
||||
{ children }
|
||||
</KeyboardAvoidingView>
|
||||
|
||||
@@ -37,6 +37,11 @@ type Props = {
|
||||
*/
|
||||
hasTabNavigator?: boolean,
|
||||
|
||||
/**
|
||||
* Is the screen presented as a modal?
|
||||
*/
|
||||
isModalPresentation?: boolean,
|
||||
|
||||
/**
|
||||
* Insets for the SafeAreaView.
|
||||
*/
|
||||
@@ -54,7 +59,8 @@ const JitsiScreen = ({
|
||||
footerComponent,
|
||||
hasTabNavigator = false,
|
||||
hasBottomTextInput = false,
|
||||
safeAreaInsets = [ 'bottom', 'left', 'right' ],
|
||||
isModalPresentation = true,
|
||||
safeAreaInsets = [ 'left', 'right' ],
|
||||
style
|
||||
}: Props) => (
|
||||
<View
|
||||
@@ -63,13 +69,14 @@ const JitsiScreen = ({
|
||||
contentContainerStyle = { contentContainerStyle }
|
||||
hasBottomTextInput = { hasBottomTextInput }
|
||||
hasTabNavigator = { hasTabNavigator }
|
||||
isModalPresentation = { isModalPresentation }
|
||||
style = { style }>
|
||||
<SafeAreaView
|
||||
edges = { safeAreaInsets }
|
||||
style = { styles.safeArea }>
|
||||
{ children }
|
||||
{children}
|
||||
</SafeAreaView>
|
||||
{ footerComponent && footerComponent() }
|
||||
{footerComponent && footerComponent()}
|
||||
</JitsiKeyboardAvoidingView>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -231,3 +231,12 @@ export const OVERWRITE_PARTICIPANT_NAME = 'OVERWRITE_PARTICIPANT_NAME';
|
||||
* }
|
||||
*/
|
||||
export const OVERWRITE_PARTICIPANTS_NAMES = 'OVERWRITE_PARTICIPANTS_NAMES';
|
||||
|
||||
/**
|
||||
* Updates participants local recording status.
|
||||
* {
|
||||
* type: SET_LOCAL_PARTICIPANT_RECORDING_STATUS,
|
||||
* recording: boolean
|
||||
* }
|
||||
*/
|
||||
export const SET_LOCAL_PARTICIPANT_RECORDING_STATUS = 'SET_LOCAL_PARTICIPANT_RECORDING_STATUS';
|
||||
|
||||
@@ -10,17 +10,18 @@ import {
|
||||
LOCAL_PARTICIPANT_AUDIO_LEVEL_CHANGED,
|
||||
LOCAL_PARTICIPANT_RAISE_HAND,
|
||||
MUTE_REMOTE_PARTICIPANT,
|
||||
OVERWRITE_PARTICIPANT_NAME,
|
||||
OVERWRITE_PARTICIPANTS_NAMES,
|
||||
PARTICIPANT_ID_CHANGED,
|
||||
PARTICIPANT_JOINED,
|
||||
PARTICIPANT_KICKED,
|
||||
PARTICIPANT_LEFT,
|
||||
PARTICIPANT_UPDATED,
|
||||
PIN_PARTICIPANT,
|
||||
RAISE_HAND_UPDATED,
|
||||
SCREENSHARE_PARTICIPANT_NAME_CHANGED,
|
||||
SET_LOADABLE_AVATAR_URL,
|
||||
RAISE_HAND_UPDATED,
|
||||
OVERWRITE_PARTICIPANT_NAME,
|
||||
OVERWRITE_PARTICIPANTS_NAMES
|
||||
SET_LOCAL_PARTICIPANT_RECORDING_STATUS
|
||||
} from './actionTypes';
|
||||
import {
|
||||
DISCO_REMOTE_CONTROL_FEATURE
|
||||
@@ -683,3 +684,19 @@ export function overwriteParticipantsNames(participantList) {
|
||||
participantList
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Local video recording status for the local participant.
|
||||
*
|
||||
* @param {boolean} recording - If local recording is ongoing.
|
||||
* @returns {{
|
||||
* type: SET_LOCAL_PARTICIPANT_RECORDING_STATUS,
|
||||
* recording: boolean
|
||||
* }}
|
||||
*/
|
||||
export function updateLocalRecordingStatus(recording) {
|
||||
return {
|
||||
type: SET_LOCAL_PARTICIPANT_RECORDING_STATUS,
|
||||
recording
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { getBreakoutRooms } from '../../breakout-rooms/functions';
|
||||
import { toggleE2EE } from '../../e2ee/actions';
|
||||
import { MAX_MODE } from '../../e2ee/constants';
|
||||
import {
|
||||
LOCAL_RECORDING_NOTIFICATION_ID,
|
||||
NOTIFICATION_TIMEOUT_TYPE,
|
||||
RAISE_HAND_NOTIFICATION_ID,
|
||||
showNotification
|
||||
@@ -17,6 +18,7 @@ import {
|
||||
import { isForceMuted } from '../../participants-pane/functions';
|
||||
import { CALLING, INVITED } from '../../presence-status';
|
||||
import { RAISE_HAND_SOUND_ID } from '../../reactions/constants';
|
||||
import { RECORDING_OFF_SOUND_ID, RECORDING_ON_SOUND_ID } from '../../recording';
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app';
|
||||
import {
|
||||
CONFERENCE_WILL_JOIN,
|
||||
@@ -42,7 +44,8 @@ import {
|
||||
PARTICIPANT_JOINED,
|
||||
PARTICIPANT_LEFT,
|
||||
PARTICIPANT_UPDATED,
|
||||
RAISE_HAND_UPDATED
|
||||
RAISE_HAND_UPDATED,
|
||||
SET_LOCAL_PARTICIPANT_RECORDING_STATUS
|
||||
} from './actionTypes';
|
||||
import {
|
||||
localParticipantIdChanged,
|
||||
@@ -174,6 +177,29 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
break;
|
||||
}
|
||||
|
||||
case SET_LOCAL_PARTICIPANT_RECORDING_STATUS: {
|
||||
const state = store.getState();
|
||||
const { recording } = action;
|
||||
const localId = getLocalParticipant(state)?.id;
|
||||
const { localRecording } = state['features/base/config'];
|
||||
|
||||
if (localRecording.notifyAllParticipants) {
|
||||
store.dispatch(participantUpdated({
|
||||
// XXX Only the local participant is allowed to update without
|
||||
// stating the JitsiConference instance (i.e. participant property
|
||||
// `conference` for a remote participant) because the local
|
||||
// participant is uniquely identified by the very fact that there is
|
||||
// only one local participant.
|
||||
|
||||
id: localId,
|
||||
local: true,
|
||||
localRecording: recording
|
||||
}));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MUTE_REMOTE_PARTICIPANT: {
|
||||
const { conference } = store.getState()['features/base/conference'];
|
||||
|
||||
@@ -389,6 +415,8 @@ StateListenerRegistry.register(
|
||||
id: participant.getId(),
|
||||
features: { 'screen-sharing': true }
|
||||
})),
|
||||
'localRecording': (participant, value) =>
|
||||
_localRecordingUpdated(store, conference, participant.getId(), value),
|
||||
'raisedHand': (participant, value) =>
|
||||
_raiseHandUpdated(store, conference, participant.getId(), value),
|
||||
'region': (participant, value) =>
|
||||
@@ -566,7 +594,15 @@ function _maybePlaySounds({ getState, dispatch }, action) {
|
||||
function _participantJoinedOrUpdated(store, next, action) {
|
||||
const { dispatch, getState } = store;
|
||||
const { overwrittenNameList } = store.getState()['features/base/participants'];
|
||||
const { participant: { avatarURL, email, id, local, name, raisedHandTimestamp } } = action;
|
||||
const { participant: {
|
||||
avatarURL,
|
||||
email,
|
||||
id,
|
||||
local,
|
||||
localRecording,
|
||||
name,
|
||||
raisedHandTimestamp
|
||||
} } = action;
|
||||
|
||||
// Send an external update of the local participant's raised hand state
|
||||
// if a new raised hand state is defined in the action.
|
||||
@@ -587,6 +623,20 @@ function _participantJoinedOrUpdated(store, next, action) {
|
||||
action.participant.name = overwrittenNameList[id];
|
||||
}
|
||||
|
||||
// Send an external update of the local participant's local recording state
|
||||
// if a new local recording state is defined in the action.
|
||||
if (typeof localRecording !== 'undefined') {
|
||||
if (local) {
|
||||
const conference = getCurrentConference(getState);
|
||||
|
||||
// Send localRecording signalling only if there is a change
|
||||
if (conference
|
||||
&& localRecording !== getLocalParticipant(getState()).localRecording) {
|
||||
conference.setLocalParticipantProperty('localRecording', localRecording);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allow the redux update to go through and compare the old avatar
|
||||
// to the new avatar and emit out change events if necessary.
|
||||
const result = next(action);
|
||||
@@ -618,6 +668,35 @@ function _participantJoinedOrUpdated(store, next, action) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a local recording status update.
|
||||
*
|
||||
* @param {Function} dispatch - The Redux dispatch function.
|
||||
* @param {Object} conference - The conference for which we got an update.
|
||||
* @param {string} participantId - The ID of the participant from which we got an update.
|
||||
* @param {boolean} newValue - The new value of the local recording status.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _localRecordingUpdated({ dispatch, getState }, conference, participantId, newValue) {
|
||||
const state = getState();
|
||||
|
||||
dispatch(participantUpdated({
|
||||
conference,
|
||||
id: participantId,
|
||||
localRecording: newValue
|
||||
}));
|
||||
const participantName = getParticipantDisplayName(state, participantId);
|
||||
|
||||
dispatch(showNotification({
|
||||
titleKey: 'notify.somebody',
|
||||
title: participantName,
|
||||
descriptionKey: newValue ? 'notify.localRecordingStarted' : 'notify.localRecordingStopped',
|
||||
uid: LOCAL_RECORDING_NOTIFICATION_ID
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
|
||||
dispatch(playSound(newValue ? RECORDING_ON_SOUND_ID : RECORDING_OFF_SOUND_ID));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles a raise hand status update.
|
||||
*
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import { isMobileBrowser } from '../../../environment/utils';
|
||||
import { getFieldValue } from '../../../react';
|
||||
|
||||
type Props = {
|
||||
@@ -131,11 +130,16 @@ export default class InputField extends PureComponent<Props, State> {
|
||||
onChange = { this._onChange }
|
||||
onFocus = { this._onFocus }
|
||||
onKeyDown = { this._onKeyDown }
|
||||
onKeyPress = { this._onKeyPress }
|
||||
placeholder = { this.props.placeHolder }
|
||||
readOnly = { this.props.readOnly }
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
ref = { inputElement => this.props.autoFocus && isMobileBrowser()
|
||||
&& inputElement && inputElement.focus() }
|
||||
ref = { inputElement => {
|
||||
if (this.props.autoFocus) {
|
||||
inputElement && inputElement.focus();
|
||||
setTimeout(() => inputElement && inputElement.focus(), 200);
|
||||
}
|
||||
} }
|
||||
type = { this.props.type }
|
||||
value = { this.state.value } />
|
||||
);
|
||||
@@ -200,4 +204,14 @@ export default class InputField extends PureComponent<Props, State> {
|
||||
|
||||
onSubmit && event.key === 'Enter' && onSubmit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop event propagation on key press.
|
||||
*
|
||||
* @param {Event} event - Key press event object.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onKeyPress(event) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,6 @@
|
||||
/**
|
||||
* The default server URL to open if no other was specified.
|
||||
*/
|
||||
export const DEFAULT_SERVER_URL = 'https://meet.jit.si';
|
||||
//export const DEFAULT_SERVER_URL = 'https://abora6.jitsi.net#config.replaceParticipant=true';
|
||||
export const DEFAULT_SERVER_URL = 'https://alpha.jitsi.net';
|
||||
//export const DEFAULT_SERVER_URL = 'https://meet.jit.si';
|
||||
|
||||
@@ -11,6 +11,8 @@ export const commonClassName = {
|
||||
overflowMenuItem: 'overflow-menu-item',
|
||||
overflowMenuItemIcon: 'overflow-menu-item-icon',
|
||||
participantAvatar: 'participant-avatar',
|
||||
prejoinDialog: 'prejoin-dialog',
|
||||
prejoinDialogButton: 'prejoin-dialog-btn',
|
||||
toolboxIcon: 'toolbox-icon',
|
||||
toolboxButton: 'toolbox-button',
|
||||
toolboxContentItems: 'toolbox-content-items'
|
||||
@@ -120,6 +122,112 @@ export const commonStyles = (theme: Object) => {
|
||||
[commonClassName.participantAvatar]: {
|
||||
margin: `${theme.spacing(2)}px ${theme.spacing(3)}px ${theme.spacing(2)}px 0`
|
||||
},
|
||||
[commonClassName.prejoinDialog]: {
|
||||
background: '#1C2025',
|
||||
boxShadow: '0px 2px 20px rgba(0, 0, 0, 0.5)',
|
||||
borderRadius: '5px',
|
||||
color: '#fff',
|
||||
height: '400px',
|
||||
width: '375px',
|
||||
|
||||
[`${commonClassName.prejoinDialog}--small`]: {
|
||||
height: 300,
|
||||
width: 400
|
||||
},
|
||||
|
||||
[`${commonClassName.prejoinDialog}-label`]: {
|
||||
fontSize: '15px',
|
||||
lineHeight: '24px'
|
||||
},
|
||||
|
||||
[`${commonClassName.prejoinDialog}-label-num`]: {
|
||||
background: '#2b3b4b',
|
||||
border: '1px solid #A4B8D1',
|
||||
borderRadius: '50%',
|
||||
color: '#fff',
|
||||
display: 'inline-block',
|
||||
height: '24px',
|
||||
marginRight: `${theme.spacing(2)}px`,
|
||||
width: '24px'
|
||||
},
|
||||
|
||||
[`${commonClassName.prejoinDialog}-container`]: {
|
||||
alignItems: 'center',
|
||||
background: 'rgba(0,0,0,0.6)',
|
||||
display: 'flex',
|
||||
height: '100vh',
|
||||
justifyContent: 'center',
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
width: '100vw',
|
||||
zIndex: 3
|
||||
},
|
||||
|
||||
[`${commonClassName.prejoinDialog}-flag`]: {
|
||||
display: 'inline-block',
|
||||
marginRight: `${theme.spacing(2)}px}`,
|
||||
transform: 'scale(1.2)'
|
||||
},
|
||||
|
||||
[`${commonClassName.prejoinDialog}-title`]: {
|
||||
display: 'inline-block',
|
||||
fontSize: '24px',
|
||||
lineHeight: '32px'
|
||||
},
|
||||
|
||||
[`${commonClassName.prejoinDialog}-icon`]: {
|
||||
cursor: 'pointer',
|
||||
|
||||
'& > svg': {
|
||||
fill: '#A4B8D1'
|
||||
}
|
||||
},
|
||||
|
||||
[commonClassName.prejoinDialogButton]: {
|
||||
width: '309px'
|
||||
},
|
||||
|
||||
[`${commonClassName.prejoinDialog}-dialin-container`]: {
|
||||
textAlign: 'center'
|
||||
},
|
||||
|
||||
[`${commonClassName.prejoinDialog}-delimiter`]: {
|
||||
background: '#5f6266',
|
||||
border: '0',
|
||||
height: '1px',
|
||||
margin: '0',
|
||||
padding: '0',
|
||||
width: '100%'
|
||||
},
|
||||
|
||||
[`${commonClassName.prejoinDialog}-delimiter-container`]: {
|
||||
margin: `${theme.spacing(3)}px 0 ${theme.spacing(4)}px 0`,
|
||||
position: 'relative'
|
||||
},
|
||||
|
||||
[`${commonClassName.prejoinDialog}-delimiter-txt-container`]: {
|
||||
position: 'absolute',
|
||||
textAlign: 'center',
|
||||
top: '-8px',
|
||||
width: '100%'
|
||||
},
|
||||
|
||||
[`${commonClassName.prejoinDialog}-delimiter-txt`]: {
|
||||
background: '#1C2025',
|
||||
color: '#5f6266',
|
||||
fontSize: '11px',
|
||||
textTransform: 'uppercase',
|
||||
padding: `0 ${theme.spacing(2)}px`
|
||||
}
|
||||
},
|
||||
|
||||
[commonClassName.prejoinDialogButton]: {
|
||||
[`&.primary, &${commonClassName.prejoinDialogButton}.text`]: {
|
||||
width: '310px'
|
||||
}
|
||||
},
|
||||
|
||||
[commonClassName.toolboxIcon]: {
|
||||
display: 'flex',
|
||||
borderRadius: 3,
|
||||
|
||||
@@ -23,9 +23,13 @@ const blacklist = [ '__proto__', 'constructor', 'prototype' ];
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function parseURLParams(
|
||||
url: URL,
|
||||
url: URL | string,
|
||||
dontParse: boolean = false,
|
||||
source: string = 'hash'): Object {
|
||||
if (typeof url === 'string') {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
url = new URL(url);
|
||||
}
|
||||
const paramStr = source === 'search' ? url.search : url.hash;
|
||||
const params = {};
|
||||
const paramParts = (paramStr && paramStr.substr(1).split('&')) || [];
|
||||
|
||||
@@ -524,7 +524,7 @@ export function urlObjectToString(o: Object): ?string {
|
||||
// query/search
|
||||
|
||||
// Web's ExternalAPI jwt and lang
|
||||
const { jwt, lang } = o;
|
||||
const { jwt, lang, release } = o;
|
||||
|
||||
const search = new URLSearchParams(url.search);
|
||||
|
||||
@@ -538,6 +538,10 @@ export function urlObjectToString(o: Object): ?string {
|
||||
search.set('lang', lang || defaultLanguage);
|
||||
}
|
||||
|
||||
if (release) {
|
||||
search.set('release', release);
|
||||
}
|
||||
|
||||
const searchString = search.toString();
|
||||
|
||||
if (searchString) {
|
||||
@@ -603,3 +607,20 @@ export function addHashParamsToURL(url: URL, hashParamsToAdd: Object = {}) {
|
||||
export function getDecodedURI(uri: string) {
|
||||
return decodeURI(uri.replace(/^https?:\/\//i, ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new param to a url string. Checks whether to use '?' or '&' as a separator (checks for already existing params).
|
||||
*
|
||||
* @param {string} url - The url to modify.
|
||||
* @param {string} name - The param name to add.
|
||||
* @param {string} value - The value for the param.
|
||||
*
|
||||
* @returns {string} - The modified url.
|
||||
*/
|
||||
export function appendURLParam(url: string, name: string, value: string) {
|
||||
const newUrl = new URL(url);
|
||||
|
||||
newUrl.searchParams.append(name, value);
|
||||
|
||||
return newUrl.toString();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import { CHAT_ENABLED, getFeatureFlag } from '../../../base/flags';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { IconChat, IconChatUnread } from '../../../base/icons';
|
||||
import { connect } from '../../../base/redux';
|
||||
import {
|
||||
@@ -76,4 +77,4 @@ function _mapStateToProps(state, ownProps) {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(ChatButton);
|
||||
export default translate(connect(_mapStateToProps)(ChatButton));
|
||||
|
||||
@@ -56,7 +56,8 @@ export default {
|
||||
borderTopColor: 'rgb(209, 219, 231)',
|
||||
borderTopWidth: 1,
|
||||
flexDirection: 'row',
|
||||
paddingHorizontal: BoxModel.padding
|
||||
paddingBottom: '4%',
|
||||
paddingHorizontal: BaseTheme.spacing[3]
|
||||
},
|
||||
|
||||
inputField: {
|
||||
|
||||
@@ -104,6 +104,7 @@ class ChromeExtensionBanner extends PureComponent<Props, State> {
|
||||
shouldShow: false
|
||||
};
|
||||
|
||||
this.isEdge = /Edg(e)?/.test(navigator.userAgent);
|
||||
this._onClosePressed = this._onClosePressed.bind(this);
|
||||
this._onInstallExtensionClick = this._onInstallExtensionClick.bind(this);
|
||||
this._shouldNotRender = this._shouldNotRender.bind(this);
|
||||
@@ -196,8 +197,10 @@ class ChromeExtensionBanner extends PureComponent<Props, State> {
|
||||
* @returns {void}
|
||||
*/
|
||||
_onInstallExtensionClick() {
|
||||
const { edgeUrl, url } = this.props.bannerCfg;
|
||||
|
||||
sendAnalytics(createChromeExtensionBannerEvent(true));
|
||||
window.open(this.props.bannerCfg.url);
|
||||
window.open(this.isEdge && edgeUrl ? edgeUrl : url);
|
||||
this.setState({ closePressed: true });
|
||||
}
|
||||
|
||||
@@ -264,7 +267,7 @@ class ChromeExtensionBanner extends PureComponent<Props, State> {
|
||||
|
||||
return null;
|
||||
}
|
||||
const { t } = this.props;
|
||||
const { bannerCfg, t } = this.props;
|
||||
const mainClassNames = this.props.conference
|
||||
? 'chrome-extension-banner chrome-extension-banner__pos_in_meeting'
|
||||
: 'chrome-extension-banner';
|
||||
@@ -306,7 +309,10 @@ class ChromeExtensionBanner extends PureComponent<Props, State> {
|
||||
<div
|
||||
className = 'chrome-extension-banner__button-text'
|
||||
id = 'chrome-extension-banner__button-text'>
|
||||
{ t('chromeExtensionBanner.buttonText') }
|
||||
{ t(this.isEdge && bannerCfg.edgeUrl
|
||||
? 'chromeExtensionBanner.buttonTextEdge'
|
||||
: 'chromeExtensionBanner.buttonText')
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -22,11 +22,14 @@ import {
|
||||
} from '../../../filmstrip';
|
||||
import { CalleeInfoContainer } from '../../../invite';
|
||||
import { LargeVideo } from '../../../large-video';
|
||||
import { startKnocking } from '../../../lobby/actions.any';
|
||||
import { KnockingParticipantList } from '../../../lobby/components/native';
|
||||
import { getIsLobbyVisible } from '../../../lobby/functions';
|
||||
import { navigate }
|
||||
from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
import { shouldEnableAutoKnock } from '../../../mobile/navigation/functions';
|
||||
import { screen } from '../../../mobile/navigation/routes';
|
||||
import { setPictureInPictureEnabled } from '../../../mobile/picture-in-picture';
|
||||
import { Captions } from '../../../subtitles';
|
||||
import { setToolboxVisible } from '../../../toolbox/actions';
|
||||
import { Toolbox } from '../../../toolbox/components/native';
|
||||
@@ -61,11 +64,6 @@ type Props = AbstractProps & {
|
||||
*/
|
||||
_brandingStyles: Object,
|
||||
|
||||
/**
|
||||
* Branding image background.
|
||||
*/
|
||||
_brandingImageBackgroundUrl: string,
|
||||
|
||||
/**
|
||||
* Wherther the calendar feature is enabled or not.
|
||||
*/
|
||||
@@ -104,6 +102,11 @@ type Props = AbstractProps & {
|
||||
*/
|
||||
_largeVideoParticipantId: string,
|
||||
|
||||
/**
|
||||
* Local participant's display name.
|
||||
*/
|
||||
_localParticipantDisplayName: string,
|
||||
|
||||
/**
|
||||
* Whether Picture-in-Picture is enabled.
|
||||
*/
|
||||
@@ -120,6 +123,11 @@ type Props = AbstractProps & {
|
||||
*/
|
||||
_toolboxVisible: boolean,
|
||||
|
||||
/**
|
||||
* Indicates if we should auto-knock.
|
||||
*/
|
||||
_shouldEnableAutoKnock: boolean,
|
||||
|
||||
/**
|
||||
* Indicates whether the lobby screen should be visible.
|
||||
*/
|
||||
@@ -184,6 +192,7 @@ class Conference extends AbstractConference<Props, State> {
|
||||
*/
|
||||
componentDidMount() {
|
||||
BackHandler.addEventListener('hardwareBackPress', this._onHardwareBackPress);
|
||||
setPictureInPictureEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,10 +201,18 @@ class Conference extends AbstractConference<Props, State> {
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidUpdate(prevProps) {
|
||||
const { _showLobby } = this.props;
|
||||
const {
|
||||
_shouldEnableAutoKnock,
|
||||
_showLobby,
|
||||
dispatch
|
||||
} = this.props;
|
||||
|
||||
if (!prevProps._showLobby && _showLobby) {
|
||||
navigate(screen.lobby.root);
|
||||
|
||||
if (_shouldEnableAutoKnock) {
|
||||
dispatch(startKnocking());
|
||||
}
|
||||
}
|
||||
|
||||
if (prevProps._showLobby && !_showLobby) {
|
||||
@@ -216,6 +233,7 @@ class Conference extends AbstractConference<Props, State> {
|
||||
BackHandler.removeEventListener('hardwareBackPress', this._onHardwareBackPress);
|
||||
|
||||
clearTimeout(this._expandedLabelTimeout.current);
|
||||
setPictureInPictureEnabled(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -226,7 +244,6 @@ class Conference extends AbstractConference<Props, State> {
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
_brandingImageBackgroundUrl,
|
||||
_brandingStyles,
|
||||
_fullscreenEnabled
|
||||
} = this.props;
|
||||
@@ -237,8 +254,7 @@ class Conference extends AbstractConference<Props, State> {
|
||||
styles.conference,
|
||||
_brandingStyles
|
||||
] }>
|
||||
<BrandingImageBackground
|
||||
uri = { _brandingImageBackgroundUrl } />
|
||||
<BrandingImageBackground />
|
||||
<StatusBar
|
||||
barStyle = 'light-content'
|
||||
hidden = { _fullscreenEnabled }
|
||||
@@ -520,7 +536,7 @@ class Conference extends AbstractConference<Props, State> {
|
||||
function _mapStateToProps(state) {
|
||||
const { isOpen } = state['features/participants-pane'];
|
||||
const { aspectRatio, reducedUI } = state['features/base/responsive-ui'];
|
||||
const { backgroundColor, backgroundImageUrl } = state['features/dynamic-branding'];
|
||||
const { backgroundColor } = state['features/dynamic-branding'];
|
||||
const participantCount = getParticipantCount(state);
|
||||
const brandingStyles = backgroundColor ? {
|
||||
backgroundColor
|
||||
@@ -530,7 +546,6 @@ function _mapStateToProps(state) {
|
||||
...abstractMapStateToProps(state),
|
||||
_aspectRatio: aspectRatio,
|
||||
_brandingStyles: brandingStyles,
|
||||
_brandingImageBackgroundUrl: backgroundImageUrl,
|
||||
_calendarEnabled: isCalendarEnabled(state),
|
||||
_connecting: isConnecting(state),
|
||||
_filmstripVisible: isFilmstripVisible(state),
|
||||
@@ -540,6 +555,7 @@ function _mapStateToProps(state) {
|
||||
_largeVideoParticipantId: state['features/large-video'].participantId,
|
||||
_pictureInPictureEnabled: getFeatureFlag(state, PIP_ENABLED),
|
||||
_reducedUI: reducedUI,
|
||||
_shouldEnableAutoKnock: shouldEnableAutoKnock(state),
|
||||
_showLobby: getIsLobbyVisible(state),
|
||||
_toolboxVisible: isToolboxVisible(state)
|
||||
};
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
// @flow
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Text, TouchableOpacity, View } from 'react-native';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||
import { getFeatureFlag, INVITE_ENABLED } from '../../../base/flags';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { Icon, IconAddPeople } from '../../../base/icons';
|
||||
import { getParticipantCountWithFake } from '../../../base/participants';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { StyleType } from '../../../base/styles';
|
||||
import { isInBreakoutRoom } from '../../../breakout-rooms/functions';
|
||||
import { doInvitePeople } from '../../../invite/actions.native';
|
||||
|
||||
@@ -35,11 +31,6 @@ type Props = {
|
||||
*/
|
||||
_isLonelyMeeting: boolean,
|
||||
|
||||
/**
|
||||
* Color schemed styles of the component.
|
||||
*/
|
||||
_styles: StyleType,
|
||||
|
||||
/**
|
||||
* The Redux Dispatch function.
|
||||
*/
|
||||
@@ -76,7 +67,6 @@ class LonelyMeetingExperience extends PureComponent<Props> {
|
||||
_isInBreakoutRoom,
|
||||
_isInviteFunctionsDiabled,
|
||||
_isLonelyMeeting,
|
||||
_styles,
|
||||
t
|
||||
} = this.props;
|
||||
|
||||
@@ -86,29 +76,18 @@ class LonelyMeetingExperience extends PureComponent<Props> {
|
||||
|
||||
return (
|
||||
<View style = { styles.lonelyMeetingContainer }>
|
||||
<Text
|
||||
style = { [
|
||||
styles.lonelyMessage,
|
||||
_styles.lonelyMessage
|
||||
] }>
|
||||
<Text style = { styles.lonelyMessage }>
|
||||
{ t('lonelyMeetingExperience.youAreAlone') }
|
||||
</Text>
|
||||
{ !_isInviteFunctionsDiabled && !_isInBreakoutRoom && (
|
||||
<TouchableOpacity
|
||||
onPress = { this._onPress }
|
||||
style = { [
|
||||
styles.lonelyButton,
|
||||
_styles.lonelyButton
|
||||
] }>
|
||||
style = { styles.lonelyButton }>
|
||||
<Icon
|
||||
size = { 24 }
|
||||
src = { IconAddPeople }
|
||||
style = { styles.lonelyButtonComponents } />
|
||||
<Text
|
||||
style = { [
|
||||
styles.lonelyButtonComponents,
|
||||
_styles.lonelyMessage
|
||||
] }>
|
||||
<Text style = { styles.lonelyButtonComponents }>
|
||||
{ t('lonelyMeetingExperience.button') }
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
@@ -117,8 +96,6 @@ class LonelyMeetingExperience extends PureComponent<Props> {
|
||||
);
|
||||
}
|
||||
|
||||
_onPress: () => void;
|
||||
|
||||
/**
|
||||
* Callback for the onPress function of the button.
|
||||
*
|
||||
@@ -136,7 +113,7 @@ class LonelyMeetingExperience extends PureComponent<Props> {
|
||||
* @private
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state): $Shape<Props> {
|
||||
function _mapStateToProps(state) {
|
||||
const { disableInviteFunctions } = state['features/base/config'];
|
||||
const { conference } = state['features/base/conference'];
|
||||
const flag = getFeatureFlag(state, INVITE_ENABLED, true);
|
||||
@@ -145,8 +122,7 @@ function _mapStateToProps(state): $Shape<Props> {
|
||||
return {
|
||||
_isInBreakoutRoom,
|
||||
_isInviteFunctionsDiabled: !flag || disableInviteFunctions,
|
||||
_isLonelyMeeting: conference && getParticipantCountWithFake(state) === 1,
|
||||
_styles: ColorSchemeRegistry.get(state, 'Conference')
|
||||
_isLonelyMeeting: conference && getParticipantCountWithFake(state) === 1
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Text, SafeAreaView, View } from 'react-native';
|
||||
import { Text, View } from 'react-native';
|
||||
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import JitsiScreen from '../../../../base/modal/components/JitsiScreen';
|
||||
|
||||
import JitsiScreen from '../../../../base/modal/components/JitsiScreen';
|
||||
import { LoadingIndicator, TintedView } from '../../../../base/react';
|
||||
import { isLocalVideoTrackDesktop } from '../../../../base/tracks';
|
||||
import { setPictureInPictureEnabled } from '../../../../mobile/picture-in-picture/functions';
|
||||
import { setIsCarmode } from '../../../../video-layout/actions';
|
||||
import ConferenceTimer from '../../ConferenceTimer';
|
||||
import { isConnecting } from '../../functions';
|
||||
@@ -15,8 +17,6 @@ import MicrophoneButton from './MicrophoneButton';
|
||||
import SoundDeviceButton from './SoundDeviceButton';
|
||||
import TitleBar from './TitleBar';
|
||||
import styles from './styles';
|
||||
import { isLocalVideoTrackDesktop } from '../../../../base/tracks';
|
||||
import { setPictureInPictureDisabled } from '../../../../mobile/picture-in-picture/functions';
|
||||
|
||||
/**
|
||||
* Implements the carmode tab.
|
||||
@@ -31,14 +31,14 @@ const CarmodeTab = (): JSX.Element => {
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(setIsCarmode(true));
|
||||
setPictureInPictureDisabled(true);
|
||||
setPictureInPictureEnabled(false);
|
||||
|
||||
return () => {
|
||||
dispatch(setIsCarmode(false));
|
||||
if (!isSharing) {
|
||||
setPictureInPictureDisabled(false);
|
||||
setPictureInPictureEnabled(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { Button } from 'react-native-paper';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { openDialog } from '../../../../base/dialog/actions';
|
||||
import { openSheet } from '../../../../base/dialog/actions';
|
||||
import AudioRoutePickerDialog from '../../../../mobile/audio-mode/components/AudioRoutePickerDialog';
|
||||
|
||||
import AudioIcon from './AudioIcon';
|
||||
@@ -19,7 +19,7 @@ const SelectSoundDevice = () : JSX.Element => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const onSelect = useCallback(() =>
|
||||
dispatch(openDialog(AudioRoutePickerDialog))
|
||||
dispatch(openSheet(AudioRoutePickerDialog))
|
||||
, [ dispatch ]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Text, View } from 'react-native';
|
||||
|
||||
import { getConferenceName } from '../../../../base/conference/functions';
|
||||
import { ConnectionIndicator } from '../../../../connection-indicator';
|
||||
import { getFeatureFlag, MEETING_NAME_ENABLED } from '../../../../base/flags';
|
||||
import { JitsiRecordingConstants } from '../../../../base/lib-jitsi-meet';
|
||||
import { connect } from '../../../../base/redux';;
|
||||
import { RecordingLabel } from '../../../../recording';
|
||||
import { VideoQualityLabel } from '../../../../video-quality';
|
||||
|
||||
import { getLocalParticipant } from '../../../../base/participants';
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
@@ -32,35 +35,42 @@ type Props = {
|
||||
* @param {Props} props - The React props passed to this component.
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
const TitleBar = (props: Props) : JSX.Element => (<>
|
||||
<View
|
||||
pointerEvents = 'box-none'
|
||||
style = { styles.titleBarWrapper }>
|
||||
const TitleBar = (props: Props) : JSX.Element => {
|
||||
const localParticipant = useSelector(getLocalParticipant);
|
||||
const localParticipantId = localParticipant?.id;
|
||||
|
||||
return (<>
|
||||
<View
|
||||
pointerEvents = 'box-none'
|
||||
style = { styles.roomNameWrapper }>
|
||||
<View style = { styles.qualityLabelContainer }>
|
||||
<VideoQualityLabel />
|
||||
</View>
|
||||
|
||||
<View style = { styles.headerLabels }>
|
||||
<RecordingLabel mode = { JitsiRecordingConstants.mode.FILE } />
|
||||
<RecordingLabel mode = { JitsiRecordingConstants.mode.STREAM } />
|
||||
</View>
|
||||
|
||||
{
|
||||
props._meetingNameEnabled
|
||||
&& <View style = { styles.roomNameView }>
|
||||
<Text
|
||||
numberOfLines = { 1 }
|
||||
style = { styles.roomName }>
|
||||
{props._meetingName}
|
||||
</Text>
|
||||
style = { styles.titleBarWrapper }>
|
||||
<View
|
||||
pointerEvents = 'box-none'
|
||||
style = { styles.roomNameWrapper }>
|
||||
<View style = { styles.qualityLabelContainer }>
|
||||
<VideoQualityLabel />
|
||||
</View>
|
||||
}
|
||||
<ConnectionIndicator
|
||||
participantId = { localParticipantId }
|
||||
iconStyle = { styles.connectionIndicatorIcon } />
|
||||
<View style = { styles.headerLabels }>
|
||||
<RecordingLabel mode = { JitsiRecordingConstants.mode.FILE } />
|
||||
<RecordingLabel mode = { JitsiRecordingConstants.mode.STREAM } />
|
||||
</View>
|
||||
|
||||
{
|
||||
props._meetingNameEnabled
|
||||
&& <View style = { styles.roomNameView }>
|
||||
<Text
|
||||
numberOfLines = { 1 }
|
||||
style = { styles.roomName }>
|
||||
{props._meetingName}
|
||||
</Text>
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</>);
|
||||
</>);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps part of the Redux store to the props of this component.
|
||||
|
||||
@@ -203,5 +203,9 @@ export default {
|
||||
color: BaseTheme.palette.text01,
|
||||
marginBottom: 32,
|
||||
...BaseTheme.typography.bodyShortRegularLarge
|
||||
},
|
||||
|
||||
connectionIndicatorIcon: {
|
||||
fontSize: 20
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { ColorSchemeRegistry, schemeColor } from '../../../base/color-scheme';
|
||||
import { fixAndroidViewClipping } from '../../../base/styles';
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
|
||||
@@ -36,10 +35,6 @@ export default {
|
||||
margin: 10
|
||||
},
|
||||
|
||||
headerNavigationIcon: {
|
||||
marginLeft: 14
|
||||
},
|
||||
|
||||
headerNavigationButton: {
|
||||
height: BaseTheme.spacing[6],
|
||||
marginTop: 20,
|
||||
@@ -48,15 +43,13 @@ export default {
|
||||
|
||||
headerNavigationText: {
|
||||
color: BaseTheme.palette.text01,
|
||||
fontSize: HEADER_ACTION_BUTTON_SIZE,
|
||||
marginHorizontal: BaseTheme.spacing[3]
|
||||
fontSize: HEADER_ACTION_BUTTON_SIZE
|
||||
},
|
||||
|
||||
headerNavigationTextBold: {
|
||||
...BaseTheme.typography.labelButton,
|
||||
color: BaseTheme.palette.text01,
|
||||
fontSize: HEADER_ACTION_BUTTON_SIZE,
|
||||
marginHorizontal: BaseTheme.spacing[3]
|
||||
fontSize: HEADER_ACTION_BUTTON_SIZE
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -87,6 +80,7 @@ export default {
|
||||
|
||||
lonelyButton: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: BaseTheme.palette.action01,
|
||||
borderRadius: 24,
|
||||
flexDirection: 'row',
|
||||
height: BaseTheme.spacing[6],
|
||||
@@ -95,6 +89,7 @@ export default {
|
||||
},
|
||||
|
||||
lonelyButtonComponents: {
|
||||
color: BaseTheme.palette.text01,
|
||||
marginHorizontal: 6
|
||||
},
|
||||
|
||||
@@ -105,6 +100,7 @@ export default {
|
||||
},
|
||||
|
||||
lonelyMessage: {
|
||||
color: BaseTheme.palette.text01,
|
||||
paddingVertical: BaseTheme.spacing[2]
|
||||
},
|
||||
|
||||
@@ -236,13 +232,3 @@ export default {
|
||||
paddingLeft: BaseTheme.spacing[2]
|
||||
}
|
||||
};
|
||||
|
||||
ColorSchemeRegistry.register('Conference', {
|
||||
lonelyButton: {
|
||||
backgroundColor: schemeColor('inviteButtonBackground')
|
||||
},
|
||||
|
||||
lonelyMessage: {
|
||||
color: schemeColor('onVideoText')
|
||||
}
|
||||
});
|
||||
|
||||
@@ -32,6 +32,11 @@ export type Props = {
|
||||
*/
|
||||
participantId: string,
|
||||
|
||||
/**
|
||||
* Custom icon style.
|
||||
*/
|
||||
iconStyle?: Object,
|
||||
|
||||
/**
|
||||
* The source name of the track.
|
||||
*/
|
||||
|
||||
@@ -58,7 +58,7 @@ class ConnectionIndicator extends AbstractConnectionIndicator<Props, State> {
|
||||
}}>
|
||||
<BaseIndicator
|
||||
icon = { IconConnectionActive }
|
||||
iconStyle = { iconStyle } />
|
||||
iconStyle = { this.props.iconStyle || iconStyle } />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { NativeModules } from 'react-native';
|
||||
|
||||
const { Dropbox } = NativeModules;
|
||||
|
||||
import { setPictureInPictureDisabled } from '../mobile/picture-in-picture/functions';
|
||||
import { setPictureInPictureEnabled } from '../mobile/picture-in-picture/functions';
|
||||
|
||||
/**
|
||||
* Action to authorize the Jitsi Recording app in dropbox.
|
||||
@@ -13,12 +13,12 @@ import { setPictureInPictureDisabled } from '../mobile/picture-in-picture/functi
|
||||
* access token or rejected with an error.
|
||||
*/
|
||||
export async function _authorizeDropbox(): Promise<Object> {
|
||||
setPictureInPictureDisabled(true);
|
||||
setPictureInPictureEnabled(false);
|
||||
|
||||
try {
|
||||
return await Dropbox.authorize();
|
||||
} finally {
|
||||
setPictureInPictureDisabled(false);
|
||||
setPictureInPictureEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@ import React from 'react';
|
||||
import { Image } from 'react-native';
|
||||
import { SvgUri } from 'react-native-svg';
|
||||
|
||||
// @ts-ignore
|
||||
import { connect } from '../../../base/redux';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
@@ -21,13 +24,25 @@ const BrandingImageBackground: React.FC<Props> = ({ uri }:Props) => {
|
||||
|
||||
let backgroundImage;
|
||||
|
||||
if (!uri) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (imageType?.includes('.svg')) {
|
||||
backgroundImage
|
||||
= (
|
||||
<SvgUri
|
||||
height = '100%'
|
||||
|
||||
// Force uniform scaling.
|
||||
// Align the <min-x> of the element's viewBox
|
||||
// with the smallest X value of the viewport.
|
||||
// Align the <min-y> of the element's viewBox
|
||||
// with the smallest Y value of the viewport.
|
||||
preserveAspectRatio = 'xMinYMin'
|
||||
style = { styles.brandingImageBackgroundSvg }
|
||||
uri = { imgSrc }
|
||||
viewBox = '0 0 400 650'
|
||||
width = '100%' />
|
||||
);
|
||||
} else {
|
||||
@@ -42,4 +57,20 @@ const BrandingImageBackground: React.FC<Props> = ({ uri }:Props) => {
|
||||
return backgroundImage;
|
||||
};
|
||||
|
||||
export default BrandingImageBackground;
|
||||
/**
|
||||
* Maps (parts of) the Redux state to the associated props for the
|
||||
* {@code DialInLink} component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @private
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state: any) {
|
||||
const { backgroundImageUrl } = state['features/dynamic-branding'];
|
||||
|
||||
return {
|
||||
uri: backgroundImageUrl
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(BrandingImageBackground);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user