mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-09-22 04:39:17 +00:00
Compare commits
1 Commits
android-sd
...
pending-dt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc54a87f2e |
@@ -1,4 +1,4 @@
|
||||
osx_image: xcode11.1
|
||||
osx_image: xcode10.2
|
||||
language: objective-c
|
||||
script:
|
||||
- "./ios/travis-ci/build-ipa.sh"
|
||||
|
||||
12
Makefile
12
Makefile
@@ -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:
|
||||
|
||||
@@ -10,7 +10,7 @@ MVN_HTTP=0
|
||||
DEFAULT_SDK_VERSION=$(grep sdkVersion ${THIS_DIR}/../gradle.properties | cut -d"=" -f2)
|
||||
SDK_VERSION=${OVERRIDE_SDK_VERSION:-${DEFAULT_SDK_VERSION}}
|
||||
RN_VERSION=$(jq -r '.dependencies."react-native"' ${THIS_DIR}/../../package.json)
|
||||
JSC_VERSION="r"$(jq -r '.dependencies."jsc-android"' ${THIS_DIR}/../../node_modules/react-native/package.json | cut -d . -f 1 | cut -c 2-)
|
||||
JSC_VERSION="r"$(jq -r '.dependencies."jsc-android"' ${THIS_DIR}/../../node_modules/react-native/package.json | cut -d . -f 1)
|
||||
DO_GIT_TAG=${GIT_TAG:-0}
|
||||
|
||||
if [[ $THE_MVN_REPO == http* ]]; then
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
24
config.js
24
config.js
@@ -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,16 +425,6 @@ var config = {
|
||||
// the menu has option to flip the locally seen video for local presentations
|
||||
// disableLocalVideoFlip: false
|
||||
|
||||
// Deployment specific URLs.
|
||||
// deploymentUrls: {
|
||||
// // 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',
|
||||
// // If specified a 'Download our apps' button will be displayed in the overflow menu with a link
|
||||
// // to the specified URL for an app download page.
|
||||
// downloadAppsUrl: 'https://docs.example.com/our-apps.html'
|
||||
// }
|
||||
|
||||
// List of undocumented settings used in jitsi-meet
|
||||
/**
|
||||
_immediateReloadThreshold
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
.filmstrip-toolbox,
|
||||
.always-on-top-toolbox {
|
||||
background-color: $newToolbarBackgroundColor;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
z-index: $toolbarZ;
|
||||
|
||||
.toolbox-icon {
|
||||
cursor: pointer;
|
||||
padding: 7px;
|
||||
|
||||
&.toggled {
|
||||
background: $AOTToolbarButtonToggleColor;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.toolbox-button {
|
||||
&:nth-child(2) {
|
||||
svg {
|
||||
fill: $hangupColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.always-on-top-toolbox {
|
||||
flex-direction: row;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
transform: translateX(-50%);
|
||||
|
||||
.toolbox-button {
|
||||
&:first-child {
|
||||
.toolbox-icon {
|
||||
border-top-left-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
.toolbox-icon {
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filmstrip-toolbox {
|
||||
flex-direction: column;
|
||||
|
||||
.toolbox-button {
|
||||
.toolbox-icon {
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -270,6 +270,89 @@
|
||||
}
|
||||
}
|
||||
|
||||
.always-on-top-toolbox,
|
||||
.filmstrip-toolbox {
|
||||
background-color: $newToolbarBackgroundColor;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: $toolbarZ;
|
||||
|
||||
i {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
}
|
||||
|
||||
i:hover {
|
||||
background-color: $AOTToolbarButtonHoverColor;
|
||||
}
|
||||
|
||||
i.toggled {
|
||||
background: $AOTToolbarButtonToggleColor;
|
||||
}
|
||||
|
||||
i.toggled:hover:not(.disabled) {
|
||||
background-color: $AOTToolbarButtonHoverColor;
|
||||
}
|
||||
|
||||
.toolbox-button {
|
||||
color: $toolbarButtonColor;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.always-on-top-toolbox {
|
||||
flex-direction: row;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
transform: translateX(-50%);
|
||||
z-index: $toolbarZ;
|
||||
|
||||
i {
|
||||
font-size: $newToolbarFontSize;
|
||||
height: $newToolbarSize;
|
||||
line-height: $newToolbarSize;
|
||||
width: $newToolbarSize;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
cursor: initial;
|
||||
}
|
||||
|
||||
.toolbox-button:first-child i {
|
||||
border-top-left-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
.toolbox-button:last-child i {
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.filmstrip-toolbox {
|
||||
i {
|
||||
font-size: 1.9em;
|
||||
height: 37px;
|
||||
line-height: 37px;
|
||||
width: 37px;
|
||||
}
|
||||
|
||||
.toolbox-button:first-child i {
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
}
|
||||
|
||||
.toolbox-button:last-child i {
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* START of fade in animation for main toolbar
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/** Insert custom CSS for any additional content in the welcome page settings toolbar **/
|
||||
@@ -32,7 +32,6 @@ $flagsImagePath: "../images/";
|
||||
@import 'overlay/overlay';
|
||||
@import 'inlay';
|
||||
@import 'reload_overlay/reload_overlay';
|
||||
@import 'mini_toolbox';
|
||||
@import 'modals/desktop-picker/desktop-picker';
|
||||
@import 'modals/device-selection/device-selection';
|
||||
@import 'modals/dialog';
|
||||
@@ -52,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';
|
||||
|
||||
@@ -63,8 +63,6 @@
|
||||
width: -webkit-max-content;
|
||||
word-break: break-all;
|
||||
max-width: 400px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.info-dialog-dial-in {
|
||||
@@ -88,15 +86,6 @@
|
||||
cursor: inherit;
|
||||
}
|
||||
|
||||
.info-dialog-url-icon {
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
|
||||
svg {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.info-dialog-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
@@ -225,10 +214,4 @@
|
||||
-moz-user-select: text;
|
||||
-webkit-user-select: text;
|
||||
}
|
||||
|
||||
.info-dialog-url-text-unselectable {
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,37 +19,29 @@ server {
|
||||
ssl_certificate_key /etc/jitsi/meet/jitsi-meet.example.com.key;
|
||||
|
||||
root /usr/share/jitsi-meet;
|
||||
ssi on;
|
||||
index index.html index.htm;
|
||||
error_page 404 /static/404.html;
|
||||
|
||||
location = /config.js {
|
||||
location /config.js {
|
||||
alias /etc/jitsi/meet/jitsi-meet.example.com-config.js;
|
||||
}
|
||||
|
||||
location = /external_api.js {
|
||||
location /external_api.js {
|
||||
alias /usr/share/jitsi-meet/libs/external_api.min.js;
|
||||
}
|
||||
|
||||
#ensure all static content can always be found first
|
||||
location ~ ^/(libs|css|static|images|fonts|lang|sounds|connection_optimization|.well-known)/(.*)$
|
||||
{
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
alias /usr/share/jitsi-meet/$1/$2;
|
||||
location ~ ^/([a-zA-Z0-9=\?]+)$ {
|
||||
rewrite ^/(.*)$ / break;
|
||||
}
|
||||
|
||||
location / {
|
||||
ssi on;
|
||||
}
|
||||
|
||||
# BOSH
|
||||
location = /http-bind {
|
||||
location /http-bind {
|
||||
proxy_pass http://localhost:5280/http-bind;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header Host $http_host;
|
||||
}
|
||||
|
||||
location ~ ^/([^?&:’“]+)$ {
|
||||
try_files $uri @root_path;
|
||||
}
|
||||
|
||||
location @root_path {
|
||||
rewrite ^/(.*)$ / break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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',
|
||||
@@ -51,7 +50,7 @@ var interfaceConfig = {
|
||||
'fodeviceselection', 'hangup', 'profile', 'info', 'chat', 'recording',
|
||||
'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
|
||||
'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
|
||||
'tileview', 'videobackgroundblur', 'download', 'help'
|
||||
'tileview', 'videobackgroundblur'
|
||||
],
|
||||
|
||||
SETTINGS_SECTIONS: [ 'devices', 'language', 'moderator', 'profile', 'calendar' ],
|
||||
@@ -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 */
|
||||
|
||||
@@ -62,7 +62,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 +81,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
|
||||
|
||||
@@ -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
|
||||
@@ -67,10 +62,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,14 +92,7 @@ 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)
|
||||
@@ -276,7 +272,7 @@ 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)
|
||||
@@ -334,8 +330,8 @@ PODS:
|
||||
- ReactCommon/turbomodule/core (= 0.61.1)
|
||||
- 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
|
||||
@@ -390,14 +386,14 @@ DEPENDENCIES:
|
||||
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
|
||||
- ReactCommon/turbomodule (from `../node_modules/react-native/ReactCommon`)
|
||||
- "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`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/CocoaPods/Specs.git:
|
||||
https://github.com/cocoapods/specs.git:
|
||||
- Amplitude-iOS
|
||||
- boost-for-react-native
|
||||
- CocoaLumberjack
|
||||
@@ -410,14 +406,12 @@ SPEC REPOS:
|
||||
- FirebaseDynamicLinks
|
||||
- FirebaseInstanceID
|
||||
- GoogleAppMeasurement
|
||||
- GoogleSignIn
|
||||
- GoogleToolboxForMac
|
||||
- GoogleUtilities
|
||||
- GTMSessionFetcher
|
||||
- nanopb
|
||||
- ObjectiveDropboxOfficial
|
||||
trunk:
|
||||
- AppAuth
|
||||
- GoogleSignIn
|
||||
- GTMAppAuth
|
||||
- GTMSessionFetcher
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
BVLinearGradient:
|
||||
@@ -485,7 +479,7 @@ EXTERNAL SOURCES:
|
||||
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:
|
||||
@@ -497,7 +491,6 @@ EXTERNAL SOURCES:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Amplitude-iOS: 2ad4d7270c99186236c1272a3a9425463b1ae1a7
|
||||
AppAuth: bce82c76043657c99d91e7882e8a9e1a93650cd4
|
||||
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
|
||||
BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872
|
||||
CocoaLumberjack: 2f44e60eb91c176d471fdba43b9e3eae6a721947
|
||||
@@ -515,10 +508,10 @@ 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
|
||||
@@ -535,7 +528,7 @@ SPEC CHECKSUMS:
|
||||
react-native-keep-awake: eba3137546b10003361b37c761f6c429b59814ae
|
||||
react-native-netinfo: 8d8db463bcc5db66a8ac5c48a7d86beb3b92f61a
|
||||
react-native-webrtc: c5e3d631179a933548a8e49bddbd8fad02586095
|
||||
react-native-webview: 4dbc1d2a4a6b9c5e9e723c62651917aa2b5e579e
|
||||
react-native-webview: a95842e3f351a6d2c8bc8bcc9eab689c7e7e5ad4
|
||||
React-RCTActionSheet: af4d951113b1e068bb30611f91b984a7a73597ff
|
||||
React-RCTAnimation: 4f518d70bb6890b7c3d9d732f84786d6693ca297
|
||||
React-RCTBlob: 072a4888c08de0eef6d04eaa727d25e577e6ff26
|
||||
@@ -547,12 +540,12 @@ SPEC CHECKSUMS:
|
||||
React-RCTVibration: 8be61459e3749d1fb02cf414edd05b3007622882
|
||||
ReactCommon: 4fba5be89efdf0b5720e0adb3d8d7edf6e532db0
|
||||
RNCAsyncStorage: 8e31405a9f12fbf42c2bb330e4560bfd79c18323
|
||||
RNGoogleSignin: 39336070b35fc4cea6a98cf111e00480317be0ae
|
||||
RNGoogleSignin: d030c6c6591db24c3cee649f64c7babf0a1699a0
|
||||
RNSound: c980916b596cc15c8dcd2f6ecd3b13c4881dbe20
|
||||
RNSVG: aac12785382e8fd4f28d072fe640612e34914631
|
||||
RNWatch: 09738b339eceb66e4d80a2371633ca5fb380fa42
|
||||
Yoga: d8c572ddec8d05b7dba08e4e5f1924004a177078
|
||||
|
||||
PODFILE CHECKSUM: cb84b325b724c6ef7c8b24aa52ca7b6f681a095c
|
||||
PODFILE CHECKSUM: 5d4de5dc42643ef3864a9100b834caeafd625db7
|
||||
|
||||
COCOAPODS: 1.8.1
|
||||
COCOAPODS: 1.7.2
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
|
||||
<ActionContent
|
||||
title = "Run Script"
|
||||
scriptText = "exec > /tmp/${PROJECT_NAME}_archive.log 2>&1 UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal if [ "true" == ${ALREADYINVOKED:-false} ] then echo "RECURSION: Detected, stopping" else export ALREADYINVOKED="true" # make sure the output directory exists mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" echo "Building for iPhoneSimulator" xcodebuild -workspace "${WORKSPACE_PATH}" -scheme "${TARGET_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 8' ONLY_ACTIVE_ARCH=NO ARCHS='i386 x86_64' BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" ENABLE_BITCODE=YES OTHER_CFLAGS="-fembed-bitcode" BITCODE_GENERATION_MODE=bitcode clean build # Step 1. Copy the framework structure (from iphoneos build) to the universal folder echo "Copying to output folder" cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FULL_PRODUCT_NAME}" "${UNIVERSAL_OUTPUTFOLDER}/" # Step 2. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/." if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule" fi # Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory echo "Combining executables" lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${EXECUTABLE_PATH}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${EXECUTABLE_PATH}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${EXECUTABLE_PATH}" # Step 4. Create universal binaries for embedded frameworks #for SUB_FRAMEWORK in $( ls "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks" ); do #BINARY_NAME="${SUB_FRAMEWORK%.*}" #lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SUB_FRAMEWORK}/${BINARY_NAME}" "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" #done # Step 5. Convenience step to copy the framework to the project's directory echo "Copying to project dir" yes | cp -Rf "${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}" "${PROJECT_DIR}" fi ">
|
||||
scriptText = "exec > /tmp/${PROJECT_NAME}_archive.log 2>&1 UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal if [ "true" == ${ALREADYINVOKED:-false} ] then echo "RECURSION: Detected, stopping" else export ALREADYINVOKED="true" # make sure the output directory exists mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" echo "Building for iPhoneSimulator" xcodebuild -workspace "${WORKSPACE_PATH}" -scheme "${TARGET_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6' ONLY_ACTIVE_ARCH=NO ARCHS='i386 x86_64' BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" ENABLE_BITCODE=YES OTHER_CFLAGS="-fembed-bitcode" BITCODE_GENERATION_MODE=bitcode clean build # Step 1. Copy the framework structure (from iphoneos build) to the universal folder echo "Copying to output folder" cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FULL_PRODUCT_NAME}" "${UNIVERSAL_OUTPUTFOLDER}/" # Step 2. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/." if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule" fi # Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory echo "Combining executables" lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${EXECUTABLE_PATH}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${EXECUTABLE_PATH}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${EXECUTABLE_PATH}" # Step 4. Create universal binaries for embedded frameworks #for SUB_FRAMEWORK in $( ls "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks" ); do #BINARY_NAME="${SUB_FRAMEWORK%.*}" #lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SUB_FRAMEWORK}/${BINARY_NAME}" "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" #done # Step 5. Convenience step to copy the framework to the project's directory echo "Copying to project dir" yes | cp -Rf "${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}" "${PROJECT_DIR}" fi">
|
||||
<EnvironmentBuildable>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#import "ReactUtils.h"
|
||||
|
||||
#import <RNGoogleSignin/RNGoogleSignin.h>
|
||||
#import <WebRTC/RTCLogging.h>
|
||||
|
||||
|
||||
@implementation JitsiMeet {
|
||||
@@ -55,11 +54,6 @@
|
||||
|
||||
// Register a log handler for React.
|
||||
registerReactLogHandler();
|
||||
|
||||
#if 0
|
||||
// Enable WebRTC logs
|
||||
RTCSetMinDebugLogLevel(RTCLoggingSeverityInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -96,7 +90,8 @@
|
||||
|
||||
if ([RNGoogleSignin application:app
|
||||
openURL:url
|
||||
options:options]) {
|
||||
sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
|
||||
annotation:options[UIApplicationOpenURLOptionsAnnotationKey]]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -184,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 {
|
||||
|
||||
@@ -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": "Китайски (Китай)"
|
||||
}
|
||||
@@ -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)"
|
||||
}
|
||||
@@ -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": ""
|
||||
}
|
||||
@@ -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)"
|
||||
}
|
||||
@@ -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)"
|
||||
}
|
||||
@@ -14,7 +14,6 @@
|
||||
"fr": "French",
|
||||
"frCA": "French (Canadian)",
|
||||
"hr": "Croatian",
|
||||
"hu": "Hungarian",
|
||||
"hy": "Armenian",
|
||||
"it": "Italian",
|
||||
"ja": "Japanese",
|
||||
|
||||
@@ -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": ""
|
||||
}
|
||||
}
|
||||
1187
lang/main-hu.json
1187
lang/main-hu.json
File diff suppressed because it is too large
Load Diff
@@ -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 qu’arribe 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 qu’arribe 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 d’aquestes 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 l’enregistrament de la conferéncia...",
|
||||
"rec": "ENRG",
|
||||
"serviceDescription": "Vòstre enregistrament serà salvagardat pel servici dedicat.",
|
||||
@@ -512,7 +508,7 @@
|
||||
"alertOk": "D’acòrdi",
|
||||
"alertTitle": "Avertiment",
|
||||
"alertURLText": "L’URL 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 d’enregistraments locals",
|
||||
"lockRoom": "Tirar lo senhal de la conferéncia",
|
||||
"moreActions": "Passar al menú mai d’accions",
|
||||
@@ -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 qualqu’un",
|
||||
@@ -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 l’ecran complèt",
|
||||
"enterTileView": "Dintrar dins la vista mosaïca",
|
||||
"enterTileView": "",
|
||||
"exitFullScreen": "Sortir de l’ecran 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 d’ecran.",
|
||||
"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
@@ -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",
|
||||
|
||||
@@ -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 weren’t 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 weren’t 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",
|
||||
@@ -570,11 +556,9 @@
|
||||
"cc": "Toggle subtitles",
|
||||
"chat": "Toggle chat window",
|
||||
"document": "Toggle shared document",
|
||||
"download": "Download our apps",
|
||||
"feedback": "Leave feedback",
|
||||
"fullScreen": "Toggle full screen",
|
||||
"hangup": "Leave the call",
|
||||
"help": "Help",
|
||||
"invite": "Invite people",
|
||||
"kick": "Kick participant",
|
||||
"localRecording": "Toggle local recording controls",
|
||||
@@ -583,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",
|
||||
@@ -610,14 +593,12 @@
|
||||
"closeChat": "Close chat",
|
||||
"documentClose": "Close shared document",
|
||||
"documentOpen": "Open shared document",
|
||||
"download": "Download our apps",
|
||||
"enterFullScreen": "View full screen",
|
||||
"enterTileView": "Enter tile view",
|
||||
"exitFullScreen": "Exit full screen",
|
||||
"exitTileView": "Exit tile view",
|
||||
"feedback": "Leave feedback",
|
||||
"hangup": "Leave",
|
||||
"help": "Help",
|
||||
"invite": "Invite people",
|
||||
"login": "Login",
|
||||
"logout": "Logout",
|
||||
@@ -626,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",
|
||||
@@ -727,7 +707,7 @@
|
||||
"connectCalendarButton": "Connect your calendar",
|
||||
"connectCalendarText": "Connect your calendar to view all your meetings in {{app}}. Plus, add {{provider}} meetings to your calendar and start them with one click.",
|
||||
"enterRoomTitle": "Start a new meeting",
|
||||
"roomNameAllowedChars": "Meeting name should not contain any of these characters: ?, &, :, ', \", %, #.",
|
||||
"onlyAsciiAllowed": "Meeting name should only contain latin characters and numbers.",
|
||||
"go": "GO",
|
||||
"join": "JOIN",
|
||||
"info": "Info",
|
||||
|
||||
@@ -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());
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -513,31 +512,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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
3071
package-lock.json
generated
3071
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
@@ -35,7 +35,6 @@
|
||||
"@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",
|
||||
@@ -49,7 +48,7 @@
|
||||
"i18next-browser-languagedetector": "3.0.1",
|
||||
"i18next-xhr-backend": "3.0.0",
|
||||
"jQuery-Impromptu": "github:trentrichardson/jQuery-Impromptu#v6.0.0",
|
||||
"jitsi-meet-logger": "github:jitsi/jitsi-meet-logger#5ec92357570dc8f0b7ffc1528820721c84c6af8b",
|
||||
"jitsi-meet-logger": "github:jitsi/jitsi-meet-logger#a885cc98688ef2c3972284bda901596a26ffee52",
|
||||
"jquery": "3.4.0",
|
||||
"jquery-contextmenu": "2.4.5",
|
||||
"jquery-i18next": "1.2.1",
|
||||
@@ -57,7 +56,7 @@
|
||||
"js-utils": "github:jitsi/js-utils#192b1c996e8c05530eb1f19e82a31069c3021e31",
|
||||
"jsrsasign": "8.0.12",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#cdd2029b4b6b3626658f9834c324e1ffb7474795",
|
||||
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#3f7613748d7669cd3fd031bbdf9069e4309f6f56",
|
||||
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
|
||||
"lodash": "4.17.13",
|
||||
"moment": "2.19.4",
|
||||
@@ -72,6 +71,7 @@
|
||||
"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:react-native-webrtc/react-native-webrtc#a12a6cdfdefe53d03b388394e4cf10966bd99fca",
|
||||
"react-native-webview": "7.4.1",
|
||||
"react-native-webrtc": "github:jitsi/react-native-webrtc#047b019a7ce1ec93ab4a2f6796e997d7a02e8e5d",
|
||||
"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",
|
||||
@@ -122,14 +121,14 @@
|
||||
"imports-loader": "0.7.1",
|
||||
"jetifier": "1.6.4",
|
||||
"metro-react-native-babel-preset": "0.56.0",
|
||||
"node-sass": "4.12.0",
|
||||
"node-sass": "4.10.0",
|
||||
"precommit-hook": "3.0.0",
|
||||
"string-replace-loader": "2.1.1",
|
||||
"style-loader": "0.19.0",
|
||||
"webpack": "4.27.1",
|
||||
"webpack": "4.26.1",
|
||||
"webpack-bundle-analyzer": "3.4.1",
|
||||
"webpack-cli": "3.1.2",
|
||||
"webpack-dev-server": "3.8.2"
|
||||
"webpack-dev-server": "3.1.14"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
} from '../../base/dialog';
|
||||
import { translate } from '../../base/i18n';
|
||||
import { JitsiConnectionErrors } from '../../base/lib-jitsi-meet';
|
||||
import type { StyleType } from '../../base/styles';
|
||||
import { StyleType } from '../../base/styles';
|
||||
|
||||
import { authenticateAndUpgradeRole, cancelLogin } from '../actions';
|
||||
import styles from './styles';
|
||||
|
||||
@@ -153,8 +153,6 @@ class ColorSchemeRegistry {
|
||||
const colorScheme = toState(stateful)['features/base/color-scheme'];
|
||||
|
||||
return {
|
||||
...defaultScheme._defaultTheme,
|
||||
...colorScheme._defaultTheme,
|
||||
...defaultScheme[componentName],
|
||||
...colorScheme[componentName]
|
||||
}[colorDefinition];
|
||||
|
||||
@@ -6,26 +6,18 @@ import { ColorPalette, getRGBAFormat } from '../styles';
|
||||
* The default color scheme of the application.
|
||||
*/
|
||||
export default {
|
||||
'_defaultTheme': {
|
||||
// Generic app theme colors that are used accross the entire app.
|
||||
// All scheme definitions below inherit these values.
|
||||
'BottomSheet': {
|
||||
background: 'rgb(255, 255, 255)',
|
||||
icon: 'rgb(28, 32, 37)',
|
||||
text: 'rgb(28, 32, 37)'
|
||||
},
|
||||
'Chat': {
|
||||
displayName: 'rgb(94, 109, 121)',
|
||||
localMsgBackground: 'rgb(215, 230, 249)',
|
||||
privateMsgBackground: 'rgb(250, 219, 219)',
|
||||
privateMsgNotice: 'rgb(186, 39, 58)',
|
||||
remoteMsgBackground: 'rgb(241, 242, 246)',
|
||||
replyBorder: 'rgb(219, 197, 200)',
|
||||
replyIcon: 'rgb(94, 109, 121)'
|
||||
icon: '#1c2025',
|
||||
label: '#1c2025'
|
||||
},
|
||||
'Dialog': {
|
||||
background: 'rgb(255, 255, 255)',
|
||||
border: 'rgba(0, 3, 6, 0.6)',
|
||||
buttonBackground: ColorPalette.blue,
|
||||
buttonLabel: ColorPalette.white
|
||||
buttonLabel: ColorPalette.white,
|
||||
icon: '#1c2025',
|
||||
text: '#1c2025'
|
||||
},
|
||||
'Header': {
|
||||
background: ColorPalette.blue,
|
||||
@@ -38,7 +30,8 @@ export default {
|
||||
background: 'rgb(42, 58, 75)'
|
||||
},
|
||||
'LoadConfigOverlay': {
|
||||
background: 'rgb(249, 249, 249)'
|
||||
background: 'rgb(249, 249, 249)',
|
||||
text: 'rgb(28, 32, 37)'
|
||||
},
|
||||
'Thumbnail': {
|
||||
activeParticipantHighlight: 'rgb(81, 214, 170)',
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'
|
||||
];
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
];
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ ColorSchemeRegistry.register('BottomSheet', {
|
||||
* Style for the label in a generic item rendered in the menu.
|
||||
*/
|
||||
labelStyle: {
|
||||
color: schemeColor('text'),
|
||||
color: schemeColor('label'),
|
||||
flexShrink: 1,
|
||||
fontSize: MD_FONT_SIZE,
|
||||
marginLeft: 32,
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -23,11 +23,6 @@ type Props = {
|
||||
*/
|
||||
id?: string,
|
||||
|
||||
/**
|
||||
* Function to invoke on click.
|
||||
*/
|
||||
onClick?: Function,
|
||||
|
||||
/**
|
||||
* The size of the icon (if not provided by the style object).
|
||||
*/
|
||||
@@ -58,7 +53,6 @@ export default function Icon(props: Props) {
|
||||
className,
|
||||
color,
|
||||
id,
|
||||
onClick,
|
||||
size,
|
||||
src: IconComponent,
|
||||
style
|
||||
@@ -75,7 +69,6 @@ export default function Icon(props: Props) {
|
||||
return (
|
||||
<Container
|
||||
className = { `jitsi-icon ${className}` }
|
||||
onClick = { onClick }
|
||||
style = { restStyle }>
|
||||
<IconComponent
|
||||
fill = { calculatedColor }
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 4C4 2.89543 4.89543 2 6 2H14C15.1046 2 16 2.89543 16 4H6V18C4.89543 18 4 17.1046 4 16V4ZM10 8V20H18V8H10ZM10 6H18C19.1046 6 20 6.89543 20 8V20C20 21.1046 19.1046 22 18 22H10C8.89543 22 8 21.1046 8 20V8C8 6.89543 8.89543 6 10 6Z" fill="#5E6D7A"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 401 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 13.3705V5C11 4.44772 11.4477 4 12 4C12.5523 4 13 4.44772 13 5V13.4667L15.631 10.5433C16.0005 10.1328 16.6328 10.0995 17.0433 10.469C17.4538 10.8384 17.4871 11.4707 17.1176 11.8812L12.1064 17.4492C12.0727 17.4867 12.0139 17.4867 11.9802 17.4492L6.96897 11.8812C6.59951 11.4707 6.63278 10.8384 7.04329 10.469C7.4538 10.0995 8.08609 10.1328 8.45555 10.5433L11 13.3705ZM20 15C20 14.4477 20.4477 14 21 14C21.5523 14 22 14.4477 22 15V21C22 21.5523 21.5523 22 21 22H3C2.96548 22 2.93137 21.9983 2.89776 21.9948C2.3935 21.9436 2 21.5178 2 21V15C2 14.4477 2.44772 14 3 14C3.55228 14 4 14.4477 4 15V20H20V15Z" fill="#A4B8D1"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 773 B |
@@ -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 |
@@ -18,19 +18,16 @@ export { default as IconClose } from './close.svg';
|
||||
export { default as IconClosedCaption } from './closed_caption.svg';
|
||||
export { default as IconConnectionActive } from './gsm-bars.svg';
|
||||
export { default as IconConnectionInactive } from './ninja.svg';
|
||||
export { default as IconCopy } from './copy.svg';
|
||||
export { default as IconDeviceBluetooth } from './bluetooth.svg';
|
||||
export { default as IconDeviceEarpiece } from './phone-talk.svg';
|
||||
export { default as IconDeviceHeadphone } from './headset.svg';
|
||||
export { default as IconDeviceSpeaker } from './volume.svg';
|
||||
export { default as IconDominantSpeaker } from './dominant-speaker.svg';
|
||||
export { default as IconDownload } from './download.svg';
|
||||
export { default as IconEventNote } from './event_note.svg';
|
||||
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';
|
||||
@@ -39,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';
|
||||
@@ -52,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';
|
||||
|
||||
@@ -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 |
@@ -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 |
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -63,13 +63,13 @@ export default class JitsiMeetLogStorage {
|
||||
for (let i = 0, len = logEntries.length; i < len; i++) {
|
||||
const logEntry = logEntries[i];
|
||||
|
||||
if (logEntry.timestamp) {
|
||||
logMessage += `${logEntry.timestamp} `;
|
||||
if (typeof logEntry === 'object') {
|
||||
// Aggregated message
|
||||
logMessage += `(${logEntry.count}) ${logEntry.text}\n`;
|
||||
} else {
|
||||
// Regular message
|
||||
logMessage += `${logEntry}\n`;
|
||||
}
|
||||
if (logEntry.count > 1) {
|
||||
logMessage += `(${logEntry.count}) `;
|
||||
}
|
||||
logMessage += `${logEntry.text}\n`;
|
||||
}
|
||||
logMessage += '"}';
|
||||
|
||||
|
||||
@@ -39,8 +39,7 @@ function buildTransport() {
|
||||
'warn',
|
||||
'error'
|
||||
].reduce((logger, logName) => {
|
||||
logger[logName] = (timestamp: string, ...args: Array<string>) => {
|
||||
// It ignores the timestamp argument, because LogBridge will add it on the native side anyway
|
||||
logger[logName] = (...args: Array<string>) => {
|
||||
const nargs = args.map(arg => {
|
||||
if (arg instanceof Error) {
|
||||
const errorBody = {
|
||||
|
||||
@@ -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 } />
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from '../../media';
|
||||
import { Container, TintedView } from '../../react';
|
||||
import { connect } from '../../redux';
|
||||
import type { StyleType } from '../../styles';
|
||||
import { StyleType } from '../../styles';
|
||||
import { TestHint } from '../../testing/components';
|
||||
import { getTrackByMediaTypeAndParticipant } from '../../tracks';
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ export default class Linkify extends Component<Props> {
|
||||
return (
|
||||
<ReactLinkify
|
||||
componentDecorator = { this._componentDecorator }>
|
||||
<Text selectable = { true }>
|
||||
<Text>
|
||||
{ this.props.children }
|
||||
</Text>
|
||||
</ReactLinkify>
|
||||
|
||||
@@ -28,7 +28,6 @@ export const ColorPalette = {
|
||||
overflowMenuItemUnderlay: '#EEEEEE',
|
||||
red: '#D00000',
|
||||
transparent: 'rgba(0, 0, 0, 0)',
|
||||
warning: 'rgb(215, 121, 118)',
|
||||
white: '#FFFFFF',
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
export * from './helpers';
|
||||
export * from './httpUtils';
|
||||
export * from './loadScript';
|
||||
export * from './openURLInBrowser';
|
||||
export * from './uri';
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import { getLogger } from '../logging/functions';
|
||||
|
||||
export default getLogger('features/base/util');
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
@@ -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).
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -4,8 +4,6 @@ import { PureComponent } from 'react';
|
||||
|
||||
import { getLocalizedDateFormatter } from '../../base/i18n';
|
||||
|
||||
import { MESSAGE_TYPE_ERROR, MESSAGE_TYPE_LOCAL } from '../constants';
|
||||
|
||||
/**
|
||||
* Formatter string to display the message timestamp.
|
||||
*/
|
||||
@@ -58,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 === MESSAGE_TYPE_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 === MESSAGE_TYPE_LOCAL ? message.recipient : t('chat.you')
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import { getParticipantDisplayName } from '../../base/participants';
|
||||
|
||||
import { setPrivateMessageRecipient } from '../actions';
|
||||
|
||||
export 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<P: Props> extends PureComponent<P> {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
};
|
||||
}
|
||||
@@ -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));
|
||||
@@ -1,4 +1,3 @@
|
||||
// @flow
|
||||
|
||||
export * from './native';
|
||||
export { default as PrivateMessageButton } from './PrivateMessageButton';
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
export * from './web';
|
||||
|
||||
export { default as PrivateMessageButton } from './PrivateMessageButton';
|
||||
|
||||
@@ -3,31 +3,21 @@
|
||||
import React from 'react';
|
||||
import { KeyboardAvoidingView, SafeAreaView } from 'react-native';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||
import { translate } from '../../../base/i18n';
|
||||
|
||||
import { HeaderWithNavigation, SlidingView } from '../../../base/react';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { StyleType } from '../../../base/styles';
|
||||
|
||||
import AbstractChat, {
|
||||
_mapDispatchToProps,
|
||||
_mapStateToProps as _abstractMapStateToProps,
|
||||
type Props as AbstractProps
|
||||
_mapStateToProps,
|
||||
type Props
|
||||
} from '../AbstractChat';
|
||||
|
||||
import ChatInputBar from './ChatInputBar';
|
||||
import MessageContainer from './MessageContainer';
|
||||
import MessageRecipient from './MessageRecipient';
|
||||
import styles from './styles';
|
||||
|
||||
type Props = AbstractProps & {
|
||||
|
||||
/**
|
||||
* The color-schemed stylesheet of the feature.
|
||||
*/
|
||||
_styles: StyleType
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a React native component that renders the chat window (modal) of
|
||||
* the mobile client.
|
||||
@@ -50,8 +40,6 @@ class Chat extends AbstractChat<Props> {
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
const { _styles } = this.props;
|
||||
|
||||
return (
|
||||
<SlidingView
|
||||
onHide = { this._onClose }
|
||||
@@ -63,9 +51,8 @@ class Chat extends AbstractChat<Props> {
|
||||
<HeaderWithNavigation
|
||||
headerLabelKey = 'chat.title'
|
||||
onPressBack = { this._onClose } />
|
||||
<SafeAreaView style = { _styles.backdrop }>
|
||||
<SafeAreaView style = { styles.backdrop }>
|
||||
<MessageContainer messages = { this.props._messages } />
|
||||
<MessageRecipient />
|
||||
<ChatInputBar onSend = { this.props._onSendMessage } />
|
||||
</SafeAreaView>
|
||||
</KeyboardAvoidingView>
|
||||
@@ -91,17 +78,4 @@ class Chat extends AbstractChat<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps part of the redux state to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
return {
|
||||
..._abstractMapStateToProps(state),
|
||||
_styles: ColorSchemeRegistry.get(state, 'Chat')
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps, _mapDispatchToProps)(Chat));
|
||||
|
||||
@@ -4,28 +4,15 @@ import React from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
|
||||
import { Avatar } from '../../../base/avatar';
|
||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { Linkify } from '../../../base/react';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { type StyleType } from '../../../base/styles';
|
||||
|
||||
import { MESSAGE_TYPE_ERROR, MESSAGE_TYPE_LOCAL } from '../../constants';
|
||||
import { replaceNonUnicodeEmojis } from '../../functions';
|
||||
|
||||
import AbstractChatMessage, { type Props as AbstractProps } from '../AbstractChatMessage';
|
||||
import PrivateMessageButton from '../PrivateMessageButton';
|
||||
import AbstractChatMessage, { type Props } from '../AbstractChatMessage';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
type Props = AbstractProps & {
|
||||
|
||||
/**
|
||||
* The color-schemed stylesheet of the feature.
|
||||
*/
|
||||
_styles: StyleType
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a single chat message.
|
||||
*/
|
||||
@@ -36,58 +23,50 @@ class ChatMessage extends AbstractChatMessage<Props> {
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
const { _styles, message } = this.props;
|
||||
const localMessage = message.messageType === MESSAGE_TYPE_LOCAL;
|
||||
const { privateMessage } = message;
|
||||
const { message } = this.props;
|
||||
const localMessage = message.messageType === 'local';
|
||||
|
||||
// Style arrays that need to be updated in various scenarios, such as
|
||||
// error messages or others.
|
||||
const detailsWrapperStyle = [
|
||||
styles.detailsWrapper
|
||||
];
|
||||
const messageBubbleStyle = [
|
||||
styles.messageBubble
|
||||
const textWrapperStyle = [
|
||||
styles.textWrapper
|
||||
];
|
||||
|
||||
if (localMessage) {
|
||||
// This is a message sent by the local participant.
|
||||
|
||||
// The wrapper needs to be aligned to the right.
|
||||
detailsWrapperStyle.push(styles.ownMessageDetailsWrapper);
|
||||
|
||||
// The bubble needs some additional styling
|
||||
messageBubbleStyle.push(_styles.localMessageBubble);
|
||||
} else if (message.messageType === MESSAGE_TYPE_ERROR) {
|
||||
// This is a system message.
|
||||
|
||||
// The bubble needs some additional styling
|
||||
messageBubbleStyle.push(styles.systemMessageBubble);
|
||||
} else {
|
||||
// This is a remote message sent by a remote participant.
|
||||
|
||||
// The bubble needs some additional styling
|
||||
messageBubbleStyle.push(_styles.remoteMessageBubble);
|
||||
// The bubble needs to be differently styled.
|
||||
textWrapperStyle.push(styles.ownTextWrapper);
|
||||
} else if (message.messageType === 'error') {
|
||||
// The bubble needs to be differently styled.
|
||||
textWrapperStyle.push(styles.systemTextWrapper);
|
||||
}
|
||||
|
||||
if (privateMessage) {
|
||||
messageBubbleStyle.push(_styles.privateMessageBubble);
|
||||
}
|
||||
const messageText = message.messageType === 'error'
|
||||
? this.props.t('chat.error', {
|
||||
error: message.error,
|
||||
originalText: message.message
|
||||
})
|
||||
: message.message;
|
||||
|
||||
return (
|
||||
<View style = { styles.messageWrapper } >
|
||||
{ this._renderAvatar() }
|
||||
<View style = { detailsWrapperStyle }>
|
||||
<View style = { messageBubbleStyle }>
|
||||
<View style = { styles.textWrapper } >
|
||||
{ this._renderDisplayName() }
|
||||
<Linkify linkStyle = { styles.chatLink }>
|
||||
{ replaceNonUnicodeEmojis(this._getMessageText()) }
|
||||
</Linkify>
|
||||
{ this._renderPrivateNotice() }
|
||||
</View>
|
||||
{ this._renderPrivateReplyButton() }
|
||||
<View style = { textWrapperStyle } >
|
||||
{
|
||||
this.props.showDisplayName
|
||||
&& this._renderDisplayName()
|
||||
}
|
||||
<Linkify linkStyle = { styles.chatLink }>
|
||||
{ replaceNonUnicodeEmojis(messageText) }
|
||||
</Linkify>
|
||||
</View>
|
||||
{ this._renderTimestamp() }
|
||||
{ this.props.showTimestamp && this._renderTimestamp() }
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
@@ -95,10 +74,6 @@ class ChatMessage extends AbstractChatMessage<Props> {
|
||||
|
||||
_getFormattedTimestamp: () => string;
|
||||
|
||||
_getMessageText: () => string;
|
||||
|
||||
_getPrivateNoticeMessage: () => string;
|
||||
|
||||
/**
|
||||
* Renders the avatar of the sender.
|
||||
*
|
||||
@@ -119,77 +94,24 @@ class ChatMessage extends AbstractChatMessage<Props> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the display name of the sender if necessary.
|
||||
* Renders the display name of the sender.
|
||||
*
|
||||
* @returns {React$Element<*> | null}
|
||||
* @returns {React$Element<*>}
|
||||
*/
|
||||
_renderDisplayName() {
|
||||
const { _styles, message, showDisplayName } = this.props;
|
||||
|
||||
if (!showDisplayName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Text style = { _styles.displayName }>
|
||||
{ message.displayName }
|
||||
<Text style = { styles.displayName }>
|
||||
{ this.props.message.displayName }
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the message privacy notice, if necessary.
|
||||
* Renders the time at which the message was sent.
|
||||
*
|
||||
* @returns {React$Element<*> | null}
|
||||
*/
|
||||
_renderPrivateNotice() {
|
||||
const { _styles, message } = this.props;
|
||||
|
||||
if (!message.privateMessage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Text style = { _styles.privateNotice }>
|
||||
{ this._getPrivateNoticeMessage() }
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the private reply button, if necessary.
|
||||
*
|
||||
* @returns {React$Element<*> | null}
|
||||
*/
|
||||
_renderPrivateReplyButton() {
|
||||
const { _styles, message } = this.props;
|
||||
const { messageType, privateMessage } = message;
|
||||
|
||||
if (!privateMessage || messageType === MESSAGE_TYPE_LOCAL) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style = { _styles.replyContainer }>
|
||||
<PrivateMessageButton
|
||||
participantID = { message.id }
|
||||
reply = { true }
|
||||
showLabel = { false }
|
||||
toggledStyles = { _styles.replyStyles } />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the time at which the message was sent, if necessary.
|
||||
*
|
||||
* @returns {React$Element<*> | null}
|
||||
* @returns {React$Element<*>}
|
||||
*/
|
||||
_renderTimestamp() {
|
||||
if (!this.props.showTimestamp) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Text style = { styles.timeText }>
|
||||
{ this._getFormattedTimestamp() }
|
||||
@@ -198,16 +120,4 @@ class ChatMessage extends AbstractChatMessage<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps part of the redux state to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
return {
|
||||
_styles: ColorSchemeRegistry.get(state, 'Chat')
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(ChatMessage));
|
||||
export default translate(ChatMessage);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user