Compare commits

..

6 Commits

Author SHA1 Message Date
Horatiu Muresan
6e6ed1b9a2 Address review 2022-05-06 12:39:32 +03:00
Horatiu Muresan
0a07770c20 Align rec and audio only labels 2022-05-05 18:25:04 +03:00
Horatiu Muresan
1829a9b678 Update car icon 2022-05-05 17:02:44 +03:00
Horatiu Muresan
6948fb98cc fix 2022-05-05 13:57:02 +03:00
Horatiu Muresan
698ab32a62 Refactor carmnode
- open as a modal
- add long press to talk
- add long press analytics
- video mute keeps the previous state after carmode closes
- and more
2022-05-05 13:00:36 +03:00
Horatiu Muresan
ac965b86bc feat(carmode) Add carmode screen 2022-05-03 13:56:40 +03:00
366 changed files with 23905 additions and 6572 deletions

View File

@@ -3,9 +3,11 @@ build/*
# Third-party source code which we (1) do not want to modify or (2) try to
# modify as little as possible.
flow-typed/*
libs/*
resources/*
react/features/stream-effects/virtual-background/vendor/*
load-test/*
react/features/face-landmarks/resources/*
# ESLint will by default ignore its own configuration file. However, there does

View File

@@ -2,12 +2,13 @@ BUILD_DIR = build
CLEANCSS = ./node_modules/.bin/cleancss
DEPLOY_DIR = libs
LIBJITSIMEET_DIR = node_modules/lib-jitsi-meet
LIBFLAC_DIR = node_modules/libflacjs/dist/min
OLM_DIR = node_modules/@matrix-org/olm
TF_WASM_DIR = node_modules/@tensorflow/tfjs-backend-wasm/dist/
RNNOISE_WASM_DIR = node_modules/rnnoise-wasm/dist
TFLITE_WASM = react/features/stream-effects/virtual-background/vendor/tflite
MEET_MODELS_DIR = react/features/stream-effects/virtual-background/vendor/models
FACE_MODELS_DIR = node_modules/@vladmandic/human-models/models
FACE_MODELS_DIR = node_modules/@vladmandic/face-api/model
NODE_SASS = ./node_modules/.bin/sass
NPM = npm
OUTPUT_DIR = .
@@ -19,14 +20,17 @@ WEBPACK_DEV_SERVER = ./node_modules/.bin/webpack serve --mode development
all: compile deploy clean
compile:
compile: compile-load-test
$(WEBPACK)
compile-load-test:
${NPM} install --prefix resources/load-test && ${NPM} run build --prefix resources/load-test
clean:
rm -fr $(BUILD_DIR)
.NOTPARALLEL:
deploy: deploy-init deploy-appbundle deploy-rnnoise-binary deploy-tflite deploy-meet-models deploy-lib-jitsi-meet deploy-olm deploy-tf-wasm deploy-css deploy-local deploy-face-landmarks
deploy: deploy-init deploy-appbundle deploy-rnnoise-binary deploy-tflite deploy-meet-models deploy-lib-jitsi-meet deploy-libflac deploy-olm deploy-tf-wasm deploy-css deploy-local deploy-face-landmarks
deploy-init:
rm -fr $(DEPLOY_DIR)
@@ -40,6 +44,8 @@ deploy-appbundle:
$(BUILD_DIR)/do_external_connect.min.js.map \
$(BUILD_DIR)/external_api.min.js \
$(BUILD_DIR)/external_api.min.js.map \
$(BUILD_DIR)/flacEncodeWorker.min.js \
$(BUILD_DIR)/flacEncodeWorker.min.js.map \
$(BUILD_DIR)/dial_in_info_bundle.min.js \
$(BUILD_DIR)/dial_in_info_bundle.min.js.map \
$(BUILD_DIR)/alwaysontop.min.js \
@@ -64,6 +70,12 @@ deploy-lib-jitsi-meet:
$(LIBJITSIMEET_DIR)/modules/browser/capabilities.json \
$(DEPLOY_DIR)
deploy-libflac:
cp \
$(LIBFLAC_DIR)/libflac4-1.3.2.min.js \
$(LIBFLAC_DIR)/libflac4-1.3.2.min.js.mem \
$(DEPLOY_DIR)
deploy-olm:
cp \
$(OLM_DIR)/olm.wasm \
@@ -91,10 +103,10 @@ deploy-meet-models:
deploy-face-landmarks:
cp \
$(FACE_MODELS_DIR)/blazeface-front.bin \
$(FACE_MODELS_DIR)/blazeface-front.json \
$(FACE_MODELS_DIR)/emotion.bin \
$(FACE_MODELS_DIR)/emotion.json \
$(FACE_MODELS_DIR)/tiny_face_detector_model-weights_manifest.json \
$(FACE_MODELS_DIR)/tiny_face_detector_model.bin \
$(FACE_MODELS_DIR)/face_expression_model-weights_manifest.json \
$(FACE_MODELS_DIR)/face_expression_model.bin \
$(DEPLOY_DIR)
deploy-css:
@@ -106,7 +118,7 @@ deploy-local:
([ ! -x deploy-local.sh ] || ./deploy-local.sh)
.NOTPARALLEL:
dev: deploy-init deploy-css deploy-rnnoise-binary deploy-tflite deploy-meet-models deploy-lib-jitsi-meet deploy-olm deploy-tf-wasm deploy-face-landmarks
dev: deploy-init deploy-css deploy-rnnoise-binary deploy-tflite deploy-meet-models deploy-lib-jitsi-meet deploy-libflac deploy-olm deploy-tf-wasm deploy-face-landmarks
$(WEBPACK_DEV_SERVER)
source-package:

View File

@@ -1,7 +1,8 @@
<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>

View File

@@ -26,5 +26,5 @@ android.useAndroidX=true
android.enableJetifier=true
android.bundle.enableUncompressedNativeLibs=false
appVersion=22.3.0
sdkVersion=5.2.0
appVersion=22.2.0
sdkVersion=5.1.0

View File

@@ -76,8 +76,7 @@ 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_CLOSED_CAPTIONS_ENABLED("org.jitsi.meet.SET_CLOSED_CAPTIONS_ENABLED");
SET_VIDEO_MUTED("org.jitsi.meet.SET_VIDEO_MUTED");
private final String action;

View File

@@ -48,10 +48,4 @@ 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;
}
}

View File

@@ -95,7 +95,6 @@ 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;
}

View File

@@ -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, extraData);
JitsiMeetOngoingConferenceService.launch(this);
}
protected void onConferenceTerminated(HashMap<String, Object> extraData) {

View File

@@ -17,22 +17,18 @@
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.
@@ -43,22 +39,16 @@ import java.util.HashMap;
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, HashMap<String, Object> extraData) {
static void launch(Context context) {
OngoingNotification.createOngoingConferenceNotificationChannel();
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
Bundle extraDataBundle = new Bundle();
extraDataBundle.putSerializable(EXTRA_DATA_KEY, extraData);
intent.putExtra(EXTRA_DATA_BUNDLE_KEY, extraDataBundle);
intent.setAction(Action.START.getName());
ComponentName componentName;
@@ -89,15 +79,6 @@ 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();
@@ -120,45 +101,37 @@ 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);
// 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);
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) {
stopSelf();
break;
default:
JitsiMeetLogger.w(TAG + " Unknown action received: " + action);
break;
}
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;
}
return START_NOT_STICKY;
@@ -174,6 +147,7 @@ public class JitsiMeetOngoingConferenceService extends Service
}
public enum Action {
START(TAG + ":START"),
HANGUP(TAG + ":HANGUP"),
MUTE(TAG + ":MUTE"),
UNMUTE(TAG + ":UNMUTE");
@@ -198,15 +172,6 @@ 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
@@ -215,12 +180,10 @@ public class JitsiMeetOngoingConferenceService extends Service
Notification notification = OngoingNotification.buildOngoingConferenceNotification(isAudioMuted);
if (notification == null) {
stopSelf();
JitsiMeetLogger.w(TAG + " Couldn't update service, notification is null");
JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null");
} else {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(OngoingNotification.NOTIFICATION_ID, notification);
JitsiMeetLogger.i(TAG + " audio muted changed");
startForeground(OngoingNotification.NOTIFICATION_ID, notification);
JitsiMeetLogger.i(TAG + " Service started");
}
}
}

View File

@@ -24,7 +24,6 @@ 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;
@@ -126,14 +125,18 @@ public class JitsiMeetView extends BaseReactView<JitsiMeetViewListener>
* page.
*/
public void enterPictureInPicture() {
try {
WebRTCModule pipModule
= ReactInstanceManagerHolder.getNativeModule(
WebRTCModule.class);
pipModule.addDecryptors();
}
catch (Exception e) {
int a = 1;
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");
}
}
}

View File

@@ -28,7 +28,6 @@ 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;
@@ -44,7 +43,7 @@ class PictureInPictureModule extends ReactContextBaseJavaModule {
private static final String TAG = NAME;
private static boolean isSupported;
private boolean isEnabled;
private boolean isDisabled;
public PictureInPictureModule(ReactApplicationContext reactContext) {
super(reactContext);
@@ -85,10 +84,34 @@ class PictureInPictureModule extends ReactContextBaseJavaModule {
*/
@TargetApi(Build.VERSION_CODES.O)
public void enterPictureInPicture() {
WebRTCModule pipModule
= ReactInstanceManagerHolder.getNativeModule(
WebRTCModule.class);
pipModule.addDecryptors();
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");
}
}
/**
@@ -100,15 +123,17 @@ class PictureInPictureModule extends ReactContextBaseJavaModule {
*/
@ReactMethod
public void enterPictureInPicture(Promise promise) {
WebRTCModule pipModule
= ReactInstanceManagerHolder.getNativeModule(
WebRTCModule.class);
pipModule.addDecryptors();
try {
enterPictureInPicture();
promise.resolve(null);
} catch (RuntimeException re) {
promise.reject(re);
}
}
@ReactMethod
public void setPictureInPictureEnabled(Boolean enabled) {
this.isEnabled = enabled;
public void setPictureInPictureDisabled(Boolean disabled) {
this.isDisabled = disabled;
}
public boolean isPictureInPictureSupported() {

View File

@@ -35,8 +35,6 @@ 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;
@@ -59,13 +57,6 @@ 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(
@@ -97,8 +88,6 @@ 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));

View File

@@ -923,35 +923,6 @@ export default {
: isVideoMutedByUser(APP.store);
},
/**
* Verify if there is an ongoing system audio sharing session and apply to the provided track
* as a AudioMixer effect.
*
* @param {*} localAudioTrack - track to which system audio track will be applied as an effect, most likely
* microphone local audio track.
*/
async _maybeApplyAudioMixerEffect(localAudioTrack) {
// At the time of writing this comment there were two separate flows for toggling screen-sharing
// and system audio sharing, the first is the legacy method using the functionality from conference.js
// the second is used when both sendMultipleVideoStreams and sourceNameSignaling flags are set to true.
// The second flow uses functionality from base/conference/middleware.web.js.
// We check if system audio sharing was done using the first flow by verifying this._desktopAudioStream and
// for the second by checking 'features/screen-share' state.
const { desktopAudioTrack } = APP.store.getState()['features/screen-share'];
const currentDesktopAudioTrack = this._desktopAudioStream || desktopAudioTrack;
// If system audio is already being sent, mix it with the provided audio track.
if (currentDesktopAudioTrack) {
// In case system audio sharing was done in the absence of an initial mic audio track, there is no
// AudioMixerEffect so we have to remove system audio track from the room before setting it as an effect.
await room.replaceTrack(currentDesktopAudioTrack, null);
this._mixerEffect = new AudioMixerEffect(currentDesktopAudioTrack);
logger.debug('Mixing new audio track with existing screen audio track.');
await localAudioTrack.setEffect(this._mixerEffect);
}
},
/**
* Simulates toolbar button click for audio mute. Used by shortcuts and API.
* @param {boolean} mute true for mute and false for unmute.
@@ -1005,11 +976,7 @@ export default {
// Rollback the audio muted status by using null track
return null;
})
.then(async audioTrack => {
await this._maybeApplyAudioMixerEffect(audioTrack);
this.useAudioStream(audioTrack);
});
.then(audioTrack => this.useAudioStream(audioTrack));
} else {
muteLocalAudio(mute);
}
@@ -1650,26 +1617,12 @@ export default {
let promise = _prevMutePresenterVideo = _prevMutePresenterVideo.then(() => {
// mute the presenter track if it exists.
if (this.localPresenterVideo) {
return (
this.localPresenterVideo.dispose().then(() => {
APP.store.dispatch(trackRemoved(this.localPresenterVideo));
this.localPresenterVideo = null;
})
.then(() => {
APP.store.dispatch(setVideoMuted(true, MEDIA_TYPE.PRESENTER));
// 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));
})
);
return this.localPresenterVideo.dispose().then(() => {
APP.store.dispatch(trackRemoved(this.localPresenterVideo));
this.localPresenterVideo = null;
});
}
});
@@ -1759,12 +1712,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) {
@@ -2619,7 +2572,13 @@ export default {
return stream;
})
.then(async stream => {
await this._maybeApplyAudioMixerEffect(stream);
// In case screen sharing audio is also shared we mix it with new input stream. The old _mixerEffect
// will be cleaned up when the existing track is replaced.
if (this._mixerEffect) {
this._mixerEffect = new AudioMixerEffect(this._desktopAudioStream);
await stream.setEffect(this._mixerEffect);
}
return this.useAudioStream(stream);
})
@@ -2653,9 +2612,12 @@ 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() === MEDIA_TYPE.VIDEO));
= Boolean(
tracks.find(
track => track.jitsiTrack
&& track.jitsiTrack.getType() === 'video'));
if (isTrackInRedux && !this.isSharingScreen) {
if (!isTrackInRedux) {
this.muteVideo(audioOnly);
}

108
config.js
View File

@@ -295,14 +295,6 @@ 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,
@@ -567,10 +559,6 @@ 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']
// },
@@ -598,17 +586,8 @@ var config = {
// Array with avatar URL prefixes that need to use CORS.
// corsAvatarURLs: [ 'https://www.gravatar.com/avatar/' ],
// Base URL for a Gravatar-compatible service. Defaults to Gravatar.
// DEPRECATED! Use `gravatar.baseUrl` instead.
// gravatarBaseURL: 'https://www.gravatar.com/avatar/',
// Setup for Gravatar-compatible services.
// gravatar: {
// // Defaults to Gravatar.
// baseUrl: 'https://www.gravatar.com/avatar/',
// // True if Gravatar should be disabled.
// disabled: false
// },
// Base URL for a Gravatar-compatible service. Defaults to libravatar.
// gravatarBaseURL: 'https://seccdn.libravatar.org/avatar/',
// App name to be displayed in the invitation email subject, as an alternative to
// interfaceConfig.APP_NAME.
@@ -630,7 +609,6 @@ var config = {
// 'chat',
// 'closedcaptions',
// 'desktop',
// 'dock-iframe'
// 'download',
// 'embedmeeting',
// 'etherpad',
@@ -644,6 +622,8 @@ var config = {
// 'linktosalesforce',
// 'livestreaming',
// 'microphone',
// 'mute-everyone',
// 'mute-video-everyone',
// 'participants-pane',
// 'profile',
// 'raisehand',
@@ -657,7 +637,6 @@ var config = {
// 'stats',
// 'tileview',
// 'toggle-camera',
// 'undock-iframe',
// 'videoquality',
// '__end'
// ],
@@ -784,7 +763,7 @@ var config = {
// enableEmailInStats: false,
// faceLandmarks: {
// // Enables sharing your face coordinates. Used for centering faces within a video.
// // Enables sharing your face cordinates. Used for centering faces within a video.
// enableFaceCentering: false,
// // Enables detecting face expressions and sharing data with other participants
@@ -793,14 +772,11 @@ 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,
// // Milliseconds for processing a new image capture in order to detect face coordinates if they exist.
// captureInterval: 1000
// // Miliseconds for processing a new image capture in order to detect face coordinates if they exist.
// captureInterval: 100
// },
// Controls the percentage of automatic feedback shown to participants when callstats is enabled.
@@ -880,10 +856,6 @@ 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
@@ -958,22 +930,33 @@ 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
@@ -1019,8 +1002,7 @@ var config = {
// Disables all invite functions from the app (share, invite, dial out...etc)
// disableInviteFunctions: true,
// Disables storing the room name to the recents list. When in an iframe this is ignored and
// the room is never stored in the recents list.
// Disables storing the room name to the recents list
// doNotStoreRoom: true,
// Deployment specific URLs.
@@ -1117,24 +1099,22 @@ var config = {
*/
// dynamicBrandingUrl: '',
// Options related to the participants pane.
// participantsPane: {
// // Hides the moderator settings tab.
// hideModeratorSettingsTab: false,
// // Hides the more actions button.
// hideMoreActionsButton: false,
// // Hides the mute all button.
// hideMuteAllButton: false
// },
// Options related to the breakout rooms feature.
// breakoutRooms: {
// // Hides the add breakout room button. This replaces `hideAddRoomButton`.
// hideAddRoomButton: false,
// // Hides the auto assign participants button.
// hideAutoAssignButton: false,
// // Hides the participants pane footer menu.
// hideFooterMenu: false,
// // Hides the join breakout room button.
// hideJoinRoomButton: false
// hideJoinRoomButton: false,
// // Hides the moderator settings tab.
// hideModeratorSettingsTab: false,
// // Hides the more actions button.
// hideMoreActionsButton: false,
// // Hides the mute all button.
// hideMuteAllButton: false
// },
// When true the user cannot add more images to be used as virtual background.
@@ -1163,7 +1143,7 @@ var config = {
// If a label's id is not in any of the 2 arrays, it will not be visible at all on the header.
// conferenceInfo: {
// // those labels will not be hidden in tandem with the toolbox.
// alwaysVisible: ['recording', 'raised-hands-count'],
// alwaysVisible: ['recording', 'local-recording', 'raised-hands-count'],
// // those labels will be auto-hidden in tandem with the toolbox buttons.
// autoHide: [
// 'subject',
@@ -1207,24 +1187,14 @@ var config = {
// will open an etherpad document.
// etherpad_base: 'https://your-etherpad-installati.on/p/',
// To enable information about dial-in access to meetings you need to provide
// dialInNumbersUrl and dialInConfCodeUrl.
// dialInNumbersUrl returns a json array of numbers that can be used for dial-in.
// {"countryCode":"US","tollFree":false,"formattedNumber":"+1 123-456-7890"}
// dialInConfCodeUrl is the conference mapper converting a meeting id to a PIN used for dial-in
// or the other way around (more info in resources/cloud-api.swagger)
//
// For JaaS customers the default values are:
// dialInNumbersUrl: 'https://conference-mapper.jitsi.net/v1/access/dids',
// dialInConfCodeUrl: 'https://conference-mapper.jitsi.net/v1/access',
//
// List of undocumented settings used in jitsi-meet
/**
_immediateReloadThreshold
debug
debugAudioLevels
deploymentInfo
dialInConfCodeUrl
dialInNumbersUrl
dialOutAuthUrl
dialOutCodesUrl
disableRemoteControl
@@ -1309,6 +1279,7 @@ 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
@@ -1354,9 +1325,6 @@ var config = {
// 'transcribing.failedToStart' // shown when transcribing fails to start
// ],
// List of notifications to be disabled. Works in tandem with the above setting.
// disabledNotifications: [],
// Prevent the filmstrip from autohiding when screen width is under a certain threshold
// disableFilmstripAutohiding: false,

View File

@@ -8,8 +8,7 @@ import { LoginDialog } from './react/features/authentication/components';
import { isTokenAuthEnabled } from './react/features/authentication/functions';
import {
connectionEstablished,
connectionFailed,
constructOptions
connectionFailed
} from './react/features/base/connection/actions';
import { openDialog } from './react/features/base/dialog/actions';
import { setJWT } from './react/features/base/jwt';
@@ -20,10 +19,7 @@ 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,
setPrejoinPageVisibility
} from './react/features/prejoin/actions';
import { setPrejoinDisplayNameRequired } from './react/features/prejoin/actions';
const logger = Logger.getLogger(__filename);
/**
@@ -85,10 +81,12 @@ 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) {
export async function connect(id, password, roomName) {
const connectionConfig = Object.assign({}, config);
const state = APP.store.getState();
let { jwt } = state['features/base/jwt'];
const { iAmRecorder, iAmSipGateway } = state['features/base/config'];
@@ -102,7 +100,19 @@ export async function connect(id, password) {
}
}
const connection = new JitsiMeetJS.JitsiConnection(null, jwt, constructOptions(state));
// 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);
if (config.iAmRecorder) {
connection.addFeature(DISCO_JIBRI_FEATURE);
@@ -247,7 +257,6 @@ function requestAuth(roomName) {
resolve(connection);
};
APP.store.dispatch(setPrejoinPageVisibility(false));
APP.store.dispatch(
openDialog(LoginDialog, { onSuccess,
roomName })

View File

@@ -23,26 +23,7 @@
.recording-header-line {
border-top: 1px solid #5e6d7a;
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;
}
padding-top: 32px;
}
.recording-switch-disabled {
@@ -59,7 +40,7 @@
border-radius: 4px;
height: 40px;
justify-content: center;
width: 42px;
width: 56px;
}
.cloud-content-recording-icon-container {
@@ -71,7 +52,7 @@
}
.jitsi-recording-header {
margin-bottom: 16px;
margin-bottom: 32px;
}
.jitsi-content-recording-icon-container-with-switch {

View File

@@ -5,6 +5,8 @@
.remote-videos {
align-items: center;
box-sizing: border-box;
display: flex;
flex-direction: column;
overscroll-behavior: contain;
}

View File

@@ -40,6 +40,7 @@ $flagsImagePath: "../images/";
@import 'modals/invite/info';
@import 'modals/screen-share/share-audio';
@import 'modals/screen-share/share-screen-warning';
@import 'modals/local-recording/local-recording';
@import 'videolayout_default';
@import 'notice';
@import 'subject';

View File

@@ -0,0 +1,92 @@
.localrec-participant-stats {
list-style: none;
padding: 0;
width: 100%;
font-weight: 500;
.localrec-participant-stats-item__status-dot {
position: relative;
display: block;
width: 9px;
height: 9px;
border-radius: 50%;
margin: 0 auto;
&.status-on {
background: green;
}
&.status-off {
background: gray;
}
&.status-unknown {
background: darkgoldenrod;
}
&.status-error {
background: darkred;
}
}
.localrec-participant-stats-item__status,
.localrec-participant-stats-item__name,
.localrec-participant-stats-item__sessionid {
display: inline-block;
margin: 5px 0;
vertical-align: middle;
}
.localrec-participant-stats-item__status {
width: 5%;
}
.localrec-participant-stats-item__name {
width: 40%;
}
.localrec-participant-stats-item__sessionid {
width: 55%;
}
.localrec-participant-stats-item__name,
.localrec-participant-stats-item__sessionid {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.localrec-control-info-label {
font-weight: bold;
}
.localrec-control-info-label:after {
content: ' ';
}
.localrec-control-action-link {
display: inline-block;
line-height: 1.5em;
a {
cursor: pointer;
vertical-align: middle;
}
}
.localrec-control-action-link:before {
color: $linkFontColor;
content: '\2022';
font-size: 1.5em;
padding: 0 10px;
vertical-align: middle;
}
.localrec-control-action-link:first-child:before {
content: '';
padding: 0;
}
.localrec-control-action-links {
font-weight: bold;
margin-top: 10px;
white-space: nowrap;
}

View File

@@ -1,4 +1,5 @@
@import 'lobby';
@import 'premeeting-screens';
@import 'prejoin';
@import 'prejoin-dialog';
@import 'prejoin-third-party';

View File

@@ -0,0 +1,118 @@
.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;
}
}

View File

@@ -3,25 +3,6 @@
width: 100%;
}
&-avatar {
margin: 8px auto 16px;
&-name {
color: white;
font-size: 16px;
font-weight: 600;
line-height: 26px;
margin-bottom: 32px;
text-align: center;
}
&-container {
align-items: center;
display: flex;
flex-direction: column;
}
}
&-error {
background-color: #E04757;
border-radius: 6px;

4
debian/control vendored
View File

@@ -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, lua-basexx, lua-luaossl, lua-cjson
Depends: openssl, prosody (>= 0.11.0) | prosody-trunk | prosody-0.12 | prosody-0.11, lua-sec
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
Depends: ${misc:Depends}, prosody-trunk | prosody-0.11 | prosody-0.12 | prosody (>= 0.11.2), libssl-dev, luarocks, jitsi-meet-prosody, git, lua-basexx
Description: Prosody token authentication plugin for Jitsi Meet
Package: jitsi-meet-turnserver

View File

@@ -48,6 +48,11 @@ case "$1" in
db_stop
if [ -f "$PROSODY_HOST_CONFIG" ] ; then
# Install luajwt (also on update, to make sure we get the latest version).
if ! luarocks install luajwtjitsi 3.0-0; then
echo "Failed to install luajwtjitsi - try installing it manually"
fi
# search for the token auth, if this is not enabled this is the
# first time we install tokens package and needs a config change
if ! egrep -q '^\s*authentication\s*=\s*"token"' "$PROSODY_HOST_CONFIG"; then

View File

@@ -14,3 +14,5 @@ resources/robots.txt /usr/share/jitsi-meet/
resources/*.sh /usr/share/jitsi-meet/scripts/
pwa-worker.js /usr/share/jitsi-meet/
manifest.json /usr/share/jitsi-meet/
resources/load-test/*.html /usr/share/jitsi-meet/load-test/
resources/load-test/libs /usr/share/jitsi-meet/load-test/

View File

@@ -137,18 +137,3 @@ Component "lobby.jitmeet.example.com" "muc"
"muc_rate_limit";
"polls";
}
-- Enables dial-in for Jitsi meet components customers
-- Note: make sure you have the following packages installed: lua-basexx, liblua5.3-dev, libssl-dev, luarocks
-- and execute $ sudo luarocks install luajwtjitsi 3.0-0
VirtualHost "jigasi.meet.jitsi"
enabled = false -- Jitsi meet components customers remove this line
modules_enabled = {
"ping";
"bosh";
}
authentication = "token"
app_id = "jitsi";
asap_key_server = "https://jaas-public-keys.jitsi.net/jitsi-components/prod-8x8"
asap_accepted_issuers = { "jaas-components" }
asap_accepted_audiences = { "jigasi.jitmeet.example.com" }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 490 B

BIN
images/jitsiLogo_square.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 713 KiB

After

Width:  |  Height:  |  Size: 298 KiB

View File

@@ -353,7 +353,7 @@ PODS:
- react-native-video/Video (= 5.2.0)
- react-native-video/Video (5.2.0):
- React-Core
- react-native-webrtc (1.100.1):
- react-native-webrtc (1.100.0):
- React-Core
- react-native-webview (11.15.1):
- React-Core
@@ -718,7 +718,7 @@ SPEC CHECKSUMS:
react-native-slider: 6e9b86e76cce4b9e35b3403193a6432ed07e0c81
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
react-native-video: a4c2635d0802f983594b7057e1bce8f442f0ad28
react-native-webrtc: 206a0ac12a5633d2ec4605174d7c9f12f0d674b2
react-native-webrtc: b8f2769386d51a6a8c89778478618fe311226bc3
react-native-webview: ea4899a1056c782afa96dd082179a66cbebf5504
React-perflogger: 30ab8d6db10e175626069e742eead3ebe8f24fd5
React-RCTActionSheet: 4b45da334a175b24dabe75f856b98fed3dfd6201
@@ -749,4 +749,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: bef1335067eaa4e8c558b1248f8ab3948de855bc
COCOAPODS: 1.11.3
COCOAPODS: 1.11.2

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>22.3.0</string>
<string>22.2.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>22.3.0</string>
<string>22.2.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>22.3.0</string>
<string>22.2.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>UISupportedInterfaceOrientations</key>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>22.3.0</string>
<string>22.2.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CLKComplicationPrincipalClass</key>

View File

@@ -12,8 +12,6 @@ DO_GIT_TAG=${GIT_TAG:-0}
echo "Releasing Jitsi Meet SDK ${SDK_VERSION}"
${THIS_DIR}/../../node_modules/react-native-webrtc/tools/downloadBitcode.sh
pushd ${RELEASE_REPO}
# Generate podspec file
@@ -37,7 +35,7 @@ xcodebuild archive \
-sdk iphonesimulator \
-destination='generic/platform=iOS Simulator' \
-archivePath ios/sdk/out/ios-simulator \
ENABLE_BITCODE=YES \
ENABLE_BITCODE=NO \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
xcodebuild archive \
@@ -47,7 +45,7 @@ xcodebuild archive \
-sdk iphoneos \
-destination='generic/platform=iOS' \
-archivePath ios/sdk/out/ios-device \
ENABLE_BITCODE=YES \
ENABLE_BITCODE=NO \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
xcodebuild -create-xcframework \
@@ -63,6 +61,7 @@ pushd ${RELEASE_REPO}
# Put the new files in the repo
cp -a ${PROJECT_REPO}/ios/sdk/out/JitsiMeetSDK.xcframework Frameworks/
cp -a ${PROJECT_REPO}/node_modules/react-native-webrtc/apple/WebRTC.xcframework Frameworks/
# Add all files to git
if [[ $DO_GIT_TAG == 1 ]]; then

View File

@@ -248,8 +248,6 @@ RCT_EXPORT_METHOD(updateDeviceList) {
- (void)audioSessionDidChangeRoute:(RTCAudioSession *)session
reason:(AVAudioSessionRouteChangeReason)reason
previousRoute:(AVAudioSessionRouteDescription *)previousRoute {
DDLogInfo(@"[AudioMode] Route changed, reason: %lu", (unsigned long)reason);
// Update JS about the changes.
[self notifyDevicesChanged];
@@ -261,12 +259,16 @@ RCT_EXPORT_METHOD(updateDeviceList) {
self->forceSpeaker = NO;
self->forceEarpiece = NO;
break;
case AVAudioSessionRouteChangeReasonCategoryChange:
// The category has changed, re-apply our config.
// NB: It's tempting to doa category check here and skip the processing,
// but that won't work. If the config changes but the category remains
// the same we'll still find ourselves here.
case AVAudioSessionRouteChangeReasonCategoryChange: {
// The category has changed. Check if it's the one we want and adjust as
// needed.
RTCAudioSessionConfiguration *currentConfig = [self configForMode:self->activeMode];
if ([session.category isEqualToString:currentConfig.category]) {
// We are in the desired category, nothing to do here.
return;
}
break;
}
default:
return;
}

View File

@@ -27,6 +27,5 @@
- (void)closeChat;
- (void)sendChatMessage:(NSString*)message :(NSString*)to ;
- (void)sendSetVideoMuted:(BOOL)muted;
- (void)sendSetClosedCaptionsEnabled:(BOOL)enabled;
@end

View File

@@ -27,7 +27,6 @@ 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
@@ -50,8 +49,7 @@ RCT_EXPORT_MODULE();
@"OPEN_CHAT": openChatAction,
@"CLOSE_CHAT": closeChatAction,
@"SEND_CHAT_MESSAGE": sendChatMessageAction,
@"SET_VIDEO_MUTED" : setVideoMutedAction,
@"SET_CLOSED_CAPTIONS_ENABLED": setClosedCaptionsEnabledAction
@"SET_VIDEO_MUTED" : setVideoMutedAction
};
};
@@ -75,8 +73,7 @@ RCT_EXPORT_MODULE();
openChatAction,
closeChatAction,
sendChatMessageAction,
setVideoMutedAction,
setClosedCaptionsEnabledAction
setVideoMutedAction
];
}
@@ -208,10 +205,5 @@ 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

View File

@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>5.2.0</string>
<string>5.1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>

View File

@@ -45,6 +45,5 @@
- (void)closeChat;
- (void)sendChatMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to;
- (void)setVideoMuted:(BOOL)muted;
- (void)setClosedCaptionsEnabled:(BOOL)enabled;
@end

View File

@@ -160,11 +160,6 @@ static void initializeViewsMap() {
[externalAPI sendSetVideoMuted:muted];
}
- (void)setClosedCaptionsEnabled:(BOOL)enabled {
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
[externalAPI sendSetClosedCaptionsEnabled:enabled];
}
#pragma mark Private methods
/**

View File

@@ -17,14 +17,14 @@
import UIKit
final class DragGestureController {
var insets: UIEdgeInsets = UIEdgeInsets.zero
var currentPosition: PiPViewCoordinator.Position? = nil
private var frameBeforeDragging: CGRect = CGRect.zero
private weak var view: UIView?
private lazy var panGesture: UIPanGestureRecognizer = {
UIPanGestureRecognizer(target: self,
action: #selector(handlePan(gesture:)))
return UIPanGestureRecognizer(target: self,
action: #selector(handlePan(gesture:)))
}()
func startDragListener(inView view: UIView) {
@@ -40,7 +40,7 @@ final class DragGestureController {
}
@objc private func handlePan(gesture: UIPanGestureRecognizer) {
guard let view = view else { return }
guard let view = self.view else { return }
let translation = gesture.translation(in: view.superview)
let velocity = gesture.velocity(in: view.superview)
@@ -65,7 +65,7 @@ final class DragGestureController {
let velocityMagnitude = magnitude(vector: velocity)
let animationDuration = 0.5
let initialSpringVelocity =
velocityMagnitude / distanceMagnitude / CGFloat(animationDuration)
velocityMagnitude / distanceMagnitude / CGFloat(animationDuration)
frame.origin = CGPoint(x: finalPos.x, y: finalPos.y)
@@ -75,7 +75,8 @@ final class DragGestureController {
initialSpringVelocity: initialSpringVelocity,
options: .curveLinear,
animations: {
view.frame = frame })
view.frame = frame
}, completion: nil)
default:
break
@@ -84,11 +85,9 @@ final class DragGestureController {
private func calculateFinalPosition() -> CGPoint {
guard
let view = view,
let view = self.view,
let bounds = view.superview?.frame
else {
return CGPoint.zero
}
else { return CGPoint.zero }
let currentSize = view.frame.size
let adjustedBounds = bounds.inset(by: insets)
@@ -110,26 +109,19 @@ final class DragGestureController {
goUp = location.y < bounds.midY
}
if (goLeft && goUp) {
currentPosition = .upperLeftCorner
}
let finalPosX: CGFloat =
goLeft
? adjustedBounds.origin.x
: bounds.size.width - insets.right - currentSize.width
let finalPosY: CGFloat =
goUp
? adjustedBounds.origin.y
: bounds.size.height - insets.bottom - currentSize.height
if (!goLeft && goUp) {
currentPosition = .upperRightCorner
}
if (!goLeft && !goUp) {
currentPosition = .lowerRightCorner
}
if (goLeft && !goUp) {
currentPosition = .lowerLeftCorner
}
return currentPosition!.getOriginIn(bounds: adjustedBounds, size: currentSize)
return CGPoint(x: finalPosX, y: finalPosY)
}
private func magnitude(vector: CGPoint) -> CGFloat {
sqrt(pow(vector.x, 2) + pow(vector.y, 2))
return sqrt(pow(vector.x, 2) + pow(vector.y, 2))
}
}

View File

@@ -19,23 +19,16 @@ import UIKit
public typealias AnimationCompletion = (Bool) -> Void
public protocol PiPViewCoordinatorDelegate: class {
func exitPictureInPicture()
}
/// Coordinates the view state of a specified view to allow
/// to be presented in full screen or in a custom Picture in Picture mode.
/// This object will also provide the drag and tap interactions of the view
/// when is presented in Picture in Picture mode.
/// when is presented in Picure in Picture mode.
public class PiPViewCoordinator {
public enum Position {
case lowerRightCorner
case upperRightCorner
case lowerLeftCorner
case upperLeftCorner
}
/// Limits the boundaries of view position on screen when minimized
public var dragBoundInsets: UIEdgeInsets = UIEdgeInsets(top: 25,
left: 5,
@@ -46,15 +39,23 @@ public class PiPViewCoordinator {
}
}
public let initialPositionInSuperView: Position = .lowerRightCorner
public enum Position {
case lowerRightCorner
case upperRightCorner
case lowerLeftCorner
case upperLeftCorner
}
public var initialPositionInSuperview = Position.lowerRightCorner
// Unused. Remove on the next major release.
@available(*, deprecated, message: "The PiP window size is now fixed to 150px.")
public var c: CGFloat = 0.0
public weak var delegate: PiPViewCoordinatorDelegate?
private(set) var isInPiP: Bool = false // true if view is in PiP mode
private(set) var view: UIView
private var currentBounds: CGRect = CGRect.zero
@@ -65,13 +66,6 @@ public class PiPViewCoordinator {
public init(withView view: UIView) {
self.view = view
// Required because otherwise the view will not rotate correctly.
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// Otherwise the enter/exit pip animation looks odd
// when pip window is bottom left, top left or top right,
// because the jitsi view content does not animate, but jumps to the new size immediately.
view.clipsToBounds = true
}
/// Configure the view to be always on top of all the contents
@@ -80,9 +74,7 @@ public class PiPViewCoordinator {
public func configureAsStickyView(withParentView parentView: UIView? = nil) {
guard
let parentView = parentView ?? UIApplication.shared.keyWindow
else {
return
}
else { return }
parentView.addSubview(view)
currentBounds = parentView.bounds
@@ -117,9 +109,6 @@ public class PiPViewCoordinator {
/// around screen, and add a button of top of the view to be able to exit mode
public func enterPictureInPicture() {
isInPiP = true
// Resizing is done by hand when in pip.
view.autoresizingMask = []
animateViewChange()
dragController.startDragListener(inView: view)
dragController.insets = dragBoundInsets
@@ -136,9 +125,6 @@ public class PiPViewCoordinator {
/// exit pip button, and disable the drag gesture
@objc public func exitPictureInPicture() {
isInPiP = false
// Enable autoresizing again, which got disabled for pip.
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
animateViewChange()
dragController.stopDragListener()
@@ -150,7 +136,7 @@ public class PiPViewCoordinator {
let exitSelector = #selector(toggleExitPiP)
tapGestureRecognizer?.removeTarget(self, action: exitSelector)
tapGestureRecognizer = nil
delegate?.exitPictureInPicture()
}
@@ -158,12 +144,6 @@ public class PiPViewCoordinator {
/// screen size changes
public func resetBounds(bounds: CGRect) {
currentBounds = bounds
// Is required because otherwise the pip window is buggy when rotating the device.
// When not in pip then autoresize will do the job.
if (isInPiP) {
view.frame = changeViewRect()
}
}
/// Stop the dragging gesture of the root view
@@ -189,6 +169,7 @@ public class PiPViewCoordinator {
}
// MARK: - Interactions
@objc private func toggleExitPiP() {
if exitPiPButton == nil {
// show button
@@ -205,43 +186,31 @@ public class PiPViewCoordinator {
}
}
func animateViewChange() {
// MARK: - Size calculation
private func animateViewChange() {
UIView.animate(withDuration: 0.25) {
self.view.frame = self.changeViewRect()
self.view.setNeedsLayout()
}
}
private func changeViewRect() -> CGRect {
let bounds = currentBounds
if !isInPiP {
guard isInPiP else {
return bounds
}
// resize to suggested ratio and position to the bottom right
let adjustedBounds = bounds.inset(by: dragBoundInsets)
let size = CGSize(width: 150, height: 150)
let origin = (dragController.currentPosition ?? initialPositionInSuperView).getOriginIn(bounds: adjustedBounds, size: size)
let origin = initialPositionFor(pipSize: size, bounds: adjustedBounds)
return CGRect(x: origin.x, y: origin.y, width: size.width, height: size.height)
}
// MARK: - Animation helpers
private func animateTransition(animations: @escaping () -> Void,
completion: AnimationCompletion?) {
UIView.animate(withDuration: 0.1,
delay: 0,
options: .beginFromCurrentState,
animations: animations,
completion: completion)
}
}
// MARK: -
extension PiPViewCoordinator.Position {
func getOriginIn(bounds: CGRect, size: CGSize) -> CGPoint {
switch self {
private func initialPositionFor(pipSize size: CGSize, bounds: CGRect) -> CGPoint {
switch initialPositionInSuperview {
case .lowerLeftCorner:
return CGPoint(x: bounds.minX, y: bounds.maxY - size.height)
case .lowerRightCorner:
@@ -252,4 +221,16 @@ extension PiPViewCoordinator.Position {
return CGPoint(x: bounds.maxX - size.width, y: bounds.minY)
}
}
// MARK: - Animation helpers
private func animateTransition(animations: @escaping () -> Void,
completion: AnimationCompletion?) {
UIView.animate(withDuration: 0.1,
delay: 0,
options: .beginFromCurrentState,
animations: animations,
completion: completion)
}
}

View File

@@ -77,17 +77,6 @@
"refresh": "حدِّث الرزنامة",
"today": "اليوم"
},
"carmode": {
"actions": {
"leaveMeeting": "اترك الاجتماع",
"selectSoundDevice": "حدد جهاز الصوت"
},
"labels": {
"buttonLabel": "وضع السيارة",
"title": "وضع القيادة الآمنة",
"videoStopped": "تم إيقاف الفيديو الخاص بك"
}
},
"chat": {
"enter": "أدخل الغرفة",
"error": "خطأ: لم تُرسَل رسالتك. السبب: {{error}}",
@@ -116,7 +105,6 @@
},
"chromeExtensionBanner": {
"buttonText": "نزِّل إضافة متصفح كروم",
"buttonTextEdge": "قم بتثبيت ملحق Edge",
"close": "إغلق",
"dontShowAgain": "لا ترني هذه مرة أخرى",
"installExtensionText": "نزِّل الإضافة للدمج مع رزنامة غوغل ورزنامة أوفيس 365"
@@ -208,9 +196,6 @@
"selectADevice": "اختر جهازًا",
"testAudio": "اختبر الصوت"
},
"dialIn": {
"screenTitle": "ملخص الطلب"
},
"dialOut": {
"statusMessage": "{{status}} الآن"
},
@@ -661,8 +646,6 @@
"linkToSalesforceKey": "ربط هذا المُلتقى",
"linkToSalesforceProgress": "جارٍ ربط الاجتماع بـ Salesforce ...",
"linkToSalesforceSuccess": "تم ربط الاجتماع بـ Salesforce",
"localRecordingStarted": "بدأ {{name}} تسجيلًا محليًا.",
"localRecordingStopped": "أوقف {{name}} التسجيل المحلي.",
"me": "أنا",
"moderationInEffectCSDescription": "يرجى رفع اليد إذا كنت تريد مشاركة شاشتك.",
"moderationInEffectCSTitle": "تم حظر مشاركة الشاشة من قبل المشرف",
@@ -818,7 +801,6 @@
"initiated": "بدأ الاتصال",
"joinAudioByPhone": "انضم مع صوت من الجوال",
"joinMeeting": "انضم للمُلتقى",
"joinMeetingInLowBandwidthMode": "الانضمام في وضع النطاق الترددي المنخفض",
"joinWithoutAudio": "انضم دون صوت",
"keyboardShortcuts": "تفعيل اختصارات لوحة المفاتيح",
"linkCopied": "نُسِخ الرابط",
@@ -894,7 +876,6 @@
"limitNotificationDescriptionWeb": "نظرًا للضغط الكبير، سيقيَّد التسجيل إلى {{limit}} د، ولكن إن أردت التسجيل لمدة مفتوحة، جرِّب <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
"linkGenerated": "لقد أنشأنا رابطًا لتسجيلك.",
"live": "مباشر",
"localRecordingWarning": "تأكد من تحديد علامة التبويب الحالية لاستخدام الفيديو والصوت الصحيحين. التسجيل محدود حاليًا بـ 1 كيغابايت ، أي حوالي 100 دقيقة.",
"loggedIn": "مُسجَّل باسم {{userName}}",
"off": "أوقِف التسجيل",
"offBy": "أوقَف {{name}} التسجيل",
@@ -902,7 +883,6 @@
"onBy": "بدأ {{name}} التسجيل",
"pending": "التحضير لتسجيل المُلتقى...",
"rec": "تسجيل",
"saveLocalRecording": "حفظ ملف التسجيل محليا",
"serviceDescription": "ستحفظ خدمة التسجيل الفيديو المستجل",
"serviceDescriptionCloud": "تسجيل سحابي",
"serviceDescriptionCloudInfo": "يتم مسح المُلتقيات المسجلة تلقائيًا بعد 24 ساعة من وقت التسجيل.",
@@ -910,12 +890,10 @@
"sessionAlreadyActive": "هذه الجلسة قيد التسجيل أو البث المباشر.",
"signIn": "دخول",
"signOut": "خروج",
"surfaceError": "الرجاء تحديد علامة التبويب الحالية.",
"unavailable": "عجبًا! {{serviceName}} غير متاحة حاليًا. نعمل على حل المشكلة. حاول مرة أخرى لاحقًا.",
"unavailableTitle": "التسجيل غير متاح",
"uploadToCloud": "تحميل إلى السحابة"
},
"screenshareDisplayName": "شاشة {{name}}",
"sectionList": {
"pullToRefresh": "اسحب للتحديث"
},
@@ -953,7 +931,6 @@
"playSounds": "تشغيل الصوت عند:",
"reactions": "ردود فعل المُلتقى",
"sameAsSystem": "مثل النظام ({{label}})",
"screenTitle": "إعدادات",
"selectAudioOutput": "خرج الصوت",
"selectCamera": "الكاميرا",
"selectMic": "المجهار (المايكروفون)",
@@ -979,7 +956,6 @@
"disableCrashReportingWarning": "أمتأكد من تعطيل تقارير الأعطال التقنية؟ ستسري الإعدادات الجديدة بعد إعادة تشغيل التطبيق",
"disableP2P": "تعطيل وضع واحد شخص-لشخص",
"displayName": "عرض الاسم",
"displayNamePlaceholderText": "على سبيل المثال: علي الحيدري",
"email": "البريد الإلكتروني",
"header": "الإعدادات",
"profileSection": "الملف الشخصي",
@@ -1033,12 +1009,10 @@
"boo": "Boo",
"breakoutRoom": "الانضمام / مغادرة غرفة فرعية",
"callQuality": "اضبط دقة الفيديو",
"carmode": "وضع السيارة",
"cc": "اظهِر/اخفِ الترجمة",
"chat": "اظهِر/اخفِ نافذة الدردشة",
"clap": "تصفيق",
"collapse": "قلّص",
"dock": "إرساء في النافذة الرئيسية",
"document": "اظهِر/اخفِ الملف المشارك",
"download": "نزِّل التطبيق",
"embedMeeting": "ضمِّن المُلتقى",
@@ -1089,7 +1063,6 @@
"tileView": "اظهِر/اخفِ عرض العنوان",
"toggleCamera": "بدِّل الكاميرا",
"toggleFilmstrip": "بدِّل وضع الشريط السينمائي (filmstrip)",
"undock": "فك في نافذة منفصلة",
"videoblur": "استعمل/اخرج من وضع تغبيش خلفية الفيديو",
"videomute": "بدِّل وضع اخفاء الفيديو"
},
@@ -1106,7 +1079,6 @@
"closeChat": "أغلق الدردشة",
"closeReactionsMenu": "إغلاق قائمة ردود الفعل",
"disableReactionSounds": "يمكنك تعطيل أصوات ردود الفعل لهذا المُلتقى",
"dock": "إرساء في النافذة الرئيسية",
"documentClose": "أغلق الملف المشارك",
"documentOpen": "افتح الملف المشارك",
"download": "نزِّل التطبيق",
@@ -1175,7 +1147,6 @@
"talkWhileMutedPopup": "أتحاول التحدث؟ المجهار مكتوم لديك.",
"tileViewToggle": "بدِّل عنوان العرض",
"toggleCamera": "بدِّل الكاميرا",
"undock": "فك في نافذة منفصلة",
"videoSettings": "اعدادات الفيديو",
"videomute": "استعمل / أوقف الكاميرا"
},

View File

@@ -31,7 +31,6 @@
},
"audioDevices": {
"bluetooth": "Bluetooth",
"car": "Àudio del cotxe",
"headphones": "Auriculars",
"none": "No hi ha disponible cap aparell d'àudio",
"phone": "Telèfon",
@@ -40,6 +39,9 @@
"audioOnly": {
"audioOnly": "Poca amplada de banda"
},
"blankPage": {
"meetingEnded": "La reunió ha acabat"
},
"breakoutRooms": {
"actions": {
"add": "Afegeix una sala de descans",
@@ -77,22 +79,10 @@
"refresh": "Actualitza l'agenda",
"today": "Avui"
},
"carmode": {
"actions": {
"leaveMeeting": "Abandona la reunió",
"selectSoundDevice": "Seleccioneu l'aparell d'àudio"
},
"labels": {
"buttonLabel": "Mode cotxe",
"title": "Mode conducció segura",
"videoStopped": "El vídeo està aturat"
}
},
"chat": {
"enter": "Entra a la sala",
"error": "Error: no s'ha enviat el missatge. Raó: {{error}}",
"fieldPlaceHolder": "Escriviu aquí el missatge",
"lobbyChatMessageTo": "Envia un missatge en la sala d'espera a {{recipient}}",
"message": "Missatge",
"messageAccessibleTitle": "{{user}} diu:",
"messageAccessibleTitleMe": "jo dic:",
@@ -218,15 +208,13 @@
"Remove": "Elimina",
"Share": "Comparteix",
"Submit": "Tramet",
"WaitForHostMsg": "La conferència encara no ha començat. Si en sou l'amfitrió, autentiqueu-vos. Altrament, espereu que arribi l'amfitrió.",
"WaitForHostMsg": "La conferència encara no ha començat. Si en sou l'amfitrió autentiqueu-vos. Altrament, espereu que arribi l'amfitrió.",
"WaitingForHostTitle": "S'està esperant l'amfitrió...",
"Yes": "Sí",
"accessibilityLabel": {
"liveStreaming": "Transmissió en directe"
},
"add": "Afegeix",
"addMeetingNote": "Afegiu una nota sobre aquesta reunió",
"addOptionalNote": "Afegeix una nota (opcional):",
"allow": "Permet",
"alreadySharedVideoMsg": "Un altre participant està compartint un vídeo. Aquesta conferència només permet compartir un vídeo a la vegada.",
"alreadySharedVideoTitle": "Només es permet un vídeo compartit a la vegada",
@@ -278,8 +266,6 @@
"kickParticipantDialog": "Esteu segur que voleu expulsar aquest participant?",
"kickParticipantTitle": "Voleu expulsar aquest participant?",
"kickTitle": "Ep! {{participantDisplayName}} us ha expulsat de la reunió",
"linkMeeting": "Enllaça la reunió",
"linkMeetingTitle": "Enllaça la reunió a Salesforce",
"liveStreaming": "Transmissió en directe",
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "No és possible mentre l'enregistrament estigui actiu",
"liveStreamingDisabledTooltip": "No es pot iniciar la transmissió en directe.",
@@ -334,7 +320,6 @@
"popupError": "El vostre navegador bloca les finestres emergents d'aquest lloc. Habiliteu les finestres emergents a la configuració de seguretat del navegador i torneu-ho a intentar.",
"popupErrorTitle": "Finestres emergents blocades",
"readMore": "més",
"recentlyUsedObjects": "Els objectes que heu usat recentment",
"recording": "Enregistrament",
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "No és possible mentre hi ha una transmissió en directe activa",
"recordingDisabledTooltip": "No es pot enregistrar.",
@@ -357,12 +342,6 @@
"screenSharingFailed": "Ep! Alguna cosa ha anat malament, no hem pogut iniciar la compartició de pantalla!",
"screenSharingFailedTitle": "La compartició de pantalla ha fallat!",
"screenSharingPermissionDeniedError": "Ep! Alguna cosa ha anat malament amb els permisos de compartició de pantalla. Torna a carregar-la i prova-ho una altra vegada.",
"searchInSalesforce": "Cerca a Salesforce",
"searchResults": "Resultats de la cerca({{count}})",
"searchResultsDetailsError": "Alguna cosa ha anat malament en recuperar les dades del propietari.",
"searchResultsError": "Alguna cosa ha anat malament en recuperar les dades.",
"searchResultsNotFound": "No s'ha trobat cap resultat.",
"searchResultsTryAgain": "Proveu usant paraules clau alternatives.",
"sendPrivateMessage": "Fa poc que heu rebut un missatge privat. Voleu respondre'l de forma privada, o voleu enviar el missatge al grup?",
"sendPrivateMessageCancel": "Envia'l al grup",
"sendPrivateMessageOk": "Envia'l en privat",
@@ -372,22 +351,20 @@
"sessionRestarted": "La trucada s'ha reiniciat a causa d'un problema de connexió.",
"shareAudio": "Continua",
"shareAudioTitle": "Com compartir l'àudio",
"shareAudioWarningD1": "cal que atureu la compartició de pantalla abans de compartir l'àudio.",
"shareAudioWarningD2": "cal que reinicieu la compartició de pantalla i marqueu l'opció «Comparteix l'àudio».",
"shareAudioWarningD1": "heu d'aturar la compartició de pantalla abans de compartir l'àudio.",
"shareAudioWarningD2": "heu de reiniciar la compartició de pantalla i marcar l'opció «Comparteix l'àudio».",
"shareAudioWarningH1": "Si voleu compartir només l'àudio:",
"shareAudioWarningTitle": "Cal que atureu la compartició de pantalla abans de compartir l'àudio",
"shareAudioWarningTitle": "Heu d'aturar la compartició de pantalla abans de compartir l'àudio",
"shareMediaWarningGenericH2": "Si voleu compartir la pantalla i l'àudio",
"shareScreenWarningD1": "heu d'aturar l'ús compartit d'àudio abans de compartir la pantalla.",
"shareScreenWarningD2": "heu d'aturar l'ús compartit d'àudio, iniciar l'ús compartit de la pantalla i marcar l'opció «Comparteix l'àudio».",
"shareScreenWarningH1": "Si només voleu compartir la pantalla:",
"shareScreenWarningTitle": "Cal que atureu l'ús compartit d'àudio abans de compartir la pantalla",
"shareScreenWarningTitle": "Heu d'aturar l'ús compartit d'àudio abans de compartir la pantalla",
"shareVideoLinkError": "Proporcioneu un enllaç de vídeo correcte.",
"shareVideoTitle": "Comparteix el vídeo",
"shareYourScreen": "Comparteix la pantalla",
"shareYourScreenDisabled": "S'ha inhabilitat la compartició de pantalla.",
"sharedVideoDialogError": "Error: URL no vàlid",
"sharedVideoLinkPlaceholder": "Enllaç de YouTube o enllaç directe del vídeo",
"start": "Inicia",
"startLiveStreaming": "Inicia la transmissió en directe",
"startRecording": "Inicia l'enregistrament",
"startRemoteControlErrorMessage": "S'ha produït un error en intentar iniciar la sessió de control remot!",
@@ -430,10 +407,6 @@
"veryBad": "Molt dolenta",
"veryGood": "Molt bona"
},
"giphy": {
"noResults": "No s'ha trobat cap resultat :(",
"search": "Cerca a GIPHY"
},
"helpView": {
"header": "Centre d'ajuda"
},
@@ -500,7 +473,6 @@
"focusLocal": "Focus al vostre vídeo",
"focusRemote": "Focus en el vídeo d'una altra persona",
"fullScreen": "Entra o surt de la pantalla completa",
"giphyMenu": "Mostra o amaga el menú GIPHY",
"keyboardShortcuts": "Dreceres de teclat",
"localRecording": "Mostra o amaga els controls d'enregistrament local",
"mute": "Silencia o activa el so",
@@ -555,7 +527,6 @@
"admitAll": "Admet tothom",
"allow": "Permet",
"backToKnockModeButton": "Demaneu per a unir-vos",
"chat": "Xat",
"dialogTitle": "Mode de sala d'espera",
"disableDialogContent": "El mode de sala d'espera es troba activat. Aquesta funcionalitat evita que els participants no desitjats puguin unir-se a la reunió. Voleu desactivar-ho?",
"disableDialogSubmit": "Desactiva",
@@ -568,7 +539,6 @@
"errorMissingPassword": "Introduïu la contrasenya de la reunió",
"invalidPassword": "La contrasenya no és vàlida",
"joinRejectedMessage": "La vostra sol·licitud ha estat rebutjada per un moderador.",
"joinRejectedTitle": "S'ha rebutjat la petició d'unir-s'hi.",
"joinTitle": "Entra a la reunió",
"joinWithPasswordMessage": "S'està intentant unir-s'hi amb contrasenya, espereu...",
"joiningMessage": "Us unireu a la reunió de seguida que algú accepti la sol·licitud",
@@ -577,8 +547,6 @@
"knockButton": "Demana d'unir-se",
"knockTitle": "Algú vol unir-se a la reunió",
"knockingParticipantList": "Llista de participants que piquen per a entrar",
"lobbyChatStartedNotification": "{{moderator}} ha començat un xat en la sala d'espera amb {{attendee}}",
"lobbyChatStartedTitle": "{{moderator}} ha començat un xat en la sala d'espera amb vós.",
"nameField": "Introduïu el vostre nom",
"notificationLobbyAccessDenied": "{{originParticipantName}} ha rebutjat l'entrada de {{targetParticipantName}}",
"notificationLobbyAccessGranted": "{{originParticipantName}} ha acceptat l'entrada de {{targetParticipantName}}",
@@ -641,7 +609,6 @@
"displayNotifications": "Mostra les notificacions sobre",
"focus": "Focus de la conferència",
"focusFail": "{{component}} no és disponible, torneu a intentar en {{ms}} segons",
"gifsMenu": "GIPHY",
"groupTitle": "Notificacions",
"hostAskedUnmute": "El moderador vol que parleu",
"invitedOneMember": "S'ha convidat {{name}}",
@@ -651,12 +618,6 @@
"leftOneMember": "{{name}} ha sortit de la reunió",
"leftThreePlusMembers": "{{name}} i molts d'altres han sortit de la reunió",
"leftTwoMembers": "{{first}} i {{second}} han sortit de la reunió",
"linkToSalesforce": "Enllaç a Salesforce",
"linkToSalesforceDescription": "Podeu enllaçar el resum de la reunió a un objecte Salesforce.",
"linkToSalesforceError": "No s'ha pogut enllaçar la reunió a Salesforce",
"linkToSalesforceKey": "Enllaça aquesta reunió",
"linkToSalesforceProgress": "S'està enllaçant la reunió a Salesforce...",
"linkToSalesforceSuccess": "La reunió s'ha enllaçat a Salesforce",
"me": "Jo",
"moderationInEffectCSDescription": "Aixequeu la mà si voleu compartir la pantalla.",
"moderationInEffectCSTitle": "El moderador ha blocat la compartició de pantalla",
@@ -680,8 +641,6 @@
"oldElectronClientDescription1": "Sembla que useu una versió antiga del client Jitsi Meet, que té vulnerabilitats de seguretat conegudes. Assegureu-vos d'actualitzar-lo",
"oldElectronClientDescription2": "última construcció",
"oldElectronClientDescription3": "ara!",
"participantWantsToJoin": "Vol unir-se a la reunió",
"participantsWantToJoin": "Volen unir-se a la reunió",
"passwordRemovedRemotely": "Un altre participant ha eliminat $t(lockRoomPasswordUppercase)",
"passwordSetRemotely": "Un altre participant ha establert la $t(lockRoomPassword)",
"raiseHandAction": "Aixeca la mà",
@@ -689,7 +648,7 @@
"raisedHands": "{{participantName}} i {{raisedHands}} persones més",
"reactionSounds": "Desactiva el so",
"reactionSoundsForAll": "Desactiva el so per a tothom",
"screenShareNoAudio": "No s'ha marcat la compartició d'àudio en la pantalla de selecció de la finestra.",
"screenShareNoAudio": "La casella Comparteix l'àudio no s'ha marcat a la pantalla de selecció de la finestra.",
"screenShareNoAudioTitle": "No s'ha pogut compartir l'àudio del sistema!",
"selfViewTitle": "Sempre podeu activar la vista pròpia des de la configuració",
"somebody": "Algú",
@@ -701,9 +660,7 @@
"videoMutedRemotelyDescription": "Sempre la podeu activar de nou.",
"videoMutedRemotelyTitle": "{{participantDisplayName}} us ha apagat el vídeo",
"videoUnmuteBlockedDescription": "L'activació de la càmera i la compartició d'escriptori s'han blocat temporalment per limitacions del sistema.",
"videoUnmuteBlockedTitle": "L'activació de la càmera i la compartició d'escriptori estan blocades!",
"viewLobby": "Mostra la sala d'espera",
"waitingParticipants": "{{waitingParticipants}} persones"
"videoUnmuteBlockedTitle": "L'activació de la càmera i la compartició d'escriptori estan blocades!"
},
"participantsPane": {
"actions": {
@@ -735,7 +692,6 @@
},
"passwordDigitsOnly": "Fins a {{number}} dígits",
"passwordSetRemotely": "Establerta per un altre participant",
"pinnedParticipant": "El participant està fixat",
"polls": {
"answer": {
"skip": "Omet",
@@ -792,7 +748,7 @@
"veryPoorConnection": "És esperable que la qualitat de la trucada sigui realment terrible.",
"videoFreezing": "És esperable que el vídeo es congeli, passi a negre i aparegui pixelat.",
"videoHighQuality": "És esperable que el vídeo tingui una bona qualitat.",
"videoLowQuality": "És esperable que el vídeo sigui de poca qualitat en termes de fotogrames per segon i resolució.",
"videoLowQuality": "És esperable que el vídeo sigui de poca qualitat en termes de marcs per segon i resolució.",
"videoTearing": "És esperable que el vídeo aparegui pixelat o amb defectes visuals."
},
"copyAndShare": "Copia i comparteix l'enllaç de la reunió",
@@ -851,18 +807,6 @@
},
"raisedHand": "Vull parlar",
"raisedHandsLabel": "Nombre de mans aixecades",
"record": {
"already": {
"linked": "La reunió ja està enllaçada amb aquest objecte de Salesforce."
},
"type": {
"account": "Compte",
"contact": "Contacte",
"lead": "Principal",
"opportunity": "Oportunitat",
"owner": "Propietari"
}
},
"recording": {
"authDropboxText": "Puja a Dropbox",
"availableSpace": "Espai disponible: {{spaceLeft}} MB (aproximadament {{duration}} minuts d'enregistrament)",
@@ -876,12 +820,7 @@
"expandedOn": "S'està enregistrant la reunió.",
"expandedPending": "S'ha iniciat l'enregistrament...",
"failedToStart": "No s'ha pogut iniciar l'enregistrament",
"fileSharingdescription": "Compartiu l'enllaç de l'enregistrament de la reunió amb els participants",
"highlight": "Destaca",
"highlightMoment": "Destaca el moment",
"highlightMomentDisabled": "Podeu destacar moment en iniciar-se l'enregistrament",
"highlightMomentSuccess": "Moment destacat",
"highlightMomentSucessDescription": "S'ha afegit el moment destacat al resum de la reunió.",
"fileSharingdescription": "Comparteix l'enregistrament amb els participants de la reunió",
"inProgress": "L'enregistrament o la transmissió en directe és en progrés",
"limitNotificationDescriptionNative": "A causa de la gran demanda, el vostre enregistrament es limitarà a {{limit}} min. Per a enregistraments il·limitats, proveu <3>{{app}}</3>.",
"limitNotificationDescriptionWeb": "A causa de la gran demanda, l'enregistrament es limitarà a {{limit}} min. Per a enregistraments il·limitats, proveu <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
@@ -896,7 +835,6 @@
"rec": "ENREG",
"serviceDescription": "El servei d'enregistrament desarà el vostre enregistrament",
"serviceDescriptionCloud": "Enregistrament al núvol",
"serviceDescriptionCloudInfo": "Les reunions enregistrades s'esborren automàticament 24 hores després de l'enregistrament.",
"serviceName": "Servei d'enregistrament",
"sessionAlreadyActive": "Aquesta sessió ja s'està enregistrant o emetent en directe.",
"signIn": "Inicia la sessió",
@@ -905,7 +843,6 @@
"unavailableTitle": "L'enregistrament no és disponible",
"uploadToCloud": "Puja al núvol"
},
"screenshareDisplayName": "Pantalla de: {{name}}",
"sectionList": {
"pullToRefresh": "Estireu per a actualitzar"
},
@@ -925,14 +862,13 @@
},
"desktopShareFramerate": "Velocitat de fotogrames en la compartició d'escriptori",
"desktopShareHighFpsWarning": "Una velocitat de fotogrames més alta per a compartir escriptori pot afectar l'amplada de banda. Heu de reiniciar la compartició de pantalla perquè la nova configuració tingui efecte.",
"desktopShareWarning": "Cal que reinicieu la compartició de pantalla perquè la nova configuració tingui efecte.",
"desktopShareWarning": "Heu de reiniciar la compartició de pantalla perquè la nova configuració tingui efecte.",
"devices": "Aparells",
"followMe": "Tothom que em segueix",
"framesPerSecond": "fotogrames per segon",
"framesPerSecond": "marcs per segon",
"incomingMessage": "Missatge entrant",
"language": "Llengua",
"loggedIn": "Sessió iniciada com a {{name}}",
"maxStageParticipants": "El nombre màxim de participants que es poden fixar en la escena principal",
"microphones": "Micròfons",
"moderator": "Moderador",
"more": "Més",
@@ -985,7 +921,6 @@
"speakerStats": {
"angry": "Enuig",
"disgusted": "Disgust",
"displayEmotions": "Mostra les emocions",
"fearful": "Temor",
"happy": "Felicitat",
"hours": "{{count}}h",
@@ -1020,19 +955,16 @@
"boo": "Esbroncada",
"breakoutRoom": "Entra o surt de la sala de descans",
"callQuality": "Gestiona la qualitat de la trucada",
"carmode": "Mode cotxe",
"cc": "Activa o desactiva els subtítols",
"chat": "Obre o tanca el xat",
"clap": "Picament de mans",
"collapse": "Col·lapsa",
"dock": "Acobla a la finestra principal",
"document": "Activa o desactiva el document compartit",
"download": "Baixeu les nostres aplicacions",
"embedMeeting": "Insereix la reunió",
"expand": "Expandeix",
"feedback": "Deixa comentaris",
"fullScreen": "Activa o desactiva la pantalla completa",
"giphy": "Mostra o amaga el menú GIPHY",
"grantModerator": "Concedir drets de moderador",
"hangup": "Surt de la reunió",
"help": "Ajuda",
@@ -1040,7 +972,6 @@
"kick": "Expulsa el participant",
"laugh": "Riure",
"like": "Polzes amunt",
"linkToSalesforce": "Enllaç a Salesforce",
"lobbyButton": "Activa o desactiva la sala d'espera",
"localRecording": "Activa o desactiva els controls d'enregistrament local",
"lockRoom": "Activa o desactiva la contrasenya de la reunió",
@@ -1063,11 +994,10 @@
"remoteVideoMute": "Desactiva la càmera del participant",
"security": "Opcions de seguretat",
"selectBackground": "Trieu un fons",
"selfView": "Mostra o amaga la visualització d'un mateix",
"shareRoom": "Convida-hi algú",
"shareYourScreen": "Inicia o atura la compartició de pantalla",
"shareaudio": "Comparteix l'àudio",
"sharedvideo": "Mostra o amaga la compartició de vídeo",
"sharedvideo": "Activa o desactiva la compartició de vídeo",
"shortcuts": "Activa o desactiva les dreceres",
"show": "Mostra-ho en l'escena",
"silence": "Silenci",
@@ -1076,7 +1006,6 @@
"tileView": "Activa o desactiva el mode mosaic",
"toggleCamera": "Activa o desactiva la càmera",
"toggleFilmstrip": "Mostra o amaga la cinta",
"undock": "Desacobla en una finestra separada",
"videoblur": "Activa o desactiva el desenfocament del vídeo",
"videomute": "Activa o desactiva la càmera"
},
@@ -1093,7 +1022,6 @@
"closeChat": "Tanca el xat",
"closeReactionsMenu": "Tanca el menú de reaccions",
"disableReactionSounds": "Podeu desactivar els sons de reacció per a aquesta reunió",
"dock": "Acobla en la finestra principal",
"documentClose": "Tanca el document compartit",
"documentOpen": "Obre el document compartit",
"download": "Baixeu les nostres aplicacions",
@@ -1104,7 +1032,6 @@
"exitFullScreen": "Surt de la pantalla completa",
"exitTileView": "Surt del mode mosaic",
"feedback": "Deixa comentaris",
"giphy": "Mostra o amaga el menú GIPHY",
"hangup": "Surt la reunió",
"help": "Ajuda",
"invite": "Convida-hi persones",
@@ -1112,7 +1039,6 @@
"laugh": "Riure",
"leaveBreakoutRoom": "Surt de la sala de descans",
"like": "Polzes amunt",
"linkToSalesforce": "Enllaç a Salesforce",
"lobbyButtonDisable": "Desactiva el mode de sala d'espera",
"lobbyButtonEnable": "Activa el mode de sala d'espera",
"login": "Inicia sessió",
@@ -1162,7 +1088,6 @@
"talkWhileMutedPopup": "Intenteu parlar? Esteu silenciat.",
"tileViewToggle": "Activa o desactiva el mode mosaic",
"toggleCamera": "Activa o desactiva la càmera",
"undock": "Desacobla en una finestra principal",
"videoSettings": "Paràmetres de vídeo",
"videomute": "Inicia o atura la càmera"
},
@@ -1233,12 +1158,8 @@
"moderator": "Moderador",
"mute": "El participant està silenciat",
"muted": "Silenciat",
"pinToStage": "Fixa a l'escena",
"remoteControl": "Inicia o atura el control remot",
"screenSharing": "El participant està compartint la pantalla",
"show": "Mostra-ho en l'escena",
"showSelfView": "Mostra la visualització d'un mateix",
"unpinFromStage": "Deixa de fixar",
"videoMuted": "La càmera està desactivada",
"videomute": "El participant ha aturat la càmera"
},

View File

@@ -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 partecipanti.",
"failedToAdd": "L'aggiunta di nuovi partecipanti è fallita",
"disabled": "Non puoi invitare persone.",
"failedToAdd": "L'aggiunta di nuove persone è fallita",
"footerText": "La chiamata all'esterno è disabilitata.",
"googleEmail": "Email Google",
"inviteMoreHeader": "Sei l'unico presente nella riunione",
"inviteMoreMailSubject": "Unisciti alla riunione {{appName}}",
"inviteMorePrompt": "Invita altri partecipanti",
"inviteMorePrompt": "Invita altre persone",
"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 partecipanti a questa riunione",
"title": "Invita persone a questa riunione",
"yahooEmail": "Email Yahoo"
},
"audioDevices": {
@@ -77,17 +77,6 @@
"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}}",
@@ -112,7 +101,7 @@
},
"title": "Conversazione",
"titleWithPolls": "Conversazione",
"you": "te"
"you": "tu"
},
"chromeExtensionBanner": {
"buttonText": "Installa l'estensione Chrome",
@@ -315,10 +304,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 audio",
"muteParticipantButton": "Spegni microfono",
"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 video",
"muteParticipantsVideoButton": "Spegni videocamera",
"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?",
@@ -474,10 +463,10 @@
"moreNumbers": "Più numeri",
"noNumbers": "Nessun numero da chiamare.",
"noPassword": "Nessuna",
"noRoom": "Non è stata specificata nessuna riunione da chiamare.",
"noRoom": "Non è stata specificata nessuna stanza da chiamare.",
"numbers": "Numeri da chiamare",
"password": "$t(lockRoomPasswordUppercase):",
"sip": "Indirizzo SIP",
"sip": "SIP address",
"title": "Condividi",
"tooltip": "Invia il collegamento e i numeri telefonici di questa riunione"
},
@@ -629,21 +618,21 @@
"me": "io",
"notify": {
"OldElectronAPPTitle": "Falla di sicurezza!",
"allowAction": "Autorizza",
"allowAction": "Permetti",
"allowedUnmute": "Puoi accendere il microfono, avviare la videocamera, o condividere il tuo schermo.",
"audioUnmuteBlockedDescription": "Lo sblocco dei microfoni è stato temporaneamente bloccato per limiti del sistema.",
"audioUnmuteBlockedDescription": "Lo sblocco dei microfoni è stato temporaneament bloccato per limiti del sistema.",
"audioUnmuteBlockedTitle": "Riattivazione dei microfoni bloccata!",
"chatMessages": "Messaggi delle conversazioni",
"connectedOneMember": "{{name}} è entrato in riunione",
"connectedThreePlusMembers": "{{name}} e altri {{count}} sono entrati in riunione",
"connectedTwoMembers": "{{first}} e {{second}} sono entrati in riunione",
"connectedOneMember": "{{name}} si è connesso",
"connectedThreePlusMembers": "{{name}} e altri {{count}} si sono connessi",
"connectedTwoMembers": "{{first}} e {{second}} si sono connessi",
"disconnected": "disconnesso",
"displayNotifications": "Mostra le notifiche per",
"focus": "Focus su riunione",
"focusFail": "{{component}} non disponibile - riprovo tra {{ms}} sec",
"focusFail": "{{component}} non disponibile - riprova in {{ms}} sec",
"gifsMenu": "GIPHY",
"groupTitle": "Notifiche",
"hostAskedUnmute": "Il moderatore ti dice di accendere il microfono",
"hostAskedUnmute": "Il moderatore vorrebbe che tu parlassi",
"invitedOneMember": "{{displayName}} è stato invitato",
"invitedThreePlusMembers": "Hai invitato {{name}} e altri {{count}}",
"invitedTwoMembers": "Hai invitato {{first}} e {{second}}",
@@ -657,8 +646,6 @@
"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",
@@ -672,10 +659,10 @@
"moderationStoppedTitle": "Moderazione interrotta",
"moderationToggleDescription": "da {{participantDisplayName}}",
"moderator": "Impostati i permessi di moderatore!",
"muted": "Hai iniziato la conversazione con audio disattivato.",
"muted": "Hai iniziato la conversazione con l'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 audio disattivato!",
"mutedTitle": "Hai l'audio disattivato!",
"newDeviceAction": "OK, usala",
"newDeviceAudioTitle": "Trovata nuova origine audio",
"newDeviceCameraTitle": "Trovata nuova videocamera",
@@ -711,10 +698,10 @@
"actions": {
"allow": "Permetti ai partecipanti di:",
"allowVideo": "Autorizza video",
"askUnmute": "Chiedi di accendere microfono",
"askUnmute": "Chiedi di riattivare audio",
"audioModeration": "Riattivare audio",
"blockEveryoneMicCamera": "Blocca audio e video a tutti",
"invite": "Invita partecipanti",
"invite": "Invita persone",
"moreModerationActions": "Altre opzioni di moderazione",
"moreModerationControls": "Altri controlli di moderazione",
"moreParticipantOptions": "Altre opzioni partecipanti",
@@ -727,7 +714,7 @@
"videoModeration": "Riavviare videocamera"
},
"close": "Chiudi",
"header": "Partecipanti e sala d'attesa",
"header": "Partecipanti",
"headings": {
"lobby": "Sala d'attesa ({{count}})",
"participantsList": "Partecipanti alla riunione ({{count}})",
@@ -889,7 +876,6 @@
"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",
@@ -897,7 +883,6 @@
"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.",
@@ -905,17 +890,15 @@
"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"
@@ -947,7 +930,7 @@
"participantLeft": "Partecipante Uscito",
"playSounds": "Suoni attivati",
"reactions": "Reazioni riunione",
"sameAsSystem": "Stesso del computer ({{label}})",
"sameAsSystem": "Come nel sistema ({{label}})",
"selectAudioOutput": "Uscita audio",
"selectCamera": "Videocamera",
"selectMic": "Microfono",
@@ -978,8 +961,8 @@
"profileSection": "Profilo",
"serverURL": "URL del server",
"showAdvanced": "Impostazioni avanzate",
"startWithAudioMuted": "Inizia con audio disattivato",
"startWithVideoMuted": "Inizia con video disattivato",
"startWithAudioMuted": "Inizia con l'audio disattivato",
"startWithVideoMuted": "Avvia con il video disattivato",
"version": "Versione"
},
"share": {
@@ -1020,18 +1003,16 @@
"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",
@@ -1042,51 +1023,50 @@
"grantModerator": "Autorizza moderatore",
"hangup": "Lascia la riunione",
"help": "Aiuto",
"invite": "Invita partecipanti",
"invite": "Invita persone",
"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": "Altre opzioni",
"mute": "Attiva/Disattiva audio",
"moreOptions": "Più 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 nellimmagine",
"pip": "Attiva/disattiva immagine nellimmagine",
"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, o uno solo",
"tileView": "Vedi tutti i partecipanti insieme, o uno solo",
"toggleCamera": "Cambia videocamera",
"toggleFilmstrip": "Attiva/Disattiva pellicola",
"undock": "Sgancia in una finestra separata",
"toggleFilmstrip": "Attiva/disattiva pellicola",
"videoblur": "Sfoca video",
"videomute": "Attiva/Disattiva videocamera"
"videomute": "Attiva/disattiva videocamera"
},
"addPeople": "Aggiungi partecipanti alla chiamata",
"addPeople": "Aggiungi persone alla chiamata",
"audioOnlyOff": "Disabilita modalità per banda limitata",
"audioOnlyOn": "Abilita modalità per banda limitata",
"audioRoute": "Scegli l'uscita audio",
@@ -1094,12 +1074,11 @@
"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",
@@ -1113,7 +1092,7 @@
"giphy": "Menù GIPHY",
"hangup": "Butta giù",
"help": "Aiuto",
"invite": "Invita partecipanti",
"invite": "Invita persone",
"joinBreakoutRoom": "Entra in sottogruppo",
"laugh": "Ridi",
"leaveBreakoutRoom": "Lascia breakout room",
@@ -1124,9 +1103,9 @@
"login": "Accedi",
"logout": "Scollegati",
"lowerYourHand": "Abbassa la mano",
"moreActions": "Altre azioni",
"moreOptions": "Altre opzioni",
"mute": "Attiva/Disattiva microfono",
"moreActions": "Più azioni",
"moreOptions": "Più 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.",
@@ -1142,7 +1121,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",
@@ -1168,12 +1147,11 @@
"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.",
@@ -1198,12 +1176,12 @@
},
"videoSIPGW": {
"busy": "Stiamo lavorando per liberare le risorse. Riprova tra qualche minuto.",
"busyTitle": "Il servizio Riunione al momento è occupato",
"busyTitle": "Il servizio Stanza 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 riunione",
"errorInviteTitle": "Errore nell'invito alla stanza",
"pending": "{{displayName}} è stato invitato"
},
"videoStatus": {
@@ -1240,7 +1218,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",
@@ -1259,7 +1237,7 @@
"image1": "Spiaggia",
"image2": "Parete neutra bianca",
"image3": "Stanza bianca vuota",
"image4": "Lampada da pavimento nera",
"image4": "Lampanda da pavimento nera",
"image5": "Montagna",
"image6": "Foresta",
"image7": "Alba",
@@ -1270,13 +1248,13 @@
"title": "Sfondi",
"uploadedImage": "Carica immagine {{index}}",
"webAssemblyWarning": "Il WebAssembly non è supportato",
"webAssemblyWarningDescription": "Il WebAssembly è disabilitato o non è supportato da questo browser"
"webAssemblyWarningDescription": "Il WebAssembly è disabilitato o non è supportat da questo browser"
},
"volumeSlider": "Sbarra volume",
"welcomepage": {
"accessibilityLabel": {
"join": "Tocca per accedere",
"roomname": "Inserisci nome riunione"
"roomname": "Inserisci nome stanza"
},
"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.",
@@ -1295,7 +1273,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",
@@ -1311,11 +1289,11 @@
"privacy": "Riservatezza",
"recentList": "Recenti",
"recentListDelete": "Cancella",
"recentListEmpty": "La lista delle riunioni recenti è vuota. Partecipa almeno ad una riunione e potrai riavviarla in seguito.",
"recentListEmpty": "La tua lista è vuota. Conversa con qualcuno del tuo team e lo vedrai apparire nella lista delle riunioni recenti.",
"reducedUIText": "Benvenuto in {{app}}!",
"roomNameAllowedChars": "Il nome della riunione non deve contenere questi caratteri: ?, &, :, ', \", %, #.",
"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.",
"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.",
"sendFeedback": "Invia feedback",
"startMeeting": "Inizia riunione",
"terms": "Termini di utilizzo",

View File

@@ -77,17 +77,6 @@
"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}}",
@@ -116,7 +105,6 @@
},
"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"
@@ -195,7 +183,7 @@
"unsupportedBrowser": "Parece que está a usar um browser que não suportamos."
},
"defaultLink": "ex.: {{url}}",
"defaultNickname": "ex.: João Dias",
"defaultNickname": "ex.: João Pedro",
"deviceError": {
"cameraError": "Falha ao aceder à sua câmara",
"cameraPermission": "Erro ao obter permissão para a câmara",
@@ -208,9 +196,6 @@
"selectADevice": "Selecione um dispositivo",
"testAudio": "Tocar um som de teste"
},
"dialIn": {
"screenTitle": "Resumo da marcação"
},
"dialOut": {
"statusMessage": "está agora {{status}}"
},
@@ -292,7 +277,7 @@
"lockRoom": "Adicionar reunião $t(lockRoomPassword)",
"lockTitle": "Bloqueio falhado",
"login": "Entrar",
"logoutQuestion": "Tem a certeza de que quer terminar a sessão e sair da conferência?",
"logoutQuestion": "Tem a certeza de que quer terminar a sessão e interromper a 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",
@@ -361,7 +346,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 Salesforce",
"searchInSalesforce": "Pesquisar na Força de Vendas",
"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.",
@@ -655,14 +640,12 @@
"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 Salesforce",
"linkToSalesforceDescription": "Pode ligar o resumo da reunião a um objecto da Salesforce.",
"linkToSalesforceError": "Falha na ligação da reunião à Salesforce",
"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",
"linkToSalesforceKey": "Ligar esta reunião",
"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.",
"linkToSalesforceProgress": "A ligar a reunião à Força de Vendas...",
"linkToSalesforceSuccess": "A reunião foi ligada à Força de Vendas",
"me": "Eu",
"moderationInEffectCSDescription": "Por favor, levantem a mão se quiserem partilhar o vosso ecrã.",
"moderationInEffectCSTitle": "A partilha de ecrã é bloqueada pelo moderador",
@@ -818,7 +801,6 @@
"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",
@@ -894,7 +876,6 @@
"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",
@@ -902,7 +883,6 @@
"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.",
@@ -910,12 +890,11 @@
"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ã de {{name}}",
"screenshareDisplayName": "ecrã do {{name}}",
"sectionList": {
"pullToRefresh": "Puxe para atualizar"
},
@@ -953,7 +932,6 @@
"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",
@@ -979,7 +957,6 @@
"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",
@@ -1033,12 +1010,10 @@
"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",
@@ -1053,7 +1028,7 @@
"kick": "Remover participante",
"laugh": "Risos",
"like": "Aprovado",
"linkToSalesforce": "Link para a Salesforce",
"linkToSalesforce": "Link para a Força de Vendas",
"lobbyButton": "Ativar/desativar sala de espera",
"localRecording": "Mudar os controlos locais de gravação",
"lockRoom": "Mudar palavra-chave de reunião",
@@ -1089,7 +1064,6 @@
"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"
},
@@ -1106,7 +1080,6 @@
"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",
@@ -1125,7 +1098,7 @@
"laugh": "Risos",
"leaveBreakoutRoom": "Sair da sala",
"like": "Aprovado",
"linkToSalesforce": "Link para a Salesforce",
"linkToSalesforce": "Link para a Força de Vendas",
"lobbyButtonDisable": "Desativar sala de espera",
"lobbyButtonEnable": "Ativar sala de espera",
"login": "Iniciar sessão",
@@ -1175,7 +1148,6 @@
"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"
},

View File

@@ -116,7 +116,6 @@
},
"chromeExtensionBanner": {
"buttonText": "Install Chrome Extension",
"buttonTextEdge": "Install Edge Extension",
"close": "Close",
"dontShowAgain": "Dont show me this again",
"installExtensionText": "Install the extension for Google Calendar and Office 365 integration"
@@ -208,9 +207,6 @@
"selectADevice": "Select a device",
"testAudio": "Play a test sound"
},
"dialIn": {
"screenTitle": "Dial-in summary"
},
"dialOut": {
"statusMessage": "is now {{status}}"
},
@@ -292,7 +288,7 @@
"lockRoom": "Add meeting $t(lockRoomPassword)",
"lockTitle": "Lock failed",
"login": "Login",
"logoutQuestion": "Are you sure you want to logout and leave the conference?",
"logoutQuestion": "Are you sure you want to logout and stop 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",
@@ -661,8 +657,6 @@
"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",
@@ -818,7 +812,6 @@
"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",
@@ -894,8 +887,6 @@
"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",
@@ -903,7 +894,6 @@
"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.",
@@ -911,7 +901,6 @@
"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"
@@ -954,7 +943,6 @@
"playSounds": "Play sound on",
"reactions": "Meeting reactions",
"sameAsSystem": "Same as system ({{label}})",
"screenTitle": "Settings",
"selectAudioOutput": "Audio output",
"selectCamera": "Camera",
"selectMic": "Microphone",
@@ -980,7 +968,6 @@
"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",
@@ -1034,12 +1021,11 @@
"boo": "Boo",
"breakoutRoom": "Join/leave breakout room",
"callQuality": "Manage video quality",
"carmode": "Car Mode",
"carmode": "Carmode",
"cc": "Toggle subtitles",
"chat": "Open / Close chat",
"clap": "Clap",
"collapse": "Collapse",
"dock": "Dock in main window",
"document": "Toggle shared document",
"download": "Download our apps",
"embedMeeting": "Embed meeting",
@@ -1090,7 +1076,6 @@
"tileView": "Toggle tile view",
"toggleCamera": "Toggle camera",
"toggleFilmstrip": "Toggle filmstrip",
"undock": "Undock into separate window",
"videoblur": "Toggle video blur",
"videomute": "Start / Stop camera"
},
@@ -1107,7 +1092,6 @@
"closeChat": "Close chat",
"closeReactionsMenu": "Close reactions menu",
"disableReactionSounds": "You can disable reaction sounds for this meeting",
"dock": "Dock in main window",
"documentClose": "Close shared document",
"documentOpen": "Open shared document",
"download": "Download our apps",
@@ -1176,7 +1160,6 @@
"talkWhileMutedPopup": "Trying to speak? You are muted.",
"tileViewToggle": "Toggle tile view",
"toggleCamera": "Toggle camera",
"undock": "Undock into separate window",
"videoSettings": "Video settings",
"videomute": "Start / Stop camera"
},

View File

@@ -40,8 +40,7 @@ import {
isParticipantModerator,
isLocalParticipantModerator,
hasRaisedHand,
grantModerator,
overwriteParticipantsNames
grantModerator
} from '../../react/features/base/participants';
import { updateSettings } from '../../react/features/base/settings';
import { isToggleCameraEnabled, toggleCamera } from '../../react/features/base/tracks';
@@ -429,11 +428,6 @@ function initCommands() {
logger.error('Failed sending endpoint text message', err);
}
},
'overwrite-names': participantList => {
logger.debug('Overwrite names command received');
APP.store.dispatch(overwriteParticipantsNames(participantList));
},
'toggle-e2ee': enabled => {
logger.debug('Toggle E2EE key command received');
APP.store.dispatch(toggleE2EE(enabled));
@@ -1461,22 +1455,6 @@ class API {
});
}
/**
* Notify external application (if API is enabled) that the iframe
* docked state has been changed. The responsibility for implementing
* the dock / undock functionality lies with the external application.
*
* @param {boolean} docked - Whether or not the iframe has been set to
* be docked or undocked.
* @returns {void}
*/
notifyIframeDockStateChanged(docked: boolean) {
this._sendEvent({
name: 'iframe-dock-state-changed',
docked
});
}
/**
* Notify external application of a participant, remote or local, being
* removed from the conference by another participant.
@@ -1682,32 +1660,6 @@ class API {
});
}
/**
* Notify external application that the breakout rooms changed.
*
* @param {Array} rooms - Array of breakout rooms.
* @returns {void}
*/
notifyBreakoutRoomsUpdated(rooms) {
this._sendEvent({
name: 'breakout-rooms-updated',
rooms
});
}
/**
* Notify the external application that the state of the participants pane changed.
*
* @param {boolean} open - Wether the panel is open or not.
* @returns {void}
*/
notifyParticipantsPaneToggled(open) {
this._sendEvent({
name: 'participants-pane-toggled',
open
});
}
/**
* Disposes the allocated resources.
*

View File

@@ -46,7 +46,6 @@ const commands = {
kickParticipant: 'kick-participant',
muteEveryone: 'mute-everyone',
overwriteConfig: 'overwrite-config',
overwriteNames: 'overwrite-names',
password: 'password',
pinParticipant: 'pin-participant',
rejectParticipant: 'reject-participant',
@@ -95,7 +94,6 @@ const events = {
'avatar-changed': 'avatarChanged',
'audio-availability-changed': 'audioAvailabilityChanged',
'audio-mute-status-changed': 'audioMuteStatusChanged',
'breakout-rooms-updated': 'breakoutRoomsUpdated',
'browser-support': 'browserSupport',
'camera-error': 'cameraError',
'chat-updated': 'chatUpdated',
@@ -110,7 +108,6 @@ const events = {
'feedback-submitted': 'feedbackSubmitted',
'feedback-prompt-displayed': 'feedbackPromptDisplayed',
'filmstrip-display-changed': 'filmstripDisplayChanged',
'iframe-dock-state-changed': 'iframeDockStateChanged',
'incoming-message': 'incomingMessage',
'knocking-participant': 'knockingParticipant',
'log': 'log',
@@ -126,7 +123,6 @@ 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',
@@ -302,7 +298,6 @@ 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();
@@ -319,8 +314,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
invitees,
devices,
userInfo,
e2eeKey,
release
e2eeKey
} = parseArguments(args);
const localStorageContent = jitsiLocalStorage.getItem('jitsiLocalStorage');
@@ -335,8 +329,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
userInfo,
appData: {
localStorageContent
},
release
}
});
this._createIFrame(height, width, onload);
this._transport = new Transport({

View File

@@ -17,7 +17,6 @@ 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';
@@ -181,7 +180,6 @@ function authenticate(room: Object, lockPassword: string) {
if (isTokenAuthEnabled(config) || room.isExternalAuthEnabled()) {
doExternalAuth(room, lockPassword);
} else {
APP.store.dispatch(setPrejoinPageVisibility(false));
APP.store.dispatch(openLoginDialog());
}
}

View File

@@ -160,18 +160,6 @@ export default class LargeVideoManager {
this.videoContainer.removeResizeListener(
this._onVideoResolutionUpdate);
if (getSourceNameSignalingFeatureFlag(APP.store.getState())) {
// Remove track streaming status listener.
// TODO: when this class is converted to a function react component,
// use a custom hook to update a local track streaming status.
if (this.videoTrack && !this.videoTrack.local) {
this.videoTrack.jitsiTrack.off(JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED,
this.handleTrackStreamingStatusChanged);
APP.store.dispatch(trackStreamingStatusChanged(this.videoTrack.jitsiTrack,
this.videoTrack.jitsiTrack.getTrackStreamingStatus()));
}
}
this.removePresenceLabel();
ReactDOM.unmountComponentAtNode(this._dominantSpeakerAvatarContainer);
@@ -272,16 +260,14 @@ export default class LargeVideoManager {
// TODO: when this class is converted to a function react component,
// use a custom hook to update a local track streaming status.
if (this.videoTrack?.jitsiTrack?.getSourceName() !== videoTrack?.jitsiTrack?.getSourceName()) {
if (this.videoTrack && !this.videoTrack.local) {
if (this.videoTrack) {
this.videoTrack.jitsiTrack.off(JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED,
this.handleTrackStreamingStatusChanged);
APP.store.dispatch(trackStreamingStatusChanged(this.videoTrack.jitsiTrack,
this.videoTrack.jitsiTrack.getTrackStreamingStatus()));
}
this.videoTrack = videoTrack;
if (this.videoTrack && !this.videoTrack.local) {
if (videoTrack && !videoTrack.local) {
this.videoTrack = videoTrack;
this.videoTrack.jitsiTrack.on(JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED,
this.handleTrackStreamingStatusChanged);
APP.store.dispatch(trackStreamingStatusChanged(this.videoTrack.jitsiTrack,

448
package-lock.json generated
View File

@@ -34,7 +34,7 @@
"@hapi/bourne": "2.0.0",
"@jitsi/js-utils": "2.0.0",
"@jitsi/logger": "2.0.0",
"@jitsi/rtcstats": "9.2.0",
"@jitsi/rtcstats": "9.0.1",
"@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,12 +49,11 @@
"@react-navigation/elements": "1.2.1",
"@react-navigation/material-top-tabs": "6.0.6",
"@react-navigation/native": "6.0.6",
"@react-navigation/native-stack": "6.6.2",
"@react-navigation/stack": "6.0.11",
"@svgr/webpack": "4.3.2",
"@tensorflow/tfjs-backend-wasm": "3.13.0",
"@tensorflow/tfjs-core": "3.13.0",
"@vladmandic/human": "2.6.5",
"@vladmandic/human-models": "2.5.9",
"@vladmandic/face-api": "1.6.4",
"@xmldom/xmldom": "0.7.5",
"amplitude-js": "8.2.1",
"base64-js": "1.3.1",
@@ -72,9 +71,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/v1457.0.0+ad75454f/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1430.0.0+ccf9ebed/lib-jitsi-meet.tgz",
"libflacjs": "https://git@github.com/mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"lodash": "4.17.21",
"moment": "2.29.2",
"moment-duration-format": "2.2.2",
@@ -94,7 +93,7 @@
"react-native-collapsible": "1.6.0",
"react-native-default-preference": "1.4.4",
"react-native-device-info": "8.4.8",
"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-dialog": "9.2.1",
"react-native-gesture-handler": "2.1.0",
"react-native-get-random-values": "1.7.2",
"react-native-immersive": "2.0.0",
@@ -113,7 +112,7 @@
"react-native-url-polyfill": "1.3.0",
"react-native-video": "https://git@github.com/jitsi/react-native-video#4f6dad990d17ce42894df993780b5386a9c11b85",
"react-native-watch-connectivity": "1.0.4",
"react-native-webrtc": "1.100.1",
"react-native-webrtc": "1.100.0",
"react-native-webview": "11.15.1",
"react-native-youtube-iframe": "2.2.1",
"react-redux": "7.1.0",
@@ -129,7 +128,6 @@
"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"
},
@@ -142,10 +140,6 @@
"@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 +162,7 @@
"style-loader": "0.19.0",
"traverse": "0.6.6",
"ts-loader": "9.2.6",
"typescript": "4.6.4",
"typescript": "4.3.5",
"unorm": "1.6.0",
"webpack": "5.57.1",
"webpack-bundle-analyzer": "4.4.2",
@@ -3551,13 +3545,37 @@
"integrity": "sha512-QZE0NpI/GKRdZK0vhuyFYWr4XkCz4slihkSfy6RTszjj/YEHZKIV7yGJo6Hbs3kYI2h5v7apoy+h2WCOMumPJw=="
},
"node_modules/@jitsi/rtcstats": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.2.0.tgz",
"integrity": "sha512-bGQRLFio25++bi3s0em0xKD+WIqhDwg8OQ71K4BXZNOVL3eVX3R/bxbSEok6UYjFQxwoVjfdM4J8cHUu7RwrQw==",
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.0.1.tgz",
"integrity": "sha512-kImbDneVzU3pBDyY0vOruG96iYnMp2aOeHxYvnHgXGCTQfqF4dcPGtWMucSb5Dz7KEY6+U6G77Kay5C9p9lFjw==",
"dependencies": {
"@jitsi/js-utils": "^2.0.0",
"@jitsi/js-utils": "1.0.0",
"sdp": "^3.0.3",
"uuid": "^8.3.2"
"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"
}
},
"node_modules/@jitsi/sdp-interop": {
@@ -5024,33 +5042,6 @@
"react-native": "*"
}
},
"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": {
"@react-navigation/elements": "^1.3.3",
"warn-once": "^0.1.0"
},
"peerDependencies": {
"@react-navigation/native": "^6.0.0",
"react": "*",
"react-native": "*",
"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",
@@ -5059,6 +5050,24 @@
"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",
"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/@sideway/address": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
@@ -5385,16 +5394,6 @@
"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,36 +5490,15 @@
"dev": true
},
"node_modules/@types/react": {
"version": "17.0.14",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.14.tgz",
"integrity": "sha512-0WwKHUbWuQWOce61UexYuWTGuGY/8JvtUe/dtQ6lR4sZ3UiylHotJeWpf3ArP9+DSGUoLY3wbU59VyMrJps5VQ==",
"version": "17.0.39",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz",
"integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==",
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-native": {
"version": "0.67.6",
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.67.6.tgz",
"integrity": "sha512-NM6atxrefIXMLE/PyQ1bIQjQ/lWLdls3uVxItzKvNUUVZlGqgn/uGN4MarM9quSf90uSqJYPIAeAgTtBTUjhgg==",
"dev": true,
"dependencies": {
"@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",
@@ -5573,12 +5551,6 @@
"@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",
@@ -5606,22 +5578,14 @@
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz",
"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
},
"node_modules/@vladmandic/human": {
"version": "2.6.5",
"resolved": "https://registry.npmjs.org/@vladmandic/human/-/human-2.6.5.tgz",
"integrity": "sha512-5fG5lICkJw17d8fT9ZHtioAPLmOKsQlNN4rbuA1t21HlV7KL3M2EMbYeO+ZE0t6VLSioZZH/KoOFvW5A0JP0Hg==",
"node_modules/@vladmandic/face-api": {
"version": "1.6.4",
"resolved": "https://registry.npmjs.org/@vladmandic/face-api/-/face-api-1.6.4.tgz",
"integrity": "sha512-tVx8lCL1mKb44qeN5EEypJNXqxRYXh+7BcSzfY4iMaZIoF5Y+Jev20UiIn9JvxwGV2caWkdFIjpvw+OxsL/kdg==",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@vladmandic/human-models": {
"version": "2.5.9",
"resolved": "https://registry.npmjs.org/@vladmandic/human-models/-/human-models-2.5.9.tgz",
"integrity": "sha512-WhV0RIeELsA73LGMpemYJvpIEuG0nkh6rP1x7JctKDQkNaARgWolTq9r1RUvWw++rQfzfZ82bYcAauJcaGW6bw==",
"dependencies": {
"@vladmandic/human": "^2.5.8"
}
},
"node_modules/@webassemblyjs/ast": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
@@ -8341,11 +8305,6 @@
"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",
@@ -10680,14 +10639,6 @@
"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",
@@ -11650,11 +11601,6 @@
"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",
@@ -12168,8 +12114,8 @@
},
"node_modules/lib-jitsi-meet": {
"version": "0.0.0",
"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==",
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1430.0.0+ccf9ebed/lib-jitsi-meet.tgz",
"integrity": "sha512-Jce3+uVwV8xn8RG6x49I3xTUdTC1hzwxCsCAYvHkc10wMNHNtWl3jHGNR1MUQHyIbpzM7iGK1trdHnk9pAU/1Q==",
"license": "Apache-2.0",
"dependencies": {
"@jitsi/js-utils": "2.0.0",
@@ -12199,6 +12145,29 @@
"uuid": "dist/bin/uuid"
}
},
"node_modules/libflacjs": {
"version": "4.0.0",
"resolved": "git+https://git@github.com/mmig/libflac.js.git#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"integrity": "sha512-7cscxyqMkeUa5PpHOqhIkXgyrmPqxCzYobtXnrnwXFkY5+tvRjwsZqQQ52Z9K4AebDzpNaApK+NVn+gK4CwWUw==",
"license": "MIT",
"bin": {
"libflac4-1.3.2.dev.js": "dist/dev/libflac4-1.3.2.dev.js",
"libflac4-1.3.2.dev.js.map": "dist/dev/libflac4-1.3.2.dev.js.map",
"libflac4-1.3.2.dev.wasm.js": "dist/dev/libflac4-1.3.2.dev.wasm.js",
"libflac4-1.3.2.dev.wasm.wasm": "dist/dev/libflac4-1.3.2.dev.wasm.wasm",
"libflac4-1.3.2.dev.wasm.wasm.map": "dist/dev/libflac4-1.3.2.dev.wasm.wasm.map",
"libflac4-1.3.2.dev.wasm.wast": "dist/dev/libflac4-1.3.2.dev.wasm.wast",
"libflac4-1.3.2.js": "dist/libflac4-1.3.2.js",
"libflac4-1.3.2.min.js": "dist/min/libflac4-1.3.2.min.js",
"libflac4-1.3.2.min.js.mem": "dist/min/libflac4-1.3.2.min.js.mem",
"libflac4-1.3.2.min.js.symbols": "dist/min/libflac4-1.3.2.min.js.symbols",
"libflac4-1.3.2.min.wasm.js": "dist/min/libflac4-1.3.2.min.wasm.js",
"libflac4-1.3.2.min.wasm.js.symbols": "dist/min/libflac4-1.3.2.min.wasm.js.symbols",
"libflac4-1.3.2.min.wasm.wasm": "dist/min/libflac4-1.3.2.min.wasm.wasm",
"libflac4-1.3.2.wasm.js": "dist/libflac4-1.3.2.wasm.js",
"libflac4-1.3.2.wasm.wasm": "dist/libflac4-1.3.2.wasm.wasm"
}
},
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@@ -14833,6 +14802,11 @@
"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",
@@ -15422,10 +15396,9 @@
}
},
"node_modules/react-native-dialog": {
"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",
"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==",
"peerDependencies": {
"react-native": ">=0.63.0"
}
@@ -16045,9 +16018,9 @@
}
},
"node_modules/react-native-webrtc": {
"version": "1.100.1",
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.100.1.tgz",
"integrity": "sha512-2dF8HrZWdfrbm1NLso424xgNeGFf4WK5Jlqs7ecVDvCMWHTYVHVwyNt52zx1yiOMEqQWk4edOd4xhWJfUiOvMg==",
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.100.0.tgz",
"integrity": "sha512-sBLl8Ihj3xfYn0NZJdDxelB/dZ422FWg/kcLdSw6Wk4eM3MeNW3iFwVsqg2dLzeDnuoQ06i7hOdtP7pGAiKsug==",
"hasInstallScript": true,
"dependencies": {
"base64-js": "1.5.1",
@@ -18675,9 +18648,9 @@
}
},
"node_modules/typescript": {
"version": "4.6.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
"integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@@ -19155,40 +19128,6 @@
"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",
@@ -22694,13 +22633,35 @@
"integrity": "sha512-QZE0NpI/GKRdZK0vhuyFYWr4XkCz4slihkSfy6RTszjj/YEHZKIV7yGJo6Hbs3kYI2h5v7apoy+h2WCOMumPJw=="
},
"@jitsi/rtcstats": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.2.0.tgz",
"integrity": "sha512-bGQRLFio25++bi3s0em0xKD+WIqhDwg8OQ71K4BXZNOVL3eVX3R/bxbSEok6UYjFQxwoVjfdM4J8cHUu7RwrQw==",
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.0.1.tgz",
"integrity": "sha512-kImbDneVzU3pBDyY0vOruG96iYnMp2aOeHxYvnHgXGCTQfqF4dcPGtWMucSb5Dz7KEY6+U6G77Kay5C9p9lFjw==",
"requires": {
"@jitsi/js-utils": "^2.0.0",
"@jitsi/js-utils": "1.0.0",
"sdp": "^3.0.3",
"uuid": "^8.3.2"
"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=="
}
}
},
"@jitsi/sdp-interop": {
@@ -23753,22 +23714,6 @@
"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",
@@ -23777,6 +23722,16 @@
"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",
@@ -24046,16 +24001,6 @@
"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",
@@ -24152,36 +24097,15 @@
"dev": true
},
"@types/react": {
"version": "17.0.14",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.14.tgz",
"integrity": "sha512-0WwKHUbWuQWOce61UexYuWTGuGY/8JvtUe/dtQ6lR4sZ3UiylHotJeWpf3ArP9+DSGUoLY3wbU59VyMrJps5VQ==",
"version": "17.0.39",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz",
"integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==",
"requires": {
"@types/prop-types": "*",
"@types/scheduler": "*",
"csstype": "^3.0.2"
}
},
"@types/react-native": {
"version": "0.67.6",
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.67.6.tgz",
"integrity": "sha512-NM6atxrefIXMLE/PyQ1bIQjQ/lWLdls3uVxItzKvNUUVZlGqgn/uGN4MarM9quSf90uSqJYPIAeAgTtBTUjhgg==",
"dev": true,
"requires": {
"@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",
@@ -24234,12 +24158,6 @@
"@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",
@@ -24267,18 +24185,10 @@
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz",
"integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
},
"@vladmandic/human": {
"version": "2.6.5",
"resolved": "https://registry.npmjs.org/@vladmandic/human/-/human-2.6.5.tgz",
"integrity": "sha512-5fG5lICkJw17d8fT9ZHtioAPLmOKsQlNN4rbuA1t21HlV7KL3M2EMbYeO+ZE0t6VLSioZZH/KoOFvW5A0JP0Hg=="
},
"@vladmandic/human-models": {
"version": "2.5.9",
"resolved": "https://registry.npmjs.org/@vladmandic/human-models/-/human-models-2.5.9.tgz",
"integrity": "sha512-WhV0RIeELsA73LGMpemYJvpIEuG0nkh6rP1x7JctKDQkNaARgWolTq9r1RUvWw++rQfzfZ82bYcAauJcaGW6bw==",
"requires": {
"@vladmandic/human": "^2.5.8"
}
"@vladmandic/face-api": {
"version": "1.6.4",
"resolved": "https://registry.npmjs.org/@vladmandic/face-api/-/face-api-1.6.4.tgz",
"integrity": "sha512-tVx8lCL1mKb44qeN5EEypJNXqxRYXh+7BcSzfY4iMaZIoF5Y+Jev20UiIn9JvxwGV2caWkdFIjpvw+OxsL/kdg=="
},
"@webassemblyjs/ast": {
"version": "1.11.1",
@@ -26426,11 +26336,6 @@
"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",
@@ -28256,11 +28161,6 @@
"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",
@@ -28950,11 +28850,6 @@
"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",
@@ -29369,8 +29264,8 @@
}
},
"lib-jitsi-meet": {
"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==",
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1430.0.0+ccf9ebed/lib-jitsi-meet.tgz",
"integrity": "sha512-Jce3+uVwV8xn8RG6x49I3xTUdTC1hzwxCsCAYvHkc10wMNHNtWl3jHGNR1MUQHyIbpzM7iGK1trdHnk9pAU/1Q==",
"requires": {
"@jitsi/js-utils": "2.0.0",
"@jitsi/logger": "2.0.0",
@@ -29398,6 +29293,11 @@
}
}
},
"libflacjs": {
"version": "git+https://git@github.com/mmig/libflac.js.git#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"integrity": "sha512-7cscxyqMkeUa5PpHOqhIkXgyrmPqxCzYobtXnrnwXFkY5+tvRjwsZqQQ52Z9K4AebDzpNaApK+NVn+gK4CwWUw==",
"from": "libflacjs@https://git@github.com/mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d"
},
"lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@@ -31501,6 +31401,11 @@
}
}
},
"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",
@@ -31941,8 +31846,9 @@
"integrity": "sha512-92676ZWHZHsPM/EW1ulgb2MuVfjYfMWRTWMbLcrCsipkcMaZ9Traz5mpsnCS7KZpsOksnvUinzDIjsct2XGc6Q=="
},
"react-native-dialog": {
"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=="
"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=="
},
"react-native-gesture-handler": {
"version": "2.1.0",
@@ -32312,9 +32218,9 @@
}
},
"react-native-webrtc": {
"version": "1.100.1",
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.100.1.tgz",
"integrity": "sha512-2dF8HrZWdfrbm1NLso424xgNeGFf4WK5Jlqs7ecVDvCMWHTYVHVwyNt52zx1yiOMEqQWk4edOd4xhWJfUiOvMg==",
"version": "1.100.0",
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.100.0.tgz",
"integrity": "sha512-sBLl8Ihj3xfYn0NZJdDxelB/dZ422FWg/kcLdSw6Wk4eM3MeNW3iFwVsqg2dLzeDnuoQ06i7hOdtP7pGAiKsug==",
"requires": {
"base64-js": "1.5.1",
"event-target-shim": "6.0.2",
@@ -34361,9 +34267,9 @@
}
},
"typescript": {
"version": "4.6.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
"integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
"dev": true
},
"ua-parser-js": {
@@ -34708,28 +34614,6 @@
"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",

View File

@@ -39,7 +39,7 @@
"@hapi/bourne": "2.0.0",
"@jitsi/js-utils": "2.0.0",
"@jitsi/logger": "2.0.0",
"@jitsi/rtcstats": "9.2.0",
"@jitsi/rtcstats": "9.0.1",
"@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,12 +54,11 @@
"@react-navigation/elements": "1.2.1",
"@react-navigation/material-top-tabs": "6.0.6",
"@react-navigation/native": "6.0.6",
"@react-navigation/native-stack": "6.6.2",
"@react-navigation/stack": "6.0.11",
"@svgr/webpack": "4.3.2",
"@tensorflow/tfjs-backend-wasm": "3.13.0",
"@tensorflow/tfjs-core": "3.13.0",
"@vladmandic/human": "2.6.5",
"@vladmandic/human-models": "2.5.9",
"@vladmandic/face-api": "1.6.4",
"@xmldom/xmldom": "0.7.5",
"amplitude-js": "8.2.1",
"base64-js": "1.3.1",
@@ -77,9 +76,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/v1457.0.0+ad75454f/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1430.0.0+ccf9ebed/lib-jitsi-meet.tgz",
"libflacjs": "https://git@github.com/mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"lodash": "4.17.21",
"moment": "2.29.2",
"moment-duration-format": "2.2.2",
@@ -99,7 +98,7 @@
"react-native-collapsible": "1.6.0",
"react-native-default-preference": "1.4.4",
"react-native-device-info": "8.4.8",
"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-dialog": "9.2.1",
"react-native-gesture-handler": "2.1.0",
"react-native-get-random-values": "1.7.2",
"react-native-immersive": "2.0.0",
@@ -118,7 +117,7 @@
"react-native-url-polyfill": "1.3.0",
"react-native-video": "https://git@github.com/jitsi/react-native-video#4f6dad990d17ce42894df993780b5386a9c11b85",
"react-native-watch-connectivity": "1.0.4",
"react-native-webrtc": "1.100.1",
"react-native-webrtc": "1.100.0",
"react-native-webview": "11.15.1",
"react-native-youtube-iframe": "2.2.1",
"react-redux": "7.1.0",
@@ -134,7 +133,6 @@
"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"
},
@@ -147,10 +145,6 @@
"@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",
@@ -173,7 +167,7 @@
"style-loader": "0.19.0",
"traverse": "0.6.6",
"ts-loader": "9.2.6",
"typescript": "4.6.4",
"typescript": "4.3.5",
"unorm": "1.6.0",
"webpack": "5.57.1",
"webpack-bundle-analyzer": "4.4.2",
@@ -189,12 +183,8 @@
"lint": "eslint --max-warnings 0 .",
"lang-sort": "./resources/lang-sort.sh",
"lint-fix": "eslint --max-warnings 0 --fix .",
"postinstall": "patch-package --error-on-fail && jetify",
"postinstall": "patch-package && jetify",
"validate": "npm ls",
"start": "make dev"
},
"resolutions": {
"@types/react": "17.0.14",
"@types/react-dom": "17.0.14"
}
}

View File

@@ -0,0 +1,118 @@
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,
},

View File

@@ -2,7 +2,6 @@
import { API_ID } from '../../../modules/API/constants';
import { getName as getAppName } from '../app/functions';
import { getAnalyticsRoomName } from '../base/conference';
import {
checkChromeExtensionsInstalled,
isMobileBrowser
@@ -13,7 +12,6 @@ import JitsiMeetJS, {
} from '../base/lib-jitsi-meet';
import { isAnalyticsEnabled } from '../base/lib-jitsi-meet/functions';
import { getJitsiMeetGlobalNS, loadScript, parseURIString } from '../base/util';
import { inIframe } from '../base/util/iframeUtils';
import { AmplitudeHandler, MatomoHandler } from './handlers';
import logger from './logger';
@@ -156,9 +154,7 @@ export async function createHandlers({ getState }: { getState: Function }) {
* @param {Array<Object>} handlers - The analytics handlers.
* @returns {void}
*/
export function initAnalytics(store: Store, handlers: Array<Object>) {
const { getState, dispatch } = store;
export function initAnalytics({ getState }: { getState: Function }, handlers: Array<Object>) {
if (!isAnalyticsEnabled(getState) || handlers.length === 0) {
return;
}
@@ -169,6 +165,7 @@ export function initAnalytics(store: Store, handlers: Array<Object>) {
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 = {};
@@ -206,7 +203,7 @@ export function initAnalytics(store: Store, handlers: Array<Object>) {
}
analytics.addPermanentProperties(permanentProperties);
analytics.setConferenceName(getAnalyticsRoomName(state, dispatch));
analytics.setConferenceName(roomName);
// Set the handlers last, since this triggers emptying of the cache
analytics.setAnalyticsHandlers(handlers);
@@ -224,6 +221,24 @@ export function initAnalytics(store: Store, handlers: Array<Object>) {
}
}
/**
* Checks whether we are loaded in iframe.
*
* @returns {boolean} Returns {@code true} if loaded in iframe.
* @private
*/
export function inIframe() {
if (navigator.product === 'ReactNative') {
return false;
}
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}
/**
* Tries to load the scripts for the external analytics handlers and creates them.
*

View File

@@ -15,17 +15,11 @@ 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 { isPrejoinPageEnabled } from '../mobile/navigation/functions';
import {
goBackToRoot,
navigateRoot
} from '../mobile/navigation/rootNavigationContainerRef';
import { navigateRoot } from '../mobile/navigation/rootNavigationContainerRef';
import { screen } from '../mobile/navigation/routes';
import { setFatalError } from '../overlay';
@@ -92,11 +86,7 @@ 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 = appendURLParam(url, 'room', getBackendSafeRoomName(room)));
const { release } = parseURLParams(location, true, 'search');
release && (url = appendURLParam(url, 'release', release));
room && (url += `?room=${getBackendSafeRoomName(room)}`);
let config;
@@ -138,15 +128,7 @@ export function appNavigate(uri: ?string) {
if (room) {
dispatch(createDesiredLocalTracks());
if (isPrejoinPageEnabled(getState())) {
navigateRoot(screen.preJoin);
} else {
dispatch(connect());
navigateRoot(screen.conference.root);
}
} else {
goBackToRoot(getState(), dispatch);
dispatch(connect());
}
};
}

View File

@@ -15,10 +15,8 @@ import {
import { setLocationURL } from '../base/connection';
import { loadConfig } from '../base/lib-jitsi-meet/functions.web';
import {
appendURLParam,
getBackendSafeRoomName,
parseURIString,
parseURLParams
parseURIString
} from '../base/util';
import { isVpaasMeeting } from '../jaas/functions';
import {
@@ -95,11 +93,7 @@ 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 = appendURLParam(url, 'room', getBackendSafeRoomName(room)));
const { release } = parseURLParams(location, true, 'search');
release && (url = appendURLParam(url, 'release', release));
room && (url += `?room=${getBackendSafeRoomName(room)}`);
let config;

View File

@@ -1,15 +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 { DimensionsDetector, clientResized, setSafeAreaInsets } from '../../base/responsive-ui';
import { Platform } from '../../base/react';
import { DimensionsDetector, clientResized } from '../../base/responsive-ui';
import { updateSettings } from '../../base/settings';
import { _getRouteToRender } from '../getRouteToRender.native';
import logger from '../logger';
@@ -23,16 +22,16 @@ import '../reducers';
declare var __DEV__;
const DialogContainerWrapper = Platform.select({
ios: FullWindowOverlay,
default: View
});
/**
* The type of React {@code Component} props of {@link App}.
*/
type Props = AbstractAppProps & {
/**
* An object of colors that override the default colors of the app/sdk.
*/
colorScheme: ?Object,
/**
* Identifier for this app on the native side.
*/
@@ -77,7 +76,6 @@ export class App extends AbstractApp {
// Bind event handler so it is only bound once per instance.
this._onDimensionsChanged = this._onDimensionsChanged.bind(this);
this._onSafeAreaInsetsChanged = this._onSafeAreaInsetsChanged.bind(this);
}
/**
@@ -100,31 +98,13 @@ export class App extends AbstractApp {
*/
async _extraInit() {
const { dispatch, getState } = this.state.store;
// We set these early enough so then we avoid any unnecessary re-renders.
dispatch(updateFlags(this.props.flags));
const route = await _getRouteToRender();
// We need the root navigator to be set early.
await this._navigate(route);
// HACK ALERT!
// Wait until the root navigator is ready.
// We really need to break the inheritance relationship between App,
// AbstractApp and BaseApp, it's very inflexible and cumbersome right now.
const rootNavigationReady = new Promise(resolve => {
const i = setInterval(() => {
const { ready } = getState()['features/app'] || {};
if (ready) {
clearInterval(i);
resolve();
}
}, 50);
});
await rootNavigationReady;
// We set these early enough so then we avoid any unnecessary re-renders.
dispatch(updateFlags(this.props.flags));
// Check if serverURL is configured externally and not allowed to change.
const serverURLChangeEnabled = getFeatureFlag(getState(), SERVER_URL_CHANGE_ENABLED, true);
@@ -158,13 +138,10 @@ export class App extends AbstractApp {
*/
_createMainElement(component, props) {
return (
<SafeAreaProvider>
<DimensionsDetector
onDimensionsChanged = { this._onDimensionsChanged }
onSafeAreaInsetsChanged = { this._onSafeAreaInsetsChanged }>
{ super._createMainElement(component, props) }
</DimensionsDetector>
</SafeAreaProvider>
<DimensionsDetector
onDimensionsChanged = { this._onDimensionsChanged }>
{ super._createMainElement(component, props) }
</DimensionsDetector>
);
}
@@ -221,23 +198,6 @@ export class App extends AbstractApp {
dispatch(clientResized(width, height));
}
/**
* Updates the safe are insets values.
*
* @param {Object} insets - The insets.
* @param {number} insets.top - The top inset.
* @param {number} insets.right - The right inset.
* @param {number} insets.bottom - The bottom inset.
* @param {number} insets.left - The left inset.
* @private
* @returns {void}
*/
_onSafeAreaInsetsChanged(insets) {
const { dispatch } = this.state.store;
dispatch(setSafeAreaInsets(insets));
}
/**
* Renders the platform specific dialog container.
*
@@ -245,12 +205,7 @@ export class App extends AbstractApp {
*/
_renderDialogContainer() {
return (
<DialogContainerWrapper
pointerEvents = 'box-none'
style = { StyleSheet.absoluteFill }>
<BottomSheetContainer />
<DialogContainer />
</DialogContainerWrapper>
<DialogContainer />
);
}
}

View File

@@ -7,8 +7,7 @@ import { toState } from '../base/redux';
import { Conference } from '../conference';
import { getDeepLinkingPage } from '../deep-linking';
import { UnsupportedDesktopBrowser } from '../unsupported-browser';
import { BlankPage, WelcomePage } from '../welcome';
import { isWelcomePageEnabled } from '../welcome/functions';
import { BlankPage, isWelcomePageUserEnabled, WelcomePage } from '../welcome';
/**
* Determines which route is to be rendered in order to depict a specific Redux
@@ -73,7 +72,7 @@ function _getWebConferenceRoute(state) {
function _getWebWelcomePageRoute(state) {
const route = _getEmptyRoute();
if (isWelcomePageEnabled(state)) {
if (isWelcomePageUserEnabled(state)) {
if (isSupportedBrowser()) {
route.component = WelcomePage;
} else {

View File

@@ -2,6 +2,7 @@
import {
createConnectionEvent,
inIframe,
sendAnalytics
} from '../analytics';
import { SET_ROOM } from '../base/conference';
@@ -11,7 +12,6 @@ import {
getURLWithoutParams
} from '../base/connection';
import { MiddlewareRegistry } from '../base/redux';
import { inIframe } from '../base/util/iframeUtils';
import { reloadNow } from './actions';
import { _getRouteToRender } from './getRouteToRender';

View File

@@ -36,7 +36,6 @@ 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';

View File

@@ -1,7 +1,6 @@
// @flow
import '../authentication/middleware';
import '../dynamic-branding/middleware';
import '../gifs/middleware';
import '../mobile/audio-mode/middleware';
import '../mobile/background/middleware';

View File

@@ -7,6 +7,7 @@ import '../dynamic-branding/middleware';
import '../e2ee/middleware';
import '../external-api/middleware';
import '../keyboard-shortcuts/middleware';
import '../local-recording/middleware';
import '../no-audio-signal/middleware';
import '../notifications/middleware';
import '../noise-detection/middleware';

View File

@@ -1,22 +0,0 @@
import { ReducerRegistry } from '../base/redux';
import { _ROOT_NAVIGATION_READY } from '../mobile/navigation/actionTypes';
/**
* Listen for actions which changes the state of the app feature.
*
* @param {Object} state - The Redux state of the feature features/app.
* @param {Object} action - Action object.
* @param {string} action.type - Type of action.
* @returns {Object}
*/
ReducerRegistry.register('features/app', (state = {}, action) => {
switch (action.type) {
case _ROOT_NAVIGATION_READY:
return {
...state,
ready: action.ready
};
default:
return state;
}
});

View File

@@ -8,6 +8,4 @@ import '../mobile/full-screen/reducer';
import '../mobile/watchos/reducer';
import '../shared-video/reducer';
import './reducer.native';
import './reducers.any';

View File

@@ -4,6 +4,7 @@ import '../base/devices/reducer';
import '../e2ee/reducer';
import '../face-landmarks/reducer';
import '../feedback/reducer';
import '../local-recording/reducer';
import '../no-audio-signal/reducer';
import '../noise-detection/reducer';
import '../participants-pane/reducer';

View File

@@ -1,4 +0,0 @@
export interface IStore {
getState: Function,
dispatch: Function
}

View File

@@ -29,11 +29,14 @@ export function authenticateAndUpgradeRole(
id: string,
password: string,
conference: Object) {
return (dispatch: Dispatch<any>) => {
return (dispatch: Dispatch<any>, getState: Function) => {
const { password: roomPassword }
= getState()['features/base/conference'];
const process
= conference.authenticateAndUpgradeRole({
id,
password,
roomPassword,
onLoginSuccessful() {
// When the login succeeds, the process has completed half

View File

@@ -1,15 +1,23 @@
/* @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}.
*/
@@ -36,12 +44,22 @@ 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.
*/
@@ -50,7 +68,12 @@ type Props = {
/**
* Invoked to obtain translated strings.
*/
t: Function
t: Function,
/**
* Override the default visibility.
*/
visible: boolean
};
/**
@@ -97,6 +120,10 @@ type State = {
* of the configuration parameters.
*/
class LoginDialog extends Component<Props, State> {
static defaultProps = {
visible: true
};
/**
* Initializes a new LoginDialog instance.
*
@@ -127,40 +154,42 @@ class LoginDialog extends Component<Props, State> {
render() {
const {
_connecting: connecting,
t
t,
visible
} = this.props;
return (
<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>
<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>
);
}
@@ -175,10 +204,12 @@ 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) {
@@ -199,22 +230,34 @@ 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) {
return t(messageKey, messageOptions);
const message = t(messageKey, messageOptions);
const messageStyles
= messageIsError ? styles.errorMessage : styles.progressMessage;
return (
<Text style = { messageStyles }>
{ message }
</Text>
);
}
return null;
}
_onUsernameChange: (string) => void;
/**
* Called when user edits the username.
*
@@ -228,6 +271,8 @@ class LoginDialog extends Component<Props, State> {
});
}
_onPasswordChange: (string) => void;
/**
* Called when user edits the password.
*
@@ -241,6 +286,8 @@ class LoginDialog extends Component<Props, State> {
});
}
_onCancel: () => void;
/**
* Notifies this LoginDialog that it has been dismissed by cancel.
*
@@ -248,9 +295,14 @@ class LoginDialog extends Component<Props, State> {
* @returns {void}
*/
_onCancel() {
this.props.dispatch(cancelLogin());
const { _onCancel, dispatch } = this.props;
_onCancel && _onCancel();
dispatch(cancelLogin());
}
_onLogin: () => void;
/**
* Notifies this LoginDialog that the login button (OK) has been pressed by
* the user.
@@ -303,7 +355,8 @@ function _mapStateToProps(state) {
_configHosts: configHosts,
_connecting: Boolean(connecting) || Boolean(thenableWithCancel),
_error: connectionError || authenticateAndUpgradeRoleError,
_progress: progress
_progress: progress,
_styles: ColorSchemeRegistry.get(state, 'LoginDialog')
};
}

View File

@@ -1,10 +1,14 @@
// @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 { openLoginDialog, cancelWaitForOwner } from '../../actions.native';
import { cancelWaitForOwner } from '../../actions.native';
import LoginDialog from './LoginDialog';
/**
* The type of the React {@code Component} props of {@link WaitForOwnerDialog}.
@@ -38,9 +42,14 @@ 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);
}
/**
@@ -56,10 +65,17 @@ class WaitForOwnerDialog extends Component<Props> {
confirmLabel = 'dialog.IamHost'
descriptionKey = 'dialog.WaitForHostMsg'
onCancel = { this._onCancel }
onSubmit = { this._onLogin } />
onSubmit = { this._onLogin }>
<LoginDialog
// eslint-disable-next-line react/jsx-handler-names
_onCancel = { this._onLoginDialogCancel }
visible = { this.state.showLoginDialog } />
</ConfirmDialog>
);
}
_onCancel: () => void;
/**
* Called when the cancel button is clicked.
*
@@ -70,6 +86,8 @@ class WaitForOwnerDialog extends Component<Props> {
this.props.dispatch(cancelWaitForOwner());
}
_onLogin: () => void;
/**
* Called when the OK button is clicked.
*
@@ -77,7 +95,17 @@ class WaitForOwnerDialog extends Component<Props> {
* @returns {void}
*/
_onLogin() {
this.props.dispatch(openLoginDialog());
this.setState({ showLoginDialog: true });
}
/**
* Called when the nested login dialog is cancelled.
*
* @private
* @returns {void}
*/
_onLoginDialogCancel() {
this.setState({ showLoginDialog: false });
}
}

View File

@@ -0,0 +1,41 @@
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')
}
});

View File

@@ -15,7 +15,6 @@ import {
JitsiConnectionErrors
} from '../base/lib-jitsi-meet';
import { MiddlewareRegistry } from '../base/redux';
import { setPrejoinPageVisibility } from '../prejoin';
import {
CANCEL_LOGIN,
@@ -121,7 +120,6 @@ 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;

View File

@@ -51,10 +51,9 @@ 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) || passwordRequired) {
if (authRequired && !conference) {
dispatch(maybeRedirectToWelcomePage());
}
}

View File

@@ -18,7 +18,6 @@ export const MEDIA_TYPE_TO_PENDING_STORE_KEY: {[key: MediaType]: string} = {
[MEDIA_TYPE.VIDEO]: 'pendingVideo'
};
export const ASKED_TO_UNMUTE_NOTIFICATION_ID = 'asked-to-unmute';
export const ASKED_TO_UNMUTE_SOUND_ID = 'ASKED_TO_UNMUTE_SOUND';
export const AUDIO_MODERATION_NOTIFICATION_ID = 'audio-moderation';

View File

@@ -2,7 +2,6 @@
import { MEDIA_TYPE, type MediaType } from '../base/media/constants';
import { isLocalParticipantModerator } from '../base/participants/functions';
import { isInBreakoutRoom } from '../breakout-rooms/functions';
import { MEDIA_TYPE_TO_WHITELIST_STORE_KEY, MEDIA_TYPE_TO_PENDING_STORE_KEY } from './constants';
@@ -50,7 +49,7 @@ export const isEnabled = (mediaType: MediaType) => (state: Object) => isEnabledF
export const isSupported = () => (state: Object) => {
const { conference } = state['features/base/conference'];
return Boolean(!isInBreakoutRoom(state) && conference?.isAVModerationSupported());
return conference ? conference.isAVModerationSupported() : false;
};
/**

View File

@@ -48,9 +48,7 @@ import {
participantRejected
} from './actions';
import {
ASKED_TO_UNMUTE_NOTIFICATION_ID,
ASKED_TO_UNMUTE_SOUND_ID,
AUDIO_MODERATION_NOTIFICATION_ID,
ASKED_TO_UNMUTE_SOUND_ID, AUDIO_MODERATION_NOTIFICATION_ID,
CS_MODERATION_NOTIFICATION_ID,
VIDEO_MODERATION_NOTIFICATION_ID
} from './constants';
@@ -80,8 +78,6 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
let descriptionKey;
let titleKey;
let uid;
const localParticipant = getLocalParticipant(getState);
const raisedHand = hasRaisedHand(localParticipant);
switch (action.mediaType) {
case MEDIA_TYPE.AUDIO: {
@@ -104,7 +100,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
dispatch(showNotification({
customActionNameKey: [ 'notify.raiseHandAction' ],
customActionHandler: [ () => batch(() => {
!raisedHand && dispatch(raiseHand(true));
dispatch(raiseHand(true));
dispatch(hideNotification(uid));
}) ],
descriptionKey,
@@ -226,8 +222,7 @@ StateListenerRegistry.register(
titleKey: 'notify.hostAskedUnmute',
sticky: true,
customActionNameKey: [ 'notify.unmute' ],
customActionHandler: [ () => dispatch(muteLocal(false, MEDIA_TYPE.AUDIO)) ],
uid: ASKED_TO_UNMUTE_NOTIFICATION_ID
customActionHandler: [ () => dispatch(muteLocal(false, MEDIA_TYPE.AUDIO)) ]
}, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
dispatch(playSound(ASKED_TO_UNMUTE_SOUND_ID));
}

View File

@@ -29,7 +29,11 @@ export default {
inviteButtonBackground: 'rgb(0, 119, 225)',
onVideoText: 'white'
},
'Dialog': {},
'Dialog': {
border: 'rgba(0, 3, 6, 0.6)',
buttonBackground: ColorPalette.blue,
buttonLabel: ColorPalette.white
},
'Header': {
background: ColorPalette.blue,
icon: ColorPalette.white,
@@ -37,6 +41,10 @@ export default {
statusBarContent: ColorPalette.white,
text: ColorPalette.white
},
'Modal': {},
'LargeVideo': {
background: '#040404'
},
'Toolbox': {
button: 'rgb(255, 255, 255)',
buttonToggled: 'rgb(38, 58, 76)',

View File

@@ -206,16 +206,6 @@ 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.

View File

@@ -56,7 +56,6 @@ import {
P2P_STATUS_CHANGED,
SEND_TONES,
SET_FOLLOW_ME,
SET_OBFUSCATED_ROOM,
SET_PASSWORD,
SET_PASSWORD_FAILED,
SET_ROOM,
@@ -805,24 +804,6 @@ 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.
*

View File

@@ -1,6 +1,5 @@
// @flow
import { sha512_256 as sha512 } from 'js-sha512';
import _ from 'lodash';
import { getName } from '../../app/functions';
@@ -20,7 +19,6 @@ import {
safeDecodeURIComponent
} from '../util';
import { setObfuscatedRoom } from './actions';
import {
AVATAR_URL_COMMAND,
EMAIL_COMMAND,
@@ -300,47 +298,6 @@ 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).

View File

@@ -1,6 +1,6 @@
// @flow
import { setPictureInPictureEnabled } from '../../mobile/picture-in-picture/functions';
import { setPictureInPictureDisabled } 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());
setPictureInPictureEnabled(true);
setPictureInPictureDisabled(false);
}
}
@@ -54,7 +54,7 @@ function _toggleScreenSharing(enabled, store) {
* @returns {void}
*/
function _startScreenSharing(dispatch, state) {
setPictureInPictureEnabled(false);
setPictureInPictureDisabled(true);
JitsiMeetJS.createLocalTracks({ devices: [ 'desktop' ] })
.then(tracks => {
@@ -73,6 +73,6 @@ function _startScreenSharing(dispatch, state) {
.catch(error => {
console.log('ERROR creating ScreeSharing stream ', error);
setPictureInPictureEnabled(true);
setPictureInPictureDisabled(false);
});
}

View File

@@ -44,14 +44,9 @@ MiddlewareRegistry.register(store => next => action => {
break;
}
case CONFERENCE_FAILED: {
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));
}
enableForcedReload
&& action.error?.name === JitsiConferenceErrors.CONFERENCE_RESTARTED
&& dispatch(setSkipPrejoinOnReload(true));
break;
}

View File

@@ -18,7 +18,6 @@ import {
LOCK_STATE_CHANGED,
P2P_STATUS_CHANGED,
SET_FOLLOW_ME,
SET_OBFUSCATED_ROOM,
SET_PASSWORD,
SET_PENDING_SUBJECT_CHANGE,
SET_ROOM,
@@ -89,12 +88,6 @@ 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);

View File

@@ -83,7 +83,6 @@ export default [
'debugAudioLevels',
'defaultLocalDisplayName',
'defaultRemoteDisplayName',
'deploymentUrls',
'desktopSharingFrameRate',
'desktopSharingSources',
'disable1On1Mode',
@@ -95,7 +94,6 @@ export default [
'disableBeforeUnloadHandlers',
'disableChatSmileys',
'disableDeepLinking',
'disabledNotifications',
'disabledSounds',
'disableFilmstripAutohiding',
'disableInitialGUM',
@@ -165,7 +163,6 @@ export default [
'gatherStats',
'giphy',
'googleApiApplicationClientID',
'gravatar.disabled',
'hiddenPremeetingButtons',
'hideConferenceSubject',
'hideDisplayName',
@@ -193,7 +190,6 @@ export default [
'openSharedDocumentOnJoin',
'opusMaxAverageBitrate',
'p2p',
'participantsPane',
'pcStatsInterval',
'preferH264',
'preferredCodec',

View File

@@ -65,7 +65,7 @@ const CONFERENCE_HEADER_MAPPING = {
hideConferenceTimer: [ 'conference-timer' ],
hideConferenceSubject: [ 'subject' ],
hideParticipantsStats: [ 'participants-count' ],
hideRecordingLabel: [ 'recording' ]
hideRecordingLabel: [ 'recording', 'local-recording' ]
};
ReducerRegistry.register('features/base/config', (state = _getInitialState(), action) => {

View File

@@ -1,71 +0,0 @@
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;
}

View File

@@ -1,10 +1,15 @@
// @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,
@@ -13,12 +18,9 @@ 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.
*
@@ -76,7 +78,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);
@@ -260,6 +262,69 @@ 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.
*

View File

@@ -16,8 +16,6 @@ export {
} from './actions.native';
import logger from './logger';
export * from './actions.any';
/**
* Opens new connection.
*

View File

@@ -7,15 +7,6 @@
*/
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.
*
@@ -27,15 +18,3 @@ export const HIDE_SHEET = 'HIDE_SHEET';
*
*/
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';

View File

@@ -2,12 +2,7 @@
import type { Dispatch } from 'redux';
import {
HIDE_DIALOG,
HIDE_SHEET,
OPEN_DIALOG,
OPEN_SHEET
} from './actionTypes';
import { HIDE_DIALOG, OPEN_DIALOG } from './actionTypes';
import { isDialogOpen } from './functions';
/**
@@ -29,19 +24,6 @@ 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.
*
@@ -62,26 +44,6 @@ 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

View File

@@ -1,4 +1,7 @@
// @flow
import React from 'react';
import { View } from 'react-native';
import Dialog from 'react-native-dialog';
import { translate } from '../../../i18n';
@@ -43,16 +46,16 @@ class AlertDialog extends AbstractDialog<Props> {
: renderHTML(t(contentKey.key, contentKey.params));
return (
<Dialog.Container
coverScreen = { false }
visible = { true }>
<Dialog.Description>
{ content }
</Dialog.Description>
<Dialog.Button
label = { t('dialog.Ok') }
onPress = { this._onSubmit } />
</Dialog.Container>
<View>
<Dialog.Container visible = { true }>
<Dialog.Description>
{ content }
</Dialog.Description>
<Dialog.Button
label = { t('dialog.Ok') }
onPress = { this._onSubmit } />
</Dialog.Container>
</View>
);
}

View File

@@ -1,17 +1,40 @@
import React, { PureComponent, type Node } from 'react';
import { SafeAreaView, ScrollView, View } from 'react-native';
// @flow
import React, { PureComponent, type Node } from 'react';
import { PanResponder, SafeAreaView, ScrollView, View } from 'react-native';
import { ColorSchemeRegistry } from '../../../color-scheme';
import { SlidingView } from '../../../react';
import { connect } from '../../../redux';
import { hideSheet } from '../../actions';
import { StyleType } from '../../../styles';
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.
*/
@@ -22,17 +45,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.
*/
@@ -58,6 +81,8 @@ type Props = {
* A component emulating Android's BottomSheet.
*/
class BottomSheet extends PureComponent<Props> {
panResponder: Object;
/**
* Default values for {@code BottomSheet} component's properties.
*
@@ -69,28 +94,18 @@ class BottomSheet extends PureComponent<Props> {
};
/**
* Initializes a new instance.
* Instantiates a new component.
*
* @param {Props} props - The React {@code Component} props to initialize
* the new instance with.
* @inheritdoc
*/
constructor(props: Props) {
super(props);
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());
}
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: this._onShouldSetResponder.bind(this),
onMoveShouldSetPanResponder: this._onShouldSetResponder.bind(this),
onPanResponderRelease: this._onGestureEnd.bind(this)
});
}
/**
@@ -101,6 +116,8 @@ class BottomSheet extends PureComponent<Props> {
*/
render() {
const {
_height,
_styles,
addScrollViewPadding,
renderHeader,
renderFooter,
@@ -112,7 +129,7 @@ class BottomSheet extends PureComponent<Props> {
<SlidingView
accessibilityRole = 'menu'
accessibilityViewIsModal = { true }
onHide = { this._onCancel }
onHide = { this.props.onCancel }
position = 'bottom'
show = { showSlidingView }>
<View
@@ -126,16 +143,20 @@ class BottomSheet extends PureComponent<Props> {
style = { [
styles.sheetItemContainer,
renderHeader
? styles.sheetHeader
: styles.sheet,
renderFooter && styles.sheetFooter,
style
] }>
? _styles.sheetHeader
: _styles.sheet,
renderFooter && _styles.sheetFooter,
style,
{
maxHeight: _height - 100
}
] }
{ ...this.panResponder.panHandlers }>
<ScrollView
bounces = { false }
showsVerticalScrollIndicator = { false }
style = { [
renderFooter && styles.sheet,
renderFooter && _styles.sheet,
addScrollViewPadding && styles.scrollView
] } >
{ this.props.children }
@@ -146,6 +167,63 @@ 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;
}
}
export default connect()(BottomSheet);
/**
* 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);

View File

@@ -1,20 +0,0 @@
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;

View File

@@ -1,4 +1,7 @@
// @flow
import React from 'react';
import { View } from 'react-native';
import Dialog from 'react-native-dialog';
import { translate } from '../../../i18n';
@@ -23,7 +26,7 @@ type Props = {
/**
* The React {@code Component} children.
*/
children?: Node,
children?: React$Node,
/**
* The i18n key of the text label for the confirm button.
@@ -108,25 +111,25 @@ class ConfirmDialog extends AbstractDialog<Props> {
? styles.destructiveDialogButton : styles.dialogButton;
return (
<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>
<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>
);
}

View File

@@ -1,4 +1,4 @@
import React, { Fragment } from 'react';
import React from 'react';
import { ReactionEmoji } from '../../../../reactions/components';
import { getReactionsQueue } from '../../../../reactions/functions.any';
@@ -38,12 +38,10 @@ class DialogContainer extends AbstractDialogContainer {
* @returns {ReactElement}
*/
render() {
return (
<Fragment>
{this._renderReactions()}
{this._renderDialogContent()}
</Fragment>
);
return (<React.Fragment>
{this._renderReactions()}
{this._renderDialogContent()}
</React.Fragment>);
}
}

View File

@@ -1,4 +1,7 @@
// @flow
import React from 'react';
import { View } from 'react-native';
import Dialog from 'react-native-dialog';
import { translate } from '../../../i18n';
@@ -92,39 +95,40 @@ class InputDialog<P: Props, S: State> extends AbstractDialog<P, S> {
} = this.props;
return (
<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>
<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>
);
}

View File

@@ -1,3 +1,5 @@
// @flow
import { StyleSheet } from 'react-native';
import BaseTheme from '../../../../base/ui/components/BaseTheme.native';
@@ -18,6 +20,85 @@ 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.
*/
@@ -55,39 +136,12 @@ export const inputDialog = {
};
/**
* The React {@code Component} styles of {@code BottomSheet}. These have
* been implemented as per the Material Design guidelines:
* Default styles for the items of a {@code BottomSheet}-based menu.
*
* 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,
maxHeight: '75%'
},
ColorSchemeRegistry.register('BottomSheet', {
buttons: {
/**
* Style for the {@code Icon} element in a generic item of the menu.
@@ -140,53 +194,7 @@ export const bottomSheetStyles = {
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.
@@ -264,3 +272,28 @@ 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'
}
});

View File

@@ -1,11 +1,8 @@
/* @flow */
import { assign, ReducerRegistry } from '../redux';
import {
HIDE_DIALOG,
HIDE_SHEET,
OPEN_DIALOG,
OPEN_SHEET
} from './actionTypes';
import { HIDE_DIALOG, OPEN_DIALOG } from './actionTypes';
/**
* Reduces redux actions which show or hide dialogs.
@@ -35,18 +32,6 @@ 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;

View File

@@ -160,12 +160,6 @@ 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.

Some files were not shown because too many files have changed in this diff Show More