Compare commits

..

1 Commits

Author SHA1 Message Date
Saúl Ibarra Corretgé
8d53dce1eb chore(rn,versions) bump sdk and app versions 2023-04-24 15:34:58 +03:00
715 changed files with 8582 additions and 19063 deletions

View File

@@ -1,8 +1,6 @@
# The build artifacts of the jitsi-meet project.
build/*
doc/*
# Third-party source code which we (1) do not want to modify or (2) try to
# modify as little as possible.
libs/*

16
.github/stale.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 90
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- confirmed
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View File

@@ -12,24 +12,14 @@ jobs:
with:
node-version: 16
cache: 'npm'
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v35
- name: Get changed lang files
id: lang-files
run: echo "all=$(echo "${{ steps.changed-files.outputs.all_changed_files }}" | grep -oE 'lang\/\S+' | tr '\n' ' ')" >> "$GITHUB_OUTPUT"
- run: npm install
- name: Check git status
run: git status
- name: Normalize lang files to ensure sorted
if: steps.lang-files.outputs.all
run: npm run lang-sort
- name: Check lang files are formatted correctly
if: steps.lang-files.outputs.all
run: npm run lint:lang
- name: Check if the git repository is clean
run: $(exit $(git status --porcelain --untracked-files=no | head -255 | wc -l)) || (echo "Dirty git tree"; git diff; exit 1)
- run: npm run lint:ci && npm run tsc:ci
- run: npm run lint:ci
linux-build:
name: Build Frontend (Linux)
runs-on: ubuntu-latest

View File

@@ -1,21 +0,0 @@
name: 'Close stale issues and PRs'
on:
schedule:
- cron: '30 1 * * *'
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v8
with:
stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
stale-pr-message: 'This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
stale-issue-label: 'stale'
stale-pr-label: 'stale'
exempt-issue-labels: 'confirmed,help-needed'
exempt-pr-labels: 'confirmed'
days-before-issue-stale: 60
days-before-pr-stale: 90
days-before-issue-close: 10
days-before-pr-close: 10

17
.gitignore vendored
View File

@@ -61,9 +61,8 @@ buck-out/
# fastlane
#
**/fastlane/report.xml
**/fastlane/Preview.html
**/fastlane/test_output
*/fastlane/report.xml
*/fastlane/Preview.html
# Build artifacts
*.jsbundle
@@ -94,15 +93,3 @@ twa/*.aab
twa/assetlinks.json
tsconfig.json
# React Native SDK
#
react-native-sdk/android/src
react-native-sdk/images
react-native-sdk/ios
react-native-sdk/lang
react-native-sdk/modules
react-native-sdk/node_modules
react-native-sdk/react
react-native-sdk/service
react-native-sdk/sounds

View File

@@ -16,8 +16,7 @@
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:exported="true"
android:label="@string/app_name"
android:launchMode="singleInstance"
android:taskAffinity=""
android:launchMode="singleTask"
android:name=".MainActivity"
android:resizeableActivity="true"
android:supportsPictureInPicture="true"

View File

@@ -10,17 +10,16 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.1'
classpath 'com.android.tools.build:gradle:7.0.4'
classpath 'com.google.gms:google-services:4.3.14'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2'
}
}
ext {
kotlinVersion = "1.7.0"
buildToolsVersion = "31.0.0"
compileSdkVersion = 32
minSdkVersion = 24
minSdkVersion = 23
targetSdkVersion = 32
supportLibVersion = "28.0.0"

View File

@@ -26,5 +26,5 @@ android.useAndroidX=true
android.enableJetifier=true
android.bundle.enableUncompressedNativeLibs=false
appVersion=23.2.0
sdkVersion=8.2.2
appVersion=23.0.0
sdkVersion=8.0.0

View File

@@ -29,18 +29,14 @@ if [[ $MVN_HTTP == 1 ]]; then
# Push React Native
echo "Pushing React Native ${RN_VERSION} to the Maven repo"
pushd ${THIS_DIR}/../../node_modules/react-native/android/com/facebook/react/react-native/${RN_VERSION}
cat react-native-${RN_VERSION}.pom \
| sed "s#<packaging>pom</packaging>#<packaging>aar</packaging>#" \
| sed "/<optional>/d" \
> react-native-${RN_VERSION}-fixed.pom
mvn \
deploy:deploy-file \
-Durl=${MVN_REPO} \
-DrepositoryId=${MVN_REPO_ID} \
-Dfile=react-native-${RN_VERSION}-release.aar \
-Dfile=react-native-${RN_VERSION}.aar \
-Dpackaging=aar \
-DgeneratePom=false \
-DpomFile=react-native-${RN_VERSION}-fixed.pom || true
-DpomFile=react-native-${RN_VERSION}.pom || true
popd
# Push JSC
echo "Pushing JSC ${JSC_VERSION} to the Maven repo"
@@ -59,17 +55,13 @@ else
if [[ ! -d ${MVN_REPO}/com/facebook/react/react-native/${RN_VERSION} ]]; then
echo "Pushing React Native ${RN_VERSION} to the Maven repo"
pushd ${THIS_DIR}/../../node_modules/react-native/android/com/facebook/react/react-native/${RN_VERSION}
cat react-native-${RN_VERSION}.pom \
| sed "s#<packaging>pom</packaging>#<packaging>aar</packaging>#" \
| sed "/<optional>/d" \
> react-native-${RN_VERSION}-fixed.pom
mvn \
deploy:deploy-file \
-Durl=${MVN_REPO} \
-Dfile=react-native-${RN_VERSION}-release.aar \
-Dfile=react-native-${RN_VERSION}.aar \
-Dpackaging=aar \
-DgeneratePom=false \
-DpomFile=react-native-${RN_VERSION}-fixed.pom
-DpomFile=react-native-${RN_VERSION}.pom
popd
fi

View File

@@ -25,7 +25,6 @@ import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.module.annotations.ReactModule;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
@@ -33,10 +32,7 @@ import java.util.Map;
class AppInfoModule
extends ReactContextBaseJavaModule {
private static final String BUILD_CONFIG = "org.jitsi.meet.sdk.BuildConfig";
public static final String NAME = "AppInfo";
public static final boolean GOOGLE_SERVICES_ENABLED = getGoogleServicesEnabled();
public static final boolean LIBRE_BUILD = getLibreBuild();
public AppInfoModule(ReactApplicationContext reactContext) {
super(reactContext);
@@ -79,8 +75,8 @@ class AppInfoModule
constants.put(
"version",
packageInfo == null ? "" : packageInfo.versionName);
constants.put("LIBRE_BUILD", LIBRE_BUILD);
constants.put("GOOGLE_SERVICES_ENABLED", GOOGLE_SERVICES_ENABLED);
constants.put("LIBRE_BUILD", BuildConfig.LIBRE_BUILD);
constants.put("GOOGLE_SERVICES_ENABLED", BuildConfig.GOOGLE_SERVICES_ENABLED);
return constants;
}
@@ -89,47 +85,4 @@ class AppInfoModule
public String getName() {
return NAME;
}
/**
* Checks if libre google services object is null based on build configuration.
*/
private static boolean getGoogleServicesEnabled() {
Object googleServicesEnabled = getBuildConfigValue("GOOGLE_SERVICES_ENABLED");
if (googleServicesEnabled !=null) {
return (Boolean) googleServicesEnabled;
}
return false;
}
/**
* Checks if libre build field is null based on build configuration.
*/
private static boolean getLibreBuild() {
Object libreBuild = getBuildConfigValue("LIBRE_BUILD");
if (libreBuild !=null) {
return (Boolean) libreBuild;
}
return false;
}
/**
* Gets build config value of a certain field.
*
* @param fieldName Field from build config.
*/
private static Object getBuildConfigValue(String fieldName) {
try {
Class<?> c = Class.forName(BUILD_CONFIG);
Field f = c.getDeclaredField(fieldName);
f.setAccessible(true);
return f.get(null);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

View File

@@ -45,12 +45,6 @@ class AudioDeviceHandlerGeneric implements
*/
private AudioModeModule module;
/**
* Constant defining a Hearing Aid. Only available on API level >= 28.
* The value of: AudioDeviceInfo.TYPE_HEARING_AID
*/
private static final int TYPE_HEARING_AID = 23;
/**
* Constant defining a USB headset. Only available on API level >= 26.
* The value of: AudioDeviceInfo.TYPE_USB_HEADSET
@@ -91,7 +85,6 @@ class AudioDeviceHandlerGeneric implements
break;
case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
case AudioDeviceInfo.TYPE_WIRED_HEADSET:
case TYPE_HEARING_AID:
case TYPE_USB_HEADSET:
devices.add(AudioModeModule.DEVICE_HEADPHONES);
break;

View File

@@ -13,7 +13,6 @@ import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import androidx.annotation.RequiresApi;
import com.facebook.react.bridge.Promise;
@@ -358,7 +357,7 @@ public class ConnectionService extends android.telecom.ConnectionService {
JitsiMeetLogger.i(TAG + " onDisconnect " + getCallUUID());
WritableNativeMap data = new WritableNativeMap();
data.putString("callUUID", getCallUUID());
RNConnectionService.getInstance().emitEvent(
ReactInstanceManagerHolder.emitEvent(
"org.jitsi.meet:features/connection_service#disconnect",
data);
// The JavaScript side will not go back to the native with
@@ -378,7 +377,7 @@ public class ConnectionService extends android.telecom.ConnectionService {
JitsiMeetLogger.i(TAG + " onAbort " + getCallUUID());
WritableNativeMap data = new WritableNativeMap();
data.putString("callUUID", getCallUUID());
RNConnectionService.getInstance().emitEvent(
ReactInstanceManagerHolder.emitEvent(
"org.jitsi.meet:features/connection_service#abort",
data);
// The JavaScript side will not go back to the native with
@@ -407,7 +406,7 @@ public class ConnectionService extends android.telecom.ConnectionService {
@Override
public void onCallAudioStateChanged(CallAudioState state) {
JitsiMeetLogger.d(TAG + " onCallAudioStateChanged: " + state);
RNConnectionService module = RNConnectionService.getInstance();
RNConnectionService module = ReactInstanceManagerHolder.getNativeModule(RNConnectionService.class);
if (module != null) {
module.onCallAudioStateChange(state);
}

View File

@@ -10,19 +10,14 @@ import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
@@ -40,7 +35,6 @@ class RNConnectionService extends ReactContextBaseJavaModule {
private static final String TAG = ConnectionService.TAG;
private static RNConnectionService sRNConnectionServiceInstance;
/**
* Handler for dealing with call state changes. We are acting as a proxy between ConnectionService
* and other modules such as {@link AudioModeModule}.
@@ -63,11 +57,6 @@ class RNConnectionService extends ReactContextBaseJavaModule {
RNConnectionService(ReactApplicationContext reactContext) {
super(reactContext);
sRNConnectionServiceInstance = this;
}
static RNConnectionService getInstance() {
return sRNConnectionServiceInstance;
}
@ReactMethod
@@ -237,22 +226,4 @@ class RNConnectionService extends ReactContextBaseJavaModule {
interface CallAudioStateListener {
void onCallAudioStateChange(android.telecom.CallAudioState callAudioState);
}
/**
* Helper function to send an event to JavaScript.
*
* @param eventName {@code String} containing the event name.
* @param data {@code Object} optional ancillary data for the event.
*/
void emitEvent(
String eventName,
@Nullable Object data) {
ReactContext reactContext = getReactApplicationContext();
if (reactContext != null) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, data);
}
}
}

2
app.js
View File

@@ -18,6 +18,7 @@ import './react/features/base/jitsi-local-storage/setup';
import conference from './conference';
import API from './modules/API';
import UI from './modules/UI/UI';
import keyboardshortcut from './modules/keyboardshortcut/keyboardshortcut';
import translation from './modules/translation/translation';
// Initialize Olm as early as possible.
@@ -37,6 +38,7 @@ window.APP = {
'index.loaded': window.indexLoadedTime
},
keyboardshortcut,
translation,
UI
};

View File

@@ -87,7 +87,6 @@ import {
} from './react/features/base/lib-jitsi-meet';
import { isFatalJitsiConnectionError } from './react/features/base/lib-jitsi-meet/functions';
import {
gumPending,
setAudioAvailable,
setAudioMuted,
setAudioUnmutePermissions,
@@ -101,7 +100,6 @@ import {
getStartWithVideoMuted,
isVideoMutedByUser
} from './react/features/base/media/functions';
import { IGUMPendingState } from './react/features/base/media/types';
import {
dominantSpeakerChanged,
localParticipantAudioLevelChanged,
@@ -142,7 +140,6 @@ import { downloadJSON } from './react/features/base/util/downloadJSON';
import { showDesktopPicker } from './react/features/desktop-picker/actions';
import { appendSuffix } from './react/features/display-name/functions';
import { maybeOpenFeedbackDialog, submitFeedback } from './react/features/feedback/actions';
import { initKeyboardShortcuts } from './react/features/keyboard-shortcuts/actions';
import { maybeSetLobbyChatMessageListener } from './react/features/lobby/actions.any';
import { setNoiseSuppressionEnabled } from './react/features/noise-suppression/actions';
import { hideNotification, showNotification, showWarningNotification } from './react/features/notifications/actions';
@@ -363,11 +360,11 @@ class ConferenceConnector {
const [ vnode ] = params;
APP.store.dispatch(overwriteConfig(newConfig))
.then(() => this._conference.leaveRoom())
.then(() => APP.store.dispatch(setIAmVisitor(Boolean(vnode))))
.then(this._conference.leaveRoom())
.then(APP.store.dispatch(setIAmVisitor(Boolean(vnode))))
// we do not clear local tracks on error, so we need to manually clear them
.then(() => APP.store.dispatch(destroyLocalTracks()))
.then(APP.store.dispatch(destroyLocalTracks()))
.then(() => {
// Reset VideoLayout. It's destroyed in features/video-layout/middleware.web.js so re-initialize it.
VideoLayout.initLargeVideo();
@@ -420,7 +417,7 @@ class ConferenceConnector {
if (newConfig) {
APP.store.dispatch(overwriteConfig(newConfig))
.then(() => this._conference.leaveRoom())
.then(this._conference.leaveRoom())
.then(() => {
_connectionPromise = connect(this._conference.roomName);
@@ -495,21 +492,6 @@ function disconnect() {
return connection.disconnect().then(onDisconnected, onDisconnected);
}
/**
* Sets the GUM pending state for the tracks that have failed.
*
* NOTE: Some of the track that we will be setting to GUM pending state NONE may not have failed but they may have
* been requested. This won't be a problem because their current GUM pending state will be NONE anyway.
* @param {JitsiLocalTrack} tracks - The tracks that have been created.
* @returns {void}
*/
function setGUMPendingStateOnFailedTracks(tracks) {
const tracksTypes = tracks.map(track => track.getType());
const nonPendingTracks = [ MEDIA_TYPE.AUDIO, MEDIA_TYPE.VIDEO ].filter(type => !tracksTypes.includes(type));
APP.store.dispatch(gumPending(nonPendingTracks, IGUMPendingState.NONE));
}
/**
* Handles CONNECTION_FAILED events from lib-jitsi-meet.
*
@@ -576,7 +558,7 @@ export default {
);
}
let tryCreateLocalTracks = Promise.resolve([]);
let tryCreateLocalTracks;
// On Electron there is no permission prompt for granting permissions. That's why we don't need to
// spend much time displaying the overlay screen. If GUM is not resolved within 15 seconds it will
@@ -617,66 +599,76 @@ export default {
return [];
});
} else if (requestedAudio || requestedVideo) {
APP.store.dispatch(gumPending(initialDevices, IGUMPendingState.PENDING_UNMUTE));
} else if (!requestedAudio && !requestedVideo) {
// Resolve with no tracks
tryCreateLocalTracks = Promise.resolve([]);
} else {
tryCreateLocalTracks = createLocalTracksF({
devices: initialDevices,
timeout,
firePermissionPromptIsShownEvent: true
})
.catch(async error => {
if (error.name === JitsiTrackErrors.TIMEOUT && !browser.isElectron()) {
errors.audioAndVideoError = error;
.catch(err => {
if (requestedAudio && requestedVideo) {
// Try audio only...
errors.audioAndVideoError = err;
if (err.name === JitsiTrackErrors.TIMEOUT && !browser.isElectron()) {
// In this case we expect that the permission prompt is still visible. There is no point of
// executing GUM with different source. Also at the time of writing the following
// inconsistency have been noticed in some browsers - if the permissions prompt is visible
// and another GUM is executed the prompt does not change its content but if the user
// clicks allow the user action isassociated with the latest GUM call.
errors.audioOnlyError = err;
errors.videoOnlyError = err;
return [];
}
return createLocalTracksF(audioOptions);
} else if (requestedAudio && !requestedVideo) {
errors.audioOnlyError = err;
return [];
} else if (requestedVideo && !requestedAudio) {
errors.videoOnlyError = err;
return [];
}
logger.error('Should never happen');
})
.catch(err => {
// Log this just in case...
if (!requestedAudio) {
logger.error('The impossible just happened', err);
}
errors.audioOnlyError = err;
// Try video only...
return requestedVideo
? createLocalTracksF({
devices: [ MEDIA_TYPE.VIDEO ],
firePermissionPromptIsShownEvent: true
})
: [];
})
.catch(err => {
// Log this just in case...
if (!requestedVideo) {
logger.error('The impossible just happened', err);
}
errors.videoOnlyError = err;
return [];
}
// Retry with separate gUM calls.
const gUMPromises = [];
const tracks = [];
if (requestedAudio) {
gUMPromises.push(createLocalTracksF(audioOptions));
}
if (requestedVideo) {
gUMPromises.push(createLocalTracksF({
devices: [ MEDIA_TYPE.VIDEO ],
timeout,
firePermissionPromptIsShownEvent: true
}));
}
const results = await Promise.allSettled(gUMPromises);
let errorMsg;
results.forEach((result, idx) => {
if (result.status === 'fulfilled') {
tracks.push(result.value[0]);
} else {
errorMsg = result.reason;
const isAudio = idx === 0;
logger.error(`${isAudio ? 'Audio' : 'Video'} track creation failed with error ${errorMsg}`);
if (isAudio) {
errors.audioOnlyError = errorMsg;
} else {
errors.videoOnlyError = errorMsg;
}
}
});
if (errors.audioOnlyError && errors.videoOnlyError) {
errors.audioAndVideoError = errorMsg;
}
return tracks;
});
}
// Hide the permissions prompt/overlay as soon as the tracks are created. Don't wait for the connection to
// be established, as in some cases like when auth is required, connection won't be established until the user
// inputs their credentials, but the dialog would be overshadowed by the overlay.
// Hide the permissions prompt/overlay as soon as the tracks are
// created. Don't wait for the connection to be made, since in some
// cases, when auth is required, for instance, that won't happen until
// the user inputs their credentials, but the dialog would be
// overshadowed by the overlay.
tryCreateLocalTracks.then(tracks => {
APP.store.dispatch(mediaPermissionPromptVisibilityChanged(false));
@@ -817,51 +809,43 @@ export default {
const initialOptions = {
startAudioOnly: config.startAudioOnly,
startScreenSharing: config.startScreenSharing,
startWithAudioMuted: getStartWithAudioMuted(state) || isUserInteractionRequiredForUnmute(state),
startWithVideoMuted: getStartWithVideoMuted(state) || isUserInteractionRequiredForUnmute(state)
startWithAudioMuted: getStartWithAudioMuted(state)
|| isUserInteractionRequiredForUnmute(state),
startWithVideoMuted: getStartWithVideoMuted(state)
|| isUserInteractionRequiredForUnmute(state)
};
this.roomName = roomName;
try {
// Initialize the device list first. This way, when creating tracks based on preferred devices, loose label
// matching can be done in cases where the exact ID match is no longer available, such as -
// 1. When the camera device has switched USB ports.
// 2. When in startSilent mode we want to start with audio muted
// Initialize the device list first. This way, when creating tracks
// based on preferred devices, loose label matching can be done in
// cases where the exact ID match is no longer available, such as
// when the camera device has switched USB ports.
// when in startSilent mode we want to start with audio muted
await this._initDeviceList();
} catch (error) {
logger.warn('initial device list initialization failed', error);
}
// Filter out the local tracks based on various config options, i.e., when user joins muted or is muted by
// focus. However, audio track will always be created even though it is not added to the conference since we
// want audio related features (noisy mic, talk while muted, etc.) to work even if the mic is muted.
const handleInitialTracks = (options, tracks) => {
let localTracks = tracks;
// No local tracks are added when user joins as a visitor.
if (iAmVisitor(state)) {
return [];
}
if (options.startWithAudioMuted || room?.isStartAudioMuted()) {
const handleStartAudioMuted = (options, tracks) => {
if (options.startWithAudioMuted) {
// Always add the track on Safari because of a known issue where audio playout doesn't happen
// if the user joins audio and video muted, i.e., if there is no local media capture.
if (browser.isWebKitBased()) {
this.muteAudio(true, true);
} else {
localTracks = localTracks.filter(track => track.getType() !== MEDIA_TYPE.AUDIO);
return tracks.filter(track => track.getType() !== MEDIA_TYPE.AUDIO);
}
}
if (room?.isStartVideoMuted()) {
localTracks = localTracks.filter(track => track.getType() !== MEDIA_TYPE.VIDEO);
}
return localTracks;
return tracks;
};
if (isPrejoinPageVisible(state)) {
_connectionPromise = connect(roomName).then(c => {
// We want to initialize it early, in case of errors to be able to gather logs.
// we want to initialize it early, in case of errors to be able
// to gather logs
APP.connection = c;
return c;
@@ -874,38 +858,48 @@ export default {
APP.store.dispatch(makePrecallTest(this._getConferenceOptions()));
const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(initialOptions);
const localTracks = await tryCreateLocalTracks;
const tracks = await tryCreateLocalTracks;
// Initialize device list a second time to ensure device labels get populated in case of an initial gUM
// acceptance; otherwise they may remain as empty strings.
// Initialize device list a second time to ensure device labels
// get populated in case of an initial gUM acceptance; otherwise
// they may remain as empty strings.
this._initDeviceList(true);
if (isPrejoinPageVisible(state)) {
APP.store.dispatch(gumPending([ MEDIA_TYPE.AUDIO, MEDIA_TYPE.VIDEO ], IGUMPendingState.NONE));
return APP.store.dispatch(initPrejoin(localTracks, errors));
return APP.store.dispatch(initPrejoin(tracks, errors));
}
logger.debug('Prejoin screen no longer displayed at the time when tracks were created');
this._displayErrorsForCreateInitialLocalTracks(errors);
const tracks = handleInitialTracks(initialOptions, localTracks);
let localTracks = handleStartAudioMuted(initialOptions, tracks);
setGUMPendingStateOnFailedTracks(tracks);
// In case where gUM is slow and resolves after the startAudio/VideoMuted coming from jicofo, we can be
// join unmuted even though jicofo had instruct us to mute, so let's respect that before passing the tracks
if (!browser.isWebKitBased()) {
if (room?.isStartAudioMuted()) {
localTracks = localTracks.filter(track => track.getType() !== MEDIA_TYPE.AUDIO);
}
}
return this._setLocalAudioVideoStreams(tracks);
if (room?.isStartVideoMuted()) {
localTracks = localTracks.filter(track => track.getType() !== MEDIA_TYPE.VIDEO);
}
// Do not add the tracks if the user has joined the call as a visitor.
if (iAmVisitor(state)) {
return Promise.resolve();
}
return this._setLocalAudioVideoStreams(localTracks);
}
const [ tracks, con ] = await this.createInitialLocalTracksAndConnect(roomName, initialOptions);
this._initDeviceList(true);
const filteredTracks = handleInitialTracks(initialOptions, tracks);
setGUMPendingStateOnFailedTracks(filteredTracks);
return this.startConference(con, filteredTracks);
return this.startConference(con, handleStartAudioMuted(initialOptions, tracks));
},
/**
@@ -1028,7 +1022,6 @@ export default {
showUI && APP.store.dispatch(notifyMicError(error));
};
APP.store.dispatch(gumPending([ MEDIA_TYPE.AUDIO ], IGUMPendingState.PENDING_UNMUTE));
createLocalTracksF({ devices: [ 'audio' ] })
.then(([ audioTrack ]) => audioTrack)
.catch(error => {
@@ -1040,10 +1033,7 @@ export default {
.then(async audioTrack => {
await this._maybeApplyAudioMixerEffect(audioTrack);
return this.useAudioStream(audioTrack);
})
.finally(() => {
APP.store.dispatch(gumPending([ MEDIA_TYPE.AUDIO ], IGUMPendingState.NONE));
this.useAudioStream(audioTrack);
});
} else {
muteLocalAudio(mute);
@@ -1082,7 +1072,7 @@ export default {
*/
muteVideo(mute, showUI = true) {
if (this.videoSwitchInProgress) {
logger.warn('muteVideo - unable to perform operations while video switch is in progress');
console.warn('muteVideo - unable to perform operations while video switch is in progress');
return;
}
@@ -1123,8 +1113,6 @@ export default {
this.isCreatingLocalTrack = true;
APP.store.dispatch(gumPending([ MEDIA_TYPE.VIDEO ], IGUMPendingState.PENDING_UNMUTE));
// Try to create local video if there wasn't any.
// This handles the case when user joined with no video
// (dismissed screen sharing screen or in audio only mode), but
@@ -1149,7 +1137,6 @@ export default {
})
.finally(() => {
this.isCreatingLocalTrack = false;
APP.store.dispatch(gumPending([ MEDIA_TYPE.VIDEO ], IGUMPendingState.NONE));
});
} else {
// FIXME show error dialog if it fails (should be handled by react)
@@ -1462,16 +1449,11 @@ export default {
* @private
*/
_setLocalAudioVideoStreams(tracks = []) {
const { dispatch } = APP.store;
const pendingGUMDevicesToRemove = [];
const promises = tracks.map(track => {
if (track.isAudioTrack()) {
pendingGUMDevicesToRemove.push(MEDIA_TYPE.AUDIO);
return this.useAudioStream(track);
} else if (track.isVideoTrack()) {
logger.debug(`_setLocalAudioVideoStreams is calling useVideoStream with track: ${track}`);
pendingGUMDevicesToRemove.push(MEDIA_TYPE.VIDEO);
return this.useVideoStream(track);
}
@@ -1483,10 +1465,6 @@ export default {
});
return Promise.allSettled(promises).then(() => {
if (pendingGUMDevicesToRemove.length > 0) {
dispatch(gumPending(pendingGUMDevicesToRemove, IGUMPendingState.NONE));
}
this._localTracksInitialized = true;
logger.log(`Initialized with ${tracks.length} local tracks`);
});
@@ -2029,10 +2007,7 @@ export default {
room.on(
JitsiConferenceEvents.NON_PARTICIPANT_MESSAGE_RECEIVED,
(...args) => {
APP.store.dispatch(nonParticipantMessageReceived(...args));
APP.API.notifyNonParticipantMessageReceived(...args);
});
(...args) => APP.store.dispatch(nonParticipantMessageReceived(...args)));
room.on(
JitsiConferenceEvents.LOCK_STATE_CHANGED,
@@ -2203,11 +2178,6 @@ export default {
UIEvents.VIDEO_DEVICE_CHANGED,
cameraDeviceId => {
const videoWasMuted = this.isLocalVideoMuted();
const localVideoTrack = getLocalJitsiVideoTrack(APP.store.getState());
if (localVideoTrack?.getDeviceId() === cameraDeviceId) {
return;
}
sendAnalytics(createDeviceChangedEvent('video', 'input'));
@@ -2338,7 +2308,10 @@ export default {
APP.UI.initConference();
dispatch(initKeyboardShortcuts());
if (!config.disableShortcuts) {
APP.keyboardshortcut.init();
}
dispatch(conferenceJoined(room));
const jwt = APP.store.getState()['features/base/jwt'];
@@ -2452,9 +2425,7 @@ export default {
const { dispatch } = APP.store;
const setAudioOutputPromise
= setAudioOutputDeviceId(newDevices.audiooutput, dispatch)
.catch(err => {
logger.error(`Failed to set the audio output device to ${newDevices.audiooutput} - ${err}`);
});
.catch(); // Just ignore any errors in catch block.
promises.push(setAudioOutputPromise);
}
@@ -2492,7 +2463,7 @@ export default {
}
// check for video
if (requestedInput.video) {
if (!requestedInput.video) {
APP.store.dispatch(checkAndNotifyForNewDevice(newAvailDevices.videoInput, oldDevices.videoInput));
}
@@ -2536,15 +2507,14 @@ export default {
// Create the tracks and replace them only if the user is unmuted.
if (requestedInput.audio || requestedInput.video) {
let tracks = [];
const realAudioDeviceId = hasDefaultMicChanged
? getDefaultDeviceId(APP.store.getState(), 'audioInput') : newDevices.audioinput;
try {
tracks = await mediaDeviceHelper.createLocalTracksAfterDeviceListChanged(
createLocalTracksF,
requestedInput.video ? newDevices.videoinput : null,
requestedInput.audio ? realAudioDeviceId : null
);
newDevices.videoinput,
hasDefaultMicChanged
? getDefaultDeviceId(APP.store.getState(), 'audioInput')
: newDevices.audioinput);
} catch (error) {
logger.error(`Track creation failed on device change, ${error}`);
@@ -2675,22 +2645,17 @@ export default {
async leaveRoom(doDisconnect = true, reason = '') {
APP.store.dispatch(conferenceWillLeave(room));
const maybeDisconnect = () => {
if (doDisconnect) {
return disconnect();
}
};
if (room && room.isJoined()) {
return room.leave(reason).then(() => maybeDisconnect())
.catch(e => {
logger.error(e);
return maybeDisconnect();
return room.leave(reason).finally(() => {
if (doDisconnect) {
return disconnect();
}
});
}
return maybeDisconnect();
if (doDisconnect) {
return disconnect();
}
},
/**

View File

@@ -74,9 +74,6 @@ var config = {
//
testing: {
// Allows the setting of a custom bandwidth value from the UI.
// assumeBandwidth: true,
// Disables the End to End Encryption feature. Useful for debugging
// issues related to insertable streams.
// disableE2EE: false,
@@ -1068,12 +1065,7 @@ var config = {
// },
// e2ee: {
// labels: {
// description: '',
// label: '',
// tooltip: '',
// warning: '',
// },
// labels,
// externallyManagedKey: false,
// },
@@ -1383,6 +1375,7 @@ var config = {
dialOutRegionUrl
disableRemoteControl
displayJids
e2eeLabels
firefox_fake_device
googleApiApplicationClientID
iAmRecorder
@@ -1413,7 +1406,6 @@ var config = {
disableAGC
disableAP
disableHPF
disableLocalStats
disableNS
enableTalkWhileMuted
forceJVB121Ratio

View File

@@ -32,14 +32,6 @@
pointer-events: none;
z-index: $toolbarZ + 2;
&.shift-up {
bottom: calc(((#{$newToolbarSize} + 30px) * 2) * -1);
.toolbox-content {
margin-bottom: 46px;
}
}
&.visible {
bottom: 0;
}

View File

@@ -41,36 +41,3 @@
display: -webkit-flex !important;
display: flex !important;
}
/**
* resets default button styles,
* mostly intended to be used on interactive elements that
* differ from their default styles (e.g. <a>) or have custom styles
*/
.invisible-button {
background: none;
border: none;
color: inherit;
cursor: pointer;
padding: 0;
}
/**
* style an element the same as an <a>
* useful on some cases where we visually have a link but it's actually a <button>
*/
.as-link {
@extend .invisible-button;
display: inline;
color: #44A5FF;
text-decoration: none;
font-weight: bold;
&:focus,
&:hover,
&:active {
text-decoration: underline;
}
}

View File

@@ -108,10 +108,6 @@
#largeVideoContainer {
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
margin: 0 !important;
}
#largeVideoWrapper {

View File

@@ -57,10 +57,6 @@
line-height: 24px;
border-collapse: collapse;
* {
user-select: text;
}
thead {
text-align: left;
}

View File

@@ -21,7 +21,7 @@
&-actions {
margin-top: 10px;
button {
a {
cursor: pointer;
text-decoration: none;
font-size: 14px;

View File

@@ -1,6 +1,3 @@
doc/debian/jitsi-meet/jitsi-meet.example /usr/share/jitsi-meet-web-config/
doc/debian/jitsi-meet/jitsi-meet.example-apache /usr/share/jitsi-meet-web-config/
config.js /usr/share/jitsi-meet-web-config/
doc/jaas/nginx-jaas.conf /usr/share/jitsi-meet-web-config/
doc/jaas/index-jaas.html /usr/share/jitsi-meet-web-config/
doc/jaas/8x8.vc-config.js /usr/share/jitsi-meet-web-config/

View File

@@ -12,5 +12,3 @@ resources/robots.txt /usr/share/jitsi-meet/
resources/*.sh /usr/share/jitsi-meet/scripts/
pwa-worker.js /usr/share/jitsi-meet/
manifest.json /usr/share/jitsi-meet/
doc/jaas/move-to-jaas.sh /usr/share/jitsi-meet/scripts/
doc/jaas/update-asap-daily.sh /usr/share/jitsi-meet/scripts/

View File

@@ -84,12 +84,8 @@ Component "conference.jitmeet.example.com" "muc"
"polls";
--"token_verification";
"muc_rate_limit";
"muc_password_whitelist";
}
admins = { "focusUser@auth.jitmeet.example.com" }
muc_password_whitelist = {
"focusUser@auth.jitmeet.example.com"
}
muc_room_locking = false
muc_room_default_public_jids = true

View File

@@ -58,8 +58,6 @@ server {
add_header Strict-Transport-Security "max-age=63072000" always;
set $prefix "";
set $custom_index "";
set $config_js_location /etc/jitsi/meet/jitsi-meet.example.com-config.js;
ssl_certificate /etc/jitsi/meet/jitsi-meet.example.com.crt;
ssl_certificate_key /etc/jitsi/meet/jitsi-meet.example.com.key;
@@ -79,10 +77,8 @@ server {
gzip_proxied no-cache no-store private expired auth;
gzip_min_length 512;
include /etc/jitsi/meet/jaas/*.conf;
location = /config.js {
alias $config_js_location;
alias /etc/jitsi/meet/jitsi-meet.example.com-config.js;
}
location = /external_api.js {
@@ -96,11 +92,6 @@ server {
proxy_set_header Host $http_host;
}
location ~ ^/_api/public/(.*)$ {
autoindex off;
alias /etc/jitsi/meet/public/$1;
}
# ensure all static content can always be found first
location ~ ^/(libs|css|static|images|fonts|lang|sounds|.well-known)/(.*)$
{
@@ -151,12 +142,11 @@ server {
#}
location ~ ^/([^/?&:'"]+)$ {
set $roomname "$1";
try_files $uri @root_path;
}
location @root_path {
rewrite ^/(.*)$ /$custom_index break;
rewrite ^/(.*)$ / break;
}
location ~ ^/([^/?&:'"]+)/config.js$
@@ -164,7 +154,7 @@ server {
set $subdomain "$1.";
set $subdir "$1/";
alias $config_js_location;
alias /etc/jitsi/meet/jitsi-meet.example.com-config.js;
}
# Matches /(TENANT)/pwa-worker.js or /(TENANT)/manifest.json to rewrite to / and look for file

View File

@@ -1,7 +0,0 @@
</script>
<script src="https://8x8.vc/<!--# echo var="subdir" default="" -->config.js" onload="{
config.p2p.disabledCodec='VP9';
config.videoQuality.disabledCodec='VP9';
config.e2ee = { externallyManagedKey: true };
}"/>
<script>

View File

@@ -1,22 +0,0 @@
## How to switch your deployment to [JaaS](https://jaas.8x8.vc) in one easy step
Note: By default it will have e2ee(end-to-end) encryption enabled that works only on chromium based browsers (Chrome, Edge, ...). If a participant joins from another browser or mobile the e2ee is turned off.
In order to use your deployment with JaaS you first need to login to your [JaaS Developer console](https://jaas.8x8.vc/#/apikeys) and generate a key pair.
Use `Add API key` button and then `Generate API key pair`. Make sure you download the generated private key from:
<img src="generated_key_dialog.png" height="250">
Make sure you transfer this downloaded private key to your server. Copy the key id from:
<img src="api_keys_kid.png" height="200">
Now on your server run the helper script passing the private key file and the key id:
```
sudo /usr/share/jitsi-meet/scripts/move-to-jaas.sh /my/path/test-key.pk <key_id>
```
More information about JaaS Api keys at: https://developer.8x8.com/jaas/docs/jaas-console-api-keys
If you want to adjust the enabled services you can do that in /etc/jits/meet/jaas/nginx-jaas.conf. The part after `proxy_set_body` is the jwt token content that will be used for the client tokens. More info about the JaaS tokens: https://developer.8x8.com/jaas/docs/api-keys-jwt

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

View File

@@ -1,33 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<script src='external_api.js' async></script>
<style>html, body, #jaas-container { height: 100%; }</style>
<script type="text/javascript">
function getRoomName(pathname) {
const contextRootEndIndex = pathname.lastIndexOf('/');
return pathname.substring(contextRootEndIndex + 1);
}
window.onload = () => {
const jaasJwt = <!--#include virtual="/jaas-jwt" -->;
const api = new JitsiMeetExternalAPI(
window.location.host, {
roomName: `${jaasJwt.tenant}/${jaasJwt.confId}`,
parentNode: document.querySelector('#jaas-container'),
jwt: jaasJwt.token,
e2eeKey: jaasJwt.e2eeKey
});
api.addListener('videoConferenceJoined', () => {
if (jaasJwt.e2eeKey) {
console.info('Toggling e2ee on!')
api.executeCommand('toggleE2EE', true);
}
});
}
</script>
</head>
<body>
<div id="jaas-container" />
</body>
</html>

View File

@@ -1,59 +0,0 @@
#!/bin/bash
set -e
PRIVATE_KEY=$1
JAAS_KEY_ID=$2
if [ ! -f "${PRIVATE_KEY}" ] ; then
echo "You need to specify a correct path for the private key as a first argument."
exit 1;
fi
if [[ ! "${JAAS_KEY_ID}" =~ ^vpaas-magic-cookie-[0-9a-z]+/[0-9a-z]+$ ]]; then
echo "Invalid key id passed as a second argument."
exit 2;
fi
command -v node >/dev/null 2>&1 || { echo >&2 "You must install node first, go to https://nodejs.org. Aborting."; exit 4; }
NODE_VER=$(node -v);
NODE_MAJOR_VER=$(echo ${NODE_VER:1} | cut -d. -f1);
if [ "$NODE_MAJOR_VER" -lt "18" ]; then
echo "Please install latest LTS version of node (18+)";
exit 3;
fi
# we need this util for debconf-set-selections
sudo apt install debconf-utils
# Let's pre-set some settings for token-generator
cat << EOF | sudo debconf-set-selections
token-generator token-generator/private-key string ${PRIVATE_KEY}
token-generator token-generator/kid string ${JAAS_KEY_ID}
EOF
apt install token-generator
mkdir -p /etc/jitsi/meet/jaas
VPASS_COOKIE=$(echo -n ${JAAS_KEY_ID}| cut -d/ -f1)
cp /usr/share/jitsi-meet-web-config/nginx-jaas.conf /etc/jitsi/meet/jaas
sed -i "s/jaas_magic_cookie/${VPASS_COOKIE}/g" /etc/jitsi/meet/jaas/nginx-jaas.conf
cp /usr/share/jitsi-meet-web-config/8x8.vc-config.js /etc/jitsi/meet/jaas/
echo "set \$config_js_location /etc/jitsi/meet/jaas/8x8.vc-config.js;" >> /etc/jitsi/meet/jaas/jaas-vars
echo "set \$custom_index index-jaas.html;" >> /etc/jitsi/meet/jaas/jaas-vars
ln -s /usr/share/jitsi-meet-web-config/index-jaas.html /usr/share/jitsi-meet/index-jaas.html
# let's create the daily key now
/usr/share/jitsi-meet/scripts/update-asap-daily.sh
# let's add to cron daily the update of the asap key
if [ -d /etc/cron.daily ]; then
ln -s /usr/share/jitsi-meet/scripts/update-asap-daily.sh /etc/cron.daily/update-jaas-asap.sh
else
echo "No /etc/cron.daily. Please add to your cron jobs to execute as root daily the script: /usr/share/jitsi-meet/scripts/update-asap-daily.sh"
fi

View File

@@ -1,23 +0,0 @@
include /etc/jitsi/meet/jaas/jaas-vars;
location = /jaas-jwt {
include /etc/jitsi/token-generator/daily-key;
ssi on;
proxy_method POST;
proxy_set_header content-type "application/json";
proxy_set_header Accept-Encoding "";
proxy_set_header Authorization "Bearer $jaas_asap_key";
proxy_pass_request_body off;
proxy_set_body '{"sub":"jaas_magic_cookie","context":{"features":{"livestreaming":false,"outbound-call":false,"sip-outbound-call":false,"transcription":false,"recording":false},"user":{"moderator":true}},"room": "$roomname"}';
proxy_pass http://127.0.0.1:8017/generate/client?e2eeKey=true&confId=true;
}
location @magic_root_path {
rewrite ^/(.*)$ /index.html break;
}
# Anything that didn't match above, and isn't a real file, assume it's a room name and redirect to /
location ~ ^/jaas_magic_cookie/(.*)$ {
set $subdomain "jaas_magic_cookie.";
set $subdir "jaas_magic_cookie/";
try_files $1 @magic_root_path;
}

View File

@@ -1,9 +0,0 @@
JWT_KID=$(cat /etc/jitsi/token-generator/config | grep SYSTEM_ASAP_BASE_URL_MAPPINGS | cut -d= -f2- | jq -r .[].kid)
JWT_DATE=$(echo -n $JWT_KID | cut -d/ -f2-)
JWT_DATE=${JWT_DATE#jwt-}
KEY_FILE=/etc/jitsi/token-generator/daily-key
echo -n "set \$jaas_asap_key " > ${KEY_FILE}
ASAP_KEY=$(ASAP_SIGNING_KEY_FILE=/etc/jitsi/token-generator/asap-${JWT_DATE}.key ASAP_JWT_KID="${JWT_KID}" ASAP_EXPIRES_IN="1 day" node /usr/share/token-generator/jwt.js| tail -n1)
echo -n "${ASAP_KEY};" >> ${KEY_FILE}
service nginx reload

7
globals.d.ts vendored
View File

@@ -10,6 +10,12 @@ declare global {
API: any;
conference: any;
debugLogs: any;
keyboardshortcut: {
registerShortcut: Function;
unregisterShortcut: Function;
openDialog: Function;
enable: Function;
}
};
const interfaceConfig: any;
@@ -21,7 +27,6 @@ declare global {
JitsiMeetElectron?: any;
// selenium tests handler
_sharedVideoPlayer: any;
alwaysOnTop: { api: any };
}
interface Document {

1
globals.native.d.ts vendored
View File

@@ -30,7 +30,6 @@ interface IWindow {
setImmediate: typeof setImmediate;
clearImmediate: typeof clearImmediate;
addEventListener: Function;
removeEventListener: Function;
}
interface INavigator {

View File

@@ -1,13 +1,11 @@
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
platform :ios, '12.4'
platform :ios, '12.0'
workspace 'jitsi-meet'
install! 'cocoapods', :deterministic_uuids => false
production = ENV["PRODUCTION"] == "1"
target 'JitsiMeet' do
project 'app/app.xcodeproj'
@@ -23,10 +21,8 @@ target 'JitsiMeetSDK' do
#
config = use_native_modules!
flags = get_default_flags()
use_react_native!(
:path => config[:reactNativePath],
:production => production,
:path => config["reactNativePath"],
:hermes_enabled => false,
:fabric_enabled => false,
# An absolute path to your application root.
@@ -85,7 +81,7 @@ post_install do |installer|
end
target.build_configurations.each do |config|
config.build_settings['SUPPORTS_MACCATALYST'] = 'NO'
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.4'
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'
end
end
end

View File

@@ -14,14 +14,14 @@ PODS:
- CocoaLumberjack/Core (= 3.7.2)
- CocoaLumberjack/Core (3.7.2)
- DoubleConversion (1.1.6)
- FBLazyVector (0.69.11)
- FBReactNativeSpec (0.69.11):
- FBLazyVector (0.68.6)
- FBReactNativeSpec (0.68.6):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.69.11)
- RCTTypeSafety (= 0.69.11)
- React-Core (= 0.69.11)
- React-jsi (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- RCTRequired (= 0.68.6)
- RCTTypeSafety (= 0.68.6)
- React-Core (= 0.68.6)
- React-jsi (= 0.68.6)
- ReactCommon/turbomodule/core (= 0.68.6)
- Firebase/Analytics (8.15.0):
- Firebase/Core
- Firebase/Core (8.15.0):
@@ -77,10 +77,10 @@ PODS:
- GoogleUtilities/UserDefaults (~> 7.7)
- PromisesObjC (< 3.0, >= 1.2)
- fmt (6.2.1)
- Giphy (2.2.4):
- Giphy (2.1.20):
- libwebp
- giphy-react-native-sdk (2.3.0):
- Giphy (= 2.2.4)
- giphy-react-native-sdk (1.7.0):
- Giphy (= 2.1.20)
- React-Core
- glog (0.3.5)
- GoogleAppMeasurement (8.15.0):
@@ -134,7 +134,7 @@ PODS:
- AppAuth/Core (~> 1.6)
- GTMSessionFetcher/Core (< 3.0, >= 1.5)
- GTMSessionFetcher/Core (2.3.0)
- JitsiWebRTC (111.0.2)
- JitsiWebRTC (111.0.1)
- libwebp (1.2.4):
- libwebp/demux (= 1.2.4)
- libwebp/mux (= 1.2.4)
@@ -164,203 +164,201 @@ PODS:
- DoubleConversion
- fmt (~> 6.2.1)
- glog
- RCTRequired (0.69.11)
- RCTTypeSafety (0.69.11):
- FBLazyVector (= 0.69.11)
- RCTRequired (= 0.69.11)
- React-Core (= 0.69.11)
- React (0.69.11):
- React-Core (= 0.69.11)
- React-Core/DevSupport (= 0.69.11)
- React-Core/RCTWebSocket (= 0.69.11)
- React-RCTActionSheet (= 0.69.11)
- React-RCTAnimation (= 0.69.11)
- React-RCTBlob (= 0.69.11)
- React-RCTImage (= 0.69.11)
- React-RCTLinking (= 0.69.11)
- React-RCTNetwork (= 0.69.11)
- React-RCTSettings (= 0.69.11)
- React-RCTText (= 0.69.11)
- React-RCTVibration (= 0.69.11)
- React-bridging (0.69.11):
- RCTRequired (0.68.6)
- RCTTypeSafety (0.68.6):
- FBLazyVector (= 0.68.6)
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsi (= 0.69.11)
- React-callinvoker (0.69.11)
- React-Codegen (0.69.11):
- FBReactNativeSpec (= 0.69.11)
- RCTRequired (= 0.68.6)
- React-Core (= 0.68.6)
- React (0.68.6):
- React-Core (= 0.68.6)
- React-Core/DevSupport (= 0.68.6)
- React-Core/RCTWebSocket (= 0.68.6)
- React-RCTActionSheet (= 0.68.6)
- React-RCTAnimation (= 0.68.6)
- React-RCTBlob (= 0.68.6)
- React-RCTImage (= 0.68.6)
- React-RCTLinking (= 0.68.6)
- React-RCTNetwork (= 0.68.6)
- React-RCTSettings (= 0.68.6)
- React-RCTText (= 0.68.6)
- React-RCTVibration (= 0.68.6)
- React-callinvoker (0.68.6)
- React-Codegen (0.68.6):
- FBReactNativeSpec (= 0.68.6)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.69.11)
- RCTTypeSafety (= 0.69.11)
- React-Core (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-Core (0.69.11):
- RCTRequired (= 0.68.6)
- RCTTypeSafety (= 0.68.6)
- React-Core (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsiexecutor (= 0.68.6)
- ReactCommon/turbomodule/core (= 0.68.6)
- React-Core (0.68.6):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.69.11)
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-Core/Default (= 0.68.6)
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsiexecutor (= 0.68.6)
- React-perflogger (= 0.68.6)
- Yoga
- React-Core/CoreModulesHeaders (0.69.11):
- React-Core/CoreModulesHeaders (0.68.6):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsiexecutor (= 0.68.6)
- React-perflogger (= 0.68.6)
- Yoga
- React-Core/Default (0.69.11):
- React-Core/Default (0.68.6):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsiexecutor (= 0.68.6)
- React-perflogger (= 0.68.6)
- Yoga
- React-Core/DevSupport (0.69.11):
- React-Core/DevSupport (0.68.6):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.69.11)
- React-Core/RCTWebSocket (= 0.69.11)
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-jsinspector (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-Core/Default (= 0.68.6)
- React-Core/RCTWebSocket (= 0.68.6)
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsiexecutor (= 0.68.6)
- React-jsinspector (= 0.68.6)
- React-perflogger (= 0.68.6)
- Yoga
- React-Core/RCTActionSheetHeaders (0.69.11):
- React-Core/RCTActionSheetHeaders (0.68.6):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsiexecutor (= 0.68.6)
- React-perflogger (= 0.68.6)
- Yoga
- React-Core/RCTAnimationHeaders (0.69.11):
- React-Core/RCTAnimationHeaders (0.68.6):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsiexecutor (= 0.68.6)
- React-perflogger (= 0.68.6)
- Yoga
- React-Core/RCTBlobHeaders (0.69.11):
- React-Core/RCTBlobHeaders (0.68.6):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsiexecutor (= 0.68.6)
- React-perflogger (= 0.68.6)
- Yoga
- React-Core/RCTImageHeaders (0.69.11):
- React-Core/RCTImageHeaders (0.68.6):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsiexecutor (= 0.68.6)
- React-perflogger (= 0.68.6)
- Yoga
- React-Core/RCTLinkingHeaders (0.69.11):
- React-Core/RCTLinkingHeaders (0.68.6):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsiexecutor (= 0.68.6)
- React-perflogger (= 0.68.6)
- Yoga
- React-Core/RCTNetworkHeaders (0.69.11):
- React-Core/RCTNetworkHeaders (0.68.6):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsiexecutor (= 0.68.6)
- React-perflogger (= 0.68.6)
- Yoga
- React-Core/RCTSettingsHeaders (0.69.11):
- React-Core/RCTSettingsHeaders (0.68.6):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsiexecutor (= 0.68.6)
- React-perflogger (= 0.68.6)
- Yoga
- React-Core/RCTTextHeaders (0.69.11):
- React-Core/RCTTextHeaders (0.68.6):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsiexecutor (= 0.68.6)
- React-perflogger (= 0.68.6)
- Yoga
- React-Core/RCTVibrationHeaders (0.69.11):
- React-Core/RCTVibrationHeaders (0.68.6):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsiexecutor (= 0.68.6)
- React-perflogger (= 0.68.6)
- Yoga
- React-Core/RCTWebSocket (0.69.11):
- React-Core/RCTWebSocket (0.68.6):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.69.11)
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-Core/Default (= 0.68.6)
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsiexecutor (= 0.68.6)
- React-perflogger (= 0.68.6)
- Yoga
- React-CoreModules (0.69.11):
- React-CoreModules (0.68.6):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.11)
- React-Codegen (= 0.69.11)
- React-Core/CoreModulesHeaders (= 0.69.11)
- React-jsi (= 0.69.11)
- React-RCTImage (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-cxxreact (0.69.11):
- RCTTypeSafety (= 0.68.6)
- React-Codegen (= 0.68.6)
- React-Core/CoreModulesHeaders (= 0.68.6)
- React-jsi (= 0.68.6)
- React-RCTImage (= 0.68.6)
- ReactCommon/turbomodule/core (= 0.68.6)
- React-cxxreact (0.68.6):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-callinvoker (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsinspector (= 0.69.11)
- React-logger (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-runtimeexecutor (= 0.69.11)
- React-jsi (0.69.11):
- React-callinvoker (= 0.68.6)
- React-jsi (= 0.68.6)
- React-jsinspector (= 0.68.6)
- React-logger (= 0.68.6)
- React-perflogger (= 0.68.6)
- React-runtimeexecutor (= 0.68.6)
- React-jsi (0.68.6):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsi/Default (= 0.69.11)
- React-jsi/Default (0.69.11):
- React-jsi/Default (= 0.68.6)
- React-jsi/Default (0.68.6):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsiexecutor (0.69.11):
- React-jsiexecutor (0.68.6):
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-jsinspector (0.69.11)
- React-logger (0.69.11):
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-perflogger (= 0.68.6)
- React-jsinspector (0.68.6)
- React-logger (0.68.6):
- glog
- react-native-background-timer (2.4.1):
- React-Core
@@ -374,6 +372,8 @@ PODS:
- React-Core
- react-native-pager-view (5.4.9):
- React-Core
- react-native-performance (2.1.0):
- React-Core
- react-native-safe-area-context (4.4.1):
- RCT-Folly
- RCTRequired
@@ -390,77 +390,76 @@ PODS:
- react-native-video/Video (6.0.0-alpha.1):
- PromisesSwift
- React-Core
- react-native-webrtc (111.0.1):
- react-native-webrtc (111.0.0):
- JitsiWebRTC (~> 111.0.0)
- React-Core
- react-native-webview (11.15.1):
- React-Core
- React-perflogger (0.69.11)
- React-RCTActionSheet (0.69.11):
- React-Core/RCTActionSheetHeaders (= 0.69.11)
- React-RCTAnimation (0.69.11):
- React-perflogger (0.68.6)
- React-RCTActionSheet (0.68.6):
- React-Core/RCTActionSheetHeaders (= 0.68.6)
- React-RCTAnimation (0.68.6):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.11)
- React-Codegen (= 0.69.11)
- React-Core/RCTAnimationHeaders (= 0.69.11)
- React-jsi (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-RCTBlob (0.69.11):
- RCTTypeSafety (= 0.68.6)
- React-Codegen (= 0.68.6)
- React-Core/RCTAnimationHeaders (= 0.68.6)
- React-jsi (= 0.68.6)
- ReactCommon/turbomodule/core (= 0.68.6)
- React-RCTBlob (0.68.6):
- RCT-Folly (= 2021.06.28.00-v2)
- React-Codegen (= 0.69.11)
- React-Core/RCTBlobHeaders (= 0.69.11)
- React-Core/RCTWebSocket (= 0.69.11)
- React-jsi (= 0.69.11)
- React-RCTNetwork (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-RCTImage (0.69.11):
- React-Codegen (= 0.68.6)
- React-Core/RCTBlobHeaders (= 0.68.6)
- React-Core/RCTWebSocket (= 0.68.6)
- React-jsi (= 0.68.6)
- React-RCTNetwork (= 0.68.6)
- ReactCommon/turbomodule/core (= 0.68.6)
- React-RCTImage (0.68.6):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.11)
- React-Codegen (= 0.69.11)
- React-Core/RCTImageHeaders (= 0.69.11)
- React-jsi (= 0.69.11)
- React-RCTNetwork (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-RCTLinking (0.69.11):
- React-Codegen (= 0.69.11)
- React-Core/RCTLinkingHeaders (= 0.69.11)
- React-jsi (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-RCTNetwork (0.69.11):
- RCTTypeSafety (= 0.68.6)
- React-Codegen (= 0.68.6)
- React-Core/RCTImageHeaders (= 0.68.6)
- React-jsi (= 0.68.6)
- React-RCTNetwork (= 0.68.6)
- ReactCommon/turbomodule/core (= 0.68.6)
- React-RCTLinking (0.68.6):
- React-Codegen (= 0.68.6)
- React-Core/RCTLinkingHeaders (= 0.68.6)
- React-jsi (= 0.68.6)
- ReactCommon/turbomodule/core (= 0.68.6)
- React-RCTNetwork (0.68.6):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.11)
- React-Codegen (= 0.69.11)
- React-Core/RCTNetworkHeaders (= 0.69.11)
- React-jsi (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-RCTSettings (0.69.11):
- RCTTypeSafety (= 0.68.6)
- React-Codegen (= 0.68.6)
- React-Core/RCTNetworkHeaders (= 0.68.6)
- React-jsi (= 0.68.6)
- ReactCommon/turbomodule/core (= 0.68.6)
- React-RCTSettings (0.68.6):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.11)
- React-Codegen (= 0.69.11)
- React-Core/RCTSettingsHeaders (= 0.69.11)
- React-jsi (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-RCTText (0.69.11):
- React-Core/RCTTextHeaders (= 0.69.11)
- React-RCTVibration (0.69.11):
- RCTTypeSafety (= 0.68.6)
- React-Codegen (= 0.68.6)
- React-Core/RCTSettingsHeaders (= 0.68.6)
- React-jsi (= 0.68.6)
- ReactCommon/turbomodule/core (= 0.68.6)
- React-RCTText (0.68.6):
- React-Core/RCTTextHeaders (= 0.68.6)
- React-RCTVibration (0.68.6):
- RCT-Folly (= 2021.06.28.00-v2)
- React-Codegen (= 0.69.11)
- React-Core/RCTVibrationHeaders (= 0.69.11)
- React-jsi (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-runtimeexecutor (0.69.11):
- React-jsi (= 0.69.11)
- ReactCommon/turbomodule/core (0.69.11):
- React-Codegen (= 0.68.6)
- React-Core/RCTVibrationHeaders (= 0.68.6)
- React-jsi (= 0.68.6)
- ReactCommon/turbomodule/core (= 0.68.6)
- React-runtimeexecutor (0.68.6):
- React-jsi (= 0.68.6)
- ReactCommon/turbomodule/core (0.68.6):
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-bridging (= 0.69.11)
- React-callinvoker (= 0.69.11)
- React-Core (= 0.69.11)
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-logger (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-callinvoker (= 0.68.6)
- React-Core (= 0.68.6)
- React-cxxreact (= 0.68.6)
- React-jsi (= 0.68.6)
- React-logger (= 0.68.6)
- React-perflogger (= 0.68.6)
- RNCalendarEvents (2.2.0):
- React
- RNCAsyncStorage (1.17.3):
@@ -508,10 +507,10 @@ DEPENDENCIES:
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
- React (from `../node_modules/react-native/`)
- React-bridging (from `../node_modules/react-native/ReactCommon`)
- React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
- React-Codegen (from `build/generated/ios`)
- React-Core (from `../node_modules/react-native/`)
- React-Core/DevSupport (from `../node_modules/react-native/`)
- React-Core/RCTWebSocket (from `../node_modules/react-native/`)
- React-CoreModules (from `../node_modules/react-native/React/CoreModules`)
- React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
@@ -525,6 +524,7 @@ DEPENDENCIES:
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-orientation-locker (from `../node_modules/react-native-orientation-locker`)
- react-native-pager-view (from `../node_modules/react-native-pager-view`)
- react-native-performance (from `../node_modules/react-native-performance/ios`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- "react-native-slider (from `../node_modules/@react-native-community/slider`)"
- react-native-splash-screen (from `../node_modules/react-native-splash-screen`)
@@ -606,8 +606,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/Libraries/TypeSafety"
React:
:path: "../node_modules/react-native/"
React-bridging:
:path: "../node_modules/react-native/ReactCommon"
React-callinvoker:
:path: "../node_modules/react-native/ReactCommon/callinvoker"
React-Codegen:
@@ -638,6 +636,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-orientation-locker"
react-native-pager-view:
:path: "../node_modules/react-native-pager-view"
react-native-performance:
:path: "../node_modules/react-native-performance/ios"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
react-native-slider:
@@ -705,9 +705,9 @@ SPEC CHECKSUMS:
AppAuth: e48b432bb4ba88b10cb2bcc50d7f3af21e78b9c2
boost: a7c83b31436843459a1961bfd74b96033dc77234
CocoaLumberjack: b7e05132ff94f6ae4dfa9d5bce9141893a21d9da
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
FBLazyVector: 5c0975e66853436589eae7542f4b956c7e2ef465
FBReactNativeSpec: bb062293e84c33200005312d1807d8cb94a0d66a
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
FBLazyVector: 74b042924fe14da854ac4e87cefc417f583b22b1
FBReactNativeSpec: cc0037b9914b9b1d92a15f179bc3e2e2c7cc0c6f
Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d
FirebaseAnalytics: 7761cbadb00a717d8d0939363eb46041526474fa
FirebaseCore: 5743c5785c074a794d35f2fff7ecc254a91e08b1
@@ -716,59 +716,59 @@ SPEC CHECKSUMS:
FirebaseDynamicLinks: 1dc816ef789c5adac6fede0b46d11478175c70e4
FirebaseInstallations: 40bd9054049b2eae9a2c38ef1c3dd213df3605cd
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
Giphy: 6b5f6986c8df4f71e01a8ef86595f426b3439fb5
giphy-react-native-sdk: fcda9639f8ca2cc47e0517b6ef11c19359db5f5a
glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a
Giphy: b6d5087521d251bb8c99cdc0eb07bbdf86d142d5
giphy-react-native-sdk: 7abccf2b52123a0f30ce99da895ab6288023680c
glog: 476ee3e89abb49e07f822b48323c51c57124b572
GoogleAppMeasurement: 4c19f031220c72464d460c9daa1fb5d1acce958e
GoogleDataTransport: 8378d1fa8ac49753ea6ce70d65a7cb70ce5f66e6
GoogleSignIn: 5651ce3a61e56ca864160e79b484cd9ed3f49b7a
GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749
GTMAppAuth: 0ff230db599948a9ad7470ca667337803b3fc4dd
GTMSessionFetcher: 3a63d75eecd6aa32c2fc79f578064e1214dfdec2
JitsiWebRTC: 80f62908fcf2a1160e0d14b584323fb6e6be630b
JitsiWebRTC: 9619c1f71cc16eeca76df68aa2d213c6d63274a8
libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
ObjectiveDropboxOfficial: fe206ce8c0bc49976c249d472db7fdbc53ebbd53
PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef
PromisesSwift: cf9eb58666a43bbe007302226e510b16c1e10959
RCT-Folly: b9d9fe1fc70114b751c076104e52f3b1b5e5a95a
RCTRequired: 8e9a57dddc8f8e9e816c67c2d2537271a997137a
RCTTypeSafety: 2b19e268e2036a2c2f6db6deb1ac03e28b1d607a
React: f9478e6390f177ee6b67b87a3c6afea42b39523e
React-bridging: d405ecd3ff80e1d0a4059a11063eaa9ed7a00c58
React-callinvoker: c8ffa61f3f06f486ba6647769fc98f19e25d165a
React-Codegen: 73acfdac1495b91ad5efdd3ab005568263c5def6
React-Core: 7b7c75af4b73fe0ed4e5c3cdb7d79979e81148dc
React-CoreModules: cd6e7efb38162884f08c7afa16fffaf15ff28ae4
React-cxxreact: 51157cc600c9f436a7e623913a03b775305ef86c
React-jsi: 3eeb345c4828d7b132fd38064a305f31b46d4ec3
React-jsiexecutor: 5813455a4a908fb7284aa13307a9e0386e93b0bb
React-jsinspector: 9ca5bf73ed0a195397e45fdbcd507cf7d503c428
React-logger: 700340e325f21ba2a2d6413a61ef14268c7360aa
RCT-Folly: 4d8508a426467c48885f1151029bc15fa5d7b3b8
RCTRequired: 92cbd71369a2de6add25fd2403ac39838f1b694f
RCTTypeSafety: 494e8af41d7410ed0b877210859ee3984f37e6b4
React: 59989499c0e8926a90d34a9ae0bdb2d1b5b53406
React-callinvoker: 8187db1c71cf2c1c66e8f7328a0cf77a2b255d94
React-Codegen: e806dc2f10ddae645d855cb58acf73ce41eb8ea5
React-Core: fc7339b493e368ae079850a4721bdf716cf3dba2
React-CoreModules: 2f54f6bbf2764044379332089fcbdaf79197021e
React-cxxreact: ee119270006794976e1ab271f0111a5a88b16bcf
React-jsi: ec691b2a475d13b1fd39f697145a526eeeb6661c
React-jsiexecutor: b4ce4afc5dd9c8fdd2ac59049ccf420f288ecef7
React-jsinspector: e396d5e56af08fce39f50571726b68a40f1e302d
React-logger: cec52b3f8fb0be0d47b2cb75dec69de60f2de3b6
react-native-background-timer: 17ea5e06803401a379ebf1f20505b793ac44d0fe
react-native-get-random-values: 30b3f74ca34e30e2e480de48e4add2706a40ac8f
react-native-keep-awake: afad8a51dfef9fe9655a6344771be32c8596d774
react-native-netinfo: 27f287f2d191693f3b9d01a4273137fcf91c3b5d
react-native-orientation-locker: 851f6510d8046ea2f14aa169b1e01fcd309a94ba
react-native-pager-view: 3ee7d4c7697fb3ef788346e834a60cca97ed8540
react-native-performance: f4b6604a9d5a8a7407e34a82fab6c641d9a3ec12
react-native-safe-area-context: 99b24a0c5acd0d5dcac2b1a7f18c49ea317be99a
react-native-slider: 6e9b86e76cce4b9e35b3403193a6432ed07e0c81
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
react-native-video: bb6f12a7198db53b261fefb5d609dc77417acc8b
react-native-webrtc: 2702afae1e59882b423e6077768ca0d1e6fc42ed
react-native-webrtc: a9d4d8ef61adb634e006ffd956c494ad8318d95c
react-native-webview: ea4899a1056c782afa96dd082179a66cbebf5504
React-perflogger: fdee2a0c512167ae4c19c4e230ccf6aa66a6aff0
React-RCTActionSheet: 1cf5fef4e372f1c877969710a51bea4bb25e78fe
React-RCTAnimation: 73816e3acd1f5e3f00166fc7eedb34f6b112f734
React-RCTBlob: 6976c838fb14a1daf75d7c8bb23bae9cbbf726bb
React-RCTImage: ab8a7498f215117f32271698591e4bd932dcf812
React-RCTLinking: e8e78aed2744ab9946cc8ba5716b4938c2efb1e0
React-RCTNetwork: 796f5aed4d932655d292bdc6b40f9502dcdb9542
React-RCTSettings: 7e1cd2a384b45c90caf67464572abe3833b9da3b
React-RCTText: fd6162890828f0761e03c59058fa23c3a21b2e10
React-RCTVibration: 302cfd5cc33669d7abdb7ec6790123baba66e62e
React-runtimeexecutor: 59407514818b2afbb1d7507e4e1ac834d24b0fbd
ReactCommon: b8487da74723562d7368dab27135fd182f00a91c
React-perflogger: 46620fc6d1c3157b60ed28434e08f7fd7f3f3353
React-RCTActionSheet: b1f7e72a0ba760ec684df335c61f730b5179f5ff
React-RCTAnimation: d73b62d42867ab608dfb10e100d8b91106275b18
React-RCTBlob: b5f59693721d50967c35598158e6ca01b474c7de
React-RCTImage: 37cf34d0c2fbef2e0278d42a7c5e8ea06a9fed6b
React-RCTLinking: a11dced20019cf1c2ec7fd120f18b08f2851f79e
React-RCTNetwork: ba097188e5eac42e070029e7cedd9b978940833a
React-RCTSettings: 147073708a1c1bde521cf3af045a675682772726
React-RCTText: 23f76ebfb2717d181476432e5ecf1c6c4a104c5e
React-RCTVibration: be5f18ffc644f96f904e0e673ab639ca5d673ee8
React-runtimeexecutor: d5498cfb7059bf8397b6416db4777843f3f4c1e7
ReactCommon: 1974dab5108c79b40199f12a4833d2499b9f6303
RNCalendarEvents: 7e65eb4a94f53c1744d1e275f7fafcfaa619f7a3
RNCAsyncStorage: 005c0e2f09575360f142d0d1f1f15e4ec575b1af
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
@@ -780,8 +780,8 @@ SPEC CHECKSUMS:
RNSound: 27e8268bdb0a1f191f219a33267f7e0445e8d62f
RNSVG: f3b60aeeaa81960e2e0536c3a9eef50b667ef3a9
RNWatch: dae6c858a2051dbdcfb00b9a86cf4d90400263b4
Yoga: 7f5ad94937ba3fc58c151ad1b7bbada2c275b28e
Yoga: 7929b92b1828675c1bebeb114dae8cb8fa7ef6a3
PODFILE CHECKSUM: e3579df5272b8b697c9fdc0e55aa0845b189c4dd
PODFILE CHECKSUM: d9116cb59cd7e921956e45de7cbbd75bef3862c1
COCOAPODS: 1.12.1
COCOAPODS: 1.11.3

View File

@@ -439,7 +439,7 @@
};
};
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "app" */;
compatibilityVersion = "Xcode 12.0";
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@@ -1025,10 +1025,9 @@
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
);
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
@@ -1079,9 +1078,8 @@
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
);
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
TARGETED_DEVICE_FAMILY = "1,2";

View File

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

View File

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

View File

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

View File

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

View File

@@ -98,6 +98,7 @@ platform :ios do
demo_account_required: false,
distribute_external: true,
groups: ENV["JITSI_BETA_TESTING_GROUPS"],
reject_build_waiting_for_review: true,
uses_non_exempt_encryption: false
)

View File

@@ -472,7 +472,7 @@
};
};
buildConfigurationList = 0BD906DF1EC0C00300C8C18E /* Build configuration list for PBXProject "sdk" */;
compatibilityVersion = "Xcode 12.0";
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@@ -526,7 +526,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "WITH_ENVIRONMENT=\"../../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
shellScript = "export NODE_BINARY=node\nexport NODE_ARGS=\"--max_old_space_size=4096\"\n../../node_modules/react-native/scripts/react-native-xcode.sh\n";
};
26796D8589142D80C8AFDA51 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
@@ -551,12 +551,17 @@
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-JitsiMeetSDK/Pods-JitsiMeetSDK-resources-${CONFIGURATION}-input-files.xcfilelist",
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-JitsiMeetSDK/Pods-JitsiMeetSDK-resources.sh",
"${PODS_ROOT}/Amplitude/Sources/Resources/ComodoRsaDomainValidationCA.der",
"${PODS_CONFIGURATION_BUILD_DIR}/GoogleSignIn/GoogleSignIn.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-JitsiMeetSDK/Pods-JitsiMeetSDK-resources-${CONFIGURATION}-output-files.xcfilelist",
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ComodoRsaDomainValidationCA.der",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@@ -636,12 +641,15 @@
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-JitsiMeetSDKLite/Pods-JitsiMeetSDKLite-resources-${CONFIGURATION}-input-files.xcfilelist",
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-JitsiMeetSDKLite/Pods-JitsiMeetSDKLite-resources.sh",
"${PODS_ROOT}/Amplitude/Sources/Resources/ComodoRsaDomainValidationCA.der",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-JitsiMeetSDKLite/Pods-JitsiMeetSDKLite-resources-${CONFIGURATION}-output-files.xcfilelist",
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ComodoRsaDomainValidationCA.der",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@@ -773,10 +781,9 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
@@ -830,9 +837,8 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
TARGETED_DEVICE_FAMILY = "1,2";

View File

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

View File

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

View File

@@ -39,18 +39,6 @@
"audioOnly": {
"audioOnly": "Geringe Bandbreite"
},
"bandwidthSettings": {
"assumedBandwidthBps": "z.B. 10000000 für 10 Mbps",
"assumedBandwidthBpsWarning": "Höhere Werte können zu Netzwerk-Problemen führen.",
"customValue": "spezifischer Wert",
"customValueEffect": "setzt den Wert in bps",
"leaveEmpty": "leer lassen",
"leaveEmptyEffect": "aktiviert die automatische Abschätzung",
"possibleValues": "Mögliche Werte",
"setAssumedBandwidthBps": "Angenommene Bandbreite (bps)",
"title": "Einstellungen Bandbreite",
"zeroEffect": "schaltet Video aus"
},
"breakoutRooms": {
"actions": {
"add": "Breakout-Raum hinzufügen",
@@ -168,7 +156,6 @@
"localport_plural": "Lokale Ports:",
"maxEnabledResolution": "max. senden",
"more": "Mehr anzeigen",
"no": "Nein",
"packetloss": "Paketverlust:",
"participant_id": "Personen-ID:",
"quality": {
@@ -187,8 +174,7 @@
"status": "Verbindung:",
"transport": "Protokoll:",
"transport_plural": "Protokolle:",
"video_ssrc": "Video-SSRC:",
"yes": "Ja"
"video_ssrc": "Video-SSRC:"
},
"dateUtils": {
"earlier": "Früher",
@@ -687,7 +673,6 @@
"connectedTwoMembers": "{{first}} und {{second}} nehmen am Meeting teil",
"dataChannelClosed": "Schlechte Videoqualität",
"dataChannelClosedDescription": "Die Steuerungsverbindung (Bridge Channel) wurde unterbrochen, daher ist die Videoqulität auf die schlechteste Stufe limitiert.",
"disabledIframe": "Die Einbettung ist nur für Demo-Zwecke vorgesehen. Diese Konferenz wird in {{timeout}} Minuten beendet.",
"disconnected": "getrennt",
"displayNotifications": "Benachrichtigungen anzeigen für",
"dontRemindMe": "Nicht erinnern",
@@ -882,11 +867,9 @@
"lookGood": "Ihr Mikrofon scheint zu funktionieren.",
"or": "oder",
"premeeting": "Vorschau",
"proceedAnyway": "Trotzdem fortsetzen",
"screenSharingError": "Fehler bei Bildschirmfreigabe:",
"showScreen": "Konferenzvorschau aktivieren",
"startWithPhone": "Mit Telefonaudio starten",
"unsafeRoomConsent": "Ich verstehe das Risiko und möchte der Konferenz beitreten",
"videoOnlyError": "Videofehler:",
"videoTrackError": "Videotrack konnte nicht erstellt werden.",
"viewAllNumbers": "alle Nummern anzeigen"
@@ -988,14 +971,8 @@
"security": {
"about": "Sie können Ihre Konferenz mit einem Passwort sichern. Teilnehmer müssen dieses eingeben, bevor sie an der Sitzung teilnehmen dürfen.",
"aboutReadOnly": "Mit Moderationsrechten kann die Konferenz mit einem Passwort gesichert werden. Personen müssen dieses eingeben, bevor sie an der Sitzung teilnehmen dürfen.",
"insecureRoomNameWarningNative": "Der Raumname ist unsicher. Unerwünschte Teilnehmer könnten Ihrer Konferenz beitreten. {{recommendAction}} Lernen Sie mehr über die Absicherung Ihrer Konferenz ",
"insecureRoomNameWarningWeb": "Der Raumname ist unsicher. Unerwünschte Teilnehmer könnten Ihrer Konferenz beitreten {{recommendAction}} Lernen Sie <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">hier</a> mehr über die Absicherung Ihrer Konferenz.",
"title": "Sicherheitsoptionen",
"unsafeRoomActions": {
"meeting": "Erwägen Sie die Absicherung Ihrer Konferenz über den Sicherheits-Button.",
"prejoin": "Erwägen Sie einen einzigartigeren Raumnamen zu wählen.",
"welcome": "Erwägen Sie einen einzigartigeren Raumnamen zu wählen oder wählen Sie einen der Vorschläge."
}
"insecureRoomNameWarning": "Der Raumname ist unsicher. Unerwünschte Teilnehmer könnten Ihrer Konferenz beitreten",
"title": "Sicherheitsoptionen"
},
"settings": {
"audio": "Audio",
@@ -1163,7 +1140,6 @@
"muteEveryoneElse": "Alle anderen stummschalten",
"muteEveryoneElsesVideoStream": "Alle anderen Kameras ausschalten",
"muteEveryonesVideoStream": "Alle Kameras ausschalten",
"muteGUMPending": "Verbinde Ihr Mikrofon",
"noiseSuppression": "Rauschunterdrückung",
"openChat": "Chat öffnen",
"participants": "Anwesende",
@@ -1171,7 +1147,6 @@
"privateMessage": "Private Nachricht senden",
"profile": "Profil bearbeiten",
"raiseHand": "Hand heben",
"reactions": "Interaktionen",
"reactionsMenu": "Interaktionsmenü öffnen / schließen",
"recording": "Aufzeichnung ein-/ausschalten",
"remoteMute": "Personen stummschalten",
@@ -1197,7 +1172,6 @@
"unmute": "Stummschaltung aufheben",
"videoblur": "Unscharfer Hintergrund ein-/ausschalten",
"videomute": "„Video stummschalten“ ein-/ausschalten",
"videomuteGUMPending": "Verbinde Ihre Kamera",
"videounmute": "Kamera einschalten"
},
"addPeople": "Personen zur Konferenz hinzufügen",
@@ -1248,7 +1222,6 @@
"mute": "Stummschalten",
"muteEveryone": "Alle stummschalten",
"muteEveryonesVideo": "Alle Kameras ausschalten",
"muteGUMPending": "Verbinde Ihre Kamera",
"noAudioSignalDesc": "Wenn Sie das Gerät nicht absichtlich über die Systemeinstellungen oder die Hardware stumm geschaltet haben, sollten Sie einen Wechsel des Geräts in Erwägung ziehen.",
"noAudioSignalDescSuggestion": "Wenn Sie das Gerät nicht absichtlich über die Systemeinstellungen oder die Hardware stummgeschaltet haben, sollten Sie einen Wechsel auf das vorgeschlagene Gerät in Erwägung ziehen.",
"noAudioSignalDialInDesc": "Sie können sich auch über die Einwahlnummer einwählen:",
@@ -1271,7 +1244,6 @@
"reactionLike": "Daumen hoch senden",
"reactionSilence": "Stille senden",
"reactionSurprised": "Überrascht senden",
"reactions": "Interaktionen",
"security": "Sicherheitsoptionen",
"selectBackground": "Hintergrund auswählen",
"shareRoom": "Person einladen",
@@ -1294,7 +1266,6 @@
"unmute": "Stummschaltung aufheben",
"videoSettings": "Kameraeinstellungen",
"videomute": "Kamera stoppen",
"videomuteGUMPending": "Verbinde Ihre Kamera",
"videounmute": "Kamera einschalten"
},
"transcribing": {
@@ -1406,14 +1377,7 @@
"webAssemblyWarning": "WebAssembly wird nicht unterstützt",
"webAssemblyWarningDescription": "WebAssembly ist deaktiviert oder wird in diesem Browser nicht unterstützt"
},
"visitors": {
"chatIndicator": "(Gast)",
"labelTooltip": "Anzahl Gäste: {{count}}",
"notification": {
"description": "Bitte melden Sie sich um teilzunehmen",
"title": "Sie sind Gast in der Konferenz"
}
},
"visitorsLabel": "Anzahl Gäste: {{count}}",
"volumeSlider": "Lautstärkeregler",
"welcomepage": {
"accessibilityLabel": {

View File

@@ -11,6 +11,7 @@
"defaultEmail": "Dirección de correo por defecto",
"disabled": "No puede invitar a otras personas.",
"failedToAdd": "Error al agregar participantes",
"footerText": "La marcación está desactivada.",
"googleEmail": "Correo electrónico de Google",
"inviteMoreHeader": "Usted se encuentra solo en la reunión",
"inviteMoreMailSubject": "Unirse a la reunión {{appName}}",
@@ -30,7 +31,6 @@
},
"audioDevices": {
"bluetooth": "Bluetooth",
"car": "Audio de automóvil",
"headphones": "Auriculares",
"none": "No hay dispositivos de audio disponibles",
"phone": "Teléfono",
@@ -39,37 +39,6 @@
"audioOnly": {
"audioOnly": "Solo sonido y pantalla compartida"
},
"bandwidthSettings": {
"assumedBandwidthBps": "por ejemplo 10000000 para 10 Mbps",
"assumedBandwidthBpsWarning": "Valores más altos podrían causar problemas de red.",
"customValue": "valor personalizado",
"customValueEffect": "para establecer el valor real de bps",
"leaveEmpty": "dejar vacío",
"leaveEmptyEffect": "para permitir que se realicen estimaciones",
"possibleValues": "Valores posibles",
"setAssumedBandwidthBps": "Ancho de banda asumido (bps)",
"title": "Ajustes de ancho de banda",
"zeroEffect": "para deshabilitar el video"
},
"breakoutRooms": {
"actions": {
"add": "Agregar sala para grupos pequeños",
"autoAssign": "Autoasignar a sala para grupos pequeños",
"close": "Cerrar",
"join": "Unirse",
"leaveBreakoutRoom": "Abandonar sala para grupos pequeños",
"more": "Más",
"remove": "Quitar",
"sendToBreakoutRoom": "Enviar participante a:"
},
"defaultName": "Sala para grupos pequeños #{{index}}",
"mainRoom": "Sala principal",
"notifications": {
"joined": "Uniéndose a la sala para grupos pequeños \"{{name}}\"",
"joinedMainRoom": "Uniéndose a la sala principal",
"joinedTitle": "Salas para grupos pequeños"
}
},
"calendarSync": {
"addMeetingURL": "Agregar un vínculo a la reunión",
"confirmAddLink": "¿Quiere añadir un enlace de Jitsi a este evento?",
@@ -88,27 +57,15 @@
"refresh": "Actualizar calendario",
"today": "Hoy"
},
"carmode": {
"actions": {
"selectSoundDevice": "Elija un dispositivo de sonido"
},
"labels": {
"buttonLabel": "Modo automóvil",
"title": "Modo automóvil",
"videoStopped": "Su video se ha detenido"
}
},
"chat": {
"enter": "Entrar en la sala",
"error": "Error: su mensaje no se envío. Motivo: {{error}}",
"fieldPlaceHolder": "Escriba su mensaje aquí",
"lobbyChatMessageTo": "Mensaje de chat de lobby a {{recipient}}",
"message": "Mensaje",
"messageAccessibleTitle": "{{user}} dice:",
"messageAccessibleTitleMe": "yo digo:",
"messageTo": "Mensaje privado para {{recipient}}",
"messagebox": "Escriba un mensaje",
"newMessages": "Mensajes nuevos",
"nickname": {
"popover": "Selecciona un apodo",
"title": "Introduce un apodo para usar el chat",
@@ -128,7 +85,6 @@
},
"chromeExtensionBanner": {
"buttonText": "Instalar extensión de Chrome",
"buttonTextEdge": "Instalar extensión de Edge",
"close": "Cerrar",
"dontShowAgain": "No mostrar nuevamente",
"installExtensionText": "Instalar la extensión para Google Calendar y la integración con Office 365"
@@ -159,7 +115,6 @@
"bridgeCount": "Contador del servidor: ",
"codecs": "Codecs (A/V):",
"connectedTo": "Conectado a:",
"e2eeVerified": "",
"framerate": "Fotogramas por segundo:",
"less": "Mostrar menos",
"localaddress": "Dirección local:",
@@ -168,7 +123,6 @@
"localport_plural": "Puertos locales:",
"maxEnabledResolution": "enviar max",
"more": "Mostrar más",
"no": "no",
"packetloss": "Pérdida de paquetes:",
"participant_id": "ID participante:",
"quality": {
@@ -187,8 +141,7 @@
"status": "Calidad:",
"transport": "Transporte:",
"transport_plural": "Transportes:",
"video_ssrc": "Video SSRC:",
"yes": "sí"
"video_ssrc": "Video SSRC:"
},
"dateUtils": {
"earlier": "Anterior",
@@ -197,24 +150,15 @@
},
"deepLinking": {
"appNotInstalled": "Necesitas la aplicación {{app}} para unirte a esta reunión en el teléfono.",
"description": "¿No pasó nada? Intentamos iniciar la reunión en la aplicación de escritorio {{app}}. Intenta de nuevo o inicia en la aplicación web {{app}}.",
"descriptionNew": "¿No pasó nada? Intentamos iniciar la reunión en la aplicación de escritorio {{app}}. <br /><br /> Puedes volver a intentarlo o iniciar en la aplicación web.",
"description": "¿No pasó nada? Hemos intentado iniciar la reunión en la aplicación de escritorio {{app}}. Intenta de nuevo o inicia en la aplicación web {{app}}.",
"descriptionWithoutWeb": "¿No pasó nada? Intentamos iniciar su reunión en la aplicación de escritorio {{app}}.",
"downloadApp": "Descargar la app",
"downloadMobileApp": "",
"ifDoNotHaveApp": "Si aún no tienes la app:",
"ifHaveApp": "Si ya tienes la app:",
"joinInApp": "Unirse a la reunion usando la app",
"joinInAppNew": "Unirse en la app",
"joinInBrowser": "Unirse en el navegador",
"launchMeetingLabel": "¿Cómo quieres unirte a la reunión?",
"launchWebButton": "Iniciar en el navegador",
"noMobileApp": "¿No tienes la aplicación?",
"termsAndConditions": "Al continuar aceptas nuestros <a href='{{termsAndConditionsLink}}' rel='noopener noreferrer' target='_blank'>términos y condiciones.</a>",
"title": "Iniciando la reunión en {{app}}…",
"titleNew": "Iniciando la reunión.",
"tryAgainButton": "Intentar de nuevo en el escritorio",
"unsupportedBrowser": "Parece que estás usando un navegador para el que no tenemos soporte."
"tryAgainButton": "Intentar de nuevo en el escritorio"
},
"defaultLink": "ej. {{url}}",
"defaultNickname": "ej. Juan Pérez",
@@ -225,20 +169,11 @@
"microphonePermission": "Error al obtener permiso del micrófono"
},
"deviceSelection": {
"hid": {
"callControl": "Control de llamadas",
"connectedDevices": "Dispositivos conectados:",
"deleteDevice": "Eliminar dispositivo",
"pairDevice": "Emparejar dispositivo"
},
"noPermission": "Permiso no concedido",
"previewUnavailable": "Vista previa no disponible",
"selectADevice": "Seleccionar un dispositivo",
"testAudio": "Reproducir un sonido de prueba"
},
"dialIn": {
"screenTitle": ""
},
"dialOut": {
"statusMessage": "está {{status}}"
},
@@ -254,13 +189,9 @@
"WaitingForHostTitle": "Esperando al anfitrión...",
"Yes": "Sí",
"accessibilityLabel": {
"close": "Cerrar diálogo",
"liveStreaming": "Transmisión en vivo",
"sharingTabs": "Opciones para compartir"
"liveStreaming": "Transmisión en vivo"
},
"add": "Agregar",
"addMeetingNote": "Agrega una nota acerca de esta reunión",
"addOptionalNote": "Agrega una nota (opcional):",
"allow": "Permitir",
"alreadySharedVideoMsg": "Otro participante ya está compartiendo un vídeo. Esta conferencia sólo permite compartir un vídeo a la vez.",
"alreadySharedVideoTitle": "Solo se permite un vídeo compartido a la vez",
@@ -302,7 +233,6 @@
"gracefulShutdown": "Nuestro servicio se encuentra en mantenimiento. Por favor, intente más tarde.",
"grantModeratorDialog": "¿Estás seguro de que quieres convertir a este participante en moderador?",
"grantModeratorTitle": "Convertir en moderador",
"hide": "Esconder",
"hideShareAudioHelper": "No volver a mostrar este diálogo",
"incorrectPassword": "Nombre de usuario o contraseña incorrecta",
"incorrectRoomLockPassword": "Contraseña incorrecta",
@@ -313,10 +243,9 @@
"kickParticipantDialog": "¿Seguro que quiere expulsar a este participante?",
"kickParticipantTitle": "¿Expulsar a este participante?",
"kickTitle": "¡Ay! {{participantDisplayName}} te expulsó de la reunión",
"linkMeeting": "",
"linkMeetingTitle": "",
"liveStreaming": "Transmisión en vivo",
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "No es posible mientras la grabación este activa",
"liveStreamingDisabledTooltip": "Las trasmisiones están deshabilitadas.",
"localUserControls": "Controles de usuario locales",
"lockMessage": "No se pudo bloquear la conferencia.",
"lockRoom": "Agregar $t(lockRoomPasswordUppercase) a la reunión",
@@ -350,11 +279,11 @@
"muteEveryonesVideoTitle": "¿Detener el vídeo de todos?",
"muteParticipantBody": "No podrás quitarles el modo en silencio, pero ellos pueden quitárselo en cualquier momento.",
"muteParticipantButton": "Silenciar",
"muteParticipantDialog": "¿Seguro que quieres silenciar a este participante? No podrás revertir esta acción, pero el participante podrá hacerlo en cualquier momento",
"muteParticipantTitle": "¿Silenciar a este participante?",
"muteParticipantsVideoBody": "No podrás volver a encender la cámara, pero ellos pueden volver a encenderla en cualquier momento.",
"muteParticipantsVideoBodyModerationOn": "",
"muteParticipantsVideoButton": "Detener video",
"muteParticipantsVideoDialog": "¿Estás seguro de que quieres apagar la cámara de este participante? No podrás volver a encender la cámara, pero ellos pueden volver a encenderla en cualquier momento.",
"muteParticipantsVideoDialogModerationOn": "",
"muteParticipantsVideoTitle": "¿Desactivar la cámara de este participante?",
"noDropboxToken": "No hay un token válido de Dropbox",
"password": "Contraseña",
@@ -368,9 +297,9 @@
"popupError": "Su navegador está bloqueando las ventanas emergentes de este sitio. Habilite las ventanas emergentes en la configuración de seguridad de su navegador y vuelva a intentarlo.",
"popupErrorTitle": "Ventana emergente bloqueada",
"readMore": "más",
"recentlyUsedObjects": "Tus objetos usados recientemente",
"recording": "Grabando",
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "No es posible mientras la transmisión en vivo este activa",
"recordingDisabledTooltip": "Inicio de grabación desactivado.",
"rejoinNow": "Reunirse ahora",
"remoteControlAllowedMessage": "¡{{user}} ha aceptado tu solicitud de control remoto!",
"remoteControlDeniedMessage": "¡{{user}} ha rechazado tu solicitud de control remoto!",
@@ -390,12 +319,6 @@
"screenSharingFailed": "¡Ups! ¡Algo salió mal, no se pudo iniciar la compartición de su pantalla!",
"screenSharingFailedTitle": "¡Fallo al compartir su pantalla!",
"screenSharingPermissionDeniedError": "¡Uy! Algo salió mal con tus permisos de extensión para compartir pantalla. Vuelve a cargar la página e intenta de nuevo.",
"searchInSalesforce": "Buscar en Salesforce",
"searchResults": "Resultados de búsqueda({{count}}",
"searchResultsDetailsError": "",
"searchResultsError": "Hubo un error recuperando los datos.",
"searchResultsNotFound": "No se encontraron resultados.",
"searchResultsTryAgain": "Vuelve a intentar usando palabras clave alternativas",
"sendPrivateMessage": "Acabas de recibir un mensaje privado. ¿Deseas responder en privado o a todos?",
"sendPrivateMessageCancel": "Enviar al grupo",
"sendPrivateMessageOk": "Enviar en privado",
@@ -418,10 +341,7 @@
"shareVideoTitle": "Compartir un vídeo",
"shareYourScreen": "Compartir pantalla",
"shareYourScreenDisabled": "Se desactivó la opción para compartir pantalla.",
"sharedVideoDialogError": "Error: URL inválido",
"sharedVideoLinkPlaceholder": "Enlace de YouTube o enlace de vídeo directo",
"show": "Mostrar",
"start": "Iniciar",
"startLiveStreaming": "Iniciar transmisión en vivo",
"startRecording": "Iniciar grabación",
"startRemoteControlErrorMessage": "Se produjo un error al intentar iniciar la sesión de control remoto.",
@@ -439,10 +359,6 @@
"user": "Usuario",
"userIdentifier": "Identificador de usuario",
"userPassword": "contraseña del usuario",
"verifyParticipantConfirm": "",
"verifyParticipantDismiss": "",
"verifyParticipantQuestion": "",
"verifyParticipantTitle": "Verificación de usuario",
"videoLink": "Enlace de vídeo",
"viewUpgradeOptions": "Ver opciones de mejora",
"viewUpgradeOptionsContent": "Para obtener acceso ilimitado a las funciones premium, como la grabación, las transcripciones, el streaming RTMP y otras, tendrás que actualizar tu plan.",
@@ -468,14 +384,8 @@
"veryBad": "Muy mala",
"veryGood": "Muy buena"
},
"filmstrip": {
"accessibilityLabel": {
"heading": "Miniaturas de video"
}
},
"giphy": {
"noResults": "No se encontraron resultados :(",
"search": "Busca en GIPHY"
"helpView": {
"title": "Centro de ayuda"
},
"incomingCall": {
"answer": "Contestar",
@@ -517,11 +427,9 @@
"noRoom": "No se especificó la sala a marcar.",
"numbers": "Números para entrar por llamada telefónica:",
"password": "$t(lockRoomPasswordUppercase):",
"reachedLimit": "Alcanzaste el límite de tu plan.",
"sip": "Dirección SIP",
"title": "Compartir",
"tooltip": "Compartir el enlace y acceso telefónico para esta reunión",
"upgradeOptions": "Por favor revisa las opciones de mejora en"
"tooltip": "Compartir el enlace y acceso telefónico para esta reunión"
},
"inlineDialogFailure": {
"msg": "Tuvimos un pequeño tropiezo.",
@@ -542,7 +450,6 @@
"focusLocal": "Ver tu cámara",
"focusRemote": "Ver la cámara de otras personas",
"fullScreen": "Entrar o salir de pantalla completa",
"giphyMenu": "Alternar menú GIPHY",
"keyboardShortcuts": "Atajos de teclado",
"localRecording": "Mostrar u ocultar controles de grabación local",
"mute": "Activar o silenciar el micrófono",
@@ -556,10 +463,6 @@
"toggleShortcuts": "Mostrar u ocultar atajos del teclado",
"videoMute": "Encender o apagar la cámara"
},
"largeVideo": {
"screenIsShared": "Estás compartiendo tu pantalla",
"showMeWhatImSharing": "Muéstrame qué estoy compartiendo"
},
"liveStreaming": {
"busy": "Nuestros servidores andan un poco ocupados. Vuelve a intentarlo en unos minutos.",
"busyTitle": "Todos los transmisores están ocupados",
@@ -576,7 +479,6 @@
"failedToStart": "La transmisión en vivo no se pudo iniciar",
"getStreamKeyManually": "No pudimos encontrar tu clave de transmisión. Por favor, obtenla de la página de YouTube y pégala.",
"googlePrivacyPolicy": "Política de Privacidad de Google",
"inProgress": "Grabación o transmisión en vivo en curso",
"invalidStreamKey": "Es posible que la clave de transmisión sea incorrecta, o no es de YouTube.",
"limitNotificationDescriptionNative": "Su transmisión estará limitada a {{limit}} minutos. Puede obtener transmisiones ilimitadas en {{app}}.",
"limitNotificationDescriptionWeb": "Debido a la alta demanda su transmisión estará limitada a {{limit}} minutos. Puede obtener transmisiones ilimitadas en <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
@@ -586,7 +488,6 @@
"onBy": "{{name}} inició la transmisión en vivo",
"pending": "Iniciando transmisión en vivo…",
"serviceName": "Servicio de transmisión en vivo",
"sessionAlreadyActive": "Esta sesión ya está siendo grabada o transmitida en vivo.",
"signIn": "Iniciar sesión con Google",
"signInCTA": "Para transmitir a YouTube, inicia sesión o introduce la clave de transmisión. Para transmitir a otro lugar, introduce el URL (que empieza en rtmp), seguido de la clave de transmisión. Debe haber una diagonal (/) entre ambos.",
"signOut": "Cerrar sesión",
@@ -600,8 +501,8 @@
"lobby": {
"admit": "Admitir",
"admitAll": "Admitir todo",
"allow": "permitir",
"backToKnockModeButton": "No hay contraseña, pide permiso para entrar.",
"chat": "Chat",
"dialogTitle": "Sala de espera",
"disableDialogContent": "Sala de espera activada. Así no entrarán intrusos. ¿Quieres desactivarla?",
"disableDialogSubmit": "Desactivar",
@@ -614,7 +515,6 @@
"errorMissingPassword": "Por favor, introduzca la contraseña de la reunión",
"invalidPassword": "Contraseña inválida",
"joinRejectedMessage": "Tu solicitud para entrar ha sido rechazada por un moderador.",
"joinRejectedTitle": "Solicitud para entrar rechazada.",
"joinTitle": "Entrar a la reunión",
"joinWithPasswordMessage": "Tratando de entrar con contraseña, por favor espera...",
"joiningMessage": "Podrás entrar tan pronto te acepten tu solicitud.",
@@ -623,8 +523,6 @@
"knockButton": "Pedir entrar",
"knockTitle": "Alguien quiere entrar a la reunión",
"knockingParticipantList": "Participantes que quieren entrar",
"lobbyChatStartedNotification": "{{moderator}} inició un chat de lobby con {{attendee}}",
"lobbyChatStartedTitle": "{{moderator}} inició un chat de lobby contigo.",
"nameField": "Introduce tu nombre",
"notificationLobbyAccessDenied": "{{originParticipantName}} no dejó entrar a {{targetParticipantName}}",
"notificationLobbyAccessGranted": "{{originParticipantName}} permitió entrar a {{targetParticipantName}}",
@@ -662,7 +560,6 @@
"no": "No",
"participant": "Participante",
"participantStats": "Estadística de participantes",
"selectTabTitle": "🎥 Por favor seleccione esta pestaña para grabar",
"sessionToken": "Token de sesión",
"start": "Iniciar grabación",
"stop": "Detener grabación",
@@ -679,39 +576,18 @@
"OldElectronAPPTitle": "¡Aplicación obsoleta e insegura!",
"allowAction": "Permitir",
"allowedUnmute": "Puedes anular el silencio del micrófono, iniciar la cámara o compartir la pantalla.",
"audioUnmuteBlockedDescription": "La operación de activación del micrófono ha sido bloqueada temporalmente debido a límites del sistema.",
"audioUnmuteBlockedTitle": "¡Activación del micrófono bloqueado!",
"chatMessages": "Mensajes del chat",
"connectedOneMember": "{{name}} se unió a la reunión",
"connectedThreePlusMembers": "{{name}} y {{count}} más se unieron a la reunión",
"connectedTwoMembers": "{{first}} y {{second}} se unieron a la reunión",
"dataChannelClosed": "",
"dataChannelClosedDescription": "",
"disabledIframe": "",
"disconnected": "desconectado",
"displayNotifications": "Mostrar notificaciones para",
"dontRemindMe": "No me lo recuerdes",
"focus": "Enfocar conferencia",
"focusFail": "{{component}} no disponible. Vuelve a intentar en {{ms}} segundos",
"gifsMenu": "GIPHY",
"groupTitle": "Notificaciones",
"hostAskedUnmute": "El moderador quiere que hables",
"invitedOneMember": "{{name}} ha sido invitado",
"invitedThreePlusMembers": "{{name}} y {{count}} más han sido invitados",
"invitedTwoMembers": "{{first}} y {{second}} han sido invitados",
"joinMeeting": "Unirse",
"kickParticipant": "{{kicker}} sacó a {{kicked}}",
"leftOneMember": "{{name}} abandonó la reunión",
"leftThreePlusMembers": "{{name}} y muchos otros abandonaron la reunión",
"leftTwoMembers": "{{first}} y {{second}} abandonaron la reunión",
"linkToSalesforce": "Enlace a Salesforce",
"linkToSalesforceDescription": "Puedes vincular el resumen de la reunión a un objeto Salesforce",
"linkToSalesforceError": "Error al vincular la reunión a Salesforce",
"linkToSalesforceKey": "",
"linkToSalesforceProgress": "Vinculando reunión a Salesorce...",
"linkToSalesforceSuccess": "La reunión fue vinculada a Salesforce",
"localRecordingStarted": "{{name}} ha iniciado una grabación local.",
"localRecordingStopped": "{{name}} ha detenido una grabación local.",
"me": "Yo",
"moderationInEffectCSDescription": "Por favor, levante la mano si quiere compartir su pantalla.",
"moderationInEffectCSTitle": "La pantalla compartida está bloqueada por el moderador",
@@ -732,27 +608,16 @@
"newDeviceAction": "Usar",
"newDeviceAudioTitle": "Se detectó un dispositivo de audio nuevo",
"newDeviceCameraTitle": "Se detectó una cámara nueva",
"noiseSuppressionDesktopAudioDescription": "La supresión de ruido no puede ser habilitada mientras comparte audio del escritorio, por favor deshabilítelo y vuelva a intentar.",
"noiseSuppressionFailedTitle": "Error al activar la supresión de ruido",
"noiseSuppressionNoTrackDescription": "Por favor active su micrófono primero.",
"noiseSuppressionStereoDescription": "La supresión de ruido en audio estéreo no tiene soporte actualmente",
"oldElectronClientDescription1": "Estás usando una versión vieja de la aplicación de Jitsi Meet que tiene problemas de seguridad. ¡Por favor, actualiza a la ",
"oldElectronClientDescription2": "versión más reciente",
"oldElectronClientDescription3": " YA!",
"participantWantsToJoin": "Quiere unirse a la reunión",
"participantsWantToJoin": "Quieren unirse a la reunión",
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) eliminada por otro participante",
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) agregada por otro participante",
"raiseHandAction": "Levantar la mano",
"raisedHand": "{{name}} quisiera hablar.",
"raisedHands": "",
"reactionSounds": "Desactivar sonidos",
"reactionSoundsForAll": "Desactivar sonidos para todos",
"screenShareNoAudio": "La casilla Compartir audio no estaba marcada en la pantalla de selección de ventanas.",
"screenShareNoAudioTitle": "No se pudo compartir el audio del sistema.",
"screenSharingAudioOnlyDescription": "Por favor tenga en cuenta que al compartir si pantalla está afectando el modo \"Mejor rendimiento\" y usará más ancho de banda",
"screenSharingAudioOnlyTitle": "Modo \"Mejor rendimiento\"",
"selfViewTitle": "Siempre puedes reactivar la vista propia en los ajustes",
"somebody": "Alguien",
"startSilentDescription": "Vuelve a ingresar para activar el audio",
"startSilentTitle": "¡Te uniste sin audio!",
@@ -760,11 +625,7 @@
"suboptimalExperienceTitle": "¡Tu navegador no es compatible!",
"unmute": "Reactivar micrófono",
"videoMutedRemotelyDescription": "Siempre puedes volver a encenderlo.",
"videoMutedRemotelyTitle": "Su vídeo ha sido desactivado por {{moderator}}",
"videoUnmuteBlockedDescription": "Las operaciones de desactivar la cámara y compartir pantalla hansido bloqueadas temporalmente debido a límites del sistema.",
"videoUnmuteBlockedTitle": "¡Desactivar cámara y compartir pantalla bloqueados!",
"viewLobby": "Ver lobby",
"waitingParticipants": "{{waitingParticipants}} personas"
"videoMutedRemotelyTitle": "Su vídeo ha sido desactivado por {{moderator}}"
},
"participantsPane": {
"actions": {
@@ -774,9 +635,6 @@
"audioModeration": "Desmutearse a sí mismos",
"blockEveryoneMicCamera": "Bloquear el micrófono y la cámara de todos.",
"invite": "Invitar a alguien",
"moreModerationActions": "Más opciones de moderación",
"moreModerationControls": "Más controles de moderación",
"moreParticipantOptions": "Más opciones de participantes",
"mute": "Silenciar",
"muteAll": "Silenciar a todos los demás",
"muteEveryoneElse": "Silenciar al resto",
@@ -789,22 +647,17 @@
"headings": {
"lobby": "Vestíbulo ({{count}})",
"participantsList": "Participantes en la reunión ({{count}})",
"visitors": "Visitantes ({{count}})",
"waitingLobby": "Esperando en el vestíbulo ({{count}})"
},
"search": "Buscar participantes",
"title": "Participantes"
},
"passwordDigitsOnly": "Hasta {{number}} cifras",
"passwordSetRemotely": "Definida por otro participante",
"pinParticipant": "",
"pinnedParticipant": "",
"polls": {
"answer": {
"skip": "Saltar",
"submit": "Enviar"
},
"by": "Por {{ name }}",
"create": {
"addOption": "Añadir opción",
"answerPlaceholder": "Opción {{index}}",
@@ -875,18 +728,15 @@
"initiated": "Llamada iniciada",
"joinAudioByPhone": "Entrar con audio de llamada telefónica",
"joinMeeting": "Entrar a la reunión",
"joinMeetingInLowBandwidthMode": "Entrar en modo de ancho de banda bajo",
"joinWithoutAudio": "Entrar sin sonido",
"keyboardShortcuts": "Activar los atajos de teclado",
"linkCopied": "Se copió el link",
"lookGood": "Tu micrófono funciona bien.",
"or": "o",
"premeeting": "Pre-reunión",
"proceedAnyway": "Continuar de todos modos",
"screenSharingError": "Error al compartir pantalla:",
"showScreen": "Habilitar pantalla pre-reunión",
"startWithPhone": "Iniciar con audio de llamada telefónica",
"unsafeRoomConsent": "Comprendo los riesgos, quiero unirme a la reunión",
"videoOnlyError": "Error con el vídeo:",
"videoTrackError": "No se pudo crear la pista de vídeo.",
"viewAllNumbers": "ver todos los números"
@@ -913,19 +763,6 @@
"title": "Perfil"
},
"raisedHand": "Desea hablar",
"raisedHandsLabel": "Cantidad de manos levantadas",
"record": {
"already": {
"linked": "La reunión ya está vinculada a este objeto Salesforce"
},
"type": {
"account": "Cuenta",
"contact": "Contacto",
"lead": "",
"opportunity": "Oportunidad",
"owner": "Dueño"
}
},
"recording": {
"authDropboxText": "Subir a Dropbox",
"availableSpace": "Espacio disponible: {{spaceLeft}} MB (aproximadamente {{duration}} minutos de grabación)",
@@ -940,66 +777,37 @@
"expandedPending": "La grabación se está iniciando…",
"failedToStart": "No se pudo iniciar la grabación",
"fileSharingdescription": "Compartir la grabación con los participantes de la reunión",
"highlight": "Destacar",
"highlightMoment": "Destacar momento",
"highlightMomentDisabled": "Puede destacar momentos cuando inicie la grabación",
"highlightMomentSuccess": "Momento destacado",
"highlightMomentSucessDescription": "Su momento destacado será agregado al resumen de la reunión.",
"inProgress": "Grabación o transmisión en vivo en curso",
"limitNotificationDescriptionNative": "Su grabación estará limitada a {{limit}} minutos. Puede obtener grabaciones ilimitadas en <3>{{app}}</3>.",
"limitNotificationDescriptionWeb": "Debido a la alta demanda su grabación estará limitada a {{limit}} minutos. Puede obtener grabaciones ilimitadas en <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
"linkGenerated": "Hemos generado un enlace a su grabación.",
"live": "EN VIVO",
"localRecordingNoNotificationWarning": "La grabación no será anunciada al resto de participantes. Necesitarás hacerles saber que la reunión está siendo grabada.",
"localRecordingNoVideo": "El video no está siendo grabado",
"localRecordingStartWarning": "Por favor asegúrese de detener la grabación antes de abandonar la reunión para guardarla.",
"localRecordingStartWarningTitle": "Detenga la grabación para guardarla",
"localRecordingVideoStop": "Detener su video también detendrá la grabación local. ¿Está seguro de querer continuar?",
"localRecordingVideoWarning": "Para grabar su video debe tenerlo encendido al iniciar la grabación",
"localRecordingWarning": "Asegúrese de seleccionar la pestaña actual para usar el video y audio correctos. La grabación está actualmente limitada a 1GB, que son aproximadamente 100 minutos.",
"loggedIn": "Sesión iniciada como {{userName}}",
"noMicPermission": "No se pudo crear la pista de micrófono. Por favor otorgue permiso para usar el micrófono.",
"noStreams": "",
"off": "Grabación detenida",
"offBy": "{{name}} detuvo la grabación",
"on": "Grabando",
"onBy": "{{name}} comenzó la grabación",
"onlyRecordSelf": "",
"pending": "Preparando para grabar la reunión…",
"rec": "GRA",
"saveLocalRecording": "Guardar archivo de grabación localmente (Beta)",
"serviceDescription": "El servicio de grabación guardará la grabación",
"serviceDescriptionCloud": "Grabación en la nube",
"serviceDescriptionCloudInfo": "Las reuniones grabadas son limpiadas 24h luego de su horario de grabación.",
"serviceName": "Servicio de grabación",
"sessionAlreadyActive": "Esta sesión ya está siendo grabada o transmitida en vivo.",
"signIn": "Iniciar sesión",
"signOut": "Cerrar sesión",
"surfaceError": "Por favor seleccione la pestaña actual.",
"title": "Grabando",
"unavailable": "¡Uy! {{serviceName}} actualmente no está disponible. Estamos trabajando para resolver el problema. Vuelve a intentarlo más tarde.",
"unavailableTitle": "Grabación no disponible",
"uploadToCloud": "Subir a la nube"
},
"screenshareDisplayName": "Pantalla de {{name}}",
"sectionList": {
"pullToRefresh": "Mueve el dedo para abajo para actualizar."
},
"security": {
"about": "Puedes agregar una contraseña a la reunión. Los participantes necesitarán la contraseña para unirse a la reunión.",
"aboutReadOnly": "Los participantes moderadores pueden agregar una $t(lockRoomPassword) a la reunión. Los participantes deberán proporcionar la $t(lockRoomPassword) antes de que se les permita unirse a la reunión.",
"insecureRoomNameWarningNative": "El nombre de esta sala es inseguro. Participantes indeseados podrían ingresar a su reunión. {{recommendAction}} Aprenda más sobre asegurar su reunión ",
"insecureRoomNameWarningWeb": "El nombre de esta sala es inseguro. Participantes indeseados podrían ingresar a su reunión. {{recommendAction}} Aprenda más sobre asegurar su reunión <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">aquí</a>.",
"title": "Opciones de seguridad",
"unsafeRoomActions": {
"meeting": "Considere hacer más segura su reunión utilizando el botón de seguridad.",
"prejoin": "Considere utilizar un nombre de reunión más único.",
"welcome": "Considere utilizar un nombre de reunión más único, o elija una de las sugerencias"
}
"insecureRoomNameWarning": "El nombre de la sala es inseguro. Participantes no deseados pueden llegar a unirse a la reunión.",
"securityOptions": "Opciones de seguridad"
},
"settings": {
"audio": "Audio",
"buttonLabel": "Ajustes",
"calendar": {
"about": "La integración del calendario de {{appName}} se usa para acceder al calendario de manera segura para que puedas estar al tanto de los próximos eventos.",
"disconnect": "Desconectar",
@@ -1016,16 +824,12 @@
"incomingMessage": "Mensaje entrante",
"language": "Idioma",
"loggedIn": "Sesión iniciada como {{name}}",
"maxStageParticipants": "",
"microphones": "Micrófono",
"moderator": "Moderador",
"moderatorOptions": "Opciones de moderador",
"more": "Más",
"name": "Nombre",
"noDevice": "Ninguno",
"notifications": "Notificaciones",
"participantJoined": "Un participante se ha unido",
"participantKnocking": "Un participante ha ingresado al lobby",
"participantJoined": "Un articipante incorporado",
"participantLeft": "Un participante se ha ido",
"playSounds": "Reproducir sonido",
"reactions": "Reacciones de la reunión",
@@ -1033,15 +837,12 @@
"selectAudioOutput": "Salida de audio",
"selectCamera": "Cámara",
"selectMic": "Micrófono",
"selfView": "Vista propia",
"shortcuts": "Atajos",
"sounds": "Sonidos",
"speakers": "Altavoces",
"startAudioMuted": "Todos inician silenciados",
"startReactionsMuted": "Silenciar sonidos de reacción para todos",
"startVideoMuted": "Todos inician con cámara desactivada",
"talkWhileMuted": "Hablar en silencio",
"title": "Ajustes",
"video": "Video"
"title": "Ajustes"
},
"settingsView": {
"advanced": "Avanzado",
@@ -1056,21 +857,13 @@
"disableCrashReportingWarning": "¿Estás seguro que no deseas reportarnos los crasheos? La opción se activará al reiniciar la app.",
"disableP2P": "Desactivar la comunicación directa (\"Peer-To-Peer\")",
"displayName": "Nombre a mostrar",
"displayNamePlaceholderText": "Por ejemplo: Juan Pérez",
"email": "Correo electrónico",
"emailPlaceholderText": "",
"goTo": "Ir a",
"header": "Configuración",
"help": "Ayuda",
"links": "Enlaces",
"privacy": "Privacidad",
"profileSection": "Perfil",
"serverURL": "URL del servidor",
"showAdvanced": "Mostrar configuración avanzada",
"startCarModeInLowBandwidthMode": "Iniciar módo automóvil en modo ancho de banda bajo",
"startWithAudioMuted": "Iniciar con el micrófono apagado",
"startWithVideoMuted": "Iniciar con la cámara apagada",
"terms": "Términos",
"version": "Versión"
},
"share": {
@@ -1079,21 +872,13 @@
},
"speaker": "Participante",
"speakerStats": {
"angry": "Enojado",
"disgusted": "Disgustado",
"displayEmotions": "Mostrar emociones",
"fearful": "Temeroso",
"happy": "Feliz",
"hours": "{{count}} h",
"minutes": "{{count}} min",
"name": "Nombre",
"neutral": "Neutral",
"sad": "Triste",
"search": "Buscar",
"seconds": "{{count}} s",
"speakerStats": "Estadísticas de participantes",
"speakerTime": "Tiempo hablado",
"surprised": "Sorprendido"
"speakerTime": "Tiempo hablado"
},
"startupoverlay": {
"genericTitle": "La reunión debe utilizar su micrófono y su cámara.",
@@ -1105,10 +890,6 @@
"text": "Presiona el botón <i>Reconectar</i> para volver a conectarte.",
"title": "La vídeollamada se interrumpió porque la computadora estaba suspendida."
},
"termsView": {
"title": "Términos"
},
"toggleTopPanelLabel": "Alternar panel superior",
"toolbar": {
"Settings": "Configuración",
"accessibilityLabel": {
@@ -1116,89 +897,60 @@
"audioOnly": "Alternar cámaras de los demás",
"audioRoute": "Seleccionar el dispositivo de sonido",
"boo": "Boo",
"breakoutRoom": "Unirse/abandonar sala para grupos pequeños",
"callQuality": "Administrar la calidad de vídeo",
"carmode": "Modo automóvil",
"cc": "Alternar subtítulos",
"chat": "Alternar ventana de chat",
"clap": "Aplauso",
"closeChat": "Cerrar chat",
"closeMoreActions": "Cerrar el menú de más acciones",
"closeParticipantsPane": "Cerrar panel de participantes",
"collapse": "Colapsar",
"document": "Alternar documento compartido",
"documentClose": "Cerrar documento compartido",
"documentOpen": "Abrir documento compartido",
"download": "Descargar nuestras aplicaciones",
"embedMeeting": "Insertar reunión",
"endConference": "Terminar reunión para todos",
"enterFullScreen": "Ver en pantalla completa",
"enterTileView": "Ingresar en vista de mosaico",
"exitFullScreen": "Salir de pantalla completa",
"exitTileView": "Salir de vista de mosaico",
"expand": "Ampliar",
"feedback": "Dejar comentarios",
"fullScreen": "Alternar pantalla completa",
"giphy": "Alternar menú GIPHY",
"grantModerator": "Convertir en moderador",
"hangup": "Colgar",
"heading": "Barra de herramientas",
"help": "Ayuda",
"hideWhiteboard": "Esconder pizarra",
"invite": "Invitar personas",
"kick": "Expulsar participante",
"laugh": "Ríete",
"leaveConference": "Abandonar reunión",
"like": "Pulgares arriba",
"linkToSalesforce": "Enlace a Salesforce",
"lobbyButton": "Activar / desactivar el modo lobby",
"localRecording": "Alternar controles de grabación local",
"lockRoom": "Alternar contraseña de la reunión",
"lowerHand": "Bajar mano",
"moreActions": "Alternar más acciones",
"moreActionsMenu": "Menú de más acciones",
"moreOptions": "Mostrar más opciones",
"mute": "Silenciar micrófono",
"muteEveryone": "Silenciar a todos",
"muteEveryoneElse": "Silenciar a todos los demás",
"muteEveryoneElsesVideoStream": "Detener el video del resto",
"muteEveryonesVideoStream": "Detener el video de todos",
"muteGUMPending": "Conectando su micrófono",
"noiseSuppression": "Supresión de ruido",
"openChat": "Abrir chat",
"muteEveryoneElsesVideo": "Desactivar el vídeo de los demás",
"muteEveryonesVideo": "Desactivar el vídeo de todos",
"participants": "Participantes",
"pip": "Alternar modo ventana en miniatura",
"privateMessage": "Enviar mensaje privado",
"profile": "Editar perfil",
"raiseHand": "Levantar o bajar la mano",
"reactions": "Reacciones",
"reactionsMenu": "Abrir / Cerrar el menú de reacciones",
"recording": "Alternar grabación",
"remoteMute": "Silenciar participante",
"remoteVideoMute": "Desactivar la cámara del participante",
"security": "Opciones de seguridad",
"selectBackground": "Seleccione el fondo",
"selfView": "Alternar vista propia",
"shareRoom": "Invitar a alguien",
"shareYourScreen": "Comenzar / detener compartir pantalla",
"shareaudio": "Compartir audio",
"sharedvideo": "Alternar vídeo compartido",
"shortcuts": "Alternar accesos directos",
"show": "Mostrar en primer",
"showWhiteboard": "Mostrar vista propia",
"silence": "Silencio",
"speakerStats": "Alternar estadísticas del orador",
"stopScreenSharing": "Dejar de compartir pantalla",
"stopSharedVideo": "Detener video",
"surprised": "Sorprendido",
"tileView": "Alternar vista de mosaico",
"toggleCamera": "Alternar cámara",
"toggleFilmstrip": "Alternar mosaicos",
"unmute": "Activar micrófono",
"videoblur": "Alternar desenfoque de vídeo",
"videomute": "Alternar vídeo",
"videomuteGUMPending": "Conectando tu cámara",
"videounmute": "Encender cámara"
"videomute": "Alternar vídeo"
},
"addPeople": "Agregar personas a la llamada",
"audioOnlyOff": "Mostrar cámaras de los demás",
@@ -1211,33 +963,23 @@
"chat": "Abrir o cerrar chat",
"clap": "Aplauso",
"closeChat": "Cerrar chat",
"closeParticipantsPane": "Cerrar panel de participantes",
"closeReactionsMenu": "Cerrar el menú de reacciones",
"disableNoiseSuppression": "Desactivar supresión de ruido",
"disableReactionSounds": "Puede desactivar los sonidos de reacción para esta reunión",
"documentClose": "Cerrar documento compartido",
"documentOpen": "Abrir documento compartido",
"download": "Descarga nuestras aplicaciones",
"e2ee": "Cifrado de extremo a extremo",
"embedMeeting": "Insertar reunión",
"enableNoiseSuppression": "Activar supresión de ruido",
"endConference": "Terminar reunión para todos",
"enterFullScreen": "Pantalla completa",
"enterTileView": "Ver en cuadrícula",
"exitFullScreen": "Salir de pantalla completa",
"exitTileView": "Salir de vista de mosaico",
"feedback": "Dejar sugerencias",
"giphy": "Alternar menú GIPHY",
"hangup": "Colgar",
"help": "Ayuda",
"hideWhiteboard": "Esconder pizarra",
"invite": "Invitar personas",
"joinBreakoutRoom": "Unirse a sala para grupos pequeños",
"laugh": "Ríete",
"leaveBreakoutRoom": "Abandonar sala para grupos pequeños",
"leaveConference": "Abandonar reunión",
"like": "Pulgares arriba",
"linkToSalesforce": "",
"lobbyButtonDisable": "Desactivar el modo lobby",
"lobbyButtonEnable": "Activar el modo lobby",
"login": "Inicio de sesión",
@@ -1248,13 +990,11 @@
"mute": "Activar o silenciar el micrófono",
"muteEveryone": "Silenciar a todos",
"muteEveryonesVideo": "Desactivar la cámara de todos",
"muteGUMPending": "Conectando tu micrónono",
"noAudioSignalDesc": "Checa si no está silenciado en tu configuración del sistema o dispositivo, o cambia de micrófono.",
"noAudioSignalDescSuggestion": "Si no lo silenciaste a propósito desde la configuración del sistema o el dispositivo, intenta usar este otro micrófono:",
"noAudioSignalDialInDesc": "Además, puedes llamar usando:",
"noAudioSignalDialInLinkDesc": "Números de llamada",
"noAudioSignalTitle": "¡No se registra audio de tu micrófono!",
"noiseSuppression": "Supresión de ruido",
"noisyAudioInputDesc": "Tu micrófono está haciendo ruido, siléncialo, ajusta su volumen en configuración del sistema, o cambia de micrófono.",
"noisyAudioInputTitle": "Tu micrófono parece estar ruidoso",
"openChat": "Abrir chat",
@@ -1271,14 +1011,12 @@
"reactionLike": "Enviar la reacción de los pulgares hacia arriba",
"reactionSilence": "Enviar reacción de silencio",
"reactionSurprised": "Enviar reacción de sorpresa",
"reactions": "Reacciones",
"security": "Opciones de seguridad",
"selectBackground": "Seleccionar fondo",
"shareRoom": "Invitar a alguien",
"shareaudio": "Compartir audio",
"sharedvideo": "Compartir un vídeo",
"shortcuts": "Ver atajos del teclado",
"showWhiteboard": "Mostrar pizarra",
"silence": "Silencio",
"speakerStats": "Estadísticas de los participantes",
"startScreenSharing": "Comenzar a compartir pantalla",
@@ -1291,11 +1029,8 @@
"talkWhileMutedPopup": "¿Intentas hablar? Estás silenciado.",
"tileViewToggle": "Activar o desactivar vista en cuadrícula",
"toggleCamera": "Alternar cámara",
"unmute": "Activar",
"videoSettings": "Ajustes de vídeo",
"videomute": "Detener cámara",
"videomuteGUMPending": "Conectando tu cámara",
"videounmute": "Iniciar cámara"
"videomute": "Iniciar o detener cámara"
},
"transcribing": {
"ccButtonTooltip": "Iniciar o detener subtítulos",
@@ -1305,15 +1040,10 @@
"labelToolTip": "La reunión se está transcribiendo",
"off": "Transcripción detenida",
"pending": "Preparando para transcribir la reunión…",
"sourceLanguageDesc": "El lenguaje actual de la reunión es <b>{{sourceLanguage}}</b>. <br/> Puedes cambiarlo desde ",
"sourceLanguageHere": "aquí",
"start": "Mostrar subtítulos",
"stop": "Dejar de mostrar subtítulos",
"subtitles": "Subtítulos",
"subtitlesOff": "",
"tr": "TR"
},
"unpinParticipant": "",
"userMedia": {
"androidGrantPermissions": "Selecciona <b><i>Permitir</i></b> cuando el navegador solicite permisos.",
"chromeGrantPermissions": "Selecciona <b><i>Permitir</i></b> cuando el navegador solicite permisos.",
@@ -1337,26 +1067,20 @@
"pending": "{{displayName}} ha sido invitado"
},
"videoStatus": {
"adjustFor": "Ajustar para:",
"audioOnly": "AUD",
"audioOnlyExpanded": "Estás en modo de ancho de banda bajo. En este modo, sólo recibirás audio y pantalla compartida.",
"bestPerformance": "Mejor rendimiento",
"callQuality": "Calidad de vídeo",
"hd": "HD",
"hdTooltip": "Viendo vídeo en alta definición",
"highDefinition": "Alta definición",
"highestQuality": "Calidad máxima",
"labelTooiltipNoVideo": "Sin vídeo",
"labelTooltipAudioOnly": "Modo de ancho de banda bajo habilitado",
"ld": "LD",
"ldTooltip": "Viendo vídeo en baja definición",
"lowDefinition": "Baja definición",
"performanceSettings": "Ajustes de rendimiento",
"recording": "Grabación en curso",
"sd": "SD",
"sdTooltip": "Viendo vídeo en definición estándar",
"standardDefinition": "Definición estándar",
"streaming": "Transmisión en curso"
"standardDefinition": "Definición estándar"
},
"videothumbnail": {
"connectionInfo": "Información de conexión",
@@ -1366,19 +1090,12 @@
"domuteVideoOfOthers": "Desactivar la cámara de todos los demás",
"flip": "Voltear",
"grantModerator": "Convertir en moderador",
"hideSelfView": "Esconder vista propia",
"kick": "Expulsar",
"mirrorVideo": "Espejar mi video",
"moderator": "Moderador",
"mute": "Se silenció el participante",
"muted": "Silenciado",
"pinToStage": "",
"remoteControl": "Control remoto",
"screenSharing": "El participante está compartiendo su pantalla",
"show": "Mostrar en primer plano",
"showSelfView": "Mostrar vista propia",
"unpinFromStage": "",
"verify": "Verificar participante",
"videoMuted": "Cámara desactivada",
"videomute": "El participante paró su cámara"
},
@@ -1403,16 +1120,7 @@
"slightBlur": "Desenfoque Ligero",
"title": "Fondos virtuales",
"uploadedImage": "Imagen subida {{index}}",
"webAssemblyWarning": "No se admite WebAssembly",
"webAssemblyWarningDescription": "WebAssembly está desactivado o no cuenta con soporte en este navegador"
},
"visitors": {
"chatIndicator": "(visitante)",
"labelTooltip": "Cantidad de visitantes: {{count}}",
"notification": {
"description": "Levanta la mano para participar",
"title": "Eres un visitante en la reunión"
}
"webAssemblyWarning": "No se admite WebAssembly"
},
"volumeSlider": "Deslizador de volumen",
"welcomepage": {
@@ -1446,7 +1154,6 @@
"microsoftLogo": "Logotipo de Microsoft",
"policyLogo": "Logotipo de la política"
},
"meetingsAccessibilityLabel": "Reuniones",
"mobileDownLoadLinkAndroid": "Descargar la aplicación móvil para Android",
"mobileDownLoadLinkFDroid": "Descargar la aplicación móvil para F-Droid",
"mobileDownLoadLinkIos": "Descargar la aplicación móvil para iOS",
@@ -1455,21 +1162,13 @@
"recentList": "Reciente",
"recentListDelete": "Eliminar",
"recentListEmpty": "Tu historial de reuniones está vacío. Reúnete y aparecerán aquí.",
"recentMeetings": "Tus reuniones recientes",
"reducedUIText": "¡Bienvenido a {{app}}!",
"roomNameAllowedChars": "El nombre de la reunión no debe contener ninguno de estos caracteres: ?, &, :, ', \", %, #.",
"roomname": "Introduce el nombre de la sala",
"roomnameHint": "Introduce el nombre o URL de la sala a la que deseas unirte. Puedes inventar un nombre, simplemente infórmaselo a las personas con las que te reunirás para que introduzcan el mismo nombre.",
"sendFeedback": "Enviar sugerencias",
"settings": "Ajustes",
"startMeeting": "Iniciar la reunión",
"terms": "Términos",
"title": "Videoconferencias seguras, con gran variedad de funcionalidades y completamente gratuitas",
"upcomingMeetings": "Tus próximas reuniones"
},
"whiteboard": {
"accessibilityLabel": {
"heading": "Pizarra"
}
"title": "Videoconferencias seguras, con gran variedad de funcionalidades y completamente gratuitas"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -156,7 +156,6 @@
"localport_plural": "Portas locais:",
"maxEnabledResolution": "enviar máx",
"more": "Mostrar mais",
"no": "não",
"packetloss": "Perda de pacote:",
"participant_id": "Participante id:",
"quality": {
@@ -175,8 +174,7 @@
"status": "Ligação:",
"transport": "Transporte:",
"transport_plural": "Transportes:",
"video_ssrc": "Vídeo SSRC:",
"yes": "sim"
"video_ssrc": "Vídeo SSRC:"
},
"dateUtils": {
"earlier": "Mais cedo",
@@ -321,13 +319,13 @@
"micPermissionDeniedError": "Não concedeu autorização para utilizar o seu microfone. Ainda pode participar na conferência, mas outros não o ouvirão. Use o botão da câmara na barra de endereço para corrigir isto.",
"micTimeoutError": "Não foi possível iniciar a fonte de áudio. Tempo limite expirado!",
"micUnknownError": "Não pode usar microfone por uma razão desconhecida.",
"moderationAudioLabel": "Permitir aos participantes ligar o som",
"moderationVideoLabel": "Permitir aos participantes ligar a câmara",
"muteEveryoneDialog": "Os participantes podem ligar o som a qualquer momento.",
"moderationAudioLabel": "Permitir aos participantes reativar o som",
"moderationVideoLabel": "Permitir aos participantes reativar o vídeo",
"muteEveryoneDialog": "Os participantes podem reativar o som a qualquer momento.",
"muteEveryoneDialogModerationOn": "Os participantes podem enviar um pedido para falar a qualquer momento.",
"muteEveryoneElseDialog": "Uma vez silenciados, não poderá reativá-los, mas eles podem ligar o microfone a qualquer momento.",
"muteEveryoneElseDialog": "Uma vez silenciados, não poderá reativá-los, mas eles podem reativar-se a qualquer momento.",
"muteEveryoneElseTitle": "Silenciar todos excepto {{whom}}?",
"muteEveryoneElsesVideoDialog": "Quando a câmara for desligada, não poderá voltar a ligá-la, mas eles podem voltar a ligá-la em qualquer momento.",
"muteEveryoneElsesVideoDialog": "Quando a câmara for desativada, não poderá voltar a ligá-la, mas eles podem voltar a ligá-la em qualquer momento.",
"muteEveryoneElsesVideoTitle": "Parar o vídeo de todos excepto {{whom}}?",
"muteEveryoneSelf": "você mesmo",
"muteEveryoneStartMuted": "A partir de agora, toda a gente começa a ficar calada",
@@ -675,10 +673,8 @@
"connectedTwoMembers": "{{first}} e {{second}} entraram na reunião",
"dataChannelClosed": "Deficiência na qualidade do vídeo",
"dataChannelClosedDescription": "O canal de ponte foi desconectado e, portanto, a qualidade do vídeo está limitada à sua configuração mais baixa.",
"disabledIframe": "A incorporação destina-se apenas a fins de demonstração, pelo que esta chamada será desligada em {{timeout}} minutos.",
"disconnected": "desconectado",
"displayNotifications": "Mostrar notificações para",
"dontRemindMe": "Não me lembre",
"focus": "Foco da conferência",
"focusFail": "{{component}} não disponĩvel - tente em {{ms}} seg.",
"gifsMenu": "GIPHY",
@@ -758,8 +754,8 @@
"actions": {
"allow": "Permitir aos participantes:",
"allowVideo": "Permitir vídeo",
"askUnmute": "Pedir para ligar o som",
"audioModeration": "Ligar o microfone deles",
"askUnmute": "Pedir para ligar o microfone",
"audioModeration": "Ativar o microfone deles",
"blockEveryoneMicCamera": "Bloquear o microfone e a câmara de todos",
"invite": "Convidar alguém",
"moreModerationActions": "Mais opções de moderação",
@@ -870,11 +866,9 @@
"lookGood": "O seu microfone funciona corretamente",
"or": "ou",
"premeeting": "Pré-reunião",
"proceedAnyway": "Continuar na mesma",
"screenSharingError": "Erro de partilha de ecrã:",
"showScreen": "Ativar o ecrã de pré-reunião",
"startWithPhone": "Iniciar com o áudio do telefone",
"unsafeRoomConsent": "Compreendo os riscos, quero participar na reunião",
"videoOnlyError": "Erro de vídeo:",
"videoTrackError": "Não foi possível criar a pista de vídeo.",
"viewAllNumbers": "ver todos os números"
@@ -950,7 +944,7 @@
"noStreams": "Não foi detetado nenhum sinal áudio ou vídeo.",
"off": "Gravação parada",
"offBy": "{{name}} parou a gravação",
"on": "Começou a gravação",
"on": "Gravando",
"onBy": "{{name}} iniciou a gravação",
"onlyRecordSelf": "Gravar apenas as minhas transmissões áudio e vídeo",
"pending": "Preparando para gravar a reunião...",
@@ -976,14 +970,8 @@
"security": {
"about": "Pode adicionar uma $t(lockRoomPassword) à sua reunião. Os participantes terão de fornecer a $t(lockRoomPassword) antes de serem autorizados a participar na reunião.",
"aboutReadOnly": "Os participantes moderadores podem acrescentar uma $t(lockRoomPassword) à reunião. Os participantes terão de fornecer a $t(lockRoomPassword) antes de serem autorizados a participar na reunião.",
"insecureRoomNameWarningNative": "O nome da sala não é seguro. Participantes indesejados podem juntar-se à sua reunião. {{recommendAction}} Saiba mais sobre como proteger a sua reunião ",
"insecureRoomNameWarningWeb": "O nome da sala não é seguro. Participantes indesejados podem juntar-se à sua reunião. {{recommendAction}} Saiba mais sobre como proteger a sua reunião <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">here</a>.",
"title": "Opções de Segurança",
"unsafeRoomActions": {
"meeting": "Considere a possibilidade de proteger a sua reunião utilizando o botão de segurança.",
"prejoin": "Considere a utilização de um nome de reunião mais personalizado.",
"welcome": "Considere utilizar um nome de reunião mais personalizado ou selecione uma das sugestões."
}
"insecureRoomNameWarning": "O nome da sala é inseguro. Participantes indesejados podem juntar-se à sua conferência. Considere proteger a sua reunião utilizando o botão de segurança.",
"title": "Opções de segurança"
},
"settings": {
"audio": "Áudio",
@@ -1158,7 +1146,6 @@
"privateMessage": "Enviar mensagem privada",
"profile": "Editar o seu perfil",
"raiseHand": "Levantar a mão",
"reactions": "Reações",
"reactionsMenu": "Menu de reações",
"recording": "Mudar gravação",
"remoteMute": "Participante sem som",
@@ -1256,7 +1243,6 @@
"reactionLike": "Enviar reação de aprovado",
"reactionSilence": "Enviar reação de silêncio",
"reactionSurprised": "Enviar reação de surpreendido",
"reactions": "Reações",
"security": "Opções de segurança",
"selectBackground": "Selecionar plano de fundo",
"shareRoom": "Convidar alguém",
@@ -1390,14 +1376,7 @@
"webAssemblyWarning": "WebAssembly não suportado",
"webAssemblyWarningDescription": "WebAssembly desactivado ou não suportado por este navegador"
},
"visitors": {
"chatIndicator": "(visitante)",
"labelTooltip": "Número de visitantes: {{count}}",
"notification": {
"description": "Para participar levante a sua mão",
"title": "É um visitante na reunião"
}
},
"visitorsLabel": "Número de visitantes: {{count}}",
"volumeSlider": "Controlo de volume",
"welcomepage": {
"accessibilityLabel": {

View File

@@ -68,9 +68,9 @@
},
"join": "Gå med",
"joinTooltip": "Gå med i mötet",
"nextMeeting": "Nästa möte",
"nextMeeting": "nästa möte",
"noEvents": "Det finns inga inbokade kommande aktiviteter.",
"ongoingMeeting": "Pågående möte",
"ongoingMeeting": "pågående möte",
"permissionButton": "Öppna inställningar",
"permissionMessage": "Tillåtelse från kalendern krävs för att se dina möten i appen.",
"refresh": "Uppdatera kalender",
@@ -147,7 +147,6 @@
"bridgeCount": "Serverantal: ",
"codecs": "Codecs (A/V):",
"connectedTo": "Ansluten till:",
"e2eeVerified": "E2EE verifierad",
"framerate": "Bildfrekvens:",
"less": "Visa mindre",
"localaddress": "Lokal adress:",
@@ -156,7 +155,6 @@
"localport_plural": "Lokala portar:",
"maxEnabledResolution": "Sänd maxiamlt",
"more": "Visa mer",
"no": "Nej",
"packetloss": "Paketförluster:",
"participant_id": "Deltagar id:",
"quality": {
@@ -175,8 +173,7 @@
"status": "Anslutning:",
"transport": "Transport:",
"transport_plural": "Transporter:",
"video_ssrc": "Video SSRC:",
"yes": "Ja"
"video_ssrc": "Video SSRC:"
},
"dateUtils": {
"earlier": "Tidigare",
@@ -186,25 +183,17 @@
"deepLinking": {
"appNotInstalled": "Du behöver mobilappen {{app}} för att gå med i det här mötet från din telefon.",
"description": "Hände inget? Vi försökte starta mötet i programmet {{app}} i din skrivbordsapp. Försök igen eller starta det i webbappen {{app}}.",
"descriptionNew": "Hände inget? Vi försökte starta mötet i programmet {{app}} i din skrivbordsapp. <br /><br /> Försök igen eller starta det på webben.",
"descriptionWithoutWeb": "Händer inget? Vi försökte starta mötet i {{app}}-skrivbordsappen.",
"downloadApp": "Hämta appen",
"downloadMobileApp": "Ladda ner mobilappen",
"ifDoNotHaveApp": "Om du inte har appen än:",
"ifHaveApp": "Om du redan har appen:",
"joinInApp": "Delta i detta möte med din app",
"joinInAppNew": "Delta i appen",
"joinInBrowser": "Delta på webben",
"launchMeetingLabel": "Hur vill du delta i detta möte?",
"launchWebButton": "Starta på webben",
"noMobileApp": "Har du inte appen?",
"termsAndConditions": "Genom att fortsätta godkänner du våra <a href='{{termsAndConditionsLink}}' rel='noopener noreferrer' target='_blank'>villkor.</a>",
"title": "Startar ditt möte i {{app}} ...",
"titleNew": "Startar ditt möte...",
"tryAgainButton": "Försök igen på skrivbordet",
"unsupportedBrowser": "Det verkar som att du använder en webbläsare som vi inte stöder."
},
"defaultLink": "t.ex. {{url}}",
"defaultLink": "t ex. {{url}}",
"defaultNickname": "till exempel Julia Eriksson",
"deviceError": {
"cameraError": "Det gick inte att komma åt kameran",
@@ -213,12 +202,6 @@
"microphonePermission": "Fel vid begäran om åtkomst till mikrofon"
},
"deviceSelection": {
"hid": {
"callControl": "Samtalskontroll",
"connectedDevices": "Anslutna enheter",
"deleteDevice": "Radera enhet",
"pairDevice": "Para enhet"
},
"noPermission": "Behörighet nekad",
"previewUnavailable": "Förhandsgranskning inte tillgänglig",
"selectADevice": "Välj en enhet",
@@ -242,9 +225,7 @@
"WaitingForHostTitle": "Väntar på värden ...",
"Yes": "Ja",
"accessibilityLabel": {
"close": "Stäng",
"liveStreaming": "Livesändning",
"sharingTabs": "Delningsalternativ"
"liveStreaming": "Livesändning"
},
"add": "Lägg till",
"addMeetingNote": "Mötesinformation",
@@ -427,10 +408,6 @@
"user": "Användare",
"userIdentifier": "Användar-ID",
"userPassword": "Lösenord",
"verifyParticipantConfirm": "Dem matchar",
"verifyParticipantDismiss": "Dem matchar inte",
"verifyParticipantQuestion": "EXPERIMENTELLT: Fråga deltagaren; {{participantName}} om han/hon kan se samma innehåll, i samma ordning.",
"verifyParticipantTitle": "Användarverifikation",
"videoLink": "Videolänk",
"viewUpgradeOptions": "Se uppgraderings alternativ",
"viewUpgradeOptionsContent": "För att få obegränsad tillgång till premiumfunktioner som inspelning, transkriptioner, RTMP -streaming och mer måste du uppgradera din plan.",
@@ -456,15 +433,13 @@
"veryBad": "Mycket dåligt",
"veryGood": "Mycket bra"
},
"filmstrip": {
"accessibilityLabel": {
"heading": "Videomineatyrer"
}
},
"giphy": {
"noResults": "Inga resultat funna :(",
"search": "Sök efter GIPHY"
},
"helpView": {
"title": "Hjälpcenter"
},
"incomingCall": {
"answer": "Svara",
"audioCallTitle": "Inkommande samtal",
@@ -542,8 +517,7 @@
"toggleParticipantsPane": "Visa eller dölj deltagarfönstret",
"toggleScreensharing": "Växla mellan kamera och skärmdelning",
"toggleShortcuts": "Visa eller dölj kortkommandon",
"videoMute": "Aktivera / inaktivera din kamera",
"whiteboard": "Visa / dölj whiteboardtavlan"
"videoMute": "Aktivera / avaktivera din kamera"
},
"largeVideo": {
"screenIsShared": "Du delar din skärm",
@@ -589,6 +563,7 @@
"lobby": {
"admit": "Godkänn",
"admitAll": "Godkänn alla",
"allow": "Tillåt",
"backToKnockModeButton": "Tillbaka till väntrum",
"chat": "Chatt",
"dialogTitle": "Väntrum",
@@ -674,12 +649,8 @@
"connectedOneMember": "{{name}} har gått med i mötet",
"connectedThreePlusMembers": "{{name}} och {{count}} andra har gått med i mötet",
"connectedTwoMembers": "{{first}} och {{second}} har gått med i mötet",
"dataChannelClosed": "Försämrad videokvalitet",
"dataChannelClosedDescription": "Bryggkanalen har kopplats bort och därmed är videokvaliteten begränsad till sin lägsta inställning",
"disabledIframe": "Inbäddning är endast avsedd för demonstrationsändamål, så det här samtalet kommer att kopplas ner om {{timeout}} minuter.",
"disconnected": "frånkopplad",
"displayNotifications": "Visa aviseringar för",
"dontRemindMe": "Påminn mig inte",
"focus": "Konferensfokus",
"focusFail": "{{component}} inte tillgänglig försöker igen om {{ms}} sek",
"gifsMenu": "GIPHY",
@@ -688,7 +659,6 @@
"invitedOneMember": "{{name}} har bjudits in",
"invitedThreePlusMembers": "{{name}} och {{count}} andra har bjudits in",
"invitedTwoMembers": "{{first}} och {{second}} har bjudits in",
"joinMeeting": "Delta",
"kickParticipant": "{{kicked}} sparkades ut av {{kicker}}",
"leftOneMember": "{{name}} lämnade mötet",
"leftThreePlusMembers": "{{name}} och många andra lämnade mötet",
@@ -739,8 +709,6 @@
"reactionSoundsForAll": "Inaktivera ljud för alla",
"screenShareNoAudio": "\"Dela ljudrutan\" aktiverades inte i fönstret för val av fönster.",
"screenShareNoAudioTitle": "Det gick inte att dela systemljud!",
"screenSharingAudioOnlyDescription": "Observera att genom att dela din skärm påverkar du läget \"Bästa prestanda\" och du kommer att använda mer bandbredd.",
"screenSharingAudioOnlyTitle": "Läget \"Bästa prestanda\"",
"selfViewTitle": "Du kan alltid ta bort döljandet av självvyn från inställningarna",
"somebody": "Någon",
"startSilentDescription": "Anslut till mötet igen för att aktivera ljud",
@@ -778,7 +746,6 @@
"headings": {
"lobby": "Väntrum ({{count}})",
"participantsList": "Mötesdeltagare ({{count}})",
"visitors": "Gäster ({{count}})",
"waitingLobby": "Väntar i väntrum ({{count}})"
},
"search": "Sök efter deltagare",
@@ -786,7 +753,6 @@
},
"passwordDigitsOnly": "Ange max {{number}} siffror",
"passwordSetRemotely": "satt av en annan deltagare",
"pinParticipant": "{{participantName}} - Fäst",
"pinnedParticipant": "Deltagaren är fäst",
"polls": {
"answer": {
@@ -871,11 +837,9 @@
"lookGood": "Din mikrofon fungerar som den ska",
"or": "eller",
"premeeting": "Förmöte",
"proceedAnyway": "Fortsätt ändå",
"screenSharingError": "Skärmdelningsfel:",
"showScreen": "Aktivera skärmen före mötet",
"startWithPhone": "Börja med telefonljud",
"unsafeRoomConsent": "Jag förstår riskerna, jag vill vara med på mötet",
"videoOnlyError": "Videofel:",
"videoTrackError": "Det gick inte att skapa videospår.",
"viewAllNumbers": "visa alla nummer"
@@ -894,6 +858,9 @@
"rejected": "Avvisad",
"ringing": "Ringer..."
},
"privacyView": {
"title": "Privat"
},
"profile": {
"avatar": "avatar",
"setDisplayNameLabel": "Ange ditt visningsnamn",
@@ -902,7 +869,7 @@
"title": "Profil"
},
"raisedHand": "Räck upp handen",
"raisedHandsLabel": "Antal uppräckta händer",
"raisedHandsLabel": "Antal upphöjda händer",
"record": {
"already": {
"linked": "Mötet är redan länkat till detta Salesforce-objekt."
@@ -947,7 +914,6 @@
"localRecordingVideoWarning": "För att spela in din video måste du ha den på när du startar inspelningen",
"localRecordingWarning": "Se till att du väljer den aktuella fliken för att kunna använda rätt video och ljud. Inspelningen är för närvarande begränsad till 1 GB, vilket är cirka 100 minuter.",
"loggedIn": "Inloggad som {{userName}}",
"noMicPermission": "Mikrofonspåret kunde inte skapas. Vänligen ge tillstånd att använda mikrofonen.",
"noStreams": "Ingen ljud- eller videoström upptäcktes.",
"off": "Inspelningen avslutades",
"offBy": "{{name}} avslutade inspelningen",
@@ -977,17 +943,10 @@
"security": {
"about": "Du kan lägga till ett $t(lockRoomPassword) till ditt möte. Deltagarna måste ange $t(lockRoomPassword) innan de får gå med i mötet.",
"aboutReadOnly": "Moderatorn kan lägga till ett $t(lockRoomPassword) till mötet. Deltagarna måste ange $t(lockRoomPassword) innan de får gå med i mötet.",
"insecureRoomNameWarningNative": "Rumsnamnet är osäkert. Oönskade deltagare kan gå med i ditt möte. {{recommendAction}} Läs mer om att säkra ditt möte",
"insecureRoomNameWarningWeb": "Rumsnamnet är osäkert. Oönskade deltagare kan gå med i ditt möte. {{recommendAction}} Läs mer om hur du säkerställer att du möter <a href=\"{{securityUrl}}\" rel=\"security\"-målet =\"_blank\">här</a>.",
"title": "Säkerhetsalternativ",
"unsafeRoomActions": {
"meeting": "Överväg att göra ditt möte säkrare med hjälp av säkerhetsknappen.",
"prejoin": "Överväg att använda ett mer unikt mötesnamn.",
"welcome": "Överväg att använda ett mer unikt mötesnamn, eller välj ett av förslagen."
}
"insecureRoomNameWarning": "Rummets namn är osäkert. Oönskade deltagare kan gå med i din konferens. Överväg att säkra ditt möte med hjälp av säkerhetsknappen.",
"title": "Säkerhetsalternativ"
},
"settings": {
"audio": "Ljud",
"buttonLabel": "Inställningar",
"calendar": {
"about": "Kalenderintegrationen med {{appName}} används för att hämta din kalender på ett säkert sätt så att den kan läsa framtida händelser.",
@@ -1008,11 +967,9 @@
"maxStageParticipants": "Maximalt antal deltagare som kan fästas på huvudscenen",
"microphones": "Mikrofoner",
"moderator": "Moderator",
"moderatorOptions": "Moderatoralternativ",
"more": "Mer",
"name": "Namn",
"noDevice": "Inga enheter",
"notifications": "Notifikationer",
"participantJoined": "Deltagare ansluten",
"participantKnocking": "Deltagare har anslutit till lobbyn",
"participantLeft": "Deltagare lämnat mötet",
@@ -1023,14 +980,13 @@
"selectCamera": "Kamera",
"selectMic": "Mikrofon",
"selfView": "Självvy",
"shortcuts": "Genvägar",
"sounds": "Ljud",
"speakers": "Högtalare",
"startAudioMuted": "Alla börjar tystade",
"startReactionsMuted": "Stäng av reaktionsljud för alla",
"startVideoMuted": "Alla börjar osynliga",
"talkWhileMuted": "Prata medan din ljud är inaktiverad",
"title": "Inställningar",
"video": "Video"
"title": "Inställningar"
},
"settingsView": {
"advanced": "Avancerat",
@@ -1047,7 +1003,6 @@
"displayName": "Skärmnamn",
"displayNamePlaceholderText": "Exempel: John Doe",
"email": "E-post",
"emailPlaceholderText": "mejl@exempel.se",
"goTo": "Gå till",
"header": "Inställningar",
"help": "Hjälp",
@@ -1105,87 +1060,69 @@
"audioOnly": "Slå av eller på ljudet",
"audioRoute": "Välj ljudenhet",
"boo": "Bua",
"breakoutRoom": "Anslut eller lämna grupprum",
"breakoutRoom": "Gå med i/lämna grupprum",
"callQuality": "Hantera videokvalitet",
"carmode": "Billäge",
"cc": "Slå av eller på undertexter",
"chat": "Öppna eller stäng chattfönster",
"clap": "Applådera",
"closeChat": "Stäng chatten",
"closeMoreActions": "Stäng menyn för fler åtgärder",
"closeParticipantsPane": "Stäng deltagarfönstret",
"collapse": "Minimera",
"document": "Växla delat dokument",
"documentClose": "Stäng delat dokument",
"documentOpen": "Öppna delat dokument",
"download": "Ladda ner våra appar",
"clap": "Klappa",
"collapse": "Kollaps",
"document": "Öppna eller stäng delat dokument",
"download": "Ladda ner app",
"embedMeeting": "Bädda in möte",
"endConference": "Avsluta möte för alla",
"enterFullScreen": "Visa helskärm",
"enterTileView": "Öppna sida vid sida",
"exitFullScreen": "Avsluta helskärm",
"exitTileView": "Avsluta sida vid sida",
"expand": "Utöka",
"feedback": "Ge feedback",
"fullScreen": "Växla helskärm",
"giphy": "Växla GIPHY-menyn",
"grantModerator": "Tilldela moderatorrättigheter",
"hangup": "Lämna mötet",
"heading": "Verktygsfält",
"endConference": "Avsluta mötet för alla",
"expand": "Expandera",
"feedback": "Lämna återkoppling",
"fullScreen": "Öppna eller stäng fullskärm",
"giphy": "Växla GIPHY meny",
"grantModerator": "Godkänn moderator",
"hangup": "Lämna samtalet",
"help": "Hjälp",
"hideWhiteboard": "Dölj whiteboard",
"invite": "Bjud in personer",
"invite": "Bjud in andra",
"kick": "Sparka ut deltagare",
"laugh": "Skratta",
"leaveConference": "Lämna mötet",
"leaveConference": "Lämna möte",
"like": "Tummen upp",
"linkToSalesforce": "Länk till Salesforce",
"lobbyButton": "Aktivera / inaktivera lobbyläge",
"localRecording": "Växla lokala inspelningskontroller",
"lockRoom": "Växla möteslösenord",
"lowerHand": "Sänk din hand",
"moreActions": "Fler åtgärder",
"moreActionsMenu": "Menyn Fler åtgärder",
"lobbyButton": "Aktivera/inaktivera väntrumsläge",
"localRecording": "Öppna eller stäng lokala inspelningsverktyg",
"lockRoom": "Slå av eller på möteslösenord",
"moreActions": "Öppna eller stäng menyn för fler åtgärder",
"moreActionsMenu": "Meny för fler åtgärder",
"moreOptions": "Visa fler alternativ",
"mute": "Mute",
"muteEveryone": "Stäng av ljudet för alla",
"muteEveryoneElse": "Stäng av ljudet för alla andra",
"mute": "Slå av eller på ljud",
"muteEveryone": "Tysta alla",
"muteEveryoneElse": "Inkativerad ljud för alla andra",
"muteEveryoneElsesVideoStream": "Stoppa alla andras video",
"muteEveryonesVideoStream": "Stoppa allas video",
"noiseSuppression": "Brusdämpning",
"openChat": "Öppna chatt",
"participants": "Öppna deltagarfönstret",
"pip": "Växla bild-i-bild-läge",
"noiseSuppression": "Brusreducering",
"participants": "Deltagare",
"pip": "Öppna eller stäng bild-i-bild-läge",
"privateMessage": "Skicka privat meddelande",
"profile": "Redigera din profil",
"raiseHand": "Räck upp handen",
"reactions": "Reaktioner",
"reactionsMenu": "Reaktionsmeny",
"recording": "Växla inspelning",
"remoteMute": "Ljud av deltagare",
"remoteVideoMute": "Inaktivera kameran för deltagaren",
"raiseHand": "Räck upp eller ta ner handen",
"reactionsMenu": "Öppna7ständ meny för reaktioner",
"recording": "Slå av eller på inspelning",
"remoteMute": "Tysta deltagare",
"remoteVideoMute": "Inaktivera kamera för deltagare",
"security": "Säkerhetsalternativ",
"selectBackground": "Välj bakgrund",
"selfView": "Växla självvy",
"shareRoom": "Bjud in någon",
"shareYourScreen": "Börja dela din skärm",
"shareYourScreen": "Slå av eller på skärmdelning",
"shareaudio": "Dela ljud",
"sharedvideo": "Dela video",
"shortcuts": "Växla genvägar",
"sharedvideo": "Slå av eller på videodelning",
"shortcuts": "Stäng eller öppna genvägar",
"show": "Visa på scenen",
"showWhiteboard": "Visa whiteboard",
"silence": "Tystnad",
"speakerStats": "Växla deltagarstatistik",
"stopScreenSharing": "Sluta dela din skärm",
"stopSharedVideo": "Stoppa video",
"surprised": "Förvånad",
"tileView": "Växla sida vid sida",
"silence": "Tyst läge",
"speakerStats": "Stäng eller öppna talarstatistik",
"surprised": "Överaskning",
"tileView": "Öppna eller stäng panelvyn",
"toggleCamera": "Växla kamera",
"toggleFilmstrip": "Växla filmremsa",
"unmute": "Slå på ljudet",
"videoblur": "Växla videooskärpa",
"videomute": "Stoppa kamera",
"videounmute": "Starta kameran"
"videomute": "Sätt på eller stäng av mikrofonen",
"whiteboard": "Visa/dölj whiteboardtavlan"
},
"addPeople": "Lägg till personer i samtal",
"audioOnlyOff": "Avsluta ljudläget",
@@ -1198,7 +1135,6 @@
"chat": "Öppna / stäng chatten",
"clap": "Klappa",
"closeChat": "Stäng chatt",
"closeParticipantsPane": "Stäng deltagarrutan",
"closeReactionsMenu": "Stäng meny för reaktioner",
"disableNoiseSuppression": "Inaktivera brusreducering",
"disableReactionSounds": "Du kan inaktivera reaktionsljud för det här mötet",
@@ -1207,7 +1143,6 @@
"download": "Ladda ner vår app",
"e2ee": "End-to-End kryptering",
"embedMeeting": "Bädda in möte",
"enableNoiseSuppression": "Aktivera brusreducering",
"endConference": "Avsluta mötet för alla",
"enterFullScreen": "Visa fullskärm",
"enterTileView": "Öppna panelvy",
@@ -1257,7 +1192,6 @@
"reactionLike": "Skicka tummen upp",
"reactionSilence": "Skicka tyst reaktion",
"reactionSurprised": "Skicka reaktionen överaskad",
"reactions": "Reaktioner",
"security": "Säkerhetsalternativ",
"selectBackground": "Välj bakgrund",
"shareRoom": "Bjud in någon",
@@ -1277,13 +1211,11 @@
"talkWhileMutedPopup": "Försöker du tala? Din mikrofon är tystad.",
"tileViewToggle": "Öppna eller stäng panelvyn",
"toggleCamera": "Byta kamera",
"unmute": "Slå på ljud",
"videoSettings": "Video inställningar",
"videomute": "Inaktivera kameran",
"videounmute": "Aktivera kameran"
"videomute": "Aktivera / avaktivera kameran"
},
"transcribing": {
"ccButtonTooltip": "Aktivera / Inaktivera undertexter",
"ccButtonTooltip": "Starta / Avsluta undertexter",
"error": "Transkriberingen misslyckades. Försök igen.",
"expandedLabel": "Transkribering är aktiverad",
"failedToStart": "Det gick inte att starta transkribering",
@@ -1298,7 +1230,6 @@
"subtitlesOff": "Av",
"tr": "TR"
},
"unpinParticipant": "Lossa deltagare",
"userMedia": {
"androidGrantPermissions": "Välj <b><i>Tillåt</i></b> när din webbläsare begär åtkomst.",
"chromeGrantPermissions": "Välj <b><i>Tillåt</i></b> när din webbläsare begär åtkomst.",
@@ -1337,11 +1268,9 @@
"ldTooltip": "Titta på lågupplöst video",
"lowDefinition": "Låg upplösning",
"performanceSettings": "Prestandainställningar",
"recording": "Inspelning pågår",
"sd": "SD",
"sdTooltip": "Titta på video med standardupplösning",
"standardDefinition": "Normal upplösning",
"streaming": "Streaming pågår"
"standardDefinition": "Normal upplösning"
},
"videothumbnail": {
"connectionInfo": "Anslutningsinformation",
@@ -1353,7 +1282,6 @@
"grantModerator": "Godkänn moderator",
"hideSelfView": "Dölj självvyn",
"kick": "Sparka ut",
"mirrorVideo": "Spegelvänd video",
"moderator": "Moderator",
"mute": "Deltagaren har avstängd mikrofon",
"muted": "Tystad",
@@ -1363,9 +1291,8 @@
"show": "Visa på scenen",
"showSelfView": "Visa självvy",
"unpinFromStage": "Ta loss",
"verify": "Verifiera",
"videoMuted": "Kamera inaktiverad",
"videomute": "Deltagaren har stängt av kameran"
"videoMuted": "kamera inaktiverad",
"videomute": "Deltagaren har stäng av kameran"
},
"virtualBackground": {
"addBackground": "Lägg till bakgrund",
@@ -1391,14 +1318,6 @@
"webAssemblyWarning": "WebAssembly stöds inte",
"webAssemblyWarningDescription": "WebAssembly inaktiverad eller stöds inte av den här webbläsaren"
},
"visitors": {
"chatIndicator": "(besökare)",
"labelTooltip": "Antal besökare: {{count}}",
"notification": {
"description": "Räck upp handen för att delta",
"title": "Du är en besökare i mötet"
}
},
"volumeSlider": "Volymreglage",
"welcomepage": {
"accessibilityLabel": {
@@ -1419,7 +1338,6 @@
"go": "KÖR",
"goSmall": "BÖRJA",
"headerSubtitle": "Säkra möten med hög kvalitet",
"headerTitle": "Jitsi Meet",
"info": "Info",
"jitsiOnMobile": "Jitsi på mobilen - ladda ner våra appar och starta ett möte var som helst",
"join": "Gå med",
@@ -1431,7 +1349,6 @@
"microsoftLogo": "Microsoft logotyp",
"policyLogo": "Policy-logotyp"
},
"meetingsAccessibilityLabel": "Möten",
"mobileDownLoadLinkAndroid": "Ladda ner mobilappen för Android",
"mobileDownLoadLinkFDroid": "Ladda ner mobilappen för F-droid",
"mobileDownLoadLinkIos": "Ladda ner mobilappen för iOS",
@@ -1440,7 +1357,6 @@
"recentList": "Tidigare",
"recentListDelete": "Radera",
"recentListEmpty": "Inga tidigare möten. Chatta med ditt team och hitta alla tidigare möten där.",
"recentMeetings": "Dina senaste möten",
"reducedUIText": "Välkommen till {{app}}!",
"roomNameAllowedChars": "Mötesnamn kan inte innehålla dessa tecken: ?, &,:, ', \",%, #.",
"roomname": "Skriv in rumsnamn",
@@ -1449,12 +1365,6 @@
"settings": "Inställningar",
"startMeeting": "Starta möte",
"terms": "Villkor",
"title": "Säkra, välutrustade och helt kostnadsfria videokonferenser",
"upcomingMeetings": "Dina kommande möten"
},
"whiteboard": {
"accessibilityLabel": {
"heading": "Whiteboard"
}
"title": "Säkra, välutrustade och helt kostnadsfria videokonferenser"
}
}

View File

@@ -1,8 +1,5 @@
{
"addPeople": {
"accessibilityLabel": {
"meetingLink": "Meeting link: {{url}}"
},
"add": "Invite",
"addContacts": "Invite your contacts",
"contacts": "contacts",
@@ -42,18 +39,6 @@
"audioOnly": {
"audioOnly": "Low bandwidth"
},
"bandwidthSettings": {
"assumedBandwidthBps": "e.g. 10000000 for 10 Mbps",
"assumedBandwidthBpsWarning": "Higher values might cause network issues.",
"customValue": "custom value",
"customValueEffect": "to set the actual bps value",
"leaveEmpty": "leave empty",
"leaveEmptyEffect": "to allow estimations to take place",
"possibleValues": "Possible values",
"setAssumedBandwidthBps": "Assumed bandwidth (bps)",
"title": "Bandwidth settings",
"zeroEffect": "to disable video"
},
"breakoutRooms": {
"actions": {
"add": "Add breakout room",
@@ -257,8 +242,6 @@
"WaitingForHostTitle": "Waiting for the host ...",
"Yes": "Yes",
"accessibilityLabel": {
"Cancel": "Cancel (leave dialog)",
"Ok": "OK (save and leave dialog)",
"close": "Close dialog",
"liveStreaming": "Live Stream",
"sharingTabs": "Sharing options"
@@ -464,9 +447,6 @@
"title": "Embed this meeting"
},
"feedback": {
"accessibilityLabel": {
"yourChoice": "Your choice: {{rating}}"
},
"average": "Average",
"bad": "Bad",
"detailsLabel": "Tell us more about it.",
@@ -695,7 +675,6 @@
"connectedTwoMembers": "{{first}} and {{second}} joined the meeting",
"dataChannelClosed": "Video quality impaired",
"dataChannelClosedDescription": "The bridge channel has been disconnected and thus video quality is limited to its lowest setting.",
"disabledIframe": "Embedding is only meant for demo purposes, so this call will disconnect in {{timeout}} minutes.",
"disconnected": "disconnected",
"displayNotifications": "Display notifications for",
"dontRemindMe": "Do not remind me",
@@ -890,11 +869,9 @@
"lookGood": "Your microphone is working properly",
"or": "or",
"premeeting": "Pre meeting",
"proceedAnyway": "Proceed anyway",
"screenSharingError": "Screen sharing error:",
"showScreen": "Enable pre meeting screen",
"startWithPhone": "Start with phone audio",
"unsafeRoomConsent": "I understand the risks, I want to join the meeting",
"videoOnlyError": "Video error:",
"videoTrackError": "Could not create video track.",
"viewAllNumbers": "view all numbers"
@@ -996,14 +973,8 @@
"security": {
"about": "You can add a $t(lockRoomPassword) to your meeting. Participants will need to provide the $t(lockRoomPassword) before they are allowed to join the meeting.",
"aboutReadOnly": "Moderator participants can add a $t(lockRoomPassword) to the meeting. Participants will need to provide the $t(lockRoomPassword) before they are allowed to join the meeting.",
"insecureRoomNameWarningNative": "The room name is unsafe. Unwanted participants may join your meeting. {{recommendAction}} Learn more about securing you meeting ",
"insecureRoomNameWarningWeb": "The room name is unsafe. Unwanted participants may join your meeting. {{recommendAction}} Learn more about securing you meeting <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">here</a>.",
"title": "Security Options",
"unsafeRoomActions": {
"meeting": "Consider securing your meeting using the security button.",
"prejoin": "Consider using a more unique meeting name.",
"welcome": "Consider using a more unique meeting name, or pick one of the suggestions."
}
"insecureRoomNameWarning": "The room name is unsafe. Unwanted participants may join your conference. Consider securing your meeting using the security button.",
"title": "Security Options"
},
"settings": {
"audio": "Audio",
@@ -1171,7 +1142,6 @@
"muteEveryoneElse": "Mute everyone else",
"muteEveryoneElsesVideoStream": "Stop everyone else's video",
"muteEveryonesVideoStream": "Stop everyone's video",
"muteGUMPending": "Connecting your microphone",
"noiseSuppression": "Noise suppression",
"openChat": "Open chat",
"participants": "Open participants pane",
@@ -1179,7 +1149,6 @@
"privateMessage": "Send private message",
"profile": "Edit your profile",
"raiseHand": "Raise your hand",
"reactions": "Reactions",
"reactionsMenu": "Reactions menu",
"recording": "Toggle recording",
"remoteMute": "Mute participant",
@@ -1205,7 +1174,6 @@
"unmute": "Unmute",
"videoblur": "Toggle video blur",
"videomute": "Stop camera",
"videomuteGUMPending": "Connecting your camera",
"videounmute": "Start camera"
},
"addPeople": "Add people to your call",
@@ -1256,7 +1224,6 @@
"mute": "Mute",
"muteEveryone": "Mute everyone",
"muteEveryonesVideo": "Disable everyone's camera",
"muteGUMPending": "Connecting your microphone",
"noAudioSignalDesc": "If you did not purposely mute it from system settings or hardware, consider switching the device.",
"noAudioSignalDescSuggestion": "If you did not purposely mute it from system settings or hardware, consider switching to the suggested device.",
"noAudioSignalDialInDesc": "You can also dial-in using:",
@@ -1279,7 +1246,6 @@
"reactionLike": "Send thumbs up reaction",
"reactionSilence": "Send silence reaction",
"reactionSurprised": "Send surprised reaction",
"reactions": "Reactions",
"security": "Security options",
"selectBackground": "Select background",
"shareRoom": "Invite someone",
@@ -1302,7 +1268,6 @@
"unmute": "Unmute",
"videoSettings": "Video settings",
"videomute": "Stop camera",
"videomuteGUMPending": "Connecting your camera",
"videounmute": "Start camera"
},
"transcribing": {
@@ -1349,7 +1314,7 @@
"audioOnly": "AUD",
"audioOnlyExpanded": "You are in low bandwidth mode. In this mode you will receive only audio and screen sharing.",
"bestPerformance": "Best performance",
"callQuality": "Video Quality (0 for best performance, 3 for highest quality)",
"callQuality": "Video Quality",
"hd": "HD",
"hdTooltip": "Viewing high definition video",
"highDefinition": "High definition",
@@ -1391,10 +1356,6 @@
"videomute": "Participant has stopped the camera"
},
"virtualBackground": {
"accessibilityLabel": {
"currentBackground": "Current background: {{background}}",
"selectBackground": "Select a background"
},
"addBackground": "Add background",
"apply": "Apply",
"backgroundEffectError": "Failed to apply background effect.",

View File

@@ -1,4 +1,5 @@
/* global APP */
// @flow
import Logger from '@jitsi/logger';
import { createApiEvent } from '../../react/features/analytics/AnalyticsEvents';
@@ -17,13 +18,12 @@ import { isEnabledFromState } from '../../react/features/av-moderation/functions
import {
endConference,
sendTones,
setAssumedBandwidthBps,
setFollowMe,
setLocalSubject,
setPassword,
setSubject
} from '../../react/features/base/conference/actions';
import { getCurrentConference, isP2pActive } from '../../react/features/base/conference/functions';
import { getCurrentConference } from '../../react/features/base/conference/functions';
import { overwriteConfig } from '../../react/features/base/config/actions';
import { getWhitelistedJSON } from '../../react/features/base/config/functions.any';
import { toggleDialog } from '../../react/features/base/dialog/actions';
@@ -113,16 +113,14 @@ import { isAudioMuteButtonDisabled } from '../../react/features/toolbox/function
import { setTileView, toggleTileView } from '../../react/features/video-layout/actions.any';
import { muteAllParticipants } from '../../react/features/video-menu/actions';
import { setVideoQuality } from '../../react/features/video-quality/actions';
import { toggleWhiteboard } from '../../react/features/whiteboard/actions.any';
import { getJitsiMeetTransport } from '../transport';
import {
API_ID,
ENDPOINT_TEXT_MESSAGE_NAME
} from './constants';
import { API_ID, ENDPOINT_TEXT_MESSAGE_NAME } from './constants';
const logger = Logger.getLogger(__filename);
declare var APP: Object;
/**
* List of the available commands.
*/
@@ -312,17 +310,6 @@ function initCommands() {
APP.store.dispatch(sendTones(tones, duration, pause));
},
'set-assumed-bandwidth-bps': value => {
logger.debug('Set assumed bandwidth bps command received', value);
if (typeof value !== 'number' || isNaN(value)) {
logger.error('Assumed bandwidth bps must be a number.');
return;
}
APP.store.dispatch(setAssumedBandwidthBps(value));
},
'set-follow-me': value => {
logger.debug('Set follow me command received');
@@ -336,16 +323,15 @@ function initCommands() {
},
'set-large-video-participant': (participantId, videoType) => {
logger.debug('Set large video participant command received');
const { getState, dispatch } = APP.store;
if (!participantId) {
sendAnalytics(createApiEvent('largevideo.participant.set'));
dispatch(selectParticipantInLargeVideo());
APP.store.dispatch(selectParticipantInLargeVideo());
return;
}
const state = getState();
const state = APP.store.getState();
const participant = videoType === VIDEO_TYPE.DESKTOP
? getVirtualScreenshareParticipantByOwnerId(state, participantId)
: getParticipantById(state, participantId);
@@ -356,9 +342,8 @@ function initCommands() {
return;
}
dispatch(setTileView(false));
sendAnalytics(createApiEvent('largevideo.participant.set'));
dispatch(selectParticipantInLargeVideo(participant.id));
APP.store.dispatch(selectParticipantInLargeVideo(participant.id));
},
'set-participant-volume': (participantId, volume) => {
APP.store.dispatch(setVolume(participantId, volume));
@@ -827,9 +812,6 @@ function initCommands() {
} else {
logger.error(' End Conference not supported');
}
},
'toggle-whiteboard': () => {
APP.store.dispatch(toggleWhiteboard());
}
};
transport.on('event', ({ data, name }) => {
@@ -981,10 +963,6 @@ function initCommands() {
callback(getRoomsInfo(APP.store.getState()));
break;
}
case 'get-p2p-status': {
callback(isP2pActive(APP.store.getState()));
break;
}
default:
return false;
}
@@ -1031,7 +1009,7 @@ function toggleScreenSharing(enable) {
* @param {MouseEvent} event - The mouse event to sanitize.
* @returns {Object}
*/
function sanitizeMouseEvent(event) {
function sanitizeMouseEvent(event: MouseEvent) {
const {
clientX,
clientY,
@@ -1069,7 +1047,7 @@ function sanitizeMouseEvent(event) {
* Jitsi Meet.
*/
class API {
_enabled;
_enabled: boolean;
/**
* Initializes the API. Setups message event listeners that will receive
@@ -1104,7 +1082,7 @@ class API {
* otherwise.
* @returns {void}
*/
notifyLargeVideoVisibilityChanged(isHidden) {
notifyLargeVideoVisibilityChanged(isHidden: boolean) {
this._sendEvent({
name: 'large-video-visibility-changed',
isVisible: !isHidden
@@ -1118,7 +1096,7 @@ class API {
* @param {Object} event - The message to pass onto spot.
* @returns {void}
*/
sendProxyConnectionEvent(event) {
sendProxyConnectionEvent(event: Object) {
this._sendEvent({
name: 'proxy-connection-event',
...event
@@ -1131,7 +1109,7 @@ class API {
* @param {Object} event - The event to be sent.
* @returns {void}
*/
_sendEvent(event = {}) {
_sendEvent(event: Object = {}) {
if (this._enabled) {
transport.sendEvent(event);
}
@@ -1144,7 +1122,7 @@ class API {
* @param {boolean} isOpen - True if the chat panel is open.
* @returns {void}
*/
notifyChatUpdated(unreadCount, isOpen) {
notifyChatUpdated(unreadCount: number, isOpen: boolean) {
this._sendEvent({
name: 'chat-updated',
unreadCount,
@@ -1159,7 +1137,7 @@ class API {
* @param {boolean} privateMessage - True if the message was a private message.
* @returns {void}
*/
notifySendingChatMessage(message, privateMessage) {
notifySendingChatMessage(message: string, privateMessage: boolean) {
this._sendEvent({
name: 'outgoing-message',
message,
@@ -1173,7 +1151,7 @@ class API {
* @param {MouseEvent} event - The mousemove event.
* @returns {void}
*/
notifyMouseEnter(event) {
notifyMouseEnter(event: MouseEvent) {
this._sendEvent({
name: 'mouse-enter',
event: sanitizeMouseEvent(event)
@@ -1186,7 +1164,7 @@ class API {
* @param {MouseEvent} event - The mousemove event.
* @returns {void}
*/
notifyMouseLeave(event) {
notifyMouseLeave(event: MouseEvent) {
this._sendEvent({
name: 'mouse-leave',
event: sanitizeMouseEvent(event)
@@ -1199,7 +1177,7 @@ class API {
* @param {MouseEvent} event - The mousemove event.
* @returns {void}
*/
notifyMouseMove(event) {
notifyMouseMove(event: MouseEvent) {
this._sendEvent({
name: 'mouse-move',
event: sanitizeMouseEvent(event)
@@ -1213,7 +1191,7 @@ class API {
* @param {boolean} enabled - Whether or not the new moderation status is enabled.
* @returns {void}
*/
notifyModerationChanged(mediaType, enabled) {
notifyModerationChanged(mediaType: string, enabled: boolean) {
this._sendEvent({
name: 'moderation-status-changed',
mediaType,
@@ -1228,7 +1206,7 @@ class API {
* @param {string} mediaType - Media type for which the participant was approved.
* @returns {void}
*/
notifyParticipantApproved(participantId, mediaType) {
notifyParticipantApproved(participantId: string, mediaType: string) {
this._sendEvent({
name: 'moderation-participant-approved',
id: participantId,
@@ -1243,7 +1221,7 @@ class API {
* @param {string} mediaType - Media type for which the participant was rejected.
* @returns {void}
*/
notifyParticipantRejected(participantId, mediaType) {
notifyParticipantRejected(participantId: string, mediaType: string) {
this._sendEvent({
name: 'moderation-participant-rejected',
id: participantId,
@@ -1259,7 +1237,7 @@ class API {
*
* @returns {void}
*/
notifyNotificationTriggered(title, description) {
notifyNotificationTriggered(title: string, description: string) {
this._sendEvent({
description,
name: 'notification-triggered',
@@ -1273,7 +1251,7 @@ class API {
* @param {number} videoQuality - The video quality. The number represents the maximum height of the video streams.
* @returns {void}
*/
notifyVideoQualityChanged(videoQuality) {
notifyVideoQualityChanged(videoQuality: number) {
this._sendEvent({
name: 'video-quality-changed',
videoQuality
@@ -1288,7 +1266,9 @@ class API {
* @returns {void}
*/
notifyReceivedChatMessage(
{ body, id, nick, privateMessage, ts } = {}) {
{ body, id, nick, privateMessage, ts }: {
body: *, id: string, nick: string, privateMessage: boolean, ts: *
} = {}) {
if (APP.conference.isLocalId(id)) {
return;
}
@@ -1311,7 +1291,7 @@ class API {
* @param {Object} props - The display name of the user.
* @returns {void}
*/
notifyUserJoined(id, props) {
notifyUserJoined(id: string, props: Object) {
this._sendEvent({
name: 'participant-joined',
id,
@@ -1326,7 +1306,7 @@ class API {
* @param {string} id - User id.
* @returns {void}
*/
notifyUserLeft(id) {
notifyUserLeft(id: string) {
this._sendEvent({
name: 'participant-left',
id
@@ -1341,7 +1321,7 @@ class API {
* @param {string} role - The new user role.
* @returns {void}
*/
notifyUserRoleChanged(id, role) {
notifyUserRoleChanged(id: string, role: string) {
this._sendEvent({
name: 'participant-role-changed',
id,
@@ -1357,7 +1337,7 @@ class API {
* @param {string} avatarURL - The new avatar URL of the participant.
* @returns {void}
*/
notifyAvatarChanged(id, avatarURL) {
notifyAvatarChanged(id: string, avatarURL: string) {
this._sendEvent({
name: 'avatar-changed',
avatarURL,
@@ -1372,7 +1352,7 @@ class API {
* @param {Object} data - The event data.
* @returns {void}
*/
notifyEndpointTextMessageReceived(data) {
notifyEndpointTextMessageReceived(data: Object) {
this._sendEvent({
name: 'endpoint-text-message-received',
data
@@ -1386,7 +1366,7 @@ class API {
* @param {string} faceExpression - Detected face expression.
* @returns {void}
*/
notifyFaceLandmarkDetected(faceBox, faceExpression) {
notifyFaceLandmarkDetected(faceBox: Object, faceExpression: string) {
this._sendEvent({
name: 'face-landmark-detected',
faceBox,
@@ -1400,7 +1380,7 @@ class API {
* @param {Object} data - The event data.
* @returns {void}
*/
notifySharingParticipantsChanged(data) {
notifySharingParticipantsChanged(data: Object) {
this._sendEvent({
name: 'content-sharing-participants-changed',
data
@@ -1414,7 +1394,7 @@ class API {
* @param {Object} devices - The new device list.
* @returns {void}
*/
notifyDeviceListChanged(devices) {
notifyDeviceListChanged(devices: Object) {
this._sendEvent({
name: 'device-list-changed',
devices
@@ -1432,8 +1412,8 @@ class API {
* @returns {void}
*/
notifyDisplayNameChanged(
id,
{ displayName, formattedDisplayName }) {
id: string,
{ displayName, formattedDisplayName }: Object) {
this._sendEvent({
name: 'display-name-change',
displayname: displayName,
@@ -1451,8 +1431,8 @@ class API {
* @returns {void}
*/
notifyEmailChanged(
id,
{ email }) {
id: string,
{ email }: Object) {
this._sendEvent({
name: 'email-change',
email,
@@ -1464,10 +1444,10 @@ class API {
* Notify external application (if API is enabled) that the an error has been logged.
*
* @param {string} logLevel - The message log level.
* @param {Array<string>} args - Array of strings composing the log message.
* @param {Array} args - Array of strings composing the log message.
* @returns {void}
*/
notifyLog(logLevel, args) {
notifyLog(logLevel: string, args: Array<string>) {
this._sendEvent({
name: 'log',
logLevel,
@@ -1485,7 +1465,7 @@ class API {
* user and the type of the room.
* @returns {void}
*/
notifyConferenceJoined(roomName, id, props) {
notifyConferenceJoined(roomName: string, id: string, props: Object) {
this._sendEvent({
name: 'video-conference-joined',
roomName,
@@ -1500,7 +1480,7 @@ class API {
* @param {string} roomName - User id.
* @returns {void}
*/
notifyConferenceLeft(roomName) {
notifyConferenceLeft(roomName: string) {
this._sendEvent({
name: 'video-conference-left',
roomName
@@ -1515,7 +1495,7 @@ class API {
*
* @returns {void}
*/
notifyDataChannelClosed(code, reason) {
notifyDataChannelClosed(code: number, reason: string) {
this._sendEvent({
name: 'data-channel-closed',
code,
@@ -1558,7 +1538,7 @@ class API {
* @param {boolean} muted - The new muted status.
* @returns {void}
*/
notifyAudioMutedStatusChanged(muted) {
notifyAudioMutedStatusChanged(muted: boolean) {
this._sendEvent({
name: 'audio-mute-status-changed',
muted
@@ -1572,7 +1552,7 @@ class API {
* @param {boolean} muted - The new muted status.
* @returns {void}
*/
notifyVideoMutedStatusChanged(muted) {
notifyVideoMutedStatusChanged(muted: boolean) {
this._sendEvent({
name: 'video-mute-status-changed',
muted
@@ -1586,7 +1566,7 @@ class API {
* @param {boolean} available - True if available and false otherwise.
* @returns {void}
*/
notifyAudioAvailabilityChanged(available) {
notifyAudioAvailabilityChanged(available: boolean) {
audioAvailable = available;
this._sendEvent({
name: 'audio-availability-changed',
@@ -1601,7 +1581,7 @@ class API {
* @param {boolean} available - True if available and false otherwise.
* @returns {void}
*/
notifyVideoAvailabilityChanged(available) {
notifyVideoAvailabilityChanged(available: boolean) {
videoAvailable = available;
this._sendEvent({
name: 'video-availability-changed',
@@ -1616,7 +1596,7 @@ class API {
* @param {string} id - User id of the new on stage participant.
* @returns {void}
*/
notifyOnStageParticipantChanged(id) {
notifyOnStageParticipantChanged(id: string) {
this._sendEvent({
name: 'on-stage-participant-changed',
id
@@ -1630,7 +1610,7 @@ class API {
* @param {boolean} isVisible - Whether the prejoin video is visible.
* @returns {void}
*/
notifyPrejoinVideoVisibilityChanged(isVisible) {
notifyPrejoinVideoVisibilityChanged(isVisible: boolean) {
this._sendEvent({
name: 'on-prejoin-video-changed',
isVisible
@@ -1664,7 +1644,7 @@ class API {
* @param {string} message - Additional information about the error.
* @returns {void}
*/
notifyOnCameraError(type, message) {
notifyOnCameraError(type: string, message: string) {
this._sendEvent({
name: 'camera-error',
type,
@@ -1680,7 +1660,7 @@ class API {
* @param {string} message - Additional information about the error.
* @returns {void}
*/
notifyOnMicError(type, message) {
notifyOnMicError(type: string, message: string) {
this._sendEvent({
name: 'mic-error',
type,
@@ -1696,7 +1676,7 @@ class API {
* @param {string} error - A failure message, if any.
* @returns {void}
*/
notifyFeedbackSubmitted(error) {
notifyFeedbackSubmitted(error: string) {
this._sendEvent({
name: 'feedback-submitted',
error
@@ -1721,7 +1701,7 @@ class API {
* be displayed or hidden.
* @returns {void}
*/
notifyFilmstripDisplayChanged(visible) {
notifyFilmstripDisplayChanged(visible: boolean) {
this._sendEvent({
name: 'filmstrip-display-changed',
visible
@@ -1738,7 +1718,7 @@ class API {
* other participant.
* @returns {void}
*/
notifyKickedOut(kicked, kicker) {
notifyKickedOut(kicked: Object, kicker: Object) {
this._sendEvent({
name: 'participant-kicked-out',
kicked,
@@ -1767,7 +1747,7 @@ class API {
* share is capturing.
* @returns {void}
*/
notifyScreenSharingStatusChanged(on, details) {
notifyScreenSharingStatusChanged(on: boolean, details: Object) {
this._sendEvent({
name: 'screen-sharing-status-changed',
on,
@@ -1782,7 +1762,7 @@ class API {
* @param {string} id - Id of the dominant participant.
* @returns {void}
*/
notifyDominantSpeakerChanged(id) {
notifyDominantSpeakerChanged(id: string) {
this._sendEvent({
name: 'dominant-speaker-changed',
id
@@ -1796,7 +1776,7 @@ class API {
* @param {string} subject - Conference subject.
* @returns {void}
*/
notifySubjectChanged(subject) {
notifySubjectChanged(subject: string) {
this._sendEvent({
name: 'subject-change',
subject
@@ -1811,7 +1791,7 @@ class API {
* otherwise.
* @returns {void}
*/
notifyTileViewChanged(enabled) {
notifyTileViewChanged(enabled: boolean) {
this._sendEvent({
name: 'tile-view-changed',
enabled
@@ -1824,7 +1804,7 @@ class API {
* @param {string} localStorageContent - The new localStorageContent.
* @returns {void}
*/
notifyLocalStorageChanged(localStorageContent) {
notifyLocalStorageChanged(localStorageContent: string) {
this._sendEvent({
name: 'local-storage-changed',
localStorageContent
@@ -1838,7 +1818,7 @@ class API {
* @param {boolean} handRaised - Whether user has raised hand.
* @returns {void}
*/
notifyRaiseHandUpdated(id, handRaised) {
notifyRaiseHandUpdated(id: string, handRaised: boolean) {
this._sendEvent({
name: 'raise-hand-updated',
handRaised,
@@ -1854,7 +1834,7 @@ class API {
* @param {string} error - Error type or null if success.
* @returns {void}
*/
notifyRecordingStatusChanged(on, mode, error) {
notifyRecordingStatusChanged(on: boolean, mode: string, error?: string) {
this._sendEvent({
name: 'recording-status-changed',
on,
@@ -1871,7 +1851,7 @@ class API {
* @param {number} ttl - The recording download link time to live.
* @returns {void}
*/
notifyRecordingLinkAvailable(link, ttl) {
notifyRecordingLinkAvailable(link: string, ttl: number) {
this._sendEvent({
name: 'recording-link-available',
link,
@@ -1885,7 +1865,7 @@ class API {
* @param {Object} participant - Participant data such as id and name.
* @returns {void}
*/
notifyKnockingParticipant(participant) {
notifyKnockingParticipant(participant: Object) {
this._sendEvent({
name: 'knocking-participant',
participant
@@ -1898,7 +1878,7 @@ class API {
* @param {Object} error - The error.
* @returns {void}
*/
notifyError(error) {
notifyError(error: Object) {
this._sendEvent({
name: 'error-occurred',
error
@@ -1912,7 +1892,7 @@ class API {
* @param {boolean} preventExecution - Whether execution of the button click was prevented or not.
* @returns {void}
*/
notifyToolbarButtonClicked(key, preventExecution) {
notifyToolbarButtonClicked(key: string, preventExecution: boolean) {
this._sendEvent({
name: 'toolbar-button-clicked',
key,
@@ -1926,7 +1906,7 @@ class API {
* @param {boolean} supported - If browser is supported or not.
* @returns {void}
*/
notifyBrowserSupport(supported) {
notifyBrowserSupport(supported: boolean) {
this._sendEvent({
name: 'browser-support',
supported
@@ -2013,50 +1993,6 @@ class API {
});
}
/**
* Notify external application (if API is enabled) if whiteboard state is
* changed.
*
* @param {WhiteboardStatus} status - The new whiteboard status.
* @returns {void}
*/
notifyWhiteboardStatusChanged(status) {
this._sendEvent({
name: 'whiteboard-status-changed',
status
});
}
/**
* Notify external application (if API is enabled) if non participant message
* is received.
*
* @param {string} id - The resource id of the sender.
* @param {Object} json - The json carried by the message.
* @returns {void}
*/
notifyNonParticipantMessageReceived(id, json) {
this._sendEvent({
name: 'non-participant-message-received',
id,
message: json
});
}
/**
* Notify the external application (if API is enabled) if the connection type changed.
*
* @param {boolean} isP2p - Whether the new connection is P2P.
* @returns {void}
*/
notifyP2pStatusChanged(isP2p) {
this._sendEvent({
name: 'p2p-status-changed',
isP2p
});
}
/**
* Disposes the allocated resources.
*

View File

@@ -15,10 +15,3 @@ export const API_ID = parseURLParams(window.location).jitsi_meet_external_api_id
* The payload name for the datachannel/endpoint text message event.
*/
export const ENDPOINT_TEXT_MESSAGE_NAME = 'endpoint-text-message';
/**
* The min value that can be set for the assumed bandwidth.
* Setting it to this value means not assuming any bandwidth,
* but rather allowing the estimations to take place.
*/
export const MIN_ASSUMED_BANDWIDTH_BPS = -1;

View File

@@ -36,6 +36,7 @@ const commands = {
cancelPrivateChat: 'cancel-private-chat',
closeBreakoutRoom: 'close-breakout-room',
displayName: 'display-name',
e2eeKey: 'e2ee-key',
endConference: 'end-conference',
email: 'email',
grantModerator: 'grant-moderator',
@@ -58,7 +59,6 @@ const commands = {
sendEndpointTextMessage: 'send-endpoint-text-message',
sendParticipantToRoom: 'send-participant-to-room',
sendTones: 'send-tones',
setAssumedBandwidthBps: 'set-assumed-bandwidth-bps',
setFollowMe: 'set-follow-me',
setLargeVideoParticipant: 'set-large-video-participant',
setMediaEncryptionKey: 'set-media-encryption-key',
@@ -89,8 +89,7 @@ const commands = {
toggleSubtitles: 'toggle-subtitles',
toggleTileView: 'toggle-tile-view',
toggleVirtualBackgroundDialog: 'toggle-virtual-background',
toggleVideo: 'toggle-video',
toggleWhiteboard: 'toggle-whiteboard'
toggleVideo: 'toggle-video'
};
/**
@@ -128,10 +127,8 @@ const events = {
'mouse-enter': 'mouseEnter',
'mouse-leave': 'mouseLeave',
'mouse-move': 'mouseMove',
'non-participant-message-received': 'nonParticipantMessageReceived',
'notification-triggered': 'notificationTriggered',
'outgoing-message': 'outgoingMessage',
'p2p-status-changed': 'p2pStatusChanged',
'participant-joined': 'participantJoined',
'participant-kicked-out': 'participantKickedOut',
'participant-left': 'participantLeft',
@@ -156,8 +153,7 @@ const events = {
'subject-change': 'subjectChange',
'suspend-detected': 'suspendDetected',
'tile-view-changed': 'tileViewChanged',
'toolbar-button-clicked': 'toolbarButtonClicked',
'whiteboard-status-changed': 'whiteboardStatusChanged'
'toolbar-button-clicked': 'toolbarButtonClicked'
};
/**
@@ -317,7 +313,6 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
* @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.
* @param {string} [options.sandbox] - Sandbox directive for the created iframe, if desired.
*/
constructor(domain, ...args) {
super();
@@ -335,8 +330,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
devices,
userInfo,
e2eeKey,
release,
sandbox = ''
release
} = parseArguments(args);
const localStorageContent = jitsiLocalStorage.getItem('jitsiLocalStorage');
@@ -354,7 +348,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
},
release
});
this._createIFrame(height, width, onload, sandbox);
this._createIFrame(height, width, onload);
this._transport = new Transport({
backend: new PostMessageTransportBackend({
postisOptions: {
@@ -387,12 +381,11 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
* parseSizeParam for format details.
* @param {Function} onload - The function that will listen
* for onload event.
* @param {string} sandbox - Sandbox directive for the created iframe, if desired.
* @returns {void}
*
* @private
*/
_createIFrame(height, width, onload, sandbox) {
_createIFrame(height, width, onload) {
const frameName = `jitsiConferenceFrame${id}`;
this._frame = document.createElement('iframe');
@@ -403,10 +396,6 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
this._frame.setAttribute('allowFullScreen', 'true');
this._frame.style.border = 0;
if (sandbox) {
this._frame.sandbox = sandbox;
}
if (onload) {
// waits for iframe resources to load
// and fires event when it is done
@@ -562,22 +551,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
switch (name) {
case 'video-conference-joined': {
if (typeof this._tmpE2EEKey !== 'undefined') {
const hexToBytes = hex => {
const bytes = [];
for (let c = 0; c < hex.length; c += 2) {
bytes.push(parseInt(hex.substring(c, c + 2), 16));
}
return bytes;
};
this.executeCommand('setMediaEncryptionKey', JSON.stringify({
exportedKey: hexToBytes(this._tmpE2EEKey),
index: 0
}));
this.executeCommand(commands.e2eeKey, this._tmpE2EEKey);
this._tmpE2EEKey = undefined;
}
@@ -695,6 +669,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
this._numberOfParticipants = allParticipants;
}
/**
* Returns the rooms info in the conference.
*
@@ -706,17 +681,6 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
});
}
/**
* Returns whether the conference is P2P.
*
* @returns {Promise}
*/
isP2pActive() {
return this._transport.sendRequest({
name: 'get-p2p-status'
});
}
/**
* Adds event listener to Meet Jitsi.
*

View File

@@ -1,3 +1,5 @@
// @flow
import Logger from '@jitsi/logger';
const logger = Logger.getLogger(__filename);
@@ -9,7 +11,7 @@ const logger = Logger.getLogger(__filename);
* the external communication.
* @returns {Promise}
*/
export function getAvailableDevices(transport) {
export function getAvailableDevices(transport: Object) {
return transport.sendRequest({
type: 'devices',
name: 'getAvailableDevices'
@@ -27,7 +29,7 @@ export function getAvailableDevices(transport) {
* the external communication.
* @returns {Promise}
*/
export function getCurrentDevices(transport) {
export function getCurrentDevices(transport: Object) {
return transport.sendRequest({
type: 'devices',
name: 'getCurrentDevices'
@@ -48,7 +50,7 @@ export function getCurrentDevices(transport) {
* Default - 'input'.
* @returns {Promise}
*/
export function isDeviceChangeAvailable(transport, deviceType) {
export function isDeviceChangeAvailable(transport: Object, deviceType: string) {
return transport.sendRequest({
deviceType,
type: 'devices',
@@ -64,7 +66,7 @@ export function isDeviceChangeAvailable(transport, deviceType) {
* the external communication.
* @returns {Promise}
*/
export function isDeviceListAvailable(transport) {
export function isDeviceListAvailable(transport: Object) {
return transport.sendRequest({
type: 'devices',
name: 'isDeviceListAvailable'
@@ -79,7 +81,7 @@ export function isDeviceListAvailable(transport) {
* the external communication.
* @returns {Promise}
*/
export function isMultipleAudioInputSupported(transport) {
export function isMultipleAudioInputSupported(transport: Object) {
return transport.sendRequest({
type: 'devices',
name: 'isMultipleAudioInputSupported'
@@ -95,7 +97,7 @@ export function isMultipleAudioInputSupported(transport) {
* @param {string} id - The id of the new device.
* @returns {Promise}
*/
export function setAudioInputDevice(transport, label, id) {
export function setAudioInputDevice(transport: Object, label: string, id: string) {
return _setDevice(transport, {
id,
kind: 'audioinput',
@@ -112,7 +114,7 @@ export function setAudioInputDevice(transport, label, id) {
* @param {string} id - The id of the new device.
* @returns {Promise}
*/
export function setAudioOutputDevice(transport, label, id) {
export function setAudioOutputDevice(transport: Object, label: string, id: string) {
return _setDevice(transport, {
id,
kind: 'audiooutput',
@@ -128,7 +130,7 @@ export function setAudioOutputDevice(transport, label, id) {
* @param {Object} device - The new device to be used.
* @returns {Promise}
*/
function _setDevice(transport, device) {
function _setDevice(transport: Object, device) {
return transport.sendRequest({
type: 'devices',
name: 'setDevice',
@@ -145,7 +147,7 @@ function _setDevice(transport, device) {
* @param {string} id - The id of the new device.
* @returns {Promise}
*/
export function setVideoInputDevice(transport, label, id) {
export function setVideoInputDevice(transport: Object, label: string, id: string) {
return _setDevice(transport, {
id,
kind: 'videoinput',

View File

@@ -11,11 +11,11 @@ import { setColorAlpha } from '../../react/features/base/util/helpers';
import { setDocumentUrl } from '../../react/features/etherpad/actions';
import { setFilmstripVisible } from '../../react/features/filmstrip/actions.any';
import {
joinLeaveNotificationsDisabled,
setNotificationsEnabled,
showNotification
} from '../../react/features/notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../../react/features/notifications/constants';
import { joinLeaveNotificationsDisabled } from '../../react/features/notifications/functions';
import {
dockToolbox,
setToolboxEnabled,

View File

@@ -1,4 +1,5 @@
/* global APP */
// @flow
import Logger from '@jitsi/logger';
import { openConnection } from '../../../connection';
@@ -22,6 +23,7 @@ import ExternalLoginDialog from './LoginDialog';
let externalAuthWindow;
declare var APP: Object;
const logger = Logger.getLogger(__filename);
@@ -75,7 +77,7 @@ function doExternalAuth(room, lockPassword) {
* back with "?jwt={the JWT token}" query parameter added.
* @param {string} [roomName] the name of the conference room.
*/
export function redirectToTokenAuthService(roomName) {
export function redirectToTokenAuthService(roomName: string) {
const config = APP.store.getState()['features/base/config'];
// FIXME: This method will not preserve the other URL params that were
@@ -172,7 +174,7 @@ function initJWTTokenListener(room) {
* @param {JitsiConference} room
* @param {string} [lockPassword] password to use if the conference is locked
*/
function authenticate(room, lockPassword) {
function authenticate(room: Object, lockPassword: string) {
const config = APP.store.getState()['features/base/config'];
if (isTokenAuthEnabled(config) || room.isExternalAuthEnabled()) {
@@ -187,7 +189,7 @@ function authenticate(room, lockPassword) {
* @param {JitsiConference} room
* @param {string} [lockPassword] password to use if the conference is locked
*/
function requireAuth(room, lockPassword) {
function requireAuth(room: Object, lockPassword: string) {
if (isDialogOpen(APP.store, WaitForOwnerDialog) || isDialogOpen(APP.store, LoginDialog)) {
return;
}
@@ -205,7 +207,7 @@ function requireAuth(room, lockPassword) {
* @param {string} [lockPassword] password to use if the conference is locked
* @returns {Promise}
*/
function logout(room) {
function logout(room: Object) {
return new Promise(resolve => {
room.room.moderator.logout(resolve);
}).then(url => {

View File

@@ -1,4 +1,6 @@
/* global APP */
// @flow
declare var APP: Object;
export default {
@@ -8,7 +10,7 @@ export default {
* @param {function} callback - callback to invoke when auth popup is closed.
* @returns auth dialog
*/
showExternalAuthDialog(url, callback) {
showExternalAuthDialog(url: string, callback: ?Function) {
const dialog = APP.UI.messageHandler.openCenteredPopup(
url, 910, 660,

View File

@@ -15,7 +15,7 @@ const Filmstrip = {
// horizontal film strip mode for calculating how tall large video
// display should be.
if (isFilmstripVisible(APP.store) && !interfaceConfig.VERTICAL_FILMSTRIP) {
return document.querySelector('.filmstrip')?.offsetHeight ?? 0;
return document.querySelector('.filmstrip').offsetHeight;
}
return 0;

View File

@@ -0,0 +1,261 @@
/* global APP */
import { jitsiLocalStorage } from '@jitsi/js-utils';
import Logger from '@jitsi/logger';
import {
ACTION_SHORTCUT_PRESSED as PRESSED,
ACTION_SHORTCUT_RELEASED as RELEASED,
createShortcutEvent
} from '../../react/features/analytics/AnalyticsEvents';
import { sendAnalytics } from '../../react/features/analytics/functions';
import { clickOnVideo } from '../../react/features/filmstrip/actions';
import { openSettingsDialog } from '../../react/features/settings/actions';
import { SETTINGS_TABS } from '../../react/features/settings/constants';
const logger = Logger.getLogger(__filename);
/**
* Map of shortcuts. When a shortcut is registered it enters the mapping.
* @type {Map}
*/
const _shortcuts = new Map();
/**
* Map of registered keyboard keys and translation keys describing the
* action performed by the key.
* @type {Map}
*/
const _shortcutsHelp = new Map();
/**
* The key used to save in local storage if keyboard shortcuts are enabled.
*/
const _enableShortcutsKey = 'enableShortcuts';
/**
* Prefer keyboard handling of these elements over global shortcuts.
* If a button is triggered using the Spacebar it should not trigger PTT.
* If an input element is focused and M is pressed it should not mute audio.
*/
const _elementsBlacklist = [
'input',
'textarea',
'button',
'[role=button]',
'[role=menuitem]',
'[role=radio]',
'[role=tab]',
'[role=option]',
'[role=switch]',
'[role=range]',
'[role=log]'
];
/**
* An element selector for elements that have their own keyboard handling.
*/
const _focusedElementsSelector = `:focus:is(${_elementsBlacklist.join(',')})`;
/**
* Maps keycode to character, id of popover for given function and function.
*/
const KeyboardShortcut = {
init() {
this._initGlobalShortcuts();
window.onkeyup = e => {
if (!this.getEnabled()) {
return;
}
const key = this._getKeyboardKey(e).toUpperCase();
const num = parseInt(key, 10);
if (!document.querySelector(_focusedElementsSelector)) {
if (_shortcuts.has(key)) {
_shortcuts.get(key).function(e);
} else if (!isNaN(num) && num >= 0 && num <= 9) {
APP.store.dispatch(clickOnVideo(num));
}
}
};
window.onkeydown = e => {
if (!this.getEnabled()) {
return;
}
const focusedElement = document.querySelector(_focusedElementsSelector);
if (!focusedElement) {
if (this._getKeyboardKey(e).toUpperCase() === ' ') {
if (APP.conference.isLocalAudioMuted()) {
sendAnalytics(createShortcutEvent(
'push.to.talk',
PRESSED));
logger.log('Talk shortcut pressed');
APP.conference.muteAudio(false);
}
}
} else if (this._getKeyboardKey(e).toUpperCase() === 'ESCAPE') {
// Allow to remove focus from selected elements using ESC key.
if (focusedElement && focusedElement.blur) {
focusedElement.blur();
}
}
};
},
/**
* Enables/Disables the keyboard shortcuts.
* @param {boolean} value - the new value.
*/
enable(value) {
jitsiLocalStorage.setItem(_enableShortcutsKey, value);
},
getEnabled() {
// Should be enabled if not explicitly set to false
// eslint-disable-next-line no-unneeded-ternary
return jitsiLocalStorage.getItem(_enableShortcutsKey) === 'false' ? false : true;
},
getShortcutsDescriptions() {
return _shortcutsHelp;
},
/**
* Opens the {@SettingsDialog} dialog on the Shortcuts page.
*
* @returns {void}
*/
openDialog() {
APP.store.dispatch(openSettingsDialog(SETTINGS_TABS.SHORTCUTS, false));
},
/**
* Registers a new shortcut.
*
* @param shortcutChar the shortcut character triggering the action
* @param shortcutAttr the "shortcut" html element attribute mapping an
* element to this shortcut and used to show the shortcut character on the
* element tooltip
* @param exec the function to be executed when the shortcut is pressed
* @param helpDescription the description of the shortcut that would appear
* in the help menu
* @param altKey whether or not the alt key must be pressed.
*/
registerShortcut(// eslint-disable-line max-params
shortcutChar,
shortcutAttr,
exec,
helpDescription,
altKey = false) {
_shortcuts.set(altKey ? `:${shortcutChar}` : shortcutChar, {
character: shortcutChar,
function: exec,
shortcutAttr,
altKey
});
if (helpDescription) {
this._addShortcutToHelp(altKey ? `:${shortcutChar}` : shortcutChar, helpDescription);
}
},
/**
* Unregisters a shortcut.
*
* @param shortcutChar unregisters the given shortcut, which means it will
* no longer be usable
* @param altKey whether or not shortcut is combo with alt key
*/
unregisterShortcut(shortcutChar, altKey = false) {
_shortcuts.delete(altKey ? `:${shortcutChar}` : shortcutChar);
_shortcutsHelp.delete(shortcutChar);
},
/**
* @param e a KeyboardEvent
* @returns {string} e.key or something close if not supported
*/
_getKeyboardKey(e) {
// If alt is pressed a different char can be returned so this takes
// the char from the code. It also prefixes with a colon to differentiate
// alt combo from simple keypress.
if (e.altKey) {
const key = e.code.replace('Key', '');
return `:${key}`;
}
// If e.key is a string, then it is assumed it already plainly states
// the key pressed. This may not be true in all cases, such as with Edge
// and "?", when the browser cannot properly map a key press event to a
// keyboard key. To be safe, when a key is "Unidentified" it must be
// further analyzed by jitsi to a key using e.which.
if (typeof e.key === 'string' && e.key !== 'Unidentified') {
return e.key;
}
if (e.type === 'keypress'
&& ((e.which >= 32 && e.which <= 126)
|| (e.which >= 160 && e.which <= 255))) {
return String.fromCharCode(e.which);
}
// try to fallback (0-9A-Za-z and QWERTY keyboard)
switch (e.which) {
case 27:
return 'Escape';
case 191:
return e.shiftKey ? '?' : '/';
}
if (e.shiftKey || e.type === 'keypress') {
return String.fromCharCode(e.which);
}
return String.fromCharCode(e.which).toLowerCase();
},
/**
* Adds the given shortcut to the help dialog.
*
* @param shortcutChar the shortcut character
* @param shortcutDescriptionKey the description of the shortcut
* @private
*/
_addShortcutToHelp(shortcutChar, shortcutDescriptionKey) {
_shortcutsHelp.set(shortcutChar, shortcutDescriptionKey);
},
/**
* Initialise global shortcuts.
* Global shortcuts are shortcuts for features that don't have a button or
* link associated with the action. In other words they represent actions
* triggered _only_ with a shortcut.
*/
_initGlobalShortcuts() {
this.registerShortcut('?', null, () => {
sendAnalytics(createShortcutEvent('help'));
this.openDialog();
}, 'keyboardShortcuts.toggleShortcuts');
// register SPACE shortcut in two steps to insure visibility of help
// message
this.registerShortcut(' ', null, () => {
sendAnalytics(createShortcutEvent('push.to.talk', RELEASED));
logger.log('Talk shortcut released');
APP.conference.muteAudio(true);
});
this._addShortcutToHelp('SPACE', 'keyboardShortcuts.pushToTalk');
/**
* FIXME: Currently focus keys are directly implemented below in
* onkeyup. They should be moved to the SmallVideo instead.
*/
this._addShortcutToHelp('0', 'keyboardShortcuts.focusLocal');
this._addShortcutToHelp('1-9', 'keyboardShortcuts.focusRemote');
}
};
export default KeyboardShortcut;

View File

@@ -1,8 +1,15 @@
/* @flow */
import $ from 'jquery';
import jqueryI18next from 'jquery-i18next';
import i18next from '../../react/features/base/i18n/i18next';
type DocumentElement = {
lang: string
}
/**
* Notifies that the {@link i18next} instance has finished its initialization.
*
@@ -11,7 +18,7 @@ import i18next from '../../react/features/base/i18n/i18next';
*/
function _onI18nInitialized() {
const documentElement
const documentElement: DocumentElement
= document.documentElement || {};
$('[data-i18n]').localize();
@@ -40,7 +47,7 @@ class Translation {
/**
*
*/
generateTranslationHTML(key, options) {
generateTranslationHTML(key: string, options: Object) {
const optAttr
= options ? ` data-i18n-options='${JSON.stringify(options)}'` : '';
@@ -53,7 +60,7 @@ class Translation {
/**
*
*/
translateElement(selector, options) {
translateElement(selector: Object, options: Object) {
// XXX i18next expects undefined if options are missing.
selector.localize(options ? options : undefined);
}

5755
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -20,9 +20,9 @@
"@emotion/styled": "11.10.6",
"@giphy/js-fetch-api": "4.7.1",
"@giphy/react-components": "6.8.1",
"@giphy/react-native-sdk": "2.3.0",
"@giphy/react-native-sdk": "1.7.0",
"@hapi/bourne": "2.0.0",
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.14/jitsi-excalidraw-0.0.14.tgz",
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.12/jitsi-excalidraw-0.0.12.tgz",
"@jitsi/js-utils": "2.0.5",
"@jitsi/logger": "2.0.0",
"@jitsi/rnnoise-wasm": "0.1.0",
@@ -65,7 +65,7 @@
"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/v1643.0.0+0748d89a/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1620.0.0+7f0012f7/lib-jitsi-meet.tgz",
"lodash": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",
@@ -73,13 +73,13 @@
"optional-require": "1.0.3",
"promise.allsettled": "1.0.4",
"punycode": "2.1.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-emoji-render": "1.2.4",
"react-focus-on": "3.8.1",
"react-focus-lock": "2.5.1",
"react-i18next": "10.11.4",
"react-linkify": "1.0.0-alpha",
"react-native": "0.69.11",
"react-native": "0.68.6",
"react-native-background-timer": "2.4.1",
"react-native-calendar-events": "2.2.0",
"react-native-callstats": "3.73.7",
@@ -104,7 +104,7 @@
"react-native-url-polyfill": "1.3.0",
"react-native-video": "https://git@github.com/react-native-video/react-native-video#7c48ae7c8544b2b537fb60194e9620b9fcceae52",
"react-native-watch-connectivity": "1.0.11",
"react-native-webrtc": "111.0.1",
"react-native-webrtc": "111.0.0",
"react-native-webview": "11.15.1",
"react-native-youtube-iframe": "2.2.1",
"react-redux": "7.1.0",
@@ -125,22 +125,21 @@
},
"devDependencies": {
"@babel/core": "7.16.0",
"@babel/eslint-parser": "7.21.8",
"@babel/eslint-parser": "7.16.0",
"@babel/plugin-proposal-export-default-from": "7.16.0",
"@babel/preset-env": "7.16.0",
"@babel/preset-flow": "7.16.0",
"@babel/preset-react": "7.16.0",
"@jitsi/eslint-config": "4.1.5",
"@types/amplitude-js": "8.16.2",
"@types/audioworklet": "0.0.29",
"@types/dom-screen-wake-lock": "1.0.1",
"@types/js-md5": "0.4.3",
"@types/lodash": "4.14.182",
"@types/punycode": "2.1.0",
"@types/react": "17.0.14",
"@types/react-dom": "17.0.14",
"@types/react-linkify": "1.0.1",
"@types/react-native": "0.69.20",
"@types/react-native-keep-awake": "2.0.3",
"@types/react-native": "0.68.9",
"@types/react-native-video": "5.0.14",
"@types/react-redux": "7.1.24",
"@types/react-window": "1.8.5",
@@ -150,28 +149,29 @@
"@types/w3c-image-capture": "1.0.6",
"@types/w3c-web-hid": "1.0.3",
"@types/zxcvbn": "4.4.1",
"@typescript-eslint/eslint-plugin": "5.59.5",
"@typescript-eslint/parser": "5.59.5",
"@typescript-eslint/eslint-plugin": "5.30.5",
"@typescript-eslint/parser": "5.30.4",
"babel-loader": "8.2.3",
"babel-plugin-optional-require": "0.3.1",
"circular-dependency-plugin": "5.2.0",
"clean-css-cli": "4.3.0",
"css-loader": "3.6.0",
"eslint": "8.40.0",
"eslint-plugin-import": "2.27.5",
"eslint": "8.35.0",
"eslint-plugin-flowtype": "8.0.3",
"eslint-plugin-import": "2.25.2",
"eslint-plugin-jsdoc": "37.0.3",
"eslint-plugin-react": "7.32.2",
"eslint-plugin-react-native": "4.0.0",
"eslint-plugin-typescript-sort-keys": "2.3.0",
"eslint-plugin-react": "7.26.1",
"eslint-plugin-react-native": "3.11.0",
"eslint-plugin-typescript-sort-keys": "2.1.0",
"jetifier": "1.6.4",
"metro-react-native-babel-preset": "0.70.3",
"metro-react-native-babel-preset": "0.67.0",
"patch-package": "6.4.7",
"process": "0.11.10",
"sass": "1.26.8",
"style-loader": "3.3.1",
"traverse": "0.6.6",
"ts-loader": "9.4.2",
"typescript": "5.0.4",
"ts-loader": "9.4.1",
"typescript": "4.7.4",
"unorm": "1.6.0",
"webpack": "5.76.0",
"webpack-bundle-analyzer": "4.4.2",
@@ -179,8 +179,8 @@
"webpack-dev-server": "4.7.3"
},
"overrides": {
"strophe.js@1.5.0": {
"@xmldom/xmldom": "0.8.7"
"strophe.js@1.6.0": {
"@xmldom/xmldom": "0.8.7"
}
},
"engines": {
@@ -193,7 +193,7 @@
"tsc:web": "tsc --noEmit --project tsconfig.web.json",
"tsc:native": "tsc --noEmit --project tsconfig.native.json",
"tsc:ci": "npm run tsc:web && npm run tsc:native",
"lint:ci": "eslint --ext .js,.ts,.tsx --max-warnings 0 .",
"lint:ci": "eslint --ext .js,.ts,.tsx --max-warnings 0 . && npm run tsc:ci && npm run lint:lang",
"lint:lang": "for file in lang/*.json; do npx --yes jsonlint -q $file || exit 1; done",
"lang-sort": "./resources/lang-sort.sh",
"lint-fix": "eslint --ext .js,.ts,.tsx --max-warnings 0 --fix .",

View File

@@ -0,0 +1,11 @@
diff --git a/node_modules/eslint-plugin-flowtype/dist/configs/recommended.json b/node_modules/eslint-plugin-flowtype/dist/configs/recommended.json
index 90a0d69..2ad7d68 100644
--- a/node_modules/eslint-plugin-flowtype/dist/configs/recommended.json
+++ b/node_modules/eslint-plugin-flowtype/dist/configs/recommended.json
@@ -1,5 +1,5 @@
{
- "parser": "@babel/eslint",
+ "parser": "@babel/eslint-parser",
"parserOptions": {
"babelOptions": {
"plugins": [

View File

@@ -1,3 +0,0 @@
package-lock=true
; FIXME Set legacy-peer-deps=false when we upgrade RN.
legacy-peer-deps=true

View File

@@ -1,48 +0,0 @@
# <p align="center">Jitsi Meet React Native SDK</p>
## Installation
Inside your project, run `npm i @jitsi/react-native-sdk`.<br/><br/>Additionally if not already installed, the following dependencies need to be added:
<br/>`npm i @react-native-async-storage/async-storage react-native-webrtc`
[comment]: # (These deps definitely need to be added manually, more could be neccesary)
### iOS
#### Project Info.plist
- Add a *Privacy - Camera Usage Description*
- Add a *Privacy - Microphone Usage Description*
#### General
- Signing & capabilites:
- Add Background modes
- Audio
- Voice over IP
- Background fetch
- Add Copy Sounds step:
```
SOUNDS_DIR="${PROJECT_DIR}/../node_modules/rnsdk/sounds"
cp $SOUNDS_DIR/* ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/
```
#### Podfile
- At the beginning of your target step add `pod 'ObjectiveDropboxOfficial', :modular_headers => true`
Run `cd ios && pod install && cd ..`
### Android
- In your build.gradle have at least `minSdkVersion = 24`
- TODO: HOW TO ADD COPY SOUNDS STEP
- Under the `</application>` tag of your AndroidManifest.xml make sure that it includes
```
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
```
### TODOS
- Ref ConnectionService to not rely on ReactInstanceHolder anymore
- Add Copy Sounds step to build.gradle
- Include copy sounds step in podspec (if possible)
- Add ranges for dependencies
- Add Build_Config for react native to AppInfoModule

View File

@@ -1,140 +0,0 @@
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
}
}
def isNewArchitectureEnabled() {
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
}
apply plugin: 'com.android.library'
if (isNewArchitectureEnabled()) {
apply plugin: 'com.facebook.react'
}
def getExtOrDefault(name) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['JitsiMeetReactNative_' + name]
}
def getExtOrIntegerDefault(name) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['JitsiMeetReactNative_' + name]).toInteger()
}
android {
compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
defaultConfig {
minSdkVersion getExtOrIntegerDefault('minSdkVersion')
targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
}
buildTypes {
release {
minifyEnabled false
}
}
lintOptions {
disable 'GradleCompatible'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
repositories {
mavenCentral()
google()
def found = false
def defaultDir = null
def androidSourcesName = 'React Native sources'
if (rootProject.ext.has('reactNativeAndroidRoot')) {
defaultDir = rootProject.ext.get('reactNativeAndroidRoot')
} else {
defaultDir = new File(
projectDir,
'/../../../node_modules/react-native/android'
)
}
if (defaultDir.exists()) {
maven {
url defaultDir.toString()
name androidSourcesName
}
logger.info(":${project.name}:reactNativeAndroidRoot ${defaultDir.canonicalPath}")
found = true
} else {
def parentDir = rootProject.projectDir
1.upto(5, {
if (found) return true
parentDir = parentDir.parentFile
def androidSourcesDir = new File(
parentDir,
'node_modules/react-native'
)
def androidPrebuiltBinaryDir = new File(
parentDir,
'node_modules/react-native/android'
)
if (androidPrebuiltBinaryDir.exists()) {
maven {
url androidPrebuiltBinaryDir.toString()
name androidSourcesName
}
logger.info(":${project.name}:reactNativeAndroidRoot ${androidPrebuiltBinaryDir.canonicalPath}")
found = true
} else if (androidSourcesDir.exists()) {
maven {
url androidSourcesDir.toString()
name androidSourcesName
}
logger.info(":${project.name}:reactNativeAndroidRoot ${androidSourcesDir.canonicalPath}")
found = true
}
})
}
if (!found) {
throw new GradleException(
"${project.name}: unable to locate React Native android sources. " +
"Ensure you have you installed React Native as a dependency in your project and try again."
)
}
}
dependencies {
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+"
implementation 'com.squareup.duktape:duktape-android:1.3.0'
implementation 'com.dropbox.core:dropbox-core-sdk:4.0.1'
implementation 'com.jakewharton.timber:timber:4.7.1'
// From node_modules
}
if (isNewArchitectureEnabled()) {
react {
jsRootDir = file("../src/")
libraryName = "JitsiMeetReactNative"
codegenJavaPackageName = "org.jitsi.meet.sdk"
}
}

View File

@@ -1,5 +0,0 @@
JitsiMeetReactNative_kotlinVersion=1.7.0
JitsiMeetReactNative_minSdkVersion=21
JitsiMeetReactNative_targetSdkVersion=31
JitsiMeetReactNative_compileSdkVersion=31
JitsiMeetReactNative_ndkversion=21.4.7075529

View File

@@ -1,4 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.jitsi.meet.sdk">
</manifest>

View File

@@ -1,39 +0,0 @@
package org.jitsi.meet.sdk;
import androidx.annotation.NonNull;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class JitsiMeetReactNativePackage implements ReactPackage {
@NonNull
@Override
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
List<NativeModule> modules
= new ArrayList<>(Arrays.<NativeModule>asList(
new AndroidSettingsModule(reactContext),
new AppInfoModule(reactContext),
new AudioModeModule(reactContext),
new JavaScriptSandboxModule(reactContext),
new LocaleDetector(reactContext),
new LogBridgeModule(reactContext),
new PictureInPictureModule(reactContext),
new ProximityModule(reactContext),
new org.jitsi.meet.sdk.net.NAT64AddrInfoModule(reactContext)
));
return modules;
}
@NonNull
@Override
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

View File

@@ -1,99 +0,0 @@
/* eslint-disable lines-around-comment, no-undef, no-unused-vars */
import 'react-native-gesture-handler';
// Apply all necessary polyfills as early as possible
// to make sure anything imported henceforth sees them.
import 'react-native-get-random-values';
import '../react/features/mobile/polyfills';
// @ts-ignore
import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
import { View } from 'react-native';
import { convertPropsToURL } from '../functions';
import { appNavigate } from '../react/features/app/actions.native';
import { App } from '../react/features/app/components/App.native';
import { setAudioMuted, setVideoMuted } from '../react/features/base/media/actions';
// @ts-ignore
import JitsiThemePaperProvider from '../react/features/base/ui/components/JitsiThemeProvider';
interface IAppProps {
flags: [];
meetingOptions: {
domain: string;
roomName: string;
onReadyToClose?: Function;
onConferenceJoined?: Function;
onConferenceWillJoin?: Function;
onConferenceLeft?: Function;
onParticipantJoined?: Function;
settings?: {
startWithAudioMuted?: boolean;
startAudioOnly?: boolean;
startWithVideoMuted?: boolean;
}
};
style?: Object;
}
/**
* Main React Native SDK component that displays a Jitsi Meet conference and gets all required params as props
*/
const JitsiMeet = forwardRef(({ flags, meetingOptions, style }: IAppProps, ref) => {
const [ appProps, setAppProps ] = useState({});
const app = useRef(null);
// eslint-disable-next-line arrow-body-style
useImperativeHandle(ref, () => ({
close: () => {
const dispatch = app.current.state.store.dispatch;
dispatch(appNavigate(undefined));
},
setAudioMuted: muted => {
const dispatch = app.current.state.store.dispatch;
dispatch(setAudioMuted(muted));
},
setVideoMuted: muted => {
const dispatch = app.current.state.store.dispatch;
dispatch(setVideoMuted(muted));
}
}));
useEffect(
() => {
const url = convertPropsToURL(meetingOptions.domain, meetingOptions.roomName);
setAppProps({
'url': {
url,
config: meetingOptions.settings
},
'rnSdkHandlers': {
onReadyToClose: meetingOptions.onReadyToClose,
onConferenceJoined: meetingOptions.onConferenceJoined,
onConferenceWillJoin: meetingOptions.onConferenceWillJoin,
onConferenceLeft: meetingOptions.onConferenceLeft,
onParticipantJoined: meetingOptions.onParticipantJoined
},
'flags': { ...flags }
});
}, []
);
return (
<View style = { style }>
<JitsiThemePaperProvider>
{/* @ts-ignore */}
<App
{ ...appProps }
ref = { app } />
</JitsiThemePaperProvider>
</View>
);
});
export default JitsiMeet;

View File

@@ -1,7 +0,0 @@
module.exports = {
androidSourcePath: '../android/sdk/src/main/java/org/jitsi/meet/sdk',
androidTargetPath: './android/src/main/java/org/jitsi/meet/sdk',
iosSrcPath: '../ios/sdk/src',
iosDestPath: './ios/src'
};

View File

@@ -1,8 +0,0 @@
/**
* Converts the meetingOptions domain and roomName to a URL that can be passed to the App component.
* @param {*} domain domain address from props.
* @param {*} roomName room name from props.
*/
export function convertPropsToURL(domain, roomName) {
return `${domain}/${roomName}`;
}

View File

@@ -1,26 +0,0 @@
require 'json'
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
Pod::Spec.new do |s|
s.name = package['name']
s.version = package['version']
s.summary = package['description']
s.description = package['description']
s.license = package['license']
s.author = package['author']
s.homepage = package['homepage']
s.source = { :git => package['repository']['url'], :tag => s.version }
s.requires_arc = true
s.platform = :ios, '12.4'
s.preserve_paths = 'ios/**/*'
s.source_files = 'ios/**/*.{h,m,swift}'
s.dependency 'React-Core'
s.dependency 'ObjectiveDropboxOfficial', '6.2.3'
s.dependency 'JitsiWebRTC', '~> 111.0.0'
end

File diff suppressed because it is too large Load Diff

View File

@@ -1,107 +0,0 @@
{
"name": "@jitsi/react-native-sdk",
"version": "0.1.0",
"description": "React Native SDK for Jitsi Meet.",
"main": "index.js",
"license": "Apache-2.0",
"author": "",
"homepage": "https://jitsi.org",
"repository": {
"type": "git",
"url": "git://github.com/jitsi/jitsi-meet.git"
},
"dependencies": {
"@amplitude/react-native": "2.7.0",
"@giphy/react-components": "6.8.1",
"@giphy/react-native-sdk": "2.3.0",
"@hapi/bourne": "2.0.0",
"@jitsi/js-utils": "2.0.5",
"@jitsi/logger": "2.0.0",
"@jitsi/rtcstats": "9.5.1",
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
"@react-navigation/bottom-tabs": "6.5.3",
"@react-navigation/elements": "1.3.13",
"@react-navigation/material-top-tabs": "6.5.2",
"@react-navigation/native": "6.1.2",
"@react-navigation/stack": "6.3.11",
"@xmldom/xmldom": "0.8.7",
"base64-js": "1.3.1",
"grapheme-splitter": "1.0.4",
"i18n-iso-countries": "6.8.0",
"i18next": "17.0.6",
"i18next-browser-languagedetector": "3.0.1",
"i18next-xhr-backend": "3.0.0",
"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/v1643.0.0+0748d89a/lib-jitsi-meet.tgz",
"lodash": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",
"optional-require": "1.0.3",
"promise.allsettled": "1.0.4",
"punycode": "2.1.1",
"react-emoji-render": "1.2.4",
"react-i18next": "10.11.4",
"react-linkify": "1.0.0-alpha",
"react-redux": "7.1.0",
"react-window": "1.8.6",
"react-youtube": "10.1.0",
"redux": "4.0.4",
"redux-thunk": "2.4.1",
"unorm": "1.6.0",
"util": "0.12.1",
"uuid": "8.3.2",
"zxcvbn": "4.4.2"
},
"peerDependencies": {
"@react-native-async-storage/async-storage": "1.17.3",
"@react-native-community/clipboard": "1.5.1",
"@react-native-community/netinfo": "7.1.7",
"@react-native-community/slider": "4.1.12",
"@react-native-google-signin/google-signin": "7.0.4",
"@react-native-masked-view/masked-view": "0.2.6",
"react-native": "*",
"react": "*",
"react-dom": "*",
"react-native-background-timer": "2.4.1",
"react-native-calendar-events": "2.2.0",
"react-native-callstats": "3.73.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-get-random-values": "1.7.2",
"react-native-immersive": "2.0.0",
"react-native-keep-awake": "4.0.0",
"react-native-pager-view": "5.4.9",
"react-native-paper": "4.11.1",
"react-native-performance": "2.1.0",
"react-native-orientation-locker": "1.5.0",
"react-native-sound": "0.11.1",
"react-native-splash-screen": "3.3.0",
"react-native-svg": "12.4.3",
"react-native-svg-transformer": "1.0.0",
"react-native-tab-view": "3.1.1",
"react-native-url-polyfill": "1.3.0",
"react-native-video": "https://git@github.com/react-native-video/react-native-video#7c48ae7c8544b2b537fb60194e9620b9fcceae52",
"react-native-watch-connectivity": "1.0.11",
"react-native-webrtc": "111.0.0",
"react-native-webview": "11.15.1",
"react-native-youtube-iframe": "2.2.1"
},
"overrides": {
"strophe.js@1.5.0": {
"@xmldom/xmldom": "0.8.7"
}
},
"scripts": {
"prepare": "node prepare_sdk.js"
},
"bugs": {
"url": "https://github.com/jitsi/jitsi-meet/issues"
},
"keywords": [
"react-native"
]
}

View File

@@ -1,214 +0,0 @@
const fs = require('fs');
const path = require('path');
const packageJSON = require('../package.json');
const {
androidSourcePath,
androidTargetPath,
iosDestPath,
iosSrcPath
} = require('./constants.ts');
const SDKPackageJSON = require('./package.json');
/**
* Copies a specified file in a way that recursive copy is possible.
*/
function copyFileSync(source, target) {
let targetFile = target;
// If target is a directory, a new file with the same name will be created
if (fs.existsSync(target)) {
if (fs.lstatSync(target).isDirectory()) {
targetFile = path.join(target, path.basename(source));
}
}
fs.copyFileSync(source, targetFile);
}
/**
* Copies a specified directory recursively.
*/
function copyFolderRecursiveSync(source, target) {
let files = [];
const targetFolder = path.join(target, path.basename(source));
if (!fs.existsSync(targetFolder)) {
fs.mkdirSync(targetFolder, { recursive: true });
}
if (fs.lstatSync(source).isDirectory()) {
files = fs.readdirSync(source);
files.forEach(file => {
const curSource = path.join(source, file);
if (fs.lstatSync(curSource).isDirectory()) {
copyFolderRecursiveSync(curSource, targetFolder);
} else {
copyFileSync(curSource, targetFolder);
}
});
}
}
/**
* Merges the dependency versions from the root package.json with the dependencies of the SDK package.json.
*/
function mergeDependencyVersions() {
for (const key in SDKPackageJSON.dependencies) {
if (SDKPackageJSON.dependencies.hasOwnProperty(key)) {
SDKPackageJSON.dependencies[key] = packageJSON.dependencies[key] || packageJSON.devDependencies[key];
}
}
const data = JSON.stringify(SDKPackageJSON, null, 4);
fs.writeFileSync('package.json', data);
}
// TODO: put this in a seperate step
mergeDependencyVersions();
copyFolderRecursiveSync(
'../images',
'.'
);
copyFolderRecursiveSync(
'../sounds',
'.'
);
copyFolderRecursiveSync(
'../lang',
'.'
);
copyFolderRecursiveSync(
'../modules',
'.'
);
copyFolderRecursiveSync(
'../react',
'.'
);
copyFolderRecursiveSync(
'../service',
'.'
);
copyFolderRecursiveSync(
'../ios/sdk/sdk.xcodeproj',
'./ios'
);
copyFolderRecursiveSync(
`${iosSrcPath}/callkit`,
iosDestPath
);
copyFolderRecursiveSync(
`${iosSrcPath}/dropbox`,
iosDestPath
);
copyFolderRecursiveSync(
'../ios/sdk/src/picture-in-picture',
iosDestPath
);
fs.copyFileSync(
`${iosSrcPath}/AppInfo.m`,
`${iosDestPath}/AppInfo.m`
);
fs.copyFileSync(
`${iosSrcPath}/AudioMode.m`,
`${iosDestPath}/AudioMode.m`
);
fs.copyFileSync(
`${iosSrcPath}/InfoPlistUtil.m`,
`${iosDestPath}/InfoPlistUtil.m`
);
fs.copyFileSync(
`${iosSrcPath}/InfoPlistUtil.h`,
`${iosDestPath}/InfoPlistUtil.h`
);
fs.copyFileSync(
`${iosSrcPath}/JavaScriptSandbox.m`,
`${iosDestPath}/JavaScriptSandbox.m`
);
fs.copyFileSync(
`${iosSrcPath}/JitsiAudioSession.m`,
`${iosDestPath}/JitsiAudioSession.m`
);
fs.copyFileSync(
`${iosSrcPath}/JitsiAudioSession.h`,
`${iosDestPath}/JitsiAudioSession.h`
);
fs.copyFileSync(
`${iosSrcPath}/JitsiAudioSession+Private.h`,
`${iosDestPath}/JitsiAudioSession+Private.h`
);
fs.copyFileSync(
`${iosSrcPath}/LocaleDetector.m`,
`${iosDestPath}/LocaleDetector.m`
);
fs.copyFileSync(
`${iosSrcPath}/POSIX.m`,
`${iosDestPath}/POSIX.m`
);
fs.copyFileSync(
`${iosSrcPath}/Proximity.m`,
`${iosDestPath}/Proximity.m`
);
copyFolderRecursiveSync(
`${androidSourcePath}/log`,
`${androidTargetPath}/log`
);
copyFolderRecursiveSync(
`${androidSourcePath}/net`,
`${androidTargetPath}/log`
);
fs.copyFileSync(
`${androidSourcePath}/AndroidSettingsModule.java`,
`${androidTargetPath}/AndroidSettingsModule.java`
);
fs.copyFileSync(
`${androidSourcePath}/AppInfoModule.java`,
`${androidTargetPath}/AppInfoModule.java`
);
fs.copyFileSync(
`${androidSourcePath}/AudioDeviceHandlerConnectionService.java`,
`${androidTargetPath}/AudioDeviceHandlerConnectionService.java`
);
fs.copyFileSync(
`${androidSourcePath}/AudioDeviceHandlerGeneric.java`,
`${androidTargetPath}/AudioDeviceHandlerGeneric.java`
);
fs.copyFileSync(
`${androidSourcePath}/AudioModeModule.java`,
`${androidTargetPath}/AudioModeModule.java`
);
fs.copyFileSync(
`${androidSourcePath}/ConnectionService.java`,
`${androidTargetPath}/ConnectionService.java`
);
fs.copyFileSync(
`${androidSourcePath}/JavaScriptSandboxModule.java`,
`${androidTargetPath}/JavaScriptSandboxModule.java`
);
fs.copyFileSync(
`${androidSourcePath}/LocaleDetector.java`,
`${androidTargetPath}/LocaleDetector.java`
);
fs.copyFileSync(
`${androidSourcePath}/LogBridgeModule.java`,
`${androidTargetPath}/LogBridgeModule.java`
);
fs.copyFileSync(
`${androidSourcePath}/PictureInPictureModule.java`,
`${androidTargetPath}/PictureInPictureModule.java`
);
fs.copyFileSync(
`${androidSourcePath}/ProximityModule.java`,
`${androidTargetPath}/ProximityModule.java`
);
fs.copyFileSync(
`${androidSourcePath}/RNConnectionService.java`,
`${androidTargetPath}/RNConnectionService.java`
);

View File

@@ -26,5 +26,10 @@ module.exports = {
ios: null
}
}
},
project: {
ios: {
project: '.ios/jitsi-meet.xcworkspace'
}
}
};

View File

@@ -1,6 +1,7 @@
module.exports = {
'extends': [
'../.eslintrc.js',
'@jitsi/eslint-config/flow',
'@jitsi/eslint-config/jsdoc',
'@jitsi/eslint-config/react',
'.eslintrc-react-native.js'
@@ -29,10 +30,15 @@ module.exports = {
}
],
'rules': {
'flowtype/no-types-missing-file-annotation': 0,
// XXX remove this eventually.
'react/jsx-indent-props': 0
},
'settings': {
'flowtype': {
'onlyFilesWithFlowAnnotation': true
},
'react': {
'version': 'detect'
}

View File

@@ -1,3 +1,5 @@
// @flow
import React, { Component } from 'react';
// We need to reference these files directly to avoid loading things that are not available
@@ -17,15 +19,15 @@ const TOOLBAR_TIMEOUT = 4000;
/**
* The type of the React {@code Component} state of {@link AlwaysOnTop}.
*/
interface IState {
avatarURL: string;
customAvatarBackgrounds: Array<string>;
displayName: string;
formattedDisplayName: string;
isVideoDisplayed: boolean;
userID: string;
visible: boolean;
}
type State = {
avatarURL: string,
customAvatarBackgrounds: Array<string>,
displayName: string,
formattedDisplayName: string,
isVideoDisplayed: boolean,
userID: string,
visible: boolean
};
/**
* Represents the always on top page.
@@ -33,7 +35,7 @@ interface IState {
* @class AlwaysOnTop
* @augments Component
*/
export default class AlwaysOnTop extends Component<any, IState> {
export default class AlwaysOnTop extends Component<*, State> {
_hovered: boolean;
/**
@@ -42,7 +44,7 @@ export default class AlwaysOnTop extends Component<any, IState> {
* @param {*} props - The read-only properties with which the new instance
* is to be initialized.
*/
constructor(props: any) {
constructor(props: *) {
super(props);
this.state = {
@@ -66,25 +68,28 @@ export default class AlwaysOnTop extends Component<any, IState> {
this._onMouseOver = this._onMouseOver.bind(this);
}
_avatarChangedListener: () => void;
/**
* Handles avatar changed api events.
*
* @returns {void}
*/
_avatarChangedListener({ avatarURL, id }: { avatarURL: string; id: string; }) {
_avatarChangedListener({ avatarURL, id }) {
if (api._getOnStageParticipant() === id
&& avatarURL !== this.state.avatarURL) {
this.setState({ avatarURL });
}
}
_displayNameChangedListener: () => void;
/**
* Handles display name changed api events.
*
* @returns {void}
*/
_displayNameChangedListener({ displayname, formattedDisplayName, id }: { displayname: string;
formattedDisplayName: string; id: string; }) {
_displayNameChangedListener({ displayname, formattedDisplayName, id }) {
if (api._getOnStageParticipant() === id
&& (formattedDisplayName !== this.state.formattedDisplayName
|| displayname !== this.state.displayName)) {
@@ -113,6 +118,8 @@ export default class AlwaysOnTop extends Component<any, IState> {
TOOLBAR_TIMEOUT);
}
_videoChangedListener: () => void;
/**
* Handles large video changed api events.
*
@@ -134,6 +141,8 @@ export default class AlwaysOnTop extends Component<any, IState> {
});
}
_mouseMove: () => void;
/**
* Handles mouse move events.
*
@@ -143,6 +152,8 @@ export default class AlwaysOnTop extends Component<any, IState> {
this.state.visible || this.setState({ visible: true });
}
_onMouseOut: () => void;
/**
* Toolbar mouse out handler.
*
@@ -152,6 +163,8 @@ export default class AlwaysOnTop extends Component<any, IState> {
this._hovered = false;
}
_onMouseOver: () => void;
/**
* Toolbar mouse over handler.
*
@@ -216,7 +229,7 @@ export default class AlwaysOnTop extends Component<any, IState> {
this._hideToolbarAfterTimeout();
api.getCustomAvatarBackgrounds()
.then((res: { avatarBackgrounds?: string[]; }) =>
.then(res =>
this.setState({
customAvatarBackgrounds: res.avatarBackgrounds || []
}))
@@ -229,7 +242,7 @@ export default class AlwaysOnTop extends Component<any, IState> {
* @inheritdoc
* @returns {void}
*/
componentDidUpdate(_prevProps: any, prevState: IState) {
componentDidUpdate(prevProps: *, prevState: State) {
if (!prevState.visible && this.state.visible) {
this._hideToolbarAfterTimeout();
}

View File

@@ -1,9 +1,11 @@
// @flow
import React, { Component } from 'react';
// We need to reference these files directly to avoid loading things that are not available
// in this environment (e.g. JitsiMeetJS or interfaceConfig)
import { IconMic, IconMicSlash } from '../base/icons/svg';
import { IProps } from '../base/toolbox/components/AbstractButton';
import type { Props } from '../base/toolbox/components/AbstractButton';
import ToolbarButton from './ToolbarButton';
@@ -12,25 +14,23 @@ const { api } = window.alwaysOnTop;
/**
* The type of the React {@code Component} state of {@link AudioMuteButton}.
*/
interface IState {
type State = {
/**
* Whether audio is available is not.
*/
audioAvailable: boolean;
audioAvailable: boolean,
/**
* Whether audio is muted or not.
*/
audioMuted: boolean;
}
type Props = Partial<IProps>;
audioMuted: boolean
};
/**
* Stateless "mute/unmute audio" button for the Always-on-Top windows.
*/
export default class AudioMuteButton extends Component<Props, IState> {
export default class AudioMuteButton extends Component<Props, State> {
icon = IconMic;
toggledIcon = IconMicSlash;
accessibilityLabel = 'Audio mute';
@@ -38,7 +38,7 @@ export default class AudioMuteButton extends Component<Props, IState> {
/**
* Initializes a new {@code AudioMuteButton} instance.
*
* @param {IProps} props - The React {@code Component} props to initialize
* @param {Props} props - The React {@code Component} props to initialize
* the new {@code AudioMuteButton} instance with.
*/
constructor(props: Props) {
@@ -94,23 +94,27 @@ export default class AudioMuteButton extends Component<Props, IState> {
this._audioMutedListener);
}
_audioAvailabilityListener: ({ available: boolean }) => void;
/**
* Handles audio available api events.
*
* @param {{ available: boolean }} status - The new available status.
* @returns {void}
*/
_audioAvailabilityListener({ available }: { available: boolean; }) {
_audioAvailabilityListener({ available }) {
this.setState({ audioAvailable: available });
}
_audioMutedListener: ({ muted: boolean }) => void;
/**
* Handles audio muted api events.
*
* @param {{ muted: boolean }} status - The new muted status.
* @returns {void}
*/
_audioMutedListener({ muted }: { muted: boolean; }) {
_audioMutedListener({ muted }) {
this.setState({ audioMuted: muted });
}
@@ -140,14 +144,16 @@ export default class AudioMuteButton extends Component<Props, IState> {
* Changes the muted state.
*
* @override
* @param {boolean} _audioMuted - Whether audio should be muted or not.
* @param {boolean} audioMuted - Whether audio should be muted or not.
* @protected
* @returns {void}
*/
_setAudioMuted(_audioMuted: boolean) {
_setAudioMuted(audioMuted: boolean) { // eslint-disable-line no-unused-vars
this.state.audioAvailable && api.executeCommand('toggleAudio');
}
_onClick: () => {};
/**
* Handles clicking / pressing the button, and toggles the audio mute state
* accordingly.
@@ -167,13 +173,11 @@ export default class AudioMuteButton extends Component<Props, IState> {
render() {
const toggled = this._isAudioMuted();
return (
<ToolbarButton
accessibilityLabel = { this.accessibilityLabel }
disabled = { this._isDisabled() }
icon = { toggled ? this.toggledIcon : this.icon }
onClick = { this._onClick }
toggled = { toggled } />
);
return (<ToolbarButton
accessibilityLabel = { this.accessibilityLabel }
disabled = { this._isDisabled() }
icon = { toggled ? this.toggledIcon : this.icon }
onClick = { this._onClick }
toggled = { toggled } />);
}
}

View File

@@ -1,20 +1,19 @@
// @flow
import React, { Component } from 'react';
// We need to reference these files directly to avoid loading things that are not available
// in this environment (e.g. JitsiMeetJS or interfaceConfig)
import { IconHangup } from '../base/icons/svg';
import { IProps } from '../base/toolbox/components/AbstractButton';
import type { Props } from '../base/toolbox/components/AbstractButton';
import ToolbarButton from './ToolbarButton';
const { api } = window.alwaysOnTop;
type Props = Partial<IProps>;
/**
* Stateless hangup button for the Always-on-Top windows.
*/
export default class HangupButton extends Component<Props> {
export default class HangupButton extends Component<Props, *> {
accessibilityLabel = 'Hangup';
icon = IconHangup;
@@ -22,7 +21,7 @@ export default class HangupButton extends Component<Props> {
/**
* Initializes a new {@code HangupButton} instance.
*
* @param {IProps} props - The React {@code Component} props to initialize
* @param {Props} props - The React {@code Component} props to initialize
* the new {@code HangupButton} instance with.
*/
constructor(props: Props) {
@@ -32,6 +31,8 @@ export default class HangupButton extends Component<Props> {
this._onClick = this._onClick.bind(this);
}
_onClick: () => {};
/**
* Handles clicking / pressing the button, and disconnects the conference.
*
@@ -49,12 +50,10 @@ export default class HangupButton extends Component<Props> {
* @returns {ReactElement}
*/
render() {
return (
<ToolbarButton
accessibilityLabel = { this.accessibilityLabel }
customClass = 'hangup-button'
icon = { this.icon }
onClick = { this._onClick } />
);
return (<ToolbarButton
accessibilityLabel = { this.accessibilityLabel }
customClass = 'hangup-button'
icon = { this.icon }
onClick = { this._onClick } />);
}
}

View File

@@ -1,3 +1,5 @@
// @flow
import React, { Component } from 'react';
import AudioMuteButton from './AudioMuteButton';
@@ -7,30 +9,30 @@ import VideoMuteButton from './VideoMuteButton';
/**
* The type of the React {@code Component} props of {@link Toolbar}.
*/
interface IProps {
type Props = {
/**
* Additional CSS class names to add to the root of the toolbar.
*/
className: string;
className: string,
/**
* Callback invoked when no longer moused over the toolbar.
*/
onMouseOut: (e?: React.MouseEvent) => void;
onMouseOut: Function,
/**
* Callback invoked when the mouse has moved over the toolbar.
*/
onMouseOver: (e?: React.MouseEvent) => void;
}
onMouseOver: Function
};
/**
* Represents the toolbar in the Always On Top window.
*
* @augments Component
*/
export default class Toolbar extends Component<IProps> {
export default class Toolbar extends Component<Props> {
/**
* Implements React's {@link Component#render()}.
*

View File

@@ -2,38 +2,38 @@ import React, { useCallback } from 'react';
import Icon from '../base/icons/components/Icon';
interface IProps {
type Props = {
/**
* Accessibility label for button.
*/
accessibilityLabel: string;
accessibilityLabel: string,
/**
* An extra class name to be added at the end of the element's class name
* in order to enable custom styling.
*/
customClass?: string;
customClass?: string,
/**
* Whether or not the button is disabled.
*/
disabled?: boolean;
/**
* Button icon.
*/
icon: Function;
disabled?: boolean,
/**
* Click handler.
*/
onClick: (e?: React.MouseEvent) => void;
onClick: Function,
/**
* Button icon.
*/
icon: Object,
/**
* Whether or not the button is toggled.
*/
toggled?: boolean;
toggled?: boolean
}
const ToolbarButton = ({
@@ -43,7 +43,7 @@ const ToolbarButton = ({
onClick,
icon,
toggled = false
}: IProps) => {
}: Props) => {
const onKeyPress = useCallback(event => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();

View File

@@ -1,16 +1,15 @@
// @flow
import React, { Component } from 'react';
// We need to reference these files directly to avoid loading things that are not available
// in this environment (e.g. JitsiMeetJS or interfaceConfig)
import { IconVideo, IconVideoOff } from '../base/icons/svg';
import { IProps } from '../base/toolbox/components/AbstractButton';
import type { Props } from '../base/toolbox/components/AbstractButton';
import ToolbarButton from './ToolbarButton';
const { api } = window.alwaysOnTop;
type Props = Partial<IProps>;
/**
* The type of the React {@code Component} state of {@link VideoMuteButton}.
*/
@@ -19,12 +18,12 @@ type State = {
/**
* Whether video is available is not.
*/
videoAvailable: boolean;
videoAvailable: boolean,
/**
* Whether video is muted or not.
*/
videoMuted: boolean;
videoMuted: boolean
};
/**
@@ -120,34 +119,40 @@ export default class VideoMuteButton extends Component<Props, State> {
* Changes the muted state.
*
* @override
* @param {boolean} _videoMuted - Whether video should be muted or not.
* @param {boolean} videoMuted - Whether video should be muted or not.
* @protected
* @returns {void}
*/
_setVideoMuted(_videoMuted: boolean) {
_setVideoMuted(videoMuted: boolean) { // eslint-disable-line no-unused-vars
this.state.videoAvailable && api.executeCommand('toggleVideo', false, true);
}
_videoAvailabilityListener: ({ available: boolean }) => void;
/**
* Handles video available api events.
*
* @param {{ available: boolean }} status - The new available status.
* @returns {void}
*/
_videoAvailabilityListener({ available }: { available: boolean; }) {
_videoAvailabilityListener({ available }) {
this.setState({ videoAvailable: available });
}
_videoMutedListener: ({ muted: boolean }) => void;
/**
* Handles video muted api events.
*
* @param {{ muted: boolean }} status - The new muted status.
* @returns {void}
*/
_videoMutedListener({ muted }: { muted: boolean; }) {
_videoMutedListener({ muted }) {
this.setState({ videoMuted: muted });
}
_onClick: () => {};
/**
* Handles clicking / pressing the button, and toggles the video mute state
* accordingly.
@@ -168,13 +173,11 @@ export default class VideoMuteButton extends Component<Props, State> {
render() {
const toggled = this._isVideoMuted();
return (
<ToolbarButton
accessibilityLabel = { this.accessibilityLabel }
disabled = { this._isDisabled() }
icon = { toggled ? this.toggledIcon : this.icon }
onClick = { this._onClick }
toggled = { toggled } />
);
return (<ToolbarButton
accessibilityLabel = { this.accessibilityLabel }
disabled = { this._isDisabled() }
icon = { toggled ? this.toggledIcon : this.icon }
onClick = { this._onClick }
toggled = { toggled } />);
}
}

View File

@@ -1,11 +1,14 @@
// @flow
import React from 'react';
import ReactDOM from 'react-dom';
import AlwaysOnTop from './AlwaysOnTop';
// Render the main/root Component.
// $FlowExpectedError
ReactDOM.render(<AlwaysOnTop />, document.getElementById('react'));
window.addEventListener(
'beforeunload',
() => ReactDOM.unmountComponentAtNode(document.getElementById('react') ?? document.body));
() => ReactDOM.unmountComponentAtNode(document.getElementById('react')));

View File

@@ -173,15 +173,7 @@ export function initAnalytics(store: IStore, handlers: Array<Object>) {
const { group, server } = state['features/base/jwt'];
const { locationURL = { href: '' } } = state['features/base/connection'];
const { tenant } = parseURIString(locationURL.href) || {};
const permanentProperties: {
appName?: string;
externalApi?: boolean;
group?: string;
inIframe?: boolean;
server?: string;
tenant?: string;
websocket?: boolean;
} & typeof deploymentInfo = {};
const permanentProperties: any = {};
if (server) {
permanentProperties.server = server;
@@ -210,8 +202,7 @@ export function initAnalytics(store: IStore, handlers: Array<Object>) {
if (deploymentInfo) {
for (const key in deploymentInfo) {
if (deploymentInfo.hasOwnProperty(key)) {
permanentProperties[key as keyof typeof deploymentInfo] = deploymentInfo[
key as keyof typeof deploymentInfo];
permanentProperties[key] = deploymentInfo[key as keyof typeof deploymentInfo];
}
}
}
@@ -244,7 +235,7 @@ export function initAnalytics(store: IStore, handlers: Array<Object>) {
* @returns {Promise} Resolves with the handlers that have been successfully loaded and rejects if there are no handlers
* loaded or the analytics is disabled.
*/
function _loadHandlers(scriptURLs: string[] = [], handlerConstructorOptions: Object) {
function _loadHandlers(scriptURLs: any[] = [], handlerConstructorOptions: Object) {
const promises: Promise<{ error?: Error; type: string; url?: string; }>[] = [];
for (const url of scriptURLs) {

View File

@@ -1,4 +1,3 @@
import { Amplitude } from '@amplitude/react-native';
import DefaultPreference from 'react-native-default-preference';
import DeviceInfo from 'react-native-device-info';
@@ -8,7 +7,7 @@ import DeviceInfo from 'react-native-device-info';
* @param {AmplitudeClient} amplitude - The amplitude instance.
* @returns {void}
*/
export async function fixDeviceID(amplitude: Amplitude) {
export async function fixDeviceID(amplitude: any) {
await DefaultPreference.setName('jitsi-preferences');
const current = await DefaultPreference.get('amplitudeDeviceId');

View File

@@ -1,11 +1,9 @@
import { AmplitudeClient } from 'amplitude-js';
/**
* Custom logic for setting the correct device id.
*
* @param {AmplitudeClient} _amplitude - The amplitude instance.
* @returns {void}
*/
export function fixDeviceID(_amplitude: AmplitudeClient): Promise<any> {
export function fixDeviceID(_amplitude: any): Promise<any> {
return new Promise(resolve => resolve(true));
}

View File

@@ -1,3 +1,4 @@
/* eslint-disable lines-around-comment */
import { setRoom } from '../base/conference/actions';
import {
configWillLoad,
@@ -8,11 +9,10 @@ import {
import {
createFakeConfig,
restoreConfig
} from '../base/config/functions.native';
import { connect, disconnect, setLocationURL } from '../base/connection/actions.native';
} from '../base/config/functions';
import { connect, disconnect, setLocationURL } from '../base/connection/actions';
import { loadConfig } from '../base/lib-jitsi-meet/functions.native';
import { createDesiredLocalTracks } from '../base/tracks/actions.native';
import isInsecureRoomName from '../base/util/isInsecureRoomName';
import { createDesiredLocalTracks } from '../base/tracks/actions';
import { parseURLParams } from '../base/util/parseURLParams';
import {
appendURLParam,
@@ -20,14 +20,16 @@ import {
parseURIString,
toURLString
} from '../base/util/uri';
// @ts-ignore
import { isPrejoinPageEnabled } from '../mobile/navigation/functions';
import {
goBackToRoot,
navigateRoot
// @ts-ignore
} from '../mobile/navigation/rootNavigationContainerRef';
// @ts-ignore
import { screen } from '../mobile/navigation/routes';
import { clearNotifications } from '../notifications/actions';
import { isUnsafeRoomWarningEnabled } from '../prejoin/functions';
import { addTrackStateToURL, getDefaultURL } from './functions.native';
import logger from './logger';
@@ -53,7 +55,7 @@ export function appNavigate(uri?: string, options: IReloadNowOptions = {}) {
// If the specified location (URI) does not identify a host, use the app's
// default.
if (!location?.host) {
if (!location || !location.host) {
const defaultLocation = parseURIString(getDefaultURL(getState));
if (location) {
@@ -138,14 +140,10 @@ export function appNavigate(uri?: string, options: IReloadNowOptions = {}) {
dispatch(setRoom(room));
if (room) {
if (isUnsafeRoomWarningEnabled(getState()) && isInsecureRoomName(room)) {
navigateRoot(screen.unsafeRoomWarning);
return;
}
dispatch(createDesiredLocalTracks());
dispatch(clearNotifications());
// @ts-ignore
const { hidePrejoin } = options;
if (!hidePrejoin && isPrejoinPageEnabled(getState())) {

View File

@@ -49,7 +49,7 @@ export function appNavigate(uri?: string) {
// If the specified location (URI) does not identify a host, use the app's
// default.
if (!location?.host) {
if (!location || !location.host) {
const defaultLocation = parseURIString(getDefaultURL(getState));
if (location) {
@@ -129,6 +129,14 @@ export function appNavigate(uri?: string) {
dispatch(setLocationURL(locationURL));
dispatch(setConfig(config));
if (inIframe() && getState()['features/base/config'].disableIframeAPI) {
// in case iframeAPI is disabled redirect to the promotional page
dispatch(redirectToStaticPage('static/close3.html', `#jitsi_meet_external_api_id=${API_ID}`));
return;
}
dispatch(setRoom(room));
};
}

View File

@@ -12,7 +12,7 @@ export interface IProps {
* XXX Refer to the implementation of loadURLObject: in
* ios/sdk/src/JitsiMeetView.m for further information.
*/
timestamp: number;
timestamp: any;
/**
* The URL, if any, with which the app was launched.

View File

@@ -42,7 +42,7 @@ export class App extends AbstractApp {
*
* @override
*/
_createMainElement(component: React.ComponentType, props?: Object) {
_createMainElement(component: React.ComponentType, props: any) {
return (
<JitsiThemeProvider>
<GlobalStyles />

View File

@@ -5,6 +5,8 @@ import { IStateful } from '../base/app/types';
import { isRoomValid } from '../base/conference/functions';
import { isSupportedBrowser } from '../base/environment/environment';
import { toState } from '../base/redux/functions';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import Conference from '../conference/components/web/Conference';
import { getDeepLinkingPage } from '../deep-linking/functions';
import UnsupportedDesktopBrowser from '../unsupported-browser/components/UnsupportedDesktopBrowser';

View File

@@ -10,7 +10,6 @@ import '../mobile/navigation/middleware';
import '../mobile/permissions/middleware';
import '../mobile/proximity/middleware';
import '../mobile/wake-lock/middleware';
import '../mobile/react-native-sdk/middleware';
import '../mobile/watchos/middleware';
import '../share-room/middleware';
import '../shared-video/middleware';

View File

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

View File

@@ -1,10 +1,8 @@
import '../base/devices/reducer';
import '../base/premeeting/reducer';
import '../base/tooltip/reducer';
import '../e2ee/reducer';
import '../face-landmarks/reducer';
import '../feedback/reducer';
import '../keyboard-shortcuts/reducer';
import '../no-audio-signal/reducer';
import '../noise-detection/reducer';
import '../participants-pane/reducer';

View File

@@ -20,7 +20,6 @@ import { ILoggingState } from '../base/logging/reducer';
import { IMediaState } from '../base/media/reducer';
import { INetInfoState } from '../base/net-info/reducer';
import { IParticipantsState } from '../base/participants/reducer';
import { IPreMeetingState } from '../base/premeeting/types';
import { IResponsiveUIState } from '../base/responsive-ui/reducer';
import { ISettingsState } from '../base/settings/reducer';
import { ISoundsState } from '../base/sounds/reducer';
@@ -44,7 +43,6 @@ import { IGifsState } from '../gifs/reducer';
import { IGoogleApiState } from '../google-api/reducer';
import { IInviteState } from '../invite/reducer';
import { IJaaSState } from '../jaas/reducer';
import { IKeyboardShortcutsState } from '../keyboard-shortcuts/types';
import { ILargeVideoState } from '../large-video/reducer';
import { ILobbyState } from '../lobby/reducer';
import { IMobileAudioModeState } from '../mobile/audio-mode/reducer';
@@ -111,7 +109,6 @@ export interface IReduxState {
'features/base/net-info': INetInfoState;
'features/base/no-src-data': INoSrcDataState;
'features/base/participants': IParticipantsState;
'features/base/premeeting': IPreMeetingState;
'features/base/responsive-ui': IResponsiveUIState;
'features/base/settings': ISettingsState;
'features/base/sounds': ISoundsState;
@@ -136,7 +133,6 @@ export interface IReduxState {
'features/google-api': IGoogleApiState;
'features/invite': IInviteState;
'features/jaas': IJaaSState;
'features/keyboard-shortcuts': IKeyboardShortcutsState;
'features/large-video': ILargeVideoState;
'features/lobby': ILobbyState;
'features/mobile/audio-mode': IMobileAudioModeState;

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