mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-05-08 21:32:31 +00:00
Compare commits
6 Commits
android-sd
...
mobile-22.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64ed41880e | ||
|
|
f1f912f25a | ||
|
|
44319b377d | ||
|
|
8deebebe47 | ||
|
|
b6ef7716bc | ||
|
|
171c6c6ebf |
@@ -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>
|
||||
|
||||
@@ -26,5 +26,5 @@ android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
android.bundle.enableUncompressedNativeLibs=false
|
||||
|
||||
appVersion=99.0.0
|
||||
sdkVersion=99.0.0
|
||||
appVersion=22.2.1
|
||||
sdkVersion=5.1.1
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
android:name=".JitsiMeetActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/JitsiMeetActivityStyle"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:windowSoftInputMode="adjustResize"/>
|
||||
|
||||
240
android/sdk/src/main/java/org/jitsi/meet/sdk/BaseReactView.java
Normal file
240
android/sdk/src/main/java/org/jitsi/meet/sdk/BaseReactView.java
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright @ 2018-present 8x8, Inc.
|
||||
* Copyright @ 2018 Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.facebook.react.ReactRootView;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.rnimmersive.RNImmersiveModule;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* Base class for all views which are backed by a React Native view.
|
||||
*/
|
||||
public abstract class BaseReactView<ListenerT>
|
||||
extends FrameLayout {
|
||||
|
||||
/**
|
||||
* Background color used by {@code BaseReactView} and the React Native root
|
||||
* view.
|
||||
*/
|
||||
protected static int BACKGROUND_COLOR = 0xFF111111;
|
||||
|
||||
/**
|
||||
* The collection of all existing {@code BaseReactView}s. Used to find the
|
||||
* {@code BaseReactView} when delivering events coming from
|
||||
* {@link ExternalAPIModule}.
|
||||
*/
|
||||
static final Set<BaseReactView> views
|
||||
= Collections.newSetFromMap(new WeakHashMap<BaseReactView, Boolean>());
|
||||
|
||||
/**
|
||||
* Finds a {@code BaseReactView} which matches a specific external API
|
||||
* scope.
|
||||
*
|
||||
* @param externalAPIScope - The external API scope associated with the
|
||||
* {@code BaseReactView} to find.
|
||||
* @return The {@code BaseReactView}, if any, associated with the specified
|
||||
* {@code externalAPIScope}; otherwise, {@code null}.
|
||||
*/
|
||||
public static BaseReactView findViewByExternalAPIScope(
|
||||
String externalAPIScope) {
|
||||
synchronized (views) {
|
||||
for (BaseReactView view : views) {
|
||||
if (view.externalAPIScope.equals(externalAPIScope)) {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all registered React views.
|
||||
*
|
||||
* @return An {@link ArrayList} containing all views currently held by React.
|
||||
*/
|
||||
static ArrayList<BaseReactView> getViews() {
|
||||
return new ArrayList<>(views);
|
||||
}
|
||||
|
||||
/**
|
||||
* The unique identifier of this {@code BaseReactView} within the process
|
||||
* for the purposes of {@link ExternalAPIModule}. The name scope was
|
||||
* inspired by postis which we use on Web for the similar purposes of the
|
||||
* iframe-based external API.
|
||||
*/
|
||||
protected String externalAPIScope;
|
||||
|
||||
/**
|
||||
* The listener (e.g. {@link JitsiMeetViewListener}) instance for reporting
|
||||
* events occurring in Jitsi Meet.
|
||||
*/
|
||||
@Deprecated
|
||||
private ListenerT listener;
|
||||
|
||||
/**
|
||||
* React Native root view.
|
||||
*/
|
||||
private ReactRootView reactRootView;
|
||||
|
||||
public BaseReactView(@NonNull Context context) {
|
||||
super(context);
|
||||
initialize((Activity)context);
|
||||
}
|
||||
|
||||
public BaseReactView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initialize((Activity)context);
|
||||
}
|
||||
|
||||
public BaseReactView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
initialize((Activity)context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@code ReactRootView} for the given app name with the given
|
||||
* props. Once created it's set as the view of this {@code FrameLayout}.
|
||||
*
|
||||
* @param appName - The name of the "app" (in React Native terms) to load.
|
||||
* @param props - The React Component props to pass to the app.
|
||||
*/
|
||||
public void createReactRootView(String appName, @Nullable Bundle props) {
|
||||
if (props == null) {
|
||||
props = new Bundle();
|
||||
}
|
||||
|
||||
props.putString("externalAPIScope", externalAPIScope);
|
||||
|
||||
if (reactRootView == null) {
|
||||
reactRootView = new ReactRootView(getContext());
|
||||
reactRootView.startReactApplication(
|
||||
ReactInstanceManagerHolder.getReactInstanceManager(),
|
||||
appName,
|
||||
props);
|
||||
reactRootView.setBackgroundColor(BACKGROUND_COLOR);
|
||||
addView(reactRootView);
|
||||
} else {
|
||||
reactRootView.setAppProperties(props);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the React resources (specifically the {@link ReactRootView})
|
||||
* associated with this view.
|
||||
*
|
||||
* MUST be called when the {@link Activity} holding this view is destroyed,
|
||||
* typically in the {@code onDestroy} method.
|
||||
*/
|
||||
public void dispose() {
|
||||
if (reactRootView != null) {
|
||||
removeView(reactRootView);
|
||||
reactRootView.unmountReactApplication();
|
||||
reactRootView = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the listener set on this {@code BaseReactView}.
|
||||
*
|
||||
* @return The listener set on this {@code BaseReactView}.
|
||||
*/
|
||||
@Deprecated
|
||||
public ListenerT getListener() {
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract method called by {@link ExternalAPIModule} when an event is
|
||||
* received for this view.
|
||||
*
|
||||
* @param name - The name of the event.
|
||||
* @param data - The details of the event associated with/specific to the
|
||||
* specified {@code name}.
|
||||
*/
|
||||
@Deprecated
|
||||
protected abstract void onExternalAPIEvent(String name, ReadableMap data);
|
||||
|
||||
@Deprecated
|
||||
protected void onExternalAPIEvent(
|
||||
Map<String, Method> listenerMethods,
|
||||
String name, ReadableMap data) {
|
||||
ListenerT listener = getListener();
|
||||
|
||||
if (listener != null) {
|
||||
ListenerUtils.runListenerMethod(
|
||||
listener, listenerMethods, name, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the window containing this view gains or loses focus.
|
||||
*
|
||||
* @param hasFocus If the window of this view now has focus, {@code true};
|
||||
* otherwise, {@code false}.
|
||||
*/
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
|
||||
// https://github.com/mockingbot/react-native-immersive#restore-immersive-state
|
||||
RNImmersiveModule immersive = RNImmersiveModule.getInstance();
|
||||
|
||||
if (hasFocus && immersive != null) {
|
||||
immersive.emitImmersiveStateChangeEvent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a specific listener on this {@code BaseReactView}.
|
||||
*
|
||||
* @param listener The listener to set on this {@code BaseReactView}.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setListener(ListenerT listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
private void initialize(Activity activity) {
|
||||
setBackgroundColor(BACKGROUND_COLOR);
|
||||
|
||||
ReactInstanceManagerHolder.initReactInstanceManager(activity);
|
||||
|
||||
// Hook this BaseReactView into ExternalAPI.
|
||||
externalAPIScope = UUID.randomUUID().toString();
|
||||
synchronized (views) {
|
||||
views.add(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,25 +95,37 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an event that occurred on the JavaScript side of the SDK to
|
||||
* the native side.
|
||||
* the specified {@link BaseReactView}'s listener.
|
||||
*
|
||||
* @param name The name of the event.
|
||||
* @param data The details/specifics of the event to send determined
|
||||
* by/associated with the specified {@code name}.
|
||||
* @param scope
|
||||
*/
|
||||
@ReactMethod
|
||||
public void sendEvent(String name, ReadableMap data) {
|
||||
public void sendEvent(String name, ReadableMap data, String scope) {
|
||||
// Keep track of the current ongoing conference.
|
||||
OngoingConferenceTracker.getInstance().onExternalAPIEvent(name, data);
|
||||
|
||||
JitsiMeetLogger.d(TAG + " Sending event: " + name + " with data: " + data);
|
||||
broadcastEmitter.sendBroadcast(name, data);
|
||||
// The JavaScript App needs to provide uniquely identifying information
|
||||
// to the native ExternalAPI module so that the latter may match the
|
||||
// former to the native BaseReactView which hosts it.
|
||||
BaseReactView view = BaseReactView.findViewByExternalAPIScope(scope);
|
||||
|
||||
if (view != null) {
|
||||
JitsiMeetLogger.d(TAG + " Sending event: " + name + " with data: " + data);
|
||||
try {
|
||||
view.onExternalAPIEvent(name, data);
|
||||
broadcastEmitter.sendBroadcast(name, data);
|
||||
} catch (Exception e) {
|
||||
JitsiMeetLogger.e(e, TAG + " onExternalAPIEvent: error sending event");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,9 +167,12 @@ public class JitsiMeetActivity extends AppCompatActivity
|
||||
}
|
||||
}
|
||||
|
||||
protected void leave() {
|
||||
Intent hangupBroadcastIntent = BroadcastIntentHelper.buildHangUpIntent();
|
||||
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(hangupBroadcastIntent);
|
||||
public void leave() {
|
||||
if (this.jitsiView != null) {
|
||||
this.jitsiView .leave();
|
||||
} else {
|
||||
JitsiMeetLogger.w("Cannot leave, view is null");
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable
|
||||
@@ -210,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) {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
* Copyright @ 2017-2018 Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* Base {@link Fragment} for applications integrating Jitsi Meet at a higher level. It
|
||||
* contains all the required wiring between the {@code JitsiMeetView} and
|
||||
* the Fragment lifecycle methods already implemented.
|
||||
*
|
||||
* In this fragment we use a single {@code JitsiMeetView} instance. This
|
||||
* instance gives us access to a view which displays the welcome page and the
|
||||
* conference itself. All lifecycle methods associated with this Fragment are
|
||||
* hooked to the React Native subsystem via proxy calls through the
|
||||
* {@code JitsiMeetActivityDelegate} static methods.
|
||||
*
|
||||
* @deprecated use {@link JitsiMeetActivity} or directly {@link JitsiMeetView}
|
||||
*/
|
||||
@Deprecated
|
||||
public class JitsiMeetFragment extends Fragment {
|
||||
|
||||
/**
|
||||
* Instance of the {@link JitsiMeetView} which this activity will display.
|
||||
*/
|
||||
private JitsiMeetView view;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
return this.view = new JitsiMeetView(getActivity());
|
||||
}
|
||||
|
||||
public JitsiMeetView getJitsiView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
JitsiMeetActivityDelegate.onHostDestroy(getActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
JitsiMeetActivityDelegate.onHostResume(getActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
|
||||
JitsiMeetActivityDelegate.onHostPause(getActivity());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
public 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;
|
||||
|
||||
@@ -80,7 +70,7 @@ public class JitsiMeetOngoingConferenceService extends Service
|
||||
}
|
||||
}
|
||||
|
||||
public static void abort(Context context) {
|
||||
static void abort(Context context) {
|
||||
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
|
||||
context.stopService(intent);
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,33 +16,36 @@
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.facebook.react.ReactRootView;
|
||||
import com.rnimmersive.RNImmersiveModule;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
public class JitsiMeetView extends FrameLayout {
|
||||
public class JitsiMeetView extends BaseReactView<JitsiMeetViewListener>
|
||||
implements OngoingConferenceTracker.OngoingConferenceListener {
|
||||
|
||||
/**
|
||||
* Background color used by {@code BaseReactView} and the React Native root
|
||||
* view.
|
||||
* The {@code Method}s of {@code JitsiMeetViewListener} by event name i.e.
|
||||
* redux action types.
|
||||
*/
|
||||
private static final int BACKGROUND_COLOR = 0xFF111111;
|
||||
private static final Map<String, Method> LISTENER_METHODS
|
||||
= ListenerUtils.mapListenerMethods(JitsiMeetViewListener.class);
|
||||
|
||||
/**
|
||||
* React Native root view.
|
||||
* The URL of the current conference.
|
||||
*/
|
||||
private ReactRootView reactRootView;
|
||||
// XXX Currently, one thread writes and one thread reads, so it should be
|
||||
// fine to have this field volatile without additional synchronization.
|
||||
private volatile String url;
|
||||
|
||||
/**
|
||||
* Helper method to recursively merge 2 {@link Bundle} objects representing React Native props.
|
||||
@@ -106,19 +109,10 @@ public class JitsiMeetView extends FrameLayout {
|
||||
initialize(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the React resources (specifically the {@link ReactRootView})
|
||||
* associated with this view.
|
||||
*
|
||||
* MUST be called when the {@link Activity} holding this view is destroyed,
|
||||
* typically in the {@code onDestroy} method.
|
||||
*/
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (reactRootView != null) {
|
||||
removeView(reactRootView);
|
||||
reactRootView.unmountReactApplication();
|
||||
reactRootView = null;
|
||||
}
|
||||
OngoingConferenceTracker.getInstance().removeListener(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,7 +130,8 @@ public class JitsiMeetView extends FrameLayout {
|
||||
PictureInPictureModule.class);
|
||||
if (pipModule != null
|
||||
&& pipModule.isPictureInPictureSupported()
|
||||
&& !JitsiMeetActivityDelegate.arePermissionsBeingRequested()) {
|
||||
&& !JitsiMeetActivityDelegate.arePermissionsBeingRequested()
|
||||
&& this.url != null) {
|
||||
try {
|
||||
pipModule.enterPictureInPicture();
|
||||
} catch (RuntimeException re) {
|
||||
@@ -156,40 +151,10 @@ public class JitsiMeetView extends FrameLayout {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@code ReactRootView} for the given app name with the given
|
||||
* props. Once created it's set as the view of this {@code FrameLayout}.
|
||||
*
|
||||
* @param appName - The name of the "app" (in React Native terms) to load.
|
||||
* @param props - The React Component props to pass to the app.
|
||||
* Leaves the currently active conference.
|
||||
*/
|
||||
private void createReactRootView(String appName, @Nullable Bundle props) {
|
||||
if (props == null) {
|
||||
props = new Bundle();
|
||||
}
|
||||
|
||||
if (reactRootView == null) {
|
||||
reactRootView = new ReactRootView(getContext());
|
||||
reactRootView.startReactApplication(
|
||||
ReactInstanceManagerHolder.getReactInstanceManager(),
|
||||
appName,
|
||||
props);
|
||||
reactRootView.setBackgroundColor(BACKGROUND_COLOR);
|
||||
addView(reactRootView);
|
||||
} else {
|
||||
reactRootView.setAppProperties(props);
|
||||
}
|
||||
}
|
||||
|
||||
private void initialize(@NonNull Context context) {
|
||||
// Check if the parent Activity implements JitsiMeetActivityInterface,
|
||||
// otherwise things may go wrong.
|
||||
if (!(context instanceof JitsiMeetActivityInterface)) {
|
||||
throw new RuntimeException("Enclosing Activity must implement JitsiMeetActivityInterface");
|
||||
}
|
||||
|
||||
setBackgroundColor(BACKGROUND_COLOR);
|
||||
|
||||
ReactInstanceManagerHolder.initReactInstanceManager((Activity) context);
|
||||
public void leave() {
|
||||
setProps(new Bundle());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,27 +179,46 @@ public class JitsiMeetView extends FrameLayout {
|
||||
createReactRootView("App", props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for {@link OngoingConferenceTracker} events.
|
||||
* @param conferenceUrl
|
||||
*/
|
||||
@Override
|
||||
public void onCurrentConferenceChanged(String conferenceUrl) {
|
||||
// This property was introduced in order to address
|
||||
// an exception in the Picture-in-Picture functionality which arose
|
||||
// because of delays related to bridging between JavaScript and Java. To
|
||||
// reduce these delays do not wait for the call to be transferred to the
|
||||
// UI thread.
|
||||
this.url = conferenceUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for {@link ExternalAPIModule} events.
|
||||
*
|
||||
* @param name The name of the event.
|
||||
* @param data The details/specifics of the event to send determined
|
||||
* by/associated with the specified {@code name}.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
protected void onExternalAPIEvent(String name, ReadableMap data) {
|
||||
onExternalAPIEvent(LISTENER_METHODS, name, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
dispose();
|
||||
super.onDetachedFromWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the window containing this view gains or loses focus.
|
||||
*
|
||||
* @param hasFocus If the window of this view now has focus, {@code true};
|
||||
* otherwise, {@code false}.
|
||||
*/
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
|
||||
// https://github.com/mockingbot/react-native-immersive#restore-immersive-state
|
||||
RNImmersiveModule immersive = RNImmersiveModule.getInstance();
|
||||
|
||||
if (hasFocus && immersive != null) {
|
||||
immersive.emitImmersiveStateChangeEvent();
|
||||
private void initialize(@NonNull Context context) {
|
||||
// Check if the parent Activity implements JitsiMeetActivityInterface,
|
||||
// otherwise things may go wrong.
|
||||
if (!(context instanceof JitsiMeetActivityInterface)) {
|
||||
throw new RuntimeException("Enclosing Activity must implement JitsiMeetActivityInterface");
|
||||
}
|
||||
|
||||
OngoingConferenceTracker.getInstance().addListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright @ 2017-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Interface for listening to events coming from Jitsi Meet.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface JitsiMeetViewListener {
|
||||
/**
|
||||
* Called when a conference was joined.
|
||||
*
|
||||
* @param data Map with a "url" key with the conference URL.
|
||||
*/
|
||||
void onConferenceJoined(Map<String, Object> data);
|
||||
|
||||
/**
|
||||
* Called when the active conference ends, be it because of user choice or
|
||||
* because of a failure.
|
||||
*
|
||||
* @param data Map with an "error" key with the error and a "url" key with
|
||||
* the conference URL. If the conference finished gracefully no `error`
|
||||
* key will be present. The possible values for "error" are described here:
|
||||
* https://github.com/jitsi/lib-jitsi-meet/blob/master/JitsiConnectionErrors.js
|
||||
* https://github.com/jitsi/lib-jitsi-meet/blob/master/JitsiConferenceErrors.js
|
||||
*/
|
||||
void onConferenceTerminated(Map<String, Object> data);
|
||||
|
||||
/**
|
||||
* Called before the conference is joined.
|
||||
*
|
||||
* @param data Map with a "url" key with the conference URL.
|
||||
*/
|
||||
void onConferenceWillJoin(Map<String, Object> data);
|
||||
}
|
||||
167
android/sdk/src/main/java/org/jitsi/meet/sdk/ListenerUtils.java
Normal file
167
android/sdk/src/main/java/org/jitsi/meet/sdk/ListenerUtils.java
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright @ 2018-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.ReadableMapKeySetIterator;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Utility methods for helping with transforming {@link ExternalAPIModule}
|
||||
* events into listener methods. Used with descendants of {@link BaseReactView}.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class ListenerUtils {
|
||||
/**
|
||||
* Extracts the methods defined in a listener and creates a mapping of this
|
||||
* form: event name -> method.
|
||||
*
|
||||
* @param listener - The listener whose methods we want to slurp.
|
||||
* @return A mapping with event names - methods.
|
||||
*/
|
||||
public static Map<String, Method> mapListenerMethods(Class listener) {
|
||||
Map<String, Method> methods = new HashMap<>();
|
||||
|
||||
// Figure out the mapping between the listener methods
|
||||
// and the events i.e. redux action types.
|
||||
Pattern onPattern = Pattern.compile("^on[A-Z]+");
|
||||
Pattern camelcasePattern = Pattern.compile("([a-z0-9]+)([A-Z0-9]+)");
|
||||
|
||||
for (Method method : listener.getDeclaredMethods()) {
|
||||
// * The method must be public (because it is declared by an
|
||||
// interface).
|
||||
// * The method must be/return void.
|
||||
if (!Modifier.isPublic(method.getModifiers())
|
||||
|| !Void.TYPE.equals(method.getReturnType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// * The method name must start with "on" followed by a
|
||||
// capital/uppercase letter (in agreement with the camelcase
|
||||
// coding style customary to Java in general and the projects of
|
||||
// the Jitsi community in particular).
|
||||
String name = method.getName();
|
||||
|
||||
if (!onPattern.matcher(name).find()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// * The method must accept/have exactly 1 parameter of a type
|
||||
// assignable from HashMap.
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
|
||||
if (parameterTypes.length != 1
|
||||
|| !parameterTypes[0].isAssignableFrom(HashMap.class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert the method name to an event name.
|
||||
name
|
||||
= camelcasePattern.matcher(name.substring(2))
|
||||
.replaceAll("$1_$2")
|
||||
.toUpperCase(Locale.ROOT);
|
||||
methods.put(name, method);
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the right listener method for the given event.
|
||||
* NOTE: This function will run asynchronously on the UI thread.
|
||||
*
|
||||
* @param listener - The listener on which the method will be called.
|
||||
* @param listenerMethods - Mapping with event names and the matching
|
||||
* methods.
|
||||
* @param eventName - Name of the event.
|
||||
* @param eventData - Data associated with the event.
|
||||
*/
|
||||
public static void runListenerMethod(
|
||||
final Object listener,
|
||||
final Map<String, Method> listenerMethods,
|
||||
final String eventName,
|
||||
final ReadableMap eventData) {
|
||||
// Make sure listener methods are invoked on the UI thread. It
|
||||
// was requested by SDK consumers.
|
||||
if (UiThreadUtil.isOnUiThread()) {
|
||||
runListenerMethodOnUiThread(
|
||||
listener, listenerMethods, eventName, eventData);
|
||||
} else {
|
||||
UiThreadUtil.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
runListenerMethodOnUiThread(
|
||||
listener, listenerMethods, eventName, eventData);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper companion for {@link ListenerUtils#runListenerMethod} which runs
|
||||
* in the UI thread.
|
||||
*/
|
||||
private static void runListenerMethodOnUiThread(
|
||||
Object listener,
|
||||
Map<String, Method> listenerMethods,
|
||||
String eventName,
|
||||
ReadableMap eventData) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
||||
Method method = listenerMethods.get(eventName);
|
||||
if (method != null) {
|
||||
try {
|
||||
method.invoke(listener, toHashMap(eventData));
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new {@code HashMap} instance with the key-value
|
||||
* associations of a specific {@code ReadableMap}.
|
||||
*
|
||||
* @param readableMap the {@code ReadableMap} specifying the key-value
|
||||
* associations with which the new {@code HashMap} instance is to be
|
||||
* initialized.
|
||||
* @return a new {@code HashMap} instance initialized with the key-value
|
||||
* associations of the specified {@code readableMap}.
|
||||
*/
|
||||
private static HashMap<String, Object> toHashMap(ReadableMap readableMap) {
|
||||
HashMap<String, Object> hashMap = new HashMap<>();
|
||||
|
||||
for (ReadableMapKeySetIterator i = readableMap.keySetIterator();
|
||||
i.hasNextKey();) {
|
||||
String key = i.nextKey();
|
||||
|
||||
hashMap.put(key, readableMap.getString(key));
|
||||
}
|
||||
|
||||
return hashMap;
|
||||
}
|
||||
}
|
||||
@@ -43,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);
|
||||
@@ -84,7 +84,7 @@ class PictureInPictureModule extends ReactContextBaseJavaModule {
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
public void enterPictureInPicture() {
|
||||
if (!isEnabled) {
|
||||
if (isDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -132,8 +132,8 @@ class PictureInPictureModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setPictureInPictureEnabled(Boolean enabled) {
|
||||
this.isEnabled = enabled;
|
||||
public void setPictureInPictureDisabled(Boolean disabled) {
|
||||
this.isDisabled = disabled;
|
||||
}
|
||||
|
||||
public boolean isPictureInPictureSupported() {
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<resources>
|
||||
<style name="JitsiMeetActivityStyle" parent="Theme.AppCompat.Light.NoActionBar"/>
|
||||
</resources>
|
||||
141
conference.js
141
conference.js
@@ -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,13 @@ 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);
|
||||
}
|
||||
|
||||
@@ -3094,12 +3057,34 @@ export default {
|
||||
* @param email {string} the new email
|
||||
*/
|
||||
changeLocalEmail(email = '') {
|
||||
const localParticipant = getLocalParticipant(APP.store.getState());
|
||||
|
||||
const formattedEmail = String(email).trim();
|
||||
|
||||
if (formattedEmail === localParticipant.email) {
|
||||
return;
|
||||
}
|
||||
|
||||
const localId = localParticipant.id;
|
||||
|
||||
APP.store.dispatch(participantUpdated({
|
||||
// XXX Only the local participant is allowed to update without
|
||||
// stating the JitsiConference instance (i.e. participant property
|
||||
// `conference` for a remote participant) because the local
|
||||
// participant is uniquely identified by the very fact that there is
|
||||
// only one local participant.
|
||||
|
||||
id: localId,
|
||||
local: true,
|
||||
email: formattedEmail
|
||||
}));
|
||||
|
||||
APP.store.dispatch(updateSettings({
|
||||
email: formattedEmail
|
||||
}));
|
||||
|
||||
APP.API.notifyEmailChanged(localId, {
|
||||
email: formattedEmail
|
||||
});
|
||||
sendData(commands.EMAIL, formattedEmail);
|
||||
},
|
||||
|
||||
@@ -3108,12 +3093,29 @@ export default {
|
||||
* @param url {string} the new url
|
||||
*/
|
||||
changeLocalAvatarUrl(url = '') {
|
||||
const { avatarURL, id } = getLocalParticipant(APP.store.getState());
|
||||
|
||||
const formattedUrl = String(url).trim();
|
||||
|
||||
if (formattedUrl === avatarURL) {
|
||||
return;
|
||||
}
|
||||
|
||||
APP.store.dispatch(participantUpdated({
|
||||
// XXX Only the local participant is allowed to update without
|
||||
// stating the JitsiConference instance (i.e. participant property
|
||||
// `conference` for a remote participant) because the local
|
||||
// participant is uniquely identified by the very fact that there is
|
||||
// only one local participant.
|
||||
|
||||
id,
|
||||
local: true,
|
||||
avatarURL: formattedUrl
|
||||
}));
|
||||
|
||||
APP.store.dispatch(updateSettings({
|
||||
avatarURL: formattedUrl
|
||||
}));
|
||||
|
||||
sendData(commands.AVATAR_URL, url);
|
||||
},
|
||||
|
||||
@@ -3154,6 +3156,23 @@ export default {
|
||||
*/
|
||||
changeLocalDisplayName(nickname = '') {
|
||||
const formattedNickname = getNormalizedDisplayName(nickname);
|
||||
const { id, name } = getLocalParticipant(APP.store.getState());
|
||||
|
||||
if (formattedNickname === name) {
|
||||
return;
|
||||
}
|
||||
|
||||
APP.store.dispatch(participantUpdated({
|
||||
// XXX Only the local participant is allowed to update without
|
||||
// stating the JitsiConference instance (i.e. participant property
|
||||
// `conference` for a remote participant) because the local
|
||||
// participant is uniquely identified by the very fact that there is
|
||||
// only one local participant.
|
||||
|
||||
id,
|
||||
local: true,
|
||||
name: formattedNickname
|
||||
}));
|
||||
|
||||
APP.store.dispatch(updateSettings({
|
||||
displayName: formattedNickname
|
||||
|
||||
166
config.js
166
config.js
@@ -143,7 +143,6 @@ var config = {
|
||||
|
||||
// Disable measuring of audio levels.
|
||||
// disableAudioLevels: false,
|
||||
|
||||
// audioLevelsInterval: 200,
|
||||
|
||||
// Enabling this will run the lib-jitsi-meet no audio detection module which
|
||||
@@ -272,9 +271,8 @@ var config = {
|
||||
|
||||
// Recording
|
||||
|
||||
// DEPRECATED. Use recordingService.enabled instead.
|
||||
// Whether to enable file recording or not.
|
||||
// fileRecordingsEnabled: false,
|
||||
|
||||
// Enable the dropbox integration.
|
||||
// dropbox: {
|
||||
// appKey: '<APP_KEY>' // Specify your app key here.
|
||||
@@ -284,77 +282,38 @@ var config = {
|
||||
// redirectURI:
|
||||
// 'https://jitsi-meet.example.com/subfolder/static/oauth.html'
|
||||
// },
|
||||
|
||||
// recordingService: {
|
||||
// // When integrations like dropbox are enabled only that will be shown,
|
||||
// // by enabling fileRecordingsServiceEnabled, we show both the integrations
|
||||
// // and the generic recording service (its configuration and storage type
|
||||
// // depends on jibri configuration)
|
||||
// enabled: false,
|
||||
|
||||
// // Whether to show the possibility to share file recording with other people
|
||||
// // (e.g. meeting participants), based on the actual implementation
|
||||
// // on the backend.
|
||||
// sharingEnabled: false,
|
||||
|
||||
// // Hide the warning that says we only store the recording for 24 hours.
|
||||
// hideStorageWarning: false
|
||||
// },
|
||||
|
||||
// DEPRECATED. Use recordingService.enabled instead.
|
||||
// When integrations like dropbox are enabled only that will be shown,
|
||||
// by enabling fileRecordingsServiceEnabled, we show both the integrations
|
||||
// and the generic recording service (its configuration and storage type
|
||||
// depends on jibri configuration)
|
||||
// fileRecordingsServiceEnabled: false,
|
||||
|
||||
// DEPRECATED. Use recordingService.sharingEnabled instead.
|
||||
// Whether to show the possibility to share file recording with other people
|
||||
// (e.g. meeting participants), based on the actual implementation
|
||||
// on the backend.
|
||||
// fileRecordingsServiceSharingEnabled: false,
|
||||
|
||||
// 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
|
||||
// },
|
||||
|
||||
// DEPRECATED. Use transcription.enabled instead.
|
||||
// Transcription (in interface_config,
|
||||
// subtitles and buttons can be configured)
|
||||
// transcribingEnabled: false,
|
||||
|
||||
// DEPRECATED. Use transcription.useAppLanguage instead.
|
||||
// If true transcriber will use the application language.
|
||||
// The application language is either explicitly set by participants in their settings or automatically
|
||||
// detected based on the environment, e.g. if the app is opened in a chrome instance which is using french as its
|
||||
// default language then transcriptions for that participant will be in french.
|
||||
// Defaults to true.
|
||||
// transcribeWithAppLanguage: true,
|
||||
|
||||
// DEPRECATED. Use transcription.preferredLanguage instead.
|
||||
// Transcriber language. This settings will only work if "transcribeWithAppLanguage" is explicitly set to false.
|
||||
// Available languages can be found in
|
||||
// ./src/react/features/transcribing/transcriber-langs.json.
|
||||
// preferredTranscribeLanguage: 'en-US',
|
||||
|
||||
// DEPRECATED. Use transcription.autoCaptionOnRecord instead.
|
||||
// Enables automatic turning on captions when recording is started
|
||||
// autoCaptionOnRecord: false,
|
||||
|
||||
// Transcription options.
|
||||
// transcription: {
|
||||
// // Whether the feature should be enabled or not.
|
||||
// enabled: false,
|
||||
|
||||
// // If true transcriber will use the application language.
|
||||
// // The application language is either explicitly set by participants in their settings or automatically
|
||||
// // detected based on the environment, e.g. if the app is opened in a chrome instance which
|
||||
// // is using french as its default language then transcriptions for that participant will be in french.
|
||||
// // Defaults to true.
|
||||
// useAppLanguage: true,
|
||||
|
||||
// // Transcriber language. This settings will only work if "useAppLanguage"
|
||||
// // is explicitly set to false.
|
||||
// // Available languages can be found in
|
||||
// // ./src/react/features/transcribing/transcriber-langs.json.
|
||||
// preferredLanguage: 'en-US',
|
||||
|
||||
// // Disable start transcription for all participants.
|
||||
// disableStartForAll: false,
|
||||
|
||||
// // Enables automatic turning on captions when recording is started
|
||||
// autoCaptionOnRecord: false
|
||||
// },
|
||||
|
||||
// Misc
|
||||
|
||||
// Default value for the channel "last N" attribute. -1 for unlimited.
|
||||
@@ -416,7 +375,7 @@ var config = {
|
||||
// // This will result in Safari not being able to decode video from endpoints sending VP9 video.
|
||||
// // When set to false, the conference falls back to VP8 whenever there is an endpoint that doesn't support the
|
||||
// // preferred codec and goes back to the preferred codec when that endpoint leaves.
|
||||
// enforcePreferredCodec: false,
|
||||
// // enforcePreferredCodec: false,
|
||||
//
|
||||
// // Provides a way to configure the maximum bitrates that will be enforced on the simulcast streams for
|
||||
// // video tracks. The keys in the object represent the type of the stream (LD, SD or HD) and the values
|
||||
@@ -584,8 +543,8 @@ var config = {
|
||||
// enableFeaturesBasedOnToken: false,
|
||||
|
||||
// When enabled the password used for locking a room is restricted to up to the number of digits specified
|
||||
// default: roomPasswordNumberOfDigits: false,
|
||||
// roomPasswordNumberOfDigits: 10,
|
||||
// default: roomPasswordNumberOfDigits: false,
|
||||
|
||||
// Message to show the users. Example: 'The service will be down for
|
||||
// maintenance at 01:00 AM GMT,
|
||||
@@ -600,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']
|
||||
// },
|
||||
@@ -663,7 +618,6 @@ var config = {
|
||||
// 'chat',
|
||||
// 'closedcaptions',
|
||||
// 'desktop',
|
||||
// 'dock-iframe'
|
||||
// 'download',
|
||||
// 'embedmeeting',
|
||||
// 'etherpad',
|
||||
@@ -677,6 +631,8 @@ var config = {
|
||||
// 'linktosalesforce',
|
||||
// 'livestreaming',
|
||||
// 'microphone',
|
||||
// 'mute-everyone',
|
||||
// 'mute-video-everyone',
|
||||
// 'participants-pane',
|
||||
// 'profile',
|
||||
// 'raisehand',
|
||||
@@ -690,7 +646,6 @@ var config = {
|
||||
// 'stats',
|
||||
// 'tileview',
|
||||
// 'toggle-camera',
|
||||
// 'undock-iframe',
|
||||
// 'videoquality',
|
||||
// '__end'
|
||||
// ],
|
||||
@@ -817,7 +772,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
|
||||
@@ -826,14 +781,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.
|
||||
@@ -913,10 +865,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
|
||||
@@ -991,22 +939,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
|
||||
@@ -1052,8 +1011,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.
|
||||
@@ -1150,24 +1108,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.
|
||||
@@ -1206,8 +1162,7 @@ var config = {
|
||||
// 'transcribing',
|
||||
// 'video-quality',
|
||||
// 'insecure-room',
|
||||
// 'highlight-moment',
|
||||
// 'top-panel-toggle'
|
||||
// 'highlight-moment'
|
||||
// ]
|
||||
// },
|
||||
|
||||
@@ -1343,6 +1298,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
|
||||
@@ -1388,9 +1344,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,
|
||||
|
||||
@@ -1401,14 +1354,7 @@ var config = {
|
||||
|
||||
// // Disables the stage filmstrip
|
||||
// // (displaying multiple participants on stage besides the vertical filmstrip)
|
||||
// disableStageFilmstrip: false,
|
||||
|
||||
// // Disables the top panel (only shown when a user is sharing their screen).
|
||||
// disableTopPanel: false,
|
||||
|
||||
// // The minimum number of participants that must be in the call for
|
||||
// // the top panel layout to be used.
|
||||
// minParticipantCountForTopPanel: 50
|
||||
// disableStageFilmstrip: false
|
||||
// },
|
||||
|
||||
// Tile view related config options.
|
||||
|
||||
@@ -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,9 +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
|
||||
} from './react/features/prejoin/actions';
|
||||
import { setPrejoinDisplayNameRequired } from './react/features/prejoin/actions';
|
||||
const logger = Logger.getLogger(__filename);
|
||||
|
||||
/**
|
||||
@@ -84,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'];
|
||||
@@ -101,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);
|
||||
|
||||
@@ -19,34 +19,11 @@
|
||||
font-size: 14px;
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
&.space-top {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.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 {
|
||||
@@ -63,7 +40,7 @@
|
||||
border-radius: 4px;
|
||||
height: 40px;
|
||||
justify-content: center;
|
||||
width: 42px;
|
||||
width: 56px;
|
||||
}
|
||||
|
||||
.cloud-content-recording-icon-container {
|
||||
@@ -75,7 +52,7 @@
|
||||
}
|
||||
|
||||
.jitsi-recording-header {
|
||||
margin-bottom: 16px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.jitsi-content-recording-icon-container-with-switch {
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
.remote-videos {
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@import 'lobby';
|
||||
@import 'premeeting-screens';
|
||||
@import 'prejoin';
|
||||
@import 'prejoin-dialog';
|
||||
@import 'prejoin-third-party';
|
||||
|
||||
118
css/premeeting/_prejoin-dialog.scss
Normal file
118
css/premeeting/_prejoin-dialog.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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
4
debian/control
vendored
@@ -33,7 +33,7 @@ Description: Configuration for web serving of Jitsi Meet
|
||||
|
||||
Package: jitsi-meet-prosody
|
||||
Architecture: all
|
||||
Depends: openssl, prosody (>= 0.11.0) | prosody-trunk | prosody-0.12 | prosody-0.11, lua-sec, 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
|
||||
|
||||
5
debian/jitsi-meet-tokens.postinst
vendored
5
debian/jitsi-meet-tokens.postinst
vendored
@@ -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
|
||||
|
||||
@@ -138,11 +138,11 @@ Component "lobby.jitmeet.example.com" "muc"
|
||||
"polls";
|
||||
}
|
||||
|
||||
-- Enables dial-in for Jitsi meet components customers
|
||||
-- Enabled dial-in for JaaS 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
|
||||
enabled = false -- JaaS customers remove this line
|
||||
modules_enabled = {
|
||||
"ping";
|
||||
"bosh";
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 490 B |
@@ -144,7 +144,7 @@ var interfaceConfig = {
|
||||
RECENT_LIST_ENABLED: true,
|
||||
REMOTE_THUMBNAIL_RATIO: 1, // 1:1
|
||||
|
||||
SETTINGS_SECTIONS: [ 'devices', 'language', 'moderator', 'profile', 'calendar', 'sounds', 'more' ],
|
||||
SETTINGS_SECTIONS: [ 'devices', 'language', 'moderator', 'profile', 'calendar', 'sounds' ],
|
||||
|
||||
/**
|
||||
* Specify which sharing features should be displayed. If the value is not set
|
||||
|
||||
@@ -9,9 +9,9 @@ install! 'cocoapods', :deterministic_uuids => false
|
||||
target 'JitsiMeet' do
|
||||
project 'app/app.xcodeproj'
|
||||
|
||||
pod 'Firebase/Analytics', '~> 8.0'
|
||||
pod 'Firebase/Crashlytics', '~> 8.0'
|
||||
pod 'Firebase/DynamicLinks', '~> 8.0'
|
||||
pod 'Firebase/Analytics', '~> 6.33.0'
|
||||
pod 'Firebase/Crashlytics', '~> 6.33.0'
|
||||
pod 'Firebase/DynamicLinks', '~> 6.33.0'
|
||||
end
|
||||
|
||||
target 'JitsiMeetSDK' do
|
||||
|
||||
194
ios/Podfile.lock
194
ios/Podfile.lock
@@ -21,60 +21,50 @@ PODS:
|
||||
- React-Core (= 0.68.1)
|
||||
- React-jsi (= 0.68.1)
|
||||
- ReactCommon/turbomodule/core (= 0.68.1)
|
||||
- Firebase/Analytics (8.15.0):
|
||||
- Firebase/Analytics (6.33.0):
|
||||
- Firebase/Core
|
||||
- Firebase/Core (8.15.0):
|
||||
- Firebase/Core (6.33.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseAnalytics (~> 8.15.0)
|
||||
- Firebase/CoreOnly (8.15.0):
|
||||
- FirebaseCore (= 8.15.0)
|
||||
- Firebase/Crashlytics (8.15.0):
|
||||
- FirebaseAnalytics (= 6.8.3)
|
||||
- Firebase/CoreOnly (6.33.0):
|
||||
- FirebaseCore (= 6.10.3)
|
||||
- Firebase/Crashlytics (6.33.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseCrashlytics (~> 8.15.0)
|
||||
- Firebase/DynamicLinks (8.15.0):
|
||||
- FirebaseCrashlytics (~> 4.6.1)
|
||||
- Firebase/DynamicLinks (6.33.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseDynamicLinks (~> 8.15.0)
|
||||
- FirebaseAnalytics (8.15.0):
|
||||
- FirebaseAnalytics/AdIdSupport (= 8.15.0)
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (~> 8.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.7)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.7)
|
||||
- GoogleUtilities/Network (~> 7.7)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.7)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- FirebaseAnalytics/AdIdSupport (8.15.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (~> 8.0)
|
||||
- GoogleAppMeasurement (= 8.15.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.7)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.7)
|
||||
- GoogleUtilities/Network (~> 7.7)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.7)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- FirebaseCore (8.15.0):
|
||||
- FirebaseCoreDiagnostics (~> 8.0)
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- GoogleUtilities/Logger (~> 7.7)
|
||||
- FirebaseCoreDiagnostics (8.15.0):
|
||||
- GoogleDataTransport (~> 9.1)
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- GoogleUtilities/Logger (~> 7.7)
|
||||
- nanopb (~> 2.30908.0)
|
||||
- FirebaseCrashlytics (8.15.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (~> 8.0)
|
||||
- GoogleDataTransport (~> 9.1)
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- nanopb (~> 2.30908.0)
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- FirebaseDynamicLinks (8.15.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (8.15.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- GoogleUtilities/UserDefaults (~> 7.7)
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- FirebaseDynamicLinks (~> 4.3.1)
|
||||
- FirebaseAnalytics (6.8.3):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- FirebaseInstallations (~> 1.6)
|
||||
- GoogleAppMeasurement (= 6.8.3)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.7)
|
||||
- GoogleUtilities/MethodSwizzler (~> 6.7)
|
||||
- GoogleUtilities/Network (~> 6.7)
|
||||
- "GoogleUtilities/NSData+zlib (~> 6.7)"
|
||||
- nanopb (~> 1.30906.0)
|
||||
- FirebaseCore (6.10.3):
|
||||
- FirebaseCoreDiagnostics (~> 1.6)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/Logger (~> 6.7)
|
||||
- FirebaseCoreDiagnostics (1.7.0):
|
||||
- GoogleDataTransport (~> 7.4)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/Logger (~> 6.7)
|
||||
- nanopb (~> 1.30906.0)
|
||||
- FirebaseCrashlytics (4.6.2):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- FirebaseInstallations (~> 1.6)
|
||||
- GoogleDataTransport (~> 7.2)
|
||||
- nanopb (~> 1.30906.0)
|
||||
- PromisesObjC (~> 1.2)
|
||||
- FirebaseDynamicLinks (4.3.1):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- FirebaseInstallations (1.7.0):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/UserDefaults (~> 6.7)
|
||||
- PromisesObjC (~> 1.2)
|
||||
- fmt (6.2.1)
|
||||
- Giphy (2.1.20):
|
||||
- libwebp
|
||||
@@ -82,52 +72,36 @@ PODS:
|
||||
- Giphy (= 2.1.20)
|
||||
- React-Core
|
||||
- glog (0.3.5)
|
||||
- GoogleAppMeasurement (8.15.0):
|
||||
- GoogleAppMeasurement/AdIdSupport (= 8.15.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.7)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.7)
|
||||
- GoogleUtilities/Network (~> 7.7)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.7)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- GoogleAppMeasurement/AdIdSupport (8.15.0):
|
||||
- GoogleAppMeasurement/WithoutAdIdSupport (= 8.15.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.7)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.7)
|
||||
- GoogleUtilities/Network (~> 7.7)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.7)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- GoogleAppMeasurement/WithoutAdIdSupport (8.15.0):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.7)
|
||||
- GoogleUtilities/MethodSwizzler (~> 7.7)
|
||||
- GoogleUtilities/Network (~> 7.7)
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.7)"
|
||||
- nanopb (~> 2.30908.0)
|
||||
- GoogleDataTransport (9.1.4):
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- nanopb (< 2.30910.0, >= 2.30908.0)
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- GoogleAppMeasurement (6.8.3):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.7)
|
||||
- GoogleUtilities/MethodSwizzler (~> 6.7)
|
||||
- GoogleUtilities/Network (~> 6.7)
|
||||
- "GoogleUtilities/NSData+zlib (~> 6.7)"
|
||||
- nanopb (~> 1.30906.0)
|
||||
- GoogleDataTransport (7.5.1):
|
||||
- nanopb (~> 1.30906.0)
|
||||
- GoogleSignIn (6.0.2):
|
||||
- AppAuth (~> 1.4)
|
||||
- GTMAppAuth (~> 1.0)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
- GoogleUtilities/AppDelegateSwizzler (7.7.0):
|
||||
- GoogleUtilities/AppDelegateSwizzler (6.7.2):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Environment (7.7.0):
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- GoogleUtilities/Logger (7.7.0):
|
||||
- GoogleUtilities/Environment (6.7.2):
|
||||
- PromisesObjC (~> 1.2)
|
||||
- GoogleUtilities/Logger (6.7.2):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/MethodSwizzler (7.7.0):
|
||||
- GoogleUtilities/MethodSwizzler (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network (7.7.0):
|
||||
- GoogleUtilities/Network (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (7.7.0)"
|
||||
- GoogleUtilities/Reachability (7.7.0):
|
||||
- "GoogleUtilities/NSData+zlib (6.7.2)"
|
||||
- GoogleUtilities/Reachability (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/UserDefaults (7.7.0):
|
||||
- GoogleUtilities/UserDefaults (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GTMAppAuth (1.2.2):
|
||||
- AppAuth/Core (~> 1.4)
|
||||
@@ -142,13 +116,13 @@ PODS:
|
||||
- libwebp/mux (1.2.1):
|
||||
- libwebp/demux
|
||||
- libwebp/webp (1.2.1)
|
||||
- nanopb (2.30908.0):
|
||||
- nanopb/decode (= 2.30908.0)
|
||||
- nanopb/encode (= 2.30908.0)
|
||||
- nanopb/decode (2.30908.0)
|
||||
- nanopb/encode (2.30908.0)
|
||||
- nanopb (1.30906.0):
|
||||
- nanopb/decode (= 1.30906.0)
|
||||
- nanopb/encode (= 1.30906.0)
|
||||
- nanopb/decode (1.30906.0)
|
||||
- nanopb/encode (1.30906.0)
|
||||
- ObjectiveDropboxOfficial (6.2.3)
|
||||
- PromisesObjC (2.1.1)
|
||||
- PromisesObjC (1.2.12)
|
||||
- RCT-Folly (2021.06.28.00-v2):
|
||||
- boost
|
||||
- DoubleConversion
|
||||
@@ -379,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
|
||||
@@ -467,7 +441,7 @@ PODS:
|
||||
- React-Core
|
||||
- RNReanimated (1.13.4):
|
||||
- React-Core
|
||||
- RNScreens (3.13.1):
|
||||
- RNScreens (3.10.1):
|
||||
- React-Core
|
||||
- React-RCTImage
|
||||
- RNSound (0.11.1):
|
||||
@@ -488,9 +462,9 @@ DEPENDENCIES:
|
||||
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
|
||||
- FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`)
|
||||
- Firebase/Analytics (~> 8.0)
|
||||
- Firebase/Crashlytics (~> 8.0)
|
||||
- Firebase/DynamicLinks (~> 8.0)
|
||||
- Firebase/Analytics (~> 6.33.0)
|
||||
- Firebase/Crashlytics (~> 6.33.0)
|
||||
- Firebase/DynamicLinks (~> 6.33.0)
|
||||
- "giphy-react-native-sdk (from `../node_modules/@giphy/react-native-sdk`)"
|
||||
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
||||
- ObjectiveDropboxOfficial (= 6.2.3)
|
||||
@@ -700,27 +674,27 @@ SPEC CHECKSUMS:
|
||||
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
|
||||
FBLazyVector: 2c76493a346ef8cacf1f442926a39f805fffec1f
|
||||
FBReactNativeSpec: 371350f24afa87b6aba606972ec959dcd4a95c9a
|
||||
Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d
|
||||
FirebaseAnalytics: 7761cbadb00a717d8d0939363eb46041526474fa
|
||||
FirebaseCore: 5743c5785c074a794d35f2fff7ecc254a91e08b1
|
||||
FirebaseCoreDiagnostics: 92e07a649aeb66352b319d43bdd2ee3942af84cb
|
||||
FirebaseCrashlytics: feb07e4e9187be3c23c6a846cce4824e5ce2dd0b
|
||||
FirebaseDynamicLinks: 1dc816ef789c5adac6fede0b46d11478175c70e4
|
||||
FirebaseInstallations: 40bd9054049b2eae9a2c38ef1c3dd213df3605cd
|
||||
Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5
|
||||
FirebaseAnalytics: 5dd088bd2e67bb9d13dbf792d1164ceaf3052193
|
||||
FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd
|
||||
FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1
|
||||
FirebaseCrashlytics: 1a747c9cc084a24dc6d9511c991db1cd078154eb
|
||||
FirebaseDynamicLinks: 6eac37d86910382eafb6315d952cc44c9e176094
|
||||
FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2
|
||||
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
|
||||
Giphy: b6d5087521d251bb8c99cdc0eb07bbdf86d142d5
|
||||
giphy-react-native-sdk: 7abccf2b52123a0f30ce99da895ab6288023680c
|
||||
glog: 476ee3e89abb49e07f822b48323c51c57124b572
|
||||
GoogleAppMeasurement: 4c19f031220c72464d460c9daa1fb5d1acce958e
|
||||
GoogleDataTransport: 5fffe35792f8b96ec8d6775f5eccd83c998d5a3b
|
||||
GoogleAppMeasurement: 966e88df9d19c15715137bb2ddaf52373f111436
|
||||
GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833
|
||||
GoogleSignIn: fd381840dbe7c1137aa6dc30849a5c3e070c034a
|
||||
GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1
|
||||
GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
|
||||
GTMAppAuth: ad5c2b70b9a8689e1a04033c9369c4915bfcbe89
|
||||
GTMSessionFetcher: 43748f93435c2aa068b1cbe39655aaf600652e91
|
||||
libwebp: 98a37e597e40bfdb4c911fc98f2c53d0b12d05fc
|
||||
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
|
||||
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
|
||||
ObjectiveDropboxOfficial: fe206ce8c0bc49976c249d472db7fdbc53ebbd53
|
||||
PromisesObjC: ab77feca74fa2823e7af4249b8326368e61014cb
|
||||
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
|
||||
RCT-Folly: 4d8508a426467c48885f1151029bc15fa5d7b3b8
|
||||
RCTRequired: 00581111c53531e39e3c6346ef0d2c0cf52a5a37
|
||||
RCTTypeSafety: 07e03ee7800e7dd65cba8e52ad0c2edb06c96604
|
||||
@@ -744,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
|
||||
@@ -767,12 +741,12 @@ SPEC CHECKSUMS:
|
||||
RNGestureHandler: e5c7cab5f214503dcefd6b2b0cefb050e1f51c4a
|
||||
RNGoogleSignin: c4381751eefd73c552b923ba347a9bfc6f18771c
|
||||
RNReanimated: c1b56d030d1616239861534d9adb531f8cffab68
|
||||
RNScreens: 40a2cb40a02a609938137a1e0acfbf8fc9eebf19
|
||||
RNScreens: 522705f2e5c9d27efb17f24aceb2bf8335bc7b8e
|
||||
RNSound: 27e8268bdb0a1f191f219a33267f7e0445e8d62f
|
||||
RNSVG: ce9d996113475209013317e48b05c21ee988d42e
|
||||
RNWatch: 99637948ec9b5c9ec5a41920642594ad5ba07e80
|
||||
Yoga: 17cd9a50243093b547c1e539c749928dd68152da
|
||||
|
||||
PODFILE CHECKSUM: 0e8826a5cb9ee147354a83321ecb3104132f510b
|
||||
PODFILE CHECKSUM: bef1335067eaa4e8c558b1248f8ab3948de855bc
|
||||
|
||||
COCOAPODS: 1.11.3
|
||||
COCOAPODS: 1.11.2
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>99.0.0</string>
|
||||
<string>22.2.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSExtension</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>99.0.0</string>
|
||||
<string>22.2.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>99.0.0</string>
|
||||
<string>22.2.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>99.0.0</string>
|
||||
<string>22.2.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>CLKComplicationPrincipalClass</key>
|
||||
|
||||
@@ -24,14 +24,8 @@
|
||||
0BD906EA1EC0C00300C8C18E /* JitsiMeet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BD906E81EC0C00300C8C18E /* JitsiMeet.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
4E51B76425E5345E0038575A /* ScheenshareEventEmiter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E51B76225E5345E0038575A /* ScheenshareEventEmiter.h */; };
|
||||
4E51B76525E5345E0038575A /* ScheenshareEventEmiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E51B76325E5345E0038575A /* ScheenshareEventEmiter.m */; };
|
||||
4EBA6E61286072E300B31882 /* JitsiMeetViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4EBA6E5F286072E300B31882 /* JitsiMeetViewController.h */; };
|
||||
4EBA6E62286072E300B31882 /* JitsiMeetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EBA6E60286072E300B31882 /* JitsiMeetViewController.m */; };
|
||||
4EBA6E652860B1E800B31882 /* JitsiMeetRenderingView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4EBA6E632860B1E800B31882 /* JitsiMeetRenderingView.h */; };
|
||||
4EBA6E662860B1E800B31882 /* JitsiMeetRenderingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EBA6E642860B1E800B31882 /* JitsiMeetRenderingView.m */; };
|
||||
4ED4FFF32721B9B90074E620 /* JitsiAudioSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 4ED4FFF12721B9B90074E620 /* JitsiAudioSession.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
4ED4FFF42721B9B90074E620 /* JitsiAudioSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ED4FFF22721B9B90074E620 /* JitsiAudioSession.m */; };
|
||||
4EEC9630286C73A2008705FA /* JitsiMeetView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4EEC962E286C73A2008705FA /* JitsiMeetView+Private.h */; };
|
||||
4EEC9631286C73A2008705FA /* JitsiMeetView+Private.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EEC962F286C73A2008705FA /* JitsiMeetView+Private.m */; };
|
||||
6F08DF7D4458EE3CF3F36F6D /* libPods-JitsiMeetSDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E4376CA6886DE68FD7A4294B /* libPods-JitsiMeetSDK.a */; };
|
||||
A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */ = {isa = PBXBuildFile; fileRef = A4A934E8212F3ADB001E9388 /* Dropbox.m */; };
|
||||
C6245F5D2053091D0040BE68 /* image-resize@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6245F5B2053091D0040BE68 /* image-resize@2x.png */; };
|
||||
@@ -85,15 +79,9 @@
|
||||
0BD906E91EC0C00300C8C18E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
4E51B76225E5345E0038575A /* ScheenshareEventEmiter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScheenshareEventEmiter.h; sourceTree = "<group>"; };
|
||||
4E51B76325E5345E0038575A /* ScheenshareEventEmiter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ScheenshareEventEmiter.m; sourceTree = "<group>"; };
|
||||
4EBA6E5F286072E300B31882 /* JitsiMeetViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeetViewController.h; sourceTree = "<group>"; };
|
||||
4EBA6E60286072E300B31882 /* JitsiMeetViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JitsiMeetViewController.m; sourceTree = "<group>"; };
|
||||
4EBA6E632860B1E800B31882 /* JitsiMeetRenderingView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeetRenderingView.h; sourceTree = "<group>"; };
|
||||
4EBA6E642860B1E800B31882 /* JitsiMeetRenderingView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JitsiMeetRenderingView.m; sourceTree = "<group>"; };
|
||||
4ED4FFF12721B9B90074E620 /* JitsiAudioSession.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiAudioSession.h; sourceTree = "<group>"; };
|
||||
4ED4FFF22721B9B90074E620 /* JitsiAudioSession.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JitsiAudioSession.m; sourceTree = "<group>"; };
|
||||
4ED4FFF52721BAE10074E620 /* JitsiAudioSession+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiAudioSession+Private.h"; sourceTree = "<group>"; };
|
||||
4EEC962E286C73A2008705FA /* JitsiMeetView+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetView+Private.h"; sourceTree = "<group>"; };
|
||||
4EEC962F286C73A2008705FA /* JitsiMeetView+Private.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "JitsiMeetView+Private.m"; sourceTree = "<group>"; };
|
||||
891FE43DAD30BC8976683100 /* Pods-JitsiMeetSDK.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeetSDK.release.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeetSDK/Pods-JitsiMeetSDK.release.xcconfig"; sourceTree = "<group>"; };
|
||||
98E09B5C73D9036B4ED252FC /* Pods-JitsiMeet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
9C77CA3CC919B081F1A52982 /* Pods-JitsiMeet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.release.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.release.xcconfig"; sourceTree = "<group>"; };
|
||||
@@ -106,6 +94,7 @@
|
||||
C69EFA0B209A0F660027712B /* JMCallKitListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JMCallKitListener.swift; sourceTree = "<group>"; };
|
||||
C6A3425E204EF76800E062DD /* DragGestureController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragGestureController.swift; sourceTree = "<group>"; };
|
||||
C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiPViewCoordinator.swift; sourceTree = "<group>"; };
|
||||
C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetView+Private.h"; sourceTree = "<group>"; };
|
||||
C81E9AB825AC5AD800B134D9 /* ExternalAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExternalAPI.h; sourceTree = "<group>"; };
|
||||
C8AFD27D2462C613000293D2 /* InfoPlistUtil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InfoPlistUtil.h; sourceTree = "<group>"; };
|
||||
C8AFD27E2462C613000293D2 /* InfoPlistUtil.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InfoPlistUtil.m; sourceTree = "<group>"; };
|
||||
@@ -205,17 +194,12 @@
|
||||
DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */,
|
||||
DE81A2DD2317ED5400AE1940 /* JitsiMeetBaseLogHandler.m */,
|
||||
0B412F161EDEC65D00B1A0A6 /* JitsiMeetView.h */,
|
||||
4EEC962E286C73A2008705FA /* JitsiMeetView+Private.h */,
|
||||
4EEC962F286C73A2008705FA /* JitsiMeetView+Private.m */,
|
||||
0B412F171EDEC65D00B1A0A6 /* JitsiMeetView.m */,
|
||||
4EBA6E632860B1E800B31882 /* JitsiMeetRenderingView.h */,
|
||||
4EBA6E642860B1E800B31882 /* JitsiMeetRenderingView.m */,
|
||||
4EBA6E5F286072E300B31882 /* JitsiMeetViewController.h */,
|
||||
4EBA6E60286072E300B31882 /* JitsiMeetViewController.m */,
|
||||
DE81A2D72316AC7600AE1940 /* LogBridge.m */,
|
||||
DE65AAC92317FFCD00290BEC /* LogUtils.h */,
|
||||
DEAFA777229EAD3B0033A7FA /* RNRootView.h */,
|
||||
DEAFA778229EAD520033A7FA /* RNRootView.m */,
|
||||
C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */,
|
||||
0B412F1B1EDEC80100B1A0A6 /* JitsiMeetViewDelegate.h */,
|
||||
DEFC743D21B178FA00E4DD96 /* LocaleDetector.m */,
|
||||
C6A3426B204F127900E062DD /* picture-in-picture */,
|
||||
@@ -300,14 +284,11 @@
|
||||
DEA9F284258A5D9900D4CD74 /* JitsiMeetSDK.h in Headers */,
|
||||
4E51B76425E5345E0038575A /* ScheenshareEventEmiter.h in Headers */,
|
||||
DE65AACC2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h in Headers */,
|
||||
4EBA6E652860B1E800B31882 /* JitsiMeetRenderingView.h in Headers */,
|
||||
0B412F221EDEF6EA00B1A0A6 /* JitsiMeetViewDelegate.h in Headers */,
|
||||
4ED4FFF32721B9B90074E620 /* JitsiAudioSession.h in Headers */,
|
||||
4EEC9630286C73A2008705FA /* JitsiMeetView+Private.h in Headers */,
|
||||
0BD906EA1EC0C00300C8C18E /* JitsiMeet.h in Headers */,
|
||||
DE81A2D42316AC4D00AE1940 /* JitsiMeetLogger.h in Headers */,
|
||||
DE65AACA2317FFCD00290BEC /* LogUtils.h in Headers */,
|
||||
4EBA6E61286072E300B31882 /* JitsiMeetViewController.h in Headers */,
|
||||
DEAD3226220C497000E93636 /* JitsiMeetConferenceOptions.h in Headers */,
|
||||
C81E9AB925AC5AD800B134D9 /* ExternalAPI.h in Headers */,
|
||||
C8AFD27F2462C613000293D2 /* InfoPlistUtil.h in Headers */,
|
||||
@@ -468,7 +449,6 @@
|
||||
files = (
|
||||
0BB9AD7B1F5EC8F4001C08DB /* CallKit.m in Sources */,
|
||||
DE81A2DF2317ED5400AE1940 /* JitsiMeetBaseLogHandler.m in Sources */,
|
||||
4EBA6E662860B1E800B31882 /* JitsiMeetRenderingView.m in Sources */,
|
||||
4ED4FFF42721B9B90074E620 /* JitsiAudioSession.m in Sources */,
|
||||
0BB9AD7D1F60356D001C08DB /* AppInfo.m in Sources */,
|
||||
DE81A2D92316AC7600AE1940 /* LogBridge.m in Sources */,
|
||||
@@ -485,11 +465,9 @@
|
||||
0BCA49611EC4B6C600B793EE /* Proximity.m in Sources */,
|
||||
C69EFA0C209A0F660027712B /* JMCallKitEmitter.swift in Sources */,
|
||||
DEFE535621FB2E8300011A3A /* ReactUtils.m in Sources */,
|
||||
4EEC9631286C73A2008705FA /* JitsiMeetView+Private.m in Sources */,
|
||||
C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */,
|
||||
4E51B76525E5345E0038575A /* ScheenshareEventEmiter.m in Sources */,
|
||||
A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */,
|
||||
4EBA6E62286072E300B31882 /* JitsiMeetViewController.m in Sources */,
|
||||
C69EFA0D209A0F660027712B /* JMCallKitProxy.swift in Sources */,
|
||||
DE81A2D52316AC4D00AE1940 /* JitsiMeetLogger.m in Sources */,
|
||||
C69EFA0E209A0F660027712B /* JMCallKitListener.swift in Sources */,
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTEventEmitter.h>
|
||||
|
||||
static NSString * const sendEventNotificationName = @"org.jitsi.meet.SendEvent";
|
||||
|
||||
@interface ExternalAPI : RCTEventEmitter<RCTBridgeModule>
|
||||
|
||||
- (void)sendHangUp;
|
||||
@@ -29,6 +27,5 @@ static NSString * const sendEventNotificationName = @"org.jitsi.meet.SendEvent";
|
||||
- (void)closeChat;
|
||||
- (void)sendChatMessage:(NSString*)message :(NSString*)to ;
|
||||
- (void)sendSetVideoMuted:(BOOL)muted;
|
||||
- (void)sendSetClosedCaptionsEnabled:(BOOL)enabled;
|
||||
|
||||
@end
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#import "ExternalAPI.h"
|
||||
#import "JitsiMeetView+Private.h"
|
||||
|
||||
// Events
|
||||
static NSString * const hangUpAction = @"org.jitsi.meet.HANG_UP";
|
||||
@@ -26,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
|
||||
|
||||
@@ -49,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
|
||||
};
|
||||
};
|
||||
|
||||
@@ -74,8 +73,7 @@ RCT_EXPORT_MODULE();
|
||||
openChatAction,
|
||||
closeChatAction,
|
||||
sendChatMessageAction,
|
||||
setVideoMutedAction,
|
||||
setClosedCaptionsEnabledAction
|
||||
setVideoMutedAction
|
||||
];
|
||||
}
|
||||
|
||||
@@ -88,15 +86,33 @@ RCT_EXPORT_MODULE();
|
||||
* @param scope
|
||||
*/
|
||||
RCT_EXPORT_METHOD(sendEvent:(NSString *)name
|
||||
data:(NSDictionary *)data) {
|
||||
data:(NSDictionary *)data
|
||||
scope:(NSString *)scope) {
|
||||
// The JavaScript App needs to provide uniquely identifying information to
|
||||
// the native ExternalAPI module so that the latter may match the former
|
||||
// to the native JitsiMeetView which hosts it.
|
||||
JitsiMeetView *view = [JitsiMeetView viewForExternalAPIScope:scope];
|
||||
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
|
||||
id delegate = view.delegate;
|
||||
|
||||
if (!delegate) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ([name isEqual: @"PARTICIPANTS_INFO_RETRIEVED"]) {
|
||||
[self onParticipantsInfoRetrieved: data];
|
||||
return;
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:sendEventNotificationName
|
||||
object:nil
|
||||
userInfo:@{@"name": name, @"data": data}];
|
||||
|
||||
SEL sel = NSSelectorFromString([self methodNameFromEventName:name]);
|
||||
|
||||
if (sel && [delegate respondsToSelector:sel]) {
|
||||
[delegate performSelector:sel withObject:data];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) onParticipantsInfoRetrieved:(NSDictionary *)data {
|
||||
@@ -108,6 +124,28 @@ RCT_EXPORT_METHOD(sendEvent:(NSString *)name
|
||||
[participantInfoCompletionHandlers removeObjectForKey:completionHandlerId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a specific event name i.e. redux action type description to a
|
||||
* method name.
|
||||
*
|
||||
* @param eventName The event name to convert to a method name.
|
||||
* @return A method name constructed from the specified `eventName`.
|
||||
*/
|
||||
- (NSString *)methodNameFromEventName:(NSString *)eventName {
|
||||
NSMutableString *methodName
|
||||
= [NSMutableString stringWithCapacity:eventName.length];
|
||||
|
||||
for (NSString *c in [eventName componentsSeparatedByString:@"_"]) {
|
||||
if (c.length) {
|
||||
[methodName appendString:
|
||||
methodName.length ? c.capitalizedString : c.lowercaseString];
|
||||
}
|
||||
}
|
||||
[methodName appendString:@":"];
|
||||
|
||||
return methodName;
|
||||
}
|
||||
|
||||
- (void)sendHangUp {
|
||||
[self sendEventWithName:hangUpAction body:nil];
|
||||
}
|
||||
@@ -167,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
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>99.0.0</string>
|
||||
<string>5.1.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
|
||||
#import <Intents/Intents.h>
|
||||
#import <RNGoogleSignin/RNGoogleSignin.h>
|
||||
#import <WebRTC/RTCLogging.h>
|
||||
|
||||
#import "Dropbox.h"
|
||||
#import "JitsiMeet+Private.h"
|
||||
@@ -27,6 +25,9 @@
|
||||
#import "RNSplashScreen.h"
|
||||
#import "ScheenshareEventEmiter.h"
|
||||
|
||||
#import <RNGoogleSignin/RNGoogleSignin.h>
|
||||
#import <WebRTC/RTCLogging.h>
|
||||
|
||||
@implementation JitsiMeet {
|
||||
RCTBridgeWrapper *_bridgeWrapper;
|
||||
NSDictionary *_launchOptions;
|
||||
@@ -86,12 +87,8 @@
|
||||
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *))restorationHandler {
|
||||
|
||||
JitsiMeetConferenceOptions *options = [self optionsFromUserActivity:userActivity];
|
||||
if (options) {
|
||||
[JitsiMeetView updateProps:[options asProps]];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return options && [JitsiMeetView setPropsInViews:[options asProps]];
|
||||
}
|
||||
|
||||
- (BOOL)application:(UIApplication *)app
|
||||
@@ -115,9 +112,8 @@
|
||||
JitsiMeetConferenceOptions *conferenceOptions = [JitsiMeetConferenceOptions fromBuilder:^(JitsiMeetConferenceOptionsBuilder *builder) {
|
||||
builder.room = [url absoluteString];
|
||||
}];
|
||||
[JitsiMeetView updateProps:[conferenceOptions asProps]];
|
||||
|
||||
return true;
|
||||
return [JitsiMeetView setPropsInViews:[conferenceOptions asProps]];
|
||||
}
|
||||
|
||||
#pragma mark - Utility methods
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright @ 2022-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "JitsiMeetViewDelegate.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface JitsiMeetRenderingView : UIView
|
||||
|
||||
@property (nonatomic, assign) BOOL isPiPEnabled;
|
||||
|
||||
- (void)setProps:(NSDictionary *_Nonnull)newProps;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright @ 2022-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
#import "JitsiMeetRenderingView.h"
|
||||
#import "ReactUtils.h"
|
||||
#import "RNRootView.h"
|
||||
#import "JitsiMeet+Private.h"
|
||||
|
||||
/**
|
||||
* Backwards compatibility: turn the boolean prop into a feature flag.
|
||||
*/
|
||||
static NSString *const PiPEnabledFeatureFlag = @"pip.enabled";
|
||||
|
||||
@interface JitsiMeetRenderingView ()
|
||||
@end
|
||||
|
||||
@implementation JitsiMeetRenderingView {
|
||||
/**
|
||||
* React Native view where the entire content will be rendered.
|
||||
*/
|
||||
RNRootView *rootView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes the given props to the React Native application. The props which we pass
|
||||
* are a combination of 3 different sources:
|
||||
*
|
||||
* - JitsiMeet.defaultConferenceOptions
|
||||
* - This function's parameters
|
||||
* - Some extras which are added by this function
|
||||
*/
|
||||
- (void)setProps:(NSDictionary *_Nonnull)newProps {
|
||||
NSMutableDictionary *props = mergeProps([[JitsiMeet sharedInstance] getDefaultProps], newProps);
|
||||
|
||||
// Set the PiP flag if it wasn't manually set.
|
||||
NSMutableDictionary *featureFlags = props[@"flags"];
|
||||
// TODO: temporary implementation
|
||||
if (featureFlags[PiPEnabledFeatureFlag] == nil) {
|
||||
featureFlags[PiPEnabledFeatureFlag] = @(self.isPiPEnabled);
|
||||
}
|
||||
|
||||
// This method is supposed to be imperative i.e. a second
|
||||
// invocation with one and the same URL is expected to join the respective
|
||||
// conference again if the first invocation was followed by leaving the
|
||||
// conference. However, React and, respectively,
|
||||
// appProperties/initialProperties are declarative expressions i.e. one and
|
||||
// the same URL will not trigger an automatic re-render in the JavaScript
|
||||
// source code. The workaround implemented below introduces imperativeness
|
||||
// in React Component props by defining a unique value per invocation.
|
||||
props[@"timestamp"] = @(mach_absolute_time());
|
||||
|
||||
if (rootView) {
|
||||
// Update props with the new URL.
|
||||
rootView.appProperties = props;
|
||||
} else {
|
||||
RCTBridge *bridge = [[JitsiMeet sharedInstance] getReactBridge];
|
||||
rootView = [[RNRootView alloc] initWithBridge:bridge
|
||||
moduleName:@"App"
|
||||
initialProperties:props];
|
||||
rootView.backgroundColor = self.backgroundColor;
|
||||
|
||||
// Add rootView as a subview which completely covers this one.
|
||||
[rootView setFrame:[self bounds]];
|
||||
rootView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[self addSubview:rootView];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright @ 2022-present 8x8, Inc.
|
||||
* Copyright @ 2018-present 8x8, Inc.
|
||||
* Copyright @ 2017-2018 Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,16 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <JitsiMeetSDK/JitsiMeetSDK.h>
|
||||
#import "JitsiMeetView.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@interface JitsiMeetView ()
|
||||
|
||||
static NSString * const updateViewPropsNotificationName = @"org.jitsi.meet.UpdateViewProps";
|
||||
|
||||
@interface JitsiMeetView (Private)
|
||||
|
||||
+ (void)updateProps:(NSDictionary *_Nonnull)newProps;
|
||||
+ (instancetype _Nullable)viewForExternalAPIScope:(NSString *_Nonnull)externalAPIScope;
|
||||
+ (BOOL)setPropsInViews:(NSDictionary *_Nonnull)newProps;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright @ 2022-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "JitsiMeetView+Private.h"
|
||||
|
||||
@implementation JitsiMeetView (Private)
|
||||
|
||||
+ (void)updateProps:(NSDictionary *_Nonnull)newProps {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:updateViewPropsNotificationName object:nil userInfo:@{@"props": newProps}];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -45,6 +45,5 @@
|
||||
- (void)closeChat;
|
||||
- (void)sendChatMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to;
|
||||
- (void)setVideoMuted:(BOOL)muted;
|
||||
- (void)setClosedCaptionsEnabled:(BOOL)enabled;
|
||||
|
||||
@end
|
||||
|
||||
@@ -20,22 +20,43 @@
|
||||
#import "ExternalAPI.h"
|
||||
#import "JitsiMeet+Private.h"
|
||||
#import "JitsiMeetConferenceOptions+Private.h"
|
||||
#import "JitsiMeetView.h"
|
||||
#import "JitsiMeetViewController.h"
|
||||
#import "JitsiMeetView+Private.h"
|
||||
#import "ReactUtils.h"
|
||||
#import "RNRootView.h"
|
||||
|
||||
@interface JitsiMeetView ()
|
||||
|
||||
@property (nonatomic, strong) JitsiMeetViewController *jitsiMeetViewController;
|
||||
@property (nonatomic, strong) UINavigationController *navController;
|
||||
@property (nonatomic, readonly) BOOL isPiPEnabled;
|
||||
/**
|
||||
* Backwards compatibility: turn the boolean prop into a feature flag.
|
||||
*/
|
||||
static NSString *const PiPEnabledFeatureFlag = @"pip.enabled";
|
||||
|
||||
@end
|
||||
|
||||
@implementation JitsiMeetView
|
||||
@implementation JitsiMeetView {
|
||||
/**
|
||||
* The unique identifier of this `JitsiMeetView` within the process for the
|
||||
* purposes of `ExternalAPI`. The name scope was inspired by postis which we
|
||||
* use on Web for the similar purposes of the iframe-based external API.
|
||||
*/
|
||||
NSString *externalAPIScope;
|
||||
|
||||
@dynamic isPiPEnabled;
|
||||
/**
|
||||
* React Native view where the entire content will be rendered.
|
||||
*/
|
||||
RNRootView *rootView;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `JitsiMeetView`s associated with their `ExternalAPI` scopes (i.e. unique
|
||||
* identifiers within the process).
|
||||
*/
|
||||
static NSMapTable<NSString *, JitsiMeetView *> *views;
|
||||
/**
|
||||
* This gets called automagically when the program starts.
|
||||
*/
|
||||
__attribute__((constructor))
|
||||
static void initializeViewsMap() {
|
||||
views = [NSMapTable strongToWeakObjectsMapTable];
|
||||
}
|
||||
|
||||
#pragma mark Initializers
|
||||
|
||||
@@ -66,10 +87,6 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal initialization:
|
||||
*
|
||||
@@ -77,105 +94,145 @@
|
||||
* - initializes the external API scope
|
||||
*/
|
||||
- (void)initWithXXX {
|
||||
self.jitsiMeetViewController = [[JitsiMeetViewController alloc] init];
|
||||
self.jitsiMeetViewController.view.frame = [self bounds];
|
||||
[self addSubview:self.jitsiMeetViewController.view];
|
||||
|
||||
[self registerObservers];
|
||||
// Hook this JitsiMeetView into ExternalAPI.
|
||||
externalAPIScope = [NSUUID UUID].UUIDString;
|
||||
[views setObject:self forKey:externalAPIScope];
|
||||
|
||||
// Set a background color which is in accord with the JavaScript and Android
|
||||
// parts of the application and causes less perceived visual flicker than
|
||||
// the default background color.
|
||||
self.backgroundColor
|
||||
= [UIColor colorWithRed:.07f green:.07f blue:.07f alpha:1];
|
||||
}
|
||||
|
||||
#pragma mark API
|
||||
|
||||
- (void)join:(JitsiMeetConferenceOptions *)options {
|
||||
[self.jitsiMeetViewController join:options withPiP:self.isPiPEnabled];
|
||||
[self setProps:options == nil ? @{} : [options asProps]];
|
||||
}
|
||||
|
||||
- (void)leave {
|
||||
[self.jitsiMeetViewController leave];
|
||||
[self setProps:@{}];
|
||||
}
|
||||
|
||||
- (void)hangUp {
|
||||
[self.jitsiMeetViewController hangUp];
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI sendHangUp];
|
||||
}
|
||||
|
||||
- (void)setAudioMuted:(BOOL)muted {
|
||||
[self.jitsiMeetViewController setAudioMuted:muted];
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI sendSetAudioMuted:muted];
|
||||
}
|
||||
|
||||
- (void)sendEndpointTextMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to {
|
||||
[self.jitsiMeetViewController sendEndpointTextMessage:message :to];
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI sendEndpointTextMessage:message :to];
|
||||
}
|
||||
|
||||
- (void)toggleScreenShare:(BOOL)enabled {
|
||||
[self.jitsiMeetViewController toggleScreenShare:enabled];
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI toggleScreenShare:enabled];
|
||||
}
|
||||
|
||||
- (void)retrieveParticipantsInfo:(void (^ _Nonnull)(NSArray * _Nullable))completionHandler {
|
||||
[self.jitsiMeetViewController retrieveParticipantsInfo:completionHandler];
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI retrieveParticipantsInfo:completionHandler];
|
||||
}
|
||||
|
||||
- (void)openChat:(NSString*)to {
|
||||
[self.jitsiMeetViewController openChat:to];
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI openChat:to];
|
||||
}
|
||||
|
||||
- (void)closeChat {
|
||||
[self.jitsiMeetViewController closeChat];
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI closeChat];
|
||||
}
|
||||
|
||||
- (void)sendChatMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to {
|
||||
[self.jitsiMeetViewController sendChatMessage:message :to];
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI sendChatMessage:message :to];
|
||||
}
|
||||
|
||||
- (void)setVideoMuted:(BOOL)muted {
|
||||
[self.jitsiMeetViewController setVideoMuted:muted];
|
||||
}
|
||||
|
||||
- (void)setClosedCaptionsEnabled:(BOOL)enabled {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI sendSetClosedCaptionsEnabled:enabled];
|
||||
[externalAPI sendSetVideoMuted:muted];
|
||||
}
|
||||
|
||||
#pragma mark Private
|
||||
#pragma mark Private methods
|
||||
|
||||
- (BOOL)isPiPEnabled {
|
||||
return self.delegate && [self.delegate respondsToSelector:@selector(enterPictureInPicture:)];
|
||||
}
|
||||
/**
|
||||
* Passes the given props to the React Native application. The props which we pass
|
||||
* are a combination of 3 different sources:
|
||||
*
|
||||
* - JitsiMeet.defaultConferenceOptions
|
||||
* - This function's parameters
|
||||
* - Some extras which are added by this function
|
||||
*/
|
||||
- (void)setProps:(NSDictionary *_Nonnull)newProps {
|
||||
NSMutableDictionary *props = mergeProps([[JitsiMeet sharedInstance] getDefaultProps], newProps);
|
||||
|
||||
- (void)registerObservers {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleSendEventNotification:) name:sendEventNotificationName object:nil];
|
||||
}
|
||||
// Set the PiP flag if it wasn't manually set.
|
||||
NSMutableDictionary *featureFlags = props[@"flags"];
|
||||
if (featureFlags[PiPEnabledFeatureFlag] == nil) {
|
||||
featureFlags[PiPEnabledFeatureFlag]
|
||||
= [NSNumber numberWithBool:
|
||||
self.delegate && [self.delegate respondsToSelector:@selector(enterPictureInPicture:)]];
|
||||
}
|
||||
|
||||
- (void)handleSendEventNotification:(NSNotification *)notification {
|
||||
NSString *eventName = notification.userInfo[@"name"];
|
||||
NSString *eventData = notification.userInfo[@"data"];
|
||||
|
||||
SEL sel = NSSelectorFromString([self methodNameFromEventName:eventName]);
|
||||
props[@"externalAPIScope"] = externalAPIScope;
|
||||
|
||||
if (sel && [self.delegate respondsToSelector:sel]) {
|
||||
[self.delegate performSelector:sel withObject:eventData];
|
||||
// This method is supposed to be imperative i.e. a second
|
||||
// invocation with one and the same URL is expected to join the respective
|
||||
// conference again if the first invocation was followed by leaving the
|
||||
// conference. However, React and, respectively,
|
||||
// appProperties/initialProperties are declarative expressions i.e. one and
|
||||
// the same URL will not trigger an automatic re-render in the JavaScript
|
||||
// source code. The workaround implemented below introduces imperativeness
|
||||
// in React Component props by defining a unique value per invocation.
|
||||
props[@"timestamp"] = @(mach_absolute_time());
|
||||
|
||||
if (rootView) {
|
||||
// Update props with the new URL.
|
||||
rootView.appProperties = props;
|
||||
} else {
|
||||
RCTBridge *bridge = [[JitsiMeet sharedInstance] getReactBridge];
|
||||
rootView
|
||||
= [[RNRootView alloc] initWithBridge:bridge
|
||||
moduleName:@"App"
|
||||
initialProperties:props];
|
||||
rootView.backgroundColor = self.backgroundColor;
|
||||
|
||||
// Add rootView as a subview which completely covers this one.
|
||||
[rootView setFrame:[self bounds]];
|
||||
rootView.autoresizingMask
|
||||
= UIViewAutoresizingFlexibleWidth
|
||||
| UIViewAutoresizingFlexibleHeight;
|
||||
[self addSubview:rootView];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a specific event name i.e. redux action type description to a
|
||||
* method name.
|
||||
*
|
||||
* @param eventName The event name to convert to a method name.
|
||||
* @return A method name constructed from the specified `eventName`.
|
||||
*/
|
||||
- (NSString *)methodNameFromEventName:(NSString *)eventName {
|
||||
NSMutableString *methodName
|
||||
= [NSMutableString stringWithCapacity:eventName.length];
|
||||
+ (BOOL)setPropsInViews:(NSDictionary *_Nonnull)newProps {
|
||||
BOOL handled = NO;
|
||||
|
||||
for (NSString *c in [eventName componentsSeparatedByString:@"_"]) {
|
||||
if (c.length) {
|
||||
[methodName appendString:
|
||||
methodName.length ? c.capitalizedString : c.lowercaseString];
|
||||
}
|
||||
}
|
||||
[methodName appendString:@":"];
|
||||
if (views) {
|
||||
for (NSString *externalAPIScope in views) {
|
||||
JitsiMeetView *view
|
||||
= [self viewForExternalAPIScope:externalAPIScope];
|
||||
|
||||
return methodName;
|
||||
if (view) {
|
||||
[view setProps:newProps];
|
||||
handled = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
+ (instancetype)viewForExternalAPIScope:(NSString *)externalAPIScope {
|
||||
return [views objectForKey:externalAPIScope];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright @ 2022-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "JitsiMeetConferenceOptions.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface JitsiMeetViewController : UIViewController
|
||||
|
||||
- (void)join:(JitsiMeetConferenceOptions *)options withPiP:(BOOL)enablePiP;
|
||||
- (void)leave;
|
||||
- (void)hangUp;
|
||||
- (void)setAudioMuted:(BOOL)muted;
|
||||
- (void)sendEndpointTextMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to;
|
||||
- (void)toggleScreenShare:(BOOL)enabled;
|
||||
- (void)retrieveParticipantsInfo:(void (^ _Nonnull)(NSArray * _Nullable))completionHandler;
|
||||
- (void)openChat:(NSString*)to;
|
||||
- (void)closeChat;
|
||||
- (void)sendChatMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to;
|
||||
- (void)setVideoMuted:(BOOL)muted;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright @ 2022-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "JitsiMeetViewController.h"
|
||||
#import "JitsiMeet+Private.h"
|
||||
#import "JitsiMeetConferenceOptions+Private.h"
|
||||
#import "JitsiMeetRenderingView.h"
|
||||
#import "JitsiMeetView+Private.h"
|
||||
|
||||
@interface JitsiMeetViewController ()
|
||||
|
||||
@property (strong, nonatomic) JitsiMeetRenderingView *view;
|
||||
|
||||
@end
|
||||
|
||||
@implementation JitsiMeetViewController
|
||||
|
||||
@dynamic view;
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[self registerObservers];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)loadView {
|
||||
[super loadView];
|
||||
|
||||
self.view = [[JitsiMeetRenderingView alloc] init];
|
||||
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// Set a background color which is in accord with the JavaScript and Android
|
||||
// parts of the application and causes less perceived visual flicker than
|
||||
// the default background color.
|
||||
self.view.backgroundColor = [UIColor colorWithRed:.07f green:.07f blue:.07f alpha:1];
|
||||
}
|
||||
|
||||
- (void)join:(JitsiMeetConferenceOptions *)options withPiP:(BOOL)enablePiP {
|
||||
self.view.isPiPEnabled = enablePiP;
|
||||
[self.view setProps:options == nil ? @{} : [options asProps]];
|
||||
}
|
||||
|
||||
- (void)leave {
|
||||
[self.view setProps:@{}];
|
||||
}
|
||||
|
||||
- (void)hangUp {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI sendHangUp];
|
||||
}
|
||||
|
||||
- (void)setAudioMuted:(BOOL)muted {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI sendSetAudioMuted:muted];
|
||||
}
|
||||
|
||||
- (void)sendEndpointTextMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI sendEndpointTextMessage:message :to];
|
||||
}
|
||||
|
||||
- (void)toggleScreenShare:(BOOL)enabled {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI toggleScreenShare:enabled];
|
||||
}
|
||||
|
||||
- (void)retrieveParticipantsInfo:(void (^ _Nonnull)(NSArray * _Nullable))completionHandler {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI retrieveParticipantsInfo:completionHandler];
|
||||
}
|
||||
|
||||
- (void)openChat:(NSString*)to {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI openChat:to];
|
||||
}
|
||||
|
||||
- (void)closeChat {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI closeChat];
|
||||
}
|
||||
|
||||
- (void)sendChatMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI sendChatMessage:message :to];
|
||||
}
|
||||
|
||||
- (void)setVideoMuted:(BOOL)muted {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI sendSetVideoMuted:muted];
|
||||
}
|
||||
|
||||
#pragma mark Private
|
||||
|
||||
- (void)registerObservers {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleUpdateViewPropsNotification:) name:updateViewPropsNotificationName object:nil];
|
||||
}
|
||||
|
||||
- (void)handleUpdateViewPropsNotification:(NSNotification *)notification {
|
||||
NSDictionary *props = [notification.userInfo objectForKey:@"props"];
|
||||
[self.view setProps:props];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -116,7 +116,6 @@
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
"buttonText": "نزِّل إضافة متصفح كروم",
|
||||
"buttonTextEdge": "قم بتثبيت ملحق Edge",
|
||||
"close": "إغلق",
|
||||
"dontShowAgain": "لا ترني هذه مرة أخرى",
|
||||
"installExtensionText": "نزِّل الإضافة للدمج مع رزنامة غوغل ورزنامة أوفيس 365"
|
||||
@@ -208,9 +207,6 @@
|
||||
"selectADevice": "اختر جهازًا",
|
||||
"testAudio": "اختبر الصوت"
|
||||
},
|
||||
"dialIn": {
|
||||
"screenTitle": "ملخص الطلب"
|
||||
},
|
||||
"dialOut": {
|
||||
"statusMessage": "{{status}} الآن"
|
||||
},
|
||||
@@ -661,8 +657,6 @@
|
||||
"linkToSalesforceKey": "ربط هذا المُلتقى",
|
||||
"linkToSalesforceProgress": "جارٍ ربط الاجتماع بـ Salesforce ...",
|
||||
"linkToSalesforceSuccess": "تم ربط الاجتماع بـ Salesforce",
|
||||
"localRecordingStarted": "بدأ {{name}} تسجيلًا محليًا.",
|
||||
"localRecordingStopped": "أوقف {{name}} التسجيل المحلي.",
|
||||
"me": "أنا",
|
||||
"moderationInEffectCSDescription": "يرجى رفع اليد إذا كنت تريد مشاركة شاشتك.",
|
||||
"moderationInEffectCSTitle": "تم حظر مشاركة الشاشة من قبل المشرف",
|
||||
@@ -818,7 +812,6 @@
|
||||
"initiated": "بدأ الاتصال",
|
||||
"joinAudioByPhone": "انضم مع صوت من الجوال",
|
||||
"joinMeeting": "انضم للمُلتقى",
|
||||
"joinMeetingInLowBandwidthMode": "الانضمام في وضع النطاق الترددي المنخفض",
|
||||
"joinWithoutAudio": "انضم دون صوت",
|
||||
"keyboardShortcuts": "تفعيل اختصارات لوحة المفاتيح",
|
||||
"linkCopied": "نُسِخ الرابط",
|
||||
@@ -894,7 +887,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 +894,6 @@
|
||||
"onBy": "بدأ {{name}} التسجيل",
|
||||
"pending": "التحضير لتسجيل المُلتقى...",
|
||||
"rec": "تسجيل",
|
||||
"saveLocalRecording": "حفظ ملف التسجيل محليا",
|
||||
"serviceDescription": "ستحفظ خدمة التسجيل الفيديو المستجل",
|
||||
"serviceDescriptionCloud": "تسجيل سحابي",
|
||||
"serviceDescriptionCloudInfo": "يتم مسح المُلتقيات المسجلة تلقائيًا بعد 24 ساعة من وقت التسجيل.",
|
||||
@@ -910,7 +901,6 @@
|
||||
"sessionAlreadyActive": "هذه الجلسة قيد التسجيل أو البث المباشر.",
|
||||
"signIn": "دخول",
|
||||
"signOut": "خروج",
|
||||
"surfaceError": "الرجاء تحديد علامة التبويب الحالية.",
|
||||
"unavailable": "عجبًا! {{serviceName}} غير متاحة حاليًا. نعمل على حل المشكلة. حاول مرة أخرى لاحقًا.",
|
||||
"unavailableTitle": "التسجيل غير متاح",
|
||||
"uploadToCloud": "تحميل إلى السحابة"
|
||||
@@ -953,7 +943,6 @@
|
||||
"playSounds": "تشغيل الصوت عند:",
|
||||
"reactions": "ردود فعل المُلتقى",
|
||||
"sameAsSystem": "مثل النظام ({{label}})",
|
||||
"screenTitle": "إعدادات",
|
||||
"selectAudioOutput": "خرج الصوت",
|
||||
"selectCamera": "الكاميرا",
|
||||
"selectMic": "المجهار (المايكروفون)",
|
||||
@@ -979,7 +968,6 @@
|
||||
"disableCrashReportingWarning": "أمتأكد من تعطيل تقارير الأعطال التقنية؟ ستسري الإعدادات الجديدة بعد إعادة تشغيل التطبيق",
|
||||
"disableP2P": "تعطيل وضع واحد شخص-لشخص",
|
||||
"displayName": "عرض الاسم",
|
||||
"displayNamePlaceholderText": "على سبيل المثال: علي الحيدري",
|
||||
"email": "البريد الإلكتروني",
|
||||
"header": "الإعدادات",
|
||||
"profileSection": "الملف الشخصي",
|
||||
@@ -1038,7 +1026,6 @@
|
||||
"chat": "اظهِر/اخفِ نافذة الدردشة",
|
||||
"clap": "تصفيق",
|
||||
"collapse": "قلّص",
|
||||
"dock": "إرساء في النافذة الرئيسية",
|
||||
"document": "اظهِر/اخفِ الملف المشارك",
|
||||
"download": "نزِّل التطبيق",
|
||||
"embedMeeting": "ضمِّن المُلتقى",
|
||||
@@ -1089,7 +1076,6 @@
|
||||
"tileView": "اظهِر/اخفِ عرض العنوان",
|
||||
"toggleCamera": "بدِّل الكاميرا",
|
||||
"toggleFilmstrip": "بدِّل وضع الشريط السينمائي (filmstrip)",
|
||||
"undock": "فك في نافذة منفصلة",
|
||||
"videoblur": "استعمل/اخرج من وضع تغبيش خلفية الفيديو",
|
||||
"videomute": "بدِّل وضع اخفاء الفيديو"
|
||||
},
|
||||
@@ -1106,7 +1092,6 @@
|
||||
"closeChat": "أغلق الدردشة",
|
||||
"closeReactionsMenu": "إغلاق قائمة ردود الفعل",
|
||||
"disableReactionSounds": "يمكنك تعطيل أصوات ردود الفعل لهذا المُلتقى",
|
||||
"dock": "إرساء في النافذة الرئيسية",
|
||||
"documentClose": "أغلق الملف المشارك",
|
||||
"documentOpen": "افتح الملف المشارك",
|
||||
"download": "نزِّل التطبيق",
|
||||
@@ -1175,7 +1160,6 @@
|
||||
"talkWhileMutedPopup": "أتحاول التحدث؟ المجهار مكتوم لديك.",
|
||||
"tileViewToggle": "بدِّل عنوان العرض",
|
||||
"toggleCamera": "بدِّل الكاميرا",
|
||||
"undock": "فك في نافذة منفصلة",
|
||||
"videoSettings": "اعدادات الفيديو",
|
||||
"videomute": "استعمل / أوقف الكاميرا"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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 nell’immagine",
|
||||
"pip": "Attiva/disattiva immagine nell’immagine",
|
||||
"privateMessage": "Invia messaggio privato",
|
||||
"profile": "Modifica profilo",
|
||||
"raiseHand": "Alza/Abbassa la mano",
|
||||
"reactionsMenu": "Apri/Chiudi menù delle reaction",
|
||||
"recording": "Avvia/Ferma registrazione",
|
||||
"reactionsMenu": "Apri/chiudi menù delle reaction",
|
||||
"recording": "Avvia/ferma registrazione",
|
||||
"remoteMute": "Spegni microfono al partecipante",
|
||||
"remoteVideoMute": "Spegni videocamera del partecipante",
|
||||
"security": "Impostazioni di sicurezza",
|
||||
"selectBackground": "Scegli sfondo",
|
||||
"selfView": "Mostra tua immagine",
|
||||
"shareRoom": "Invita qualcuno",
|
||||
"shareYourScreen": "Attiva/Disattiva condivisione schermo",
|
||||
"shareYourScreen": "Attiva/disattiva condivisione schermo",
|
||||
"shareaudio": "Condividi audio",
|
||||
"sharedvideo": "Attiva/Disattiva condivisione",
|
||||
"shortcuts": "Attiva/Disattiva scorciatoie",
|
||||
"sharedvideo": "Attiva/disattiva condivisione",
|
||||
"shortcuts": "Attiva/disattiva scorciatoie",
|
||||
"show": "Mostra in primo piano",
|
||||
"silence": "Silenzio",
|
||||
"speakerStats": "Attiva/Disattiva statistiche relatore",
|
||||
"speakerStats": "Attiva/disattiva statistiche relatore",
|
||||
"surprised": "Sorpreso",
|
||||
"tileView": "Vedi tutti i partecipanti, 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",
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -116,7 +116,6 @@
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
"buttonText": "Install Chrome Extension",
|
||||
"buttonTextEdge": "Install Edge Extension",
|
||||
"close": "Close",
|
||||
"dontShowAgain": "Don’t show me this again",
|
||||
"installExtensionText": "Install the extension for Google Calendar and Office 365 integration"
|
||||
@@ -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,23 +887,13 @@
|
||||
"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.",
|
||||
"localRecordingNoVideo": "Video is not being recorded",
|
||||
"localRecordingStartWarning": "Please make sure you stop the recording before exiting the meeting in order to save it.",
|
||||
"localRecordingStartWarningTitle": "Stop the recording to save it",
|
||||
"localRecordingVideoStop": "Stopping your video will also stop the local recording. Are you sure you want to continue?",
|
||||
"localRecordingVideoWarning": "To record your video you must have it on when starting the recording",
|
||||
"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}}",
|
||||
"noStreams": "No audio or video stream detected.",
|
||||
"off": "Recording stopped",
|
||||
"offBy": "{{name}} stopped the recording",
|
||||
"on": "Recording started",
|
||||
"onBy": "{{name}} started the recording",
|
||||
"onlyRecordSelf": "Record only my audio and video streams",
|
||||
"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.",
|
||||
@@ -918,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"
|
||||
@@ -957,12 +939,10 @@
|
||||
"name": "Name",
|
||||
"noDevice": "None",
|
||||
"participantJoined": "Participant Joined",
|
||||
"participantKnocking": "Participant entered lobby",
|
||||
"participantLeft": "Participant Left",
|
||||
"playSounds": "Play sound on",
|
||||
"reactions": "Meeting reactions",
|
||||
"sameAsSystem": "Same as system ({{label}})",
|
||||
"screenTitle": "Settings",
|
||||
"selectAudioOutput": "Audio output",
|
||||
"selectCamera": "Camera",
|
||||
"selectMic": "Microphone",
|
||||
@@ -988,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",
|
||||
@@ -1033,7 +1012,6 @@
|
||||
"termsView": {
|
||||
"header": "Terms"
|
||||
},
|
||||
"toggleTopPanelLabel": "Toggle top panel",
|
||||
"toolbar": {
|
||||
"Settings": "Settings",
|
||||
"accessibilityLabel": {
|
||||
@@ -1048,7 +1026,6 @@
|
||||
"chat": "Open / Close chat",
|
||||
"clap": "Clap",
|
||||
"collapse": "Collapse",
|
||||
"dock": "Dock in main window",
|
||||
"document": "Toggle shared document",
|
||||
"download": "Download our apps",
|
||||
"embedMeeting": "Embed meeting",
|
||||
@@ -1099,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"
|
||||
},
|
||||
@@ -1116,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",
|
||||
@@ -1185,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"
|
||||
},
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
11
modules/API/external/external_api.js
vendored
11
modules/API/external/external_api.js
vendored
@@ -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({
|
||||
|
||||
432
package-lock.json
generated
432
package-lock.json
generated
@@ -34,7 +34,7 @@
|
||||
"@hapi/bourne": "2.0.0",
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
"@jitsi/rtcstats": "9.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,7 +49,7 @@
|
||||
"@react-navigation/elements": "1.2.1",
|
||||
"@react-navigation/material-top-tabs": "6.0.6",
|
||||
"@react-navigation/native": "6.0.6",
|
||||
"@react-navigation/stack": "6.2.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",
|
||||
@@ -72,9 +72,8 @@
|
||||
"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/v1466.0.0+2682b4ec/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1431.0.0+742232c9/lib-jitsi-meet.tgz",
|
||||
"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",
|
||||
@@ -104,7 +103,7 @@
|
||||
"react-native-performance": "2.1.0",
|
||||
"react-native-reanimated": "https://git@github.com/software-mansion/react-native-reanimated#c4a6b6f687ede090f6081064abe83a2ef9a05784",
|
||||
"react-native-safe-area-context": "3.3.2",
|
||||
"react-native-screens": "3.13.1",
|
||||
"react-native-screens": "3.10.1",
|
||||
"react-native-sound": "0.11.1",
|
||||
"react-native-splash-screen": "3.3.0",
|
||||
"react-native-svg": "12.1.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",
|
||||
@@ -125,12 +124,10 @@
|
||||
"redux-thunk": "2.2.0",
|
||||
"resemblejs": "4.0.0",
|
||||
"rnnoise-wasm": "https://git@github.com/jitsi/rnnoise-wasm#566a16885897704d6e6d67a1d5ac5d39781db2af",
|
||||
"seamless-scroll-polyfill": "2.1.8",
|
||||
"styled-components": "3.4.9",
|
||||
"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"
|
||||
},
|
||||
@@ -143,11 +140,7 @@
|
||||
"@babel/preset-react": "7.16.0",
|
||||
"@babel/runtime": "7.16.0",
|
||||
"@jitsi/eslint-config": "4.0.0",
|
||||
"@types/lodash": "4.14.182",
|
||||
"@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",
|
||||
@@ -170,7 +163,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",
|
||||
@@ -3553,13 +3546,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": {
|
||||
@@ -5035,12 +5052,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/stack": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-6.2.2.tgz",
|
||||
"integrity": "sha512-P9ZfmluOXNmbs7YdG1UWS1fAh87Yse9aX8TgqOz4FlHEm5q7g5eaM35QgWByt+wif3UiqE40D8wXpqRQvMgPWg==",
|
||||
"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.3.4",
|
||||
"color": "^4.2.3",
|
||||
"@react-navigation/elements": "^1.2.1",
|
||||
"color": "^3.1.3",
|
||||
"warn-once": "^0.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -5052,45 +5069,6 @@
|
||||
"react-native-screens": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/stack/node_modules/@react-navigation/elements": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.4.tgz",
|
||||
"integrity": "sha512-O0jICpjn3jskVo4yiWzZozmj7DZy1ZBbn3O7dbenuUjZSj/cscjwaapmZZFGcI/IMmjmx8UTKsybhCFEIbGf3g==",
|
||||
"peerDependencies": {
|
||||
"@react-navigation/native": "^6.0.0",
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-safe-area-context": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/stack/node_modules/color": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
||||
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1",
|
||||
"color-string": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/stack/node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/stack/node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/@sideway/address": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
|
||||
@@ -5417,16 +5395,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",
|
||||
@@ -5474,12 +5442,6 @@
|
||||
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.182",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
|
||||
"integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/long": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz",
|
||||
@@ -5529,9 +5491,9 @@
|
||||
"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": "*",
|
||||
@@ -5547,18 +5509,6 @@
|
||||
"@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",
|
||||
@@ -5611,12 +5561,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",
|
||||
@@ -7925,9 +7869,9 @@
|
||||
"integrity": "sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA=="
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
||||
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
@@ -8379,11 +8323,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",
|
||||
@@ -10718,14 +10657,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",
|
||||
@@ -11688,11 +11619,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",
|
||||
@@ -12206,8 +12132,8 @@
|
||||
},
|
||||
"node_modules/lib-jitsi-meet": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1466.0.0+2682b4ec/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-p6PWid1e5pDw/Y9NYU32Xik6UPJ9QFUq3DawHNMPdo3tXc+5ogWKF2LT7ieA2cl5RbINnnE7oNXTkrDsQwsWiA==",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1431.0.0+742232c9/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-M2tybHP1w4AXcsUH33aiTgPlr/I0uqcwfHYUo2/zpmhI7gaxas7KxAy7VU7cqJNZh3qTiT46eYZQEeMaNffuCw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
@@ -14871,6 +14797,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",
|
||||
@@ -15460,10 +15391,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"
|
||||
}
|
||||
@@ -15572,9 +15502,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-screens": {
|
||||
"version": "3.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.13.1.tgz",
|
||||
"integrity": "sha512-xcrnuUs0qUrGpc2gOTDY4VgHHADQwp80mwR1prU/Q0JqbZN5W3koLhuOsT6FkSRKjR5t40l+4LcjhHdpqRB2HA==",
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.10.1.tgz",
|
||||
"integrity": "sha512-ZF/XHnRsuinvDY1XiCWLXxoUoSf+NgsAes2SZfX9rFQQcv128zmh/+19SSavGrSf6rQNzqytEMdRGI6yr4Gbjw==",
|
||||
"dependencies": {
|
||||
"react-freeze": "^1.0.0",
|
||||
"warn-once": "^0.1.0"
|
||||
@@ -16083,9 +16013,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",
|
||||
@@ -16870,11 +16800,6 @@
|
||||
"sdp-verify": "checker.js"
|
||||
}
|
||||
},
|
||||
"node_modules/seamless-scroll-polyfill": {
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/seamless-scroll-polyfill/-/seamless-scroll-polyfill-2.1.8.tgz",
|
||||
"integrity": "sha512-cF92Op90//vEpHphRx25rttJGXIgxcTB1WR5y0ODQhN7O4d0lSEOp5+l3sQDx0aAZ2MfXCqFEb/rG/3ghvVDIQ=="
|
||||
},
|
||||
"node_modules/seedrandom": {
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-2.4.3.tgz",
|
||||
@@ -18718,9 +18643,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",
|
||||
@@ -19198,40 +19123,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",
|
||||
@@ -22737,13 +22628,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": {
|
||||
@@ -23805,42 +23718,13 @@
|
||||
}
|
||||
},
|
||||
"@react-navigation/stack": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-6.2.2.tgz",
|
||||
"integrity": "sha512-P9ZfmluOXNmbs7YdG1UWS1fAh87Yse9aX8TgqOz4FlHEm5q7g5eaM35QgWByt+wif3UiqE40D8wXpqRQvMgPWg==",
|
||||
"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.3.4",
|
||||
"color": "^4.2.3",
|
||||
"@react-navigation/elements": "^1.2.1",
|
||||
"color": "^3.1.3",
|
||||
"warn-once": "^0.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/elements": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.4.tgz",
|
||||
"integrity": "sha512-O0jICpjn3jskVo4yiWzZozmj7DZy1ZBbn3O7dbenuUjZSj/cscjwaapmZZFGcI/IMmjmx8UTKsybhCFEIbGf3g=="
|
||||
},
|
||||
"color": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
||||
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1",
|
||||
"color-string": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sideway/address": {
|
||||
@@ -24112,16 +23996,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",
|
||||
@@ -24169,12 +24043,6 @@
|
||||
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.182",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
|
||||
"integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/long": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz",
|
||||
@@ -24224,9 +24092,9 @@
|
||||
"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": "*",
|
||||
@@ -24242,18 +24110,6 @@
|
||||
"@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",
|
||||
@@ -24306,12 +24162,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",
|
||||
@@ -26152,9 +26002,9 @@
|
||||
"integrity": "sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
||||
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
@@ -26498,11 +26348,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",
|
||||
@@ -28328,11 +28173,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",
|
||||
@@ -29022,11 +28862,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",
|
||||
@@ -29441,8 +29276,8 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1466.0.0+2682b4ec/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-p6PWid1e5pDw/Y9NYU32Xik6UPJ9QFUq3DawHNMPdo3tXc+5ogWKF2LT7ieA2cl5RbINnnE7oNXTkrDsQwsWiA==",
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1431.0.0+742232c9/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-M2tybHP1w4AXcsUH33aiTgPlr/I0uqcwfHYUo2/zpmhI7gaxas7KxAy7VU7cqJNZh3qTiT46eYZQEeMaNffuCw==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
@@ -31573,6 +31408,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",
|
||||
@@ -32013,8 +31853,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",
|
||||
@@ -32090,9 +31931,9 @@
|
||||
"integrity": "sha512-yOwiiPJ1rk+/nfK13eafbpW6sKW0jOnsRem2C1LPJjM3tfTof6hlvV5eWHATye3XOpu2cJ7N+HdkUvUDGwFD2Q=="
|
||||
},
|
||||
"react-native-screens": {
|
||||
"version": "3.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.13.1.tgz",
|
||||
"integrity": "sha512-xcrnuUs0qUrGpc2gOTDY4VgHHADQwp80mwR1prU/Q0JqbZN5W3koLhuOsT6FkSRKjR5t40l+4LcjhHdpqRB2HA==",
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.10.1.tgz",
|
||||
"integrity": "sha512-ZF/XHnRsuinvDY1XiCWLXxoUoSf+NgsAes2SZfX9rFQQcv128zmh/+19SSavGrSf6rQNzqytEMdRGI6yr4Gbjw==",
|
||||
"requires": {
|
||||
"react-freeze": "^1.0.0",
|
||||
"warn-once": "^0.1.0"
|
||||
@@ -32384,9 +32225,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",
|
||||
@@ -32954,11 +32795,6 @@
|
||||
"resolved": "https://registry.npmjs.org/sdp-transform/-/sdp-transform-2.3.0.tgz",
|
||||
"integrity": "sha1-V6lXWUIEHYV3qGnXx01MOgvYiPY="
|
||||
},
|
||||
"seamless-scroll-polyfill": {
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/seamless-scroll-polyfill/-/seamless-scroll-polyfill-2.1.8.tgz",
|
||||
"integrity": "sha512-cF92Op90//vEpHphRx25rttJGXIgxcTB1WR5y0ODQhN7O4d0lSEOp5+l3sQDx0aAZ2MfXCqFEb/rG/3ghvVDIQ=="
|
||||
},
|
||||
"seedrandom": {
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-2.4.3.tgz",
|
||||
@@ -34438,9 +34274,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": {
|
||||
@@ -34785,28 +34621,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",
|
||||
|
||||
27
package.json
27
package.json
@@ -39,7 +39,7 @@
|
||||
"@hapi/bourne": "2.0.0",
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
"@jitsi/rtcstats": "9.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,7 +54,7 @@
|
||||
"@react-navigation/elements": "1.2.1",
|
||||
"@react-navigation/material-top-tabs": "6.0.6",
|
||||
"@react-navigation/native": "6.0.6",
|
||||
"@react-navigation/stack": "6.2.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",
|
||||
@@ -77,9 +77,8 @@
|
||||
"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/v1466.0.0+2682b4ec/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1431.0.0+742232c9/lib-jitsi-meet.tgz",
|
||||
"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",
|
||||
@@ -109,7 +108,7 @@
|
||||
"react-native-performance": "2.1.0",
|
||||
"react-native-reanimated": "https://git@github.com/software-mansion/react-native-reanimated#c4a6b6f687ede090f6081064abe83a2ef9a05784",
|
||||
"react-native-safe-area-context": "3.3.2",
|
||||
"react-native-screens": "3.13.1",
|
||||
"react-native-screens": "3.10.1",
|
||||
"react-native-sound": "0.11.1",
|
||||
"react-native-splash-screen": "3.3.0",
|
||||
"react-native-svg": "12.1.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",
|
||||
@@ -130,12 +129,10 @@
|
||||
"redux-thunk": "2.2.0",
|
||||
"resemblejs": "4.0.0",
|
||||
"rnnoise-wasm": "https://git@github.com/jitsi/rnnoise-wasm#566a16885897704d6e6d67a1d5ac5d39781db2af",
|
||||
"seamless-scroll-polyfill": "2.1.8",
|
||||
"styled-components": "3.4.9",
|
||||
"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"
|
||||
},
|
||||
@@ -148,11 +145,7 @@
|
||||
"@babel/preset-react": "7.16.0",
|
||||
"@babel/runtime": "7.16.0",
|
||||
"@jitsi/eslint-config": "4.0.0",
|
||||
"@types/lodash": "4.14.182",
|
||||
"@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",
|
||||
@@ -175,7 +168,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",
|
||||
@@ -191,12 +184,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"
|
||||
}
|
||||
}
|
||||
|
||||
118
patches/react-native-dialog+9.2.1.patch
Normal file
118
patches/react-native-dialog+9.2.1.patch
Normal 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,
|
||||
},
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import ReducerRegistry from '../base/redux/ReducerRegistry';
|
||||
// @flow
|
||||
|
||||
import { ReducerRegistry } from '../base/redux';
|
||||
|
||||
import { UPDATE_LOCAL_TRACKS_DURATION } from './actionTypes';
|
||||
|
||||
@@ -28,22 +30,6 @@ const DEFAULT_STATE = {
|
||||
}
|
||||
};
|
||||
|
||||
interface Value {
|
||||
startedTime: number,
|
||||
value: number
|
||||
}
|
||||
|
||||
export interface IAnalyticsState {
|
||||
localTracksDuration: {
|
||||
audio: Value,
|
||||
video: {
|
||||
camera: Value,
|
||||
desktop: Value
|
||||
},
|
||||
conference: Value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen for actions which changes the state of the analytics feature.
|
||||
*
|
||||
@@ -52,7 +38,7 @@ export interface IAnalyticsState {
|
||||
* @param {string} action.type - Type of action.
|
||||
* @returns {Object}
|
||||
*/
|
||||
ReducerRegistry.register('features/analytics', (state: IAnalyticsState = DEFAULT_STATE, action: any) => {
|
||||
ReducerRegistry.register('features/analytics', (state = DEFAULT_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case UPDATE_LOCAL_TRACKS_DURATION:
|
||||
return {
|
||||
@@ -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());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Platform, StyleSheet, View } from 'react-native';
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
import SplashScreen from 'react-native-splash-screen';
|
||||
|
||||
import { DialogContainer } from '../../base/dialog';
|
||||
import BottomSheetContainer from '../../base/dialog/components/native/BottomSheetContainer';
|
||||
import { updateFlags } from '../../base/flags/actions';
|
||||
import { CALL_INTEGRATION_ENABLED, SERVER_URL_CHANGE_ENABLED } from '../../base/flags/constants';
|
||||
import { getFeatureFlag } from '../../base/flags/functions';
|
||||
import { Platform } from '../../base/react';
|
||||
import { DimensionsDetector, clientResized, setSafeAreaInsets } from '../../base/responsive-ui';
|
||||
import { updateSettings } from '../../base/settings';
|
||||
import { _getRouteToRender } from '../getRouteToRender.native';
|
||||
@@ -22,15 +23,16 @@ import '../reducers';
|
||||
|
||||
declare var __DEV__;
|
||||
|
||||
const DialogContainerWrapper = Platform.select({
|
||||
default: View
|
||||
});
|
||||
|
||||
/**
|
||||
* The type of React {@code Component} props of {@link App}.
|
||||
*/
|
||||
type Props = AbstractAppProps & {
|
||||
|
||||
/**
|
||||
* Identifier for this app on the native side.
|
||||
*/
|
||||
externalAPIScope: string,
|
||||
|
||||
/**
|
||||
* An object with the feature flags.
|
||||
*/
|
||||
@@ -238,12 +240,7 @@ export class App extends AbstractApp {
|
||||
*/
|
||||
_renderDialogContainer() {
|
||||
return (
|
||||
<DialogContainerWrapper
|
||||
pointerEvents = 'box-none'
|
||||
style = { StyleSheet.absoluteFill }>
|
||||
<BottomSheetContainer />
|
||||
<DialogContainer />
|
||||
</DialogContainerWrapper>
|
||||
<DialogContainer />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import '../authentication/middleware';
|
||||
import '../dynamic-branding/middleware';
|
||||
import '../gifs/middleware';
|
||||
import '../mobile/audio-mode/middleware';
|
||||
import '../mobile/background/middleware';
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import '../authentication/middleware';
|
||||
import '../base/i18n/middleware';
|
||||
import '../base/devices/middleware';
|
||||
import '../base/media/middleware';
|
||||
import '../dynamic-branding/middleware';
|
||||
import '../e2ee/middleware';
|
||||
import '../external-api/middleware';
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import { IAnalyticsState } from "../analytics/reducer"
|
||||
import { IAuthenticationState } from "../authentication/reducer"
|
||||
import { IAVModerationState } from "../av-moderation/reducer"
|
||||
import { IAppState } from "../base/app/reducer"
|
||||
import { IAudioOnlyState } from "../base/audio-only/reducer"
|
||||
import { IConferenceState } from "../base/conference/reducer"
|
||||
import { IConfig } from "../base/config/configType"
|
||||
|
||||
export interface IStore {
|
||||
getState: Function,
|
||||
dispatch: Function
|
||||
}
|
||||
|
||||
export interface IState {
|
||||
'features/analytics': IAnalyticsState,
|
||||
'features/authentication': IAuthenticationState,
|
||||
'features/av-moderation': IAVModerationState,
|
||||
'features/base/app': IAppState,
|
||||
'features/base/audio-only': IAudioOnlyState,
|
||||
'features/base/conference': IConferenceState,
|
||||
'features/base/config': IConfig,
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
41
react/features/authentication/components/native/styles.js
Normal file
41
react/features/authentication/components/native/styles.js
Normal 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')
|
||||
}
|
||||
});
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @ts-ignore
|
||||
import { assign } from '../base/redux/functions';
|
||||
import ReducerRegistry from '../base/redux/ReducerRegistry';
|
||||
// @flow
|
||||
|
||||
import { assign, ReducerRegistry } from '../base/redux';
|
||||
|
||||
import {
|
||||
CANCEL_LOGIN,
|
||||
@@ -10,13 +10,6 @@ import {
|
||||
WAIT_FOR_OWNER
|
||||
} from './actionTypes';
|
||||
|
||||
export interface IAuthenticationState {
|
||||
error?: Object|undefined;
|
||||
progress?: number|undefined;
|
||||
thenableWithCancel?: Object|undefined;
|
||||
waitForOwnerTimeoutID?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for actions which change the state of the authentication feature.
|
||||
*
|
||||
@@ -25,7 +18,7 @@ export interface IAuthenticationState {
|
||||
* @param {string} action.type - Type of action.
|
||||
* @returns {Object}
|
||||
*/
|
||||
ReducerRegistry.register('features/authentication', (state: IAuthenticationState = {}, action: any) => {
|
||||
ReducerRegistry.register('features/authentication', (state = {}, action) => {
|
||||
switch (action.type) {
|
||||
case CANCEL_LOGIN:
|
||||
return assign(state, {
|
||||
@@ -1,9 +1,11 @@
|
||||
// @flow
|
||||
|
||||
import { MEDIA_TYPE, type MediaType } from '../base/media/constants';
|
||||
|
||||
/**
|
||||
* Mapping between a media type and the witelist reducer key.
|
||||
*/
|
||||
export const MEDIA_TYPE_TO_WHITELIST_STORE_KEY: { [key: string]: string } = {
|
||||
export const MEDIA_TYPE_TO_WHITELIST_STORE_KEY: {[key: MediaType]: string} = {
|
||||
[MEDIA_TYPE.AUDIO]: 'audioWhitelist',
|
||||
[MEDIA_TYPE.VIDEO]: 'videoWhitelist'
|
||||
};
|
||||
@@ -11,7 +13,7 @@ export const MEDIA_TYPE_TO_WHITELIST_STORE_KEY: { [key: string]: string } = {
|
||||
/**
|
||||
* Mapping between a media type and the pending reducer key.
|
||||
*/
|
||||
export const MEDIA_TYPE_TO_PENDING_STORE_KEY: {[key: string]: string} = {
|
||||
export const MEDIA_TYPE_TO_PENDING_STORE_KEY: {[key: MediaType]: string} = {
|
||||
[MEDIA_TYPE.AUDIO]: 'pendingAudio',
|
||||
[MEDIA_TYPE.VIDEO]: 'pendingVideo'
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -80,8 +80,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 +102,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,
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/* @flow */
|
||||
|
||||
import { MEDIA_TYPE } from '../base/media/constants';
|
||||
import type { MediaType } from '../base/media/constants';
|
||||
import {
|
||||
PARTICIPANT_LEFT,
|
||||
PARTICIPANT_UPDATED
|
||||
// @ts-ignore
|
||||
} from '../base/participants';
|
||||
import ReducerRegistry from '../base/redux/ReducerRegistry';
|
||||
import { ReducerRegistry } from '../base/redux';
|
||||
|
||||
import {
|
||||
DISABLE_MODERATION,
|
||||
@@ -28,19 +29,8 @@ const initialState = {
|
||||
pendingVideo: []
|
||||
};
|
||||
|
||||
export interface IAVModerationState {
|
||||
audioModerationEnabled: boolean;
|
||||
videoModerationEnabled: boolean;
|
||||
audioWhitelist: { [id: string]: boolean };
|
||||
videoWhitelist: { [id: string]: boolean };
|
||||
pendingAudio: Array<{ id: string }>;
|
||||
pendingVideo: Array<{ id: string }>;
|
||||
audioUnmuteApproved?: boolean|undefined;
|
||||
videoUnmuteApproved?: boolean|undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a participant in the state for the specified media type.
|
||||
Updates a participant in the state for the specified media type.
|
||||
*
|
||||
* @param {MediaType} mediaType - The media type.
|
||||
* @param {Object} participant - Information about participant to be modified.
|
||||
@@ -48,11 +38,11 @@ export interface IAVModerationState {
|
||||
* @private
|
||||
* @returns {boolean} - Whether state instance was modified.
|
||||
*/
|
||||
function _updatePendingParticipant(mediaType: MediaType, participant: any, state: any = {}) {
|
||||
function _updatePendingParticipant(mediaType: MediaType, participant, state: Object = {}) {
|
||||
let arrayItemChanged = false;
|
||||
const storeKey = MEDIA_TYPE_TO_PENDING_STORE_KEY[mediaType];
|
||||
const arr = state[storeKey];
|
||||
const newArr = arr.map((pending: { id: string} ) => {
|
||||
const newArr = arr.map(pending => {
|
||||
if (pending.id === participant.id) {
|
||||
arrayItemChanged = true;
|
||||
|
||||
@@ -74,7 +64,7 @@ function _updatePendingParticipant(mediaType: MediaType, participant: any, state
|
||||
return false;
|
||||
}
|
||||
|
||||
ReducerRegistry.register('features/av-moderation', (state: IAVModerationState = initialState, action: any) => {
|
||||
ReducerRegistry.register('features/av-moderation', (state = initialState, action) => {
|
||||
|
||||
switch (action.type) {
|
||||
case DISABLE_MODERATION: {
|
||||
@@ -1,12 +1,10 @@
|
||||
import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
// @flow
|
||||
|
||||
import { ReducerRegistry } from '../redux';
|
||||
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
|
||||
|
||||
export interface IAppState {
|
||||
app?: Object|undefined;
|
||||
}
|
||||
|
||||
ReducerRegistry.register('features/base/app', (state: IAppState = {}, action) => {
|
||||
ReducerRegistry.register('features/base/app', (state = {}, action) => {
|
||||
switch (action.type) {
|
||||
case APP_WILL_MOUNT: {
|
||||
const { app } = action;
|
||||
@@ -1,17 +1,16 @@
|
||||
import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
// @flow
|
||||
|
||||
import { ReducerRegistry } from '../redux';
|
||||
|
||||
import { SET_AUDIO_ONLY } from './actionTypes';
|
||||
|
||||
export interface IAudioOnlyState {
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
enabled: false
|
||||
};
|
||||
|
||||
|
||||
ReducerRegistry.register('features/base/audio-only', (state: IAudioOnlyState = DEFAULT_STATE, action) => {
|
||||
ReducerRegistry.register('features/base/audio-only', (state = DEFAULT_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case SET_AUDIO_ONLY:
|
||||
return {
|
||||
@@ -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)',
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -44,11 +44,9 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
break;
|
||||
}
|
||||
case CONFERENCE_FAILED: {
|
||||
const errorName = action.error?.name;
|
||||
|
||||
if (enableForcedReload && errorName === JitsiConferenceErrors.CONFERENCE_RESTARTED) {
|
||||
dispatch(setSkipPrejoinOnReload(true));
|
||||
}
|
||||
enableForcedReload
|
||||
&& action.error?.name === JitsiConferenceErrors.CONFERENCE_RESTARTED
|
||||
&& dispatch(setSkipPrejoinOnReload(true));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
// @ts-ignore
|
||||
// @flow
|
||||
|
||||
import { LOCKED_LOCALLY, LOCKED_REMOTELY } from '../../room-lock';
|
||||
// @ts-ignore
|
||||
import { CONNECTION_WILL_CONNECT, SET_LOCATION_URL } from '../connection';
|
||||
// @ts-ignore
|
||||
import { JitsiConferenceErrors } from '../lib-jitsi-meet';
|
||||
// @ts-ignore
|
||||
import { assign, set } from '../redux';
|
||||
import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
import { assign, ReducerRegistry, set } from '../redux';
|
||||
|
||||
import {
|
||||
AUTH_STATUS_CHANGED,
|
||||
@@ -21,14 +18,12 @@ import {
|
||||
LOCK_STATE_CHANGED,
|
||||
P2P_STATUS_CHANGED,
|
||||
SET_FOLLOW_ME,
|
||||
SET_OBFUSCATED_ROOM,
|
||||
SET_PASSWORD,
|
||||
SET_PENDING_SUBJECT_CHANGE,
|
||||
SET_ROOM,
|
||||
SET_START_MUTED_POLICY,
|
||||
SET_START_REACTIONS_MUTED
|
||||
} from './actionTypes';
|
||||
// @ts-ignore
|
||||
import { isRoomValid } from './functions';
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
@@ -42,26 +37,13 @@ const DEFAULT_STATE = {
|
||||
passwordRequired: undefined
|
||||
};
|
||||
|
||||
export interface IConferenceState {
|
||||
conference: Object|undefined;
|
||||
e2eeSupported: boolean|undefined;
|
||||
joining: Object|undefined;
|
||||
leaving: Object|undefined;
|
||||
locked: string|undefined;
|
||||
membersOnly: boolean|undefined;
|
||||
password: string|undefined;
|
||||
passwordRequired: boolean|undefined;
|
||||
authEnabled?: boolean|undefined;
|
||||
authLogin?: string|undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen for actions that contain the conference object, so that it can be
|
||||
* stored for use by other action creators.
|
||||
*/
|
||||
ReducerRegistry.register(
|
||||
'features/base/conference',
|
||||
(state: IConferenceState = DEFAULT_STATE, action: any) => {
|
||||
(state = DEFAULT_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case AUTH_STATUS_CHANGED:
|
||||
return _authStatusChanged(state, action);
|
||||
@@ -106,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);
|
||||
|
||||
@@ -142,7 +118,7 @@ ReducerRegistry.register(
|
||||
* @returns {Object} The new state of the feature base/conference after the
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _authStatusChanged(state: any, { authEnabled, authLogin }: {authEnabled: boolean, authLogin: string}) {
|
||||
function _authStatusChanged(state, { authEnabled, authLogin }) {
|
||||
return assign(state, {
|
||||
authEnabled,
|
||||
authLogin
|
||||
@@ -159,7 +135,7 @@ function _authStatusChanged(state: any, { authEnabled, authLogin }: {authEnabled
|
||||
* @returns {Object} The new state of the feature base/conference after the
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _conferenceFailed(state: any, { conference, error }: {conference: Object, error: any}) {
|
||||
function _conferenceFailed(state, { conference, error }) {
|
||||
// The current (similar to getCurrentConference in
|
||||
// base/conference/functions.any.js) conference which is joining or joined:
|
||||
const conference_ = state.conference || state.joining;
|
||||
@@ -225,7 +201,7 @@ function _conferenceFailed(state: any, { conference, error }: {conference: Objec
|
||||
* @returns {Object} The new state of the feature base/conference after the
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _conferenceJoined(state: any, { conference }: {conference: any}) {
|
||||
function _conferenceJoined(state, { conference }) {
|
||||
// FIXME The indicator which determines whether a JitsiConference is locked
|
||||
// i.e. password-protected is private to lib-jitsi-meet. However, the
|
||||
// library does not fire LOCK_STATE_CHANGED upon joining a JitsiConference
|
||||
@@ -271,7 +247,7 @@ function _conferenceJoined(state: any, { conference }: {conference: any}) {
|
||||
* @returns {Object} The next/new state of the feature base/conference after the
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _conferenceLeftOrWillLeave(state: any, { conference, type }: {conference: Object, type: string}) {
|
||||
function _conferenceLeftOrWillLeave(state, { conference, type }) {
|
||||
const nextState = { ...state };
|
||||
|
||||
// The redux action CONFERENCE_LEFT is the last time that we should be
|
||||
@@ -325,7 +301,7 @@ function _conferenceLeftOrWillLeave(state: any, { conference, type }: {conferenc
|
||||
* @returns {Object} The new state of the feature base/conference after the
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _conferenceWillJoin(state: any, { conference }: {conference: Object}) {
|
||||
function _conferenceWillJoin(state, { conference }) {
|
||||
return assign(state, {
|
||||
error: undefined,
|
||||
joining: conference
|
||||
@@ -342,7 +318,7 @@ function _conferenceWillJoin(state: any, { conference }: {conference: Object}) {
|
||||
* @returns {Object} The new state of the feature base/conference after the
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _lockStateChanged(state: any, { conference, locked }: {conference: Object, locked: boolean}) {
|
||||
function _lockStateChanged(state, { conference, locked }) {
|
||||
if (state.conference !== conference) {
|
||||
return state;
|
||||
}
|
||||
@@ -363,7 +339,7 @@ function _lockStateChanged(state: any, { conference, locked }: {conference: Obje
|
||||
* @returns {Object} The new state of the feature base/conference after the
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _p2pStatusChanged(state: any, action: any) {
|
||||
function _p2pStatusChanged(state, action) {
|
||||
return set(state, 'p2p', action.p2p);
|
||||
}
|
||||
|
||||
@@ -376,7 +352,7 @@ function _p2pStatusChanged(state: any, action: any) {
|
||||
* @returns {Object} The new state of the feature base/conference after the
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _setPassword(state: any, { conference, method, password }: {conference: any, method: Object, password: string}) {
|
||||
function _setPassword(state, { conference, method, password }) {
|
||||
switch (method) {
|
||||
case conference.join:
|
||||
return assign(state, {
|
||||
@@ -423,7 +399,7 @@ function _setPassword(state: any, { conference, method, password }: {conference:
|
||||
* @returns {Object} The new state of the feature base/conference after the
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _setRoom(state: any, action: any) {
|
||||
function _setRoom(state, action) {
|
||||
let { room } = action;
|
||||
|
||||
if (!isRoomValid(room)) {
|
||||
@@ -1,467 +0,0 @@
|
||||
type ToolbarButtons = 'camera' |
|
||||
'chat' |
|
||||
'closedcaptions' |
|
||||
'desktop' |
|
||||
'dock-iframe' |
|
||||
'download' |
|
||||
'embedmeeting' |
|
||||
'etherpad' |
|
||||
'feedback' |
|
||||
'filmstrip' |
|
||||
'fullscreen' |
|
||||
'hangup' |
|
||||
'help' |
|
||||
'highlight' |
|
||||
'invite' |
|
||||
'linktosalesforce' |
|
||||
'livestreaming' |
|
||||
'microphone' |
|
||||
'participants-pane' |
|
||||
'profile' |
|
||||
'raisehand' |
|
||||
'recording' |
|
||||
'security' |
|
||||
'select-background' |
|
||||
'settings' |
|
||||
'shareaudio' |
|
||||
'sharedvideo' |
|
||||
'shortcuts' |
|
||||
'stats' |
|
||||
'tileview' |
|
||||
'toggle-camera' |
|
||||
'undock-iframe' |
|
||||
'videoquality' |
|
||||
'__end';
|
||||
|
||||
type ButtonsWithNotifyClick = 'camera' |
|
||||
'chat' |
|
||||
'closedcaptions' |
|
||||
'desktop' |
|
||||
'download' |
|
||||
'embedmeeting' |
|
||||
'etherpad' |
|
||||
'feedback' |
|
||||
'filmstrip' |
|
||||
'fullscreen' |
|
||||
'hangup' |
|
||||
'help' |
|
||||
'invite' |
|
||||
'livestreaming' |
|
||||
'microphone' |
|
||||
'mute-everyone' |
|
||||
'mute-video-everyone' |
|
||||
'participants-pane' |
|
||||
'profile' |
|
||||
'raisehand' |
|
||||
'recording' |
|
||||
'security' |
|
||||
'select-background' |
|
||||
'settings' |
|
||||
'shareaudio' |
|
||||
'sharedvideo' |
|
||||
'shortcuts' |
|
||||
'stats' |
|
||||
'tileview' |
|
||||
'toggle-camera' |
|
||||
'videoquality' |
|
||||
'add-passcode' |
|
||||
'__end';
|
||||
|
||||
type Sounds = 'ASKED_TO_UNMUTE_SOUND' |
|
||||
'E2EE_OFF_SOUND' |
|
||||
'E2EE_ON_SOUND' |
|
||||
'INCOMING_MSG_SOUND' |
|
||||
'KNOCKING_PARTICIPANT_SOUND' |
|
||||
'LIVE_STREAMING_OFF_SOUND' |
|
||||
'LIVE_STREAMING_ON_SOUND' |
|
||||
'NO_AUDIO_SIGNAL_SOUND' |
|
||||
'NOISY_AUDIO_INPUT_SOUND' |
|
||||
'OUTGOING_CALL_EXPIRED_SOUND' |
|
||||
'OUTGOING_CALL_REJECTED_SOUND' |
|
||||
'OUTGOING_CALL_RINGING_SOUND' |
|
||||
'OUTGOING_CALL_START_SOUND' |
|
||||
'PARTICIPANT_JOINED_SOUND' |
|
||||
'PARTICIPANT_LEFT_SOUND' |
|
||||
'RAISE_HAND_SOUND' |
|
||||
'REACTION_SOUND' |
|
||||
'RECORDING_OFF_SOUND' |
|
||||
'RECORDING_ON_SOUND' |
|
||||
'TALK_WHILE_MUTED_SOUND';
|
||||
|
||||
export interface IConfig {
|
||||
hosts?: {
|
||||
domain: string;
|
||||
anonymousdomain?: string;
|
||||
authdomain?: string;
|
||||
focus?: string;
|
||||
muc: string;
|
||||
};
|
||||
bosh?: string;
|
||||
websocket?: string;
|
||||
focusUserJid?: string;
|
||||
testing?: {
|
||||
disableE2EE?: boolean;
|
||||
enableThumbnailReordering?: boolean;
|
||||
mobileXmppWsThreshold?: number;
|
||||
p2pTestMode?: boolean;
|
||||
testMode?: boolean;
|
||||
noAutoPlayVideo?: boolean;
|
||||
capScreenshareBitrate?: number;
|
||||
setScreenSharingResolutionConstraints?: boolean;
|
||||
callStatsThreshold?: number;
|
||||
};
|
||||
flags?: {
|
||||
sourceNameSignaling?: boolean;
|
||||
sendMultipleVideoStreams?: boolean;
|
||||
};
|
||||
disableModeratorIndicator?: boolean;
|
||||
disableReactions?: boolean;
|
||||
disableReactionsModeration?: boolean;
|
||||
disablePolls?: boolean;
|
||||
disableSelfView?: boolean;
|
||||
disableSelfViewSettings?: boolean;
|
||||
screenshotCapture?: {
|
||||
enabled?: boolean;
|
||||
mode?: 'always' | 'recording';
|
||||
};
|
||||
webrtcIceUdpDisable?: boolean;
|
||||
webrtcIceTcpDisable?: boolean;
|
||||
enableUnifiedOnChrome?: boolean;
|
||||
disableAudioLevels?: boolean;
|
||||
audioLevelsInterval?: number;
|
||||
enableNoAudioDetection?: boolean;
|
||||
enableSaveLogs?: boolean;
|
||||
disableShowMoreStats?: boolean;
|
||||
enableNoisyMicDetection?: boolean;
|
||||
startAudioOnly?: boolean;
|
||||
startAudioMuted?: boolean;
|
||||
startWithAudioMuted?: boolean;
|
||||
startSilent?: boolean;
|
||||
enableOpusRed?: boolean;
|
||||
audioQuality?: {
|
||||
stereo?: boolean;
|
||||
opusMaxAverageBitrate?: number|null;
|
||||
};
|
||||
stereo?: boolean;
|
||||
opusMaxAverageBitrate?: number;
|
||||
resolution?: number;
|
||||
disableRemoveRaisedHandOnFocus?: boolean;
|
||||
disableSpeakerStatsSearch?: boolean;
|
||||
speakerStatsOrder?: Array<'role'|'name'|'hasLeft'>;
|
||||
maxFullResolutionParticipants?: number;
|
||||
constraints?: {
|
||||
video?: {
|
||||
height?: {
|
||||
ideal?: number;
|
||||
max?: number;
|
||||
min?: number;
|
||||
}
|
||||
}
|
||||
};
|
||||
disableSimulcast?: boolean;
|
||||
enableLayerSuspension?: boolean;
|
||||
startVideoMuted?: number;
|
||||
startWithVideoMuted?: boolean;
|
||||
preferH264?: boolean;
|
||||
disableH264?: boolean;
|
||||
desktopSharingFrameRate?: {
|
||||
min?: number;
|
||||
max?: number;
|
||||
};
|
||||
startScreenSharing?: boolean;
|
||||
fileRecordingsEnabled?: boolean;
|
||||
dropbox?: {
|
||||
appKey: string;
|
||||
redirectURI?: string;
|
||||
};
|
||||
recordingService?: {
|
||||
enabled?: boolean;
|
||||
sharingEnabled?: boolean;
|
||||
hideStorageWarning?: boolean;
|
||||
};
|
||||
fileRecordingsServiceEnabled?: boolean;
|
||||
fileRecordingsServiceSharingEnabled?: boolean;
|
||||
liveStreamingEnabled?: boolean;
|
||||
localRecording?: {
|
||||
disable?: boolean;
|
||||
notifyAllParticipants?: boolean;
|
||||
};
|
||||
transcribingEnabled?: boolean;
|
||||
transcribeWithAppLanguage?: boolean;
|
||||
preferredTranscribeLanguage?: string;
|
||||
autoCaptionOnRecord?: boolean;
|
||||
transcription?: {
|
||||
enabled?: boolean;
|
||||
useAppLanguage?: boolean;
|
||||
preferredLanguage?: string;
|
||||
disableStartForAll?: boolean;
|
||||
autoCaptionOnRecord?: boolean;
|
||||
};
|
||||
channelLastN?: number;
|
||||
connectionIndicators?: {
|
||||
autoHide?: boolean;
|
||||
autoHideTimeout?: number;
|
||||
disabled?: boolean;
|
||||
disableDetails?: boolean;
|
||||
inactiveDisabled?: boolean;
|
||||
};
|
||||
startLastN?: number;
|
||||
lastNLimits?: {
|
||||
[key: number]: number;
|
||||
};
|
||||
useNewBandwidthAllocationStrategy?: boolean;
|
||||
videoQuality?: {
|
||||
disabledCodec?: string;
|
||||
preferredCodec?: string;
|
||||
enforcePreferredCodec?: boolean;
|
||||
maxBitratesVideo?: {
|
||||
[key: string]: {
|
||||
low?: number;
|
||||
standard?: number;
|
||||
high?: number;
|
||||
}
|
||||
};
|
||||
minHeightForQualityLvl: {
|
||||
[key: number]: string;
|
||||
};
|
||||
resizeDesktopForPresenter?: boolean;
|
||||
};
|
||||
notificationTimeouts?: {
|
||||
short?: number;
|
||||
medium?: number;
|
||||
long?: number;
|
||||
};
|
||||
recordingLimit?: {
|
||||
limit?: number;
|
||||
appName?: string;
|
||||
appURL?: string;
|
||||
};
|
||||
disableRtx?: boolean;
|
||||
disableBeforeUnloadHandlers?: boolean;
|
||||
enableTcc?: boolean;
|
||||
enableRemb?: boolean;
|
||||
enableIceRestart?: boolean;
|
||||
enableForcedReload?: boolean;
|
||||
useTurnUdp?: boolean;
|
||||
enableEncodedTransformSupport?: boolean;
|
||||
disableResponsiveTiles?: boolean;
|
||||
hideLobbyButton?: boolean;
|
||||
autoKnockLobby?: boolean;
|
||||
enableLobbyChat?: boolean;
|
||||
hideAddRoomButton?: boolean;
|
||||
requireDisplayName?: boolean;
|
||||
enableWelcomePage?: boolean;
|
||||
disableShortcuts?: boolean;
|
||||
disableInitialGUM?: boolean;
|
||||
enableClosePage?: boolean;
|
||||
disable1On1Mode?: boolean|null;
|
||||
defaultLocalDisplayName?: string;
|
||||
defaultRemoteDisplayName?: string;
|
||||
hideDisplayName?: boolean;
|
||||
hideDominantSpeakerBadge?: boolean;
|
||||
defaultLanguage?: string;
|
||||
disableProfile?: boolean;
|
||||
hideEmailInSettings?: boolean;
|
||||
enableFeaturesBasedOnToken?: boolean;
|
||||
roomPasswordNumberOfDigits?: number;
|
||||
noticeMessage?: string;
|
||||
enableCalendarIntegration?: boolean;
|
||||
prejoinConfig?: {
|
||||
enabled?: boolean;
|
||||
hideDisplayName?: boolean;
|
||||
hideExtraJoinButtons?: Array<string>;
|
||||
};
|
||||
prejoinPageEnabled?: boolean;
|
||||
readOnlyName?: boolean;
|
||||
openSharedDocumentOnJoin?: boolean;
|
||||
enableInsecureRoomNameWarning?: boolean;
|
||||
enableAutomaticUrlCopy?: boolean;
|
||||
corsAvatarURLs?: Array<string>;
|
||||
gravatarBaseURL?: string;
|
||||
gravatar?: {
|
||||
baseUrl?: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
inviteAppName?: string|null;
|
||||
toolbarButtons?: Array<ToolbarButtons>;
|
||||
toolbarConfig?: {
|
||||
initialTimeout?: number;
|
||||
timeout?: number;
|
||||
alwaysVisible?: boolean;
|
||||
autoHideWhileChatIsOpen?: boolean;
|
||||
};
|
||||
buttonsWithNotifyClick?: Array<ButtonsWithNotifyClick | { key: ButtonsWithNotifyClick; preventExecution: boolean }>;
|
||||
hiddenPremeetingButtons?: Array<'microphone' | 'camera' | 'select-background' | 'invite' | 'settings'>;
|
||||
gatherStats?: boolean;
|
||||
pcStatsInterval?: number;
|
||||
callStatsID?: string;
|
||||
callStatsSecret?: string;
|
||||
callStatsConfigParams?: {
|
||||
disableBeforeUnloadHandler?: boolean;
|
||||
applicationVersion?: string;
|
||||
disablePrecalltest?: boolean;
|
||||
siteID?: string;
|
||||
additionalIDs?: {
|
||||
customerID?: string;
|
||||
tenantID?: string;
|
||||
productName?: string;
|
||||
meetingsName?: string;
|
||||
serverName?: string;
|
||||
pbxID?: string;
|
||||
pbxExtensionID?: string;
|
||||
fqExtensionID?: string;
|
||||
sessionID?: string;
|
||||
};
|
||||
collectLegacyStats?: boolean;
|
||||
collectIP?: boolean;
|
||||
};
|
||||
enableDisplayNameInStats?: boolean;
|
||||
enableEmailInStats?: boolean;
|
||||
faceLandmarks?: {
|
||||
enableFaceCentering?: boolean;
|
||||
enableFaceExpressionsDetection?: boolean;
|
||||
enableDisplayFaceExpressions?: boolean;
|
||||
enableRTCStats?: boolean;
|
||||
faceCenteringThreshold?: number;
|
||||
captureInterval?: number;
|
||||
};
|
||||
feedbackPercentage?: number;
|
||||
disableThirdPartyRequests?: boolean;
|
||||
p2p?: {
|
||||
enabled?: boolean;
|
||||
enableUnifiedOnChrome?: boolean;
|
||||
iceTransportPolicy?: string;
|
||||
preferH264?: boolean;
|
||||
preferredCodec?: string;
|
||||
disableH264?: boolean;
|
||||
disabledCodec?: string;
|
||||
backToP2PDelay?: number;
|
||||
stunServers?: Array<{urls: string}>;
|
||||
};
|
||||
analytics?: {
|
||||
disabled?: boolean;
|
||||
googleAnalyticsTrackingId?: string;
|
||||
matomoEndpoint?: string;
|
||||
matomoSiteID?: string;
|
||||
amplitudeAPPKey?: string;
|
||||
obfuscateRoomName?: boolean;
|
||||
rtcstatsEnabled?: boolean;
|
||||
rtcstatsEndpoint?: string;
|
||||
rtcstatsPolIInterval?: number;
|
||||
scriptURLs?: Array<string>;
|
||||
};
|
||||
apiLogLevels?: Array<'warn' | 'log' | 'error' | 'info' | 'debug'>;
|
||||
deploymentInfo?: {
|
||||
shard?: string;
|
||||
region?: string;
|
||||
userRegion?: string;
|
||||
};
|
||||
disabledSounds?: Array<Sounds>;
|
||||
disableRecordAudioNotification?: boolean;
|
||||
disableJoinLeaveSounds?: boolean;
|
||||
disableIncomingMessageSound?: boolean;
|
||||
chromeExtensionBanner?: {
|
||||
url?: string;
|
||||
edgeUrl?: string;
|
||||
chromeExtensionsInfo?: Array<{id: string; path: string}>;
|
||||
};
|
||||
e2ee?: {
|
||||
labels?: {
|
||||
tooltip?: string;
|
||||
description?: string;
|
||||
label?: string;
|
||||
warning?: string;
|
||||
};
|
||||
externallyManagedKey?: boolean;
|
||||
e2eeLabels?: {
|
||||
tooltip?: string;
|
||||
description?: string;
|
||||
label?: string;
|
||||
warning?: string;
|
||||
};
|
||||
};
|
||||
e2eeLabels?: {
|
||||
tooltip?: string;
|
||||
description?: string;
|
||||
label?: string;
|
||||
warning?: string;
|
||||
};
|
||||
e2eping?: {
|
||||
enabled?: boolean;
|
||||
numRequests?: number;
|
||||
maxConferenceSize?: number;
|
||||
maxMessagesPerSecond?: number;
|
||||
};
|
||||
_desktopSharingSourceDevice?: string;
|
||||
disableDeepLinking?: boolean;
|
||||
disableLocalVideoFlip?: boolean;
|
||||
doNotFlipLocalVideo?: boolean;
|
||||
disableInviteFunctions?: boolean;
|
||||
doNotStoreRoom?: boolean;
|
||||
deploymentUrls?: {
|
||||
userDocumentationURL?: string;
|
||||
downloadAppsUrl?: string;
|
||||
};
|
||||
remoteVideoMenu?: {
|
||||
disabled?: boolean;
|
||||
disableKick?: boolean;
|
||||
disableGrantModerator?: boolean;
|
||||
disablePrivateChat?: boolean;
|
||||
};
|
||||
salesforceUrl?: string;
|
||||
disableRemoteMute?: boolean;
|
||||
enableLipSync?: boolean;
|
||||
dynamicBrandingUrl?: string;
|
||||
participantsPane?: {
|
||||
hideModeratorSettingsTab?: boolean;
|
||||
hideMoreActionsButton?: boolean;
|
||||
hideMuteAllButton?: boolean;
|
||||
};
|
||||
breakoutRooms?: {
|
||||
hideAddRoomButton?: boolean;
|
||||
hideAutoAssignButton?: boolean;
|
||||
hideJoinRoomButton?: boolean;
|
||||
};
|
||||
disableAddingBackgroundImages?: boolean;
|
||||
disableScreensharingVirtualBackground?: boolean;
|
||||
backgroundAlpha?: number;
|
||||
moderatedRoomServiceUrl?: string;
|
||||
disableTileView?: boolean;
|
||||
disableTileEnlargement?: boolean;
|
||||
conferenceInfo?: {
|
||||
alwaysVisible?: Array<string>;
|
||||
autoHide?: Array<string>;
|
||||
};
|
||||
hideConferenceSubject?: boolean;
|
||||
hideConferenceTimer?: boolean;
|
||||
hideRecordingLabel?: boolean;
|
||||
hideParticipantsStats?: boolean;
|
||||
subject?: string;
|
||||
localSubject?: string;
|
||||
useHostPageLocalStorage?: boolean;
|
||||
etherpad_base?: string;
|
||||
dialInNumbersUrl?: string;
|
||||
dialInConfCodeUrl?: string;
|
||||
brandingRoomAlias?: string;
|
||||
mouseMoveCallbackInterval?: number;
|
||||
notifications?: Array<string>;
|
||||
disabledNotifications?: Array<string>;
|
||||
disableFilmstripAutohiding?: boolean;
|
||||
filmstrip?: {
|
||||
disableResizable?: boolean;
|
||||
disableStageFilmstrip?: boolean;
|
||||
disableTopPanel?: boolean;
|
||||
minParticipantCountForTopPanel?: number;
|
||||
};
|
||||
tileView?: {
|
||||
numberOfVisibleTiles?: number;
|
||||
};
|
||||
disableChatSmileys?: boolean;
|
||||
giphy?: {
|
||||
enabled?: boolean;
|
||||
sdkKey?: '';
|
||||
displayMode?: 'all' | 'tile' | 'chat';
|
||||
tileTime?: number;
|
||||
};
|
||||
locationURL?: string;
|
||||
}
|
||||
@@ -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',
|
||||
@@ -193,7 +191,6 @@ export default [
|
||||
'openSharedDocumentOnJoin',
|
||||
'opusMaxAverageBitrate',
|
||||
'p2p',
|
||||
'participantsPane',
|
||||
'pcStatsInterval',
|
||||
'preferH264',
|
||||
'preferredCodec',
|
||||
@@ -222,7 +219,6 @@ export default [
|
||||
'toolbarConfig',
|
||||
'tileView',
|
||||
'transcribingEnabled',
|
||||
'transcription',
|
||||
'useHostPageLocalStorage',
|
||||
'useTurnUdp',
|
||||
'videoQuality',
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// @flow
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
import { CONFERENCE_INFO } from '../../conference/components/constants';
|
||||
// @ts-ignore
|
||||
import { equals } from '../redux';
|
||||
import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
import { equals, ReducerRegistry } from '../redux';
|
||||
|
||||
import {
|
||||
UPDATE_CONFIG,
|
||||
@@ -12,11 +12,9 @@ import {
|
||||
SET_CONFIG,
|
||||
OVERWRITE_CONFIG
|
||||
} from './actionTypes';
|
||||
import { IConfig } from './configType';
|
||||
// @ts-ignore
|
||||
import { _cleanupConfig } from './functions';
|
||||
|
||||
declare var interfaceConfig: any;
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
/**
|
||||
* The initial state of the feature base/config when executing in a
|
||||
@@ -28,7 +26,7 @@ declare var interfaceConfig: any;
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const INITIAL_NON_RN_STATE: IConfig = {
|
||||
const INITIAL_NON_RN_STATE = {
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -40,7 +38,7 @@ const INITIAL_NON_RN_STATE: IConfig = {
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const INITIAL_RN_STATE: IConfig = {
|
||||
const INITIAL_RN_STATE = {
|
||||
analytics: {},
|
||||
|
||||
// FIXME The support for audio levels in lib-jitsi-meet polls the statistics
|
||||
@@ -63,14 +61,14 @@ const INITIAL_RN_STATE: IConfig = {
|
||||
* Mapping between old configs controlling the conference info headers visibility and the
|
||||
* new configs. Needed in order to keep backwards compatibility.
|
||||
*/
|
||||
const CONFERENCE_HEADER_MAPPING: any = {
|
||||
const CONFERENCE_HEADER_MAPPING = {
|
||||
hideConferenceTimer: [ 'conference-timer' ],
|
||||
hideConferenceSubject: [ 'subject' ],
|
||||
hideParticipantsStats: [ 'participants-count' ],
|
||||
hideRecordingLabel: [ 'recording' ]
|
||||
};
|
||||
|
||||
ReducerRegistry.register('features/base/config', (state: IConfig = _getInitialState(), action: any) => {
|
||||
ReducerRegistry.register('features/base/config', (state = _getInitialState(), action) => {
|
||||
switch (action.type) {
|
||||
case UPDATE_CONFIG:
|
||||
return _updateConfig(state, action);
|
||||
@@ -141,12 +139,12 @@ function _getInitialState() {
|
||||
* Reduces a specific Redux action SET_CONFIG of the feature
|
||||
* base/lib-jitsi-meet.
|
||||
*
|
||||
* @param {IConfig} state - The Redux state of the feature base/config.
|
||||
* @param {Object} state - The Redux state of the feature base/config.
|
||||
* @param {Action} action - The Redux action SET_CONFIG to reduce.
|
||||
* @private
|
||||
* @returns {Object} The new state after the reduction of the specified action.
|
||||
*/
|
||||
function _setConfig(state: IConfig, { config }: {config: IConfig}) {
|
||||
function _setConfig(state, { config }) {
|
||||
// The mobile app bundles jitsi-meet and lib-jitsi-meet at build time and
|
||||
// does not download them at runtime from the deployment on which it will
|
||||
// join a conference. The downloading is planned for implementation in the
|
||||
@@ -189,10 +187,10 @@ function _setConfig(state: IConfig, { config }: {config: IConfig}) {
|
||||
/**
|
||||
* Processes the conferenceInfo object against the defaults.
|
||||
*
|
||||
* @param {IConfig} config - The old config.
|
||||
* @param {Object} config - The old config.
|
||||
* @returns {Object} The processed conferenceInfo object.
|
||||
*/
|
||||
function _getConferenceInfo(config: IConfig) {
|
||||
function _getConferenceInfo(config) {
|
||||
const { conferenceInfo } = config;
|
||||
|
||||
if (conferenceInfo) {
|
||||
@@ -209,7 +207,11 @@ function _getConferenceInfo(config: IConfig) {
|
||||
|
||||
/**
|
||||
* Constructs a new config {@code Object}, if necessary, out of a specific
|
||||
* interface_config {@code Object} which is in the latest format supported by jitsi-meet.
|
||||
* config {@code Object} which is in the latest format supported by jitsi-meet.
|
||||
* Such a translation from an old config format to a new/the latest config
|
||||
* format is necessary because the mobile app bundles jitsi-meet and
|
||||
* lib-jitsi-meet at build time and does not download them at runtime from the
|
||||
* deployment on which it will join a conference.
|
||||
*
|
||||
* @param {Object} oldValue - The config {@code Object} which may or may not be
|
||||
* in the latest form supported by jitsi-meet and from which a new config
|
||||
@@ -217,11 +219,11 @@ function _getConferenceInfo(config: IConfig) {
|
||||
* @returns {Object} A config {@code Object} which is in the latest format
|
||||
* supported by jitsi-meet.
|
||||
*/
|
||||
function _translateInterfaceConfig(oldValue: IConfig) {
|
||||
function _translateLegacyConfig(oldValue: Object) {
|
||||
const newValue = oldValue;
|
||||
|
||||
if (!Array.isArray(oldValue.toolbarButtons)
|
||||
&& typeof interfaceConfig === 'object' && Array.isArray(interfaceConfig.TOOLBAR_BUTTONS)) {
|
||||
&& typeof interfaceConfig === 'object' && Array.isArray(interfaceConfig.TOOLBAR_BUTTONS)) {
|
||||
newValue.toolbarButtons = interfaceConfig.TOOLBAR_BUTTONS;
|
||||
}
|
||||
|
||||
@@ -229,7 +231,6 @@ function _translateInterfaceConfig(oldValue: IConfig) {
|
||||
oldValue.toolbarConfig = {};
|
||||
}
|
||||
|
||||
newValue.toolbarConfig = oldValue.toolbarConfig || {};
|
||||
if (typeof oldValue.toolbarConfig.alwaysVisible !== 'boolean'
|
||||
&& typeof interfaceConfig === 'object'
|
||||
&& typeof interfaceConfig.TOOLBAR_ALWAYS_VISIBLE === 'boolean') {
|
||||
@@ -248,80 +249,39 @@ function _translateInterfaceConfig(oldValue: IConfig) {
|
||||
newValue.toolbarConfig.timeout = interfaceConfig.TOOLBAR_TIMEOUT;
|
||||
}
|
||||
|
||||
if (!oldValue.connectionIndicators
|
||||
&& typeof interfaceConfig === 'object'
|
||||
&& (interfaceConfig.hasOwnProperty('CONNECTION_INDICATOR_DISABLED')
|
||||
|| interfaceConfig.hasOwnProperty('CONNECTION_INDICATOR_AUTO_HIDE_ENABLED')
|
||||
|| interfaceConfig.hasOwnProperty('CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT'))) {
|
||||
newValue.connectionIndicators = {
|
||||
disabled: interfaceConfig.CONNECTION_INDICATOR_DISABLED,
|
||||
autoHide: interfaceConfig.CONNECTION_INDICATOR_AUTO_HIDE_ENABLED,
|
||||
autoHideTimeout: interfaceConfig.CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT
|
||||
};
|
||||
}
|
||||
|
||||
if (oldValue.disableModeratorIndicator === undefined
|
||||
&& typeof interfaceConfig === 'object'
|
||||
&& interfaceConfig.hasOwnProperty('DISABLE_FOCUS_INDICATOR')) {
|
||||
newValue.disableModeratorIndicator = interfaceConfig.DISABLE_FOCUS_INDICATOR;
|
||||
}
|
||||
|
||||
if (oldValue.defaultLocalDisplayName === undefined
|
||||
&& typeof interfaceConfig === 'object'
|
||||
&& interfaceConfig.hasOwnProperty('DEFAULT_LOCAL_DISPLAY_NAME')) {
|
||||
newValue.defaultLocalDisplayName = interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME;
|
||||
}
|
||||
|
||||
if (oldValue.defaultRemoteDisplayName === undefined
|
||||
&& typeof interfaceConfig === 'object'
|
||||
&& interfaceConfig.hasOwnProperty('DEFAULT_REMOTE_DISPLAY_NAME')) {
|
||||
newValue.defaultRemoteDisplayName = interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;
|
||||
}
|
||||
|
||||
return newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new config {@code Object}, if necessary, out of a specific
|
||||
* config {@code Object} which is in the latest format supported by jitsi-meet.
|
||||
* Such a translation from an old config format to a new/the latest config
|
||||
* format is necessary because the mobile app bundles jitsi-meet and
|
||||
* lib-jitsi-meet at build time and does not download them at runtime from the
|
||||
* deployment on which it will join a conference.
|
||||
*
|
||||
* @param {Object} oldValue - The config {@code Object} which may or may not be
|
||||
* in the latest form supported by jitsi-meet and from which a new config
|
||||
* {@code Object} is to be constructed if necessary.
|
||||
* @returns {Object} A config {@code Object} which is in the latest format
|
||||
* supported by jitsi-meet.
|
||||
*/
|
||||
function _translateLegacyConfig(oldValue: IConfig) {
|
||||
const newValue = _translateInterfaceConfig(oldValue);
|
||||
|
||||
// Translate deprecated config values to new config values.
|
||||
|
||||
const filteredConferenceInfo = Object.keys(CONFERENCE_HEADER_MAPPING).filter(key => oldValue[key as keyof IConfig]);
|
||||
const filteredConferenceInfo = Object.keys(CONFERENCE_HEADER_MAPPING).filter(key => oldValue[key]);
|
||||
|
||||
if (filteredConferenceInfo.length) {
|
||||
newValue.conferenceInfo = _getConferenceInfo(oldValue);
|
||||
|
||||
filteredConferenceInfo.forEach(key => {
|
||||
newValue.conferenceInfo = oldValue.conferenceInfo ?? {};
|
||||
// hideRecordingLabel does not mean not render it at all, but autoHide it
|
||||
if (key === 'hideRecordingLabel') {
|
||||
newValue.conferenceInfo.alwaysVisible
|
||||
= (newValue.conferenceInfo?.alwaysVisible ?? []).filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c));
|
||||
= newValue.conferenceInfo.alwaysVisible.filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c));
|
||||
newValue.conferenceInfo.autoHide
|
||||
= _.union(newValue.conferenceInfo.autoHide, CONFERENCE_HEADER_MAPPING[key]);
|
||||
} else {
|
||||
newValue.conferenceInfo.alwaysVisible
|
||||
= (newValue.conferenceInfo.alwaysVisible ?? []).filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c));
|
||||
= newValue.conferenceInfo.alwaysVisible.filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c));
|
||||
newValue.conferenceInfo.autoHide
|
||||
= (newValue.conferenceInfo.autoHide ?? []).filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c));
|
||||
= newValue.conferenceInfo.autoHide.filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!oldValue.connectionIndicators
|
||||
&& typeof interfaceConfig === 'object'
|
||||
&& (interfaceConfig.hasOwnProperty('CONNECTION_INDICATOR_DISABLED')
|
||||
|| interfaceConfig.hasOwnProperty('CONNECTION_INDICATOR_AUTO_HIDE_ENABLED')
|
||||
|| interfaceConfig.hasOwnProperty('CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT'))) {
|
||||
newValue.connectionIndicators = {
|
||||
disabled: interfaceConfig.CONNECTION_INDICATOR_DISABLED,
|
||||
autoHide: interfaceConfig.CONNECTION_INDICATOR_AUTO_HIDE_ENABLED,
|
||||
autoHideTimeout: interfaceConfig.CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT
|
||||
};
|
||||
}
|
||||
|
||||
newValue.prejoinConfig = oldValue.prejoinConfig || {};
|
||||
if (oldValue.hasOwnProperty('prejoinPageEnabled')
|
||||
&& !newValue.prejoinConfig.hasOwnProperty('enabled')
|
||||
@@ -355,15 +315,33 @@ function _translateLegacyConfig(oldValue: IConfig) {
|
||||
};
|
||||
}
|
||||
|
||||
if (oldValue.disableModeratorIndicator === undefined
|
||||
&& typeof interfaceConfig === 'object'
|
||||
&& interfaceConfig.hasOwnProperty('DISABLE_FOCUS_INDICATOR')) {
|
||||
newValue.disableModeratorIndicator = interfaceConfig.DISABLE_FOCUS_INDICATOR;
|
||||
}
|
||||
|
||||
newValue.e2ee = newValue.e2ee || {};
|
||||
|
||||
if (oldValue.e2eeLabels) {
|
||||
newValue.e2ee.e2eeLabels = oldValue.e2eeLabels;
|
||||
}
|
||||
|
||||
if (oldValue.defaultLocalDisplayName === undefined
|
||||
&& typeof interfaceConfig === 'object'
|
||||
&& interfaceConfig.hasOwnProperty('DEFAULT_LOCAL_DISPLAY_NAME')) {
|
||||
newValue.defaultLocalDisplayName = interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME;
|
||||
}
|
||||
|
||||
newValue.defaultLocalDisplayName
|
||||
= newValue.defaultLocalDisplayName || 'me';
|
||||
|
||||
if (oldValue.defaultRemoteDisplayName === undefined
|
||||
&& typeof interfaceConfig === 'object'
|
||||
&& interfaceConfig.hasOwnProperty('DEFAULT_REMOTE_DISPLAY_NAME')) {
|
||||
newValue.defaultRemoteDisplayName = interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;
|
||||
}
|
||||
|
||||
if (oldValue.hideAddRoomButton) {
|
||||
newValue.breakoutRooms = {
|
||||
/* eslint-disable-next-line no-extra-parens */
|
||||
@@ -375,46 +353,6 @@ function _translateLegacyConfig(oldValue: IConfig) {
|
||||
newValue.defaultRemoteDisplayName
|
||||
= newValue.defaultRemoteDisplayName || 'Fellow Jitster';
|
||||
|
||||
newValue.transcription = newValue.transcription || {};
|
||||
if (oldValue.transcribingEnabled !== undefined) {
|
||||
newValue.transcription = {
|
||||
...newValue.transcription,
|
||||
enabled: oldValue.transcribingEnabled
|
||||
};
|
||||
}
|
||||
if (oldValue.transcribeWithAppLanguage !== undefined) {
|
||||
newValue.transcription = {
|
||||
...newValue.transcription,
|
||||
useAppLanguage: oldValue.transcribeWithAppLanguage
|
||||
};
|
||||
}
|
||||
if (oldValue.preferredTranscribeLanguage !== undefined) {
|
||||
newValue.transcription = {
|
||||
...newValue.transcription,
|
||||
preferredLanguage: oldValue.preferredTranscribeLanguage
|
||||
};
|
||||
}
|
||||
if (oldValue.autoCaptionOnRecord !== undefined) {
|
||||
newValue.transcription = {
|
||||
...newValue.transcription,
|
||||
autoCaptionOnRecord: oldValue.autoCaptionOnRecord
|
||||
};
|
||||
}
|
||||
|
||||
newValue.recordingService = newValue.recordingService || {};
|
||||
if (oldValue.fileRecordingsServiceEnabled !== undefined) {
|
||||
newValue.recordingService = {
|
||||
...newValue.recordingService,
|
||||
enabled: oldValue.fileRecordingsServiceEnabled
|
||||
};
|
||||
}
|
||||
if (oldValue.fileRecordingsServiceSharingEnabled !== undefined) {
|
||||
newValue.recordingService = {
|
||||
...newValue.recordingService,
|
||||
sharingEnabled: oldValue.fileRecordingsServiceSharingEnabled
|
||||
};
|
||||
}
|
||||
|
||||
return newValue;
|
||||
}
|
||||
|
||||
@@ -426,7 +364,7 @@ function _translateLegacyConfig(oldValue: IConfig) {
|
||||
* @private
|
||||
* @returns {Object} The new state after the reduction of the specified action.
|
||||
*/
|
||||
function _updateConfig(state: IConfig, { config }: {config: IConfig}) {
|
||||
function _updateConfig(state, { config }) {
|
||||
const newState = _.merge({}, state, config);
|
||||
|
||||
_cleanupConfig(newState);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -16,8 +16,6 @@ export {
|
||||
} from './actions.native';
|
||||
import logger from './logger';
|
||||
|
||||
export * from './actions.any';
|
||||
|
||||
/**
|
||||
* Opens new connection.
|
||||
*
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user