Compare commits

..

5 Commits

Author SHA1 Message Date
Saúl Ibarra Corretgé
5d90107875 android: raise SDK and app versions 2019-09-26 13:25:25 +02:00
Saúl Ibarra Corretgé
2d79e08747 deps: react-native-webrtc@latest
Avoid Android crashes.
2019-09-26 13:24:23 +02:00
Saúl Ibarra Corretgé
f702f828e3 android: fix NPE when handling onHostPause
If the Activity is put into the background before the ReactContext is created we
get an NPE here. While the window might be short, it's thechnically possible to
hit this, as our Crashlytics reports show.
2019-09-26 12:31:50 +02:00
Saúl Ibarra Corretgé
26ffde072e android: raise SDK version 2019-09-20 10:26:41 +02:00
Saúl Ibarra Corretgé
c8b20e037e android: make reportConnectedOutgoingCall return a Promise
The call-integration middleware relies on it returning it, as iOS does.
2019-09-20 10:26:28 +02:00
159 changed files with 3231 additions and 6102 deletions

View File

@@ -11,9 +11,6 @@ node_modules/react-native/Libraries/react-native/React.js
; "node_modules/react-native" but in the source repo it is in the root
node_modules/react-native/Libraries/react-native/React.js
; Flow doesn't support platforms
.*/Libraries/Utilities/LoadingView.js
; Ignore polyfills
node_modules/react-native/Libraries/polyfills/.*
@@ -115,4 +112,4 @@ untyped-import
untyped-type-import
[version]
^0.104.0
^0.98.0

View File

@@ -1,11 +0,0 @@
---
name: Security issues
about: Please email security@jitsi.org
---
We take security very seriously and develop all Jitsi projects to be secure and safe.
If you find (or simply suspect) a security issue in any of the Jitsi projects, please send us an email to security@jitsi.org.
We encourage responsible disclosure for the sake of our users, so please reach out before posting in a public space.

View File

@@ -1,4 +1,4 @@
osx_image: xcode11.1
osx_image: xcode10.2
language: objective-c
script:
- "./ios/travis-ci/build-ipa.sh"

View File

@@ -3,7 +3,6 @@ CLEANCSS = ./node_modules/.bin/cleancss
DEPLOY_DIR = libs
LIBJITSIMEET_DIR = node_modules/lib-jitsi-meet/
LIBFLAC_DIR = node_modules/libflacjs/dist/min/
RNNOISE_WASM_DIR = node_modules/rnnoise-wasm/dist/
NODE_SASS = ./node_modules/.bin/node-sass
NPM = npm
OUTPUT_DIR = .
@@ -21,7 +20,7 @@ compile:
clean:
rm -fr $(BUILD_DIR)
deploy: deploy-init deploy-appbundle deploy-rnnoise-binary deploy-lib-jitsi-meet deploy-libflac deploy-css deploy-local
deploy: deploy-init deploy-appbundle deploy-lib-jitsi-meet deploy-libflac deploy-css deploy-local
deploy-init:
rm -fr $(DEPLOY_DIR)
@@ -48,8 +47,6 @@ deploy-appbundle:
$(BUILD_DIR)/analytics-ga.min.map \
$(BUILD_DIR)/video-blur-effect.min.js \
$(BUILD_DIR)/video-blur-effect.min.map \
$(BUILD_DIR)/rnnoise-processor.min.js \
$(BUILD_DIR)/rnnoise-processor.min.map \
$(DEPLOY_DIR)
deploy-lib-jitsi-meet:
@@ -66,11 +63,6 @@ deploy-libflac:
$(LIBFLAC_DIR)/libflac4-1.3.2.min.js.mem \
$(DEPLOY_DIR)
deploy-rnnoise-binary:
cp \
$(RNNOISE_WASM_DIR)/rnnoise.wasm \
$(DEPLOY_DIR)
deploy-css:
$(NODE_SASS) $(STYLES_MAIN) $(STYLES_BUNDLE) && \
$(CLEANCSS) $(STYLES_BUNDLE) > $(STYLES_DESTINATION) ; \
@@ -79,7 +71,7 @@ deploy-css:
deploy-local:
([ ! -x deploy-local.sh ] || ./deploy-local.sh)
dev: deploy-init deploy-css deploy-rnnoise-binary deploy-lib-jitsi-meet deploy-libflac
dev: deploy-init deploy-css deploy-lib-jitsi-meet deploy-libflac
$(WEBPACK_DEV_SERVER)
source-package:

View File

@@ -31,9 +31,82 @@ You can get our mobile versions from here:
* [Android](https://play.google.com/store/apps/details?id=org.jitsi.meet)
* [iOS](https://itunes.apple.com/us/app/jitsi-meet/id1165103905)
## Development
## Building the sources
For web development see [here](doc/development.md), and for mobile see [here](doc/mobile.md).
Node.js >= 10 and npm >= 6 are required.
On Debian/Ubuntu systems, the required packages can be installed with:
```
sudo apt-get install npm nodejs
cd jitsi-meet
npm install
```
To build the Jitsi Meet application, just type
```
make
```
### Working with the library sources (lib-jitsi-meet)
By default the library is build from its git repository sources. The default dependency path in package.json is :
```json
"lib-jitsi-meet": "jitsi/lib-jitsi-meet",
```
To work with local copy you must change the path to:
```json
"lib-jitsi-meet": "file:///Users/name/local-lib-jitsi-meet-copy",
```
To make the project you must force it to take the sources as 'npm update':
```
npm install lib-jitsi-meet --force && make
```
Or if you are making only changes to the library:
```
npm install lib-jitsi-meet --force && make deploy-lib-jitsi-meet
```
Alternative way is to use [npm link](https://docs.npmjs.com/cli/link).
It allows to link `lib-jitsi-meet` dependency to local source in few steps:
```bash
cd lib-jitsi-meet
#### create global symlink for lib-jitsi-meet package
npm link
cd ../jitsi-meet
#### create symlink from the local node_modules folder to the global lib-jitsi-meet symlink
npm link lib-jitsi-meet
```
After changes in local `lib-jitsi-meet` repository, you can rebuild it with `npm run install` and your `jitsi-meet` repository will use that modified library.
Note: when using node version 4.x, the make file of jitsi-meet do npm update which will delete the link. It is no longer the case with version 6.x.
If you do not want to use local repository anymore you should run
```bash
cd jitsi-meet
npm unlink lib-jitsi-meet
npm install
```
### Running with webpack-dev-server for development
Use it at the CLI, type
```
make dev
```
By default the backend deployment used is `beta.meet.jit.si`. You can point the Jitsi-Meet app at a different backend by using a proxy server. To do this, set the WEBPACK_DEV_SERVER_PROXY_TARGET variable:
```
export WEBPACK_DEV_SERVER_PROXY_TARGET=https://your-example-server.com
make dev
```
The app should be running at https://localhost:8080/
## Contributing
@@ -45,8 +118,7 @@ see our [guidelines for contributing](CONTRIBUTING.md).
Jitsi Meet provides a very flexible way of embedding in external applications by using the [Jitsi Meet API](doc/api.md).
## Security
WebRTC does not (yet) provide a way of conducting multi-party conversations with end-to-end encryption.
WebRTC does not provide a way of conducting multi-party conversations with end-to-end encryption.
Unless you consistently compare DTLS fingerprints with your peers vocally, the same goes for one-to-one calls.
As a result, your stream is encrypted on the network but decrypted on the machine that hosts the bridge when using Jitsi Meet.
@@ -58,13 +130,9 @@ Jitsi Meet in terms of security.
The [meet.jit.si](https://meet.jit.si) service is maintained by the Jitsi team
at [8x8](https://8x8.com).
## Security issues
We take security very seriously and develop all Jitsi projects to be secure and safe.
If you find (or simply suspect) a security issue in any of the Jitsi projects, please send us an email to security@jitsi.org.
**We encourage responsible disclosure for the sake of our users, so please reach out before posting in a public space.**
## Mobile app
Jitsi Meet is also available as a React Native app for Android and iOS.
Instructions on how to build it can be found [here](doc/mobile.md).
## Acknowledgements

View File

@@ -20,5 +20,5 @@
android.useAndroidX=true
android.enableJetifier=true
appVersion=19.4.0
sdkVersion=2.4.0
appVersion=19.3.1
sdkVersion=2.3.2

View File

@@ -45,7 +45,6 @@ dependencies {
implementation 'com.dropbox.core:dropbox-core-sdk:3.0.8'
implementation 'com.jakewharton.timber:timber:4.7.1'
implementation 'com.squareup.duktape:duktape-android:1.3.0'
if (!rootProject.ext.libreBuild) {
implementation 'com.amplitude:android-sdk:2.14.1'

View File

@@ -1,57 +0,0 @@
/*
* Copyright @ 2019-present 8x8, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet.sdk;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.module.annotations.ReactModule;
import com.squareup.duktape.Duktape;
@ReactModule(name = JavaScriptSandboxModule.NAME)
class JavaScriptSandboxModule extends ReactContextBaseJavaModule {
public static final String NAME = "JavaScriptSandbox";
public JavaScriptSandboxModule(ReactApplicationContext reactContext) {
super(reactContext);
}
/**
* Evaluates the given code in a Duktape VM.
* @param code - The code that needs to evaluated.
* @param promise - Resolved with the output in case of success or rejected with an exception
* in case of failure.
*/
@ReactMethod
public void evaluate(String code, Promise promise) {
Duktape vm = Duktape.create();
try {
Object res = vm.evaluate(code);
promise.resolve(res.toString());
} catch (Throwable tr) {
promise.reject(tr);
} finally {
vm.close();
}
}
@Override
public String getName() {
return NAME;
}
}

View File

@@ -33,9 +33,6 @@ public class JitsiMeet {
}
public static void setDefaultConferenceOptions(JitsiMeetConferenceOptions options) {
if (options != null && options.getRoom() != null) {
throw new RuntimeException("'room' must be null in the default conference options");
}
defaultConferenceOptions = options;
}

View File

@@ -72,46 +72,6 @@ public class JitsiMeetConferenceOptions implements Parcelable {
*/
private JitsiMeetUserInfo userInfo;
public URL getServerURL() {
return serverURL;
}
public String getRoom() {
return room;
}
public String getSubject() {
return subject;
}
public String getToken() {
return token;
}
public Bundle getColorScheme() {
return colorScheme;
}
public Bundle getFeatureFlags() {
return featureFlags;
}
public boolean getAudioMuted() {
return audioMuted;
}
public boolean getAudioOnly() {
return audioOnly;
}
public boolean getVideoMuted() {
return videoMuted;
}
public JitsiMeetUserInfo getUserInfo() {
return userInfo;
}
/**
* Class used to build the immutable {@link JitsiMeetConferenceOptions} object.
*/

View File

@@ -87,7 +87,7 @@ public class JitsiMeetOngoingConferenceService extends Service
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
final String action = intent.getAction();
if (Actions.START.equals(action)) {
if (action.equals(Actions.START)) {
Notification notification = OngoingNotification.buildOngoingConferenceNotification();
if (notification == null) {
stopSelf();
@@ -96,7 +96,7 @@ public class JitsiMeetOngoingConferenceService extends Service
startForeground(OngoingNotification.NOTIFICATION_ID, notification);
JitsiMeetLogger.i(TAG + " Service started");
}
} else if (Actions.HANGUP.equals(action)) {
} else if (action.equals(Actions.HANGUP)) {
JitsiMeetLogger.i(TAG + " Hangup requested");
// Abort all ongoing calls
if (AudioModeModule.useConnectionService()) {

View File

@@ -67,7 +67,6 @@ class ReactInstanceManagerHolder {
new AudioModeModule(reactContext),
new DropboxModule(reactContext),
new ExternalAPIModule(reactContext),
new JavaScriptSandboxModule(reactContext),
new LocaleDetector(reactContext),
new LogBridgeModule(reactContext),
new PictureInPictureModule(reactContext),

View File

@@ -43,7 +43,7 @@ public class NAT64AddrInfoModule
* The host for which the module wil try to resolve both IPv4 and IPv6
* addresses in order to figure out the NAT64 prefix.
*/
private final static String HOST = "ipv4only.arpa";
private final static String HOST = "nat64.jitsi.net";
/**
* How long is the {@link NAT64AddrInfo} instance valid.

View File

@@ -10,7 +10,7 @@ project(':react-native-community-async-storage').projectDir = new File(rootProje
include ':react-native-community_netinfo'
project(':react-native-community_netinfo').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/netinfo/android')
include ':react-native-google-signin'
project(':react-native-google-signin').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/google-signin/android')
project(':react-native-google-signin').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-google-signin/android')
include ':react-native-immersive'
project(':react-native-immersive').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-immersive/android')
include ':react-native-keep-awake'

View File

@@ -104,6 +104,7 @@ import {
trackRemoved
} from './react/features/base/tracks';
import { getJitsiMeetGlobalNS } from './react/features/base/util';
import { addMessage } from './react/features/chat';
import { showDesktopPicker } from './react/features/desktop-picker';
import { appendSuffix } from './react/features/display-name';
import {
@@ -113,6 +114,7 @@ import {
import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay';
import { suspendDetected } from './react/features/power-monitor';
import { setSharedVideoStatus } from './react/features/shared-video';
import { isButtonEnabled } from './react/features/toolbox';
import { endpointMessageReceived } from './react/features/subtitles';
const logger = require('jitsi-meet-logger').getLogger(__filename);
@@ -242,6 +244,8 @@ class ConferenceConnector {
this._handleConferenceJoined.bind(this));
room.on(JitsiConferenceEvents.CONFERENCE_FAILED,
this._onConferenceFailed.bind(this));
room.on(JitsiConferenceEvents.CONFERENCE_ERROR,
this._onConferenceError.bind(this));
}
/**
@@ -344,6 +348,31 @@ class ConferenceConnector {
}
}
/**
*
*/
_onConferenceError(err, ...params) {
logger.error('CONFERENCE Error:', err, params);
switch (err) {
case JitsiConferenceErrors.CHAT_ERROR:
logger.error('Chat error.', err);
if (isButtonEnabled('chat') && !interfaceConfig.filmStripOnly) {
const [ code, msg ] = params;
APP.store.dispatch(addMessage({
hasRead: true,
error: code,
message: msg,
messageType: 'error',
timestamp: Date.now()
}));
}
break;
default:
logger.error('Unknown error.', err);
}
}
/**
*
*/

View File

@@ -1,6 +1,16 @@
/* eslint-disable no-unused-vars, no-var */
var config = {
// Configuration
//
// Alternative location for the configuration.
// configLocation: './config.json',
// Custom function which given the URL path should return a room name.
// getroomnode: function (path) { return 'someprefixpossiblybasedonpath'; },
// Connection
//
@@ -50,10 +60,6 @@ var config = {
// Enables the test specific features consumed by jitsi-meet-torture
// testMode: false
// Disables the auto-play behavior of *all* newly created video element.
// This is useful when the client runs on a host with limited resources.
// noAutoPlayVideo: false
},
// Disables ICE/UDP by filtering out local and remote UDP candidates in
@@ -419,10 +425,6 @@ var config = {
// the menu has option to flip the locally seen video for local presentations
// disableLocalVideoFlip: false
// If specified a 'Help' button will be displayed in the overflow menu with a link to the specified URL for
// user documentation.
// userDocumentationURL: 'https://docs.example.com/video-meetings.html'
// List of undocumented settings used in jitsi-meet
/**
_immediateReloadThreshold

View File

@@ -33,7 +33,7 @@ body {
}
}
.jitsi-icon svg {
svg {
fill: white;
}

View File

@@ -80,27 +80,6 @@
}
}
#chat-recipient {
align-items: center;
background-color: $defaultWarningColor;
display: flex;
flex-direction: row;
padding: 10px;
span {
color: white;
display: flex;
flex: 1;
}
div {
svg {
cursor: pointer;
fill: white
}
}
}
.chat-header {
background-color: $chatHeaderBackgroundColor;
height: 70px;
@@ -217,11 +196,6 @@
padding: 0;
}
}
.privatemessagenotice {
color: $defaultWarningColor;
font-style: italic;
}
}
.smiley {
@@ -254,7 +228,6 @@
.smileys-panel {
bottom: 100%;
box-sizing: border-box;
background-color: rgba(0, 0, 0, .6) !important;
height: auto;
max-height: 0;
overflow: hidden;
@@ -339,16 +312,6 @@
.chatmessage-wrapper {
max-width: 100%;
.replywrapper {
display: flex;
flex-direction: row;
align-items: center;
.toolbox-icon {
cursor: pointer;
}
}
}
.chatmessage {

View File

@@ -6,7 +6,7 @@
min-width: 75px;
text-align: left;
padding: 0px;
width: 180px;
width: 150px;
white-space: nowrap;
&__item {
@@ -87,7 +87,6 @@
display: inline-block;
min-width: 20px;
height: 100%;
padding-right: 10px;
> * {
@include absoluteAligning();

View File

@@ -28,7 +28,6 @@ $defaultColor: #F1F1F1;
$defaultSideBarFontColor: #44A5FF;
$defaultSemiDarkColor: #ACACAC;
$defaultDarkColor: #2b3d5c;
$defaultWarningColor: rgb(215, 121, 118);
/**
* Toolbar
@@ -164,45 +163,9 @@ $watermarkHeight: 74px;
*/
$welcomePageDescriptionColor: #fff;
$welcomePageFontFamily: inherit;
$welcomePageBackground: linear-gradient(-90deg, #1251AE 0%, #0074FF 50%, #1251AE 100%);
$welcomePageHeaderBackground: linear-gradient(-90deg, #1251AE 0%, #0074FF 50%, #1251AE 100%);
$welcomePageTitleColor: #fff;
$welcomePageHeaderBackground: none;
$welcomePageHeaderBackgroundSmall: none;
$welcomePageHeaderBackgroundPosition: none;
$welcomePageHeaderBackgroundRepeat: none;
$welcomePageHeaderBackgroundSize: none;
$welcomePageHeaderPaddingBottom: 0px;
$welcomePageHeaderTextMarginTop: 35px;
$welcomePageHeaderTextMarginBottom: 35px;
$welcomePageHeaderTextTitleMarginBottom: 16px;
$welcomePageHeaderTextDescriptionDisplay: inherit;
$welcomePageEnterRoomWidth: 680px;
$welcomePageEnterRoomPadding: 25px 30px;
$welcomePageEnterRoomBorderRadius: 0px;
$welcomePageEnterRoomInputContainerPadding: 0 8px 5px 0px;
$welcomePageEnterRoomInputContainerBorderWidth: 0px 0px 2px 0px;
$welcomePageEnterRoomInputContainerBorderStyle: solid;
$welcomePageEnterRoomInputContainerBorderImage: linear-gradient(to right, #dee1e6, #fff) 1;
$welcomePageEnterRoomTitleDisplay: inherit;
$welcomePageTabContainerDisplay: flex;
$welcomePageTabContentDisplay: inherit;
$welcomePageTabButtonsDisplay: flex;
$welcomePageTabDisplay: block;
$welcomePageButtonWidth: 51px;
$welcomePageButtonHeight: 35px;
$welcomePageButtonFontWeight: inherit;
$welcomePageButtonBorderRadius: 4px;
$welcomePageButtonLineHeight: 35px;
/**
* Deep-linking page variables.
*/

View File

@@ -4,7 +4,7 @@ body.welcome-page {
}
.welcome {
background-image: $welcomePageBackground;
background-image: $welcomePageHeaderBackground;
display: flex;
flex-direction: column;
font-family: $welcomePageFontFamily;
@@ -13,11 +13,6 @@ body.welcome-page {
position: relative;
.header {
background-image: $welcomePageHeaderBackground;
background-position: $welcomePageHeaderBackgroundPosition;
background-repeat: $welcomePageHeaderBackgroundRepeat;
background-size: $welcomePageHeaderBackgroundSize;
padding-bottom: $welcomePageHeaderPaddingBottom;
align-items: center;
display: flex;
flex-direction: column;
@@ -29,8 +24,8 @@ body.welcome-page {
.header-text {
display: flex;
flex-direction: column;
margin-top: $watermarkHeight + $welcomePageHeaderTextMarginTop;
margin-bottom: $welcomePageHeaderTextMarginBottom;
margin-top: $watermarkHeight + 35;
margin-bottom: 35px;
max-width: calc(100% - 40px);
width: 650px;
z-index: $zindex2;
@@ -41,11 +36,10 @@ body.welcome-page {
font-size: 2.5rem;
font-weight: 500;
line-height: 1.18;
margin-bottom: $welcomePageHeaderTextTitleMarginBottom;
margin-bottom: 16px;
}
.header-text-description {
display: $welcomePageHeaderTextDescriptionDisplay;
color: $welcomePageDescriptionColor;
font-size: 1rem;
font-weight: 400;
@@ -57,24 +51,23 @@ body.welcome-page {
display: flex;
align-items: center;
max-width: calc(100% - 40px);
width: $welcomePageEnterRoomWidth;
width: 680px;
z-index: $zindex2;
background-color: #fff;
padding: $welcomePageEnterRoomPadding;
border-radius: $welcomePageEnterRoomBorderRadius;
padding: 25px 30px;
.enter-room-input-container {
width: 100%;
padding: $welcomePageEnterRoomInputContainerPadding;
padding-right: 8px;
padding-bottom: 5px;
text-align: left;
color: #253858;
height: fit-content;
border-width: $welcomePageEnterRoomInputContainerBorderWidth;
border-style: $welcomePageEnterRoomInputContainerBorderStyle;
border-image: $welcomePageEnterRoomInputContainerBorderImage;
border-width: 0px 0px 2px 0px;
border-style: solid;
border-image: linear-gradient(to right, #dee1e6, #fff) 1;
.enter-room-title {
display: $welcomePageEnterRoomTitleDisplay;
font-size: 18px;
font-weight: bold;
padding-bottom: 5px;
@@ -101,11 +94,10 @@ body.welcome-page {
min-height: 354px;
width: 710px;
background: #75A7E7;
display: $welcomePageTabContainerDisplay;
display: flex;
flex-direction: column;
.tab-content{
display: $welcomePageTabContentDisplay;
margin: 5px 0px;
overflow: hidden;
flex-grow: 1;
@@ -119,14 +111,13 @@ body.welcome-page {
.tab-buttons {
font-size: 18px;
color: #FFFFFF;
display: $welcomePageTabButtonsDisplay;
display: flex;
flex-grow: 0;
flex-direction: row;
min-height: 54px;
width: 100%;
.tab {
display: $welcomePageTabDisplay;
text-align: center;
background: rgba(9,30,66,0.37);
height: 55px;
@@ -147,16 +138,15 @@ body.welcome-page {
}
.welcome-page-button {
width: $welcomePageButtonWidth;
height: $welcomePageButtonHeight;
width: 51px;
height: 35px;
font-size: 14px;
font-weight: $welcomePageButtonFontWeight;
background: #0074E0;
border-radius: $welcomePageButtonBorderRadius;
border-radius: 4px;
color: #FFFFFF;
text-align: center;
vertical-align: middle;
line-height: $welcomePageButtonLineHeight;
line-height: 35px;
cursor: pointer;
}

View File

@@ -1 +0,0 @@
/** Insert custom CSS for any additional content in the welcome page settings toolbar **/

View File

@@ -51,7 +51,6 @@ $flagsImagePath: "../images/";
@import 'ringing/ringing';
@import 'welcome_page';
@import 'welcome_page_content';
@import 'welcome_page_settings_toolbar';
@import 'toolbars';
@import 'jquery.contextMenu';
@import 'keyboard-shortcuts';

View File

@@ -1,78 +0,0 @@
# Developing Jitsi Meet
## Building the sources
Node.js >= 10 and npm >= 6 are required.
On Debian/Ubuntu systems, the required packages can be installed with:
```
sudo apt-get install npm nodejs
cd jitsi-meet
npm install
```
To build the Jitsi Meet application, just type
```
make
```
### Working with the library sources (lib-jitsi-meet)
By default the library is build from its git repository sources. The default dependency path in package.json is :
```json
"lib-jitsi-meet": "jitsi/lib-jitsi-meet",
```
To work with local copy you must change the path to:
```json
"lib-jitsi-meet": "file:///Users/name/local-lib-jitsi-meet-copy",
```
To make the project you must force it to take the sources as 'npm update':
```
npm install lib-jitsi-meet --force && make
```
Or if you are making only changes to the library:
```
npm install lib-jitsi-meet --force && make deploy-lib-jitsi-meet
```
Alternative way is to use [npm link](https://docs.npmjs.com/cli/link).
It allows to link `lib-jitsi-meet` dependency to local source in few steps:
```bash
cd lib-jitsi-meet
#### create global symlink for lib-jitsi-meet package
npm link
cd ../jitsi-meet
#### create symlink from the local node_modules folder to the global lib-jitsi-meet symlink
npm link lib-jitsi-meet
```
After changes in local `lib-jitsi-meet` repository, you can rebuild it with `npm run install` and your `jitsi-meet` repository will use that modified library.
Note: when using node version 4.x, the make file of jitsi-meet do npm update which will delete the link. It is no longer the case with version 6.x.
If you do not want to use local repository anymore you should run
```bash
cd jitsi-meet
npm unlink lib-jitsi-meet
npm install
```
### Running with webpack-dev-server for development
Use it at the CLI, type
```
make dev
```
By default the backend deployment used is `beta.meet.jit.si`. You can point the Jitsi-Meet app at a different backend by using a proxy server. To do this, set the WEBPACK_DEV_SERVER_PROXY_TARGET variable:
```
export WEBPACK_DEV_SERVER_PROXY_TARGET=https://your-example-server.com
make dev
```
The app should be running at https://localhost:8080/

View File

@@ -148,7 +148,6 @@
<!--#include virtual="title.html" -->
<!--#include virtual="plugin.head.html" -->
<!--#include virtual="static/welcomePageAdditionalContent.html" -->
<!--#include virtual="static/settingsToolbarAdditionalContent.html" -->
</head>
<body>
<div id="react"></div>

View File

@@ -27,7 +27,6 @@ var interfaceConfig = {
SHOW_DEEP_LINKING_IMAGE: false,
GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true,
DISPLAY_WELCOME_PAGE_CONTENT: true,
DISPLAY_WELCOME_PAGE_TOOLBAR_ADDITIONAL_CONTENT: false,
APP_NAME: 'Jitsi Meet',
NATIVE_APP_NAME: 'Jitsi Meet',
PROVIDER_NAME: 'Jitsi',
@@ -222,13 +221,6 @@ var interfaceConfig = {
* milliseconds, those notifications should remain displayed.
*/
// ENFORCE_NOTIFICATION_AUTO_DISMISS_TIMEOUT: 15000,
// List of undocumented settings
/**
INDICATOR_FONT_SIZES
MOBILE_DYNAMIC_LINK
PHONE_NUMBER_REGEX
*/
};
/* eslint-enable no-unused-vars, no-var, max-len */

View File

@@ -17,20 +17,9 @@ target 'JitsiMeet' do
# React Native and its dependencies
#
pod 'FBLazyVector', :path => '../node_modules/react-native/Libraries/FBLazyVector/'
pod 'FBReactNativeSpec', :path => '../node_modules/react-native/Libraries/FBReactNativeSpec/'
pod 'RCTRequired', :path => '../node_modules/react-native/Libraries/RCTRequired/'
pod 'RCTTypeSafety', :path => '../node_modules/react-native/Libraries/TypeSafety/'
pod 'React', :path => '../node_modules/react-native/'
pod 'ReactCommon', :path => '../node_modules/react-native/ReactCommon', :subspecs => [
'turbomodule'
]
pod 'React-Core', :path => '../node_modules/react-native/', :subspecs => [
'CoreModulesHeaders',
'DevSupport',
'RCTWebSocket'
]
pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules'
pod 'React-Core', :path => '../node_modules/react-native/React'
pod 'React-DevSupport', :path => '../node_modules/react-native/React'
pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
@@ -40,12 +29,13 @@ target 'JitsiMeet' do
pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
pod 'React-RCTWebSocket', :path => '../node_modules/react-native/Libraries/WebSocket'
pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
@@ -62,7 +52,7 @@ target 'JitsiMeet' do
pod 'react-native-webrtc', :path => '../node_modules/react-native-webrtc'
pod 'BVLinearGradient', :path => '../node_modules/react-native-linear-gradient'
pod 'RNCAsyncStorage', :path => '../node_modules/@react-native-community/async-storage'
pod 'RNGoogleSignin', :path => '../node_modules/@react-native-community/google-signin'
pod 'RNGoogleSignin', :path => '../node_modules/react-native-google-signin'
pod 'RNSound', :path => '../node_modules/react-native-sound'
pod 'RNSVG', :path => '../node_modules/react-native-svg'
pod 'RNWatch', :path => '../node_modules/react-native-watch-connectivity'
@@ -81,7 +71,6 @@ post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'YES'
config.build_settings['SUPPORTS_MACCATALYST'] = 'NO'
end
end
end

View File

@@ -1,10 +1,5 @@
PODS:
- Amplitude-iOS (4.0.4)
- AppAuth (1.2.0):
- AppAuth/Core (= 1.2.0)
- AppAuth/ExternalUserAgent (= 1.2.0)
- AppAuth/Core (1.2.0)
- AppAuth/ExternalUserAgent (1.2.0)
- boost-for-react-native (1.63.0)
- BVLinearGradient (2.5.6):
- React
@@ -15,14 +10,6 @@ PODS:
- Fabric (~> 1.9.0)
- DoubleConversion (1.1.6)
- Fabric (1.9.0)
- FBLazyVector (0.61.1)
- FBReactNativeSpec (0.61.1):
- Folly (= 2018.10.22.00)
- RCTRequired (= 0.61.1)
- RCTTypeSafety (= 0.61.1)
- React-Core (= 0.61.1)
- React-jsi (= 0.61.1)
- ReactCommon/turbomodule/core (= 0.61.1)
- Firebase/Core (5.18.0):
- Firebase/CoreOnly
- FirebaseAnalytics (= 5.7.0)
@@ -67,10 +54,18 @@ PODS:
- GoogleUtilities/Network (~> 5.2)
- "GoogleUtilities/NSData+zlib (~> 5.2)"
- nanopb (~> 0.3)
- GoogleSignIn (5.0.1):
- AppAuth (~> 1.2)
- GTMAppAuth (~> 1.0)
- GoogleSignIn (4.4.0):
- "GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)"
- "GoogleToolboxForMac/NSString+URLArguments (~> 2.1)"
- GTMSessionFetcher/Core (~> 1.1)
- GoogleToolboxForMac/DebugUtils (2.2.0):
- GoogleToolboxForMac/Defines (= 2.2.0)
- GoogleToolboxForMac/Defines (2.2.0)
- "GoogleToolboxForMac/NSDictionary+URLArguments (2.2.0)":
- GoogleToolboxForMac/DebugUtils (= 2.2.0)
- GoogleToolboxForMac/Defines (= 2.2.0)
- "GoogleToolboxForMac/NSString+URLArguments (= 2.2.0)"
- "GoogleToolboxForMac/NSString+URLArguments (2.2.0)"
- GoogleUtilities/AppDelegateSwizzler (5.4.1):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
@@ -89,183 +84,58 @@ PODS:
- GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (5.4.1):
- GoogleUtilities/Logger
- GTMAppAuth (1.0.0):
- AppAuth/Core (~> 1.0)
- GTMSessionFetcher (~> 1.1)
- GTMSessionFetcher (1.2.2):
- GTMSessionFetcher/Full (= 1.2.2)
- GTMSessionFetcher/Core (1.2.2)
- GTMSessionFetcher/Full (1.2.2):
- GTMSessionFetcher/Core (= 1.2.2)
- GTMSessionFetcher/Core (1.2.1)
- nanopb (0.3.901):
- nanopb/decode (= 0.3.901)
- nanopb/encode (= 0.3.901)
- nanopb/decode (0.3.901)
- nanopb/encode (0.3.901)
- ObjectiveDropboxOfficial (3.9.4)
- RCTRequired (0.61.1)
- RCTTypeSafety (0.61.1):
- FBLazyVector (= 0.61.1)
- React (0.60.5):
- React-Core (= 0.60.5)
- React-DevSupport (= 0.60.5)
- React-RCTActionSheet (= 0.60.5)
- React-RCTAnimation (= 0.60.5)
- React-RCTBlob (= 0.60.5)
- React-RCTImage (= 0.60.5)
- React-RCTLinking (= 0.60.5)
- React-RCTNetwork (= 0.60.5)
- React-RCTSettings (= 0.60.5)
- React-RCTText (= 0.60.5)
- React-RCTVibration (= 0.60.5)
- React-RCTWebSocket (= 0.60.5)
- React-Core (0.60.5):
- Folly (= 2018.10.22.00)
- RCTRequired (= 0.61.1)
- React-Core (= 0.61.1)
- React (0.61.1):
- React-Core (= 0.61.1)
- React-Core/DevSupport (= 0.61.1)
- React-Core/RCTWebSocket (= 0.61.1)
- React-RCTActionSheet (= 0.61.1)
- React-RCTAnimation (= 0.61.1)
- React-RCTBlob (= 0.61.1)
- React-RCTImage (= 0.61.1)
- React-RCTLinking (= 0.61.1)
- React-RCTNetwork (= 0.61.1)
- React-RCTSettings (= 0.61.1)
- React-RCTText (= 0.61.1)
- React-RCTVibration (= 0.61.1)
- React-Core (0.61.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default (= 0.61.1)
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- React-jsiexecutor (= 0.61.1)
- Yoga
- React-Core/CoreModulesHeaders (0.61.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- React-jsiexecutor (= 0.61.1)
- Yoga
- React-Core/Default (0.61.1):
- Folly (= 2018.10.22.00)
- glog
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- React-jsiexecutor (= 0.61.1)
- Yoga
- React-Core/DevSupport (0.61.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default (= 0.61.1)
- React-Core/RCTWebSocket (= 0.61.1)
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- React-jsiexecutor (= 0.61.1)
- React-jsinspector (= 0.61.1)
- Yoga
- React-Core/RCTActionSheetHeaders (0.61.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- React-jsiexecutor (= 0.61.1)
- Yoga
- React-Core/RCTAnimationHeaders (0.61.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- React-jsiexecutor (= 0.61.1)
- Yoga
- React-Core/RCTBlobHeaders (0.61.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- React-jsiexecutor (= 0.61.1)
- Yoga
- React-Core/RCTImageHeaders (0.61.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- React-jsiexecutor (= 0.61.1)
- Yoga
- React-Core/RCTLinkingHeaders (0.61.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- React-jsiexecutor (= 0.61.1)
- Yoga
- React-Core/RCTNetworkHeaders (0.61.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- React-jsiexecutor (= 0.61.1)
- Yoga
- React-Core/RCTSettingsHeaders (0.61.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- React-jsiexecutor (= 0.61.1)
- Yoga
- React-Core/RCTTextHeaders (0.61.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- React-jsiexecutor (= 0.61.1)
- Yoga
- React-Core/RCTVibrationHeaders (0.61.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- React-jsiexecutor (= 0.61.1)
- Yoga
- React-Core/RCTWebSocket (0.61.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default (= 0.61.1)
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- React-jsiexecutor (= 0.61.1)
- Yoga
- React-CoreModules (0.61.1):
- FBReactNativeSpec (= 0.61.1)
- Folly (= 2018.10.22.00)
- RCTTypeSafety (= 0.61.1)
- React-Core/CoreModulesHeaders (= 0.61.1)
- React-RCTImage (= 0.61.1)
- ReactCommon/turbomodule/core (= 0.61.1)
- React-cxxreact (0.61.1):
- React-cxxreact (= 0.60.5)
- React-jsiexecutor (= 0.60.5)
- yoga (= 0.60.5.React)
- React-cxxreact (0.60.5):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-jsinspector (= 0.61.1)
- React-jsi (0.61.1):
- React-jsinspector (= 0.60.5)
- React-DevSupport (0.60.5):
- React-Core (= 0.60.5)
- React-RCTWebSocket (= 0.60.5)
- React-jsi (0.60.5):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-jsi/Default (= 0.61.1)
- React-jsi/Default (0.61.1):
- React-jsi/Default (= 0.60.5)
- React-jsi/Default (0.60.5):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-jsiexecutor (0.61.1):
- React-jsiexecutor (0.60.5):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- React-jsinspector (0.61.1)
- React-cxxreact (= 0.60.5)
- React-jsi (= 0.60.5)
- React-jsinspector (0.60.5)
- react-native-background-timer (2.1.1):
- React
- react-native-calendar-events (1.7.3):
@@ -276,66 +146,35 @@ PODS:
- React
- react-native-webrtc (1.75.0):
- React
- react-native-webview (7.4.1):
- react-native-webview (5.8.1):
- React
- React-RCTActionSheet (0.61.1):
- React-Core/RCTActionSheetHeaders (= 0.61.1)
- React-RCTAnimation (0.61.1):
- React-Core/RCTAnimationHeaders (= 0.61.1)
- React-RCTBlob (0.61.1):
- React-Core/RCTBlobHeaders (= 0.61.1)
- React-Core/RCTWebSocket (= 0.61.1)
- React-jsi (= 0.61.1)
- React-RCTNetwork (= 0.61.1)
- React-RCTImage (0.61.1):
- React-Core/RCTImageHeaders (= 0.61.1)
- React-RCTNetwork (= 0.61.1)
- React-RCTLinking (0.61.1):
- React-Core/RCTLinkingHeaders (= 0.61.1)
- React-RCTNetwork (0.61.1):
- React-Core/RCTNetworkHeaders (= 0.61.1)
- React-RCTSettings (0.61.1):
- React-Core/RCTSettingsHeaders (= 0.61.1)
- React-RCTText (0.61.1):
- React-Core/RCTTextHeaders (= 0.61.1)
- React-RCTVibration (0.61.1):
- React-Core/RCTVibrationHeaders (= 0.61.1)
- ReactCommon/jscallinvoker (0.61.1):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-cxxreact (= 0.61.1)
- ReactCommon/turbomodule (0.61.1):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-Core (= 0.61.1)
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- ReactCommon/jscallinvoker (= 0.61.1)
- ReactCommon/turbomodule/core (= 0.61.1)
- ReactCommon/turbomodule/samples (= 0.61.1)
- ReactCommon/turbomodule/core (0.61.1):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-Core (= 0.61.1)
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- ReactCommon/jscallinvoker (= 0.61.1)
- ReactCommon/turbomodule/samples (0.61.1):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-Core (= 0.61.1)
- React-cxxreact (= 0.61.1)
- React-jsi (= 0.61.1)
- ReactCommon/jscallinvoker (= 0.61.1)
- ReactCommon/turbomodule/core (= 0.61.1)
- React-RCTActionSheet (0.60.5):
- React-Core (= 0.60.5)
- React-RCTAnimation (0.60.5):
- React-Core (= 0.60.5)
- React-RCTBlob (0.60.5):
- React-Core (= 0.60.5)
- React-RCTNetwork (= 0.60.5)
- React-RCTWebSocket (= 0.60.5)
- React-RCTImage (0.60.5):
- React-Core (= 0.60.5)
- React-RCTNetwork (= 0.60.5)
- React-RCTLinking (0.60.5):
- React-Core (= 0.60.5)
- React-RCTNetwork (0.60.5):
- React-Core (= 0.60.5)
- React-RCTSettings (0.60.5):
- React-Core (= 0.60.5)
- React-RCTText (0.60.5):
- React-Core (= 0.60.5)
- React-RCTVibration (0.60.5):
- React-Core (= 0.60.5)
- React-RCTWebSocket (0.60.5):
- React-Core (= 0.60.5)
- RNCAsyncStorage (1.3.4):
- React
- RNGoogleSignin (3.0.1):
- GoogleSignIn (~> 5.0.0)
- RNGoogleSignin (2.0.0):
- GoogleSignIn (~> 4.4.0)
- React
- RNSound (0.11.0):
- React
@@ -346,7 +185,7 @@ PODS:
- React
- RNWatch (0.2.0):
- React
- Yoga (1.14.0)
- yoga (0.60.5.React)
DEPENDENCIES:
- Amplitude-iOS (~> 4.0.4)
@@ -355,21 +194,15 @@ DEPENDENCIES:
- Crashlytics (~> 3.12.0)
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
- Fabric (~> 1.9.0)
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector/`)
- FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec/`)
- Firebase/Core (~> 5.18.0)
- Firebase/DynamicLinks (~> 5.18.0)
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- ObjectiveDropboxOfficial (~> 3.9.4)
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired/`)
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety/`)
- React (from `../node_modules/react-native/`)
- React-Core/CoreModulesHeaders (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-Core (from `../node_modules/react-native/React`)
- React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
- React-DevSupport (from `../node_modules/react-native/React`)
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
@@ -388,16 +221,16 @@ DEPENDENCIES:
- React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
- React-RCTText (from `../node_modules/react-native/Libraries/Text`)
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
- ReactCommon/turbomodule (from `../node_modules/react-native/ReactCommon`)
- React-RCTWebSocket (from `../node_modules/react-native/Libraries/WebSocket`)
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
- "RNGoogleSignin (from `../node_modules/@react-native-community/google-signin`)"
- RNGoogleSignin (from `../node_modules/react-native-google-signin`)
- RNSound (from `../node_modules/react-native-sound`)
- RNSVG (from `../node_modules/react-native-svg`)
- RNWatch (from `../node_modules/react-native-watch-connectivity`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
- yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
https://github.com/CocoaPods/Specs.git:
https://github.com/cocoapods/specs.git:
- Amplitude-iOS
- boost-for-react-native
- CocoaLumberjack
@@ -410,40 +243,30 @@ SPEC REPOS:
- FirebaseDynamicLinks
- FirebaseInstanceID
- GoogleAppMeasurement
- GoogleSignIn
- GoogleToolboxForMac
- GoogleUtilities
- GTMSessionFetcher
- nanopb
- ObjectiveDropboxOfficial
trunk:
- AppAuth
- GoogleSignIn
- GTMAppAuth
- GTMSessionFetcher
EXTERNAL SOURCES:
BVLinearGradient:
:path: "../node_modules/react-native-linear-gradient"
DoubleConversion:
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
FBLazyVector:
:path: "../node_modules/react-native/Libraries/FBLazyVector/"
FBReactNativeSpec:
:path: "../node_modules/react-native/Libraries/FBReactNativeSpec/"
Folly:
:podspec: "../node_modules/react-native/third-party-podspecs/Folly.podspec"
glog:
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
RCTRequired:
:path: "../node_modules/react-native/Libraries/RCTRequired/"
RCTTypeSafety:
:path: "../node_modules/react-native/Libraries/TypeSafety/"
React:
:path: "../node_modules/react-native/"
React-Core:
:path: "../node_modules/react-native/"
React-CoreModules:
:path: "../node_modules/react-native/React/CoreModules"
:path: "../node_modules/react-native/React"
React-cxxreact:
:path: "../node_modules/react-native/ReactCommon/cxxreact"
React-DevSupport:
:path: "../node_modules/react-native/React"
React-jsi:
:path: "../node_modules/react-native/ReactCommon/jsi"
React-jsiexecutor:
@@ -480,32 +303,29 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/Libraries/Text"
React-RCTVibration:
:path: "../node_modules/react-native/Libraries/Vibration"
ReactCommon:
:path: "../node_modules/react-native/ReactCommon"
React-RCTWebSocket:
:path: "../node_modules/react-native/Libraries/WebSocket"
RNCAsyncStorage:
:path: "../node_modules/@react-native-community/async-storage"
RNGoogleSignin:
:path: "../node_modules/@react-native-community/google-signin"
:path: "../node_modules/react-native-google-signin"
RNSound:
:path: "../node_modules/react-native-sound"
RNSVG:
:path: "../node_modules/react-native-svg"
RNWatch:
:path: "../node_modules/react-native-watch-connectivity"
Yoga:
yoga:
:path: "../node_modules/react-native/ReactCommon/yoga"
SPEC CHECKSUMS:
Amplitude-iOS: 2ad4d7270c99186236c1272a3a9425463b1ae1a7
AppAuth: bce82c76043657c99d91e7882e8a9e1a93650cd4
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872
CocoaLumberjack: 2f44e60eb91c176d471fdba43b9e3eae6a721947
Crashlytics: 07fb167b1694128c1c9a5a5cc319b0e9c3ca0933
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
Fabric: f988e33c97f08930a413e08123064d2e5f68d655
FBLazyVector: 0846affdb2924b01093eb696766ecb0104e409e0
FBReactNativeSpec: c4cf958af1b97799b524f63a26a1c509c0295b04
Firebase: 02f3281965c075426141a0ce1277e9de6649cab9
FirebaseAnalytics: 23851fe602c872130a2c5c55040b302120346cc2
FirebaseAnalyticsInterop: efbe45c8385ec626e29f9525e5ebd38520dfb6c1
@@ -515,44 +335,42 @@ SPEC CHECKSUMS:
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
GoogleAppMeasurement: 6cf307834da065863f9faf4c0de0a936d81dd832
GoogleSignIn: 3a51b9bb8e48b635fd7f4272cee06ca260345b86
GoogleSignIn: 7ff245e1a7b26d379099d3243a562f5747e23d39
GoogleToolboxForMac: ff31605b7d66400dcec09bed5861689aebadda4d
GoogleUtilities: 1e25823cbf46540b4284f6ef8e17b3a68ee12bbc
GTMAppAuth: 4deac854479704f348309e7b66189e604cf5e01e
GTMSessionFetcher: 61bb0f61a4cb560030f1222021178008a5727a23
GTMSessionFetcher: 32aeca0aa144acea523e1c8e053089dec2cb98ca
nanopb: 2901f78ea1b7b4015c860c2fdd1ea2fee1a18d48
ObjectiveDropboxOfficial: a5afefc83f6467c42c45f2253f583f2ad1ffc701
RCTRequired: 53825815218847d3e9c7b6d92ad2d197a926d51e
RCTTypeSafety: d886540c518e53064dfa081bf7693fd650699b92
React: 5dea58967c421bd1fdf6b94c18b9ed0f5134683c
React-Core: b381e65aa0da9b94b9dcdc4a99298075b1c3876c
React-CoreModules: 4ed224e29848ba76d26aacb8e3fe85712d3c4fe1
React-cxxreact: 52c98f5c1fb4e4d9f4b588742718350a55f4f088
React-jsi: 61ff417c95e6c3af50fb96399037e80752fb5ce7
React-jsiexecutor: ee45274419eb95614bbbadb98e20684c5f29996e
React-jsinspector: 574d597112f9ea3d1b717f6fb62aef764c70dd6f
React: 53c53c4d99097af47cf60594b8706b4e3321e722
React-Core: ba421f6b4f4cbe2fb17c0b6fc675f87622e78a64
React-cxxreact: 8384287780c4999351ad9b6e7a149d9ed10a2395
React-DevSupport: 197fb409737cff2c4f9986e77c220d7452cb9f9f
React-jsi: 4d8c9efb6312a9725b18d6fc818ffc103f60fec2
React-jsiexecutor: 90ad2f9db09513fc763bc757fdc3c4ff8bde2a30
React-jsinspector: e08662d1bf5b129a3d556eb9ea343a3f40353ae4
react-native-background-timer: 0d34748e53a972507c66963490c775321a88f6f2
react-native-calendar-events: 2fe35a9294af05de0ed819d3a1b5dac048d2c010
react-native-keep-awake: eba3137546b10003361b37c761f6c429b59814ae
react-native-netinfo: 8d8db463bcc5db66a8ac5c48a7d86beb3b92f61a
react-native-webrtc: c5e3d631179a933548a8e49bddbd8fad02586095
react-native-webview: 4dbc1d2a4a6b9c5e9e723c62651917aa2b5e579e
React-RCTActionSheet: af4d951113b1e068bb30611f91b984a7a73597ff
React-RCTAnimation: 4f518d70bb6890b7c3d9d732f84786d6693ca297
React-RCTBlob: 072a4888c08de0eef6d04eaa727d25e577e6ff26
React-RCTImage: 78c5cdf1b2de6cd3cd650dd741868fad19a35528
React-RCTLinking: 486ed1c9a659c7f9fea213868f8930b9a0a79f07
React-RCTNetwork: e79599f3160b459da03447e32b8bcca1a0f0f797
React-RCTSettings: 48b7c5a64ffe0c54c39d59eb7d9036e72305f95a
React-RCTText: 81b62b4e7f11531a5154e4daa5617670d5a2d5de
React-RCTVibration: 8be61459e3749d1fb02cf414edd05b3007622882
ReactCommon: 4fba5be89efdf0b5720e0adb3d8d7edf6e532db0
react-native-webview: a95842e3f351a6d2c8bc8bcc9eab689c7e7e5ad4
React-RCTActionSheet: b0f1ea83f4bf75fb966eae9bfc47b78c8d3efd90
React-RCTAnimation: 359ba1b5690b1e87cc173558a78e82d35919333e
React-RCTBlob: 5e2b55f76e9a1c7ae52b826923502ddc3238df24
React-RCTImage: f5f1c50922164e89bdda67bcd0153952a5cfe719
React-RCTLinking: d0ecbd791e9ddddc41fa1f66b0255de90e8ee1e9
React-RCTNetwork: e26946300b0ab7bb6c4a6348090e93fa21f33a9d
React-RCTSettings: d0d37cb521b7470c998595a44f05847777cc3f42
React-RCTText: b074d89033583d4f2eb5faf7ea2db3a13c7553a2
React-RCTVibration: 2105b2e0e2b66a6408fc69a46c8a7fb5b2fdade0
React-RCTWebSocket: cd932a16b7214898b6b7f788c8bddb3637246ac4
RNCAsyncStorage: 8e31405a9f12fbf42c2bb330e4560bfd79c18323
RNGoogleSignin: 39336070b35fc4cea6a98cf111e00480317be0ae
RNGoogleSignin: d030c6c6591db24c3cee649f64c7babf0a1699a0
RNSound: c980916b596cc15c8dcd2f6ecd3b13c4881dbe20
RNSVG: aac12785382e8fd4f28d072fe640612e34914631
RNWatch: 09738b339eceb66e4d80a2371633ca5fb380fa42
Yoga: d8c572ddec8d05b7dba08e4e5f1924004a177078
yoga: 312528f5bbbba37b4dcea5ef00e8b4033fdd9411
PODFILE CHECKSUM: cb84b325b724c6ef7c8b24aa52ca7b6f681a095c
PODFILE CHECKSUM: 86bb4d2bc94c6c76b971b9a33e5b2ced9bbfb09f
COCOAPODS: 1.8.1
COCOAPODS: 1.7.2

View File

@@ -41,6 +41,8 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
@@ -50,8 +52,8 @@
ReferencedContainer = "container:app.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -73,6 +75,8 @@
ReferencedContainer = "container:app.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>19.4.0</string>
<string>19.3.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>19.4.0</string>
<string>19.3.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>19.4.0</string>
<string>19.3.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CLKComplicationPrincipalClass</key>

View File

@@ -42,7 +42,6 @@
C69EFA0E209A0F660027712B /* JMCallKitListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA0B209A0F660027712B /* JMCallKitListener.swift */; };
C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3425E204EF76800E062DD /* DragGestureController.swift */; };
C6CC49AF207412CF000DFA42 /* PiPViewCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */; };
DE438CDA2350934700DD541D /* JavaScriptSandbox.m in Sources */ = {isa = PBXBuildFile; fileRef = DE438CD82350934700DD541D /* JavaScriptSandbox.m */; };
DE65AACA2317FFCD00290BEC /* LogUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DE65AAC92317FFCD00290BEC /* LogUtils.h */; };
DE65AACC2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */; };
DE762DB422AFDE76000DEBD6 /* JitsiMeetUserInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DE762DB322AFDE76000DEBD6 /* JitsiMeetUserInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -105,7 +104,6 @@
C6A3425E204EF76800E062DD /* DragGestureController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragGestureController.swift; sourceTree = "<group>"; };
C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiPViewCoordinator.swift; sourceTree = "<group>"; };
C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetView+Private.h"; sourceTree = "<group>"; };
DE438CD82350934700DD541D /* JavaScriptSandbox.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JavaScriptSandbox.m; sourceTree = "<group>"; };
DE65AAC92317FFCD00290BEC /* LogUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogUtils.h; sourceTree = "<group>"; };
DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetBaseLogHandler+Private.h"; sourceTree = "<group>"; };
DE762DB322AFDE76000DEBD6 /* JitsiMeetUserInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeetUserInfo.h; sourceTree = "<group>"; };
@@ -192,7 +190,6 @@
A4A934E7212F3AB8001E9388 /* dropbox */,
0BA13D301EE83FF8007BEF7F /* ExternalAPI.m */,
0BD906E91EC0C00300C8C18E /* Info.plist */,
DE438CD82350934700DD541D /* JavaScriptSandbox.m */,
0BD906E81EC0C00300C8C18E /* JitsiMeet.h */,
DEFE535821FB311F00011A3A /* JitsiMeet+Private.h */,
DEFE535321FB1BF800011A3A /* JitsiMeet.m */,
@@ -496,7 +493,6 @@
C69EFA0E209A0F660027712B /* JMCallKitListener.swift in Sources */,
0B412F191EDEC65D00B1A0A6 /* JitsiMeetView.m in Sources */,
DEFE535421FB1BF800011A3A /* JitsiMeet.m in Sources */,
DE438CDA2350934700DD541D /* JavaScriptSandbox.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -638,18 +634,15 @@
ENABLE_BITCODE = NO;
INFOPLIST_FILE = src/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.JitsiMeetSDK.ios;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = NO;
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
@@ -669,17 +662,14 @@
ENABLE_BITCODE = YES;
INFOPLIST_FILE = src/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.JitsiMeetSDK.ios;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = NO;
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};

View File

@@ -81,7 +81,7 @@
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Script"
scriptText = "exec &gt; /tmp/${PROJECT_NAME}_archive.log 2&gt;&amp;1&#10;&#10;UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal&#10;&#10;if [ &quot;true&quot; == ${ALREADYINVOKED:-false} ]&#10;then&#10;echo &quot;RECURSION: Detected, stopping&quot;&#10;else&#10;export ALREADYINVOKED=&quot;true&quot;&#10;&#10;# make sure the output directory exists&#10;mkdir -p &quot;${UNIVERSAL_OUTPUTFOLDER}&quot;&#10;&#10;echo &quot;Building for iPhoneSimulator&quot;&#10;xcodebuild -workspace &quot;${WORKSPACE_PATH}&quot; -scheme &quot;${TARGET_NAME}&quot; -configuration ${CONFIGURATION} -sdk iphonesimulator -destination &apos;platform=iOS Simulator,name=iPhone 8&apos; ONLY_ACTIVE_ARCH=NO ARCHS=&apos;i386 x86_64&apos; BUILD_DIR=&quot;${BUILD_DIR}&quot; BUILD_ROOT=&quot;${BUILD_ROOT}&quot; ENABLE_BITCODE=YES OTHER_CFLAGS=&quot;-fembed-bitcode&quot; BITCODE_GENERATION_MODE=bitcode clean build&#10;&#10;# Step 1. Copy the framework structure (from iphoneos build) to the universal folder&#10;echo &quot;Copying to output folder&quot;&#10;cp -R &quot;${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FULL_PRODUCT_NAME}&quot; &quot;${UNIVERSAL_OUTPUTFOLDER}/&quot;&#10;&#10;# Step 2. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory&#10;SIMULATOR_SWIFT_MODULES_DIR=&quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/.&quot;&#10;if [ -d &quot;${SIMULATOR_SWIFT_MODULES_DIR}&quot; ]; then&#10;cp -R &quot;${SIMULATOR_SWIFT_MODULES_DIR}&quot; &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule&quot;&#10;fi&#10;&#10;# Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory&#10;echo &quot;Combining executables&quot;&#10;lipo -create -output &quot;${UNIVERSAL_OUTPUTFOLDER}/${EXECUTABLE_PATH}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${EXECUTABLE_PATH}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphoneos/${EXECUTABLE_PATH}&quot;&#10;&#10;# Step 4. Create universal binaries for embedded frameworks&#10;#for SUB_FRAMEWORK in $( ls &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks&quot; ); do&#10;#BINARY_NAME=&quot;${SUB_FRAMEWORK%.*}&quot;&#10;#lipo -create -output &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SUB_FRAMEWORK}/${BINARY_NAME}&quot; &quot;${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}&quot;&#10;#done&#10;&#10;# Step 5. Convenience step to copy the framework to the project&apos;s directory&#10;echo &quot;Copying to project dir&quot;&#10;yes | cp -Rf &quot;${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}&quot; &quot;${PROJECT_DIR}&quot;&#10;&#10;fi&#10;">
scriptText = "exec &gt; /tmp/${PROJECT_NAME}_archive.log 2&gt;&amp;1&#10;&#10;UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal&#10;&#10;if [ &quot;true&quot; == ${ALREADYINVOKED:-false} ]&#10;then&#10;echo &quot;RECURSION: Detected, stopping&quot;&#10;else&#10;export ALREADYINVOKED=&quot;true&quot;&#10;&#10;# make sure the output directory exists&#10;mkdir -p &quot;${UNIVERSAL_OUTPUTFOLDER}&quot;&#10;&#10;echo &quot;Building for iPhoneSimulator&quot;&#10;xcodebuild -workspace &quot;${WORKSPACE_PATH}&quot; -scheme &quot;${TARGET_NAME}&quot; -configuration ${CONFIGURATION} -sdk iphonesimulator -destination &apos;platform=iOS Simulator,name=iPhone 6&apos; ONLY_ACTIVE_ARCH=NO ARCHS=&apos;i386 x86_64&apos; BUILD_DIR=&quot;${BUILD_DIR}&quot; BUILD_ROOT=&quot;${BUILD_ROOT}&quot; ENABLE_BITCODE=YES OTHER_CFLAGS=&quot;-fembed-bitcode&quot; BITCODE_GENERATION_MODE=bitcode clean build&#10;&#10;# Step 1. Copy the framework structure (from iphoneos build) to the universal folder&#10;echo &quot;Copying to output folder&quot;&#10;cp -R &quot;${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FULL_PRODUCT_NAME}&quot; &quot;${UNIVERSAL_OUTPUTFOLDER}/&quot;&#10;&#10;# Step 2. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory&#10;SIMULATOR_SWIFT_MODULES_DIR=&quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/.&quot;&#10;if [ -d &quot;${SIMULATOR_SWIFT_MODULES_DIR}&quot; ]; then&#10;cp -R &quot;${SIMULATOR_SWIFT_MODULES_DIR}&quot; &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule&quot;&#10;fi&#10;&#10;# Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory&#10;echo &quot;Combining executables&quot;&#10;lipo -create -output &quot;${UNIVERSAL_OUTPUTFOLDER}/${EXECUTABLE_PATH}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${EXECUTABLE_PATH}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphoneos/${EXECUTABLE_PATH}&quot;&#10;&#10;# Step 4. Create universal binaries for embedded frameworks&#10;#for SUB_FRAMEWORK in $( ls &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks&quot; ); do&#10;#BINARY_NAME=&quot;${SUB_FRAMEWORK%.*}&quot;&#10;#lipo -create -output &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SUB_FRAMEWORK}/${BINARY_NAME}&quot; &quot;${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}&quot;&#10;#done&#10;&#10;# Step 5. Convenience step to copy the framework to the project&apos;s directory&#10;echo &quot;Copying to project dir&quot;&#10;yes | cp -Rf &quot;${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}&quot; &quot;${PROJECT_DIR}&quot;&#10;&#10;fi">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"

View File

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

View File

@@ -1,55 +0,0 @@
/*
* Copyright @ 2019-present 8x8, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@import JavaScriptCore;
#import <React/RCTBridgeModule.h>
@interface JavaScriptSandbox : NSObject<RCTBridgeModule>
@end
@implementation JavaScriptSandbox
RCT_EXPORT_MODULE();
+ (BOOL)requiresMainQueueSetup {
return NO;
}
#pragma mark - Exported methods
RCT_EXPORT_METHOD(evaluate:(NSString *)code
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject) {
__block BOOL hasError = NO;
JSContext *ctx = [[JSContext alloc] init];
ctx.exceptionHandler = ^(JSContext *context, JSValue *exception) {
hasError = YES;
reject(@"evaluate", [exception toString], nil);
};
JSValue *ret = [ctx evaluateScript:code];
if (!hasError) {
NSString *result = [ret toString];
if (result == nil) {
reject(@"evaluate", @"Error in string coercion", nil);
} else {
resolve(result);
}
}
}
@end

View File

@@ -37,6 +37,7 @@
* List of domains used for universal linking.
*/
@property (copy, nonatomic, nullable) NSArray<NSString *> *universalLinkDomains;
/**
* Default conference options used for all conferences. These options will be merged
* with those passed to JitsiMeetView.join when joining a conference.

View File

@@ -90,7 +90,8 @@
if ([RNGoogleSignin application:app
openURL:url
options:options]) {
sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
annotation:options[UIApplicationOpenURLOptionsAnnotationKey]]) {
return YES;
}
@@ -178,15 +179,6 @@
return _universalLinkDomains ? _universalLinkDomains : @[];
}
- (void)setDefaultConferenceOptions:(JitsiMeetConferenceOptions *)defaultConferenceOptions {
if (defaultConferenceOptions != nil && _defaultConferenceOptions.room != nil) {
@throw [NSException exceptionWithName:@"RuntimeError"
reason:@"'room' must be null in the default conference options"
userInfo:nil];
}
_defaultConferenceOptions = defaultConferenceOptions;
}
#pragma mark - Private API methods
- (NSDictionary *)getDefaultProps {

View File

@@ -26,9 +26,7 @@
*/
__attribute__((constructor))
static void initializeLogger() {
NSString *mainBundleId = [NSBundle mainBundle].bundleIdentifier;
DDOSLogger *osLogger = [[DDOSLogger alloc] initWithSubsystem:mainBundleId category:@"JitsiMeetSDK"];
[DDLog addLogger:osLogger];
[DDLog addLogger:[DDOSLogger sharedInstance]];
}
+ (void)addHandler:(JitsiMeetBaseLogHandler *)handler {

View File

@@ -1,31 +1,27 @@
{
"en": "Английски",
"af": "Африканс",
"az": "Азербайджански",
"bg": "Български",
"ca": "Каталонски",
"cs": "Чешки",
"de": "Немски",
"el": "Гръцки",
"enGB": "Английски (Великобритания)",
"eo": "Есперанто",
"es": "Испански",
"esUS": "Испански (Латинска Америка)",
"fi": "Фински",
"fr": "Френски",
"frCA": "Френски (Канада)",
"hr": "Хърватски",
"hy": "Арменски",
"it": "Италиански",
"ja": "Японски",
"ko": "Корейски",
"nl": "Нидерландски",
"nb": "Норвежки букмол",
"oc": "Окситански",
"pl": "Полски",
"ptBR": "Португалски (Бразилия)",
"ru": "Руски",
"sk": "Словашки",
"sl": "Словенски",
"sv": "Шведски",
"tr": "Турски",
"vi": "Виетнамски",
"zhCN": "Китайски (Китай)",
"zhTW": "Тайвански"
"zhCN": "Китайски (Китай)"
}

View File

@@ -1,31 +1,27 @@
{
"en": "angol",
"af": "afrikaans",
"bg": "bolgár",
"ca": "katalán",
"cs": "cseh",
"de": "német",
"el": "görög",
"enGB": "angol (Egyesült Királyság)",
"eo": "eszperantó",
"es": "spanyol",
"esUS": "spanyol (Latin-Amerika)",
"fi": "finn",
"fr": "francia",
"frCA": "francia (kanadai)",
"hr": "horvát",
"hy": "örmény",
"it": "olasz",
"ja": "japán",
"ko": "koreai",
"nl": "holland",
"oc": "okszitán",
"pl": "lengyel",
"ptBR": "portugál (Brazil)",
"ru": "orosz",
"sv": "svéd",
"tr": "török",
"vi": "vietnámi",
"zhCN": "kínai (Kína)",
"zhTW": "kínai (Tajvan)"
"en": "Angol",
"af": "",
"az": "",
"bg": "Bolgár",
"cs": "",
"de": "Német",
"el": "",
"eo": "Eszperantó",
"es": "Spanyol",
"fr": "Francia",
"hy": "Örmény",
"it": "Olasz",
"ja": "",
"ko": "",
"nb": "Norvég bokmal",
"oc": "Okszitán",
"pl": "Lengyel",
"ptBR": "Portugál (Brazil)",
"ru": "Orosz",
"sk": "Szlovák",
"sl": "Szlovén",
"sv": "Svéd",
"tr": "Török",
"vi": "",
"zhCN": "Kínai (Kína)"
}

View File

@@ -2,23 +2,23 @@
"en": "Anglés",
"af": "Afrikaans",
"bg": "Bulgar",
"ca": "Catalan",
"ca": "",
"cs": "Chèc",
"de": "Aleman",
"el": "Grèc",
"enGB": "Anglés (Reialme Unit)",
"enGB": "",
"eo": "Esperanto",
"es": "Castelhan",
"esUS": "Espanhòl (America latina)",
"fi": "Finés",
"esUS": "",
"fi": "",
"fr": "Francés",
"frCA": "Francés (Canadian)",
"hr": "Croat",
"frCA": "",
"hr": "",
"hy": "Armenian",
"it": "Italian",
"ja": "Japonés",
"ko": "Corean",
"nl": "Neerlandés",
"nl": "",
"oc": "Occitan",
"pl": "Polonés",
"ptBR": "Portugués (Brasil)",
@@ -27,5 +27,5 @@
"tr": "Turc",
"vi": "Vietnamian",
"zhCN": "Chinés (China)",
"zhTW": "Chinés (Taiwan)"
"zhTW": ""
}

View File

@@ -1,31 +1,27 @@
{
"en": "Angielski",
"af": "Afrykanerski",
"en": "Anglik",
"af": "",
"az": "Azerski",
"bg": "Bułgarski",
"ca": "",
"cs": "Czeski",
"de": "Niemiecki",
"el": "Grecki",
"enGB": "",
"eo": "Esperanto",
"es": "Hiszpański",
"esUS": "",
"fi": "",
"fr": "Francuski",
"frCA": "",
"hr": "",
"hy": "Ormiański",
"it": "Włoski",
"ja": "Japoński",
"ko": "Koreański",
"nl": "",
"nb": "Norweski Bokmal",
"oc": "Oksytański",
"pl": "Polski",
"ptBR": "Portugalski (brazylijski)",
"ptBR": "portugalski (brazylijski)",
"ru": "Rosyjski",
"sk": "Słowacki",
"sl": "Słoweński",
"sv": "Szwedzki",
"tr": "Turecki",
"vi": "Wietnamski",
"zhCN": "Chiński (Chiny)",
"zhTW": ""
"zhCN": "Chiński (Chiny)"
}

View File

@@ -1,31 +1,27 @@
{
"en": "Inglês",
"af": "Africâner",
"az": "Azerbaijanês",
"bg": "Búlgaro",
"ca": "",
"cs": "Checo",
"de": "Alemão",
"el": "Grego",
"enGB": "",
"eo": "Esperanto",
"es": "Espanhol",
"esUS": "",
"fi": "",
"fr": "Francês",
"frCA": "",
"hr": "",
"hy": "Armênio",
"it": "Italiano",
"ja": "Japonês",
"ko": "Coreano",
"nl": "",
"nb": "Bokmal norueguês",
"oc": "Occitano",
"pl": "Polonês",
"ptBR": "Português (Brasil)",
"ru": "Russo",
"sk": "Eslovaco",
"sl": "Esloveno",
"sv": "Sueco",
"tr": "Turco",
"vi": "Vietnamita",
"zhCN": "Chinês (China)",
"zhTW": ""
"zhCN": "Chinês (China)"
}

View File

@@ -14,7 +14,6 @@
"fr": "French",
"frCA": "French (Canadian)",
"hr": "Croatian",
"hu": "Hungarian",
"hy": "Armenian",
"it": "Italian",
"ja": "Japanese",

View File

@@ -4,8 +4,8 @@
"countryNotSupported": "Желаната дестинация не се поддържа.",
"countryReminder": "Международно обаждане? Започнете номера с международният код!",
"disabled": "Не можете да каните хора.",
"failedToAdd": "Неуспешно добавяне на участници",
"footerText": "Изходящите разговори не са разрешени.",
"failedToAdd": "",
"footerText": "Изходящиите разговори не са разрешени.",
"loading": "Търсене на хора и телефонни номера.",
"loadingNumber": "Валидиране на номера",
"loadingPeople": "Търсене на хора",
@@ -13,49 +13,48 @@
"noValidNumbers": "Моля въведете телефонен номер",
"searchNumbers": "Добавяне на номера",
"searchPeople": "Търсене на хора",
"searchPeopleAndNumbers": "Търсене на участници или добавяне с телефони номера",
"telephone": "Телефон: {{number}}",
"title": "Добавяне на участници в срещата"
"searchPeopleAndNumbers": "",
"telephone": "",
"title": ""
},
"audioDevices": {
"bluetooth": "Bluetooth",
"bluetooth": "",
"headphones": "Слушалки",
"phone": "Телефон",
"speaker": "Говорещ",
"none": "Няма налични устройства за звук"
"speaker": "Говорещ"
},
"audioOnly": {
"audioOnly": "Нисък дебит"
"audioOnly": "Само звук"
},
"calendarSync": {
"addMeetingURL": "Добавяне на връзка за среща",
"confirmAddLink": "Искате ли да добавите връзка към това събитие?",
"addMeetingURL": "",
"confirmAddLink": "",
"error": {
"appConfiguration": "Интеграцията с календара не е настроена.",
"generic": "Грешка, моля проверете настройката за календара или го обновете.",
"notSignedIn": "Грешка при идентификация за изтегляне на събития. Моля проверете настройките на календара и опитайте отново."
"appConfiguration": "",
"generic": "",
"notSignedIn": ""
},
"join": "Влизане",
"joinTooltip": "Влизане в срещата",
"nextMeeting": "следваща среща",
"noEvents": "Няма насрочени бъдещи събития.",
"ongoingMeeting": "настояща среща",
"permissionButton": "Отваряне на настройки",
"permissionMessage": "За показване на срещите ви е нужно позволение за ползване на календара.",
"refresh": "Обновяване на календара",
"today": "Днес"
"join": "",
"joinTooltip": "",
"nextMeeting": "",
"noEvents": "",
"ongoingMeeting": "",
"permissionButton": "",
"permissionMessage": "",
"refresh": "",
"today": ""
},
"chat": {
"error": "Грешка: вашето съобщение \"{{originalText}}\" не е бе изпратено. Поради: {{error}}",
"messagebox": "Въведете съобщение",
"error": "",
"messagebox": "",
"nickname": {
"popover": "Избор на име",
"title": "Въведете име за да обменяте съобщения"
"title": ""
},
"title": "Текстови съобщения"
"title": ""
},
"connectingOverlay": {
"joiningRoom": "Свързване с вашата среща..."
"joiningRoom": ""
},
"connection": {
"ATTACHED": "Прикрепен",
@@ -73,8 +72,8 @@
"address": "Адрес:",
"bandwidth": "Предполагаема скорост:",
"bitrate": "Скорост:",
"bridgeCount": "Брой сървъри:",
"connectedTo": "Свързан към:",
"bridgeCount": "",
"connectedTo": "",
"framerate": "Кадри в секунда:",
"less": "Скриване",
"localaddress": "Локален адрес:",
@@ -97,25 +96,26 @@
"resolution": "Резолюция:",
"status": "Връзка:",
"transport": "Транспорт:",
"transport_plural": "Транспорти:"
"transport_plural": "Транспорти:",
"turn": " (обръщане)"
},
"dateUtils": {
"earlier": "По-рано",
"today": "Днес",
"yesterday": "Вчера"
"earlier": "",
"today": "",
"yesterday": ""
},
"deepLinking": {
"appNotInstalled": "Имате нужда от мобилното приложение {{app}} за влизане в тази среща от телефона.",
"description": "Нищо не се случва? Опитахме се да заредим срещата в приложението {{app}}. Пробвайте отново или влезте чрез уеб приложението {{app}}.",
"descriptionWithoutWeb": "Нищо не се случва? Опитахме се да заредим срещата в приложението {{app}}.",
"downloadApp": "Свалете приложението",
"launchWebButton": "Заредете уеб страницата",
"openApp": "Продължете към приложението",
"title": "Зареждане на срещата в {{app}}...",
"tryAgainButton": "Пробвайте отново"
"appNotInstalled": "",
"description": "",
"descriptionWithoutWeb": "",
"downloadApp": "Сваляне не приложението",
"launchWebButton": "",
"openApp": "",
"title": "",
"tryAgainButton": ""
},
"\u0005deepLinking": {},
"defaultLink": "напр. {{url}}",
"defaultNickname": "напр. Иван Иванов",
"deviceError": {
"cameraError": "Камерата е недостъпна",
"cameraPermission": "Грешка при получаване на разрешение за достъп до камерата",
@@ -126,14 +126,14 @@
"noPermission": "Не е получено разрешение",
"previewUnavailable": "Няма възможност за преглед",
"selectADevice": "Изберете устройство",
"testAudio": "Пусни пробен звук"
"testAudio": ""
},
"dialog": {
"accessibilityLabel": {
"liveStreaming": "Излъчване на живо"
},
"allow": "Разрешаване",
"alreadySharedVideoMsg": "Друг участник вече е споделил видео. Тази среща позволява само едно споделено видео.",
"alreadySharedVideoMsg": "",
"alreadySharedVideoTitle": "Разрешено е споделянето само на едно видео в даден момент",
"applicationWindow": "Прозореца на програмата",
"Back": "Назад",
@@ -150,8 +150,8 @@
"conferenceDisconnectTitle": "Връзката се разпадна.",
"conferenceReloadMsg": "Опитваме се да оправим нещата. Повторно свързване след {{seconds}} сек…",
"conferenceReloadTitle": "За съжаление, нещо се обърка.",
"confirm": "Потвърждение",
"confirmNo": "Не",
"confirm": "",
"confirmNo": "",
"confirmYes": "Да",
"connectError": "Опа! Нещо се обърка и не успяхме да се свържем с конференцията.",
"connectErrorWithMsg": "Опа! Нещо се обърка и не успяхме да се свържем с конференцията: {{msg}}",
@@ -159,66 +159,66 @@
"contactSupport": "Връзка с отдела по поддръжка",
"copy": "Копиране",
"dismiss": "Отхвърляне",
"displayNameRequired": "Здравей! Как се казваш?",
"displayNameRequired": "",
"done": "Готово",
"enterDisplayName": "Моля въведете вашето име",
"enterDisplayName": "",
"error": "Грешка",
"externalInstallationMsg": "Трябва да инсталирате разширението за споделяне на екрана.",
"externalInstallationTitle": "Нужно е разширение",
"goToStore": "Към магазина в Интернет",
"gracefulShutdown": "Услугата временно не е достъпна поради профилактика. Моля опитайте по-късно.",
"IamHost": "Аз съм домакина",
"incorrectRoomLockPassword": "Грешна парола",
"incorrectRoomLockPassword": "",
"incorrectPassword": "Неправилно потребителско име или парола",
"inlineInstallationMsg": "Трябва да инсталирате разширението за споделяне на екрана.",
"inlineInstallExtension": "Инсталиране сега",
"internalError": "Опа! Нещо се обърка. Възникна следната грешка: {{error}}",
"internalErrorTitle": "Вътрешна грешка",
"kickMessage": "Може да се свържете с {{participantDisplayName}} за повече подробности.",
"kickParticipantButton": "Изгони",
"kickParticipantDialog": "Сигурни ли сте че искате да изгоните участника?",
"kickParticipantTitle": "Изгонване на този участник?",
"kickTitle": "Ауч! {{participantDisplayName}} ви изгони от тази среща",
"kickMessage": "",
"kickParticipantButton": "",
"kickParticipantDialog": "",
"kickParticipantTitle": "",
"kickTitle": "",
"liveStreaming": "Излъчване на живо",
"liveStreamingDisabledForGuestTooltip": "Гостите не могат да стартират излъчване на живо.",
"liveStreamingDisabledTooltip": "Излъчването на живо е деактивирано.",
"liveStreamingDisabledForGuestTooltip": "",
"liveStreamingDisabledTooltip": "",
"lockMessage": "Неуспешно заключване на конференцията.",
"lockRoom": "Добавяне $t(lockRoomPasswordUppercase) за срещата",
"lockRoom": "",
"lockTitle": "Неуспешно заключване",
"logoutQuestion": "Сигурни ли сте, че искате да излезете и да прекъснете конференцията?",
"logoutTitle": "Изход",
"maxUsersLimitReached": "Лимитът за максимален брой участници бе достигнат. Капацитета на срещата е запълнен. Моля свържете се с организатора или опитайте по-късно!",
"maxUsersLimitReachedTitle": "Достигнат е лимита за максимален брой участници",
"maxUsersLimitReached": "",
"maxUsersLimitReachedTitle": "",
"micConstraintFailedError": "Микрофонът Ви не покрива някои от изискванията.",
"micNotFoundError": "Не е открит микрофон.",
"micNotSendingData": "Пуснете микрофона си от системните настройки на компютъра ви.",
"micNotSendingDataTitle": "Микрофона ви е спрян от системните настройки",
"micNotSendingData": "",
"micNotSendingDataTitle": "",
"micPermissionDeniedError": "Не сте дали разрешение за използване на микрофона. Ще можете да се присъедините в беседата, но другите няма да Ви чуват. Използвайте бутона с камерата в адресната лента, за да оправите това.",
"micUnknownError": "Невъзможен достъп до микрофона по неясна причина.",
"micUnknownError": "Не възможен достъп до микрофона по неясна причина.",
"muteParticipantBody": "Вие няма да можете да спрете заглушаването на участника, но той ще може да го направи по всяко време.",
"muteParticipantButton": "Изключи микрофона",
"muteParticipantDialog": "Сигурни ли сте че искате да заглушите този участник? Няма да можете да пуснете обратно звука му, но участника ще може да направи това сам.",
"muteParticipantTitle": "Спиране звука на участник?",
"muteParticipantDialog": "",
"muteParticipantTitle": "",
"Ok": "Готово",
"passwordLabel": "Парола",
"passwordNotSupported": "Задаването на $t(lockRoomPassword) за срещата не се поддържа.",
"passwordNotSupportedTitle": "$t(lockRoomPasswordUppercase) не се поддържа",
"passwordRequired": "Изисква се $t(lockRoomPassword) ",
"passwordLabel": "",
"passwordNotSupported": "Задаването на парола за срещата не се поддържа.",
"passwordNotSupportedTitle": "",
"passwordRequired": "",
"popupError": "Браузърът Ви блокира изскачащите прозорци от този уеб сайт. Моля, разрешете изскачащите прозорци от настройките за сигурност на браузъра си и след това опитайте отново.",
"popupErrorTitle": "Блокиран изскачащ прозорец",
"recording": "Запис",
"recordingDisabledForGuestTooltip": "Гостите не могат да стартират запис",
"recordingDisabledTooltip": "Стартирането на запис е спряно",
"recordingDisabledForGuestTooltip": "",
"recordingDisabledTooltip": "",
"rejoinNow": "Повторно присъединяване сега",
"remoteControlAllowedMessage": "{{user}} прие заявката Ви за отдалечено управление!",
"remoteControlDeniedMessage": "{{user}} отказа заявката Ви за отдалечено управление!",
"remoteControlErrorMessage": "Възникна грешка при опита за искане на разрешение за отдалечено управление от {{user}}!",
"remoteControlErrorMessage": "Възникна грешка при опита за искана на разрешение за отдалечено управление от {{user}}!",
"remoteControlRequestMessage": "Ще позволите ли на {{user}} да управлява отдалечено компютъра Ви?",
"remoteControlShareScreenWarning": "Ако натиснете „Разрешаване“, ще споделите екрана си!",
"remoteControlStopMessage": "Сесията за отдалечено управление приключи!",
"remoteControlTitle": "Отдалечено управление на компютъра",
"Remove": "Премахване",
"removePassword": "Премахване на $t(lockRoomPassword)",
"removePassword": "",
"removeSharedVideoMsg": "Наистина ли искате да премахнете споделеното си видео?",
"removeSharedVideoTitle": "Край на споделянето на видео",
"reservationError": "Грешка в системата за резервации",
@@ -226,8 +226,8 @@
"retry": "Повторен опит",
"screenSharingFailedToInstall": "Опа! Разширението за споделяне на екрана не успя да се инсталира.",
"screenSharingFailedToInstallTitle": "Разширението за споделяне на екрана не успя да се инсталира",
"screenSharingFirefoxPermissionDeniedError": "Нещо се обърка докато се опитвахме да споделим екрана. Моля уверете се че сте дали права за това.",
"screenSharingFirefoxPermissionDeniedTitle": "Упс! Не успяхме да стартираме споделянето на екрана!",
"screenSharingFirefoxPermissionDeniedError": "",
"screenSharingFirefoxPermissionDeniedTitle": "",
"screenSharingPermissionDeniedError": "Опа! Нещо се обърка с разрешенията на разширението за споделяне на екрана. Моля, презаредете и опитайте отново.",
"serviceUnavailable": "Услугата не е налична",
"sessTerminated": "Разговорът приключи",
@@ -235,86 +235,91 @@
"shareVideoLinkError": "Моля въведете правилна връзка към YouTube.",
"shareVideoTitle": "Сподели видео",
"shareYourScreen": "Споделяне на екрана",
"shareYourScreenDisabled": "Споделянето на екрана не се поддържа.",
"shareYourScreenDisabledForGuest": "Гостите не могат да споделят екрана.",
"shareYourScreenDisabled": "",
"shareYourScreenDisabledForGuest": "",
"startLiveStreaming": "Започване на излъчване на живо",
"startRecording": "Стартиране на запис",
"startRecording": "Край на записа",
"startRemoteControlErrorMessage": "Възникна грешка при опита за започване на сесията за отдалечено управление!",
"stopLiveStreaming": "Спиране на излъчването на живо",
"stopRecording": "Край на записа",
"stopRecordingWarning": "Наистина ли искате да спрем записа?",
"stopStreamingWarning": "Наистина ли искате да спрете излъчването на живо?",
"streamKey": "Ключ за излъчване на живо",
"streamKey": "",
"Submit": "Изпращане",
"thankYou": "Благодарим, че използвахте {{appName}}!",
"token": "код за достъп",
"tokenAuthFailed": "Съжаляваме, но не можете да се присъедините към този разговор.",
"tokenAuthFailedTitle": "Неуспешна идентификация",
"transcribing": "Транскрипция",
"unlockRoom": "Премахване $t(lockRoomPassword) от срещата",
"transcribing": "",
"unlockRoom": "",
"userPassword": "потребителска парола",
"WaitForHostMsg": "Конференцията <b>{{room}}</b> все още не е започнала. Ако сте домакинът тогава се идентифицирайте. В противен случай изчакайте докато домакинът пристигне.",
"WaitForHostMsgWOk": "Конференцията <b>{{room}}</b> все още не е започнала. Ако сте домакинът тогава натиснете бутона за да се идентифицирате. В противен случай изчакайте докато домакинът пристигне.",
"WaitForHostMsg": "",
"WaitForHostMsgWOk": "",
"WaitingForHost": "Чакаме домакина ...",
"Yes": "Да",
"yourEntireScreen": "Целия екран"
},
"\u0005dialog": {
"accessibilityLabel": {}
},
"dialOut": {
"statusMessage": "в момента е {{status}}"
},
"feedback": {
"average": "Средно",
"bad": "Лошо",
"detailsLabel": "Разкажете ни повече.",
"detailsLabel": "",
"good": "Добра",
"rateExperience": "Моля, оценете качеството на срещата.",
"veryBad": "Много лошо",
"veryGood": "Много добра"
},
"\u0005feedback": {},
"incomingCall": {
"answer": "Вдигни",
"audioCallTitle": "Входящ разговор",
"answer": "",
"audioCallTitle": "",
"decline": "Отхвърляне",
"productLabel": "от Jitsi Meet",
"videoCallTitle": "Входящ видео разговор"
"productLabel": "",
"videoCallTitle": ""
},
"info": {
"accessibilityLabel": "Покажи информация",
"addPassword": "Добави $t(lockRoomPassword)",
"cancelPassword": "Премахни $t(lockRoomPassword)",
"conferenceURL": "Връзка:",
"country": "Страна",
"dialANumber": "За влизане в срещата, наберете един от изброените номера и въведете кода.",
"dialInConferenceID": "Код:",
"dialInNotSupported": "Съжаляваме, обаждането в момента не се поддържа. ",
"dialInNumber": "Тел:",
"dialInSummaryError": "Проблем при достъпа на информация за опциите за влизане през телефон. Моля опитайте отново по-късно.",
"dialInTollFree": "Безплатен",
"genericError": "Упс, нещо се случи.",
"inviteLiveStream": "За да видите предаването на живо на срещата, използвйте тази връзка: {{url}}",
"invitePhone": "За влизане през телефон, използвайте: {{number}},,{{conferenceID}}#\n",
"invitePhoneAlternatives": "Търсене на друг номер за набиране?\nВижте още номера: : {{url}}\n\n\nАко вече сте набрали от телефон в стаята, влезте без да е пуснат звука: {{silentUrl}}",
"inviteURLFirstPartGeneral": "Поканени сте да се присъедините към среща.",
"inviteURLFirstPartPersonal": "{{name}} ви кани за среща.\n",
"inviteURLSecondPart": "\nВлезте в срещата:\n{{url}}\n",
"liveStreamURL": "Излъчване на живо:",
"moreNumbers": "Повече номера",
"noNumbers": "Няма номера за набиране.",
"accessibilityLabel": "",
"addPassword": "",
"cancelPassword": "",
"conferenceURL": "",
"country": "",
"dialANumber": "",
"dialInConferenceID": "",
"dialInNotSupported": "",
"dialInNumber": "",
"dialInSummaryError": "",
"dialInTollFree": "",
"genericError": "",
"inviteLiveStream": "",
"invitePhone": "",
"invitePhoneAlternatives": "",
"inviteURLFirstPartGeneral": "",
"inviteURLFirstPartPersonal": "",
"inviteURLSecondPart": "",
"liveStreamURL": "Излъчване на живо",
"moreNumbers": "",
"noNumbers": "",
"noPassword": "Няма",
"noRoom": "Няма посочена стая за информация за номера за набиране.",
"numbers": "Номера",
"password": "$t(lockRoomPasswordUppercase):",
"noRoom": "",
"numbers": "",
"password": "",
"title": "Споделяне",
"tooltip": "Споделете връзката и информацията за номера свързани със срещата",
"label": "Информация за срещата"
"tooltip": "",
"label": ""
},
"\u0005info": {},
"inviteDialog": {
"alertText": "Не успях да поканя участниците.",
"alertText": "",
"header": "Покани",
"searchCallOnlyPlaceholder": "Въведете телефонен номер",
"searchPeopleOnlyPlaceholder": "Търсене на участници",
"searchPlaceholder": "Участник или телефонен номер",
"send": "Изпрати"
"searchPeopleOnlyPlaceholder": "",
"searchPlaceholder": "",
"send": ""
},
"inlineDialogFailure": {
"msg": "Имаше грешка.",
@@ -324,182 +329,181 @@
},
"keyboardShortcuts": {
"focusLocal": "Фокусиране върху Вашето видео",
"focusRemote": "Фокусирай видеото на друг участник",
"focusRemote": "Фокусиране върху видеото на друг участник",
"fullScreen": "Влизане/излизане от режим на цял екран",
"keyboardShortcuts": "Клавишни комбинации",
"localRecording": "Показване или скриване на контролите за локален запис",
"localRecording": "",
"mute": "Спиране/пускане на микрофона",
"pushToTalk": "Натиснете, за да говорите",
"raiseHand": "Вдигнете или свалете ръка",
"showSpeakerStats": "Показване на статистика за говорителя",
"toggleChat": "Отваряне/скриване на текстовите съобщения",
"toggleFilmstrip": "Показване или скриване на видео миниатюрите",
"toggleFilmstrip": "",
"toggleScreensharing": "Смяна между камера и споделен екран",
"toggleShortcuts": "Показване или скриване на клавишните комбинации",
"videoMute": "Пускане/спиране на камерата",
"videoQuality": "Управление на качество на обаждането"
"toggleShortcuts": "",
"videoMute": "Пускане/спиране на камерата"
},
"\u0005keyboardShortcuts": {},
"liveStreaming": {
"busy": "Работим върху това да освободим ресурси за излъчване. Моля, опитайте отново след няколко минути.",
"busyTitle": "Всички излъчватели в момента са заети.",
"changeSignIn": "Смяна на акаунти.",
"choose": "Изберете предаване на живо",
"chooseCTA": "Изберете опция за предаване. Влезли сте като {{email}}.",
"enterStreamKey": "Въведете ключа от YouTube за предаване на живо.",
"changeSignIn": "",
"choose": "",
"chooseCTA": "",
"enterStreamKey": "",
"error": "Излъчването на живо беше неуспешно. Моля, опитайте отново.",
"errorAPI": "Изникна проблем с връзката към YouTube. Моля опитайте отново.",
"errorLiveStreamNotEnabled": "Предаването на живо не е пуснато за {{email}}. Моля активирайте го или сменете акаунта.",
"expandedOff": "Предаването на живо бе спряно",
"expandedOn": "Срещата се излъчва на живо в YouTube.",
"expandedPending": "Излъчването на живо се стартира...",
"errorAPI": "",
"errorLiveStreamNotEnabled": "",
"expandedOff": "",
"expandedOn": "",
"expandedPending": "",
"failedToStart": "Излъчването на живо не успя да започне",
"getStreamKeyManually": "Не успяхме да открием никакво предаване на живо. Опитайте да вземете ключа за такова от YouTube.",
"invalidStreamKey": "Ключът за предаване на живо е грешен.",
"getStreamKeyManually": "",
"invalidStreamKey": "",
"off": "Край на излъчването на живо",
"offBy": "{{name}} спря излъчването на живо",
"on": "Излъчване на живо",
"onBy": "{{name}} пусна излъчване на живо",
"pending": "Започване на излъчването на живо…",
"serviceName": "Предаване на живо",
"signedInAs": "В момента сте влезли като:",
"signIn": "Влезте с Гугъл",
"signInCTA": "Влезте или въведете ключът за излъчване на живо от YouTube.",
"serviceName": "",
"signedInAs": "",
"signIn": "",
"signInCTA": "",
"signOut": "",
"start": "Започни излъчване на живо",
"streamIdHelp": "Какво е това?",
"start": "Започване на излъчване на живо",
"streamIdHelp": "",
"unavailableTitle": "Излъчването на живо е недостъпно"
},
"\u0005liveStreaming": {},
"localRecording": {
"clientState": {
"off": "Изключено",
"on": "Включено",
"unknown": "Непознат"
"off": "",
"on": "",
"unknown": ""
},
"dialogTitle": "Управление на локален запис",
"duration": "Продължителност",
"durationNA": "Няма",
"encoding": "Кодек",
"label": "Етикет",
"labelToolTip": "Локалния запис е включен",
"localRecording": "Локален запис",
"dialogTitle": "",
"duration": "",
"durationNA": "",
"encoding": "",
"label": "",
"labelToolTip": "",
"localRecording": "",
"me": "Аз",
"messages": {
"engaged": "Локалния запис е включен.",
"finished": "Записа на сесията {{token}} приключи. Моля изпратете записа на вашият домакин.",
"finishedModerator": "Сесията {{token}} за запис приключи. Локалният запис беше запазен. Моля поканете останалите участници да ви изпратят техните записи.",
"notModerator": "Нямате права да пускате спирате локален запис."
"engaged": "",
"finished": "",
"finishedModerator": "",
"notModerator": ""
},
"moderator": "Модератор",
"no": "Не",
"no": "",
"participant": "Участник",
"participantStats": "Статистика на участник",
"sessionToken": "Тоукън за сесията",
"start": "Започни запис",
"stop": "Спри записа",
"participantStats": "",
"sessionToken": "",
"start": "Край на записа",
"stop": "Край на записа",
"yes": "Да"
},
"\u0005localRecording": {},
"lockRoomPassword": "парола",
"lockRoomPasswordUppercase": "Парола",
"me": "аз",
"notify": {
"connectedOneMember": "{{name}} влезна в срещата",
"connectedThreePlusMembers": "{{name}} и още {{count}} влезнаха в срещата",
"connectedTwoMembers": "{{first}} и {{second}} влезнаха в срещата",
"disconnected": "Напусна срещата",
"connectedOneMember": "",
"connectedThreePlusMembers": "",
"connectedTwoMembers": "",
"disconnected": "Връзка:",
"focus": "Конферентен фокус",
"focusFail": "{{component}} не е на раположение - следващ опит след {{ms}} секунди",
"focusFail": "{{component}} не е на раположения - следващ опит след {{ms}} секунди",
"grantedTo": "Даване на роля модератор на {{to}}!",
"invitedOneMember": "{{name}} бе поканен",
"invitedThreePlusMembers": "{{name}} и още {{count}} бяха поканени",
"invitedTwoMembers": "{{first}} и {{second}} бяха поканени",
"kickParticipant": "{{kicked}} беше изгонен от {{kicker}}",
"invitedOneMember": "",
"invitedThreePlusMembers": "",
"invitedTwoMembers": "",
"kickParticipant": "",
"me": "Аз",
"moderator": "Придобихте права на модератор!",
"muted": "Започвате разговора без звук.",
"mutedTitle": "Звукът ви е спрян!",
"mutedRemotelyTitle": "Микрофонът ви бе спрян от {{participantDisplayName}}!",
"mutedRemotelyDescription": "Винаги можете да пуснете микрофона си когато сте готови да говорите. Заглушете го отново за да не изпращате шум в срещата.",
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) е премахната от друг потребител",
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) създадена от друг потребител",
"raisedHand": "{{name}} иска думата.",
"mutedRemotelyTitle": "",
"mutedRemotelyDescription": "",
"passwordRemovedRemotely": "",
"passwordSetRemotely": "",
"raisedHand": "",
"somebody": "Някой",
"startSilentTitle": "Влязохте с опция да не чувате аудио!",
"startSilentDescription": "Влезте повторно за да пуснете звука",
"suboptimalBrowserWarning": "Опасяваме се, че няма да можете да се насладите на срещата. Работим по въпроса, междувременно използвайте някой от <a href='static/recommendedBrowsers.html' target='_blank'>напълно поддържаните браузъри</a>.",
"suboptimalExperienceTitle": "Внимание",
"unmute": "Пускане на микрофона",
"newDeviceCameraTitle": "Засечена е нова камера",
"newDeviceAudioTitle": "Ново аудио устройство е засечено",
"newDeviceAction": "Използвай"
"startSilentTitle": "",
"startSilentDescription": "",
"suboptimalExperienceDescription": "",
"suboptimalExperienceTitle": "",
"unmute": "",
"newDeviceCameraTitle": "",
"newDeviceAudioTitle": "",
"newDeviceAction": ""
},
"passwordSetRemotely": "зададена от друг участник",
"passwordDigitsOnly": "До {{number}} цифри",
"passwordSetRemotely": "",
"passwordDigitsOnly": "",
"poweredby": "с подкрепата на",
"presenceStatus": {
"busy": "Зает",
"calling": "Обаждане...",
"busy": "",
"calling": "",
"connected": "Свързан",
"connecting": "Свързване...",
"connecting2": "Свързване*...",
"connecting": "Свързване",
"connecting2": "Свързване",
"disconnected": "Изключен",
"expired": "Изтекъл",
"ignored": "Пренебрегнат",
"initializingCall": "Свързване на обаждането...",
"invited": "Поканен",
"rejected": "Отхвърлен",
"ringing": "Звъни..."
"expired": "",
"ignored": "",
"initializingCall": "",
"invited": "Покани",
"rejected": "",
"ringing": ""
},
"\u0005presenceStatus": {},
"profile": {
"setDisplayNameLabel": "Задайте екранното си име",
"setEmailInput": "Въведете е-поща",
"setEmailLabel": "Задайте е-пощата си в „gravatar“",
"title": "Профил"
},
"raisedHand": "Иска думата",
"recording": {
"authDropboxText": "Качете в Dropbox",
"availableSpace": "Налично място: {{spaceLeft}} MB (приблизително {{duration}} минути запис)",
"beta": "БЕТА",
"authDropboxText": "",
"availableSpace": "",
"beta": "",
"busy": "Работим върху това да освободим ресурси за запис. Моля, опитайте отново след няколко минути.",
"busyTitle": "Всички възможности за запис в момента са заети",
"error": "Грешка при опит за запис. Моля опитайте отново.",
"expandedOff": "Записът спря",
"expandedOn": "Срещата се записва в момента",
"expandedPending": "Записът започва...",
"expandedOff": "Записът спрян",
"expandedOn": "",
"expandedPending": "Записът започна",
"failedToStart": "Неуспешен опит за записване",
"fileSharingdescription": "Споделете записа с участниците в срещата",
"live": "На Живо",
"loggedIn": "Влезли сте като {{userName}}",
"fileSharingdescription": "",
"live": "",
"loggedIn": "",
"off": "Записът спрян",
"offBy": "{{name}} спря записът",
"on": "Запис",
"onBy": "{{name}} пусна запис",
"pending": "Стартира запис на срещата...",
"rec": "ЗАПИС",
"serviceDescription": "Записът ви ще се запише от специална записваща услуга",
"serviceName": "Записваща услуга",
"signIn": "Влизане",
"signOut": "Излизане",
"unavailable": "Упс! В момент {{serviceName}} е недостъпна. В момента се опитваме да решим проблема. Моля опитайте отново малко по-късно.",
"pending": "",
"rec": "",
"serviceDescription": "",
"serviceName": "",
"signIn": "",
"signOut": "",
"unavailable": "",
"unavailableTitle": "Записът е невъзможен"
},
"\u0005recording": {},
"sectionList": {
"pullToRefresh": "Издърпай за да се обнови"
"pullToRefresh": ""
},
"settings": {
"calendar": {
"about": "Календарната интеграция на {{appName}} сигурно достъпва вашия календар за да покаже настъпващите събития.",
"disconnect": "Разкачи",
"microsoftSignIn": "Влез с Microsoft акаунт",
"signedIn": "В момента достъпва календара с {{email}}. Натиснете бутона Разкачи за да спрете достъпа.",
"about": "",
"disconnect": "Изключен",
"microsoftSignIn": "",
"signedIn": "",
"title": ""
},
"devices": "Устройства",
"devices": "",
"followMe": "Всички ме следват",
"language": "Език",
"loggedIn": "Влезли сте като {{name}}",
"language": "",
"loggedIn": "",
"moderator": "Модератор",
"more": "Повече",
"more": "",
"name": "Име",
"noDevice": "Няма",
"selectAudioOutput": "Звуков изход",
@@ -509,24 +513,27 @@
"startVideoMuted": "Всички започват скрити",
"title": "Настройки"
},
"\u0005settings": {
"calendar": {}
},
"settingsView": {
"alertOk": "Потвърди",
"alertOk": "",
"alertTitle": "Внимание",
"alertURLText": "Въведената връзка за сървър е невалидна",
"buildInfoSection": "Информация за програмата",
"conferenceSection": "Конференция",
"displayName": "Име",
"email": "Поща",
"alertURLText": "",
"buildInfoSection": "",
"conferenceSection": "",
"displayName": "",
"email": "",
"header": "Настройки",
"profileSection": "Профил",
"serverURL": "Линк на сървъра",
"startWithAudioMuted": "Започни със спрян звук",
"startWithVideoMuted": "Започни със спряно видео",
"version": "Версия"
"serverURL": "",
"startWithAudioMuted": "",
"startWithVideoMuted": "",
"version": ""
},
"share": {
"dialInfoText": "\n\n=====\n\nИскате да наберете от телефона?\n\n{{defaultDialInNumber}}Използвайте този линк за повече номера\n{{dialInfoPageUrl}}",
"mainText": "Използвайте линка за да влезете в срещата:\n{{roomUrl}}"
"dialInfoText": "",
"mainText": ""
},
"speaker": "Говорещ",
"speakerStats": {
@@ -548,95 +555,99 @@
},
"toolbar": {
"accessibilityLabel": {
"audioOnly": "Пускане на режим само с звук",
"audioOnly": "",
"audioRoute": "",
"callQuality": "Управление на качестото на обаждането",
"cc": "Пускане на субтитри",
"chat": "Активиране на прозорец за съобщения",
"document": "Показване на споделен документ",
"callQuality": "",
"cc": "",
"chat": "",
"document": "Отваряне/затваряне на споделен документ",
"feedback": "",
"fullScreen": "Пускане/Спиране на изглед в цял екран",
"hangup": "Напускане на срещата",
"fullScreen": "",
"hangup": "",
"invite": "Поканете участници",
"kick": "Изгони участник",
"localRecording": "Показване на контроли за локален запис",
"lockRoom": "Смяна парола на среща",
"moreActions": "Показване на меню с повече опции",
"moreActionsMenu": "Меню с повече опции",
"mute": "Пускане/спиране на видеото",
"pip": "Пускане на Картина-в-Картина",
"kick": "",
"localRecording": "",
"lockRoom": "",
"moreActions": "",
"moreActionsMenu": "",
"mute": "",
"pip": "",
"profile": "Редактиране на профила",
"raiseHand": "Смяна искане на думата",
"recording": "Пускане/спиране на запис",
"remoteMute": "Заглуши участник",
"Settings": "Промяна на настройки",
"sharedvideo": "Споделяне на YouTube видео",
"raiseHand": "",
"recording": "",
"remoteMute": "",
"Settings": "",
"sharedvideo": "",
"shareRoom": "",
"shareYourScreen": "Споделяне на екрана",
"shortcuts": "Бързи клавиши",
"shareYourScreen": "",
"shortcuts": "",
"show": "",
"speakerStats": "Показване на статистики за участниците",
"speakerStats": "",
"tileView": "",
"toggleCamera": "",
"videomute": "Пускане/спиране на видеото",
"videoblur": "Пускане/спиране на замъгляване на видеото"
"videomute": "",
"videoblur": ""
},
"addPeople": "Добавяне на участници в разговора",
"audioOnlyOff": "Спиране режима с нисък трафик",
"audioOnlyOn": "Пускане режима с нисък трафик",
"audioRoute": "Изберете устройство за звук",
"audioOnlyOff": "",
"audioOnlyOn": "",
"audioRoute": "",
"authenticate": "Идентификация",
"callQuality": "Промяна качеството на видеото",
"callQuality": "",
"chat": "Отваряне/затваряне на текстовите съобщения",
"closeChat": "Затваряне на съобщенията",
"documentClose": "Затваряне на споделеният документ",
"documentOpen": "Отваряне на споделен документ",
"enterFullScreen": "Вижте на цял екран",
"enterTileView": "Влизане в изглед галерия",
"exitFullScreen": "Изход от цял екран",
"exitTileView": "Спиране на изглед галерия",
"feedback": "Отзиви",
"closeChat": "",
"documentClose": "Отваряне/затваряне на споделен документ",
"documentOpen": "Отваряне/затваряне на споделен документ",
"enterFullScreen": "",
"enterTileView": "",
"exitFullScreen": "",
"exitTileView": "",
"feedback": "",
"hangup": "Напускане",
"invite": "Поканете участници",
"login": "Влез",
"logout": "Изход",
"lowerYourHand": "Махни искането на думата",
"moreActions": "Още опции",
"lowerYourHand": "",
"moreActions": "",
"mute": "Спиране/пускане на микрофона",
"openChat": "Отвори съобщенията",
"pip": "Пусни Картина-в-Картина",
"openChat": "",
"pip": "",
"profile": "Редактиране на профила",
"raiseHand": "Вдигане/сваляне на ръка",
"raiseYourHand": "Поискай думата",
"raiseYourHand": "Вдигни ръка.",
"Settings": "Настройки",
"sharedvideo": "Пускане/спиране на споделянето на екрана",
"shareRoom": "Добавете някого",
"shortcuts": "Виж бързите клавиши",
"speakerStats": "Статистика за говорителите",
"startScreenSharing": "Започни споделяне на екрана",
"startSubtitles": "Пускане на субтитри",
"stopScreenSharing": "Спиране споделяне на екрана",
"stopSubtitles": "Спиране на субтитри",
"stopSharedVideo": "Спиране на YouTube видео",
"shareRoom": "",
"shortcuts": "",
"speakerStats": "Статистика на говорителя",
"startScreenSharing": "",
"startSubtitles": "",
"stopScreenSharing": "",
"stopSubtitles": "",
"stopSharedVideo": "",
"talkWhileMutedPopup": "Опитвате се да говорите? В момента микрофонът Ви е заглушен.",
"tileViewToggle": "Превключване на изглед галерия",
"toggleCamera": "Пускане/спиране на камера",
"tileViewToggle": "",
"toggleCamera": "",
"videomute": "Пускане/спиране на камерата",
"startvideoblur": "Замъгли фона ми",
"stopvideoblur": "Спиране замъгляването на фона"
"startvideoblur": "",
"stopvideoblur": ""
},
"\u0005toolbar": {
"accessibilityLabel": {}
},
"transcribing": {
"ccButtonTooltip": "Пускане / Спиране на субтитри",
"error": "Грешка при опит за транскрибиране. Моля опитайте отново.",
"expandedLabel": "Транскрибирането е пуснато",
"failedToStart": "Транскрибирането не успя при пускане",
"labelToolTip": "Тази среща се транскрибира",
"off": "Транскрибирането спря",
"pending": "Стартира се транскрибиране на срещата...",
"start": "Започва показване на субтитри",
"stop": "Спира показване на субтитри",
"tr": "СУБ"
"ccButtonTooltip": "",
"error": "Грешка при опит за запис. Моля опитайте отново.",
"expandedLabel": "",
"failedToStart": "",
"labelToolTip": "",
"off": "",
"pending": "",
"start": "",
"stop": "",
"tr": ""
},
"\u0005transcribing": {},
"userMedia": {
"androidGrantPermissions": "Изберете <b><i>Разрешаване</i></b>, когато браузърът Ви помоли за разрешение.",
"chromeGrantPermissions": "Изберете <b><i>Разрешаване</i></b>, когато браузърът Ви помоли за разрешение.",
@@ -650,34 +661,31 @@
"safariGrantPermissions": "Изберете <b><i>Добре</i></b>, когато браузърът Ви помоли за разрешение."
},
"videoSIPGW": {
"busy": "Работим по освобождаване на ресурси. Моля, опитайте след няколко минути.",
"busyTitle": "Услугата за стаи в момента е заета",
"errorAlreadyInvited": "{{displayName}} вече е поканен",
"errorInvite": "Конференцията не е стартирана. Моля, опитайте по-късно.",
"errorInviteFailed": "Работим по разрешаването на проблем. Моля, опитайте по-късно.",
"errorInviteFailedTitle": "Добавянето на {{displayName}} не успя",
"errorInviteTitle": "Грешка при добавяне на стая",
"pending": "{{displayName}} бе поканен"
"busy": "",
"busyTitle": "",
"errorAlreadyInvited": "",
"errorInvite": "",
"errorInviteFailed": "",
"errorInviteFailedTitle": "",
"errorInviteTitle": "",
"pending": ""
},
"videoStatus": {
"audioOnly": "АУДИО",
"audioOnlyExpanded": "Вие сте в режим на нисък трафик. В този режим ще получавате само аудио или споделени екрани.",
"callQuality": "Качество на видеото",
"audioOnly": "",
"audioOnlyExpanded": "",
"callQuality": "",
"hd": "ВК",
"hdTooltip": "Гледате високо качество на видеото",
"highDefinition": "Високо качество",
"labelTooiltipNoVideo": "Няма видео",
"labelTooltipAudioOnly": "Пуснат режим на нисък трафик",
"labelTooiltipNoVideo": "",
"labelTooltipAudioOnly": "Включен е режим само със звук",
"ld": "НК",
"ldTooltip": "Виждате ниско качество на видеото",
"lowDefinition": "Ниско качество",
"onlyAudioAvailable": "Само аудио е налично",
"onlyAudioSupported": "Този браузър поддържа само аудио.",
"onlyAudioAvailable": "",
"onlyAudioSupported": "",
"p2pEnabled": "Вкл. директно свързване",
"p2pVideoQualityDescription": "В директна връзка, получаваното качество може да се сменя между високо и само аудио. Останалите настройки ще са достъпни когато връзката не е директна.",
"p2pVideoQualityDescription": "",
"recHighDefinitionOnly": "Ще се предпочита високо качество.",
"sd": "СК",
"sdTooltip": "Гледате стандартно качество на видеото",
"standardDefinition": "Стандартно качество"
},
"videothumbnail": {
@@ -685,39 +693,38 @@
"flip": "Огледално",
"kick": "Изгони",
"moderator": "Модератор",
"mute": "Участника е с изключен микрофон",
"mute": "Учасника е с изключен микрофон",
"muted": "Изключен микрофон",
"remoteControl": "Отдалечено управление",
"show": "Покажи на главния екран",
"videomute": "Участник е спрял камерата си"
"show": "",
"videomute": ""
},
"welcomepage": {
"accessibilityLabel": {
"join": "Натиснете за да влезете",
"join": "",
"roomname": "Въведете име на стаята"
},
"appDescription": "Хайде на видео разговорите с целият ви екип. Всъщност, поканете всички познати. {{app}} е напълно защитено, 100% решение за видеоконференции с отворен код което може да ползвате по цял ден, всеки ден, безплатно - без да ви е нужна регистрация.",
"appDescription": "",
"audioVideoSwitch": {
"audio": "Глас",
"video": "Видео"
"audio": "",
"video": ""
},
"calendar": "Календар",
"connectCalendarButton": "Свържете вашия календар",
"connectCalendarText": "Свържете вашия календар за да видите срещите си в {{app}}. Добавяйки {{provider}} срещите в календара си ще можете да ги старирате с едно докосване.",
"enterRoomTitle": "Започни нова среща",
"onlyAsciiAllowed": "Името на срещата може да съдържа само латински букви и цифри.",
"calendar": "",
"connectCalendarButton": "",
"connectCalendarText": "",
"enterRoomTitle": "",
"go": "НАПРЕД",
"join": "ПРИСЪЕДИНЯВАНЕ",
"info": "Информация",
"info": "",
"privacy": "Поверителност",
"recentList": "Скорошни срещи",
"recentListDelete": "Изтрий",
"recentListEmpty": "Списъка с скорошни срещи е празен. След като участвате в някоя среща, ще я намерите тук.",
"reducedUIText": "Добре дошли в {{app}}!",
"recentList": "",
"recentListDelete": "",
"recentListEmpty": "",
"reducedUIText": "",
"roomname": "Въведете име на стаята",
"roomnameHint": "Въведете името или връзката на стаята в която искате да влезете. Също може да си измислите име. Само го споделете с някой, за да може и той да въведе същото име за да се срещнете.",
"roomnameHint": "",
"sendFeedback": "Изпращане на отзиви",
"terms": "Условия",
"title": "Сигурна, с много възможности, и напълно безплатна платформа за видео конференции"
"title": ""
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,7 @@
"headphones": "Escotadors",
"phone": "Telefòn",
"speaker": "Nautparlaire",
"none": "Cap de periferic àudio pas disponible"
"none": ""
},
"audioOnly": {
"audioOnly": "Benda passanta febla"
@@ -182,7 +182,7 @@
"liveStreamingDisabledForGuestTooltip": "Los convidats pòdon pas aviar una difusion en dirècte",
"liveStreamingDisabledTooltip": "Difusion en dirècte desactivada.",
"lockMessage": "Impossible de verrolhar la conferéncia.",
"lockRoom": "Ajustar un $t(lockRoomPasswordUppercase) a la conferéncia",
"lockRoom": "",
"lockTitle": "Fracàs del verrolhatge",
"logoutQuestion": "Sètz segur que vos volètz desconnectar e arrestar la conferéncia ?",
"logoutTitle": "Desconnexion",
@@ -199,10 +199,10 @@
"muteParticipantDialog": "",
"muteParticipantTitle": "Copar lo micro als participants ?",
"Ok": "D'acòrdi",
"passwordLabel": "SENHAL",
"passwordNotSupported": "Ajustar un $t(lockRoomPassword) a una conferéncia es pas suportat.",
"passwordNotSupportedTitle": "$t(lockRoomPasswordUppercase) pas suportat",
"passwordRequired": "$t(lockRoomPasswordUppercase) requesit",
"passwordLabel": "",
"passwordNotSupported": "Ajustar un senhal a una conferéncia es pas suportat.",
"passwordNotSupportedTitle": "",
"passwordRequired": "",
"popupError": "Vòstre navigator bloca las fenèstras que sorgisson a partir d'aqueste site. Mercés d'activar aquelas fenèstras dins los paramètres de vòstre navigator e de tornar ensajar.",
"popupErrorTitle": "Fenèstra que sorgís blocada",
"recording": "Enregistrament",
@@ -217,7 +217,7 @@
"remoteControlStopMessage": "La session de contraròtle alonhat es acabada !",
"remoteControlTitle": "Contraròtle a distància",
"Remove": "Suprimir",
"removePassword": "Suprimir lo",
"removePassword": "",
"removeSharedVideoMsg": "Sètz segur que volètz suprimir vòstra vidèo partejada ?",
"removeSharedVideoTitle": "Suprimir la vidèo partejada",
"reservationError": "Error del sistèma de reservacion",
@@ -250,7 +250,7 @@
"tokenAuthFailed": "O planhèm, sètz pas autorizat a rejónher l'apèl.",
"tokenAuthFailedTitle": "Fracàs de l'autentificacion",
"transcribing": "Transcripcion",
"unlockRoom": "Suprimir lo $t(lockRoomPassword) de la conferéncia",
"unlockRoom": "",
"userPassword": "senhal utilizaire",
"WaitForHostMsg": "La conferéncia <b>{{room}}</b> a pas encara començat. Se sètz lòst volgatz ben vos identificar. Autrament esperatz quarribe lòste.",
"WaitForHostMsgWOk": "La conferéncia <b>{{room}}</b> a pas encara començat. Se sètz lòst volgatz ben clicar Ok per vos identificar. Autrament esperatz quarribe lòste.",
@@ -279,8 +279,8 @@
},
"info": {
"accessibilityLabel": "Mostrar las info",
"addPassword": "Ajustar un $t(lockRoomPassword)",
"cancelPassword": "Anullar lo $t(lockRoomPassword)",
"addPassword": "",
"cancelPassword": "",
"conferenceURL": "Ligam:",
"country": "País",
"dialANumber": "Per participar a la conferéncia, sonatz un daquestes numèros puèi picatz lo senhal.",
@@ -355,9 +355,7 @@
"getStreamKeyManually": "",
"invalidStreamKey": "La clau de difusion en dirècte es benlèu pas corrècta.",
"off": "La difusion en dirècte es estada arrestada",
"offBy": "",
"on": "La difusion en dirècte es estada arrestada",
"onBy": "",
"pending": "Començar lo dirècte...",
"serviceName": "Servici de difusion en dirècte",
"signedInAs": "Sètz connectat coma :",
@@ -418,8 +416,8 @@
"mutedTitle": "Sètz en mut !",
"mutedRemotelyTitle": "{{participantDisplayName}} vos a mes en silenci !",
"mutedRemotelyDescription": "",
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) tirat per un autre participant",
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) definit per un autre participant",
"passwordRemovedRemotely": "",
"passwordSetRemotely": "",
"raisedHand": "{{name}} volriá parlar.",
"somebody": "Qualqu'un",
"startSilentTitle": "Avètz jonch sens cap de sortida àudio !",
@@ -470,9 +468,7 @@
"live": "DIRÈCTE",
"loggedIn": "Session a {{userName}}",
"off": "Enregistrament arrestar",
"offBy": "",
"on": "Enregistrament",
"onBy": "",
"pending": "Preparacion de lenregistrament de la conferéncia...",
"rec": "ENRG",
"serviceDescription": "Vòstre enregistrament serà salvagardat pel servici dedicat.",
@@ -512,7 +508,7 @@
"alertOk": "Dacòrdi",
"alertTitle": "Avertiment",
"alertURLText": "LURL del servidor es pas valida",
"buildInfoSection": "Informacions de generacion",
"buildInfoSection": "",
"conferenceSection": "Conferéncia",
"displayName": "Escais-nom",
"email": "Corrièl",
@@ -557,7 +553,7 @@
"fullScreen": "Passar al ecran complèt",
"hangup": "Quitar la sonada",
"invite": "Convidar de monde",
"kick": "Exclure un participan ",
"kick": "",
"localRecording": "Passar al panèl denregistraments locals",
"lockRoom": "Tirar lo senhal de la conferéncia",
"moreActions": "Passar al menú mai daccions",
@@ -567,7 +563,7 @@
"profile": "Modificar vòstre perfil",
"raiseHand": "Demandar la paraula",
"recording": "Passar al enregistraments",
"remoteMute": "Copar lo son del participant",
"remoteMute": "",
"Settings": "Passar als paramètres",
"sharedvideo": "Passar al partatge de vidèo Youtube",
"shareRoom": "Convidar qualquun",
@@ -581,8 +577,8 @@
"videoblur": ""
},
"addPeople": "Ajustar de monde a vòstra sonada",
"audioOnlyOff": "Desactivar lo mòde connexion febla",
"audioOnlyOn": "Activar lo mòde connexion febla",
"audioOnlyOff": "",
"audioOnlyOn": "",
"audioRoute": "Seleccionar lo periferic àudio",
"authenticate": "Autentificatz-vos",
"callQuality": "Gerir la qualitat vidèo",
@@ -591,9 +587,9 @@
"documentClose": "Tampar los documents partejats",
"documentOpen": "Dobrir los documents partejats",
"enterFullScreen": "Veire lecran complèt",
"enterTileView": "Dintrar dins la vista mosaïca",
"enterTileView": "",
"exitFullScreen": "Sortir de lecran complèt",
"exitTileView": "Quitar la vista mosaïca",
"exitTileView": "",
"feedback": "Daissar un comentari",
"hangup": "Quitar",
"invite": "Convidar de monde",
@@ -621,8 +617,8 @@
"tileViewToggle": "Activar/Desactivar la vista en mosaïc",
"toggleCamera": "Passar a la camèra",
"videomute": "Aviar / Arrestar la camèra",
"startvideoblur": "Trebolar mon rèire-plan",
"stopvideoblur": "Desactivar lo borrolatge del rèire-plan"
"startvideoblur": "",
"stopvideoblur": ""
},
"transcribing": {
"ccButtonTooltip": "Aviar / Arrestat los sostítols",
@@ -660,13 +656,13 @@
},
"videoStatus": {
"audioOnly": "AUD",
"audioOnlyExpanded": "Sètz en mòde connexion febla. Amb aqueste mòde recebretz pas que làudio e lo partatge decran.",
"audioOnlyExpanded": "",
"callQuality": "Qualitat vidèo",
"hd": "HD",
"hdTooltip": "Difusion vidèo en nauta definicion",
"highDefinition": "Nauta definicion",
"labelTooiltipNoVideo": "Pas cap de vidèo",
"labelTooltipAudioOnly": "Mòde connexion febla activat",
"labelTooltipAudioOnly": "",
"ld": "Bassa definicion",
"ldTooltip": "Difusion vidèo en bassa definicion",
"lowDefinition": "Bassa definicion",
@@ -688,7 +684,7 @@
"muted": "Mut",
"remoteControl": "Contraròtle alonhat",
"show": "",
"videomute": "Lo participant a arrestat la camèra"
"videomute": ""
},
"welcomepage": {
"accessibilityLabel": {
@@ -702,12 +698,11 @@
},
"calendar": "Calendari",
"connectCalendarButton": "Connectar lo calendari",
"connectCalendarText": "Connectatz vòstre calendièr per veire vòstras reünions dins {{app}}. Ajustatz tanben las reünions de {{provider}} a vòstre calendièr e aviatz-las amb un sol clic.",
"connectCalendarText": "",
"enterRoomTitle": "Començar una nòva conferéncia",
"onlyAsciiAllowed": "",
"go": "Crear",
"join": "PARTICIPATZ",
"info": "Infor",
"info": "",
"privacy": "Vida privada",
"recentList": "Recents",
"recentListDelete": "Suprimits",

File diff suppressed because it is too large Load Diff

View File

@@ -21,11 +21,10 @@
"bluetooth": "Bluetooth",
"headphones": "Fones de ouvido",
"phone": "Celular",
"speaker": "Alto-falantes",
"none": ""
"speaker": "Apresentador"
},
"audioOnly": {
"audioOnly": "Largura de banda baixa"
"audioOnly": "Somente áudio"
},
"calendarSync": {
"addMeetingURL": "Adicionar um link da reunião",
@@ -50,9 +49,9 @@
"messagebox": "Digite uma mensagem",
"nickname": {
"popover": "Escolha um apelido",
"title": "Digite um apelido para usar o bate-papo"
"title": "Digite um apelido para usar o chat"
},
"title": "Bate-papo"
"title": "Chat"
},
"connectingOverlay": {
"joiningRoom": "Conectando você à reunião…"
@@ -97,7 +96,8 @@
"resolution": "Resolução:",
"status": "Conexão:",
"transport": "Transporte:",
"transport_plural": "Transportes:"
"transport_plural": "Transportes:",
"turn": " (virar)"
},
"dateUtils": {
"earlier": "Mais cedo",
@@ -107,7 +107,7 @@
"deepLinking": {
"appNotInstalled": "Você precisa do aplicativo móvel {{app}} para participar da reunião no seu telefone.",
"description": "Nada acontece? Estamos tentando iniciar sua reunião no aplicativo desktop {{app}}. Tente novamente ou inicie ele na aplicação web {{app}}.",
"descriptionWithoutWeb": "Nada aconteceu? Tentamos iniciar sua reunião no aplicativo de desktop {{app}}.",
"descriptionWithoutWeb": "",
"downloadApp": "Baixe o Aplicativo",
"launchWebButton": "Iniciar na web",
"openApp": "Continue na aplicação",
@@ -115,7 +115,6 @@
"tryAgainButton": "Tente novamente no desktop"
},
"defaultLink": "ex.: {{url}}",
"defaultNickname": "ex.: João Pedro",
"deviceError": {
"cameraError": "Falha ao acessar sua câmera",
"cameraPermission": "Erro ao obter permissão para a câmera",
@@ -133,7 +132,7 @@
"liveStreaming": "Transmissão ao vivo"
},
"allow": "Permitir",
"alreadySharedVideoMsg": "Outro participante já está compartilhando um vídeo. Esta conferência permite apenas um vídeo compartilhado por vez.",
"alreadySharedVideoMsg": "",
"alreadySharedVideoTitle": "Somente um vídeo compartilhado é permitido por vez",
"applicationWindow": "Janela de aplicativo",
"Back": "Voltar",
@@ -159,51 +158,51 @@
"contactSupport": "Contate o suporte",
"copy": "Copiar",
"dismiss": "Dispensar",
"displayNameRequired": "Oi! Qual o seu nome?",
"displayNameRequired": "",
"done": "Feito",
"enterDisplayName": "Digite seu nome aqui",
"enterDisplayName": "",
"error": "Erro",
"externalInstallationMsg": "Você precisa instalar nossa extensão de compartilhamento de tela.",
"externalInstallationTitle": "Extensão requerida",
"goToStore": "Vá para a loja virtual",
"gracefulShutdown": "O sistema está em manutenção. Por favor tente novamente mais tarde.",
"IamHost": "Eu sou o anfitrião",
"incorrectRoomLockPassword": "Senha incorreta",
"incorrectRoomLockPassword": "",
"incorrectPassword": "Usuário ou senha incorretos",
"inlineInstallationMsg": "Você precisa instalar nossa extensão de compartilhamento de tela.",
"inlineInstallExtension": "Instalar agora",
"internalError": "Oops! Alguma coisa está errada. O seguinte erro ocorreu: {{error}}",
"internalErrorTitle": "Erro interno",
"kickMessage": "Você pode contatar com {{participantDisplayName}} para obter mais detalhes.",
"kickMessage": "",
"kickParticipantButton": "Remover",
"kickParticipantDialog": "Tem certeza de que deseja remover este participante?",
"kickParticipantTitle": "Chutar este participante?",
"kickTitle": "Ai! {{participantDisplayName}} expulsou você da reunião",
"kickParticipantTitle": "Deixar mudo este participante?",
"kickTitle": "",
"liveStreaming": "Transmissão ao Vivo",
"liveStreamingDisabledForGuestTooltip": "Visitantes não podem iniciar transmissão ao vivo.",
"liveStreamingDisabledTooltip": "Iniciar transmissão ao vivo desativada.",
"lockMessage": "Falha ao travar a conferência.",
"lockRoom": "Adicionar reunião $t(lockRoomPasswordUppercase)",
"lockRoom": "",
"lockTitle": "Bloqueio falhou",
"logoutQuestion": "Deseja encerrar a sessão e finalizar a conferência?",
"logoutTitle": "Encerrar sessão",
"maxUsersLimitReached": "O limite para o número máximo de participantes foi atingido. A conferência está cheia. Entre em contato com o proprietário da reunião ou tente novamente mais tarde!",
"maxUsersLimitReachedTitle": "Limite máximo de participantes atingido",
"maxUsersLimitReached": "",
"maxUsersLimitReachedTitle": "",
"micConstraintFailedError": "Seu microfone não satisfaz algumas condições necessárias.",
"micNotFoundError": "O microfone não foi encontrado.",
"micNotSendingData": "Vá para as configurações do seu computador para ativar o som do microfone e ajustar seu nível",
"micNotSendingDataTitle": "Seu microfone está mudo pelas configurações do sistema",
"micNotSendingData": "",
"micNotSendingDataTitle": "",
"micPermissionDeniedError": "Não foi permitido acessar o seu microfone. Você ainda pode entrar na conferência, mas sem enviar áudio. Clique no botão do microfone para tentar reparar.",
"micUnknownError": "Não pode usar o microfone por uma razão desconhecida.",
"muteParticipantBody": "Você não está habilitado para tirar o mudo deles, mas eles podem tirar o mudo deles mesmos a qualquer tempo.",
"muteParticipantButton": "Mudo",
"muteParticipantDialog": "Tem certeza de que deseja silenciar este participante? Você não poderá desfazer isso, mas o participante pode reabilitar o áudio a qualquer momento.",
"muteParticipantDialog": "Tem certeza de que deseja silenciar este participante? Você não poderá desativar a opção silenciar dele, mas ele poderá fazer isso quando desejar.",
"muteParticipantTitle": "Deixar mudo este participante?",
"Ok": "Ok",
"passwordLabel": "$t(lockRoomPasswordUppercase)",
"passwordNotSupported": "A configuração de uma reunião $t(lockRoomPassword) não é suportada.",
"passwordNotSupportedTitle": "$t(lockRoomPasswordUppercase) não suportado",
"passwordRequired": "$t(lockRoomPasswordUppercase) requerido",
"passwordLabel": "",
"passwordNotSupported": "Configuração de senha para a reunião não é suportada.",
"passwordNotSupportedTitle": "",
"passwordRequired": "",
"popupError": "Seu navegador está bloqueando janelas popup deste site. Habilite os popups nas configurações de segurança no seu navegador e tente novamente.",
"popupErrorTitle": "Popup bloqueado",
"recording": "Gravando",
@@ -218,7 +217,7 @@
"remoteControlStopMessage": "A sessão de controle remoto terminou!",
"remoteControlTitle": "Conexão de área de trabalho remota",
"Remove": "Remover",
"removePassword": "Remove $t(lockRoomPassword)",
"removePassword": "",
"removeSharedVideoMsg": "Deseja remover seu vídeo compartilhado?",
"removeSharedVideoTitle": "Remover vídeo compartilhado",
"reservationError": "Erro de sistema de reserva",
@@ -251,7 +250,7 @@
"tokenAuthFailed": "Desculpe, você não está autorizado a entrar nesta chamada.",
"tokenAuthFailedTitle": "Falha de autenticação",
"transcribing": "Transcrevendo",
"unlockRoom": "Remove a reunião $t(lockRoomPassword)",
"unlockRoom": "",
"userPassword": "senha do usuário",
"WaitForHostMsg": "A conferência <b>{{room}}</b> ainda não começou. Se você é o anfitrião, faça a autenticação. Do contrário, aguarde a chegada do anfitrião.",
"WaitForHostMsgWOk": "A conferência <b>{{room}}</b> ainda não começou. Se você é o anfitrião, pressione Ok para autenticar. Do contrário, aguarde a chegada do anfitrião.",
@@ -280,8 +279,8 @@
},
"info": {
"accessibilityLabel": "Mostrar info",
"addPassword": "Adicione $t(lockRoomPassword)",
"cancelPassword": "Cancela $t(lockRoomPassword)",
"addPassword": "",
"cancelPassword": "",
"conferenceURL": "Link:",
"country": "País",
"dialANumber": "Para entrar na reunião, disque um desses números e depois insira o PIN.",
@@ -292,18 +291,18 @@
"dialInTollFree": "Chamada gratuita",
"genericError": "Oops, alguma coisa deu errado.",
"inviteLiveStream": "Para ver a transmissão ao vivo da reunião, clique no link: {{url}}",
"invitePhone": "Para participar por telefone, toque aqui: {{number}} ,, {{conferenceID}} # \\ n",
"invitePhoneAlternatives": "Procurando um número de discagem diferente?\nVeja os números de discagem da reunião: {{url}} \n\n\nSe você também estiver discando através de um telefone da sala, participe sem conectar-se ao áudio: {{silentUrl}}",
"invitePhone": "",
"invitePhoneAlternatives": "",
"inviteURLFirstPartGeneral": "Você foi convidado para uma reunião.",
"inviteURLFirstPartPersonal": "{{name}} está convidando você para uma reunião.\n",
"inviteURLSecondPart": "\nEntre na reunião:\n{{url}}\n",
"inviteURLFirstPartPersonal": "",
"inviteURLSecondPart": "",
"liveStreamURL": "Transmissão ao vivo:",
"moreNumbers": "Mais números",
"noNumbers": "Sem números de discagem.",
"noPassword": "Nenhum",
"noRoom": "Nenhuma sala foi especificada para entrar.",
"numbers": "Números de discagem",
"password": "$t(lockRoomPasswordUppercase):",
"password": "",
"title": "Compartilhar",
"tooltip": "Compartilhar link e discagem para esta reunião",
"label": "Informações da reunião"
@@ -336,8 +335,7 @@
"toggleFilmstrip": "Mostrar ou ocultar miniaturas de vídeo",
"toggleScreensharing": "Trocar entre câmera e compartilhamento de tela",
"toggleShortcuts": "Mostrar ou ocultar atalhos de teclado",
"videoMute": "Iniciar ou parar sua câmera",
"videoQuality": "Gerenciar qualidade da chamada"
"videoMute": "Iniciar ou parar sua câmera"
},
"liveStreaming": {
"busy": "Estamos trabalhando para liberar os recursos de transmissão. Tente novamente em alguns minutos.",
@@ -351,17 +349,15 @@
"errorLiveStreamNotEnabled": "Transmissão ao vivo não está ativada em {{email}}. Ative a transmissão ao vivo ou registre numa conta com transmissão ao vivo ativada.",
"expandedOff": "A transmissão ao vivo foi encerrada",
"expandedOn": "A reunião está sendo transmitida pelo YouTube.",
"expandedPending": "Iniciando a transmissão ao vivo...",
"expandedPending": "A transmissão ao vivo está sendo iniciada…",
"failedToStart": "Falha ao iniciar a transmissão ao vivo",
"getStreamKeyManually": "Não conseguimos buscar nenhuma transmissão ao vivo. Tente obter sua chave de transmissão ao vivo no YouTube.",
"getStreamKeyManually": "",
"invalidStreamKey": "A senha para transmissão ao vivo pode estar incorreta.",
"off": "Transmissão ao vivo encerrada",
"offBy": "",
"on": "Transmissão ao Vivo",
"onBy": "",
"pending": "Iniciando Transmissão ao Vivo...",
"serviceName": "Serviço de Transmissão ao Vivo",
"signedInAs": "Você está conectado como:",
"signedInAs": "Você está conectado atualmente como:",
"signIn": "Faça login no Google",
"signInCTA": "Faça login ou insira sua chave de transmissão ao vivo do YouTube.",
"signOut": "Sair",
@@ -371,16 +367,16 @@
},
"localRecording": {
"clientState": {
"off": "Desligado",
"on": "Ligado",
"off": "Off",
"on": "On",
"unknown": "Desconhecido"
},
"dialogTitle": "Controles da Gravação Local",
"duration": "Duração",
"durationNA": "N/D",
"durationNA": "N/A",
"encoding": "Codificando",
"label": "LOR",
"labelToolTip": "Gravação local ativada",
"labelToolTip": "Gravação local está envolvida",
"localRecording": "Gravação local",
"me": "Eu",
"messages": {
@@ -410,30 +406,30 @@
"focusFail": "{{component}} não disponĩvel - tente em {{ms}} seg.",
"grantedTo": "Direitos de moderador concedido para {{to}}!",
"invitedOneMember": "{{displayName}} foi convidado",
"invitedThreePlusMembers": "{{name}} e {{count}} outros foram convidados",
"invitedTwoMembers": "{{first}} e {{second}} foram convidados",
"kickParticipant": "{{kicked}} foi chutado por {{kicker}}",
"invitedThreePlusMembers": "",
"invitedTwoMembers": "",
"kickParticipant": "",
"me": "Eu",
"moderator": "Direitos de moderador concedidos!",
"muted": "Você iniciou uma conversa em mudo.",
"mutedTitle": "Você está mudo!",
"mutedRemotelyTitle": "Você foi silenciado por {{participantDisplayName}}!",
"mutedRemotelyDescription": "Você sempre pode ativar o som quando estiver pronto para falar. Retire o som quando terminar para manter o ruído longe da reunião.",
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) removido por outro participante",
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) definido por outro participante",
"mutedRemotelyTitle": "",
"mutedRemotelyDescription": "",
"passwordRemovedRemotely": "",
"passwordSetRemotely": "",
"raisedHand": "{{name}} gostaria de falar.",
"somebody": "Alguém",
"startSilentTitle": "Você entrou sem saída de áudio!",
"startSilentDescription": "Volte à reunião para habilitar o áudio",
"suboptimalBrowserWarning": "",
"startSilentTitle": "",
"startSilentDescription": "",
"suboptimalExperienceDescription": "Eer ... temos medo de que sua experiência com o {{appName}} não seja tão boa aqui. Estamos procurando maneiras de melhorar isso, mas até lá tente usar um dos <a href='static/recommendedBrowsers.html' target='_blank'> navegadores totalmente compatíveis</a>.",
"suboptimalExperienceTitle": "Alerta do navegador",
"unmute": "Ativar som",
"unmute": "",
"newDeviceCameraTitle": "Nova câmera detectada",
"newDeviceAudioTitle": "Novo dispositivo de áudio detectado",
"newDeviceAction": "Usar"
},
"passwordSetRemotely": "Definido por outro participante",
"passwordDigitsOnly": "Até {{number}} dígitos",
"passwordDigitsOnly": "",
"poweredby": "distribuído por",
"presenceStatus": {
"busy": "Ocupado",
@@ -447,7 +443,7 @@
"initializingCall": "Iniciando Chamada...",
"invited": "Convidar",
"rejected": "Rejeitado",
"ringing": "Tocando..."
"ringing": "Chamando..."
},
"profile": {
"setDisplayNameLabel": "Definir seu nome de exibição",
@@ -455,7 +451,6 @@
"setEmailLabel": "Definir seu email de gravatar",
"title": "Perfil"
},
"raisedHand": "Gostaria de falar",
"recording": {
"authDropboxText": "Enviar para o Dropbox.",
"availableSpace": "Espaço disponível: {{spaceLeft}} MB (aproximadamente {{duration}} minutos de gravação)",
@@ -471,14 +466,12 @@
"live": "AOVIVO",
"loggedIn": "Conectado como {{userName}}",
"off": "Gravação parada",
"offBy": "",
"on": "Gravando",
"onBy": "",
"pending": "Preparando para gravar a reunião...",
"rec": "REC",
"serviceDescription": "Sua gravação será salva pelo serviço de gravação",
"serviceName": "Serviço de gravação",
"signIn": "Entrar",
"signIn": "entrar",
"signOut": "Sair",
"unavailable": "Oops! O {{serviceName}} está indisponível. Estamos trabalhando para resolver o problema. Por favor, tente mais tarde.",
"unavailableTitle": "Gravação indisponível"
@@ -525,10 +518,10 @@
"version": "Versão"
},
"share": {
"dialInfoText": "\n\n=====\n\nDeseja apenas discar no seu telefone?\n\n{{defaultDialInNumber}}Clique neste link para ver os números de telefone para esta reunião\n{{dialInfoPageUrl}}",
"dialInfoText": "",
"mainText": "Clique no seguinte link para entrar na reunião:{{roomUrl}}\n"
},
"speaker": "Alto-falantes",
"speaker": "Apresentador",
"speakerStats": {
"hours": "{{count}}h",
"minutes": "{{count}}m",
@@ -550,7 +543,7 @@
"accessibilityLabel": {
"audioOnly": "Alternar para apenas áudio",
"audioRoute": "Selecionar o dispositivo de som",
"callQuality": "Gerenciar qualidade do vídeo",
"callQuality": "Gerenciar qualidade da chamada",
"cc": "Alternar legendas",
"chat": "Alternar para janela de chat",
"document": "Alternar para documento compartilhado",
@@ -574,19 +567,19 @@
"shareRoom": "Convidar alguém",
"shareYourScreen": "Alternar compartilhamento de tela",
"shortcuts": "Alternar atalhos",
"show": "Mostrar no palco",
"show": "",
"speakerStats": "Alternar estatísticas do apresentador",
"tileView": "Alternar visualização em blocos",
"toggleCamera": "Alternar câmera",
"videomute": "Alternar mudo do vídeo",
"videoblur": "Alternar desfoque de vídeo"
"videoblur": ""
},
"addPeople": "Adicionar pessoas à sua chamada",
"audioOnlyOff": "",
"audioOnlyOn": "",
"audioOnlyOff": "Desativar modo somente áudio",
"audioOnlyOn": "Desativar modo somente áudio",
"audioRoute": "Selecionar o dispositivo de som",
"authenticate": "Autenticar",
"callQuality": "Gerenciar qualidade do vídeo",
"callQuality": "Gerenciar qualidade da chamada",
"chat": "Abrir ou fechar o bate-papo",
"closeChat": "Fechar chat",
"documentClose": "Fechar documento compartilhado",
@@ -622,19 +615,19 @@
"tileViewToggle": "Alternar visualização em blocos",
"toggleCamera": "Alternar câmera",
"videomute": "Iniciar ou parar a câmera",
"startvideoblur": "Desfocar meu plano de fundo",
"stopvideoblur": "Desativar desfoque de fundo"
"startvideoblur": "",
"stopvideoblur": ""
},
"transcribing": {
"ccButtonTooltip": "Iniciar/parar legendas",
"error": "Transcrição falhou. Tente novamente.",
"expandedLabel": "Transcrição ativada",
"expandedLabel": "Transcrição ligada",
"failedToStart": "Transcrição falhou ao iniciar",
"labelToolTip": "A reunião esta sendo transcrita",
"off": "Transcrição parada",
"pending": "Preparando a transcrição da reunião...",
"start": "Exibir legendas",
"stop": "Não exibir legendas",
"start": "Iniciar / Parar de mostrar as legendas",
"stop": "Iniciar / Parar de mostrar as legendas",
"tr": "TR"
},
"userMedia": {
@@ -661,23 +654,20 @@
},
"videoStatus": {
"audioOnly": "AUD",
"audioOnlyExpanded": "",
"callQuality": "Qualidade de vídeo",
"audioOnlyExpanded": "Você está no modo somente áudio. Esse modo economiza internet mas não permite ver o vídeo dos outros.",
"callQuality": "",
"hd": "HD",
"hdTooltip": "Ver vídeo em alta definição",
"highDefinition": "Alta definição (HD)",
"labelTooiltipNoVideo": "Sem vídeo",
"labelTooltipAudioOnly": "",
"labelTooltipAudioOnly": "Modo somente de áudio habilitado",
"ld": "LD",
"ldTooltip": "Ver vídeo em baixa definição",
"lowDefinition": "Baixa definição (LD)",
"onlyAudioAvailable": "Somente áudio disponível",
"onlyAudioSupported": "Suportamos somente áudio neste navegador.",
"p2pEnabled": "Ponto-a-ponto habilitada",
"p2pVideoQualityDescription": "No modo ponto a ponto, a qualidade do vídeo recebido só pode ser alternada entre alta e apenas áudio. Outras configurações não serão respeitadas até que o ponto a ponto seja encerrado.",
"p2pVideoQualityDescription": "",
"recHighDefinitionOnly": "Preferência para alta definição",
"sd": "SD",
"sdTooltip": "Ver vídeo em definição padrão",
"standardDefinition": "Definição padrão"
},
"videothumbnail": {
@@ -688,8 +678,8 @@
"mute": "Participante está mudo",
"muted": "Mudo",
"remoteControl": "Controle remoto",
"show": "Mostrar no palco",
"videomute": "O participante parou a câmera"
"show": "",
"videomute": ""
},
"welcomepage": {
"accessibilityLabel": {
@@ -705,7 +695,6 @@
"connectCalendarButton": "Conectar seu calendário",
"connectCalendarText": "Conecte seu calendário para ver todas as reuniões em {{app}}. Além disso, adicione reuniões de {{provider}} ao seu calendário e inicie-as com apenas um clique.",
"enterRoomTitle": "Iniciar uma nova reunião",
"onlyAsciiAllowed": "",
"go": "IR",
"join": "Entrar",
"info": "Informações",
@@ -713,7 +702,7 @@
"recentList": "Recente",
"recentListDelete": "Remover",
"recentListEmpty": "Sua lista recente está vazia. As reuniões que você realizar serão exibidas aqui.",
"reducedUIText": "Bem-vindo ao {{app}}!",
"reducedUIText": "",
"roomname": "Digite o nome da sala",
"roomnameHint": "Digite o nome ou a URL da sala que você deseja entrar. Você pode digitar um nome, e apenas deixe para as pessoas que você quer se reunir digitem o mesmo nome.",
"sendFeedback": "Enviar comentários",

View File

@@ -46,16 +46,13 @@
"today": "Today"
},
"chat": {
"error": "Error: your message was not sent. Reason: {{error}}",
"error": "Error: your message \"{{originalText}}\" was not sent. Reason: {{error}}",
"messagebox": "Type a message",
"messageTo": "Private message to {{recipient}}",
"nickname": {
"popover": "Choose a nickname",
"title": "Enter a nickname to use chat"
},
"privateNotice": "Private message to {{recipient}}",
"title": "Chat",
"you": "you"
"title": "Chat"
},
"connectingOverlay": {
"joiningRoom": "Connecting you to your meeting..."
@@ -238,10 +235,6 @@
"screenSharingFirefoxPermissionDeniedError": "Something went wrong while we were trying to share your screen. Please make sure that you have given us permission to do so. ",
"screenSharingFirefoxPermissionDeniedTitle": "Oops! We werent able to start screen sharing!",
"screenSharingPermissionDeniedError": "Oops! Something went wrong with your screen sharing extension permissions. Please reload and try again.",
"sendPrivateMessage": "You recently received a private message. Did you intend to reply to that privately, or you want to send your message to the group?",
"sendPrivateMessageCancel": "Send to the group",
"sendPrivateMessageOk": "Send privately",
"sendPrivateMessageTitle": "Send privately?",
"serviceUnavailable": "Service unavailable",
"sessTerminated": "Call terminated",
"Share": "Share",
@@ -275,9 +268,6 @@
"dialOut": {
"statusMessage": "is now {{status}}"
},
"documentSharing" : {
"title": "Shared Document"
},
"feedback": {
"average": "Average",
"bad": "Bad",
@@ -372,9 +362,7 @@
"getStreamKeyManually": "We werent able to fetch any live streams. Try getting your live stream key from YouTube.",
"invalidStreamKey": "Live stream key may be incorrect.",
"off": "Live Streaming stopped",
"offBy": "{{name}} stopped the live streaming",
"on": "Live Streaming",
"onBy": "{{name}} started the live streaming",
"pending": "Starting Live Stream...",
"serviceName": "Live Streaming service",
"signedInAs": "You are currently signed in as:",
@@ -487,9 +475,7 @@
"live": "LIVE",
"loggedIn": "Logged in as {{userName}}",
"off": "Recording stopped",
"offBy": "{{name}} stopped the recording",
"on": "Recording",
"onBy": "{{name}} started the recording",
"pending": "Preparing to record the meeting...",
"rec": "REC",
"serviceDescription": "Your recording will be saved by the recording service",
@@ -573,7 +559,6 @@
"feedback": "Leave feedback",
"fullScreen": "Toggle full screen",
"hangup": "Leave the call",
"help": "Help",
"invite": "Invite people",
"kick": "Kick participant",
"localRecording": "Toggle local recording controls",
@@ -582,7 +567,6 @@
"moreActionsMenu": "More actions menu",
"mute": "Toggle mute audio",
"pip": "Toggle Picture-in-Picture mode",
"privateMessage": "Send private message",
"profile": "Edit your profile",
"raiseHand": "Toggle raise hand",
"recording": "Toggle recording",
@@ -615,7 +599,6 @@
"exitTileView": "Exit tile view",
"feedback": "Leave feedback",
"hangup": "Leave",
"help": "Help",
"invite": "Invite people",
"login": "Login",
"logout": "Logout",
@@ -624,7 +607,6 @@
"mute": "Mute / Unmute",
"openChat": "Open chat",
"pip": "Enter Picture-in-Picture mode",
"privateMessage": "Send private message",
"profile": "Edit your profile",
"raiseHand": "Raise / Lower your hand",
"raiseYourHand": "Raise your hand",

View File

@@ -15,7 +15,7 @@ import Filmstrip from './videolayout/Filmstrip';
import { getLocalParticipant } from '../../react/features/base/participants';
import { toggleChat } from '../../react/features/chat';
import { setDocumentUrl } from '../../react/features/etherpad';
import { setEtherpadHasInitialzied } from '../../react/features/etherpad';
import { setFilmstripVisible } from '../../react/features/filmstrip';
import { setNotificationsEnabled } from '../../react/features/notifications';
import {
@@ -240,12 +240,10 @@ UI.initEtherpad = name => {
return;
}
logger.log('Etherpad is enabled');
etherpadManager
= new EtherpadManager(config.etherpad_base, name, eventEmitter);
etherpadManager = new EtherpadManager(eventEmitter);
const url = new URL(name, config.etherpad_base);
APP.store.dispatch(setDocumentUrl(url.toString()));
APP.store.dispatch(setEtherpadHasInitialzied());
};
/**

View File

@@ -1,12 +1,22 @@
/* global $, APP, interfaceConfig */
import { getSharedDocumentUrl, setDocumentEditingState } from '../../../react/features/etherpad';
import { setDocumentEditingState } from '../../../react/features/etherpad';
import { getToolboxHeight } from '../../../react/features/toolbox';
import VideoLayout from '../videolayout/VideoLayout';
import LargeContainer from '../videolayout/LargeContainer';
import Filmstrip from '../videolayout/Filmstrip';
/**
* Etherpad options.
*/
const options = $.param({
showControls: true,
showChat: false,
showLineNumbers: true,
useMonospaceFont: false
});
/**
*
*/
@@ -60,13 +70,13 @@ class Etherpad extends LargeContainer {
/**
* Creates new Etherpad object
*/
constructor(url) {
constructor(domain, name) {
super();
const iframe = document.createElement('iframe');
iframe.id = 'etherpadIFrame';
iframe.src = url;
iframe.src = `${domain + name}?${options}`;
iframe.frameBorder = 0;
iframe.scrolling = 'no';
iframe.width = DEFAULT_WIDTH;
@@ -189,7 +199,13 @@ export default class EtherpadManager {
/**
*
*/
constructor(eventEmitter) {
constructor(domain, name, eventEmitter) {
if (!domain || !name) {
throw new Error('missing domain or name');
}
this.domain = domain;
this.name = name;
this.eventEmitter = eventEmitter;
this.etherpad = null;
}
@@ -212,7 +228,7 @@ export default class EtherpadManager {
* Create new Etherpad frame.
*/
openEtherpad() {
this.etherpad = new Etherpad(getSharedDocumentUrl(APP.store.getState));
this.etherpad = new Etherpad(this.domain, this.name);
VideoLayout.addLargeVideoContainer(
ETHERPAD_CONTAINER_TYPE,
this.etherpad

View File

@@ -273,7 +273,7 @@ LocalVideo.prototype._updateVideoElement = function() {
// case video does not autoplay.
const video = this.container.querySelector('video');
video && !config.testing?.noAutoPlayVideo && video.play();
video && video.play();
};
export default LocalVideo;

View File

@@ -7,7 +7,6 @@ import { Provider } from 'react-redux';
import { I18nextProvider } from 'react-i18next';
import { AtlasKitThemeProvider } from '@atlaskit/theme';
import { createThumbnailOffsetParentIsNullEvent, sendAnalytics } from '../../../react/features/analytics';
import { i18next } from '../../../react/features/base/i18n';
import {
JitsiParticipantConnectionStatus
@@ -487,8 +486,6 @@ RemoteVideo.prototype.hasVideoStarted = function() {
RemoteVideo.prototype.addRemoteStreamElement = function(stream) {
if (!this.container) {
logger.debug('Not attaching remote stream due to no container');
return;
}
@@ -501,8 +498,6 @@ RemoteVideo.prototype.addRemoteStreamElement = function(stream) {
}
if (!stream.getOriginalStream()) {
logger.debug('Remote video stream has no original stream');
return;
}
@@ -513,31 +508,11 @@ RemoteVideo.prototype.addRemoteStreamElement = function(stream) {
$(streamElement).hide();
this.waitForPlayback(streamElement, stream);
stream.attach(streamElement);
// TODO: Remove once we verify that this.container.offsetParent === null was the reason for not attached video
// streams to the thumbnail.
if (isVideo && this.container.offsetParent === null) {
sendAnalytics(createThumbnailOffsetParentIsNullEvent(this.id));
const parentNodesDisplayProps = [
'#filmstripRemoteVideosContainer',
'#filmstripRemoteVideos',
'#remoteVideos',
'.filmstrip',
'#videospace',
'#videoconference_page',
'#react'
].map(selector => `${selector} - ${$(selector).css('display')}`);
const videoConferencePageParent = $('#videoconference_page').parent();
const reactDiv = document.getElementById('react');
parentNodesDisplayProps.push(
`${videoConferencePageParent.attr('class')} - ${videoConferencePageParent.css('display')}`);
parentNodesDisplayProps.push(`this.container - ${this.$container.css('display')}`);
logger.debug(`this.container.offsetParent is null [user: ${this.id}, ${
parentNodesDisplayProps.join(', ')}, #react.offsetParent - ${
reactDiv && reactDiv.offsetParent !== null ? 'not null' : 'null'}]`);
// If the container is currently visible
// we attach the stream to the element.
if (!isVideo || (this.container.offsetParent !== null && isVideo)) {
this.waitForPlayback(streamElement, stream);
stream.attach(streamElement);
}
if (!isVideo) {

View File

@@ -199,7 +199,7 @@ SmallVideo.createStreamElement = function(stream) {
element.muted = true;
}
element.autoplay = !config.testing?.noAutoPlayVideo;
element.autoplay = true;
element.id = SmallVideo.getStreamElementID(stream);
return element;
@@ -511,7 +511,7 @@ SmallVideo.prototype.isCurrentlyOnLargeVideo = function() {
* or <tt>false</tt> otherwise.
*/
SmallVideo.prototype.isVideoPlayable = function() {
return this.videoStream && !this.isVideoMuted && !APP.conference.isAudioOnly();
return this.videoStream && !this.isVideoMuted && !this.videoStream.isMuted();
};
/**
@@ -520,33 +520,40 @@ SmallVideo.prototype.isVideoPlayable = function() {
* @return {number} one of <tt>DISPLAY_VIDEO</tt>,<tt>DISPLAY_AVATAR</tt>
* or <tt>DISPLAY_BLACKNESS_WITH_NAME</tt>.
*/
SmallVideo.prototype.selectDisplayMode = function(input) {
SmallVideo.prototype.selectDisplayMode = function() {
const isAudioOnly = APP.conference.isAudioOnly();
const tileViewEnabled = shouldDisplayTileView(APP.store.getState());
const isVideoPlayable = this.isVideoPlayable();
const hasVideo = Boolean(this.selectVideoElement().length);
// Display name is always and only displayed when user is on the stage
if (input.isCurrentlyOnLargeVideo && !input.tileViewEnabled) {
return input.isVideoPlayable && !input.isAudioOnly ? DISPLAY_BLACKNESS_WITH_NAME : DISPLAY_AVATAR_WITH_NAME;
} else if (input.isVideoPlayable && input.hasVideo && !input.isAudioOnly) {
if (this.isCurrentlyOnLargeVideo() && !tileViewEnabled) {
return isVideoPlayable && !isAudioOnly ? DISPLAY_BLACKNESS_WITH_NAME : DISPLAY_AVATAR_WITH_NAME;
} else if (isVideoPlayable && hasVideo && !isAudioOnly) {
// check hovering and change state to video with name
return input.isHovered ? DISPLAY_VIDEO_WITH_NAME : DISPLAY_VIDEO;
return this._isHovered() ? DISPLAY_VIDEO_WITH_NAME : DISPLAY_VIDEO;
}
// check hovering and change state to avatar with name
return input.isHovered ? DISPLAY_AVATAR_WITH_NAME : DISPLAY_AVATAR;
return this._isHovered() ? DISPLAY_AVATAR_WITH_NAME : DISPLAY_AVATAR;
};
/**
* Computes information that determine the display mode.
* Prints information about the current display mode.
*
* @returns {Object}
* @param {string} mode - The current mode.
* @returns {void}
*/
SmallVideo.prototype.computeDisplayModeInput = function() {
return {
isCurrentlyOnLargeVideo: this.isCurrentlyOnLargeVideo(),
isHovered: this._isHovered(),
isAudioOnly: APP.conference.isAudioOnly(),
tileViewEnabled: shouldDisplayTileView(APP.store.getState()),
isVideoPlayable: this.isVideoPlayable(),
hasVideo: Boolean(this.selectVideoElement().length),
SmallVideo.prototype._printDisplayModeInfo = function(mode) {
const isAudioOnly = APP.conference.isAudioOnly();
const tileViewEnabled = shouldDisplayTileView(APP.store.getState());
const isVideoPlayable = this.isVideoPlayable();
const hasVideo = Boolean(this.selectVideoElement().length);
const displayModeInfo = {
isAudioOnly,
tileViewEnabled,
isVideoPlayable,
hasVideo,
connectionStatus: APP.conference.getParticipantConnectionStatus(this.id),
mutedWhileDisconnected: this.mutedWhileDisconnected,
wasVideoPlayed: this.wasVideoPlayed,
@@ -554,6 +561,8 @@ SmallVideo.prototype.computeDisplayModeInput = function() {
isVideoMuted: this.isVideoMuted,
videoStreamMuted: this.videoStream ? this.videoStream.isMuted() : 'no stream'
};
logger.debug(`Displaying ${mode} for ${this.id}, reason: [${JSON.stringify(displayModeInfo)}]`);
};
/**
@@ -587,10 +596,8 @@ SmallVideo.prototype.updateView = function() {
const oldDisplayMode = this.displayMode;
let displayModeString = '';
const displayModeInput = this.computeDisplayModeInput();
// Determine whether video, avatar or blackness should be displayed
this.displayMode = this.selectDisplayMode(displayModeInput);
this.displayMode = this.selectDisplayMode();
switch (this.displayMode) {
case DISPLAY_AVATAR_WITH_NAME:
@@ -617,7 +624,7 @@ SmallVideo.prototype.updateView = function() {
}
if (this.displayMode !== oldDisplayMode) {
logger.debug(`Displaying ${displayModeString} for ${this.id}, data: [${JSON.stringify(displayModeInput)}]`);
this._printDisplayModeInfo(displayModeString);
}
};

View File

@@ -200,11 +200,7 @@ const VideoLayout = {
const id = stream.getParticipantId();
const remoteVideo = remoteVideos[id];
logger.debug(`Received a new ${stream.getType()} stream for ${id}`);
if (!remoteVideo) {
logger.debug('No remote video element to add stream');
return;
}

1159
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -35,11 +35,10 @@
"@atlaskit/tooltip": "12.1.13",
"@microsoft/microsoft-graph-client": "1.1.0",
"@react-native-community/async-storage": "1.3.4",
"@react-native-community/google-signin": "3.0.1",
"@react-native-community/netinfo": "4.1.5",
"@svgr/webpack": "4.3.2",
"@tensorflow-models/body-pix": "1.1.2",
"@tensorflow/tfjs": "1.2.9",
"@tensorflow-models/body-pix": "^1.0.1",
"@tensorflow/tfjs": "^1.1.2",
"@webcomponents/url": "0.7.1",
"amplitude-js": "4.5.2",
"bc-css-flags": "3.0.0",
@@ -57,21 +56,22 @@
"js-utils": "github:jitsi/js-utils#192b1c996e8c05530eb1f19e82a31069c3021e31",
"jsrsasign": "8.0.12",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#f9808adb8eb523bae3318f9f8ef49b544651485f",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#f43c0c4bbfeb09ed816356eb5088bd61d40b91d5",
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"lodash": "4.17.13",
"moment": "2.19.4",
"moment-duration-format": "2.2.2",
"postis": "2.2.0",
"react": "16.9",
"react-dom": "16.9",
"react": "16.8.6",
"react-dom": "16.8.6",
"react-emoji-render": "1.0.0",
"react-i18next": "10.11.4",
"react-linkify": "1.0.0-alpha",
"react-native": "0.61.1",
"react-native": "0.60.5",
"react-native-background-timer": "2.1.1",
"react-native-calendar-events": "github:jitsi/react-native-calendar-events#902e6e92d6bae450a6052f76ba4d02f977ffd8f2",
"react-native-callstats": "3.61.0",
"react-native-google-signin": "2.0.0",
"react-native-immersive": "2.0.0",
"react-native-keep-awake": "4.0.0",
"react-native-linear-gradient": "2.5.6",
@@ -80,14 +80,13 @@
"react-native-svg-transformer": "0.13.0",
"react-native-swipeout": "2.3.6",
"react-native-watch-connectivity": "0.2.0",
"react-native-webrtc": "github:jitsi/react-native-webrtc#047b019a7ce1ec93ab4a2f6796e997d7a02e8e5d",
"react-native-webview": "7.4.1",
"react-native-webrtc": "github:react-native-webrtc/react-native-webrtc#1ce96e1c1fcfdfda2ab1907763c485c580e04963",
"react-native-webview": "5.8.1",
"react-redux": "7.1.0",
"react-textarea-autosize": "7.1.0",
"react-transition-group": "2.4.0",
"redux": "4.0.4",
"redux-thunk": "2.2.0",
"rnnoise-wasm": "github:jitsi/rnnoise-wasm.git#db96d11f175a22ef56c7db1ba9550835b716e615",
"styled-components": "3.4.9",
"util": "0.12.1",
"uuid": "3.1.0",
@@ -118,7 +117,7 @@
"eslint-plugin-react": "7.11.1",
"eslint-plugin-react-native": "3.3.0",
"expose-loader": "0.7.5",
"flow-bin": "0.104.0",
"flow-bin": "0.98.0",
"imports-loader": "0.7.1",
"jetifier": "1.6.4",
"metro-react-native-babel-preset": "0.56.0",

View File

@@ -692,21 +692,6 @@ export function createSyncTrackStateEvent(mediaType, muted) {
};
}
/**
* Creates an event that indicates the thumbnail offset parent is null.
*
* @param {string} id - The id of the user related to the thumbnail.
* @returns {Object} The event in a format suitable for sending via sendAnalytics.
*/
export function createThumbnailOffsetParentIsNullEvent(id) {
return {
action: 'OffsetParentIsNull',
attributes: {
id
}
};
}
/**
* Creates an event associated with a toolbar button being clicked/pressed. By
* convention, where appropriate an attribute named 'enable' should be used to

View File

@@ -15,7 +15,6 @@ import { connect, disconnect, setLocationURL } from '../base/connection';
import { loadConfig } from '../base/lib-jitsi-meet';
import { createDesiredLocalTracks } from '../base/tracks';
import {
getBackendSafeRoomName,
getLocationContextRoot,
parseURIString,
toURLString
@@ -86,7 +85,7 @@ export function appNavigate(uri: ?string) {
let url = `${baseURL}config.js`;
// XXX In order to support multiple shards, tell the room to the deployment.
room && (url += `?room=${getBackendSafeRoomName(room)}`);
room && (url += `?room=${room.toLowerCase()}`);
let config;

View File

@@ -42,6 +42,6 @@ export default class AbstractStatelessAvatar<P: Props> extends PureComponent<P>
* @returns {boolean}
*/
_isIcon(iconProp: ?string | ?Object): boolean {
return Boolean(iconProp) && (typeof iconProp === 'object' || typeof iconProp === 'function');
return Boolean(iconProp) && typeof iconProp === 'object';
}
}

View File

@@ -23,10 +23,7 @@ import {
participantUpdated
} from '../participants';
import { getLocalTracks, trackAdded, trackRemoved } from '../tracks';
import {
getBackendSafeRoomName,
getJitsiMeetGlobalNS
} from '../util';
import { getJitsiMeetGlobalNS } from '../util';
import {
AUTH_STATUS_CHANGED,
@@ -77,11 +74,6 @@ declare var APP: Object;
* @returns {void}
*/
function _addConferenceListeners(conference, dispatch) {
// A simple logger for conference errors received through
// the listener. These errors are not handled now, but logged.
conference.on(JitsiConferenceEvents.CONFERENCE_ERROR,
error => logger.error('Conference error.', error));
// Dispatches into features/base/conference follow:
conference.on(
@@ -396,7 +388,8 @@ export function createConference() {
const conference
= connection.initJitsiConference(
getBackendSafeRoomName(room), {
// XXX Lib-jitsi-meet does not accept uppercase letters.
room.toLowerCase(), {
...state['features/base/config'],
applicationName: getName(),
getWiFiStatsMethod: getJitsiMeetGlobalNS().getWiFiStats,

View File

@@ -1,137 +0,0 @@
/**
* The config keys to whitelist, the keys that can be overridden.
* Currently we can only whitelist the first part of the properties, like
* 'p2p.useStunTurn' and 'p2p.enabled' we whitelist all p2p options.
* The whitelist is used only for config.js.
*
* @type Array
*/
export default [
'_desktopSharingSourceDevice',
'_peerConnStatusOutOfLastNTimeout',
'_peerConnStatusRtcMuteTimeout',
'abTesting',
'analytics.disabled',
'autoRecord',
'autoRecordToken',
'avgRtpStatsN',
'callFlowsEnabled',
'callStatsConfIDNamespace',
'callStatsID',
'callStatsSecret',
/**
* The display name of the CallKit call representing the conference/meeting
* associated with this config.js including while the call is ongoing in the
* UI presented by CallKit and in the system-wide call history. The property
* is meant for use cases in which the room name is not desirable as a
* display name for CallKit purposes and the desired display name is not
* provided in the form of a JWT callee. As the value is associated with a
* conference/meeting, the value makes sense not as a deployment-wide
* configuration, only as a runtime configuration override/overwrite
* provided by, for example, Jitsi Meet SDK for iOS.
*
* @type string
*/
'callDisplayName',
/**
* The handle
* ({@link https://developer.apple.com/documentation/callkit/cxhandle}) of
* the CallKit call representing the conference/meeting associated with this
* config.js. The property is meant for use cases in which the room URL is
* not desirable as the handle for CallKit purposes. As the value is
* associated with a conference/meeting, the value makes sense not as a
* deployment-wide configuration, only as a runtime configuration
* override/overwrite provided by, for example, Jitsi Meet SDK for iOS.
*
* @type string
*/
'callHandle',
/**
* The UUID of the CallKit call representing the conference/meeting
* associated with this config.js. The property is meant for use cases in
* which Jitsi Meet is to work with a CallKit call created outside of Jitsi
* Meet and to be adopted by Jitsi Meet such as, for example, an incoming
* and/or outgoing CallKit call created by Jitsi Meet SDK for iOS
* clients/consumers prior to giving control to Jitsi Meet. As the value is
* associated with a conference/meeting, the value makes sense not as a
* deployment-wide configuration, only as a runtime configuration
* override/overwrite provided by, for example, Jitsi Meet SDK for iOS.
*
* @type string
*/
'callUUID',
'channelLastN',
'constraints',
'debug',
'debugAudioLevels',
'defaultLanguage',
'desktopSharingChromeDisabled',
'desktopSharingChromeExtId',
'desktopSharingChromeMinExtVersion',
'desktopSharingChromeSources',
'desktopSharingFrameRate',
'desktopSharingFirefoxDisabled',
'desktopSharingSources',
'disable1On1Mode',
'disableAEC',
'disableAGC',
'disableAP',
'disableAudioLevels',
'disableDeepLinking',
'disableH264',
'disableHPF',
'disableNS',
'disableRemoteControl',
'disableRtx',
'disableSuspendVideo',
'displayJids',
'e2eping',
'enableDisplayNameInStats',
'enableLayerSuspension',
'enableLipSync',
'disableLocalVideoFlip',
'enableRemb',
'enableStatsID',
'enableTalkWhileMuted',
'enableTcc',
'etherpad_base',
'failICE',
'fileRecordingsEnabled',
'firefox_fake_device',
'forceJVB121Ratio',
'gatherStats',
'googleApiApplicationClientID',
'hiddenDomain',
'hosts',
'iAmRecorder',
'iAmSipGateway',
'iceTransportPolicy',
'ignoreStartMuted',
'liveStreamingEnabled',
'localRecording',
'minParticipants',
'nick',
'openBridgeChannel',
'p2p',
'preferH264',
'requireDisplayName',
'resolution',
'startAudioMuted',
'startAudioOnly',
'startBitrate',
'startSilent',
'startScreenSharing',
'startVideoMuted',
'startWithVideoMuted',
'subject',
'testing',
'useIPv6',
'useNicks',
'useStunTurn',
'webrtcIceTcpDisable',
'webrtcIceUdpDisable'
];

View File

@@ -2,12 +2,152 @@
import _ from 'lodash';
import CONFIG_WHITELIST from './configWhitelist';
import { _CONFIG_STORE_PREFIX } from './constants';
import INTERFACE_CONFIG_WHITELIST from './interfaceConfigWhitelist';
import parseURLParams from './parseURLParams';
import logger from './logger';
declare var $: Object;
/**
* The config keys to whitelist, the keys that can be overridden.
* Currently we can only whitelist the first part of the properties, like
* 'p2p.useStunTurn' and 'p2p.enabled' we whitelist all p2p options.
* The whitelist is used only for config.js.
*
* @private
* @type Array
*/
const WHITELISTED_KEYS = [
'_desktopSharingSourceDevice',
'_peerConnStatusOutOfLastNTimeout',
'_peerConnStatusRtcMuteTimeout',
'abTesting',
'analytics.disabled',
'autoRecord',
'autoRecordToken',
'avgRtpStatsN',
'callFlowsEnabled',
'callStatsConfIDNamespace',
'callStatsID',
'callStatsSecret',
/**
* The display name of the CallKit call representing the conference/meeting
* associated with this config.js including while the call is ongoing in the
* UI presented by CallKit and in the system-wide call history. The property
* is meant for use cases in which the room name is not desirable as a
* display name for CallKit purposes and the desired display name is not
* provided in the form of a JWT callee. As the value is associated with a
* conference/meeting, the value makes sense not as a deployment-wide
* configuration, only as a runtime configuration override/overwrite
* provided by, for example, Jitsi Meet SDK for iOS.
*
* @type string
*/
'callDisplayName',
/**
* The handle
* ({@link https://developer.apple.com/documentation/callkit/cxhandle}) of
* the CallKit call representing the conference/meeting associated with this
* config.js. The property is meant for use cases in which the room URL is
* not desirable as the handle for CallKit purposes. As the value is
* associated with a conference/meeting, the value makes sense not as a
* deployment-wide configuration, only as a runtime configuration
* override/overwrite provided by, for example, Jitsi Meet SDK for iOS.
*
* @type string
*/
'callHandle',
/**
* The UUID of the CallKit call representing the conference/meeting
* associated with this config.js. The property is meant for use cases in
* which Jitsi Meet is to work with a CallKit call created outside of Jitsi
* Meet and to be adopted by Jitsi Meet such as, for example, an incoming
* and/or outgoing CallKit call created by Jitsi Meet SDK for iOS
* clients/consumers prior to giving control to Jitsi Meet. As the value is
* associated with a conference/meeting, the value makes sense not as a
* deployment-wide configuration, only as a runtime configuration
* override/overwrite provided by, for example, Jitsi Meet SDK for iOS.
*
* @type string
*/
'callUUID',
'channelLastN',
'constraints',
'debug',
'debugAudioLevels',
'defaultLanguage',
'desktopSharingChromeDisabled',
'desktopSharingChromeExtId',
'desktopSharingChromeMinExtVersion',
'desktopSharingChromeSources',
'desktopSharingFrameRate',
'desktopSharingFirefoxDisabled',
'desktopSharingSources',
'disable1On1Mode',
'disableAEC',
'disableAGC',
'disableAP',
'disableAudioLevels',
'disableDeepLinking',
'disableH264',
'disableHPF',
'disableNS',
'disableRemoteControl',
'disableRtx',
'disableSuspendVideo',
'displayJids',
'e2eping',
'enableDisplayNameInStats',
'enableLayerSuspension',
'enableLipSync',
'disableLocalVideoFlip',
'enableRemb',
'enableStatsID',
'enableTalkWhileMuted',
'enableTcc',
'etherpad_base',
'failICE',
'fileRecordingsEnabled',
'firefox_fake_device',
'forceJVB121Ratio',
'gatherStats',
'googleApiApplicationClientID',
'hiddenDomain',
'hosts',
'iAmRecorder',
'iAmSipGateway',
'iceTransportPolicy',
'ignoreStartMuted',
'liveStreamingEnabled',
'localRecording',
'minParticipants',
'nick',
'openBridgeChannel',
'p2p',
'preferH264',
'requireDisplayName',
'resolution',
'startAudioMuted',
'startAudioOnly',
'startBitrate',
'startSilent',
'startScreenSharing',
'startVideoMuted',
'startWithAudioMuted',
'startWithVideoMuted',
'subject',
'testing',
'useIPv6',
'useNicks',
'useStunTurn',
'webrtcIceTcpDisable',
'webrtcIceUdpDisable'
];
// XXX The functions getRoomName and parseURLParams are split out of
// functions.js because they are bundled in both app.bundle and
// do_external_connect, webpack 1 does not support tree shaking, and we don't
@@ -38,6 +178,69 @@ export function createFakeConfig(baseURL: string) {
};
}
/**
* Promise wrapper on obtain config method. When HttpConfigFetch will be moved
* to React app it's better to use load config instead.
*
* @param {string} location - URL of the domain from which the config is to be
* obtained.
* @param {string} room - Room name.
* @private
* @returns {Promise<void>}
*/
export function obtainConfig(location: string, room: string): Promise<void> {
return new Promise((resolve, reject) =>
_obtainConfig(location, room, (success, error) => {
success ? resolve() : reject(error);
})
);
}
/**
* Sends HTTP POST request to specified {@code endpoint}. In request the name
* of the room is included in JSON format:
* {
* "rooomName": "someroom12345"
* }.
*
* @param {string} endpoint - The name of HTTP endpoint to which to send
* the HTTP POST request.
* @param {string} roomName - The name of the conference room for which config
* is requested.
* @param {Function} complete - The callback to invoke upon success or failure.
* @returns {void}
*/
function _obtainConfig(endpoint: string, roomName: string, complete: Function) {
logger.info(`Send config request to ${endpoint} for room: ${roomName}`);
$.ajax(
endpoint,
{
contentType: 'application/json',
data: JSON.stringify({ roomName }),
dataType: 'json',
method: 'POST',
error(jqXHR, textStatus, errorThrown) {
logger.error('Get config error: ', jqXHR, errorThrown);
complete(false, `Get config response status: ${textStatus}`);
},
success(data) {
const { config, interfaceConfig, loggingConfig } = window;
try {
overrideConfigJSON(
config, interfaceConfig, loggingConfig,
data);
complete(true);
} catch (e) {
logger.error('Parse config error: ', e);
complete(false, e);
}
}
}
);
}
/* eslint-disable max-params, no-shadow */
/**
@@ -103,8 +306,8 @@ export function overrideConfigJSON(
/* eslint-enable max-params, no-shadow */
/**
* Apply whitelist filtering for configs with whitelists, skips this for others
* configs (loggingConfig).
* Whitelist only config.js, skips this for others configs
* (interfaceConfig, loggingConfig).
* Only extracts overridden values for keys we allow to be overridden.
*
* @param {string} configName - The config name, one of config,
@@ -115,13 +318,11 @@ export function overrideConfigJSON(
* that are whitelisted.
*/
function _getWhitelistedJSON(configName, configJSON) {
if (configName === 'interfaceConfig') {
return _.pick(configJSON, INTERFACE_CONFIG_WHITELIST);
} else if (configName === 'config') {
return _.pick(configJSON, CONFIG_WHITELIST);
if (configName !== 'config') {
return configJSON;
}
return configJSON;
return _.pick(configJSON, WHITELISTED_KEYS);
}
/**

View File

@@ -11,8 +11,8 @@ export * from './functions.any';
* @returns {void}
*/
export function _cleanupConfig(config: Object) {
config.analytics.scriptURLs = [];
if (NativeModules.AppInfo.LIBRE_BUILD) {
config.analytics.scriptURLs = [];
delete config.analytics.amplitudeAPPKey;
delete config.analytics.googleAnalyticsTrackingId;
delete config.callStatsID;

View File

@@ -1,6 +1,6 @@
// @flow
/* @flow */
import { getBackendSafeRoomName } from '../util';
declare var config: Object;
/**
* Builds and returns the room name.
@@ -8,10 +8,22 @@ import { getBackendSafeRoomName } from '../util';
* @returns {string}
*/
export default function getRoomName(): ?string {
const { getroomnode } = config;
const path = window.location.pathname;
let roomName;
// The last non-directory component of the path (name) is the room.
const roomName = path.substring(path.lastIndexOf('/') + 1) || undefined;
// Determine the room node from the URL.
if (getroomnode && typeof getroomnode === 'function') {
roomName = getroomnode.call(config, path);
} else {
// Fall back to the default strategy of making assumptions about how the
// URL maps to the room (name). It currently assumes a deployment in
// which the last non-directory component of the path (name) is the
// room.
roomName
= path.substring(path.lastIndexOf('/') + 1).toLowerCase()
|| undefined;
}
return getBackendSafeRoomName(roomName);
return roomName;
}

View File

@@ -1,70 +0,0 @@
/**
* The interface config keys to whitelist, the keys that can be overridden.
*
* @private
* @type Array
*/
export default [
'ANDROID_APP_PACKAGE',
'APP_NAME',
'APP_SCHEME',
'AUDIO_LEVEL_PRIMARY_COLOR',
'AUDIO_LEVEL_SECONDARY_COLOR',
'AUTHENTICATION_ENABLE',
'AUTO_PIN_LATEST_SCREEN_SHARE',
'BRAND_WATERMARK_LINK',
'CLOSE_PAGE_GUEST_HINT',
'CONNECTION_INDICATOR_AUTO_HIDE_ENABLED',
'CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT',
'CONNECTION_INDICATOR_DISABLED',
'DEFAULT_BACKGROUND',
'DEFAULT_LOCAL_DISPLAY_NAME',
'DEFAULT_REMOTE_DISPLAY_NAME',
'DISABLE_DOMINANT_SPEAKER_INDICATOR',
'DISABLE_FOCUS_INDICATOR',
'DISABLE_RINGING',
'DISABLE_TRANSCRIPTION_SUBTITLES',
'DISABLE_VIDEO_BACKGROUND',
'DISPLAY_WELCOME_PAGE_CONTENT',
'ENABLE_FEEDBACK_ANIMATION',
'ENFORCE_NOTIFICATION_AUTO_DISMISS_TIMEOUT',
'FILM_STRIP_MAX_HEIGHT',
'GENERATE_ROOMNAMES_ON_WELCOME_PAGE',
'INDICATOR_FONT_SIZES',
'INITIAL_TOOLBAR_TIMEOUT',
'INVITATION_POWERED_BY',
'JITSI_WATERMARK_LINK',
'LANG_DETECTION',
'LIVE_STREAMING_HELP_LINK',
'LOCAL_THUMBNAIL_RATIO',
'MAXIMUM_ZOOMING_COEFFICIENT',
'MOBILE_APP_PROMO',
'MOBILE_DOWNLOAD_LINK_ANDROID',
'MOBILE_DOWNLOAD_LINK_IOS',
'MOBILE_DYNAMIC_LINK',
'NATIVE_APP_NAME',
'OPTIMAL_BROWSERS',
'PHONE_NUMBER_REGEX',
'POLICY_LOGO',
'PROVIDER_NAME',
'RANDOM_AVATAR_URL_PREFIX',
'RANDOM_AVATAR_URL_SUFFIX',
'RECENT_LIST_ENABLED',
'REMOTE_THUMBNAIL_RATIO',
'SETTINGS_SECTIONS',
'SHOW_BRAND_WATERMARK',
'SHOW_DEEP_LINKING_IMAGE',
'SHOW_JITSI_WATERMARK',
'SHOW_POWERED_BY',
'SHOW_WATERMARK_FOR_GUESTS',
'SUPPORT_URL',
'TILE_VIEW_MAX_COLUMNS',
'TOOLBAR_ALWAYS_VISIBLE',
'TOOLBAR_BUTTONS',
'TOOLBAR_TIMEOUT',
'UNSUPPORTED_BROWSERS',
'VERTICAL_FILMSTRIP',
'VIDEO_LAYOUT_FIT',
'VIDEO_QUALITY_LABEL_DISABLED',
'filmStripOnly'
];

View File

@@ -2,7 +2,6 @@
import _ from 'lodash';
import Platform from '../react/Platform';
import { equals, ReducerRegistry, set } from '../redux';
import { CONFIG_WILL_LOAD, LOAD_CONFIG_ERROR, SET_CONFIG } from './actionTypes';
@@ -21,15 +20,6 @@ import { _cleanupConfig } from './functions';
const INITIAL_NON_RN_STATE = {
};
/**
* When we should enable H.264 on mobile. iOS 10 crashes so we disable it there.
* See: https://bugs.chromium.org/p/webrtc/issues/detail?id=11002
* Note that this is only used for P2P calls.
*
* @type {boolean}
*/
const RN_ENABLE_H264 = navigator.product === 'ReactNative' && !(Platform.OS === 'ios' && Platform.Version === 10);
/**
* The initial state of the feature base/config when executing in a React Native
* environment. The mandatory configuration to be passed to JitsiMeetJS#init().
@@ -51,8 +41,8 @@ const INITIAL_RN_STATE = {
disableAudioLevels: true,
p2p: {
disableH264: !RN_ENABLE_H264,
preferH264: RN_ENABLE_H264
disableH264: false,
preferH264: true
}
};

View File

@@ -9,10 +9,7 @@ import {
getCurrentConference
} from '../conference';
import JitsiMeetJS, { JitsiConnectionEvents } from '../lib-jitsi-meet';
import {
getBackendSafeRoomName,
parseURIString
} from '../util';
import { parseURIString } from '../util';
import {
CONNECTION_DISCONNECTED,
@@ -310,7 +307,10 @@ function _constructOptions(state) {
// Append room to the URL's search.
const { room } = state['features/base/conference'];
room && (bosh += `?room=${getBackendSafeRoomName(room)}`);
// XXX The Jitsi Meet deployments require the room argument to be in
// lower case at the time of this writing but, unfortunately, they do
// not ignore case themselves.
room && (bosh += `?room=${room.toLowerCase()}`);
options.bosh = bosh;
}

View File

@@ -6,7 +6,6 @@ declare var APP: Object;
declare var config: Object;
import { configureInitialDevices } from '../devices';
import { getBackendSafeRoomName } from '../util';
export {
connectionEstablished,
@@ -22,7 +21,8 @@ import logger from './logger';
*/
export function connect() {
return (dispatch: Dispatch<any>, getState: Function) => {
const room = getBackendSafeRoomName(getState()['features/base/conference'].room);
// XXX Lib-jitsi-meet does not accept uppercase letters.
const room = getState()['features/base/conference'].room.toLowerCase();
// XXX For web based version we use conference initialization logic
// from the old app (at the moment of writing).

View File

@@ -61,7 +61,11 @@ class BottomSheet extends PureComponent<Props> {
styles.sheetItemContainer,
_styles.sheet
] }>
{ this._getWrappedContent() }
<ScrollView
bounces = { false }
showsVerticalScrollIndicator = { false }>
{ this._getWrappedContent() }
</ScrollView>
</View>
</View>
</SlidingView>
@@ -69,32 +73,24 @@ class BottomSheet extends PureComponent<Props> {
}
/**
* Wraps the content when needed (iOS 11 and above), or just returns the original content.
* Wraps the content when needed (iOS 11 and above), or just returns the original children.
*
* @returns {React$Element}
*/
_getWrappedContent() {
const content = (
<ScrollView
bounces = { false }
showsVerticalScrollIndicator = { false } >
{ this.props.children }
</ScrollView>
);
if (Platform.OS === 'ios') {
const majorVersionIOS = parseInt(Platform.Version, 10);
if (majorVersionIOS > 10) {
return (
<SafeAreaView>
{ content }
{ this.props.children }
</SafeAreaView>
);
}
}
return content;
return this.props.children;
}
}

View File

@@ -73,12 +73,6 @@ const _LANGUAGES = {
main: require('../../../../lang/main-hr')
},
// Hungarian
'hu': {
languages: require('../../../../lang/languages-hu'),
main: require('../../../../lang/main-hu')
},
// Italian
'it': {
languages: require('../../../../lang/languages-it'),

View File

@@ -11,7 +11,7 @@ type Props = {
/**
* Class name for the web platform, if any.
*/
className: string,
className?: string,
/**
* Color of the icon (if not provided by the style object).
@@ -68,7 +68,7 @@ export default function Icon(props: Props) {
return (
<Container
className = { `jitsi-icon ${className}` }
className = { className }
style = { restStyle }>
<IconComponent
fill = { calculatedColor }
@@ -79,6 +79,3 @@ export default function Icon(props: Props) {
);
}
Icon.defaultProps = {
className: ''
};

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z"/></svg>

Before

Width:  |  Height:  |  Size: 381 B

View File

@@ -28,7 +28,6 @@ export { default as IconExitFullScreen } from './exit-full-screen.svg';
export { default as IconFeedback } from './feedback.svg';
export { default as IconFullScreen } from './full-screen.svg';
export { default as IconHangup } from './hangup.svg';
export { default as IconHelp } from './help.svg';
export { default as IconInfo } from './info.svg';
export { default as IconInvite } from './invite.svg';
export { default as IconKick } from './kick.svg';
@@ -37,7 +36,6 @@ export { default as IconMenu } from './menu.svg';
export { default as IconMenuDown } from './menu-down.svg';
export { default as IconMenuThumb } from './thumb-menu.svg';
export { default as IconMenuUp } from './menu-up.svg';
export { default as IconMessage } from './message.svg';
export { default as IconMicDisabled } from './mic-disabled.svg';
export { default as IconMicrophone } from './microphone.svg';
export { default as IconModerator } from './star.svg';
@@ -50,7 +48,6 @@ export { default as IconRaisedHand } from './raised-hand.svg';
export { default as IconRec } from './rec.svg';
export { default as IconRemoteControlStart } from './play.svg';
export { default as IconRemoteControlStop } from './stop.svg';
export { default as IconReply } from './reply.svg';
export { default as IconRestore } from './restore.svg';
export { default as IconRoomLock } from './security.svg';
export { default as IconRoomUnlock } from './security-locked.svg';

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z"/><path d="M0 0h24v24H0z" fill="none"/></svg>

Before

Width:  |  Height:  |  Size: 256 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10 9V5l-7 7 7 7v-4.1c5 0 8.5 1.6 11 5.1-1-5-4-10-11-11z"/><path d="M0 0h24v24H0z" fill="none"/></svg>

Before

Width:  |  Height:  |  Size: 194 B

View File

@@ -1,7 +1,12 @@
// @flow
import { toState } from '../redux';
import { loadScript } from '../util';
import JitsiMeetJS from './_';
import logger from './logger';
declare var APP: Object;
const JitsiConferenceErrors = JitsiMeetJS.errors.conference;
const JitsiConnectionErrors = JitsiMeetJS.errors.connection;
@@ -92,3 +97,42 @@ export function isFatalJitsiConnectionError(error: Object | string) {
|| error === JitsiConnectionErrors.OTHER_ERROR
|| error === JitsiConnectionErrors.SERVER_ERROR);
}
/**
* Loads config.js from a specific remote server.
*
* @param {string} url - The URL to load.
* @returns {Promise<Object>}
*/
export function loadConfig(url: string): Promise<Object> {
let promise;
if (typeof APP === 'undefined') {
promise
= loadScript(url, 2.5 * 1000 /* Timeout in ms */)
.then(() => {
const { config } = window;
// We don't want to pollute the global scope.
window.config = undefined;
if (typeof config !== 'object') {
throw new Error('window.config is not an object');
}
return config;
})
.catch(err => {
logger.error(`Failed to load config from ${url}`, err);
throw err;
});
} else {
// Return "the config.js file" from the global scope - that is how the
// Web app on both the client and the server was implemented before the
// React Native app was even conceived.
promise = Promise.resolve(window.config);
}
return promise;
}

View File

@@ -1,36 +0,0 @@
// @flow
import { NativeModules } from 'react-native';
import { loadScript } from '../util';
import logger from './logger';
export * from './functions.any';
const { JavaScriptSandbox } = NativeModules;
/**
* Loads config.js from a specific remote server.
*
* @param {string} url - The URL to load.
* @returns {Promise<Object>}
*/
export async function loadConfig(url: string): Promise<Object> {
try {
const configTxt = await loadScript(url, 2.5 * 1000 /* Timeout in ms */, true /* skipeval */);
const configJson = await JavaScriptSandbox.evaluate(`${configTxt}\nJSON.stringify(config);`);
const config = JSON.parse(configJson);
if (typeof config !== 'object') {
throw new Error('config is not an object');
}
logger.info(`Config loaded from ${url}`);
return config;
} catch (err) {
logger.error(`Failed to load config from ${url}`, err);
throw err;
}
}

View File

@@ -1,16 +0,0 @@
// @flow
export * from './functions.any';
/**
* Loads config.js from a specific remote server.
*
* @param {string} url - The URL to load.
* @returns {Promise<Object>}
*/
export async function loadConfig(url: string): Promise<Object> { // eslint-disable-line no-unused-vars
// Return "the config.js file" from the global scope - that is how the
// Web app on both the client and the server was implemented before the
// React Native app was even conceived.
return window.config;
}

View File

@@ -26,13 +26,7 @@ type Props = {
/**
* The JitsiLocalTrack to display.
*/
videoTrack: ?Object,
/**
* Used to determine the value of the autoplay attribute of the underlying
* video element.
*/
autoPlay: boolean
videoTrack: ?Object
};
/**
@@ -50,7 +44,7 @@ class Video extends Component<Props> {
*/
static defaultProps = {
className: '',
autoPlay: true,
id: ''
};
@@ -137,7 +131,7 @@ class Video extends Component<Props> {
render() {
return (
<video
autoPlay = { this.props.autoPlay }
autoPlay = { true }
className = { this.props.className }
id = { this.props.id }
ref = { this._setVideoElement } />

View File

@@ -23,14 +23,7 @@ type Props = AbstractVideoTrackProps & {
* The value of the id attribute of the video. Used by the torture tests
* to locate video elements.
*/
id: string,
/**
*
* Used to determine the value of the autoplay attribute of the underlying
* video element.
*/
_noAutoPlayVideo: boolean
id: string
};
/**
@@ -60,7 +53,7 @@ class VideoTrack extends AbstractVideoTrack<Props> {
render() {
return (
<Video
autoPlay = { !this.props._noAutoPlayVideo }
autoPlay = { true }
className = { this.props.className }
id = { this.props.id }
onVideoPlaying = { this._onVideoPlaying }
@@ -71,22 +64,4 @@ class VideoTrack extends AbstractVideoTrack<Props> {
_onVideoPlaying: () => void;
}
/**
* Maps (parts of) the Redux state to the associated VideoTracks props.
*
* @param {Object} state - The Redux state.
* @private
* @returns {{
* _noAutoPlayVideo: boolean
* }}
*/
function _mapStateToProps(state) {
const testingConfig = state['features/base/config'].testing;
return {
_noAutoPlayVideo: testingConfig?.noAutoPlayVideo
};
}
export default connect(_mapStateToProps)(VideoTrack);
export default connect()(VideoTrack);

View File

@@ -22,14 +22,5 @@ export default {
*
* @type {string}
*/
OS,
/**
* The operating system version on which the application is executing.
* This is intentionally set to undefined so we can tell mobile and mobile web
* appart easier.
*
* @type {number|undefined}
*/
Version: undefined
OS
};

View File

@@ -9,9 +9,9 @@ import { Image } from 'react-native';
type Props = {
/**
* The ImageSource to be rendered as image.
* The URL to be rendered as image.
*/
src: Object,
src: string,
/**
* The component's external style

View File

@@ -28,7 +28,6 @@ export const ColorPalette = {
overflowMenuItemUnderlay: '#EEEEEE',
red: '#D00000',
transparent: 'rgba(0, 0, 0, 0)',
warning: 'rgb(215, 121, 118)',
white: '#FFFFFF',
/**

View File

@@ -1,5 +1,4 @@
export * from './helpers';
export * from './httpUtils';
export * from './loadScript';
export * from './openURLInBrowser';
export * from './uri';

View File

@@ -1,9 +1,6 @@
// @flow
/**
* Default timeout for loading scripts.
*/
const DEFAULT_TIMEOUT = 5000;
import { timeoutPromise } from './timeoutPromise';
/**
* Loads a script from a specific URL. React Native cannot load a JS
@@ -16,49 +13,63 @@ const DEFAULT_TIMEOUT = 5000;
* @param {number} [timeout] - The timeout in millisecnods after which the
* loading of the specified {@code url} is to be aborted/rejected (if not
* settled yet).
* @param {boolean} skipEval - Wether we want to skip evaluating the loaded content or not.
* @returns {void}
*/
export async function loadScript(
url: string, timeout: number = DEFAULT_TIMEOUT, skipEval: boolean = false): Promise<any> {
// XXX The implementation of fetch on Android will throw an Exception on
// the Java side which will break the app if the URL is invalid (which
// the implementation of fetch on Android calls 'unexpected url'). In
// order to try to prevent the breakage of the app, try to fail on an
// invalid URL as soon as possible.
const { hostname, pathname, protocol } = new URL(url);
export function loadScript(url: string, timeout: ?number): Promise<void> {
return new Promise((resolve, reject) => {
// XXX The implementation of fetch on Android will throw an Exception on
// the Java side which will break the app if the URL is invalid (which
// the implementation of fetch on Android calls 'unexpected url'). In
// order to try to prevent the breakage of the app, try to fail on an
// invalid URL as soon as possible.
const { hostname, pathname, protocol } = new URL(url);
// XXX The standard URL implementation should throw an Error if the
// specified URL is relative. Unfortunately, the polyfill used on
// react-native does not.
if (!hostname || !pathname || !protocol) {
throw new Error(`unexpected url: ${url}`);
}
// XXX The standard URL implementation should throw an Error if the
// specified URL is relative. Unfortunately, the polyfill used on
// react-native does not.
if (!hostname || !pathname || !protocol) {
reject(`unexpected url: ${url}`);
const controller = new AbortController();
const signal = controller.signal;
const timer = setTimeout(() => {
controller.abort();
}, timeout);
const response = await fetch(url, { signal });
// If the timeout hits the above will raise AbortError.
clearTimeout(timer);
switch (response.status) {
case 200: {
const txt = await response.text();
if (skipEval) {
return txt;
return;
}
return eval.call(window, txt); // eslint-disable-line no-eval
}
default:
throw new Error(`loadScript error: ${response.statusText}`);
}
let fetch_ = fetch(url, { method: 'GET' });
// The implementation of fetch provided by react-native is based on
// XMLHttpRequest. Which defines timeout as an unsigned long with
// default value 0, which means there is no timeout.
if (timeout) {
// FIXME I don't like the approach with timeoutPromise because:
//
// * It merely abandons the underlying XHR and, consequently, opens
// us to potential issues with NetworkActivityIndicator which
// tracks XHRs.
//
// * @paweldomas also reported that timeouts seem to be respected by
// the XHR implementation on iOS. Given that we have
// implementation of loadScript based on fetch and XHR (in an
// earlier revision), I don't see why we're not using an XHR
// directly on iOS.
//
// * The approach of timeoutPromise I found on the Internet is to
// directly use XHR instead of fetch and abort the XHR on timeout.
// Which may deal with the NetworkActivityIndicator at least.
fetch_ = timeoutPromise(fetch_, timeout);
}
fetch_
.then(response => {
switch (response.status) {
case 200:
return response.responseText || response.text();
default:
throw response.statusText;
}
})
.then(responseText => {
eval.call(window, responseText); // eslint-disable-line no-eval
})
.then(resolve, reject);
});
}

View File

@@ -1,5 +0,0 @@
// @flow
import { getLogger } from '../logging/functions';
export default getLogger('features/base/util');

View File

@@ -1,17 +0,0 @@
// @flow
import { Linking } from 'react-native';
import logger from './logger';
/**
* Opens URL in the browser.
*
* @param {string} url - The URL to be opened.
* @returns {void}
*/
export function openURLInBrowser(url: string) {
Linking.openURL(url).catch(error => {
logger.error(`An error occurred while trying to open ${url}`, error);
});
}

View File

@@ -1,11 +0,0 @@
// @flow
/**
* Opens URL in the browser.
*
* @param {string} url - The URL to be opened.
* @returns {void}
*/
export function openURLInBrowser(url: string) {
window.open(url, '', 'noopener');
}

View File

@@ -96,47 +96,6 @@ function _fixURIStringScheme(uri: string) {
return uri;
}
/**
* Converts a room name to a backend-safe format. Properly lowercased and url encoded.
*
* @param {string?} room - The room name to convert.
* @returns {string?}
*/
export function getBackendSafeRoomName(room: ?string): ?string {
if (!room) {
return room;
}
/* eslint-disable no-param-reassign */
try {
// We do not know if we get an already encoded string at this point
// as different platforms do it differently, but we need a decoded one
// for sure. However since decoding a non-encoded string is a noop, we're safe
// doing it here.
room = decodeURIComponent(room);
} catch (e) {
// This can happen though if we get an unencoded string and it contains
// some characters that look like an encoded entity, but it's not.
// But in this case we're fine goin on...
}
// Normalize the character set
room = room.normalize('NFKC');
// Only decoded and normalized strings can be lowercased properly.
room = room.toLowerCase();
// But we still need to (re)encode it.
room = encodeURIComponent(room);
/* eslint-enable no-param-reassign */
// Unfortunately we still need to lowercase it, because encoding a string will
// add some uppercase characters, but some backend services
// expect it to be full lowercase. However lowercasing an encoded string
// doesn't change the string value.
return room.toLowerCase();
}
/**
* Gets the (Web application) context root defined by a specific location (URI).
*

View File

@@ -30,23 +30,11 @@ export const CLEAR_MESSAGES = 'CLEAR_MESSAGES';
*
* {
* type: SEND_MESSAGE,
* ignorePrivacy: boolean,
* message: string
* }
*/
export const SEND_MESSAGE = 'SEND_MESSAGE';
/**
* The type of action which signals the initiation of sending of as private message to the
* supplied recipient.
*
* {
* participant: Participant,
* type: SET_PRIVATE_MESSAGE_RECIPIENT
* }
*/
export const SET_PRIVATE_MESSAGE_RECIPIENT = 'SET_PRIVATE_MESSAGE_RECIPIENT';
/**
* The type of the action which signals to toggle the display of the chat panel.
*

View File

@@ -4,7 +4,6 @@ import {
ADD_MESSAGE,
CLEAR_MESSAGES,
SEND_MESSAGE,
SET_PRIVATE_MESSAGE_RECIPIENT,
TOGGLE_CHAT
} from './actionTypes';
@@ -54,37 +53,18 @@ export function clearMessages() {
* Sends a chat message to everyone in the conference.
*
* @param {string} message - The chat message to send out.
* @param {boolean} ignorePrivacy - True if the privacy notification should be ignored.
* @returns {{
* type: SEND_MESSAGE,
* ignorePrivacy: boolean,
* message: string
* }}
*/
export function sendMessage(message: string, ignorePrivacy: boolean = false) {
export function sendMessage(message: string) {
return {
type: SEND_MESSAGE,
ignorePrivacy,
message
};
}
/**
* Initiates the sending of a private message to the supplied participant.
*
* @param {Participant} participant - The participant to set the recipient to.
* @returns {{
* participant: Participant,
* type: SET_PRIVATE_MESSAGE_RECIPIENT
* }}
*/
export function setPrivateMessageRecipient(participant: Object) {
return {
participant,
type: SET_PRIVATE_MESSAGE_RECIPIENT
};
}
/**
* Toggles display of the chat side panel.
*

View File

@@ -56,32 +56,4 @@ export default class AbstractChatMessage<P: Props> extends PureComponent<P> {
return getLocalizedDateFormatter(new Date(this.props.message.timestamp))
.format(TIMESTAMP_FORMAT);
}
/**
* Generates the message text to be redered in the component.
*
* @returns {string}
*/
_getMessageText() {
const { message } = this.props;
return message.messageType === 'error'
? this.props.t('chat.error', {
error: message.message
})
: message.message;
}
/**
* Returns the message that is displayed as a notice for private messages.
*
* @returns {string}
*/
_getPrivateNoticeMessage() {
const { message, t } = this.props;
return t('chat.privateNotice', {
recipient: message.messageType === 'local' ? message.recipient : t('chat.you')
});
}
}

View File

@@ -1,116 +0,0 @@
// @flow
import { PureComponent } from 'react';
import { sendMessage, setPrivateMessageRecipient } from '../actions';
import { getParticipantById } from '../../base/participants';
type Props = {
/**
* The message that is about to be sent.
*/
message: Object,
/**
* The ID of the participant that we think the message may be intended to.
*/
participantID: string,
/**
* Function to be used to translate i18n keys.
*/
t: Function,
/**
* Prop to be invoked on sending the message.
*/
_onSendMessage: Function,
/**
* Prop to be invoked when the user wants to set a private recipient.
*/
_onSetMessageRecipient: Function,
/**
* The participant retreived from Redux by the participanrID prop.
*/
_participant: Object
};
/**
* Abstract class for the dialog displayed to avoid mis-sending private messages.
*/
export class AbstractChatPrivacyDialog extends PureComponent<Props> {
/**
* Instantiates a new instance.
*
* @inheritdoc
*/
constructor(props: Props) {
super(props);
this._onSendGroupMessage = this._onSendGroupMessage.bind(this);
this._onSendPrivateMessage = this._onSendPrivateMessage.bind(this);
}
_onSendGroupMessage: () => boolean;
/**
* Callback to be invoked for cancel action (user wants to send a group message).
*
* @returns {boolean}
*/
_onSendGroupMessage() {
this.props._onSendMessage(this.props.message);
return true;
}
_onSendPrivateMessage: () => boolean;
/**
* Callback to be invoked for submit action (user wants to send a private message).
*
* @returns {void}
*/
_onSendPrivateMessage() {
const { message, _onSendMessage, _onSetMessageRecipient, _participant } = this.props;
_onSetMessageRecipient(_participant);
_onSendMessage(message);
return true;
}
}
/**
* Maps part of the props of this component to Redux actions.
*
* @param {Function} dispatch - The Redux dispatch function.
* @returns {Props}
*/
export function _mapDispatchToProps(dispatch: Function): $Shape<Props> {
return {
_onSendMessage: (message: Object) => {
dispatch(sendMessage(message, true));
},
_onSetMessageRecipient: participant => {
dispatch(setPrivateMessageRecipient(participant));
}
};
}
/**
* Maps part of the Redux store to the props of this component.
*
* @param {Object} state - The Redux state.
* @param {Props} ownProps - The own props of the component.
* @returns {Props}
*/
export function _mapStateToProps(state: Object, ownProps: Props): $Shape<Props> {
return {
_participant: getParticipantById(state, ownProps.participantID)
};
}

View File

@@ -1,61 +0,0 @@
// @flow
import { PureComponent } from 'react';
import { getParticipantDisplayName } from '../../base/participants';
import { setPrivateMessageRecipient } from '../actions';
type Props = {
/**
* Function used to translate i18n labels.
*/
t: Function,
/**
* Function to remove the recipent setting of the chat window.
*/
_onRemovePrivateMessageRecipient: Function,
/**
* The name of the message recipient, if any.
*/
_privateMessageRecipient: ?string
};
/**
* Abstract class for the {@code MessageRecipient} component.
*/
export default class AbstractMessageRecipient extends PureComponent<Props> {
}
/**
* Maps part of the props of this component to Redux actions.
*
* @param {Function} dispatch - The Redux dispatch function.
* @returns {Props}
*/
export function _mapDispatchToProps(dispatch: Function): $Shape<Props> {
return {
_onRemovePrivateMessageRecipient: () => {
dispatch(setPrivateMessageRecipient());
}
};
}
/**
* Maps part of the Redux store to the props of this component.
*
* @param {Object} state - The Redux state.
* @returns {Props}
*/
export function _mapStateToProps(state: Object): $Shape<Props> {
const { privateMessageRecipient } = state['features/chat'];
return {
_privateMessageRecipient:
privateMessageRecipient ? getParticipantDisplayName(state, privateMessageRecipient.id) : undefined
};
}

View File

@@ -1,101 +0,0 @@
// @flow
import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox';
import { translate } from '../../base/i18n';
import { IconMessage, IconReply } from '../../base/icons';
import { getParticipantById } from '../../base/participants';
import { connect } from '../../base/redux';
import { setPrivateMessageRecipient } from '../actions';
export type Props = AbstractButtonProps & {
/**
* The ID of the participant that the message is to be sent.
*/
participantID: string,
/**
* True if the button is rendered as a reply button.
*/
reply: boolean,
/**
* Function to be used to translate i18n labels.
*/
t: Function,
/**
* The participant object retreived from Redux.
*/
_participant: Object,
/**
* Function to dispatch the result of the participant selection to send a private message.
*/
_setPrivateMessageRecipient: Function
};
/**
* Class to render a button that initiates the sending of a private message through chet.
*/
class PrivateMessageButton extends AbstractButton<Props, any> {
accessibilityLabel = 'toolbar.accessibilityLabel.privateMessage';
icon = IconMessage;
label = 'toolbar.privateMessage';
toggledIcon = IconReply;
/**
* Handles clicking / pressing the button, and kicks the participant.
*
* @private
* @returns {void}
*/
_handleClick() {
const { _participant, _setPrivateMessageRecipient } = this.props;
_setPrivateMessageRecipient(_participant);
}
/**
* Helper function to be implemented by subclasses, which must return a
* {@code boolean} value indicating if this button is toggled or not.
*
* @protected
* @returns {boolean}
*/
_isToggled() {
return this.props.reply;
}
}
/**
* Maps part of the props of this component to Redux actions.
*
* @param {Function} dispatch - The Redux dispatch function.
* @returns {Props}
*/
export function _mapDispatchToProps(dispatch: Function): $Shape<Props> {
return {
_setPrivateMessageRecipient: participant => {
dispatch(setPrivateMessageRecipient(participant));
}
};
}
/**
* Maps part of the Redux store to the props of this component.
*
* @param {Object} state - The Redux state.
* @param {Props} ownProps - The own props of the component.
* @returns {Props}
*/
export function _mapStateToProps(state: Object, ownProps: Props): $Shape<Props> {
return {
_participant: getParticipantById(state, ownProps.participantID)
};
}
export default translate(connect(_mapStateToProps, _mapDispatchToProps)(PrivateMessageButton));

View File

@@ -1,4 +1,3 @@
// @flow
export * from './native';
export { default as PrivateMessageButton } from './PrivateMessageButton';

View File

@@ -1,5 +1,3 @@
// @flow
export * from './web';
export { default as PrivateMessageButton } from './PrivateMessageButton';

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