Compare commits
41 Commits
3925
...
update-js-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7469e7fa3d | ||
|
|
c170970992 | ||
|
|
d19a659871 | ||
|
|
955b24be9d | ||
|
|
de6c7e0117 | ||
|
|
feb8fe9e34 | ||
|
|
aff6d4b36d | ||
|
|
45c60717d6 | ||
|
|
6596e27f69 | ||
|
|
8cba7e91d3 | ||
|
|
3a871cbed8 | ||
|
|
a46fd60788 | ||
|
|
97735ff548 | ||
|
|
9fdc18d1ec | ||
|
|
4a21882345 | ||
|
|
cb0cea4ebd | ||
|
|
b894daa9cf | ||
|
|
06641a7dd6 | ||
|
|
94f7b570d7 | ||
|
|
ca5605620a | ||
|
|
8d0202113a | ||
|
|
f2e59226c0 | ||
|
|
951086e499 | ||
|
|
d3a26f9b4e | ||
|
|
e1a4478a06 | ||
|
|
ed8009883b | ||
|
|
4fd5dc0ee0 | ||
|
|
1bbb937d9d | ||
|
|
c1fb276937 | ||
|
|
3867d5d62e | ||
|
|
08ab513d4e | ||
|
|
a2eca4f029 | ||
|
|
3121494d4b | ||
|
|
92e81c3dbf | ||
|
|
2761a6dbb3 | ||
|
|
faf24ca7ec | ||
|
|
c5ce44f09d | ||
|
|
6969114675 | ||
|
|
1aba57e6bb | ||
|
|
e9785c8b3d | ||
|
|
03215d8906 |
7
.github/workflows/ci.yml
vendored
@@ -1,10 +1,10 @@
|
||||
name: Linter
|
||||
name: Simple CI
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
run-linter:
|
||||
name: Run Linter
|
||||
run-ci:
|
||||
name: Build Frontend
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -13,3 +13,4 @@ jobs:
|
||||
node-version: '12.x'
|
||||
- run: npm install
|
||||
- run: npm run lint
|
||||
- run: make
|
||||
|
||||
@@ -20,5 +20,5 @@
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
appVersion=20.1.0
|
||||
sdkVersion=2.6.0
|
||||
appVersion=20.2.0
|
||||
sdkVersion=2.8.0
|
||||
|
||||
@@ -1288,6 +1288,13 @@ export default {
|
||||
options.confID = `${locationURL.host}${locationURL.pathname}`;
|
||||
options.createVADProcessor = createRnnoiseProcessorPromise;
|
||||
|
||||
// Disable CallStats, if requessted.
|
||||
if (options.disableThirdPartyRequests) {
|
||||
delete options.callStatsID;
|
||||
delete options.callStatsSecret;
|
||||
delete options.getWiFiStatsMethod;
|
||||
}
|
||||
|
||||
return options;
|
||||
},
|
||||
|
||||
|
||||
20
config.js
@@ -110,7 +110,7 @@ var config = {
|
||||
|
||||
// w3c spec-compliant video constraints to use for video capture. Currently
|
||||
// used by browsers that return true from lib-jitsi-meet's
|
||||
// util#browser#usesNewGumFlow. The constraints are independency from
|
||||
// util#browser#usesNewGumFlow. The constraints are independent from
|
||||
// this config's resolution value. Defaults to requesting an ideal aspect
|
||||
// ratio of 16:9 with an ideal resolution of 720.
|
||||
// constraints: {
|
||||
@@ -264,11 +264,6 @@ var config = {
|
||||
// a call is hangup.
|
||||
// enableClosePage: false,
|
||||
|
||||
// Enabling pre join page will add an additional step before starting the meeting,
|
||||
// where the user can configure its devices and choose the way he
|
||||
// joins audio (by phone/or web).
|
||||
// prejoinPageEnabled: false,
|
||||
|
||||
// Disable hiding of remote thumbnails when in a 1-on-1 conference call.
|
||||
// disable1On1Mode: false,
|
||||
|
||||
@@ -349,9 +344,7 @@ var config = {
|
||||
stunServers: [
|
||||
|
||||
// { urls: 'stun:jitsi-meet.example.com:443' },
|
||||
{ urls: 'stun:stun.l.google.com:19302' },
|
||||
{ urls: 'stun:stun1.l.google.com:19302' },
|
||||
{ urls: 'stun:stun2.l.google.com:19302' }
|
||||
{ urls: 'stun:meet-jit-si-turnrelay.jitsi.net:443' }
|
||||
],
|
||||
|
||||
// Sets the ICE transport policy for the p2p connection. At the time
|
||||
@@ -466,6 +459,15 @@ var config = {
|
||||
// downloadAppsUrl: 'https://docs.example.com/our-apps.html'
|
||||
// },
|
||||
|
||||
// Options related to the remote participant menu.
|
||||
// remoteVideoMenu: {
|
||||
// // If set to true the 'Kick out' button will be disabled.
|
||||
// disableKick: true
|
||||
// },
|
||||
|
||||
// If set to true all muting operations of remote participants will be disabled.
|
||||
// disableRemoteMute: true,
|
||||
|
||||
// List of undocumented settings used in jitsi-meet
|
||||
/**
|
||||
_immediateReloadThreshold
|
||||
|
||||
@@ -48,19 +48,3 @@
|
||||
.toolbox-button-wth-dialog .eYJELv {
|
||||
max-height: initial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override @atlaskit/InlineDialog styling for the video preview
|
||||
*/
|
||||
.video-preview .eYJELv {
|
||||
outline: none;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override @atlaskit/InlineDialog styling for the audio preview
|
||||
*/
|
||||
.audio-preview .eYJELv {
|
||||
outline: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
.audio-preview {
|
||||
&-content {
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
max-height: 456px;
|
||||
overflow: auto;
|
||||
width: 328px;
|
||||
}
|
||||
|
||||
&-header {
|
||||
color: #fff;
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
|
||||
&-icon {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
&-text {
|
||||
font-weight: bold;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&-entry {
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
padding: 12px 0;
|
||||
margin-left: 48px;
|
||||
|
||||
&--selected {
|
||||
background: rgba(28,32,37,0.5);
|
||||
cursor: initial;
|
||||
margin-left: 0;
|
||||
padding-left: 21px;
|
||||
}
|
||||
|
||||
&-text {
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
display: inline-block;
|
||||
line-height: 24px;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 213px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
&-speaker {
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
.audio-preview-entry {
|
||||
background: rgba(255,255,255, 0.2);
|
||||
margin-left: 0;
|
||||
padding-left: 48px;
|
||||
|
||||
&--selected {
|
||||
padding-left: 21px;
|
||||
}
|
||||
}
|
||||
|
||||
.audio-preview-test-button {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.audio-preview-entry-text {
|
||||
max-width: 256px;
|
||||
}
|
||||
}
|
||||
|
||||
&-microphone {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
&-icon {
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
|
||||
& svg {
|
||||
fill: #1C2025;
|
||||
}
|
||||
|
||||
&--check {
|
||||
background: #31B76A;
|
||||
margin-right: 13px;
|
||||
}
|
||||
|
||||
&--exclamation {
|
||||
margin-left: 6px;
|
||||
& svg {
|
||||
fill: #E54B4B;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-test-button {
|
||||
display: none;
|
||||
background: #FFF;
|
||||
border: 1px solid #D1DBE8;
|
||||
border-radius: 3px;
|
||||
color: #1C2025;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
padding: 4px 16px;
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 8px;
|
||||
}
|
||||
|
||||
&-meter-mic {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 18px;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
.jitsi-icon {
|
||||
&.metr {
|
||||
display: inline-block;
|
||||
|
||||
& > svg {
|
||||
fill: #76CF9C;
|
||||
width: 38px;
|
||||
}
|
||||
}
|
||||
|
||||
&.metr--disabled {
|
||||
& > svg {
|
||||
fill: #5E6D7A;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.metr-l-0 {
|
||||
rect:first-child {
|
||||
fill: #279255;
|
||||
}
|
||||
}
|
||||
|
||||
@for $i from 1 through 7 {
|
||||
.metr-l-#{$i} {
|
||||
rect:nth-child(-n+#{$i+1}) {
|
||||
fill: #31B76A;
|
||||
}
|
||||
rect:first-child {
|
||||
fill: #279255;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
.settings-button {
|
||||
&-container {
|
||||
position: relative;
|
||||
|
||||
.toolbox-icon {
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #d1dbe8;
|
||||
justify-content: center;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
|
||||
&:hover {
|
||||
background-color: #daebfa;
|
||||
border: 1px solid #daebfa;
|
||||
}
|
||||
|
||||
&.toggled {
|
||||
background: #2a3a4b;
|
||||
border: 1px solid #5e6d7a;
|
||||
|
||||
svg {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #5e6d7a;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled, .disabled & {
|
||||
cursor: initial;
|
||||
color: #fff;
|
||||
background-color: #a4b8d1;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: #5e6d7a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-small-icon {
|
||||
background: #FFF;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
border-radius: 50%;
|
||||
bottom: 0;
|
||||
box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.25);
|
||||
cursor: pointer;
|
||||
height: 18px;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
right: 2px;
|
||||
width: 18px;
|
||||
|
||||
&:hover {
|
||||
background-color: #daebfa;
|
||||
}
|
||||
|
||||
&> svg {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
background-color: #a4b8d1;
|
||||
cursor: default;
|
||||
|
||||
&:hover {
|
||||
background-color: #a4b8d1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
.video-preview {
|
||||
&-entry {
|
||||
cursor: pointer;
|
||||
height: 135px;
|
||||
margin-bottom: 16px;
|
||||
position: relative;
|
||||
width: 240px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&--selected {
|
||||
border: 3px solid #31B76A;
|
||||
cursor: default;
|
||||
height: 129px;
|
||||
width: 234px;
|
||||
}
|
||||
}
|
||||
|
||||
&-video {
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-overlay {
|
||||
background: rgba(42, 58, 75, 0.6);
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&-error {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -86,9 +86,5 @@ $flagsImagePath: "../images/";
|
||||
@import 'avatar';
|
||||
@import 'promotional-footer';
|
||||
@import 'chrome-extension-banner';
|
||||
@import 'settings-button';
|
||||
@import 'meter';
|
||||
@import 'audio-preview';
|
||||
@import 'video-preview';
|
||||
|
||||
/* Modules END */
|
||||
|
||||
2
debian/jitsi-meet-prosody.postinst
vendored
@@ -136,7 +136,7 @@ case "$1" in
|
||||
echo -e "\nComponent \"internal.auth.$JVB_HOSTNAME\" \"muc\"" >> $PROSODY_HOST_CONFIG
|
||||
echo -e " storage = \"null\"" >> $PROSODY_HOST_CONFIG
|
||||
echo -e " modules_enabled = { \"ping\"; }" >> $PROSODY_HOST_CONFIG
|
||||
echo -e " admins = { \"focusUser@auth.jitmeet.example.com\", \"jvb@auth.jitmeet.example.com\" }" >> $PROSODY_HOST_CONFIG
|
||||
echo -e " admins = { \"$JICOFO_AUTH_USER@auth.$JVB_HOSTNAME\", \"jvb@auth.$JVB_HOSTNAME\" }" >> $PROSODY_HOST_CONFIG
|
||||
fi
|
||||
|
||||
if [ ! -f /var/lib/prosody/$JVB_HOSTNAME.crt ]; then
|
||||
|
||||
10
debian/jitsi-meet-prosody.postrm
vendored
@@ -36,13 +36,17 @@ case "$1" in
|
||||
rm -f /etc/prosody/conf.avail/$JVB_HOSTNAME.cfg.lua
|
||||
rm -f /etc/prosody/conf.d/$JVB_HOSTNAME.cfg.lua
|
||||
|
||||
JICOFO_AUTH_DOMAIN="auth.$JVB_HOSTNAME"
|
||||
# clean up generated certificates
|
||||
rm -f /etc/prosody/certs/$JVB_HOSTNAME.crt
|
||||
rm -f /etc/prosody/certs/$JVB_HOSTNAME.key
|
||||
rm -f /etc/prosody/certs/auth.$JVB_HOSTNAME.crt
|
||||
rm -f /etc/prosody/certs/auth.$JVB_HOSTNAME.key
|
||||
rm -rf /var/lib/prosody/auth.$JVB_HOSTNAME.*
|
||||
rm -f /etc/prosody/certs/$JICOFO_AUTH_DOMAIN.crt
|
||||
rm -f /etc/prosody/certs/$JICOFO_AUTH_DOMAIN.key
|
||||
rm -rf /var/lib/prosody/$JICOFO_AUTH_DOMAIN.*
|
||||
rm -rf /var/lib/prosody/$JVB_HOSTNAME.*
|
||||
|
||||
# clean created users
|
||||
rm -rf /var/lib/prosody/`echo $JICOFO_AUTH_DOMAIN | sed -e "s/\./%2e/g"`
|
||||
fi
|
||||
|
||||
# Clear the debconf variable
|
||||
|
||||
60
debian/jitsi-meet-turnserver.postrm
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
#!/bin/sh
|
||||
# postrm script for jitsi-meet-turnserver
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <postrm> `remove'
|
||||
# * <postrm> `purge'
|
||||
# * <old-postrm> `upgrade' <new-version>
|
||||
# * <new-postrm> `failed-upgrade' <old-version>
|
||||
# * <new-postrm> `abort-install'
|
||||
# * <new-postrm> `abort-install' <old-version>
|
||||
# * <new-postrm> `abort-upgrade' <old-version>
|
||||
# * <disappearer's-postrm> `disappear' <overwriter>
|
||||
# <overwriter-version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
|
||||
# Load debconf
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
|
||||
case "$1" in
|
||||
remove)
|
||||
if [ -x "/etc/init.d/nginx" ]; then
|
||||
invoke-rc.d nginx reload || true
|
||||
fi
|
||||
if [ -x "/etc/init.d/apache2" ]; then
|
||||
invoke-rc.d apache2 reload || true
|
||||
fi
|
||||
;;
|
||||
purge)
|
||||
if [ -x "/etc/init.d/nginx" ]; then
|
||||
invoke-rc.d nginx reload || true
|
||||
fi
|
||||
if [ -x "/etc/init.d/apache2" ]; then
|
||||
invoke-rc.d apache2 reload || true
|
||||
fi
|
||||
# Clear the debconf variable
|
||||
db_purge
|
||||
;;
|
||||
upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postrm called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
db_stop
|
||||
|
||||
exit 0
|
||||
2
debian/jitsi-meet-web-config.postinst
vendored
@@ -120,6 +120,8 @@ case "$1" in
|
||||
echo ""
|
||||
echo "You are using jetty to serve jitsi-meet, we are now upgrading you to use nginx!"
|
||||
echo ""
|
||||
echo "If you are using Let’s Encrypt certificates please re-run the script."
|
||||
echo ""
|
||||
echo "------------------------------------------------"
|
||||
echo ""
|
||||
|
||||
|
||||
1
debian/jitsi-meet-web.install
vendored
@@ -11,4 +11,5 @@ fonts /usr/share/jitsi-meet/
|
||||
images /usr/share/jitsi-meet/
|
||||
lang /usr/share/jitsi-meet/
|
||||
connection_optimization /usr/share/jitsi-meet/
|
||||
resources/robots.txt /usr/share/jitsi-meet/
|
||||
resources/*.sh /usr/share/jitsi-meet/scripts/
|
||||
|
||||
@@ -50,6 +50,8 @@ Component "conference.jitmeet.example.com" "muc"
|
||||
-- "token_verification";
|
||||
}
|
||||
admins = { "focusUser@auth.jitmeet.example.com" }
|
||||
muc_room_locking = false
|
||||
muc_room_default_public_jids = true
|
||||
|
||||
-- internal muc component
|
||||
Component "internal.auth.jitmeet.example.com" "muc"
|
||||
|
||||
@@ -225,6 +225,8 @@ npm install
|
||||
make
|
||||
```
|
||||
|
||||
_NOTE: When installing on older distributions keep in mind that you need Node.js >= 10 and npm >= 6._
|
||||
|
||||
Edit host names in `/srv/jitsi-meet/config.js` (see also the example config file):
|
||||
```
|
||||
var config = {
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
# Jitsi Meet quick install
|
||||
|
||||
This document describes the required steps for a quick Jitsi Meet installation on a Debian based GNU/Linux system. Debian 8 (Jessie) or later, and Ubuntu 14.04 or later are supported out-of-the-box.
|
||||
This guide helps you ___host your own Jitsi server___. If you want to have a video conference without setting up any infrastructure, use https://meet.jit.si instead.
|
||||
|
||||
Also note that a recent default Ubuntu installation has only the `main` repository enabled, and Jitsi Meet needs packages from `universe`. Check your `/etc/apt/sources.list` file, and if `universe` is not present refer to [Ubuntu's documentation](https://help.ubuntu.com/community/Repositories/Ubuntu) on how to enable it. (Usually it amounts to copying the `main` lines and changing to `universe`.)
|
||||
This document describes the required steps for a quick Jitsi Meet installation on a Debian based GNU/Linux system. Debian 9 (Stretch) or later, and Ubuntu 18.04 (Bionic Beaver) or later are supported out-of-the-box.
|
||||
|
||||
N.B.:
|
||||
On Ubuntu systems, Jitsi requires dependencies from Ubuntu's `universe` package repository. To ensure this is enabled, run `apt-add-repository universe` at the command-line.
|
||||
|
||||
a.) All commands are supposed to be run by root. If you are logged in as a regular user with sudo rights, please prepend ___sudo___ to each of the commands.
|
||||
|
||||
b.) You only need to do this if you want to ___host your own Jitsi server___. If you just want to have a video conference with someone, use https://meet.jit.si instead.
|
||||
_Note_: Many of the installation steps require elevated privileges. If you are logged in using a regular user account, you may need to temporarily increase your permissions (for example, by using `sudo` for individual commands).
|
||||
|
||||
## Basic Jitsi Meet install
|
||||
|
||||
@@ -22,30 +20,25 @@ Then add the same FQDN in the `/etc/hosts` file, associating it with the loopbac
|
||||
|
||||
Finally on the same machine test that you can ping the FQDN with: `ping "$(hostname)"`-
|
||||
|
||||
### Add the repository
|
||||
### Add the Jitsi package repository
|
||||
```sh
|
||||
echo 'deb https://download.jitsi.org stable/' >> /etc/apt/sources.list.d/jitsi-stable.list
|
||||
wget -qO - https://download.jitsi.org/jitsi-key.gpg.key | apt-key add -
|
||||
```
|
||||
|
||||
### Update the package lists
|
||||
|
||||
```sh
|
||||
apt-get update
|
||||
```
|
||||
|
||||
If you get an error:
|
||||
E: The method driver /usr/lib/apt/methods/https could not be found.
|
||||
run:
|
||||
```sh
|
||||
apt-get install apt-transport-https
|
||||
```
|
||||
|
||||
### Install Jitsi Meet
|
||||
|
||||
Note: The installer will check if [Nginx](https://nginx.org/) or [Apache](https://httpd.apache.org/) is present (in that order) and configure a virtualhost within the web server it finds to serve Jitsi Meet. If none of the above is found it then defaults to Nginx.
|
||||
_Note_: The installer will check if [Nginx](https://nginx.org/) or [Apache](https://httpd.apache.org/) is present (in that order) and configure a virtualhost within the web server it finds to serve Jitsi Meet. If none of the above is found it then defaults to Nginx.
|
||||
If you are already running Nginx on port 443 on the same machine you better skip the turnserver configuration as it will conflict with your current port 443, so use the command `apt install --no-install-recommends jitsi-meet`.
|
||||
|
||||
```sh
|
||||
# Ensure support is available for apt repositories served via HTTPS
|
||||
apt-get install apt-transport-https
|
||||
|
||||
# Retrieve the latest package versions across all repositories
|
||||
apt-get update
|
||||
|
||||
# Perform jitsi-meet installation
|
||||
apt-get -y install jitsi-meet
|
||||
```
|
||||
|
||||
@@ -53,10 +46,12 @@ During the installation, you will be asked to enter the hostname of the Jitsi Me
|
||||
|
||||
This hostname (or IP address) will be used for virtualhost configuration inside the Jitsi Meet and also, you and your correspondents will be using it to access the web conferences.
|
||||
|
||||
### Generate a Let's Encrypt certificate
|
||||
### Generate a Let's Encrypt certificate (optional, recommended)
|
||||
|
||||
In order to have encrypted communications, you need a [TLS certificate](https://en.wikipedia.org/wiki/Transport_Layer_Security). The easiest way is to use [Let's Encrypt](https://letsencrypt.org/).
|
||||
|
||||
_Note_: Jitsi Meet mobile apps *require* a valid certificate signed by a trusted [Certificate Authority](https://en.wikipedia.org/wiki/Certificate_authority) and will not be able to connect to your server if you choose a self-signed certificate.
|
||||
|
||||
Simply run the following in your shell:
|
||||
|
||||
```sh
|
||||
@@ -65,15 +60,15 @@ Simply run the following in your shell:
|
||||
|
||||
Note that this script uses the [HTTP-01 challenge type](https://letsencrypt.org/docs/challenge-types/) and thus your instance needs to be accessible from the public internet. If you want to use a different challenge type, don't use this script and instead choose ___I want to use my own certificate___ during jitsi-meet installation.
|
||||
|
||||
|
||||
#### Advanced configuration
|
||||
If the installation is on a machine [behind NAT](https://github.com/jitsi/jitsi-meet/blob/master/doc/faq.md) further configuration of jitsi-videobridge is needed in order for it to be accessible from outside.
|
||||
If the installation is on a machine [behind NAT](https://github.com/jitsi/jitsi-meet/blob/master/doc/faq.md) jitsi-videobridge should configure itself automatically on boot. If three way call does not work further configuration of jitsi-videobridge is needed in order for it to be accessible from outside.
|
||||
Provided that all required ports are routed (forwarded) to the machine that it runs on. By default these ports are (TCP/443 or TCP/4443 and UDP/10000).
|
||||
The following extra lines need to be added the file `/etc/jitsi/videobridge/sip-communicator.properties`:
|
||||
The following extra lines need to be added to the file `/etc/jitsi/videobridge/sip-communicator.properties`:
|
||||
```
|
||||
org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS=<Local.IP.Address>
|
||||
org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS=<Public.IP.Address>
|
||||
```
|
||||
And comment the existing `org.ice4j.ice.harvest.STUN_MAPPING_HARVESTER_ADDRESSES`.
|
||||
See [the documentation of ice4j](https://github.com/jitsi/ice4j/blob/master/doc/configuration.md)
|
||||
for details.
|
||||
|
||||
@@ -88,13 +83,15 @@ To load the values and check them look [here](#systemd-details) for details.
|
||||
|
||||
By default, anyone who has access to your jitsi instance will be able to start a conference: if your server is open to the world, anyone can have a chat with anyone else. If you want to limit the ability to start a conference to registered users, set up a "secure domain". Follow the instructions at https://github.com/jitsi/jicofo#secure-domain.
|
||||
|
||||
### Open a conference
|
||||
### Confirm that your installation is working
|
||||
|
||||
Launch a web browser (Chrome, Chromium or latest Opera) and enter in the URL bar the hostname (or IP address) you used in the previous step.
|
||||
Launch a web browser (Chrome, Chromium or latest Opera) and enter the hostname or IP address from the previous step into the address bar.
|
||||
|
||||
If you used a self-signed certificate (as opposed to using Let's Encrypt), your web browser will ask you to confirm that you trust the certificate.
|
||||
|
||||
Enjoy!
|
||||
You should see a web page prompting you to create a new meeting. Make sure that you can successfully create a meeting and that other participants are able to join the session.
|
||||
|
||||
If this all worked, then congratulations! You have an operational Jitsi conference service.
|
||||
|
||||
## Adding sip-gateway to Jitsi Meet
|
||||
|
||||
@@ -123,7 +120,7 @@ Enjoy!
|
||||
## Uninstall
|
||||
|
||||
```sh
|
||||
apt-get purge jigasi jitsi-meet jitsi-meet-web-config jitsi-meet-prosody jitsi-meet-turnserver jitsi-meet-web jicofo jitsi-videobridge
|
||||
apt-get purge jigasi jitsi-meet jitsi-meet-web-config jitsi-meet-prosody jitsi-meet-turnserver jitsi-meet-web jicofo jitsi-videobridge2
|
||||
```
|
||||
|
||||
Sometimes the following packages will fail to uninstall properly:
|
||||
@@ -136,8 +133,8 @@ When this happens, just run the uninstall command a second time and it should be
|
||||
The reason for the failure is that sometimes the uninstall script is faster than the process that stops the daemons. The second run of the uninstall command fixes this, as by then the jigasi or jitsi-videobridge daemons are already stopped.
|
||||
|
||||
#### Systemd details
|
||||
To reload the systemd changes on a running system execute `systemctl daemon-reload` and `service jitsi-videobridge restart`.
|
||||
To check the tasks part execute `service jitsi-videobridge status` and you should see `Tasks: XX (limit: 65000)`.
|
||||
To reload the systemd changes on a running system execute `systemctl daemon-reload` and `service jitsi-videobridge2 restart`.
|
||||
To check the tasks part execute `service jitsi-videobridge2 status` and you should see `Tasks: XX (limit: 65000)`.
|
||||
To check the files and process part execute ```cat /proc/`cat /var/run/jitsi-videobridge/jitsi-videobridge.pid`/limits``` and you should see:
|
||||
```
|
||||
Max processes 65000 65000 processes
|
||||
|
||||
@@ -31,7 +31,7 @@ var interfaceConfig = {
|
||||
APP_NAME: 'Jitsi Meet',
|
||||
NATIVE_APP_NAME: 'Jitsi Meet',
|
||||
PROVIDER_NAME: 'Jitsi',
|
||||
LANG_DETECTION: false, // Allow i18n to detect the system language
|
||||
LANG_DETECTION: true, // Allow i18n to detect the system language
|
||||
INVITATION_POWERED_BY: true,
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,10 +5,10 @@ require_relative '../node_modules/@react-native-community/cli-platform-ios/nativ
|
||||
target 'jitsi-meet' do
|
||||
project 'app/app.xcodeproj'
|
||||
|
||||
pod 'Crashlytics', '~> 3.12.0'
|
||||
pod 'Fabric', '~> 1.9.0'
|
||||
pod 'Firebase/Core', '~> 5.18.0'
|
||||
pod 'Firebase/DynamicLinks', '~> 5.18.0'
|
||||
pod 'Crashlytics', '~> 3.14.0'
|
||||
pod 'Fabric', '~> 1.10.2'
|
||||
pod 'Firebase/Core', '~> 6.16.0'
|
||||
pod 'Firebase/DynamicLinks', '~> 6.16.0'
|
||||
end
|
||||
|
||||
target 'JitsiMeet' do
|
||||
|
||||
169
ios/Podfile.lock
@@ -11,10 +11,10 @@ PODS:
|
||||
- CocoaLumberjack (3.5.3):
|
||||
- CocoaLumberjack/Core (= 3.5.3)
|
||||
- CocoaLumberjack/Core (3.5.3)
|
||||
- Crashlytics (3.12.0):
|
||||
- Fabric (~> 1.9.0)
|
||||
- Crashlytics (3.14.0):
|
||||
- Fabric (~> 1.10.2)
|
||||
- DoubleConversion (1.1.6)
|
||||
- Fabric (1.9.0)
|
||||
- Fabric (1.10.2)
|
||||
- FBLazyVector (0.61.5-jitsi.1)
|
||||
- FBReactNativeSpec (0.61.5-jitsi.1):
|
||||
- Folly (= 2018.10.22.00)
|
||||
@@ -23,34 +23,48 @@ PODS:
|
||||
- React-Core (= 0.61.5-jitsi.1)
|
||||
- React-jsi (= 0.61.5-jitsi.1)
|
||||
- ReactCommon/turbomodule/core (= 0.61.5-jitsi.1)
|
||||
- Firebase/Core (5.18.0):
|
||||
- Firebase/Core (6.16.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseAnalytics (= 5.7.0)
|
||||
- Firebase/CoreOnly (5.18.0):
|
||||
- FirebaseCore (= 5.3.1)
|
||||
- Firebase/DynamicLinks (5.18.0):
|
||||
- FirebaseAnalytics (= 6.2.2)
|
||||
- Firebase/CoreOnly (6.16.0):
|
||||
- FirebaseCore (= 6.6.1)
|
||||
- Firebase/DynamicLinks (6.16.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseDynamicLinks (= 3.4.1)
|
||||
- FirebaseAnalytics (5.7.0):
|
||||
- FirebaseCore (~> 5.3)
|
||||
- FirebaseInstanceID (~> 3.6)
|
||||
- GoogleAppMeasurement (= 5.7.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 5.2)
|
||||
- GoogleUtilities/MethodSwizzler (~> 5.2)
|
||||
- GoogleUtilities/Network (~> 5.2)
|
||||
- "GoogleUtilities/NSData+zlib (~> 5.2)"
|
||||
- nanopb (~> 0.3)
|
||||
- FirebaseAnalyticsInterop (1.2.0)
|
||||
- FirebaseCore (5.3.1):
|
||||
- GoogleUtilities/Logger (~> 5.2)
|
||||
- FirebaseDynamicLinks (3.4.1):
|
||||
- FirebaseAnalytics (~> 5.1)
|
||||
- FirebaseAnalyticsInterop (~> 1.0)
|
||||
- FirebaseCore (~> 5.2)
|
||||
- FirebaseInstanceID (3.7.0):
|
||||
- FirebaseCore (~> 5.2)
|
||||
- GoogleUtilities/Environment (~> 5.2)
|
||||
- GoogleUtilities/UserDefaults (~> 5.2)
|
||||
- FirebaseDynamicLinks (~> 4.0.6)
|
||||
- FirebaseAnalytics (6.2.2):
|
||||
- FirebaseCore (~> 6.6)
|
||||
- FirebaseInstanceID (~> 4.3)
|
||||
- GoogleAppMeasurement (= 6.2.2)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
||||
- GoogleUtilities/Network (~> 6.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
||||
- nanopb (= 0.3.9011)
|
||||
- FirebaseAnalyticsInterop (1.5.0)
|
||||
- FirebaseCore (6.6.1):
|
||||
- FirebaseCoreDiagnostics (~> 1.2)
|
||||
- FirebaseCoreDiagnosticsInterop (~> 1.2)
|
||||
- GoogleUtilities/Environment (~> 6.5)
|
||||
- GoogleUtilities/Logger (~> 6.5)
|
||||
- FirebaseCoreDiagnostics (1.2.2):
|
||||
- FirebaseCoreDiagnosticsInterop (~> 1.2)
|
||||
- GoogleDataTransportCCTSupport (~> 2.0)
|
||||
- GoogleUtilities/Environment (~> 6.5)
|
||||
- GoogleUtilities/Logger (~> 6.5)
|
||||
- nanopb (~> 0.3.901)
|
||||
- FirebaseCoreDiagnosticsInterop (1.2.0)
|
||||
- FirebaseDynamicLinks (4.0.8):
|
||||
- FirebaseAnalyticsInterop (~> 1.3)
|
||||
- FirebaseCore (~> 6.2)
|
||||
- FirebaseInstallations (1.1.1):
|
||||
- FirebaseCore (~> 6.6)
|
||||
- GoogleUtilities/UserDefaults (~> 6.5)
|
||||
- PromisesObjC (~> 1.2)
|
||||
- FirebaseInstanceID (4.3.2):
|
||||
- FirebaseCore (~> 6.6)
|
||||
- FirebaseInstallations (~> 1.0)
|
||||
- GoogleUtilities/Environment (~> 6.5)
|
||||
- GoogleUtilities/UserDefaults (~> 6.5)
|
||||
- Folly (2018.10.22.00):
|
||||
- boost-for-react-native
|
||||
- DoubleConversion
|
||||
@@ -61,33 +75,37 @@ PODS:
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- glog (0.3.5)
|
||||
- GoogleAppMeasurement (5.7.0):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 5.2)
|
||||
- GoogleUtilities/MethodSwizzler (~> 5.2)
|
||||
- GoogleUtilities/Network (~> 5.2)
|
||||
- "GoogleUtilities/NSData+zlib (~> 5.2)"
|
||||
- nanopb (~> 0.3)
|
||||
- GoogleAppMeasurement (6.2.2):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 6.0)
|
||||
- GoogleUtilities/MethodSwizzler (~> 6.0)
|
||||
- GoogleUtilities/Network (~> 6.0)
|
||||
- "GoogleUtilities/NSData+zlib (~> 6.0)"
|
||||
- nanopb (= 0.3.9011)
|
||||
- GoogleDataTransport (5.1.0)
|
||||
- GoogleDataTransportCCTSupport (2.0.1):
|
||||
- GoogleDataTransport (~> 5.1)
|
||||
- nanopb (~> 0.3.901)
|
||||
- GoogleSignIn (5.0.1):
|
||||
- AppAuth (~> 1.2)
|
||||
- GTMAppAuth (~> 1.0)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
- GoogleUtilities/AppDelegateSwizzler (5.4.1):
|
||||
- GoogleUtilities/AppDelegateSwizzler (6.5.2):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Environment (5.4.1)
|
||||
- GoogleUtilities/Logger (5.4.1):
|
||||
- GoogleUtilities/Environment (6.5.2)
|
||||
- GoogleUtilities/Logger (6.5.2):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/MethodSwizzler (5.4.1):
|
||||
- GoogleUtilities/MethodSwizzler (6.5.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network (5.4.1):
|
||||
- GoogleUtilities/Network (6.5.2):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (5.4.1)"
|
||||
- GoogleUtilities/Reachability (5.4.1):
|
||||
- "GoogleUtilities/NSData+zlib (6.5.2)"
|
||||
- GoogleUtilities/Reachability (6.5.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/UserDefaults (5.4.1):
|
||||
- GoogleUtilities/UserDefaults (6.5.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GTMAppAuth (1.0.0):
|
||||
- AppAuth/Core (~> 1.0)
|
||||
@@ -97,12 +115,13 @@ PODS:
|
||||
- GTMSessionFetcher/Core (1.2.2)
|
||||
- GTMSessionFetcher/Full (1.2.2):
|
||||
- GTMSessionFetcher/Core (= 1.2.2)
|
||||
- nanopb (0.3.901):
|
||||
- nanopb/decode (= 0.3.901)
|
||||
- nanopb/encode (= 0.3.901)
|
||||
- nanopb/decode (0.3.901)
|
||||
- nanopb/encode (0.3.901)
|
||||
- nanopb (0.3.9011):
|
||||
- nanopb/decode (= 0.3.9011)
|
||||
- nanopb/encode (= 0.3.9011)
|
||||
- nanopb/decode (0.3.9011)
|
||||
- nanopb/encode (0.3.9011)
|
||||
- ObjectiveDropboxOfficial (3.9.4)
|
||||
- PromisesObjC (1.2.8)
|
||||
- RCTRequired (0.61.5-jitsi.1)
|
||||
- RCTTypeSafety (0.61.5-jitsi.1):
|
||||
- FBLazyVector (= 0.61.5-jitsi.1)
|
||||
@@ -352,13 +371,13 @@ DEPENDENCIES:
|
||||
- Amplitude-iOS (~> 4.0.4)
|
||||
- BVLinearGradient (from `../node_modules/react-native-linear-gradient`)
|
||||
- CocoaLumberjack (~> 3.5.3)
|
||||
- Crashlytics (~> 3.12.0)
|
||||
- Crashlytics (~> 3.14.0)
|
||||
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||
- Fabric (~> 1.9.0)
|
||||
- Fabric (~> 1.10.2)
|
||||
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector/`)
|
||||
- FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec/`)
|
||||
- Firebase/Core (~> 5.18.0)
|
||||
- Firebase/DynamicLinks (~> 5.18.0)
|
||||
- Firebase/Core (~> 6.16.0)
|
||||
- Firebase/DynamicLinks (~> 6.16.0)
|
||||
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
|
||||
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
||||
- ObjectiveDropboxOfficial (~> 3.9.4)
|
||||
@@ -401,23 +420,29 @@ SPEC REPOS:
|
||||
- Amplitude-iOS
|
||||
- boost-for-react-native
|
||||
- CocoaLumberjack
|
||||
- ObjectiveDropboxOfficial
|
||||
trunk:
|
||||
- AppAuth
|
||||
- Crashlytics
|
||||
- Fabric
|
||||
- Firebase
|
||||
- FirebaseAnalytics
|
||||
- FirebaseAnalyticsInterop
|
||||
- FirebaseCore
|
||||
- FirebaseCoreDiagnostics
|
||||
- FirebaseCoreDiagnosticsInterop
|
||||
- FirebaseDynamicLinks
|
||||
- FirebaseInstallations
|
||||
- FirebaseInstanceID
|
||||
- GoogleAppMeasurement
|
||||
- GoogleUtilities
|
||||
- nanopb
|
||||
- ObjectiveDropboxOfficial
|
||||
trunk:
|
||||
- AppAuth
|
||||
- GoogleDataTransport
|
||||
- GoogleDataTransportCCTSupport
|
||||
- GoogleSignIn
|
||||
- GoogleUtilities
|
||||
- GTMAppAuth
|
||||
- GTMSessionFetcher
|
||||
- nanopb
|
||||
- PromisesObjC
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
BVLinearGradient:
|
||||
@@ -501,26 +526,32 @@ SPEC CHECKSUMS:
|
||||
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
|
||||
BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872
|
||||
CocoaLumberjack: 2f44e60eb91c176d471fdba43b9e3eae6a721947
|
||||
Crashlytics: 07fb167b1694128c1c9a5a5cc319b0e9c3ca0933
|
||||
Crashlytics: 540b7e5f5da5a042647227a5e3ac51d85eed06df
|
||||
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
|
||||
Fabric: f988e33c97f08930a413e08123064d2e5f68d655
|
||||
Fabric: 706c8b8098fff96c33c0db69cbf81f9c551d0d74
|
||||
FBLazyVector: 4a5251159a3ed05dc11cc8b74cf937869935814b
|
||||
FBReactNativeSpec: 6fa602a20993212cc9877a81838578ffb0008bc9
|
||||
Firebase: 02f3281965c075426141a0ce1277e9de6649cab9
|
||||
FirebaseAnalytics: 23851fe602c872130a2c5c55040b302120346cc2
|
||||
FirebaseAnalyticsInterop: efbe45c8385ec626e29f9525e5ebd38520dfb6c1
|
||||
FirebaseCore: 52f851b30e11360f1e67cf04b1edfebf0a47a2d3
|
||||
FirebaseDynamicLinks: f209c3caccd82102caa0e91d393e3ccc593501fd
|
||||
FirebaseInstanceID: bd6fc5a258884e206fd5c474ebe4f5b00e21770e
|
||||
Firebase: 497158b816d0a86fc31babbd05546fcd7e6083ff
|
||||
FirebaseAnalytics: cf95d3aab897612783020fbd98401d5366f135ee
|
||||
FirebaseAnalyticsInterop: 3f86269c38ae41f47afeb43ebf32a001f58fcdae
|
||||
FirebaseCore: 85064903ed6c28e47fec9c7bd149d94ba1b6b6e7
|
||||
FirebaseCoreDiagnostics: e9b4cd8ba60dee0f2d13347332e4b7898cca5b61
|
||||
FirebaseCoreDiagnosticsInterop: 296e2c5f5314500a850ad0b83e9e7c10b011a850
|
||||
FirebaseDynamicLinks: 417dc6dbb6013233c77558290d73296f429656a6
|
||||
FirebaseInstallations: acb3216eb9784d3b1d2d2d635ff74fa892cc0c44
|
||||
FirebaseInstanceID: 7ee0d6777013bb952f377b41965bf132b6a075be
|
||||
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
|
||||
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
|
||||
GoogleAppMeasurement: 6cf307834da065863f9faf4c0de0a936d81dd832
|
||||
GoogleAppMeasurement: d0560d915abf15e692e8538ba1d58442217b6aff
|
||||
GoogleDataTransport: b29a21d813e906014ca16c00897827e40e4a24ab
|
||||
GoogleDataTransportCCTSupport: 6f15a89b0ca35d6fa523e1f752ef818588885988
|
||||
GoogleSignIn: 3a51b9bb8e48b635fd7f4272cee06ca260345b86
|
||||
GoogleUtilities: 1e25823cbf46540b4284f6ef8e17b3a68ee12bbc
|
||||
GoogleUtilities: ad0f3b691c67909d03a3327cc205222ab8f42e0e
|
||||
GTMAppAuth: 4deac854479704f348309e7b66189e604cf5e01e
|
||||
GTMSessionFetcher: 61bb0f61a4cb560030f1222021178008a5727a23
|
||||
nanopb: 2901f78ea1b7b4015c860c2fdd1ea2fee1a18d48
|
||||
nanopb: 18003b5e52dab79db540fe93fe9579f399bd1ccd
|
||||
ObjectiveDropboxOfficial: a5afefc83f6467c42c45f2253f583f2ad1ffc701
|
||||
PromisesObjC: c119f3cd559f50b7ae681fa59dc1acd19173b7e6
|
||||
RCTRequired: f63dd90a89a60602acdd44c42e5d2645ca60ab79
|
||||
RCTTypeSafety: 24a3c6d55684046ed550b1d0ef083a9bf71c8bd4
|
||||
React: 71c5a51135f291c3b32c0b558e167b858ae50e84
|
||||
@@ -553,6 +584,6 @@ SPEC CHECKSUMS:
|
||||
RNWatch: 09738b339eceb66e4d80a2371633ca5fb380fa42
|
||||
Yoga: 7b4209fda2441f99d54dd6cf4c82b094409bb68f
|
||||
|
||||
PODFILE CHECKSUM: 0fdfa45ae809c9460c80be3e0d4bbb822fccc418
|
||||
PODFILE CHECKSUM: f615794fb9184757b00cd16e534824ba6ee2fc98
|
||||
|
||||
COCOAPODS: 1.8.4
|
||||
|
||||
@@ -293,7 +293,7 @@
|
||||
B35383AD1DDA0083008F406A /* Adjust embedded framework architectures */,
|
||||
0BB7DA181EC9E695007AAE98 /* Adjust ATS */,
|
||||
DEF4813D224925A2002AD03A /* Copy Google Plist file */,
|
||||
DEC2069321CBBD6900072F03 /* Setup Fabric */,
|
||||
DEC2069321CBBD6900072F03 /* Setup Crashlytics */,
|
||||
DE11877A21EE09640078D059 /* Setup Google reverse URL handler */,
|
||||
DE4F6D6E22005C0400DE699E /* Setup Dropbox */,
|
||||
0BEA5C491F7B8F73000D0AB4 /* Embed Watch Content */,
|
||||
@@ -492,7 +492,7 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "INFO_PLIST=\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"\nDROPBOX_KEY_FILE=\"$PROJECT_DIR/dropbox.key\"\n\nif [[ -f $DROPBOX_KEY_FILE ]]; then\n /usr/libexec/PlistBuddy -c \"Delete :LSApplicationQueriesSchemes\" $INFO_PLIST\n /usr/libexec/PlistBuddy -c \"Add :LSApplicationQueriesSchemes array\" $INFO_PLIST\n /usr/libexec/PlistBuddy -c \"Add :LSApplicationQueriesSchemes:0 string 'dbapi-2'\" $INFO_PLIST\n /usr/libexec/PlistBuddy -c \"Add :LSApplicationQueriesSchemes:1 string 'dbapi-8-emm'\" $INFO_PLIST\n\n DROPBOX_KEY=$(head -n 1 $DROPBOX_KEY_FILE)\n /usr/libexec/PlistBuddy -c \"Add :CFBundleURLTypes:2:CFBundleURLName string dropbox\" $INFO_PLIST\n /usr/libexec/PlistBuddy -c \"Add :CFBundleURLTypes:2:CFBundleURLSchemes array\" $INFO_PLIST\n /usr/libexec/PlistBuddy -c \"Add :CFBundleURLTypes:2:CFBundleURLSchemes:0 string $DROPBOX_KEY\" $INFO_PLIST\nfi\n";
|
||||
};
|
||||
DEC2069321CBBD6900072F03 /* Setup Fabric */ = {
|
||||
DEC2069321CBBD6900072F03 /* Setup Crashlytics */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -501,14 +501,14 @@
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Setup Fabric";
|
||||
name = "Setup Crashlytics";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "${PODS_ROOT}/Fabric/run\n";
|
||||
shellScript = "GOOGLE_PLIST=\"$PROJECT_DIR/GoogleService-Info.plist\"\n\nif [[ -f $GOOGLE_PLIST ]]; then\n if [ \"${CONFIGURATION}\" != \"Debug\" ]; then\n find \"${DWARF_DSYM_FOLDER_PATH}\" -name \"*.dSYM\" | xargs -I \\{\\} ${PODS_ROOT}/Fabric/upload-symbols -gsp $GOOGLE_PLIST -p ios \\{\\}\n fi\nfi\n";
|
||||
};
|
||||
DEF4813D224925A2002AD03A /* Copy Google Plist file */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>20.1.0</string>
|
||||
<string>20.2.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>20.1.0</string>
|
||||
<string>20.2.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>20.1.0</string>
|
||||
<string>20.2.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>CLKComplicationPrincipalClass</key>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.6.0</string>
|
||||
<string>2.8.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"en": "Englisch",
|
||||
"af": "",
|
||||
"az": "",
|
||||
"af": "Afrikaans",
|
||||
"az": "Aserbaidschanisch",
|
||||
"bg": "Bulgarisch",
|
||||
"cs": "",
|
||||
"cs": "Tschechisch",
|
||||
"de": "Deutsch",
|
||||
"el": "",
|
||||
"el": "Griechisch",
|
||||
"eo": "Esperanto",
|
||||
"es": "Spanisch",
|
||||
"fr": "Französisch",
|
||||
"hy": "Armenisch",
|
||||
"it": "Italienisch",
|
||||
"ja": "",
|
||||
"ko": "",
|
||||
"ja": "Japanisch",
|
||||
"ko": "Koreanisch",
|
||||
"nb": "Norwegisch (Bokmal)",
|
||||
"oc": "Okzitanisch",
|
||||
"pl": "Polnisch",
|
||||
@@ -22,6 +22,6 @@
|
||||
"sl": "Slowenisch",
|
||||
"sv": "Schwedisch",
|
||||
"tr": "Türkisch",
|
||||
"vi": "",
|
||||
"vi": "Vietnamesisch",
|
||||
"zhCN": "Chinesisch (China)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,5 +28,5 @@
|
||||
"tr": "Turco",
|
||||
"vi": "Vietnamita",
|
||||
"zhCN": "Chino (China)",
|
||||
"zhTW": "Chino (Taiwan)\"msgstr \""
|
||||
"zhTW": "Chino (Taiwan)"
|
||||
}
|
||||
@@ -28,5 +28,5 @@
|
||||
"tr": "Turco",
|
||||
"vi": "Vietnamita",
|
||||
"zhCN": "Chino (China)",
|
||||
"zhTW": "Chino (Taiwan)\"msgstr \""
|
||||
"zhTW": "Chino (Taiwan)"
|
||||
}
|
||||
33
lang/languages-et.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"en": "Inglise keel",
|
||||
"af": "Afrikaani keel",
|
||||
"bg": "Bulgaaria keel",
|
||||
"ca": "Katalaani keel",
|
||||
"cs": "Tšehhi keel",
|
||||
"de": "Saksa keel",
|
||||
"el": "Kreeka keel",
|
||||
"enGB": "Inglise keel (Ühendkuningriik)",
|
||||
"eo": "Esperanto keel",
|
||||
"es": "Hispaania keel",
|
||||
"esUS": "Hispaania keel (Ladina-Ameerika)",
|
||||
"et": "Eesti keel",
|
||||
"fi": "Soome keel",
|
||||
"fr": "Prantsuse keel",
|
||||
"frCA": "Prantsuse keel (Kanada)",
|
||||
"hr": "Horvaadi keel",
|
||||
"hu": "Ungari keel",
|
||||
"hy": "Armeenia keel",
|
||||
"it": "Itaalia keel",
|
||||
"ja": "Jaapani keel",
|
||||
"ko": "Korea keel",
|
||||
"nl": "Hollandi keel",
|
||||
"oc": "Oksitaani keel",
|
||||
"pl": "Poola keel",
|
||||
"ptBR": "Portigali keel (Brasiilia)",
|
||||
"ru": "Vene keel",
|
||||
"sv": "Roosi keel",
|
||||
"tr": "Türgi keel",
|
||||
"vi": "Vietnami keel",
|
||||
"zhCN": "Hiina keel (Hiina)",
|
||||
"zhTW": "Hiina keel (Tai)"
|
||||
}
|
||||
@@ -28,5 +28,5 @@
|
||||
"tr": "Török",
|
||||
"vi": "Vietnámi",
|
||||
"zhCN": "Kínai (Kína)",
|
||||
"zhTW": "Kínai (Tajvan)\"msgstr \""
|
||||
"zhTW": "Kínai (Tajvan)"
|
||||
}
|
||||
@@ -1,32 +1,32 @@
|
||||
{
|
||||
"en": "Angielski",
|
||||
"af": "Afrykanerski",
|
||||
"bg": "Bułgarski",
|
||||
"ca": "Kataloński",
|
||||
"cs": "Czeski",
|
||||
"de": "Niemiecki",
|
||||
"el": "Grecki",
|
||||
"enGB": "Angielski (Zjednoczone Królestwo)",
|
||||
"eo": "Esperanto",
|
||||
"es": "Hiszpański",
|
||||
"esUS": "Hiszpański (Ameryka Łacińska)",
|
||||
"fi": "Fiński",
|
||||
"fr": "Francuski",
|
||||
"frCA": "Francuski (kanadyjski)",
|
||||
"hr": "Chorwacki",
|
||||
"hu": "Węgierski",
|
||||
"hy": "Ormiański",
|
||||
"it": "Włoski",
|
||||
"ja": "Japoński",
|
||||
"ko": "Koreański",
|
||||
"nl": "Holenderski",
|
||||
"oc": "Oksytański",
|
||||
"pl": "Polski",
|
||||
"ptBR": "Portugalski (brazylijski)",
|
||||
"ru": "Rosyjski",
|
||||
"sv": "Szwedzki",
|
||||
"tr": "Turecki",
|
||||
"vi": "Wietnamski",
|
||||
"zhCN": "Chiński (Chiny)",
|
||||
"zhTW": "Chiński (Tajwan)\"msgstr \""
|
||||
"en": "angielski",
|
||||
"af": "afrykanerski",
|
||||
"bg": "bułgarski",
|
||||
"ca": "kataloński",
|
||||
"cs": "czeski",
|
||||
"de": "niemiecki",
|
||||
"el": "grecki",
|
||||
"enGB": "angielski (Zjednoczone Królestwo)",
|
||||
"eo": "esperanto",
|
||||
"es": "hiszpański",
|
||||
"esUS": "hiszpański (Ameryka Łacińska)",
|
||||
"fi": "fiński",
|
||||
"fr": "francuski",
|
||||
"frCA": "francuski (kanadyjski)",
|
||||
"hr": "chorwacki",
|
||||
"hu": "węgierski",
|
||||
"hy": "ormiański",
|
||||
"it": "włoski",
|
||||
"ja": "japoński",
|
||||
"ko": "koreański",
|
||||
"nl": "holenderski",
|
||||
"oc": "oksytański",
|
||||
"pl": "polski",
|
||||
"ptBR": "portugalski (brazylijski)",
|
||||
"ru": "rosyjski",
|
||||
"sv": "szwedzki",
|
||||
"tr": "turecki",
|
||||
"vi": "wietnamski",
|
||||
"zhCN": "chiński (Chiny)",
|
||||
"zhTW": "chiński (Tajwan)"
|
||||
}
|
||||
@@ -28,5 +28,5 @@
|
||||
"tr": "Turco",
|
||||
"vi": "Vietnamita",
|
||||
"zhCN": "Chinês (China)",
|
||||
"zhTW": "Chinês (Taiwan)\"msgstr \""
|
||||
"zhTW": "Chinês (Taiwan)"
|
||||
}
|
||||
@@ -28,5 +28,5 @@
|
||||
"tr": "Turkish",
|
||||
"vi": "Vietnamese",
|
||||
"zhCN": "中文 简体 (中国)",
|
||||
"zhTW": "中文 正體 (台灣)\"msgstr \""
|
||||
"zhTW": "中文 正體 (台灣)"
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
"eo": "Esperanto",
|
||||
"es": "Spanish",
|
||||
"esUS": "Spanish (Latin America)",
|
||||
"et": "Estonian",
|
||||
"fi": "Finnish",
|
||||
"fr": "French",
|
||||
"frCA": "French (Canadian)",
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"audioDevices": {
|
||||
"bluetooth": "Bluetooth",
|
||||
"headphones": "Kopfhörer",
|
||||
"phone": "Telefon",
|
||||
"phone": "Hörer",
|
||||
"speaker": "Lautsprecher",
|
||||
"none": "Keine Audiogeräte verfügbar"
|
||||
},
|
||||
@@ -29,19 +29,19 @@
|
||||
},
|
||||
"calendarSync": {
|
||||
"addMeetingURL": "Meeting-Link hinzufügen",
|
||||
"confirmAddLink": "Wollen Sie einen Jitsi-Link zu dieser Veranstaltung hinzufügen?",
|
||||
"confirmAddLink": "Wollen Sie einen Jitsi-Link zu diesem Termin hinzufügen?",
|
||||
"error": {
|
||||
"appConfiguration": "Kalenderintegration ist nicht richtig konfiguriert.",
|
||||
"generic": "Ein Fehler ist aufgetreten. Prüfen Sie Ihre Kalendereinstellungen oder versuchen Sie, den Kalender zu aktualisieren.",
|
||||
"notSignedIn": "Ein Fehler ist während der Authentifizierung zur Anzeige von Kalendererveranstaltungen aufgetreten. Prüfen Sie Ihre Kalendereinstellungen oder versuchen Sie, sich erneut anzumelden."
|
||||
"notSignedIn": "Ein Fehler ist während der Authentifizierung zur Anzeige von Kalenderertermine aufgetreten. Prüfen Sie Ihre Kalendereinstellungen oder versuchen Sie, sich erneut anzumelden."
|
||||
},
|
||||
"join": "Teilnehmen",
|
||||
"joinTooltip": "Am Meeting teilnehmen",
|
||||
"nextMeeting": "Nächste Konferenz",
|
||||
"noEvents": "Es sind keine bevorstehenden Veranstaltungen geplant.",
|
||||
"noEvents": "Es gibt keine bevorstehenden Termine.",
|
||||
"ongoingMeeting": "Laufendes Meeting",
|
||||
"permissionButton": "Einstellungen öffnen",
|
||||
"permissionMessage": "Die App benötigt Zugriff auf den Kalender, um die Termine und Konferenzen anzuzeigen.",
|
||||
"permissionMessage": "Die App benötigt Zugriff auf den Kalender, um Termine und Konferenzen anzuzeigen.",
|
||||
"refresh": "Kalender aktualisieren",
|
||||
"today": "Heute"
|
||||
},
|
||||
@@ -78,9 +78,9 @@
|
||||
"DISCONNECTING": "Verbindung wird getrennt",
|
||||
"ERROR": "Fehler",
|
||||
"FETCH_SESSION_ID": "Sitzungs-ID erhalten...",
|
||||
"GET_SESSION_ID_ERROR": "Session-ID-Fehler erhalten: {{code}}",
|
||||
"GET_SESSION_ID_ERROR": "Sitzungs-ID-Fehler erhalten: {{code}}",
|
||||
"GOT_SESSION_ID": "Sitzungs-ID erhalten... Beendet",
|
||||
"LOW_BANDWIDTH": "Video für {{displayName}} wurde ausgeschaltet um Bandbreite einzusparen"
|
||||
"LOW_BANDWIDTH": "Video für {{displayName}} wurde ausgeschaltet, um Bandbreite einzusparen"
|
||||
},
|
||||
"connectionindicator": {
|
||||
"address": "Adresse:",
|
||||
@@ -119,9 +119,9 @@
|
||||
"yesterday": "Gestern"
|
||||
},
|
||||
"deepLinking": {
|
||||
"appNotInstalled": "Sie benötigen die {{app}}-App, um der Konferenz auf dem Smartphone beizutreten.",
|
||||
"appNotInstalled": "Sie benötigen die „{{app}}“-App, um der Konferenz auf dem Smartphone beizutreten.",
|
||||
"description": "Nichts passiert? Wir haben versucht, die Konferenz in {{app}} zu öffnen. Versuchen Sie es erneut oder treten Sie der Konferenz in {{app}} im Web bei.",
|
||||
"descriptionWithoutWeb": "Ist nichts passiert? Wir haben versucht, Ihre Besprechung in der {{{app}}} Desktop-App zu starten.",
|
||||
"descriptionWithoutWeb": "Ist nichts passiert? Wir haben versucht, Ihre Besprechung in der „{{{app}}}“-Desktop-App zu starten.",
|
||||
"downloadApp": "App herunterladen",
|
||||
"launchWebButton": "Im Web öffnen",
|
||||
"openApp": "In der App fortfahren",
|
||||
@@ -153,13 +153,13 @@
|
||||
"Back": "Zurück",
|
||||
"cameraConstraintFailedError": "Ihre Kamera erfüllt die notwendigen Anforderungen nicht.",
|
||||
"cameraNotFoundError": "Kamera nicht gefunden.",
|
||||
"cameraNotSendingData": "Die Kamera ist nicht verfügbar. Bitte prüfen ob eine andere Applikation die Kamera verwendet, eine andere Kamera vom Einstellungs-Menu auswählen oder die Applikation neu laden.",
|
||||
"cameraNotSendingData": "Die Kamera ist nicht verfügbar. Bitte prüfen, ob eine andere Applikation die Kamera verwendet, eine andere Kamera vom Einstellungs-Menü auswählen oder die Applikation neu laden.",
|
||||
"cameraNotSendingDataTitle": "Zugriff auf Kamera nicht möglich",
|
||||
"cameraPermissionDeniedError": "Die Berechtigung zur Verwendung der Kamera wurde nicht erteilt. Sie können trotzdem an der Konferenz teilnehmen, aber die anderen Teilnehmer können Sie nicht sehen. Verwenden Sie die Kamera-Schaltfläche in der Adressleiste um die Berechtigungen zu erteilen.",
|
||||
"cameraUnknownError": "Die Kamera kann aus einem unbekannten Grund nicht verwendet werden.",
|
||||
"cameraUnsupportedResolutionError": "Die Kamera unterstützt die erforderliche Auflösung nicht.",
|
||||
"Cancel": "Abbrechen",
|
||||
"close": "Schliessen",
|
||||
"close": "Schließen",
|
||||
"conferenceDisconnectMsg": "Prüfen Sie allenfalls Ihre Netzwerkverbindung. Verbinde in {{seconds}} Sekunden...",
|
||||
"conferenceDisconnectTitle": "Ihre Verbindung ist getrennt worden.",
|
||||
"conferenceReloadMsg": "Wir versuchen das zu beheben. Verbinde in {{seconds}} Sekunden...",
|
||||
@@ -177,14 +177,14 @@
|
||||
"done": "Fertig",
|
||||
"enterDisplayName": "Bitte geben Sie hier Ihren Namen ein",
|
||||
"error": "Fehler",
|
||||
"externalInstallationMsg": "Die Bildschirmfreigabeerweiterung muss installiert werden.",
|
||||
"externalInstallationMsg": "Die Bildschirmfreigabe-Erweiterung muss installiert werden.",
|
||||
"externalInstallationTitle": "Erweiterung erforderlich",
|
||||
"goToStore": "Zum Store",
|
||||
"gracefulShutdown": "Der Dienst steht momentan wegen Wartungsarbeiten nicht zur Verfügung. Bitte versuchen Sie es später noch einmal.",
|
||||
"IamHost": "Ich bin der Organisator",
|
||||
"incorrectRoomLockPassword": "Falsches Passwort",
|
||||
"incorrectPassword": "Benutzername oder Passwort ungültig",
|
||||
"inlineInstallationMsg": "Die Bildschirmfreigabeerweiterung muss installiert werden.",
|
||||
"inlineInstallationMsg": "Die Bildschirmfreigabe-Erweiterung muss installiert werden.",
|
||||
"inlineInstallExtension": "Jetzt installieren",
|
||||
"internalError": "Oh! Es hat etwas nicht funktioniert. Der folgende Fehler ist aufgetreten: {{error}}",
|
||||
"internalErrorTitle": "Interner Fehler",
|
||||
@@ -193,9 +193,9 @@
|
||||
"kickParticipantDialog": "Wollen Sie diesen Teilnehmer wirklich entfernen?",
|
||||
"kickParticipantTitle": "Teilnehmer stummschalten?",
|
||||
"kickTitle": "Autsch! {{participantDisplayName}} hat Sie aus dem Meeting geworfen.",
|
||||
"liveStreaming": "Live-Streaming",
|
||||
"liveStreamingDisabledForGuestTooltip": "Gäste können kein Live-Streaming starten.",
|
||||
"liveStreamingDisabledTooltip": "Starten des Live-Streams deaktiviert.",
|
||||
"liveStreaming": "Livestreaming",
|
||||
"liveStreamingDisabledForGuestTooltip": "Gäste können kein Livestreaming starten.",
|
||||
"liveStreamingDisabledTooltip": "Starten des Livestreams deaktiviert.",
|
||||
"lockMessage": "Die Konferenz konnte nicht gesperrt werden.",
|
||||
"lockRoom": "Meeting $t(lockRoomPasswordUppercase) hinzufügen",
|
||||
"lockTitle": "Sperren fehlgeschlagen",
|
||||
@@ -210,7 +210,7 @@
|
||||
"micPermissionDeniedError": "Die Berechtigung zur Verwendung des Mikrofons wurde nicht erteilt. Sie können trotzdem an der Konferenz teilnehmen, aber die anderen Teilnehmer können Sie nicht hören. Verwenden Sie die Kamera-Schaltfläche in der Adressleiste um die Berechtigungen zu erteilen.",
|
||||
"micUnknownError": "Das Mikrofon kann aus einem unbekannten Grund nicht verwendet werden.",
|
||||
"muteEveryoneElseDialog": "Einmal stummgeschaltet, können Sie deren Stummschaltung nicht mehr beenden, aber sie können ihre Stummschaltung jederzeit selbst beenden.",
|
||||
"muteEveryoneElseTitle": "Alle ausser {{whom}} stummschaten?",
|
||||
"muteEveryoneElseTitle": "Alle außer {{whom}} stummschaten?",
|
||||
"muteEveryoneDialog": "Wollen Sie wirklich alle stummschalten? Sie können deren Stummschaltung nicht mehr beenden, aber sie können ihre Stummschaltung jederzeit selbst beenden.",
|
||||
"muteEveryoneTitle": "Alle stummschalten?",
|
||||
"muteEveryoneSelf": "sich selbst",
|
||||
@@ -224,7 +224,7 @@
|
||||
"passwordNotSupported": "Setzen eines Konferenz-Passworts ist nicht unterstützt",
|
||||
"passwordNotSupportedTitle": "$t(lockRoomPasswordUppercase) nicht unterstützt",
|
||||
"passwordRequired": "$t(lockRoomPasswordUppercase) erforderlich",
|
||||
"popupError": "Ihr Browser blockiert Pop-ups von dieser Website. Bitte aktivieren Sie Popups in den Sicherheitseinstellungen des Browsers und versuchen Sie es erneut.",
|
||||
"popupError": "Ihr Browser blockiert Pop-ups von dieser Website. Bitte aktivieren Sie Pop-ups in den Sicherheitseinstellungen des Browsers und versuchen Sie es erneut.",
|
||||
"popupErrorTitle": "Pop-up blockiert",
|
||||
"recording": "Aufnahme",
|
||||
"recordingDisabledForGuestTooltip": "Gäste können keine Aufzeichnungen starten.",
|
||||
@@ -233,7 +233,7 @@
|
||||
"remoteControlAllowedMessage": "{{user}} hat die Anfrage zur Fernsteuerung angenommen.",
|
||||
"remoteControlDeniedMessage": "{{user}} hat die Anfrage zur Fernsteuerung verweigert.",
|
||||
"remoteControlErrorMessage": "Beim Anfordern der Fernsteuerungsberechtigung von {{user}} ist ein Fehler aufgetreten.",
|
||||
"remoteControlRequestMessage": "Möchten Sie {{user}} erlauben den Computer fernzusteuern?",
|
||||
"remoteControlRequestMessage": "Möchten Sie {{user}} erlauben, den Computer fernzusteuern?",
|
||||
"remoteControlShareScreenWarning": "Achtung, wenn Sie die Anfrage genehmigen, starten Sie die Bildschirmfreigabe!",
|
||||
"remoteControlStopMessage": "Die Fernsteuerung wurde beendet.",
|
||||
"remoteControlTitle": "Fernsteuerung",
|
||||
@@ -264,21 +264,21 @@
|
||||
"startLiveStreaming": "Einen Livestream starten",
|
||||
"startRecording": "Aufnahme starten",
|
||||
"startRemoteControlErrorMessage": "Beim Versuch die Fernsteuerung zu starten ist ein Fehler aufgetreten.",
|
||||
"stopLiveStreaming": "Live-Streaming stoppen",
|
||||
"stopLiveStreaming": "Livestreaming stoppen",
|
||||
"stopRecording": "Aufnahme stoppen",
|
||||
"stopRecordingWarning": "Sind Sie sicher, dass Sie die Aufnahme stoppen möchten?",
|
||||
"stopStreamingWarning": "Sind Sie sicher, dass Sie das Live-Streaming stoppen möchten?",
|
||||
"stopStreamingWarning": "Sind Sie sicher, dass Sie das Livestreaming stoppen möchten?",
|
||||
"streamKey": "Name/Schlüssel für den Stream",
|
||||
"Submit": "OK",
|
||||
"thankYou": "Danke für die Verwendung von {{appName}}!",
|
||||
"token": "Token",
|
||||
"tokenAuthFailed": "Sie sind nicht berechtigt dieser Konferenz beizutreten.",
|
||||
"tokenAuthFailed": "Sie sind nicht berechtigt, dieser Konferenz beizutreten.",
|
||||
"tokenAuthFailedTitle": "Authentifizierung fehlgeschlagen",
|
||||
"transcribing": "Wird transkribiert",
|
||||
"unlockRoom": "Meeting $t(lockRoomPassword) entfernen",
|
||||
"userPassword": "Benutzerpasswort",
|
||||
"WaitForHostMsg": "Die Konferenz <b>{{room}}</b> wurde noch nicht gestartet. Wenn Sie der Veranstalter sind, authentifizieren Sie sich. Warten Sie andernfalls, bis der Veranstalter erscheint.",
|
||||
"WaitForHostMsgWOk": "Die Konferenz <b>{{room}}</b> wurde noch nicht gestartet. Wenn Sie der Veranstalter sind, drücken Sie zum Authentifizieren auf OK. Warten Sie andernfalls, bis der Veranstalter erscheint.",
|
||||
"WaitForHostMsg": "Die Konferenz <b>{{room}}</b> wurde noch nicht gestartet. Wenn Sie der Organisator sind, authentifizieren Sie sich. Warten Sie andernfalls, bis der Veranstalter erscheint.",
|
||||
"WaitForHostMsgWOk": "Die Konferenz <b>{{room}}</b> wurde noch nicht gestartet. Wenn Sie der Organisator sind, drücken Sie zum Authentifizieren auf OK. Warten Sie andernfalls, bis der Veranstalter erscheint.",
|
||||
"WaitingForHost": "Warten auf den Organisator...",
|
||||
"Yes": "Ja",
|
||||
"yourEntireScreen": "Ganzer Bildschirm"
|
||||
@@ -347,7 +347,7 @@
|
||||
"msg": "Es ist ein Fehler aufgetreten.",
|
||||
"retry": "Erneut versuchen",
|
||||
"support": "Support",
|
||||
"supportMsg": "Wenn der Fehler erneut auftritt, bitte kontaktieren sie"
|
||||
"supportMsg": "Wenn der Fehler erneut auftritt, bitte kontaktieren Sie"
|
||||
},
|
||||
"keyboardShortcuts": {
|
||||
"focusLocal": "Lokales Video fokussieren",
|
||||
@@ -356,7 +356,7 @@
|
||||
"keyboardShortcuts": "Tastenkürzel",
|
||||
"localRecording": "Lokale Aufzeichnungssteuerelemente ein- oder ausblenden",
|
||||
"mute": "Stummschaltung aktivieren oder deaktivieren",
|
||||
"pushToTalk": "Drücken, um zu sprechen",
|
||||
"pushToTalk": "Push-to-Talk (Sprechtaste)",
|
||||
"raiseHand": "Hand erheben",
|
||||
"showSpeakerStats": "Statistiken für Sprecher anzeigen",
|
||||
"toggleChat": "Chat öffnen oder schließen",
|
||||
@@ -370,31 +370,31 @@
|
||||
"busy": "Es werden Resourcen zum Streamen bereitgestellt. Bitte in ein paar Minuten erneut versuchen.",
|
||||
"busyTitle": "Alle Streaming-Instanzen sind in Gebrauch",
|
||||
"changeSignIn": "Konten wechseln.",
|
||||
"choose": "Live stream auswählen",
|
||||
"choose": "Livestream auswählen",
|
||||
"chooseCTA": "Streaming-Option auswählen. Sie sind aktuell als {{email}} angemeldet.",
|
||||
"enterStreamKey": "Name/Schlüssel für den YouTube Livestream hier eingeben.",
|
||||
"error": "Das Live-Streaming ist fehlgeschlagen. Bitte versuchen Sie es erneut.",
|
||||
"errorAPI": "Beim abrufen der YouTube Livestreams ist ein Fehler aufgetreten. Bitte versuchen Sie sich erneut anzumelden.",
|
||||
"errorLiveStreamNotEnabled": "Live-Streaming ist für {{email}} nicht aktiviert. Aktivieren Sie das Live-Streaming oder melden Sie sich bei einem Konto mit aktiviertem Live-Streaming an.",
|
||||
"expandedOff": "Live-Streaming wurde angehalten",
|
||||
"enterStreamKey": "Name/Schlüssel für den YouTube-Livestream hier eingeben.",
|
||||
"error": "Das Livestreaming ist fehlgeschlagen. Bitte versuchen Sie es erneut.",
|
||||
"errorAPI": "Beim Abrufen der YouTube-Livestreams ist ein Fehler aufgetreten. Bitte versuchen Sie, sich erneut anzumelden.",
|
||||
"errorLiveStreamNotEnabled": "Livestreaming ist für {{email}} nicht aktiviert. Aktivieren Sie das Livestreaming oder melden Sie sich bei einem Konto mit aktiviertem Livestreaming an.",
|
||||
"expandedOff": "Livestreaming wurde angehalten",
|
||||
"expandedOn": "Das Meeting wird momentan an YouTube gestreamt.",
|
||||
"expandedPending": "Live-Streaming wird gestartet...",
|
||||
"failedToStart": "Live-Streaming konnte nicht gestartet werden",
|
||||
"getStreamKeyManually": "Wir waren nicht in der Lage, Live-Streams abzurufen. Versuchen Sie, Ihren Live-Stream-Schlüssel von YouTube zu erhalten.",
|
||||
"invalidStreamKey": "Der Live-Stream-Schlüssel ist u. U. falsch.",
|
||||
"off": "Live-Streaming gestoppt",
|
||||
"offBy": "{{name}} stoppte das Live-Streaming",
|
||||
"on": "Live-Streaming",
|
||||
"onBy": "{{name}} startete das Live-Streaming",
|
||||
"pending": "Live-Stream wird gestartet...",
|
||||
"serviceName": "Live Streaming-Dienst",
|
||||
"expandedPending": "Livestreaming wird gestartet...",
|
||||
"failedToStart": "Livestreaming konnte nicht gestartet werden",
|
||||
"getStreamKeyManually": "Wir waren nicht in der Lage, Livestreams abzurufen. Versuchen Sie, Ihren Livestream-Schlüssel von YouTube zu erhalten.",
|
||||
"invalidStreamKey": "Der Livestream-Schlüssel ist u. U. falsch.",
|
||||
"off": "Livestreaming gestoppt",
|
||||
"offBy": "{{name}} stoppte das Livestreaming",
|
||||
"on": "Livestreaming",
|
||||
"onBy": "{{name}} startete das Livestreaming",
|
||||
"pending": "Livestream wird gestartet...",
|
||||
"serviceName": "Livestreaming-Dienst",
|
||||
"signedInAs": "Sie sind derzeit angemeldet als:",
|
||||
"signIn": "Mit Google anmelden",
|
||||
"signInCTA": "Anmelden oder den Name/Schlüssel des YouTube Livestreams eingeben.",
|
||||
"signInCTA": "Anmelden oder den Namen/Schlüssel des YouTube-Livestreams eingeben.",
|
||||
"signOut": "Abmelden",
|
||||
"start": "Einen Livestream starten",
|
||||
"streamIdHelp": "Was ist das?",
|
||||
"unavailableTitle": "Live-Streaming nicht verfügbar"
|
||||
"unavailableTitle": "Livestreaming nicht verfügbar"
|
||||
},
|
||||
"localRecording": {
|
||||
"clientState": {
|
||||
@@ -413,7 +413,7 @@
|
||||
"messages": {
|
||||
"engaged": "Lokale Aufzeichnung ist aktiviert",
|
||||
"finished": "Aufzeichnung der Sitzung {{token}} ist beendet. Senden Sie die aufgezeichnete Datei an den Moderator.",
|
||||
"finishedModerator": "Aufzeichnung der Sitzung {{token}} ist beendet. Die Aufzeichnung der lokalen Verlaufs wurde gespeichert. Bitten Sie die anderen Teilnehmer, ihre Aufzeichnungen zu übermitteln.",
|
||||
"finishedModerator": "Aufzeichnung der Sitzung {{token}} ist beendet. Die Aufzeichnung des lokalen Verlaufs wurde gespeichert. Bitten Sie die anderen Teilnehmer, ihre Aufzeichnungen zu übermitteln.",
|
||||
"notModerator": "Sie sind nicht der Moderator. Sie können die lokale Aufzeichnung nicht starten oder stoppen."
|
||||
},
|
||||
"moderator": "Moderator",
|
||||
@@ -451,8 +451,8 @@
|
||||
"raisedHand": "{{name}} möchte sprechen.",
|
||||
"somebody": "Jemand",
|
||||
"startSilentTitle": "Sie sind ohne Audioausgabe beigetreten!",
|
||||
"startSilentDescription": "Treten Sie dem Meeting noch einma bei, um Ihr Audio zu aktivieren",
|
||||
"suboptimalExperienceDescription": "Tut uns leid, aber die Konferenz wird mit {{appName}} kein grossartiges Erlebnis. Wir versuchen immer die Situation zu verbessern, bis dahin empfehlen wir aber die Verwendung einer der <a href=\"static/recommendedBrowsers.html\" target=\"_blank\">vollständig unterstützen Browser</a>.",
|
||||
"startSilentDescription": "Treten Sie dem Meeting noch einmal bei, um Ihr Audio zu aktivieren",
|
||||
"suboptimalExperienceDescription": "Tut uns leid, aber die Konferenz wird mit {{appName}} kein großartiges Erlebnis. Wir versuchen immer die Situation zu verbessern, bis dahin empfehlen wir aber die Verwendung einer der <a href=\"static/recommendedBrowsers.html\" target=\"_blank\">vollständig unterstützen Browser</a>.",
|
||||
"suboptimalExperienceTitle": "Browserwarnung",
|
||||
"unmute": "Stummschaltung aufheben",
|
||||
"newDeviceCameraTitle": "Neue Kamera erkannt",
|
||||
@@ -479,7 +479,7 @@
|
||||
"profile": {
|
||||
"setDisplayNameLabel": "Anzeigename festlegen",
|
||||
"setEmailInput": "E-Mail eingeben",
|
||||
"setEmailLabel": "E-Mail Adresse für Gravatar",
|
||||
"setEmailLabel": "E-Mail-Adresse für Gravatar",
|
||||
"title": "Profil"
|
||||
},
|
||||
"raisedHand": "Ich möchte sprechen",
|
||||
@@ -487,7 +487,7 @@
|
||||
"authDropboxText": "In Dropbox hochladen",
|
||||
"availableSpace": "Verfügbarer Speicherplatz: {{spaceLeft}} MB (ca. {{duration}} Minuten Aufzeichnung)",
|
||||
"beta": "BETA",
|
||||
"busy": "Es werden Resourcen für eine Aufnahme bereitgestellt. Bitte in ein paar Minuten erneut versuchen.",
|
||||
"busy": "Es werden Ressourcen für eine Aufnahme bereitgestellt. Bitte in ein paar Minuten erneut versuchen.",
|
||||
"busyTitle": "Alle Aufnahme-Instanzen sind in Gebrauch",
|
||||
"error": "Die Aufzeichnung ist fehlgeschlagen. Bitte versuchen Sie es erneut.",
|
||||
"expandedOff": "Aufzeichnung wurde gestoppt",
|
||||
@@ -511,14 +511,14 @@
|
||||
"unavailableTitle": "Aufnahme nicht verfügbar"
|
||||
},
|
||||
"sectionList": {
|
||||
"pullToRefresh": "Ziehen um zu aktualisieren"
|
||||
"pullToRefresh": "Ziehen, um zu aktualisieren"
|
||||
},
|
||||
"settings": {
|
||||
"calendar": {
|
||||
"about": "Die Kalenderintegration von {{appName}} wird verwendet, um ein sicheres Zugreifen auf Ihren Kalender und Auslesen der bevorstehenden Veranstaltungen zu ermöglichen.",
|
||||
"about": "Die Kalenderintegration von {{appName}} wird verwendet, um ein sicheres Zugreifen auf Ihren Kalender und Auslesen der bevorstehenden Termine zu ermöglichen.",
|
||||
"disconnect": "Getrennt",
|
||||
"microsoftSignIn": "Mit Microsoft anmelden",
|
||||
"signedIn": "Momentan wird auf Kalenderveranstaltungen von {{email}} zugegriffen. Klicken Sie auf die folgende Schaltfläche „Trennen“, um den Zugriff auf die Kalenderveranstaltungen zu stoppen.",
|
||||
"signedIn": "Momentan wird auf Kalendertermine von {{email}} zugegriffen. Klicken Sie auf die folgende Schaltfläche „Trennen“, um den Zugriff auf die Kalendertermine zu stoppen.",
|
||||
"title": "Kalender"
|
||||
},
|
||||
"devices": "Geräte",
|
||||
@@ -540,7 +540,7 @@
|
||||
"advanced": "Erweitert",
|
||||
"alertOk": "OK",
|
||||
"alertTitle": "Warnung",
|
||||
"alertURLText": "Die angegebene Server URL ist ungültig",
|
||||
"alertURLText": "Die angegebene Server-URL ist ungültig",
|
||||
"buildInfoSection": "Build-Informationen",
|
||||
"conferenceSection": "Konferenz",
|
||||
"disableCallIntegration": "Native Anrufintegration deaktivieren",
|
||||
@@ -549,7 +549,7 @@
|
||||
"email": "E-Mail",
|
||||
"header": "Einstellungen",
|
||||
"profileSection": "Profil",
|
||||
"serverURL": "Server URL",
|
||||
"serverURL": "Server-URL",
|
||||
"showAdvanced": "Erweiterte Einstellungen anzeigen",
|
||||
"startWithAudioMuted": "Stumm beitreten",
|
||||
"startWithVideoMuted": "Ohne Video beitreten",
|
||||
@@ -574,20 +574,20 @@
|
||||
},
|
||||
"suspendedoverlay": {
|
||||
"rejoinKeyTitle": "Erneut teilnehmen",
|
||||
"text": "<i>Erneut teilnehmen</i> Schaltfläche betätigen um erneut zu verbinden.",
|
||||
"title": "Die Konferenz wurde unterbrochen, weil der Standbymodus aktiviert wurde."
|
||||
"text": "„<i>Erneut teilnehmen</i>“-Schaltfläche betätigen, um erneut zu verbinden.",
|
||||
"title": "Die Konferenz wurde unterbrochen, weil der Standby-Modus aktiviert wurde."
|
||||
},
|
||||
"toolbar": {
|
||||
"accessibilityLabel": {
|
||||
"audioOnly": "Nur Audio ein-/ausschalten",
|
||||
"audioOnly": "„Nur Audio“ ein-/ausschalten",
|
||||
"audioRoute": "Audiogerät auswählen",
|
||||
"callQuality": "Qualitätseinstellungen",
|
||||
"cc": "Untertitel ein-/ausschalten",
|
||||
"chat": "Chatfenster ein-/ausblenden",
|
||||
"document": "Geteiltes Dokument schliessen",
|
||||
"document": "Geteiltes Dokument schließen",
|
||||
"download": "Unsere Apps herunterladen",
|
||||
"feedback": "Feedback hinterlassen",
|
||||
"fullScreen": "Vollbildschirm ein-/ausblenden",
|
||||
"fullScreen": "Vollbildmodus aktivieren/deaktivieren",
|
||||
"hangup": "Anruf beenden",
|
||||
"help": "Hilfe",
|
||||
"invite": "Teilnehmer einladen",
|
||||
@@ -623,9 +623,9 @@
|
||||
"audioRoute": "Audiogerät auswählen",
|
||||
"authenticate": "Anmelden",
|
||||
"callQuality": "Qualitätseinstellungen",
|
||||
"chat": "Chat öffnen / schliessen",
|
||||
"chat": "Chat öffnen / schließen",
|
||||
"closeChat": "Chat schließen",
|
||||
"documentClose": "Geteiltes Dokument schliessen",
|
||||
"documentClose": "Geteiltes Dokument schließen",
|
||||
"documentOpen": "Geteiltes Dokument öffnen",
|
||||
"download": "Unsere Apps herunterladen",
|
||||
"enterFullScreen": "Vollbildmodus",
|
||||
@@ -649,7 +649,7 @@
|
||||
"noAudioSignalDialInDesc": "Sie können sich auch über die Einwahlnummer einwählen:",
|
||||
"noAudioSignalDialInLinkDesc" : "Einwahlnummern:",
|
||||
"noisyAudioInputTitle": "Ihr Mikrofon scheint lärmintensiv zu sein!",
|
||||
"noisyAudioInputDesc": "Es klingt, als ob Ihr Mikrofon Geräusche macht. Bitte überlegen Sie, ob Sie das Gerät stummschalten oder austauschen wollen.",
|
||||
"noisyAudioInputDesc": "Es klingt, als ob Ihr Mikrofon Störgeräusche verursacht. Bitte überlegen Sie, ob Sie das Gerät stummschalten oder austauschen wollen.",
|
||||
"openChat": "Chat öffnen",
|
||||
"pip": "Bild-in-Bild-Modus einschalten",
|
||||
"privateMessage": "Private Nachricht senden",
|
||||
@@ -666,7 +666,7 @@
|
||||
"stopScreenSharing": "Bildschirmfreigabe stoppen",
|
||||
"stopSubtitles": "Untertitel ausschalten",
|
||||
"stopSharedVideo": "YouTube-Video stoppen",
|
||||
"talkWhileMutedPopup": "Versuchen sie zu sprechen? Ihr Mikrofon ist stummgeschaltet.",
|
||||
"talkWhileMutedPopup": "Versuchen Sie zu sprechen? Ihr Mikrofon ist stummgeschaltet.",
|
||||
"tileViewToggle": "Kachelansicht ein-/ausschalten",
|
||||
"toggleCamera": "Kamera wechseln",
|
||||
"videomute": "Kamera starten / stoppen",
|
||||
@@ -710,19 +710,19 @@
|
||||
"videoStatus": {
|
||||
"audioOnly": "AUD",
|
||||
"audioOnlyExpanded": "Sie befinden sich im Modus „Nur Audio“. Dieser Modus benötigt weniger Bandbreite, Sie sehen jedoch nicht die Videos der anderen.",
|
||||
"callQuality": "Video-Qualität",
|
||||
"callQuality": "Videoqualität",
|
||||
"hd": "HD",
|
||||
"hdTooltip": "Video wird in hoher Auflösung angezeigt",
|
||||
"highDefinition": "Hohe Auflösung",
|
||||
"labelTooiltipNoVideo": "Kein Video",
|
||||
"labelTooltipAudioOnly": "Nur-Audio Modus aktiv",
|
||||
"labelTooltipAudioOnly": "„Nur Audio“-Modus aktiv",
|
||||
"ld": "LD",
|
||||
"ldTooltip": "Video wird in niedriger Auflösung angezeigt",
|
||||
"lowDefinition": "Niedrige Auflösung",
|
||||
"onlyAudioAvailable": "Nur Ton",
|
||||
"onlyAudioSupported": "In diesem Browser wird nur Audio unterstützt.",
|
||||
"p2pEnabled": "Ende-zu-Ende aktiviert",
|
||||
"p2pVideoQualityDescription": "Im Ende-zu-Ende-Modus kann die empfangene Videoqualität nur zwischen hoch und Nur-Audio umgeschaltet werden. Andere Einstellungen werden erst beim Verlassen des Ende-zu-Ende-Modus berücksichtigt.",
|
||||
"p2pVideoQualityDescription": "Im Ende-zu-Ende-Modus kann die empfangene Videoqualität nur zwischen „Hoch“ und „Nur Audio“ umgeschaltet werden. Andere Einstellungen werden erst beim Verlassen des Ende-zu-Ende-Modus berücksichtigt.",
|
||||
"recHighDefinitionOnly": "Hohe Qualität wird bevorzugt.",
|
||||
"sd": "SD",
|
||||
"sdTooltip": "Video wird in Standardauflösung angezeigt",
|
||||
@@ -745,9 +745,9 @@
|
||||
"join": "Zum Teilnehmen tippen",
|
||||
"roomname": "Konferenzname eingeben"
|
||||
},
|
||||
"appDescription": "Auf geht's! Beginne eine Videokonferenz mit dem ganzen Team. Oder besser noch, lade alle ein, die du kennst. {{app}} ist eine vollständig verschlüsselte, aus 100% Open-Source-Software bestehende Videokonferenzlösung, die du den ganzen Tag kostenlos verwenden kannst — ohne Registrierung.",
|
||||
"appDescription": "Auf geht's! Starten Sie eine Videokonferenz mit dem ganzen Team. Oder besser noch: Laden Sie alle ein, die Sie kennen. {{app}} ist eine vollständig verschlüsselte, aus 100% Open-Source-Software bestehende Videokonferenzlösung, die Sie den ganzen Tag kostenlos verwenden können — ohne Registrierung.",
|
||||
"audioVideoSwitch": {
|
||||
"audio": "Sprache",
|
||||
"audio": "Audio",
|
||||
"video": "Video"
|
||||
},
|
||||
"calendar": "Kalender",
|
||||
@@ -759,15 +759,15 @@
|
||||
"goSmall": "Los",
|
||||
"join": "Beitreten",
|
||||
"info": "Informationen",
|
||||
"privacy": "Privatsphäre",
|
||||
"privacy": "Datenschutz",
|
||||
"recentList": "Letzte",
|
||||
"recentListDelete": "Löschen",
|
||||
"recentListEmpty": "Die Liste „Letzte“ ist momentan leer. Chatten Sie mit Ihrem Team. Sie finden all Ihre letzten Meetings hier.",
|
||||
"reducedUIText": "Willkommen bei {{app}}!",
|
||||
"roomname": "Konferenzname eingeben",
|
||||
"roomnameHint": "Name oder URL der Konferenz, der Sie beitreten möchten. Sie können einen Namen erfinden, er muss nur den anderen Teilnehmern übermittelt werden, damit sie der gleichen Konferenz beitreten.",
|
||||
"sendFeedback": "Senden Sie uns Ihr Feedback",
|
||||
"terms": "Bedingungen",
|
||||
"roomnameHint": "Name oder URL der Konferenz, der Sie beitreten möchten. Sie können einen Namen erfinden, er muss nur den anderen Teilnehmern übermittelt werden, damit diese der gleichen Konferenz beitreten.",
|
||||
"sendFeedback": "Feedback senden",
|
||||
"terms": "AGB",
|
||||
"title": "Sichere, mit umfassenden Funktionen ausgestattete und vollkommen kostenlose Videokonferenzen"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"addPeople": {
|
||||
"add": "Invitar",
|
||||
"countryNotSupported": "Aun no contamos con soporte a este destino.",
|
||||
"countryNotSupported": "Aún no contamos con soporte a este destino.",
|
||||
"countryReminder": "¿Llamando fuera de los Estados Unidos? ¡Por favor, asegúrese de empezar con el código de país!",
|
||||
"disabled": "No puede invitar a otras personas.",
|
||||
"failedToAdd": "Error al agregar participantes",
|
||||
@@ -31,7 +31,7 @@
|
||||
"addMeetingURL": "Agregar un vínculo a la reunión",
|
||||
"confirmAddLink": "¿Quiere añadir un enlace de Jitsi a este evento?",
|
||||
"error": {
|
||||
"appConfiguration": "La integración del calendario no se está configurada correctamente",
|
||||
"appConfiguration": "La integración del calendario no está configurada correctamente",
|
||||
"generic": "Se ha producido un error. Compruebe la configuración del calendario o pruebe a recargarlo",
|
||||
"notSignedIn": "Se ha producido un error de autenticación para ver los eventos del calendario. Compruebe la configuración del calendario e intente iniciar sesión de nuevo"
|
||||
},
|
||||
@@ -713,7 +713,7 @@
|
||||
"standardDefinition": "Definición estándar"
|
||||
},
|
||||
"videothumbnail": {
|
||||
"domute": "Control de escritorio remoto",
|
||||
"domute": "Silenciar",
|
||||
"flip": "Voltear",
|
||||
"kick": "Expulsar",
|
||||
"moderator": "Moderador",
|
||||
@@ -753,4 +753,4 @@
|
||||
"terms": "Términos",
|
||||
"title": "Seguro, lleno de funcionalidades y videoconferencias completamente gratuitas"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"addMeetingURL": "Agregar un vínculo a la reunión",
|
||||
"confirmAddLink": "¿Quiere añadir un enlace de Jitsi a este evento?",
|
||||
"error": {
|
||||
"appConfiguration": "La integración del calendario no se está configurada correctamente",
|
||||
"appConfiguration": "La integración del calendario no está configurada correctamente",
|
||||
"generic": "Se ha producido un error. Compruebe la configuración del calendario o pruebe cargarlo nuevamente.",
|
||||
"notSignedIn": "Se ha producido un error de autenticación para ver los eventos del calendario. Compruebe la configuración del calendario e intente iniciar sesión de nuevo"
|
||||
},
|
||||
@@ -60,9 +60,9 @@
|
||||
"you": "usted"
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
"installExtensionText": "",
|
||||
"buttonText": "",
|
||||
"dontShowAgain": ""
|
||||
"installExtensionText": "Instalar la extensión para Google Calendar y la integración con Office 365",
|
||||
"buttonText": "Instalar extensión de Chrome",
|
||||
"dontShowAgain": "No mostrar nuevamente"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
"joiningRoom": "Conectando a su reunión..."
|
||||
@@ -77,7 +77,11 @@
|
||||
"DISCONNECTED": "Desconectado",
|
||||
"DISCONNECTING": "Desconectando",
|
||||
"ERROR": "Error",
|
||||
"RECONNECTING": "Ocurrió un problema en la red. Reconectando..."
|
||||
"RECONNECTING": "Ocurrió un problema en la red. Reconectando...",
|
||||
"FETCH_SESSION_ID": "Obteniendo session-id...",
|
||||
"GET_SESSION_ID_ERROR": "Obtener session-id error: {{code}}",
|
||||
"GOT_SESSION_ID": "Obteniendo session-id... Listo",
|
||||
"LOW_BANDWIDTH": "Video para {{displayName}} ha sido deshabilitado para economizar ancho de banda"
|
||||
},
|
||||
"connectionindicator": {
|
||||
"address": "Dirección:",
|
||||
@@ -125,9 +129,9 @@
|
||||
"tryAgainButton": "Intentar de nuevo en el escritorio"
|
||||
},
|
||||
"defaultLink": "p.ej. {{url}}",
|
||||
"defaultNickname": "p. ej. Jane Pink",
|
||||
"defaultNickname": "p. ej. Juan Pérez",
|
||||
"deviceError": {
|
||||
"cameraError": "Error al acceder a su cámara",
|
||||
"cameraError": "Error al acceder a tu cámara",
|
||||
"cameraPermission": "Error de permisos en la cámara",
|
||||
"microphoneError": "Error al acceder a tu micrófono",
|
||||
"microphonePermission": "Error al obtener permiso del micrófono"
|
||||
@@ -187,7 +191,7 @@
|
||||
"kickMessage": "Puede ponerse en contacto con {{participantDisplayName}} para obtener más detalles.",
|
||||
"kickParticipantButton": "Expulsar",
|
||||
"kickParticipantDialog": "¿Seguro que quiere expulsar a este participante?",
|
||||
"kickParticipantTitle": "Sacar este participante ?",
|
||||
"kickParticipantTitle": "¿Sacar este participante?",
|
||||
"kickTitle": "¡Ay! {{participantDisplayName}} te expulsó de la reunión",
|
||||
"liveStreaming": "Transmisión en vivo",
|
||||
"liveStreamingDisabledForGuestTooltip": "Los invitados no pueden iniciar la transmisión en vivo.",
|
||||
@@ -205,10 +209,16 @@
|
||||
"micNotSendingDataTitle": "Su micrófono está silenciado en la configuración de su sistema",
|
||||
"micPermissionDeniedError": "No ha otorgado permisos para usar su micrófono. Puede unirse a la conferencia, pero no lo podrán escuchar. Utilice el botón en la barra de dirección para solucionar esto.",
|
||||
"micUnknownError": "No se puede usar su micrófono por motivos desconocidos.",
|
||||
"muteEveryoneElseDialog": "Una vez silenciados, No podrás quitarles el modo en silencio, pero ellos pueden quitárselo en cualquier momento.",
|
||||
"muteEveryoneElseTitle": "¿Silenciar a todos excepto a {{whom}}?",
|
||||
"muteEveryoneDialog": "¿Está seguro que quiere silenciar a todos? No podrás quitarles el modo en silencio, pero ellos pueden quitárselo en cualquier momento.",
|
||||
"muteEveryoneTitle": "¿Silenciar a todos?",
|
||||
"muteEveryoneSelf": "Usted mismo",
|
||||
"muteEveryoneStartMuted": "Todos inician silenciados desde ahora",
|
||||
"muteParticipantBody": "No podrás quitarles el modo en silencio, pero ellos pueden quitárselo en cualquier momento.",
|
||||
"muteParticipantButton": "Silenciar",
|
||||
"muteParticipantDialog": "¿Seguro que quiere silenciar a este participante? No podrá revertir esta acción, pero el participante podrá hacerlo en cualquier momento",
|
||||
"muteParticipantTitle": "Silenciar este participante ?",
|
||||
"muteParticipantTitle": "Silenciar este participante?",
|
||||
"Ok": "Aceptar",
|
||||
"passwordLabel": "$t(lockRoomPasswordUppercase)",
|
||||
"passwordNotSupported": "No se soporta $t(lockRoomPassword) en la reunión",
|
||||
@@ -220,9 +230,9 @@
|
||||
"recordingDisabledForGuestTooltip": "Los invitados no pueden iniciar grabaciones.",
|
||||
"recordingDisabledTooltip": "Inicio de grabación desactivado.",
|
||||
"rejoinNow": "Reunirse ahora",
|
||||
"remoteControlAllowedMessage": "{{user}} ha aceptado tu solicitud de control remoto!",
|
||||
"remoteControlDeniedMessage": "{{user}} ha rechazado tu solicitud de control remoto!",
|
||||
"remoteControlErrorMessage": "Ha ocurrido un error tratando de solicitar permiso de control remoto de {{user}}!",
|
||||
"remoteControlAllowedMessage": "¡{{user}} ha aceptado tu solicitud de control remoto!",
|
||||
"remoteControlDeniedMessage": "¡{{user}} ha rechazado tu solicitud de control remoto!",
|
||||
"remoteControlErrorMessage": "¡Ha ocurrido un error tratando de solicitar permiso de control remoto de {{user}}!",
|
||||
"remoteControlRequestMessage": "¿Permitirá que {{user}} controle remotamente su escritorio?",
|
||||
"remoteControlShareScreenWarning": "¡Tenga en cuenta que si presiona \"Permitir\" usted compartirá su pantalla!",
|
||||
"remoteControlStopMessage": "¡La sesión de control remoto ha finalizado!",
|
||||
@@ -242,7 +252,7 @@
|
||||
"sendPrivateMessage": "Recientemente ha recibido un mensaje privado. ¿Pretendía responder a eso en privado, o quería enviar su mensaje al grupo?",
|
||||
"sendPrivateMessageCancel": "Enviar al grupo",
|
||||
"sendPrivateMessageOk": "Enviar en privado",
|
||||
"sendPrivateMessageTitle": "Enviar en privado ?",
|
||||
"sendPrivateMessageTitle": "¿Enviar en privado?",
|
||||
"serviceUnavailable": "Servicio no disponible",
|
||||
"sessTerminated": "Llamada finalizada",
|
||||
"Share": "Compartir",
|
||||
@@ -310,7 +320,7 @@
|
||||
"genericError": "Epa, algo salió mal.",
|
||||
"inviteLiveStream": "Para ver la transmisión en vivo de esta reunión, haz clic en este enlace: {{url}}",
|
||||
"invitePhone": "Para unirse por teléfono, marque: {{number}},,{{conferenceID}}#\n",
|
||||
"invitePhoneAlternatives": "Busca un número de acceso diferente?\nConsulte los números de acceso a las reuniones : {{url}}\n\n\nSi también marca a través de un teléfono externo, ingrese sin conectarse al audio: {{silentUrl}}",
|
||||
"invitePhoneAlternatives": "¿Busca un número de acceso diferente?\nConsulte los números de acceso a las reuniones : {{url}}\n\n\nSi también marca a través de un teléfono externo, ingrese sin conectarse al audio: {{silentUrl}}",
|
||||
"inviteURLFirstPartGeneral": "Estás invitado a unirte a una reunión.",
|
||||
"inviteURLFirstPartPersonal": "{{name}} lo invita a una reunión.\n",
|
||||
"inviteURLSecondPart": "\nIngrese a la reunión :\n{{url}}\n",
|
||||
@@ -434,13 +444,13 @@
|
||||
"moderator": "Derechos de moderador otorgados.",
|
||||
"muted": "Has iniciado la conversación con el silencio activado.",
|
||||
"mutedTitle": "Tienes el silencio activado.",
|
||||
"mutedRemotelyTitle": "Su micrófono fue silenciado por {{participantDisplayName}}!",
|
||||
"mutedRemotelyTitle": "¡Su micrófono fue silenciado por {{participantDisplayName}}!",
|
||||
"mutedRemotelyDescription": "Siempre puede reactivar sur micrófono cuando esté listo para hablar. Desactívelo de nuevo cuando termine para mantener el ruido al mínimo en la reunión.",
|
||||
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) retirada por otro participante",
|
||||
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) agregada por otro participante",
|
||||
"raisedHand": "{{name}} desea hablar.",
|
||||
"somebody": "Alguien",
|
||||
"startSilentTitle": "Ingresó sin salida de audio!",
|
||||
"startSilentTitle": "¡Ingresó sin salida de audio!",
|
||||
"startSilentDescription": "Vuelva a ingresar para activar el audio",
|
||||
"suboptimalBrowserWarning": "Nos tememos que su experiencia de reunión no será tan buena aquí. Estamos buscando formas de mejorar esto, pero hasta entonces, por favor, intente utilizar uno de los <a href='static/recommendedBrowsers.html' target='_blank'>navegadores soportados</a>.",
|
||||
"suboptimalExperienceTitle": "Advertencia del navegador",
|
||||
@@ -464,7 +474,7 @@
|
||||
"initializingCall": "Inicializando llamada...",
|
||||
"invited": "Invitado",
|
||||
"rejected": "Rechazado",
|
||||
"ringing": "Sonando..."
|
||||
"ringing": "Timbrando..."
|
||||
},
|
||||
"profile": {
|
||||
"setDisplayNameLabel": "Configurar su nombre para mostrar",
|
||||
@@ -546,7 +556,7 @@
|
||||
"version": "Versión"
|
||||
},
|
||||
"share": {
|
||||
"dialInfoText": "\n\n=====\n\nDesea llamar desde su teléfono ?\n\n{{defaultDialInNumber}}La lista de números disponibles para la reunión está disponible aquí : \n{{dialInfoPageUrl}}",
|
||||
"dialInfoText": "\n\n=====\n\n¿Desea llamar desde su teléfono?\n\n{{defaultDialInNumber}}La lista de números disponibles para la reunión está disponible aquí : \n{{dialInfoPageUrl}}",
|
||||
"mainText": "Haz clic en el enlace siguiente para unirte a la reunión:\n{{roomUrl}}"
|
||||
},
|
||||
"speaker": "Altavoz",
|
||||
@@ -560,7 +570,7 @@
|
||||
},
|
||||
"startupoverlay": {
|
||||
"policyText": " ",
|
||||
"title": "{{app}} tiene que usar el micrófono y la cámara."
|
||||
"title": "{{app}} necesita usar el micrófono y la cámara."
|
||||
},
|
||||
"suspendedoverlay": {
|
||||
"rejoinKeyTitle": "Volver a unirme",
|
||||
@@ -586,7 +596,9 @@
|
||||
"lockRoom": "Alternar contraseña de reunión",
|
||||
"moreActions": "Alternar menú de más acciones",
|
||||
"moreActionsMenu": "Menú de más acciones",
|
||||
"moreOptions": "Mostrar más opciones",
|
||||
"mute": "Alternar silenciar audio",
|
||||
"muteEveryone": "Silenciar a todos",
|
||||
"pip": "Alternar modo de imagen en imagen",
|
||||
"privateMessage": "Enviar un mensaje privado",
|
||||
"profile": "Editar el perfil",
|
||||
@@ -628,12 +640,16 @@
|
||||
"logout": "Cierre de sesión",
|
||||
"lowerYourHand": "Bajar la mano",
|
||||
"moreActions": "Más acciones",
|
||||
"moreOptions": "Más opciones",
|
||||
"mute": "Silenciar/anular silencio",
|
||||
"noAudioSignalTitle": "No hay ninguna entrada que provenga de su micrófono!",
|
||||
"muteEveryone": "Silenciar a todos",
|
||||
"noAudioSignalTitle": "¡No hay ninguna entrada que provenga de su micrófono!",
|
||||
"noAudioSignalDesc": "Si no lo silenció intencionalmente desde la configuración del sistema o el hardware, considere la posibilidad de cambiar el dispositivo.",
|
||||
"noAudioSignalDescSuggestion": "Si no lo silenció intencionalmente desde la configuración del sistema o el hardware, considere utilizar el siguiente dispositivo:",
|
||||
"noisyAudioInputTitle": "",
|
||||
"noisyAudioInputDesc": "",
|
||||
"noAudioSignalDialInDesc": "Usted puede además llamar usando:",
|
||||
"noAudioSignalDialInLinkDesc" : "Números de llamada",
|
||||
"noisyAudioInputTitle": "Su micrófono parece estar ruidoso",
|
||||
"noisyAudioInputDesc": "Parece que su micráfono está haciendo ruido, por favor considere silenciarlo o cambiar de dispositivo.",
|
||||
"openChat": "Abrir chat",
|
||||
"pip": "Introducir modo de imagen en imagen",
|
||||
"privateMessage": "Enviar un mensaje privado",
|
||||
@@ -714,6 +730,7 @@
|
||||
},
|
||||
"videothumbnail": {
|
||||
"domute": "Silenciar",
|
||||
"domuteOthers": "Silenciar a todos",
|
||||
"flip": "Dar vuelta",
|
||||
"kick": "Echar",
|
||||
"moderator": "Moderador",
|
||||
@@ -746,11 +763,11 @@
|
||||
"recentList": "Reciente",
|
||||
"recentListDelete": "Eliminar",
|
||||
"recentListEmpty": "Su lista reciente está actualmente vacía. Abra una sesión de chat con su equipo y encontrará todas sus reuniones recientes aquí.",
|
||||
"reducedUIText": "BIenvenid@ a {{app}}!",
|
||||
"reducedUIText": "¡Bienvenid@ a {{app}}!",
|
||||
"roomname": "Introducir nombre de sala",
|
||||
"roomnameHint": "Introduce el nombre o la dirección URL de la sala a la que deseas unirte. Puedes inventar un nombre, simplemente infórmaselo a las personas con las que te reunirás para que introduzcan el mismo nombre.",
|
||||
"sendFeedback": "Enviar comentario",
|
||||
"terms": "Términos",
|
||||
"title": "Conferencias en video seguras, con gran variedad de funciones y completamente gratuitas"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
777
lang/main-et.json
Normal file
@@ -0,0 +1,777 @@
|
||||
{
|
||||
"addPeople": {
|
||||
"add": "Lisa",
|
||||
"countryNotSupported": "Valitud riik ei ole toetatud.",
|
||||
"countryReminder": "Veendu, et suunakood oleks lisatud.",
|
||||
"disabled": "Uusi kontakte ei saa kõnesse lisada.",
|
||||
"failedToAdd": "Uue kontakti kõnesse lisamine ebaõnnestus",
|
||||
"footerText": "Numbri valimine on keelatud.",
|
||||
"loading": "Kontaktide otsimine...",
|
||||
"loadingNumber": "Telefoninumbri kontrollimine...",
|
||||
"loadingPeople": "Kontaktide otsimine kõnesse lisamiseks...",
|
||||
"noResults": "Vasteid ei leitud",
|
||||
"noValidNumbers": "Sisesta telefoninumber",
|
||||
"searchNumbers": "Lisa telefoninumber",
|
||||
"searchPeople": "Kontaktide otsimine",
|
||||
"searchPeopleAndNumbers": "Otsi kontakti või lisa telefoninumber",
|
||||
"telephone": "Telefoninumber: {{number}}",
|
||||
"title": "Lisa kontakte kõnesse"
|
||||
},
|
||||
"audioDevices": {
|
||||
"bluetooth": "Bluetooth",
|
||||
"headphones": "Kõrvaklapid",
|
||||
"phone": "Telefon",
|
||||
"speaker": "Kõlar",
|
||||
"none": "Heli vahendid pole kättesaadavad"
|
||||
},
|
||||
"audioOnly": {
|
||||
"audioOnly": "Ainult heli"
|
||||
},
|
||||
"calendarSync": {
|
||||
"addMeetingURL": "Lisa kõne link",
|
||||
"confirmAddLink": "Kas soovid käesolevale kõnele lisada lingi?",
|
||||
"error": {
|
||||
"appConfiguration": "Ühendus kalendriga ei ole õigesti seadistatud.",
|
||||
"generic": "Viga! Palun kontrolli kalendri seadistusi või värskenda kalendrit.",
|
||||
"notSignedIn": "Viga kalendri autentimisel! Palun kontrolli kalendri seadistusi ja logi uuesti sisse."
|
||||
},
|
||||
"join": "Liitu",
|
||||
"joinTooltip": "Liitu kõnega",
|
||||
"nextMeeting": "järgmine kõne",
|
||||
"noEvents": "Uusi kõnesid pole planeeritud..",
|
||||
"ongoingMeeting": "aktiivne kõne",
|
||||
"permissionButton": "Ava seadistused",
|
||||
"permissionMessage": "Planeeritud kõne nägemiseks on vajalik kalendri ligipääsuõigus.",
|
||||
"refresh": "Värskenda kalendrit",
|
||||
"today": "Täna"
|
||||
},
|
||||
"chat": {
|
||||
"error": "Viga: sõnumi \"{{originalText}}\" saatmine ebaõnnestus. Põhjus: {{error}}",
|
||||
"fieldPlaceHolder": "Sisesta oma sõnum siia",
|
||||
"messagebox": "Sisesta sõnum",
|
||||
"messageTo": "Privaatsõnum kasutajale {{recipient}}",
|
||||
"noMessagesMessage": "Kirjavahetust pole veel alustatud. Alusta kirjavahetust siin!",
|
||||
"nickname": {
|
||||
"popover": "Sisesta nimi",
|
||||
"title": "Sisesta nimi, et kõnega alustada"
|
||||
},
|
||||
"privateNotice": "Privaatsõnum kasutajale {{recipient}}",
|
||||
"title": "Kõne",
|
||||
"you": "you"
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
"installExtensionText": "Paigalda Google Kalendri laiendus ja Office 365 integratsioon",
|
||||
"buttonText": "Paigalda Chrome'i laiendus",
|
||||
"dontShowAgain": "Ära rohkem näita"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
"joiningRoom": "Kõnega ühendamine..."
|
||||
},
|
||||
"connection": {
|
||||
"ATTACHED": "Ühendatud",
|
||||
"AUTHENTICATING": "Autentimine...",
|
||||
"AUTHFAIL": "Autentimine ebaõnnestus",
|
||||
"CONNECTED": "Ühendatud",
|
||||
"CONNECTING": "Ühendamine...",
|
||||
"CONNFAIL": "Ühendamine ebaõnnestus",
|
||||
"DISCONNECTED": "Ühendus katkestatud",
|
||||
"DISCONNECTING": "Ühenduse katkestamine...",
|
||||
"ERROR": "Viga",
|
||||
"FETCH_SESSION_ID": "Sessiooni-ID püüdmine...",
|
||||
"GET_SESSION_ID_ERROR": "Sessiooni-ID püüdmisel tekkis viga: {{code}}",
|
||||
"GOT_SESSION_ID": "Sessiooni-ID püüdmine... Tehtud",
|
||||
"LOW_BANDWIDTH": "Kasutaja {{displayName}} video on ülekandekiiruse parandamiseks välja lülitatud"
|
||||
},
|
||||
"connectionindicator": {
|
||||
"address": "Aadress:",
|
||||
"bandwidth": "Eeldatav ülekandekiirus:",
|
||||
"bitrate": "Andmeedastuskiirus:",
|
||||
"bridgeCount": "Serverite arv: ",
|
||||
"connectedTo": "Ühendatud:",
|
||||
"e2e_rtt": "E2E RTT:",
|
||||
"framerate": "Ekraani eraldusvõime:",
|
||||
"less": "Näita vähem",
|
||||
"localaddress": "Lokaalne aadress:",
|
||||
"localaddress_plural": "Lokaalsed aadressid:",
|
||||
"localport": "Lokaalne port:",
|
||||
"localport_plural": "Lokaalsed pordid:",
|
||||
"more": "Näita rohkem",
|
||||
"packetloss": "Andmepaketi kaotus:",
|
||||
"quality": {
|
||||
"good": "Hea",
|
||||
"inactive": "Mitteaktiivne",
|
||||
"lost": "Kaotatud",
|
||||
"nonoptimal": "Mitteoptimaalne",
|
||||
"poor": "Nõrk"
|
||||
},
|
||||
"remoteaddress": "Kaugtöö aadress:",
|
||||
"remoteaddress_plural": "Kaugtöö aadressid:",
|
||||
"remoteport": "Kaugtöö port:",
|
||||
"remoteport_plural": "Kaugtöö pordid:",
|
||||
"resolution": "Resolutsioon:",
|
||||
"status": "Ühendus:",
|
||||
"transport": "Transport:",
|
||||
"transport_plural": "Transpordid:"
|
||||
},
|
||||
"dateUtils": {
|
||||
"earlier": "Varem",
|
||||
"today": "Täna",
|
||||
"yesterday": "Eile"
|
||||
},
|
||||
"deepLinking": {
|
||||
"appNotInstalled": "Kõnega liitumiseks läbi mobiiltelefoni on vaja paigaldada {{app}} rakendus.",
|
||||
"description": "Midagi ei juhtunud? Proovisime ühendust luua töölaua rakendusega. Proovi uuesti või käivita {{app}} rakendus.",
|
||||
"descriptionWithoutWeb": "Midagi ei juhtunud? Televastuvõttu prooviti avada töölaua rakendusest {{app}}.",
|
||||
"downloadApp": "Laadi rakendus alla",
|
||||
"launchWebButton": "Käivita veebis",
|
||||
"openApp": "Jätka töölaua rakendusega",
|
||||
"title": "Kõne avamine rakenduses {{app}}...",
|
||||
"tryAgainButton": "Proovi töölaua rakendusega uuesti "
|
||||
},
|
||||
"defaultLink": "nt {{url}}",
|
||||
"defaultNickname": "nt. Mari Maasikas",
|
||||
"deviceError": {
|
||||
"cameraError": "Ei saanud kaameraga ühendust",
|
||||
"cameraPermission": "Puudub õigus kasutada kaamerat",
|
||||
"microphoneError": "Ei saanud mikrofoniga ühendust",
|
||||
"microphonePermission": "Puudub õigus kasutada mikrofoni"
|
||||
},
|
||||
"deviceSelection": {
|
||||
"noPermission": "Luba pole antud",
|
||||
"previewUnavailable": "Eelvaade pole kättesaadav",
|
||||
"selectADevice": "Vali seade",
|
||||
"testAudio": "Mängi testimiseks heli"
|
||||
},
|
||||
"dialog": {
|
||||
"accessibilityLabel": {
|
||||
"liveStreaming": "Otseülekanne"
|
||||
},
|
||||
"allow": "Luba",
|
||||
"alreadySharedVideoMsg": "Teine kasutaja jagab videot. Selles kõnes on ainult ühe video jagamine korraga lubatud.",
|
||||
"alreadySharedVideoTitle": "Korraga on lubatud ainult ühe video jagamine.",
|
||||
"applicationWindow": "Rakenduse aken",
|
||||
"Back": "Tagasi",
|
||||
"cameraConstraintFailedError": "Kaamera ei vasta teatud piirangutele.",
|
||||
"cameraNotFoundError": "Kaamerat ei leitud.",
|
||||
"cameraNotSendingData": "Ei saa ühendust kaameraga. Kontrolli, kas vahend on mõne teise rakenduse poolt kasutusel, vali menüüst teine vahend või värskenda rakendust.",
|
||||
"cameraNotSendingDataTitle": "Kaamera pole kättesaadav.",
|
||||
"cameraPermissionDeniedError": "Kaamera kasutamine on keelatud. Kõnega on võimalik ühineda ilma kaamerata. Kaamera kasutamiseks vajuta aadressiribal kaamera nupule.",
|
||||
"cameraUnknownError": "Kaamerat ei saa kasutada! Põhjus teadmata.",
|
||||
"cameraUnsupportedResolutionError": "Kaamera ei toeta nõutud resolutsiooni.",
|
||||
"Cancel": "Tühista",
|
||||
"close": "Sulge",
|
||||
"conferenceDisconnectMsg": "Kontrolli võrguühendust. Taasühendamine {{seconds}}...",
|
||||
"conferenceDisconnectTitle": "Ühendus on katkenud.",
|
||||
"conferenceReloadMsg": "Lahenduse otsime. Taasühendus {{seconds}} sek...",
|
||||
"conferenceReloadTitle": "Midagi läks valesti!",
|
||||
"confirm": "Kinnita",
|
||||
"confirmNo": "Ei",
|
||||
"confirmYes": "Kinnita",
|
||||
"connectError": "Oih, midagi läks valesti! Kõnega ühendamine ebaõnnestus.",
|
||||
"connectErrorWithMsg": "Oih, midagi läks valesti! Kõnega ühendamine ebaõnnestus. Põhjus: {{msg}}.",
|
||||
"connecting": "Ühendamine.",
|
||||
"contactSupport": "Võta ühendust kasutustoega",
|
||||
"copy": "Kopeeri",
|
||||
"dismiss": "Lõpeta",
|
||||
"displayNameRequired": "Nimi on kohustuslik",
|
||||
"done": "Valmis",
|
||||
"enterDisplayName": "Sisesta nimi",
|
||||
"error": "Viga",
|
||||
"externalInstallationMsg": "Töölauale on vaja paigaldada jagamise laiendus.",
|
||||
"externalInstallationTitle": "Laiendus on kohustuslik",
|
||||
"goToStore": "Mine veebipoodi",
|
||||
"gracefulShutdown": "Rakendus on hoolduseks ajutiselt maas. Proovi hiljem uuesti!",
|
||||
"IamHost": "Mina olen võõrustaja",
|
||||
"incorrectRoomLockPassword": "Vale parool",
|
||||
"incorrectPassword": "Vale kasutajanimi või parool",
|
||||
"inlineInstallationMsg": "Töölauale tuleb paigaldada jagamise laiendus.",
|
||||
"inlineInstallExtension": "Paiglada kohe",
|
||||
"internalError": "Oih, midagi läks valesti! Veateate: {{error}}.",
|
||||
"internalErrorTitle": "Sisemine viga",
|
||||
"kickMessage": "Oih, oled kõnest eemaldatud!",
|
||||
"kickParticipantButton": "Eemalda kõnest",
|
||||
"kickParticipantDialog": "Oled kindel, et tahad kasutaja kõnest eemaldada?",
|
||||
"kickParticipantTitle": "Eemalda kasutaja kõnest?",
|
||||
"kickTitle": "Kõnest eemaldatud",
|
||||
"liveStreaming": "Otseülekanne",
|
||||
"liveStreamingDisabledForGuestTooltip": "Külalised ei saa otseülekannet alustada.",
|
||||
"liveStreamingDisabledTooltip": "Otseülekande alustamine on keelatud.",
|
||||
"lockMessage": "Ebaõnnestunud lukustada kõnet.",
|
||||
"lockRoom": "Lisa kõnele parool",
|
||||
"lockTitle": "Lukustamine ebaõnnestus",
|
||||
"logoutQuestion": "Oled kindel, et tahad kõne peatada ja välja logida?",
|
||||
"logoutTitle": "Logi välja",
|
||||
"maxUsersLimitReached": "Maksimaalne kõnes osalejate arv on täis. Võta ühendust kõne omanikuga või proovi hiljem uuesti!",
|
||||
"maxUsersLimitReachedTitle": "Maksimaalne kõnes osalejate arv on täis",
|
||||
"micConstraintFailedError": "Mikrofon ei vasta teatud piirangutele.",
|
||||
"micNotFoundError": "Mikrofoni ei leitud.",
|
||||
"micNotSendingData": "Ei saa ühendust mikrofoniga. Vali menüüst teine vahend või värskenda rakendust.",
|
||||
"micNotSendingDataTitle": "Mikrofon pole kättesaadav.",
|
||||
"micPermissionDeniedError": "Mikrofoni kasutamine on keelatud. Kõnega on võimalik ühineda, aga teised Sind ei kuule. Mikrofoni kasutamiseks vajuta aadressiribal mikrofoni nupule.",
|
||||
"micUnknownError": "Mikrofoni ei saa kasutada. Põhjus teadmata.",
|
||||
"muteEveryoneElseDialog": "Peale mikrofoni vaigistamist saab ainult kasutaja ise oma mikrofoni tagasi sisse lülitada.",
|
||||
"muteEveryoneElseTitle": "Vaigista kõikide teiste mikrofonid, välja arvatud {{whom}}?",
|
||||
"muteEveryoneDialog": "Oled kindel, et soovid kõikide teiste mikrofonid vaigistada? Neid saab tagasi sisse lülitada ainult kasutaja ise.",
|
||||
"muteEveryoneTitle": "Vaigista kõik?",
|
||||
"muteEveryoneSelf": "Sina ise",
|
||||
"muteEveryoneStartMuted": "Edaspidi alustavad kõik välja lülitatud mikrofonidega",
|
||||
"muteParticipantBody": "Teiste kasutajate mikrofoni ei saa sisse lülitada. Kasutaja saab ise otsutada, kas mikrofon on sees või väljas.",
|
||||
"muteParticipantButton": "Lülita mikrofon välja",
|
||||
"muteParticipantDialog": "Oled kindel, et soovid kasutaja mikrofoni välja lülitada? Seda saab ainult kasutaja ise sisse tagasi lülitada.",
|
||||
"muteParticipantTitle": "Lülita kasutaja mikrofon välja?",
|
||||
"Ok": "Jah",
|
||||
"passwordLabel": "Parool",
|
||||
"passwordNotSupported": "Kõnele ei saa parooli määrata.",
|
||||
"passwordNotSupportedTitle": "Parooli lisamine pole toetatud",
|
||||
"passwordRequired": "Parool on kohustuslik",
|
||||
"popupError": "Modaalaknad on veebilehitsejas keelatud. Palun luba modaalakende kasutamine veebilehitseja turvalisuse seadistuses ning proovi uuesti.",
|
||||
"popupErrorTitle": "Modaalaknad on keelatud",
|
||||
"recording": "Salvetamine",
|
||||
"recordingDisabledForGuestTooltip": "Külalised ei saa kõne salvestada.",
|
||||
"recordingDisabledTooltip": "Kõne salvestamine on keelatud.",
|
||||
"rejoinNow": "Ühine uuesti",
|
||||
"remoteControlAllowedMessage": "{{user}} andis kaugjuhtimiseks loa!",
|
||||
"remoteControlDeniedMessage": "{{user}} keelas kaugjuhtimise!",
|
||||
"remoteControlErrorMessage": "Viga kaugjuhtimiseks loa küsimisel kasutajalt {{user}}!",
|
||||
"remoteControlRequestMessage": "Kas lubad kasutajal {{user}} oma töölauda kaugjuhtida?",
|
||||
"remoteControlShareScreenWarning": "Kui vajutad nupule \"Luba\", siis jagad oma ekraani.",
|
||||
"remoteControlStopMessage": "Kaugjuhtimise sessioon on lõppenud!",
|
||||
"remoteControlTitle": "Kaugjuhtimine",
|
||||
"Remove": "Eemalda",
|
||||
"removePassword": "Eemalda parool",
|
||||
"removeSharedVideoMsg": "Oled kindel, et soovid oma jagatud video eemaldada?",
|
||||
"removeSharedVideoTitle": "Eemalda jagatud video",
|
||||
"reservationError": "Broneerimise süsteemi viga",
|
||||
"reservationErrorMsg": "Veakood: {{code}}, sõnum: {{msg}}",
|
||||
"retry": "Proovi uuesti",
|
||||
"screenSharingFailedToInstall": "Oih, ekraanijagamise laienduse paigaldamine ebaõnnestus!",
|
||||
"screenSharingFailedToInstallTitle": "Ekraanijagamise laienduse paigaldamine ebaõnnestus",
|
||||
"screenSharingFirefoxPermissionDeniedError": "Ekraani jagamisega läks midagi valesti! Veendu, et oled ekraani jagamiseks loa andnud.",
|
||||
"screenSharingFirefoxPermissionDeniedTitle": "Oih, ekraani jagamist ei saanud alustada!",
|
||||
"screenSharingPermissionDeniedError": "Oih, midagi läks valesti ekraanijagamise laienduse õigustega! Värskenda ja proovi uuesti.",
|
||||
"sendPrivateMessage": "Sulle saabus privaatsõnum. Kas soovid vastata privaatselt või avalikult?",
|
||||
"sendPrivateMessageCancel": "Saada sõnum avalikult",
|
||||
"sendPrivateMessageOk": "Saada sõnum privaatselt",
|
||||
"sendPrivateMessageTitle": "Saada privaatselt?",
|
||||
"serviceUnavailable": "Teenus pole kättesaadav",
|
||||
"sessTerminated": "Kõne lõpetatud",
|
||||
"Share": "Jaga",
|
||||
"shareVideoLinkError": "Sisesta korrektne Youtube’i link.",
|
||||
"shareVideoTitle": "Jaga videot",
|
||||
"shareYourScreen": "Jaga ekraani",
|
||||
"shareYourScreenDisabled": "Ekraani jagamine on keelatud.",
|
||||
"shareYourScreenDisabledForGuest": "Külalised ei saa ekraani jagada.",
|
||||
"startLiveStreaming": "Alusta otseülekannet",
|
||||
"startRecording": "Alusta salvestamist",
|
||||
"startRemoteControlErrorMessage": "Kaugjuhtimise sessiooni alustamisel tekkis viga!",
|
||||
"stopLiveStreaming": "Lõpeta otseülekanne",
|
||||
"stopRecording": "Lõpeta salvestamine",
|
||||
"stopRecordingWarning": "Oled kindel, et soovid salvestamist lõpetada?",
|
||||
"stopStreamingWarning": "Oled kindel, et soovid otseülekannet lõpetada?",
|
||||
"streamKey": "Otseülekande võti",
|
||||
"Submit": "Esita",
|
||||
"thankYou": "Aitäh, et kasutasid rakendust {{appName}}!",
|
||||
"token": "token",
|
||||
"tokenAuthFailed": "Kahjuks ei ole kõnega ühinemine lubatud.",
|
||||
"tokenAuthFailedTitle": "Autentimine ebaõnnestus",
|
||||
"transcribing": "Transkribeerimine",
|
||||
"unlockRoom": "Eemalda kõne parool",
|
||||
"userPassword": "kasutaja parool",
|
||||
"WaitForHostMsg": "Kõne <b>{{room}}</b> ei ole veel alanud. Autendi ennast, kui oled võõrustaja. Külalisena oota, kuni võõrustaja saabub.",
|
||||
"WaitForHostMsgWOk": "Kõne <b>{{room}}</b> ei ole veel alanud. Kui oled võõrustaja, vajuta OK, et ennast autentida. Külalisena oota, kuni võõrustaja saabub.",
|
||||
"WaitingForHost": "Võõrustaja ootamine...",
|
||||
"Yes": "Jah",
|
||||
"yourEntireScreen": "Täisekraan"
|
||||
},
|
||||
"dialOut": {
|
||||
"statusMessage": "on staatusega {{status}}"
|
||||
},
|
||||
"documentSharing": {
|
||||
"title": "Jagatud dokument"
|
||||
},
|
||||
"feedback": {
|
||||
"average": "Keskmine",
|
||||
"bad": "Halb",
|
||||
"detailsLabel": "Kirjelda täpsemalt.",
|
||||
"good": "Hea",
|
||||
"rateExperience": "Hinda kõne kvaliteeti",
|
||||
"veryBad": "Väga halb",
|
||||
"veryGood": "Väga hea"
|
||||
},
|
||||
"incomingCall": {
|
||||
"answer": "Vasta",
|
||||
"audioCallTitle": "Sissetulev kõne",
|
||||
"decline": "Lõpeta",
|
||||
"productLabel": "Jitsi",
|
||||
"videoCallTitle": "Sissetulev videokõne"
|
||||
},
|
||||
"info": {
|
||||
"accessibilityLabel": "Näita infot",
|
||||
"addPassword": "Lisa parool",
|
||||
"cancelPassword": "Tühista parool",
|
||||
"conferenceURL": "Link:",
|
||||
"country": "Riik",
|
||||
"dialANumber": "Kõnega ühinemiseks vali number ja sisesta pin-kood.",
|
||||
"dialInConferenceID": "PIN:",
|
||||
"dialInNotSupported": "Oih, sissehelistamine ei ole toetatud!",
|
||||
"dialInNumber": "Sissehelistamine:",
|
||||
"dialInSummaryError": "Sissehelistamise info pole kättesaadav. Proovi hiljem uuesti!",
|
||||
"dialInTollFree": "Maksuvaba",
|
||||
"genericError": "Oih, midagi läks valesti!",
|
||||
"inviteLiveStream": "Otseülekande nägemiseks vajuta lingile: {{url}}",
|
||||
"invitePhone": "Üks klikk heliga sissehelistamiseks: {{number}},,{{conferenceID}}#",
|
||||
"invitePhoneAlternatives": "Otsid teist sissehelistamise numbrit?\nVaata sissehelistamise numbreid: {{url}}\n\n\nKui helistad läbi ruumi, ühine kõnega väljalülitatud mikrofoni režiimis: {{silentUrl}}",
|
||||
"inviteURLFirstPartGeneral": "Oled kõnesse kutsutud.",
|
||||
"inviteURLFirstPartPersonal": "{{name}} kutsub Sind kõnesse.\n",
|
||||
"inviteURLSecondPart": "\nÜhine kõnega:\n{{url}}\n",
|
||||
"liveStreamURL": "Otseülekanne:",
|
||||
"moreNumbers": "Rohkem numbreid",
|
||||
"noNumbers": "Sissehelistamise numbrid puuduvad.",
|
||||
"noPassword": "Andmed puuduvad",
|
||||
"noRoom": "Sissehelistamise ruum pole täpsustatud.",
|
||||
"numbers": "Sissehelistamise numbrid",
|
||||
"password": "Parool:",
|
||||
"title": "Jaga",
|
||||
"tooltip": "Jaga linki ja helista, et kõnega ühineda",
|
||||
"label": "Kõne info"
|
||||
},
|
||||
"inviteDialog": {
|
||||
"alertText": "Osade kasutajate kutsumine ebaõnnestus.",
|
||||
"header": "Kutsu",
|
||||
"searchCallOnlyPlaceholder": "Sisesta telefoninumber",
|
||||
"searchPeopleOnlyPlaceholder": "Otsi kasutajaid",
|
||||
"searchPlaceholder": "Kasutaja telefoninumber",
|
||||
"send": "Saada"
|
||||
},
|
||||
"inlineDialogFailure": {
|
||||
"msg": "Midagi läks valesti.",
|
||||
"retry": "Proovi uuesti",
|
||||
"support": "Kasutajatugi",
|
||||
"supportMsg": "Kui see juhtub uuesti, võta ühendust"
|
||||
},
|
||||
"keyboardShortcuts": {
|
||||
"focusLocal": "Keskendu videole",
|
||||
"focusRemote": "Keskendu teise kasutaja videole",
|
||||
"fullScreen": "Ava/sulge täisekraani vaade",
|
||||
"keyboardShortcuts": "Klaviatuuri kiirvalikud",
|
||||
"localRecording": "Näita/peida salvestamise võimalused",
|
||||
"mute": "Lülita mikrofon sisse/välja",
|
||||
"pushToTalk": "Vajuta, et rääkida",
|
||||
"raiseHand": "Tõsta/langeta kätt",
|
||||
"showSpeakerStats": "Näita kõnelejate statistikat",
|
||||
"toggleChat": "Ava/sulge vestluse aken",
|
||||
"toggleFilmstrip": "Näita/peida video eelvaade",
|
||||
"toggleScreensharing": "Vaheta kaamera ja ekraanijagamise vahel",
|
||||
"toggleShortcuts": "Näita/peida klaviatuuri kiirvalikud",
|
||||
"videoMute": "Lülita kaamera sisse/välja",
|
||||
"videoQuality": "Halda kõne kvaliteeti"
|
||||
},
|
||||
"liveStreaming": {
|
||||
"busy": "Toimub ülekande ressursi vabastamine. Proovi mõne minuti pärast uuesti.",
|
||||
"busyTitle": "Kõik ülekandjad on hetkel hõivatud",
|
||||
"changeSignIn": "Vaheta kontot.",
|
||||
"choose": "Vali otseülekanne",
|
||||
"chooseCTA": "Vali ülekande viis. Oled sisse logitud e-mailiga {{email}}.",
|
||||
"enterStreamKey": "Sisesta siia oma YouTube’i ülekande võti.",
|
||||
"error": "Otseülekanne ebaõnnestus. Proovi uuesti.",
|
||||
"errorAPI": "YouTube’i kanaliga ühendumisel tekkis viga. Palun logi uuesti sisse.",
|
||||
"errorLiveStreamNotEnabled": "Otseülekanne ei ole e-mailiga {{email}} sisse lülitatud. Luba kasutajaga otseülekanded või vaheta kontot.",
|
||||
"expandedOff": "Otseülekanne on peatatud",
|
||||
"expandedOn": "Kõnest tehakse otseülekanne YouTube’i.",
|
||||
"expandedPending": "Otseülekanne algab...",
|
||||
"failedToStart": "Otseülekandega alustamine ebaõnnestus.",
|
||||
"getStreamKeyManually": "Ülekandjaid ei leitud. Leia YouTube’st otseülekande võti.",
|
||||
"invalidStreamKey": "Otseülekande võti võib olla vale.",
|
||||
"off": "Otseülekanne on peatatud",
|
||||
"offBy": "{{name}} lõpetas otseülekande",
|
||||
"on": "Otseülekanne",
|
||||
"onBy": "{{name}} alustas otseülekandega",
|
||||
"pending": "Otseülekande alustamine...",
|
||||
"serviceName": "Otseülekande teenus",
|
||||
"signedInAs": "Oled sisse logitud kasutajana:",
|
||||
"signIn": "Google’ga sisselogimine",
|
||||
"signInCTA": "Logi sisse või sisesta otseülekande võti YouTube’st.",
|
||||
"signOut": "Logi välja",
|
||||
"start": "Alusta otseülekannet.",
|
||||
"streamIdHelp": "Mis see on?",
|
||||
"unavailableTitle": "Otseülekanne pole kättesaadav."
|
||||
},
|
||||
"localRecording": {
|
||||
"clientState": {
|
||||
"off": "Väljas",
|
||||
"on": "Sees",
|
||||
"unknown": "Teadmata"
|
||||
},
|
||||
"dialogTitle": "Kohalikud salvestamise nupud",
|
||||
"duration": "Kestvus",
|
||||
"durationNA": "N/A",
|
||||
"encoding": "Kodeerimine",
|
||||
"label": "LOR",
|
||||
"labelToolTip": "Kohalik salvestamine on alustatud",
|
||||
"localRecording": "Kohalik salvestamine",
|
||||
"me": "Mina",
|
||||
"messages": {
|
||||
"engaged": "Local recording engaged.",
|
||||
"finished": "Salvestamise sessioon {{token}} on lõppenud. Palun saada salvestatud fail moderaatorile.",
|
||||
"finishedModerator": "Salvestamise sessioon {{token}} on lõppenud ja salvestatud. Küsi teistelt kontaktidelt nende koopiaid.",
|
||||
"notModerator": "Sa ei ole moderaator. Sa ei saa alustada ega lõpetada kohalikku salvestamist."
|
||||
},
|
||||
"moderator": "Moderaator",
|
||||
"no": "Ei",
|
||||
"participant": "Osaleja",
|
||||
"participantStats": "Osaleja andmed",
|
||||
"sessionToken": "Sessiooni token",
|
||||
"start": "Alusta salvestamist",
|
||||
"stop": "Lõpeta salvestamine",
|
||||
"yes": "Jah"
|
||||
},
|
||||
"lockRoomPassword": "parool",
|
||||
"lockRoomPasswordUppercase": "Parool",
|
||||
"me": "mina",
|
||||
"notify": {
|
||||
"connectedOneMember": "{{name}} ühines kõnega",
|
||||
"connectedThreePlusMembers": "{{name}} ja {{count}} teist kasutajat ühines kõnega",
|
||||
"connectedTwoMembers": "{{first}} ja {{second}} ühinesid kõnega",
|
||||
"disconnected": "lahti ühendatud",
|
||||
"focus": "Konverentsi fookus",
|
||||
"focusFail": "{{component}} pole kättesaadav - proovi uuesti {{ms}} sekundi pärast.",
|
||||
"grantedTo": "Moderaatori õigused on antud kasutajale {{to}}!",
|
||||
"invitedOneMember": "{{name}} on kutsutud",
|
||||
"invitedThreePlusMembers": "{{name}} ja {{count}} teist kasutajat on kutsutud",
|
||||
"invitedTwoMembers": "{{first}} ja {{second}} on kutsutud",
|
||||
"kickParticipant": "{{kicked}} eemaldati kõnest kasutaja {{kicker}} poolt",
|
||||
"me": "Mina",
|
||||
"moderator": "Moderaatori õigused jagatud!",
|
||||
"muted": "Alustasid kõnet väljalülitatud mikrofoniga.",
|
||||
"mutedTitle": "Mikrofon on välja lülitatud!",
|
||||
"mutedRemotelyTitle": "Sinu mikrofon lülitati välja kasutaja {{participantDisplayName}} poolt!",
|
||||
"mutedRemotelyDescription": "Saad alati oma mikrofoni sisse lülitada, kui soovid rääkida. Lülita mikrofon peale rääkimist uuesti välja liigse müra ja kaja vältimiseks.",
|
||||
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) eemaldatud teise kasutaja poolt",
|
||||
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) lisatud teise kasutaja poolt",
|
||||
"raisedHand": "{{name}} soovib rääkida.",
|
||||
"somebody": "Keegi",
|
||||
"startSilentTitle": "Ühinesid ilma mikrofonita!",
|
||||
"startSilentDescription": "Mikrofoni kasutamiseks ühine kõnega uuesti",
|
||||
"suboptimalExperienceDescription": "Rakenduse {{appName}} parima kvaliteedi tagamiseks palun kasuta <a href='static/recommendedBrowsers.html' target='_blank'>ühte nendest veebilehitsejatest</a>.",
|
||||
"suboptimalExperienceTitle": "Veebilehitseja hoiatus",
|
||||
"unmute": "Lülita mikrofon sisse",
|
||||
"newDeviceCameraTitle": "Leitud uus kaamera",
|
||||
"newDeviceAudioTitle": "Leitud uus heliseadeldis",
|
||||
"newDeviceAction": "Kasuta"
|
||||
},
|
||||
"passwordSetRemotely": "määratud teise kasutaja poolt",
|
||||
"passwordDigitsOnly": "Kuni {{number}} tähemärki",
|
||||
"poweredby": "teieni toodud",
|
||||
"presenceStatus": {
|
||||
"busy": "Hõivatud",
|
||||
"calling": "Helistamine...",
|
||||
"connected": "Ühendatud",
|
||||
"connecting": "Ühendamine...",
|
||||
"connecting2": "Ühendamine*...",
|
||||
"disconnected": "Lahti ühendatud",
|
||||
"expired": "Aegunud",
|
||||
"ignored": "Eiratud",
|
||||
"initializingCall": "Kõne alustamine...",
|
||||
"invited": "Kutsutud",
|
||||
"rejected": "Tagasi lükatud",
|
||||
"ringing": "Kutsumine..."
|
||||
},
|
||||
"profile": {
|
||||
"setDisplayNameLabel": "Sisesta nimi",
|
||||
"setEmailInput": "Sisesta e-mail",
|
||||
"setEmailLabel": "Sisesta gravatar email",
|
||||
"title": "Profiil"
|
||||
},
|
||||
"raisedHand": "Soovin rääkida",
|
||||
"recording": {
|
||||
"authDropboxText": "Lisa Dropbox’i",
|
||||
"availableSpace": "Vaba ruum: {{spaceLeft}} MB (ca {{duration}} minutit salvestamist)",
|
||||
"beta": "BETA",
|
||||
"busy": "Salvestamise ressursi vabastamine... Proovi mõne minuti pärast uuesti.",
|
||||
"busyTitle": "Kõik salvestajad on praegu kinni",
|
||||
"error": "Salvestamine ebaõnnestus. Proovi uuesti.",
|
||||
"expandedOff": "Salvestamine peatatud",
|
||||
"expandedOn": "Kõne salvestatakse.",
|
||||
"expandedPending": "Salvestamine on alustatud...",
|
||||
"failedToStart": "Salvestamine ebaõnnestus",
|
||||
"fileSharingdescription": "Jaga salvestust kõnelejatega",
|
||||
"live": "Otse",
|
||||
"loggedIn": "Sisseloginud kasutajana {{userName}}",
|
||||
"off": "Salvestamine on lõpetatud",
|
||||
"offBy": "{{name}} lõpetas salvestamise",
|
||||
"on": "Salvestatakse",
|
||||
"onBy": "{{name}} alustas salvestamist",
|
||||
"pending": "Kõne salvestamise ettevalmistus...",
|
||||
"rec": "REC",
|
||||
"serviceDescription": "Salvestus toimub teenuse kaudu",
|
||||
"serviceName": "Salvestamise teenus",
|
||||
"signIn": "Logi sisse",
|
||||
"signOut": "Logi välja",
|
||||
"unavailable": "Oih! {{serviceName}} ei ole hetkel kättesaadav! Proovi hiljem uuesti.",
|
||||
"unavailableTitle": "Salvestamine ei ole võimalik."
|
||||
},
|
||||
"sectionList": {
|
||||
"pullToRefresh": "Tõmba uuendamiseks"
|
||||
},
|
||||
"settings": {
|
||||
"calendar": {
|
||||
"about": "Rakenduse {{appName}} kalender kasutab turvalist ühendust ning näeb eesolevaid kõnesid.",
|
||||
"disconnect": "Ühenda lahti",
|
||||
"microsoftSignIn": "Logi sisse Microsoft’i kontoga",
|
||||
"signedIn": "Hetkel nähakse kasutaja {{email}} kalendrit. Kalendrikutsete peitmiseks vajuta “Ühenda lahti” nupule.",
|
||||
"title": "Kalender"
|
||||
},
|
||||
"devices": "Seaded",
|
||||
"followMe": "Kõik jälgivad mind",
|
||||
"language": "Keel",
|
||||
"loggedIn": "Logitud sisse nimega: {{name}}",
|
||||
"moderator": "Moderaator",
|
||||
"more": "Rohkem",
|
||||
"name": "Nimi",
|
||||
"noDevice": "Andmed puuduvad",
|
||||
"selectAudioOutput": "Heli väljund",
|
||||
"selectCamera": "Kaamera",
|
||||
"selectMic": "Mikrofon",
|
||||
"startAudioMuted": "Kõik alustavad väljalülitatud mikrofoniga",
|
||||
"startVideoMuted": "Kõik alustavad väljalülitatud kaameraga",
|
||||
"title": "Seaded"
|
||||
},
|
||||
"settingsView": {
|
||||
"advanced": "Täpsem",
|
||||
"alertOk": "OK",
|
||||
"alertTitle": "Hoiatus",
|
||||
"alertURLText": "Sisestatud link ei ole õige",
|
||||
"buildInfoSection": "Versioon",
|
||||
"conferenceSection": "Kõne",
|
||||
"disableCallIntegration": "Lülita kohaliku kõne integratsioon välja",
|
||||
"disableP2P": "Lülita otseühendus välja",
|
||||
"displayName": "Kasutatav nimi",
|
||||
"email": "E-mail",
|
||||
"header": "Seaded",
|
||||
"profileSection": "Profiil",
|
||||
"serverURL": "Serveri link",
|
||||
"showAdvanced": "Näita täpsemaid seadistusi",
|
||||
"startWithAudioMuted": "Alusta väljalülitatud heliga",
|
||||
"startWithVideoMuted": "Alusta väljalülitatud videoga",
|
||||
"version": "Versioon"
|
||||
},
|
||||
"share": {
|
||||
"dialInfoText": "\n\n=====\n\nSoovid sisse helistada oma telefonilt?\n\n{{defaultDialInNumber}}Vajuta lingile, et näha telefoninumbreid sisse helistamiseks\n{{dialInfoPageUrl}}",
|
||||
"mainText": "Vajuta lingile, et kõnega ühineda:\n{{roomUrl}}"
|
||||
},
|
||||
"speaker": "Kõneleja",
|
||||
"speakerStats": {
|
||||
"hours": "{{count}}t",
|
||||
"minutes": "{{count}}m",
|
||||
"name": "Nimi",
|
||||
"seconds": "{{count}}s",
|
||||
"speakerStats": "Kõneleja andmed",
|
||||
"speakerTime": "Kõnelemise aeg"
|
||||
},
|
||||
"startupoverlay": {
|
||||
"policyText": " ",
|
||||
"title": "{{app}} vajab ligipääsu mikrofonile ja kaamerale."
|
||||
},
|
||||
"suspendedoverlay": {
|
||||
"rejoinKeyTitle": "Ühine uuesti",
|
||||
"text": "Vajuta <i>Ühine uuesti</i> nupule, et uuesti ühineda.",
|
||||
"title": "Kõne katkestati, sest arvuti läks magama."
|
||||
},
|
||||
"toolbar": {
|
||||
"accessibilityLabel": {
|
||||
"audioOnly": "Kasuta ainult heli",
|
||||
"audioRoute": "Vali heli vahend",
|
||||
"callQuality": "Halda kõne kvaliteeti",
|
||||
"cc": "Kasuta subtiitreid",
|
||||
"chat": "Kasuta vestluse akent",
|
||||
"document": "Kasuta jagatud dokumente",
|
||||
"download": "Laadi rakendus alla",
|
||||
"feedback": "Jäta tagasiside",
|
||||
"fullScreen": "Kasuta täisekraani",
|
||||
"hangup": "Lahku kõnest",
|
||||
"help": "Abi",
|
||||
"invite": "Kutsu inimesi",
|
||||
"kick": "Eemalda kõneleja",
|
||||
"localRecording": "Näita salvestamise paneeli",
|
||||
"lockRoom": "Kasuta kõne parooli",
|
||||
"moreActions": "Kasuta toimingute menüüd",
|
||||
"moreActionsMenu": "Toimingute menüü",
|
||||
"moreOptions": "Näita rohkem valikuid",
|
||||
"mute": "Lülita heli välja",
|
||||
"muteEveryone": "Vaigista kõikide mikrofonid",
|
||||
"pip": "Kasuta pilt-pildis vaadet",
|
||||
"privateMessage": "Saada privaatsõnum",
|
||||
"profile": "Muuda profiili",
|
||||
"raiseHand": "Käe tõstmine",
|
||||
"recording": "Salvestamine",
|
||||
"remoteMute": "Lülita kasutaja mikrofon välja",
|
||||
"Settings": "Seadistused",
|
||||
"sharedvideo": "Kasuta Youtube’i video jagamist",
|
||||
"shareRoom": "Kutsu",
|
||||
"shareYourScreen": "Jaga ekraani",
|
||||
"shortcuts": "Kasuta kiirvalikuid",
|
||||
"show": "Näita laval",
|
||||
"speakerStats": "Kõnelejate statistika",
|
||||
"tileView": "Paneelvaade",
|
||||
"toggleCamera": "Kasuta kaamerat",
|
||||
"videomute": "Video väljalülitamine",
|
||||
"videoblur": "Video hägustamine"
|
||||
},
|
||||
"addPeople": "Lisa kõnesse inimesi",
|
||||
"audioOnlyOff": "Lülita “ainult heli” valik välja",
|
||||
"audioOnlyOn": "Lülita “ainult heli” valik sisse",
|
||||
"audioRoute": "Vali heli vahend",
|
||||
"authenticate": "Autendi",
|
||||
"callQuality": "Halda kõne kvaliteeti",
|
||||
"chat": "Ava/sulge vestlus",
|
||||
"closeChat": "Sulge vestlus",
|
||||
"documentClose": "Sulge jagatud dokument",
|
||||
"documentOpen": "Ava jagatud dokument",
|
||||
"download": "Laadi rakendus alla",
|
||||
"enterFullScreen": "Vaata täisekraanil",
|
||||
"enterTileView": "Vaata paneelvaates",
|
||||
"exitFullScreen": "Välju täisekraani vaatest",
|
||||
"exitTileView": "Välju paneelvaatest",
|
||||
"feedback": "Jäta tagasiside",
|
||||
"hangup": "Lahku",
|
||||
"help": "Abi",
|
||||
"invite": "Kutsu",
|
||||
"login": "Logi sisse",
|
||||
"logout": "Logi välja",
|
||||
"lowerYourHand": "Langeta kätt",
|
||||
"moreActions": "Rohkem tegevusi",
|
||||
"moreOptions": "Rohkem valikuid",
|
||||
"mute": "Mikrofon sisse/välja",
|
||||
"muteEveryone": "Vaigista kõikide mikrofonid",
|
||||
"noAudioSignalTitle": "Mikrofon ei püüa sisendit kinni!",
|
||||
"noAudioSignalDesc": "Kui Sa ei lülitanud mikrofoni seadistustest tahtlikult välja, kaalu seadme vahetamist.",
|
||||
"noAudioSignalDescSuggestion": "Kui Sa ei lülitanud mikrofoni seadistustest tahtlikult välja, kaalu seadme vahetamist.",
|
||||
"noAudioSignalDialInDesc": "Võid sisse helistada valides:",
|
||||
"noAudioSignalDialInLinkDesc" : "Sissehelistamise numbrid",
|
||||
"noisyAudioInputTitle": "Mikrofonis on müra! Tundub, et läbi mikrofoni kostub palju helisid. Kaalu mikrofoni välja lülitamist või seadme vahetamist.",
|
||||
"noisyAudioInputDesc": "Tundub, et läbi mikrofoni kostub palju helisid. Kaalu mikrofoni välja lülitamist või seadme vahetamist.",
|
||||
"openChat": "Ava vestlus",
|
||||
"pip": "Ava pilt-pildis vaade",
|
||||
"privateMessage": "Saada privaatsõnum",
|
||||
"profile": "Muuda profiili",
|
||||
"raiseHand": "Tõsta/langeta kätt",
|
||||
"raiseYourHand": "Tõsta kätt",
|
||||
"Settings": "Seaded",
|
||||
"sharedvideo": "Jaga YouTube’i videot",
|
||||
"shareRoom": "Kutsu",
|
||||
"shortcuts": "Vaata kiirvalikuid",
|
||||
"speakerStats": "Kõneleja andmed",
|
||||
"startScreenSharing": "Alust ekraani jagamist",
|
||||
"startSubtitles": "Alusta subtiitrite näitamist",
|
||||
"stopScreenSharing": "Lõpeta ekraani jagamine",
|
||||
"stopSubtitles": "Lõpeta subtiitrite näitamine",
|
||||
"stopSharedVideo": "Lõpeta YouTube’i video",
|
||||
"talkWhileMutedPopup": "Soovid rääkida? Mikrofon on välja lülitatud.",
|
||||
"tileViewToggle": "Näita paneelvaadet",
|
||||
"toggleCamera": "Kasuta kaamerat",
|
||||
"videomute": "Kaamera sisse/välja",
|
||||
"startvideoblur": "Tausta hägustamine",
|
||||
"stopvideoblur": "Lülita tausta hägustamine välja"
|
||||
},
|
||||
"transcribing": {
|
||||
"ccButtonTooltip": "Subtiitrid sisse/välja",
|
||||
"error": "Transkribeerimine ebaõnnestus. Proovi uuesti.",
|
||||
"expandedLabel": "Transkribeerimine on sisse lülitatud",
|
||||
"failedToStart": "Transkribeerimise alustamine ebaõnnestus",
|
||||
"labelToolTip": "Kõne transkribeeritakse",
|
||||
"off": "Transkribeerimine peatatud",
|
||||
"pending": "Transkribeerimise ettevalmistus...",
|
||||
"start": "Alusta subtiitrite kuvamist",
|
||||
"stop": "Lõpeta subtiitrite kuvamine",
|
||||
"tr": "TR"
|
||||
},
|
||||
"userMedia": {
|
||||
"androidGrantPermissions": "Vali <b><i>Luba</i></b>, kui veebilehitseja küsib nõusolekut.",
|
||||
"chromeGrantPermissions": "Vali <b><i>Luba</i></b>, kui veebilehitseja küsib nõusolekut.",
|
||||
"edgeGrantPermissions": "Vali <b><i>Jah</i></b>, kui veebilehitseja küsib nõusolekut.",
|
||||
"electronGrantPermissions": "Luba kasutada kaamerat ja mikrofoni",
|
||||
"firefoxGrantPermissions": "Vali <b><i>Jaga valitud vahendit</i></b>, kui veebilehitseja küsib nõusolekut.",
|
||||
"iexplorerGrantPermissions": "Vali <b><i>OK</i></b>, kui veebilehitseja küsib nõusolekut.",
|
||||
"nwjsGrantPermissions": "Luba kasutada kaamerat ja mikrofoni",
|
||||
"operaGrantPermissions": "Vali <b><i>Luba</i></b>, kui veebilehitseja küsib nõusolekut.",
|
||||
"react-nativeGrantPermissions": "Vali <b><i>Luba</i></b>, kui veebilehitseja küsib nõusolekut.",
|
||||
"safariGrantPermissions": "Vali <b><i>OK</i></b>, kui veebilehitseja küsib nõusolekut."
|
||||
},
|
||||
"videoSIPGW": {
|
||||
"busy": "Vabastatakse ressurssi... Proovi mõne minuti pärast uuesti.",
|
||||
"busyTitle": "Ruumi teenus on hetkel hõivatud",
|
||||
"errorAlreadyInvited": "{{displayName}} on juba kutsutud",
|
||||
"errorInvite": "Ühendus ei ole veel saavutatud. Proovi hiljem uuesti.",
|
||||
"errorInviteFailed": "Probleemi lahendatakse. Proovi hiljem uuesti.",
|
||||
"errorInviteFailedTitle": "Kasutaja {{displayName}} kutsumine ebaõnnestus",
|
||||
"errorInviteTitle": "Ruumi kutsumine ebaõnnestus",
|
||||
"pending": "{{displayName}} on kutsutud"
|
||||
},
|
||||
"videoStatus": {
|
||||
"audioOnly": "AUD",
|
||||
"audioOnlyExpanded": "Kasutad kõnes ainult heli. See hõivab ülekandekiirust vähem, aga video jagamine on välja lülitatud.",
|
||||
"callQuality": "Kõne kvaliteet",
|
||||
"hd": "HD",
|
||||
"hdTooltip": "Video vaatamine kõrgkvaliteediga",
|
||||
"highDefinition": "Kõrgresolutsioon",
|
||||
"labelTooiltipNoVideo": "Video puudub",
|
||||
"labelTooltipAudioOnly": "Valitud on “ainult heli” seadistus",
|
||||
"ld": "LD",
|
||||
"ldTooltip": "Video vaatamine madala kvaliteediga",
|
||||
"lowDefinition": "Madal",
|
||||
"onlyAudioAvailable": "Saab kasutada ainult heli",
|
||||
"onlyAudioSupported": "Selles veebilehitsejas on toetatud ainult heli.",
|
||||
"p2pEnabled": "Otseühendus on sisse lülitatud",
|
||||
"p2pVideoQualityDescription": "Otseühenduse režiimis saab vastuvõetava kõne heli olla “ainult heli“, või kõrge. Teisi seadistusi ei saa valida.",
|
||||
"recHighDefinitionOnly": "Eelistan kõrgresolutsiooni.",
|
||||
"sd": "SD",
|
||||
"sdTooltip": "Video vaatamine vaikekvaliteediga",
|
||||
"standardDefinition": "Vaike resolutsioon"
|
||||
},
|
||||
"videothumbnail": {
|
||||
"domute": "Lülita mikrofon välja",
|
||||
"domuteOthers": "Vaigista teiste mikrofonid",
|
||||
"flip": "Pööra",
|
||||
"kick": "Eemalda kõnest",
|
||||
"moderator": "Moderaator",
|
||||
"mute": "Kasutaja mikrofon välja lülitatud",
|
||||
"muted": "Mikrofon välja lülitatud",
|
||||
"remoteControl": "Kaugjuhtimine",
|
||||
"show": "Näita laval",
|
||||
"videomute": "Kasutaja on kaamera peatanud"
|
||||
},
|
||||
"welcomepage": {
|
||||
"accessibilityLabel": {
|
||||
"join": "Vajuta, et ühineda",
|
||||
"roomname": "Sisesta ruumi nimi"
|
||||
},
|
||||
"appDescription": "Lase käia, tee videoülekanne kogu meeskonnaga! Kutsu kõik, keda soovid. Rakendus {{app}} on krüpteeritud. 100% vabavara ülekannete tegemiseks, mida saab kasutada iga päev tasuta - ilma konto loomiseta.",
|
||||
"audioVideoSwitch": {
|
||||
"audio": "Heli",
|
||||
"video": "Video"
|
||||
},
|
||||
"calendar": "Kalender",
|
||||
"connectCalendarButton": "Ühenda kalender",
|
||||
"connectCalendarText": "Ühenda oma kalender, et kõiki kohtumisi näha rakenduses {{app}}. Lisa {{provider}} kohtumised kalendrisse ja alusta kõnesid ühe klikiga.",
|
||||
"enterRoomTitle": "Alusta uut kõnet",
|
||||
"roomNameAllowedChars": "Televastuvõtu nimi ei tohi sisaldada sümboleid: ?, &, :, ', \", %, #.",
|
||||
"go": "Mine",
|
||||
"goSmall": "Mine",
|
||||
"join": "Ühine",
|
||||
"info": "Info",
|
||||
"privacy": "Privaatsus",
|
||||
"recentList": "Hiljutised",
|
||||
"recentListDelete": "Kustuta",
|
||||
"recentListEmpty": "Hiljutiste valikute nimekiri on tühi. Vestle kasutajatega ja leia oma hiljutised kõned siit.",
|
||||
"reducedUIText": "Tere tulemast rakendusse {{app}}!",
|
||||
"roomname": "Sisesta ruumi nimi",
|
||||
"roomnameHint": "Sisesta ruumi nimi või link, millega soovid ühinega. Võid nime välja mõelda, aga anna osalejatele sellest teada, et nad saaksid ruumiga ühineda.",
|
||||
"sendFeedback": "Saada tagasiside",
|
||||
"terms": "Tingimused",
|
||||
"title": "Turvaline, võimalusi täis ja tasuta keskkond videokõnede jaoks."
|
||||
},
|
||||
"lonelyMeetingExperience": {
|
||||
"button": "Kutsu teisi",
|
||||
"youAreAlone": "Asud hetkel ruumis üksi"
|
||||
}
|
||||
}
|
||||
@@ -601,7 +601,7 @@
|
||||
"show": "Afficher en premier plan",
|
||||
"speakerStats": "Afficher/cacher les statistiques de parole",
|
||||
"tileView": "Activer/désactiver la vue mosaïque",
|
||||
"toggleCamera": "Activer/désactiver la caméra",
|
||||
"toggleCamera": "Changer de caméra",
|
||||
"videomute": "Activer/désactiver la vidéo",
|
||||
"videoblur": "Activer/désactiver le flou de la vidéo"
|
||||
},
|
||||
|
||||
@@ -21,16 +21,16 @@
|
||||
"bluetooth": "Bluetooth",
|
||||
"headphones": "Hoofdtelefoon",
|
||||
"phone": "Telefoon",
|
||||
"speaker": "Spreker"
|
||||
"speaker": "Speaker"
|
||||
},
|
||||
"audioOnly": {
|
||||
"audioOnly": "Alleen audio"
|
||||
},
|
||||
"calendarSync": {
|
||||
"addMeetingURL": "Een link naar de vergadering toevoegen",
|
||||
"confirmAddLink": "Wilt u een Jitsi-link naar deze gebeurtenis toevoegen?",
|
||||
"confirmAddLink": "Wilt u een Jitsi-link aan deze gebeurtenis toevoegen?",
|
||||
"error": {
|
||||
"appConfiguration": "De Agenda-integratie is niet naar behoren geconfigureerd.",
|
||||
"appConfiguration": "De agenda-integratie is niet juist ingesteld.",
|
||||
"generic": "Er is een fout opgetreden. Controleer de agenda-instellingen of vernieuw de agenda.",
|
||||
"notSignedIn": "Er is een fout opgetreden tijdens de verificatie voor het weergeven van agendagebeurtenissen. Controleer de agenda-instellingen en probeer u opnieuw aan te melden."
|
||||
},
|
||||
@@ -40,18 +40,23 @@
|
||||
"noEvents": "Er zijn geen gebeurtenissen gepland.",
|
||||
"ongoingMeeting": "actieve vergadering",
|
||||
"permissionButton": "Instellingen openen",
|
||||
"permissionMessage": "U hebt een machtiging voor Agenda nodig om uw vergaderingen weer te geven in de app.",
|
||||
"permissionMessage": "U hebt een machtiging voor Agenda nodig om uw afspraken weer te geven in de app.",
|
||||
"refresh": "Agenda vernieuwen",
|
||||
"today": "Vandaag"
|
||||
},
|
||||
"chat": {
|
||||
"error": "Fout: uw bericht \"{{originalText}}\" is niet verzonden. Reden: {{error}}",
|
||||
"fieldPlaceHolder": "Type hier je bericht",
|
||||
"messagebox": "Typ een bericht",
|
||||
"messageTo": "Privébericht aan {{recipient}}",
|
||||
"noMessagesMessage": "Er zijn nog geen berichten in deze bijkeenkomst. Begin een gesprek!",
|
||||
"nickname": {
|
||||
"popover": "Kies een bijnaam",
|
||||
"title": "Voer een bijnaam in om de chatfunctie te gebruiken"
|
||||
},
|
||||
"title": "Chat"
|
||||
"privateNotice": "Privébericht aan {{recipient}}",
|
||||
"title": "Chat",
|
||||
"you": "jij"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
"joiningRoom": "Er wordt verbinding gemaakt met de vergadering..."
|
||||
@@ -503,16 +508,18 @@
|
||||
"title": "Instellingen"
|
||||
},
|
||||
"settingsView": {
|
||||
"advanced": "Geavanceerd",
|
||||
"alertOk": "OK",
|
||||
"alertTitle": "Waarschuwing",
|
||||
"alertURLText": "De ingevoerde server-URL is ongeldig",
|
||||
"buildInfoSection": "Buildgegevens",
|
||||
"conferenceSection": "Conferentie",
|
||||
"conferenceSection": "Bijeenkomsten",
|
||||
"displayName": "Weergavenaam",
|
||||
"email": "E‑mail",
|
||||
"header": "Instellingen",
|
||||
"profileSection": "Profiel",
|
||||
"serverURL": "Server-URL",
|
||||
"showAdvanced": "Toon geavanceerde instellingen",
|
||||
"startWithAudioMuted": "Starten met audio gedempt",
|
||||
"startWithVideoMuted": "Starten met video gedempt",
|
||||
"version": "Versie"
|
||||
@@ -595,6 +602,7 @@
|
||||
"logout": "Afmelden",
|
||||
"lowerYourHand": "Uw hand laten zakken",
|
||||
"moreActions": "Meer acties",
|
||||
"moreOptions": "Meer opties",
|
||||
"mute": "Dempen/dempen opheffen",
|
||||
"openChat": "Chat openen",
|
||||
"pip": "Beeld-in-beeld-modus activeren",
|
||||
@@ -705,8 +713,12 @@
|
||||
"reducedUIText": "",
|
||||
"roomname": "Naam van ruimte invoeren",
|
||||
"roomnameHint": "Voer de naam of URL in van de ruimte die u wilt betreden. U kunt een naam verzinnen, maar geef de naam wel door aan de andere deelnemers, zodat zij dezelfde naam kunnen invoeren.",
|
||||
"sendFeedback": "Feedback verzenden",
|
||||
"sendFeedback": "Feedback sturen",
|
||||
"terms": "Voorwaarden",
|
||||
"title": "Veilige, volledig uitgeruste en geheel gratis videovergaderingen"
|
||||
},
|
||||
"lonelyMeetingExperience": {
|
||||
"button": "Anderen uitnodigen",
|
||||
"youAreAlone": "Je bent de enige in dit gesprek"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
"noMessagesMessage": "",
|
||||
"nickname": {
|
||||
"popover": "Wybierz swój nick",
|
||||
"title": "Wpisz swoje imię i nazwisko, aby użyć rozmowy"
|
||||
"title": "Wpisz swoją nazwę, aby użyć rozmowy"
|
||||
},
|
||||
"privateNotice": "Prywatna wiadomość do {{recipient}}",
|
||||
"title": "Rozmowa",
|
||||
@@ -76,38 +76,38 @@
|
||||
},
|
||||
"connectionindicator": {
|
||||
"address": "Adres:",
|
||||
"bandwidth": "Zakładana przepustowość:",
|
||||
"bandwidth": "Szacowana przepustowość:",
|
||||
"bitrate": "Szybkość transmisji:",
|
||||
"bridgeCount": "Liczba serwerów: ",
|
||||
"connectedTo": "Podłączone do:",
|
||||
"framerate": "Częstotliwość wyświetlania klatek:",
|
||||
"framerate": "Klatek na sekundę:",
|
||||
"less": "Pokaż mniej",
|
||||
"localaddress_0": "Adres lokalny:",
|
||||
"localaddress_1": "Adresy lokalne:",
|
||||
"localaddress_2": "Adresów lokalnych:",
|
||||
"localaddress_2": "Adresy lokalne:",
|
||||
"localport_0": "Port lokalny:",
|
||||
"localport_1": "Porty lokalne:",
|
||||
"localport_2": "Portów lokalnych:",
|
||||
"localport_2": "Porty lokalne:",
|
||||
"more": "Pokaż więcej",
|
||||
"packetloss": "Strata pakietów:",
|
||||
"packetloss": "Utrata pakietów:",
|
||||
"quality": {
|
||||
"good": "Prawdziwy",
|
||||
"inactive": "Nieaktywny",
|
||||
"lost": "Zaginiony",
|
||||
"good": "Dobre",
|
||||
"inactive": "Nieaktywne",
|
||||
"lost": "Utracone",
|
||||
"nonoptimal": "Nieoptymalne",
|
||||
"poor": "Słaby"
|
||||
"poor": "Słabe"
|
||||
},
|
||||
"remoteaddress_0": "Adres zdalny:",
|
||||
"remoteaddress_1": "Adresy zdalne:",
|
||||
"remoteaddress_2": "Adresów zdalnych:",
|
||||
"remoteaddress_2": "Adresy zdalne:",
|
||||
"remoteport_0": "Port zdalny:",
|
||||
"remoteport_1": "Porty zdalne:",
|
||||
"remoteport_2": "Portów zdalnych:",
|
||||
"remoteport_2": "Porty zdalne:",
|
||||
"resolution": "Rozdzielczość:",
|
||||
"status": "Połączenie:",
|
||||
"transport_0": "Przekazywanie:",
|
||||
"transport_1": "Przekazywania:",
|
||||
"transport_2": "Przekazywań:"
|
||||
"transport_0": "Transport:",
|
||||
"transport_1": "Transporty:",
|
||||
"transport_2": "Transporty:"
|
||||
},
|
||||
"dateUtils": {
|
||||
"earlier": "Wcześniej",
|
||||
@@ -128,7 +128,7 @@
|
||||
"defaultNickname": "np. Ziutek Kowalski",
|
||||
"deviceError": {
|
||||
"cameraError": "Błąd dostępu do Twojej kamery",
|
||||
"cameraPermission": "Błąd podczas przetwarzania uprawnień do kamery",
|
||||
"cameraPermission": "Błąd podczas otrzymywania uprawnień do kamery",
|
||||
"microphoneError": "Błąd dostępu do Twojego mikrofonu",
|
||||
"microphonePermission": "Błąd podczas otrzymywania uprawnień do mikrofonu"
|
||||
},
|
||||
@@ -209,7 +209,7 @@
|
||||
"muteParticipantButton": "Wyciszenie",
|
||||
"muteParticipantDialog": "Czy na pewno wyciszyć tego uczestnika? Nie będziesz mógł wyłączyć wyciszenia uczestników, ale oni mogą samodzielnie wyłączyć wyciszenie w dowolnym momencie.",
|
||||
"muteParticipantTitle": "Wyciszyć tego uczestnika?",
|
||||
"Ok": "Ok",
|
||||
"Ok": "OK",
|
||||
"passwordLabel": "$t(lockRoomPasswordUppercase)",
|
||||
"passwordNotSupported": "Ustanowienie spotkania $t(lockRoomPassword) nie jest obsługiwane.",
|
||||
"passwordNotSupportedTitle": "$t(lockRoomPasswordUppercase) nie jest obsługiwane",
|
||||
@@ -280,16 +280,16 @@
|
||||
"title": "Współdzielony dokument"
|
||||
},
|
||||
"feedback": {
|
||||
"average": "Średni",
|
||||
"bad": "Źle",
|
||||
"average": "Średnio",
|
||||
"bad": "Źle",
|
||||
"detailsLabel": "Powiedz nam o tym więcej.",
|
||||
"good": "Prawdziwy",
|
||||
"rateExperience": "Oceń proszę swoje doświadczenia z konferencji",
|
||||
"good": "Dobrze",
|
||||
"rateExperience": "Jak oceniasz tę konferencję?",
|
||||
"veryBad": "Bardzo źle",
|
||||
"veryGood": "1: Bardzo dobrze"
|
||||
"veryGood": "Bardzo dobrze"
|
||||
},
|
||||
"incomingCall": {
|
||||
"answer": "Odpowiedz",
|
||||
"answer": "Odbierz",
|
||||
"audioCallTitle": "Przychodzące połączenie",
|
||||
"decline": "Odrzuć",
|
||||
"productLabel": "z Jitsi Meet",
|
||||
@@ -512,18 +512,18 @@
|
||||
"title": "Kalendarz"
|
||||
},
|
||||
"devices": "Urządzenia",
|
||||
"followMe": "Wszyscy za mną",
|
||||
"followMe": "Wszyscy widzą mnie",
|
||||
"language": "Język",
|
||||
"loggedIn": "Zalogowano jako {{name}}",
|
||||
"moderator": "Moderujący",
|
||||
"moderator": "Moderacja",
|
||||
"more": "Więcej",
|
||||
"name": "Nazwa",
|
||||
"noDevice": "Brak",
|
||||
"selectAudioOutput": "Wyjście audio",
|
||||
"selectCamera": "Kamera",
|
||||
"selectMic": "Mikrofon",
|
||||
"startAudioMuted": "Wszyscy się wyciszyli",
|
||||
"startVideoMuted": "Wszyscy się ukryli",
|
||||
"startAudioMuted": "Wycisz wszystkich dołączających",
|
||||
"startVideoMuted": "Ukryj wszystkich dołączających",
|
||||
"title": "Ustawienia"
|
||||
},
|
||||
"settingsView": {
|
||||
@@ -600,7 +600,7 @@
|
||||
"shortcuts": "Przełączanie skrótów klawiszowych",
|
||||
"show": "",
|
||||
"speakerStats": "Przełączanie statystyk dotyczących mówców",
|
||||
"tileView": "Przełączanie kafelkowego widoku",
|
||||
"tileView": "Przełącz widok kafelkowy",
|
||||
"toggleCamera": "Przełączanie kamery",
|
||||
"videomute": "Przełączanie wyciszonego filmu wideo",
|
||||
"videoblur": "Przełącz rozmazanie obrazu"
|
||||
@@ -626,9 +626,9 @@
|
||||
"invite": "Zapraszaj ludzi",
|
||||
"login": "Zaloguj",
|
||||
"logout": "Wyloguj",
|
||||
"lowerYourHand": "Opuść swą rękę",
|
||||
"lowerYourHand": "Opuść rękę",
|
||||
"moreActions": "Więcej działań",
|
||||
"mute": "Wycisz / Pogłośnij",
|
||||
"mute": "Włącz / Wyłącz mikrofon",
|
||||
"noAudioSignalTitle": "",
|
||||
"noAudioSignalDesc": "",
|
||||
"noAudioSignalDescSuggestion": "",
|
||||
@@ -636,13 +636,13 @@
|
||||
"pip": "Wprowadź tryb obrazu w obrazie",
|
||||
"privateMessage": "Wyślij wiadomość prywatną",
|
||||
"profile": "Edytuj swój profil",
|
||||
"raiseHand": "Podnieś / Opuść swą rękę",
|
||||
"raiseYourHand": "Podnieś swą rękę",
|
||||
"raiseHand": "Podnieś / Opuść rękę",
|
||||
"raiseYourHand": "Podnieś rękę",
|
||||
"Settings": "Ustawienia",
|
||||
"sharedvideo": "Udostępniaj wideo w Youtube",
|
||||
"sharedvideo": "Udostępnij wideo w Youtube",
|
||||
"shareRoom": "Zaproś kogoś",
|
||||
"shortcuts": "Wyświetlanie skrótów",
|
||||
"speakerStats": "Statystyki głośników",
|
||||
"shortcuts": "Wyświetl skróty",
|
||||
"speakerStats": "Statystyki mówców",
|
||||
"startScreenSharing": "Zacznij współdzielenie ekranu",
|
||||
"startSubtitles": "Uruchom napisy",
|
||||
"stopScreenSharing": "Zatrzymaj współdzielenie ekranu",
|
||||
|
||||
@@ -571,7 +571,7 @@
|
||||
"show": "",
|
||||
"speakerStats": "Stäng eller öppna högstalarstatistik",
|
||||
"tileView": "Öppna eller stäng panelvyn",
|
||||
"toggleCamera": "Öppna eller stäng kamera",
|
||||
"toggleCamera": "Byta kamera",
|
||||
"videomute": "Sätt på eller stäng av mikrofonen",
|
||||
"videoblur": ""
|
||||
},
|
||||
@@ -614,7 +614,7 @@
|
||||
"stopSharedVideo": "Pausa YouTube-video",
|
||||
"talkWhileMutedPopup": "Försöker du tala? Din mikrofon är tystad.",
|
||||
"tileViewToggle": "Öppna eller stäng panelvyn",
|
||||
"toggleCamera": "Öppna eller stäng kamera",
|
||||
"toggleCamera": "Byta kamera",
|
||||
"videomute": "Aktivera / avaktivera kameran",
|
||||
"startvideoblur": "",
|
||||
"stopvideoblur": ""
|
||||
@@ -710,4 +710,4 @@
|
||||
"terms": "Termer",
|
||||
"title": "Säkra, välutrustade och helt kostnadsfria videokonferenser"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,7 +532,6 @@
|
||||
"selectAudioOutput": "Audio output",
|
||||
"selectCamera": "Camera",
|
||||
"selectMic": "Microphone",
|
||||
"speakers": "Speakers",
|
||||
"startAudioMuted": "Everyone starts muted",
|
||||
"startVideoMuted": "Everyone starts hidden",
|
||||
"title": "Settings"
|
||||
@@ -615,6 +614,7 @@
|
||||
"speakerStats": "Toggle speaker statistics",
|
||||
"tileView": "Toggle tile view",
|
||||
"toggleCamera": "Toggle camera",
|
||||
"toggleFilmstrip": "Toggle filmstrip",
|
||||
"videomute": "Toggle mute video",
|
||||
"videoblur": "Toggle video blur"
|
||||
},
|
||||
@@ -648,7 +648,7 @@
|
||||
"noAudioSignalDesc": "If you did not purposely mute it from system settings or hardware, consider switching the device.",
|
||||
"noAudioSignalDescSuggestion": "If you did not purposely mute it from system settings or hardware, consider switching to the suggested device.",
|
||||
"noAudioSignalDialInDesc": "You can also dial-in using:",
|
||||
"noAudioSignalDialInLinkDesc": "Dial-in numbers",
|
||||
"noAudioSignalDialInLinkDesc" : "Dial-in numbers",
|
||||
"noisyAudioInputTitle": "Your microphone appears to be noisy!",
|
||||
"noisyAudioInputDesc": "It sounds like your microphone is making noise, please consider muting or changing the device.",
|
||||
"openChat": "Open chat",
|
||||
|
||||
@@ -369,12 +369,14 @@ class API {
|
||||
* Notify external application (if API is enabled) that message was sent.
|
||||
*
|
||||
* @param {string} message - Message body.
|
||||
* @param {boolean} privateMessage - True if the message was a private message.
|
||||
* @returns {void}
|
||||
*/
|
||||
notifySendingChatMessage(message: string) {
|
||||
notifySendingChatMessage(message: string, privateMessage: boolean) {
|
||||
this._sendEvent({
|
||||
name: 'outgoing-message',
|
||||
message
|
||||
message,
|
||||
privateMessage
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
"jquery-contextmenu": "2.4.5",
|
||||
"jquery-i18next": "1.2.1",
|
||||
"js-md5": "0.6.1",
|
||||
"js-utils": "github:jitsi/js-utils#91c5e53ca5fa42907c88d56bc78254e6e56e058d",
|
||||
"js-utils": "github:jitsi/js-utils#0b2cef90613a74777fefd98d4ee3eda3879809ab",
|
||||
"jsrsasign": "8.0.12",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#a7950f8ebb489225c2e8bf41fe65f330b3de0874",
|
||||
|
||||
@@ -164,7 +164,7 @@ export function getConferenceName(stateful: Function | Object): string {
|
||||
|| subject
|
||||
|| callDisplayName
|
||||
|| (callee && callee.name)
|
||||
|| _.startCase(safeDecodeURIComponent(room));
|
||||
|| safeStartCase(safeDecodeURIComponent(room));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -351,3 +351,19 @@ export function sendLocalParticipant(
|
||||
|
||||
conference.setDisplayName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* A safe implementation of lodash#startCase that doesn't deburr the string.
|
||||
*
|
||||
* NOTE: According to lodash roadmap, lodash v5 will have this function.
|
||||
*
|
||||
* Code based on https://github.com/lodash/lodash/blob/master/startCase.js.
|
||||
*
|
||||
* @param {string} s - The string to do start case on.
|
||||
* @returns {string}
|
||||
*/
|
||||
function safeStartCase(s = '') {
|
||||
return _.words(`${s}`.replace(/['\u2019]/g, '')).reduce(
|
||||
(result, word, index) => result + (index ? ' ' : '') + _.upperFirst(word)
|
||||
, '');
|
||||
}
|
||||
|
||||
@@ -88,8 +88,10 @@ export default [
|
||||
'disableLocalVideoFlip',
|
||||
'disableNS',
|
||||
'disableRemoteControl',
|
||||
'disableRemoteMute',
|
||||
'disableRtx',
|
||||
'disableSuspendVideo',
|
||||
'disableThirdPartyRequests',
|
||||
'displayJids',
|
||||
'e2eping',
|
||||
'enableDisplayNameInStats',
|
||||
@@ -125,6 +127,7 @@ export default [
|
||||
'pcStatsInterval',
|
||||
'preferH264',
|
||||
'requireDisplayName',
|
||||
'remoteVideoMenu',
|
||||
'resolution',
|
||||
'startAudioMuted',
|
||||
'startAudioOnly',
|
||||
|
||||
@@ -43,7 +43,9 @@ const INITIAL_RN_STATE = {
|
||||
p2p: {
|
||||
disableH264: false,
|
||||
preferH264: true
|
||||
}
|
||||
},
|
||||
|
||||
remoteVideoMenu: {}
|
||||
};
|
||||
|
||||
ReducerRegistry.register('features/base/config', (state = _getInitialState(), action) => {
|
||||
|
||||
@@ -216,18 +216,6 @@ export function setAudioInputDevice(deviceId) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the output device id.
|
||||
*
|
||||
* @param {string} deviceId - The id of the new output device.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function setAudioOutputDevice(deviceId) {
|
||||
return function(dispatch) {
|
||||
return setAudioOutputDeviceId(deviceId, dispatch);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals to update the currently used video input device.
|
||||
*
|
||||
|
||||
@@ -174,60 +174,6 @@ export function formatDeviceLabel(label: string) {
|
||||
return formattedLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects containing all the microphone device ids and labels.
|
||||
*
|
||||
* @param {Object} state - The state of the application.
|
||||
* @returns {Object[]}
|
||||
*/
|
||||
export function getAudioInputDeviceData(state: Object) {
|
||||
return state['features/base/devices'].availableDevices.audioInput.map(
|
||||
({ deviceId, label }) => {
|
||||
return {
|
||||
deviceId,
|
||||
label
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objectes containing all the output device ids and labels.
|
||||
*
|
||||
* @param {Object} state - The state of the application.
|
||||
* @returns {Object[]}
|
||||
*/
|
||||
export function getAudioOutputDeviceData(state: Object) {
|
||||
return state['features/base/devices'].availableDevices.audioOutput.map(
|
||||
({ deviceId, label }) => {
|
||||
return {
|
||||
deviceId,
|
||||
label
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all the camera device ids.
|
||||
*
|
||||
* @param {Object} state - The state of the application.
|
||||
* @returns {string[]}
|
||||
*/
|
||||
export function getVideoDeviceIds(state: Object) {
|
||||
return state['features/base/devices'].availableDevices.videoInput.map(({ deviceId }) => deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there are devices of a specific type.
|
||||
*
|
||||
* @param {Object} state - The state of the application.
|
||||
* @param {string} type - The type of device: VideoOutput | audioOutput | audioInput.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function hasAvailableDevices(state: Object, type: string) {
|
||||
return state['features/base/devices'].availableDevices[type].length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set device id of the audio output device which is currently in use.
|
||||
* Empty string stands for default device.
|
||||
|
||||
@@ -13,6 +13,12 @@ export const CALENDAR_ENABLED = 'calendar.enabled';
|
||||
*/
|
||||
export const CALL_INTEGRATION_ENABLED = 'call-integration.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if chat should be enabled.
|
||||
* Default: enabled (true).
|
||||
*/
|
||||
export const CLOSE_CAPTIONS_ENABLED = 'close-captions.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if chat should be enabled.
|
||||
* Default: enabled (true).
|
||||
|
||||
@@ -49,6 +49,12 @@ const _LANGUAGES = {
|
||||
main: require('../../../../lang/main-esUS')
|
||||
},
|
||||
|
||||
// Estonian
|
||||
'et': {
|
||||
languages: require('../../../../lang/languages-et'),
|
||||
main: require('../../../../lang/main-et')
|
||||
},
|
||||
|
||||
// Finnish
|
||||
'fi': {
|
||||
languages: require('../../../../lang/languages-fi'),
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="10" height="6" viewBox="0 0 10 6" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.07001 0.248238C8.3471 -0.0596449 8.82132 -0.0846038 9.1292 0.192491C9.43709 0.469585 9.46205 0.943802 9.18495 1.25168L5.65622 5.19348C5.35829 5.52451 4.83922 5.52451 4.54128 5.19348L1.06752 1.25168C0.79043 0.943802 0.81539 0.469585 1.12327 0.192491C1.43115 -0.0846038 1.90537 -0.0596449 2.18247 0.248238L5.09875 3.57062L8.07001 0.248238Z" fill="#5E6D7A"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 509 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 14.6667C4.3181 14.6667 1.33333 11.682 1.33333 8.00007C1.33333 4.31817 4.3181 1.3334 8 1.3334C11.6819 1.3334 14.6667 4.31817 14.6667 8.00007C14.6667 11.682 11.6819 14.6667 8 14.6667ZM7.33333 4.66676C7.33333 4.29857 7.6318 4.00009 8 4.00009C8.36819 4.00009 8.66666 4.29857 8.66666 4.66676V8.00009C8.66666 8.36828 8.36819 8.66676 8 8.66676C7.6318 8.66676 7.33333 8.36828 7.33333 8.00009V4.66676ZM8 10.0001C7.63181 10.0001 7.33333 10.2985 7.33333 10.6667C7.33333 11.0349 7.63181 11.3334 8 11.3334C8.36818 11.3334 8.66666 11.0349 8.66666 10.6667C8.66666 10.2985 8.36818 10.0001 8 10.0001Z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 731 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.33331 8.00004C1.33331 11.6819 4.31808 14.6667 7.99998 14.6667C11.6819 14.6667 14.6666 11.6819 14.6666 8.00004C14.6666 4.31814 11.6819 1.33337 7.99998 1.33337C4.31808 1.33337 1.33331 4.31814 1.33331 8.00004ZM13.3333 8.00005C13.3333 10.9456 10.9455 13.3334 7.99998 13.3334C5.05446 13.3334 2.66665 10.9456 2.66665 8.00005C2.66665 5.05453 5.05446 2.66672 7.99998 2.66672C10.9455 2.66672 13.3333 5.05453 13.3333 8.00005ZM7.33331 4.66673C7.33331 4.29854 7.63179 4.00006 7.99998 4.00006C8.36817 4.00006 8.66665 4.29854 8.66665 4.66673V8.00006C8.66665 8.36825 8.36817 8.66673 7.99998 8.66673C7.63179 8.66673 7.33331 8.36825 7.33331 8.00006V4.66673ZM7.99998 10C7.63179 10 7.33331 10.2985 7.33331 10.6667C7.33331 11.0349 7.63179 11.3334 7.99998 11.3334C8.36817 11.3334 8.66665 11.0349 8.66665 10.6667C8.66665 10.2985 8.36817 10 7.99998 10Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1001 B |
@@ -3,7 +3,6 @@
|
||||
export { default as IconAdd } from './add.svg';
|
||||
export { default as IconAddPeople } from './link.svg';
|
||||
export { default as IconArrowBack } from './arrow_back.svg';
|
||||
export { default as IconArrowDown } from './arrow_down.svg';
|
||||
export { default as IconAudioOnly } from './visibility.svg';
|
||||
export { default as IconAudioOnlyOff } from './visibility-off.svg';
|
||||
export { default as IconAudioRoute } from './volume.svg';
|
||||
@@ -28,8 +27,6 @@ export { default as IconDominantSpeaker } from './dominant-speaker.svg';
|
||||
export { default as IconDownload } from './download.svg';
|
||||
export { default as IconDragHandle } from './drag-handle.svg';
|
||||
export { default as IconEventNote } from './event_note.svg';
|
||||
export { default as IconExclamation } from './exclamation.svg';
|
||||
export { default as IconExclamationSolid } from './exclamation-solid.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';
|
||||
@@ -44,10 +41,8 @@ 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 IconMeter } from './meter.svg';
|
||||
export { default as IconMicDisabled } from './mic-disabled.svg';
|
||||
export { default as IconMicrophone } from './microphone.svg';
|
||||
export { default as IconMicrophoneEmpty } from './microphone-empty.svg';
|
||||
export { default as IconModerator } from './star.svg';
|
||||
export { default as IconMuteEveryone } from './mute-everyone.svg';
|
||||
export { default as IconMuteEveryoneElse } from './mute-everyone-else.svg';
|
||||
@@ -69,6 +64,7 @@ export { default as IconSettings } from './settings.svg';
|
||||
export { default as IconSignalLevel0 } from './signal_cellular_0.svg';
|
||||
export { default as IconSignalLevel1 } from './signal_cellular_1.svg';
|
||||
export { default as IconSignalLevel2 } from './signal_cellular_2.svg';
|
||||
export { default as IconShare } from './share.svg';
|
||||
export { default as IconShareDesktop } from './share-desktop.svg';
|
||||
export { default as IconShareDoc } from './share-doc.svg';
|
||||
export { default as IconShareVideo } from './shared-video.svg';
|
||||
@@ -80,4 +76,3 @@ export { default as IconVideoQualityHD } from './HD.svg';
|
||||
export { default as IconVideoQualityLD } from './LD.svg';
|
||||
export { default as IconVideoQualitySD } from './SD.svg';
|
||||
export { default as IconVolume } from './volume.svg';
|
||||
export { default as IconVolumeEmpty } from './volume-empty.svg';
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<svg width="38" height="12" viewBox="0 0 38 12" fill="#5E6D7A" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="3" height="12" rx="1"/>
|
||||
<rect x="5" width="3" height="12" rx="1" />
|
||||
<rect x="10" width="3" height="12" rx="1" />
|
||||
<rect x="15" width="3" height="12" rx="1" />
|
||||
<rect x="20" width="3" height="12" rx="1" />
|
||||
<rect x="25" width="3" height="12" rx="1" />
|
||||
<rect x="30" width="3" height="12" rx="1" />
|
||||
<rect x="35" width="3" height="12" rx="1" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 457 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="M16 6C16 3.79086 14.2091 2 12 2C9.79086 2 8 3.79086 8 6V12C8 13.8666 9.27853 15.4346 11.0076 15.8759C11.0026 15.9166 11 15.958 11 16V17.917C8.16229 17.441 6 14.973 6 12C6 11.4477 5.55228 11 5 11C4.44772 11 4 11.4477 4 12C4 16.0796 7.05369 19.446 11 19.9381V21C11 21.5523 11.4477 22 12 22C12.5523 22 13 21.5523 13 21V19.9381C16.9463 19.446 20 16.0796 20 12C20 11.4477 19.5523 11 19 11C18.4477 11 18 11.4477 18 12C18 14.973 15.8377 17.441 13 17.917V16C13 15.958 12.9974 15.9166 12.9924 15.8759C14.7215 15.4346 16 13.8666 16 12V6ZM12 4C10.8954 4 10 4.89543 10 6V12C10 13.1046 10.8954 14 12 14C13.1046 14 14 13.1046 14 12V6C14 4.89543 13.1046 4 12 4Z" fill="#A4B8D1"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 817 B |
1
react/features/base/icons/svg/share.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" enable-background="new 0 0 50 50"><path d="M30.3 13.7L25 8.4l-5.3 5.3-1.4-1.4L25 5.6l6.7 6.7z"/><path d="M24 7h2v21h-2z"/><path d="M35 40H15c-1.7 0-3-1.3-3-3V19c0-1.7 1.3-3 3-3h7v2h-7c-.6 0-1 .4-1 1v18c0 .6.4 1 1 1h20c.6 0 1-.4 1-1V19c0-.6-.4-1-1-1h-7v-2h7c1.7 0 3 1.3 3 3v18c0 1.7-1.3 3-3 3z"/></svg>
|
||||
|
After Width: | Height: | Size: 361 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.1799 3.68341L6 8H3C2.44772 8 2 8.44771 2 9V15C2 15.5523 2.44772 16 3 16H6L11.1799 20.3166C11.2698 20.3915 11.383 20.4325 11.5 20.4325C11.7761 20.4325 12 20.2086 12 19.9325V4.06752C12 3.95055 11.959 3.83728 11.8841 3.74743C11.7073 3.53529 11.392 3.50662 11.1799 3.68341ZM4 10H6.7241L10 7.27008V16.7299L6.7241 14H4V10ZM14 8C16.2091 8 18 9.79086 18 12C18 14.2091 16.2091 16 14 16V14C15.1046 14 16 13.1046 16 12C16 10.8954 15.1046 10 14 10V8ZM14 4C18.4183 4 22 7.58172 22 12C22 16.4183 18.4183 20 14 20V18C17.3137 18 20 15.3137 20 12C20 8.68629 17.3137 6 14 6V4Z" fill="#A4B8D1"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 733 B |
@@ -39,7 +39,7 @@ export function createLocalTrack(type: string, deviceId: string) {
|
||||
export function isAnalyticsEnabled(stateful: Function | Object) {
|
||||
const { disableThirdPartyRequests, analytics = {} } = toState(stateful)['features/base/config'];
|
||||
|
||||
return !disableThirdPartyRequests && !analytics.disabled;
|
||||
return !(disableThirdPartyRequests || analytics.disabled);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -343,7 +343,9 @@ function _participantJoinedOrUpdated({ dispatch, getState }, next, action) {
|
||||
// to the new avatar and emit out change events if necessary.
|
||||
const result = next(action);
|
||||
|
||||
if (avatarURL || email || id || name) {
|
||||
const { disableThirdPartyRequests } = getState()['features/base/config'];
|
||||
|
||||
if (!disableThirdPartyRequests && (avatarURL || email || id || name)) {
|
||||
const participantId = !id && local ? getLocalParticipant(getState()).id : id;
|
||||
const updatedParticipant = getParticipantById(getState(), participantId);
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
import { isIconUrl } from './functions';
|
||||
|
||||
declare var config: Object;
|
||||
|
||||
/**
|
||||
* Tries to preload an image.
|
||||
*
|
||||
@@ -16,10 +14,6 @@ export function preloadImage(src: string | Object): Promise<string> {
|
||||
return Promise.resolve(src);
|
||||
}
|
||||
|
||||
if (typeof config === 'object' && config.disableThirdPartyRequests) {
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const image = document.createElement('img');
|
||||
|
||||
|
||||
@@ -2,36 +2,6 @@
|
||||
|
||||
export * from './functions.any';
|
||||
|
||||
/**
|
||||
* Returns the deviceId for the currently used camera.
|
||||
*
|
||||
* @param {Object} state - The state of the application.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function getCurrentCameraDeviceId(state: Object) {
|
||||
return state['features/base/settings'].cameraDeviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the deviceId for the currently used microphone.
|
||||
*
|
||||
* @param {Object} state - The state of the application.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function getCurrentMicDeviceId(state: Object) {
|
||||
return state['features/base/settings'].micDeviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the deviceId for the currently used speaker.
|
||||
*
|
||||
* @param {Object} state - The state of the application.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function getCurrentOutputDeviceId(state: Object) {
|
||||
return state['features/base/settings'].audioOutputDeviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles changes to the `disableCallIntegration` setting.
|
||||
* Noop on web.
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Icon } from '../../icons';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The decorated component (ToolboxButton).
|
||||
*/
|
||||
children: React$Node,
|
||||
|
||||
/**
|
||||
* Icon of the button.
|
||||
*/
|
||||
icon: Function,
|
||||
|
||||
/**
|
||||
* Flag used for disabling the small icon.
|
||||
*/
|
||||
iconDisabled: boolean,
|
||||
|
||||
/**
|
||||
* Click handler for the small icon.
|
||||
*/
|
||||
onIconClick: Function,
|
||||
|
||||
/**
|
||||
* Additional styles.
|
||||
*/
|
||||
styles?: Object,
|
||||
}
|
||||
|
||||
/**
|
||||
* Displayes the `ToolboxButtonWithIcon` component.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
export default function ToolboxButtonWithIcon({
|
||||
children,
|
||||
icon,
|
||||
iconDisabled,
|
||||
onIconClick,
|
||||
styles
|
||||
}: Props) {
|
||||
const iconProps = {};
|
||||
|
||||
if (iconDisabled) {
|
||||
iconProps.className = 'settings-button-small-icon settings-button-small-icon--disabled';
|
||||
} else {
|
||||
iconProps.className = 'settings-button-small-icon';
|
||||
iconProps.onClick = onIconClick;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className = 'settings-button-container'
|
||||
styles = { styles }>
|
||||
{ children }
|
||||
<Icon
|
||||
{ ...iconProps }
|
||||
size = { 9 }
|
||||
src = { icon } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -7,4 +7,3 @@ export { default as AbstractHangupButton } from './AbstractHangupButton';
|
||||
export { default as AbstractVideoMuteButton } from './AbstractVideoMuteButton';
|
||||
export { default as BetaTag } from './BetaTag';
|
||||
export { default as OverflowMenuItem } from './OverflowMenuItem';
|
||||
export { default as ToolboxButtonWithIcon } from './ToolboxButtonWithIcon';
|
||||
|
||||
@@ -76,12 +76,12 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
} else {
|
||||
// Sending the message if privacy notice doesn't need to be shown.
|
||||
|
||||
if (typeof APP !== 'undefined') {
|
||||
APP.API.notifySendingChatMessage(action.message);
|
||||
}
|
||||
|
||||
const { privateMessageRecipient } = state['features/chat'];
|
||||
|
||||
if (typeof APP !== 'undefined') {
|
||||
APP.API.notifySendingChatMessage(action.message, Boolean(privateMessageRecipient));
|
||||
}
|
||||
|
||||
if (privateMessageRecipient) {
|
||||
conference.sendPrivateTextMessage(privateMessageRecipient.id, action.message);
|
||||
_persistSentPrivateMessage(store, privateMessageRecipient.id, action.message);
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
sendAnalytics
|
||||
} from '../../../analytics';
|
||||
import { Icon, IconMenuDown, IconMenuUp } from '../../../base/icons';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { dockToolbox } from '../../../toolbox';
|
||||
|
||||
@@ -87,7 +88,12 @@ type Props = {
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Dispatch<any>
|
||||
dispatch: Dispatch<any>,
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: Function
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -338,10 +344,12 @@ class Filmstrip extends Component <Props> {
|
||||
*/
|
||||
_renderToggleButton() {
|
||||
const icon = this.props._visible ? IconMenuDown : IconMenuUp;
|
||||
const { t } = this.props;
|
||||
|
||||
return (
|
||||
<div className = 'filmstrip__toolbar'>
|
||||
<button
|
||||
aria-label = { t('toolbar.accessibilityLabel.toggleFilmstrip') }
|
||||
id = 'toggleFilmstripButton'
|
||||
onClick = { this._onToolbarToggleFilmstrip }>
|
||||
<Icon src = { icon } />
|
||||
@@ -387,4 +395,4 @@ function _mapStateToProps(state) {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(Filmstrip);
|
||||
export default translate(connect(_mapStateToProps)(Filmstrip));
|
||||
|
||||
@@ -13,9 +13,18 @@ import {
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../../base/color-scheme';
|
||||
import { AlertDialog, openDialog } from '../../../../base/dialog';
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { Icon, IconCancelSelection, IconCheck, IconClose, IconPhone, IconSearch } from '../../../../base/icons';
|
||||
import {
|
||||
Icon,
|
||||
IconCancelSelection,
|
||||
IconCheck,
|
||||
IconClose,
|
||||
IconPhone,
|
||||
IconSearch,
|
||||
IconShare
|
||||
} from '../../../../base/icons';
|
||||
import {
|
||||
AvatarListItem,
|
||||
HeaderWithNavigation,
|
||||
@@ -23,6 +32,7 @@ import {
|
||||
type Item
|
||||
} from '../../../../base/react';
|
||||
import { connect } from '../../../../base/redux';
|
||||
import { beginShareRoom } from '../../../../share-room';
|
||||
|
||||
import { setAddPeopleDialogVisible } from '../../../actions.native';
|
||||
|
||||
@@ -39,6 +49,11 @@ import styles, {
|
||||
|
||||
type Props = AbstractProps & {
|
||||
|
||||
/**
|
||||
* The color schemed style of the Header.
|
||||
*/
|
||||
_headerStyles: Object,
|
||||
|
||||
/**
|
||||
* True if the invite dialog should be open, false otherwise.
|
||||
*/
|
||||
@@ -113,6 +128,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
||||
this._onCloseAddPeopleDialog = this._onCloseAddPeopleDialog.bind(this);
|
||||
this._onInvite = this._onInvite.bind(this);
|
||||
this._onPressItem = this._onPressItem.bind(this);
|
||||
this._onShareMeeting = this._onShareMeeting.bind(this);
|
||||
this._onTypeQuery = this._onTypeQuery.bind(this);
|
||||
this._setFieldRef = this._setFieldRef.bind(this);
|
||||
}
|
||||
@@ -137,7 +153,8 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
||||
render() {
|
||||
const {
|
||||
_addPeopleEnabled,
|
||||
_dialOutEnabled
|
||||
_dialOutEnabled,
|
||||
_headerStyles
|
||||
} = this.props;
|
||||
const { inviteItems, selectableItems } = this.state;
|
||||
|
||||
@@ -206,6 +223,9 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
||||
renderItem = { this._renderItem } />
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
<SafeAreaView style = { [ styles.bottomBar, _headerStyles.headerOverlay ] }>
|
||||
{ this._renderShareMeetingButton() }
|
||||
</SafeAreaView>
|
||||
</KeyboardAvoidingView>
|
||||
</SlidingView>
|
||||
);
|
||||
@@ -349,6 +369,22 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
_onShareMeeting: () => void
|
||||
|
||||
/**
|
||||
* Shows the system share sheet to share the meeting information.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_onShareMeeting() {
|
||||
if (this.state.inviteItems.length > 0) {
|
||||
// The use probably intended to invite people.
|
||||
this._onInvite();
|
||||
} else {
|
||||
this.props.dispatch(beginShareRoom());
|
||||
}
|
||||
}
|
||||
|
||||
_onTypeQuery: string => void
|
||||
|
||||
/**
|
||||
@@ -526,6 +562,24 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a button to share the meeting info.
|
||||
*
|
||||
* @returns {React#Element<*>}
|
||||
*/
|
||||
_renderShareMeetingButton() {
|
||||
const { _headerStyles } = this.props;
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress = { this._onShareMeeting }>
|
||||
<Icon
|
||||
src = { IconShare }
|
||||
style = { [ _headerStyles.headerButtonText, styles.shareIcon ] } />
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
|
||||
_setFieldRef: ?TextInput => void
|
||||
|
||||
/**
|
||||
@@ -567,6 +621,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
||||
function _mapStateToProps(state: Object) {
|
||||
return {
|
||||
..._abstractMapStateToProps(state),
|
||||
_headerStyles: ColorSchemeRegistry.get(state, 'Header'),
|
||||
_isVisible: state['features/invite'].inviteDialogVisible
|
||||
};
|
||||
}
|
||||
|
||||
@@ -23,6 +23,12 @@ export default {
|
||||
flex: 1
|
||||
},
|
||||
|
||||
bottomBar: {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-around'
|
||||
},
|
||||
|
||||
clearButton: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
@@ -124,6 +130,10 @@ export default {
|
||||
width: ICON_SIZE + 16
|
||||
},
|
||||
|
||||
shareIcon: {
|
||||
fontSize: 42
|
||||
},
|
||||
|
||||
unselectIcon: {
|
||||
color: LIGHT_GREY,
|
||||
fontSize: 16,
|
||||
|
||||
@@ -40,6 +40,16 @@ type Props = {
|
||||
*/
|
||||
_bottomSheetStyles: StyleType,
|
||||
|
||||
/**
|
||||
* Whether or not to display the kick button.
|
||||
*/
|
||||
_disableKick: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not to display the remote mute buttons.
|
||||
*/
|
||||
_disableRemoteMute: boolean,
|
||||
|
||||
/**
|
||||
* True if the menu is currently open, false otherwise.
|
||||
*/
|
||||
@@ -75,7 +85,7 @@ class RemoteVideoMenu extends Component<Props> {
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
const { participant } = this.props;
|
||||
const { _disableKick, _disableRemoteMute, participant } = this.props;
|
||||
const buttonProps = {
|
||||
afterClick: this._onCancel,
|
||||
showLabel: true,
|
||||
@@ -83,6 +93,19 @@ class RemoteVideoMenu extends Component<Props> {
|
||||
styles: this.props._bottomSheetStyles.buttons
|
||||
};
|
||||
|
||||
const buttons = [];
|
||||
|
||||
if (!_disableRemoteMute) {
|
||||
buttons.push(<MuteButton { ...buttonProps } />);
|
||||
}
|
||||
|
||||
if (!_disableKick) {
|
||||
buttons.push(<KickButton { ...buttonProps } />);
|
||||
}
|
||||
|
||||
buttons.push(<PinButton { ...buttonProps } />);
|
||||
buttons.push(<PrivateMessageButton { ...buttonProps } />);
|
||||
|
||||
return (
|
||||
<BottomSheet onCancel = { this._onCancel }>
|
||||
<View style = { styles.participantNameContainer }>
|
||||
@@ -93,10 +116,7 @@ class RemoteVideoMenu extends Component<Props> {
|
||||
{ this.props._participantDisplayName }
|
||||
</Text>
|
||||
</View>
|
||||
<MuteButton { ...buttonProps } />
|
||||
<KickButton { ...buttonProps } />
|
||||
<PinButton { ...buttonProps } />
|
||||
<PrivateMessageButton { ...buttonProps } />
|
||||
{ buttons }
|
||||
</BottomSheet>
|
||||
);
|
||||
}
|
||||
@@ -130,13 +150,15 @@ class RemoteVideoMenu extends Component<Props> {
|
||||
*/
|
||||
function _mapStateToProps(state, ownProps) {
|
||||
const { participant } = ownProps;
|
||||
const { remoteVideoMenu = {}, disableRemoteMute } = state['features/base/config'];
|
||||
const { disableKick } = remoteVideoMenu;
|
||||
|
||||
return {
|
||||
_bottomSheetStyles:
|
||||
ColorSchemeRegistry.get(state, 'BottomSheet'),
|
||||
_bottomSheetStyles: ColorSchemeRegistry.get(state, 'BottomSheet'),
|
||||
_disableKick: Boolean(disableKick),
|
||||
_disableRemoteMute: Boolean(disableRemoteMute),
|
||||
_isOpen: isDialogOpen(state, RemoteVideoMenu_),
|
||||
_participantDisplayName: getParticipantDisplayName(
|
||||
state, participant.id)
|
||||
_participantDisplayName: getParticipantDisplayName(state, participant.id)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,16 @@ declare var interfaceConfig: Object;
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Whether or not to display the kick button.
|
||||
*/
|
||||
_disableKick: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not to display the remote mute buttons.
|
||||
*/
|
||||
_disableRemoteMute: Boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the participant is a conference moderator.
|
||||
*/
|
||||
@@ -157,6 +167,8 @@ class RemoteVideoMenuTriggerButton extends Component<Props> {
|
||||
*/
|
||||
_renderRemoteVideoMenu() {
|
||||
const {
|
||||
_disableKick,
|
||||
_disableRemoteMute,
|
||||
_isModerator,
|
||||
initialVolumeValue,
|
||||
isAudioMuted,
|
||||
@@ -169,22 +181,27 @@ class RemoteVideoMenuTriggerButton extends Component<Props> {
|
||||
const buttons = [];
|
||||
|
||||
if (_isModerator) {
|
||||
buttons.push(
|
||||
<MuteButton
|
||||
isAudioMuted = { isAudioMuted }
|
||||
key = 'mute'
|
||||
participantID = { participantID } />
|
||||
);
|
||||
buttons.push(
|
||||
<MuteEveryoneElseButton
|
||||
key = 'mute-others'
|
||||
participantID = { participantID } />
|
||||
);
|
||||
buttons.push(
|
||||
<KickButton
|
||||
key = 'kick'
|
||||
participantID = { participantID } />
|
||||
);
|
||||
if (!_disableRemoteMute) {
|
||||
buttons.push(
|
||||
<MuteButton
|
||||
isAudioMuted = { isAudioMuted }
|
||||
key = 'mute'
|
||||
participantID = { participantID } />
|
||||
);
|
||||
buttons.push(
|
||||
<MuteEveryoneElseButton
|
||||
key = 'mute-others'
|
||||
participantID = { participantID } />
|
||||
);
|
||||
}
|
||||
|
||||
if (!_disableKick) {
|
||||
buttons.push(
|
||||
<KickButton
|
||||
key = 'kick'
|
||||
participantID = { participantID } />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (remoteControlState) {
|
||||
@@ -236,9 +253,13 @@ class RemoteVideoMenuTriggerButton extends Component<Props> {
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
const participant = getLocalParticipant(state);
|
||||
const { remoteVideoMenu = {}, disableRemoteMute } = state['features/base/config'];
|
||||
const { disableKick } = remoteVideoMenu;
|
||||
|
||||
return {
|
||||
_isModerator: Boolean(participant?.role === PARTICIPANT_ROLE.MODERATOR)
|
||||
_isModerator: Boolean(participant?.role === PARTICIPANT_ROLE.MODERATOR),
|
||||
_disableKick: Boolean(disableKick),
|
||||
_disableRemoteMute: Boolean(disableRemoteMute)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// The type of (redux) action which sets the visibility of the audio settings popup.
|
||||
export const SET_AUDIO_SETTINGS_VISIBILITY = 'SET_AUDIO_SETTINGS_VISIBILITY';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which sets the visibility of the view/UI rendering
|
||||
* the app's settings.
|
||||
@@ -11,6 +8,3 @@ export const SET_AUDIO_SETTINGS_VISIBILITY = 'SET_AUDIO_SETTINGS_VISIBILITY';
|
||||
* }
|
||||
*/
|
||||
export const SET_SETTINGS_VIEW_VISIBLE = 'SET_SETTINGS_VIEW_VISIBLE';
|
||||
|
||||
// The type of (redux) action which sets the visibility of the video settings popup.
|
||||
export const SET_VIDEO_SETTINGS_VISIBILITY = 'SET_VIDEO_SETTINGS_VISIBILITY';
|
||||
|
||||
@@ -4,11 +4,7 @@ import { setFollowMe, setStartMutedPolicy } from '../base/conference';
|
||||
import { openDialog } from '../base/dialog';
|
||||
import { i18next } from '../base/i18n';
|
||||
|
||||
import {
|
||||
SET_AUDIO_SETTINGS_VISIBILITY,
|
||||
SET_SETTINGS_VIEW_VISIBLE,
|
||||
SET_VIDEO_SETTINGS_VISIBILITY
|
||||
} from './actionTypes';
|
||||
import { SET_SETTINGS_VIEW_VISIBLE } from './actionTypes';
|
||||
import { SettingsDialog } from './components';
|
||||
import { getMoreTabProps, getProfileTabProps } from './functions';
|
||||
|
||||
@@ -42,31 +38,6 @@ export function openSettingsDialog(defaultTab: string) {
|
||||
return openDialog(SettingsDialog, { defaultTab });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visiblity of the audio settings.
|
||||
*
|
||||
* @param {boolean} value - The new value.
|
||||
* @returns {Function}
|
||||
*/
|
||||
function setAudioSettingsVisibility(value: boolean) {
|
||||
return {
|
||||
type: SET_AUDIO_SETTINGS_VISIBILITY,
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visiblity of the video settings.
|
||||
*
|
||||
* @param {boolean} value - The new value.
|
||||
* @returns {Function}
|
||||
*/
|
||||
function setVideoSettingsVisibility(value: boolean) {
|
||||
return {
|
||||
type: SET_VIDEO_SETTINGS_VISIBILITY,
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the settings from the "More" tab of the settings dialog.
|
||||
@@ -113,29 +84,3 @@ export function submitProfileTab(newState: Object): Function {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the visiblity of the audio settings.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
export function toggleAudioSettings() {
|
||||
return (dispatch: Function, getState: Function) => {
|
||||
const value = getState()['features/settings'].audioSettingsVisible;
|
||||
|
||||
dispatch(setAudioSettingsVisibility(!value));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the visiblity of the video settings.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
export function toggleVideoSettings() {
|
||||
return (dispatch: Function, getState: Function) => {
|
||||
const value = getState()['features/settings'].videoSettingsVisible;
|
||||
|
||||
dispatch(setVideoSettingsVisibility(!value));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -127,11 +127,9 @@ class SettingsDialog extends Component<Props> {
|
||||
function _mapStateToProps(state) {
|
||||
const configuredTabs = interfaceConfig.SETTINGS_SECTIONS || [];
|
||||
const jwt = state['features/base/jwt'];
|
||||
const { prejoinPageEnabled } = state['features/base/config'];
|
||||
|
||||
// The settings sections to display.
|
||||
const showDeviceSettings = !prejoinPageEnabled
|
||||
&& configuredTabs.includes('devices');
|
||||
const showDeviceSettings = configuredTabs.includes('devices');
|
||||
const moreTabProps = getMoreTabProps(state);
|
||||
const { showModeratorSettings, showLanguageSettings } = moreTabProps;
|
||||
const showProfileSettings
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import AudioSettingsHeader from './AudioSettingsHeader';
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { IconMicrophoneEmpty, IconVolumeEmpty } from '../../../../base/icons';
|
||||
import { createLocalAudioTrack } from '../../../functions';
|
||||
import MicrophoneEntry from './MicrophoneEntry';
|
||||
import SpeakerEntry from './SpeakerEntry';
|
||||
|
||||
export type Props = {
|
||||
|
||||
/**
|
||||
* The deviceId of the microphone in use.
|
||||
*/
|
||||
currentMicDeviceId: string,
|
||||
|
||||
/**
|
||||
* The deviceId of the output device in use.
|
||||
*/
|
||||
currentOutputDeviceId: string,
|
||||
|
||||
/**
|
||||
* Used to set a new microphone as the current one.
|
||||
*/
|
||||
setAudioInputDevice: Function,
|
||||
|
||||
/**
|
||||
* Used to set a new output device as the current one.
|
||||
*/
|
||||
setAudioOutputDevice: Function,
|
||||
|
||||
/**
|
||||
* A list of objects containing the labels and deviceIds
|
||||
* of all the output devices.
|
||||
*/
|
||||
outputDevices: Object[],
|
||||
|
||||
/**
|
||||
* A list with objects containing the labels and deviceIds
|
||||
* of all the input devices.
|
||||
*/
|
||||
microphoneDevices: Object[],
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: Function
|
||||
};
|
||||
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* An object containing the jitsiTrack and the error (if the case)
|
||||
* for the microphone that is in use.
|
||||
*/
|
||||
currentMicData: Object
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a React {@link Component} which displayes a list of all
|
||||
* the audio input & output devices to choose from.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
class AudioSettingsContent extends Component<Props, State> {
|
||||
_componentWasUnmounted: boolean;
|
||||
|
||||
/**
|
||||
* Initializes a new {@code AudioSettingsContent} instance.
|
||||
*
|
||||
* @param {Object} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this._onMicrophoneEntryClick = this._onMicrophoneEntryClick.bind(this);
|
||||
this._onSpeakerEntryClick = this._onSpeakerEntryClick.bind(this);
|
||||
|
||||
this.state = {
|
||||
currentMicData: {
|
||||
error: false,
|
||||
jitsiTrack: null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_onMicrophoneEntryClick: (string) => void;
|
||||
|
||||
/**
|
||||
* Click handler for the microphone entries.
|
||||
*
|
||||
* @param {string} deviceId - The deviceId for the clicked microphone.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onMicrophoneEntryClick(deviceId) {
|
||||
this.props.setAudioInputDevice(deviceId);
|
||||
}
|
||||
|
||||
_onSpeakerEntryClick: (string) => void;
|
||||
|
||||
/**
|
||||
* Click handler for the speaker entries.
|
||||
*
|
||||
* @param {string} deviceId - The deviceId for the clicked speaker.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onSpeakerEntryClick(deviceId) {
|
||||
this.props.setAudioOutputDevice(deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a single microphone entry.
|
||||
*
|
||||
* @param {Object} data - An object with the deviceId and label of the microphone.
|
||||
* @param {number} index - The index of the element, used for creating a key.
|
||||
* @returns {React$Node}
|
||||
*/
|
||||
_renderMicrophoneEntry(data, index) {
|
||||
const { deviceId, label } = data;
|
||||
const key = `me-${index}`;
|
||||
const isSelected = deviceId === this.props.currentMicDeviceId;
|
||||
let jitsiTrack = null;
|
||||
let hasError = false;
|
||||
|
||||
if (isSelected) {
|
||||
({ jitsiTrack, hasError } = this.state.currentMicData);
|
||||
}
|
||||
|
||||
return (
|
||||
<MicrophoneEntry
|
||||
deviceId = { deviceId }
|
||||
hasError = { hasError }
|
||||
isSelected = { isSelected }
|
||||
jitsiTrack = { jitsiTrack }
|
||||
key = { key }
|
||||
onClick = { this._onMicrophoneEntryClick }>
|
||||
{label}
|
||||
</MicrophoneEntry>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a single speaker entry.
|
||||
*
|
||||
* @param {Object} data - An object with the deviceId and label of the speaker.
|
||||
* @param {number} index - The index of the element, used for creating a key.
|
||||
* @returns {React$Node}
|
||||
*/
|
||||
_renderSpeakerEntry(data, index) {
|
||||
const { deviceId, label } = data;
|
||||
const key = `se-${index}`;
|
||||
|
||||
return (
|
||||
<SpeakerEntry
|
||||
deviceId = { deviceId }
|
||||
isSelected = { deviceId === this.props.currentOutputDeviceId }
|
||||
key = { key }
|
||||
onClick = { this._onSpeakerEntryClick }>
|
||||
{label}
|
||||
</SpeakerEntry>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the audio track for a given micData object.
|
||||
*
|
||||
* @param {Object} micData - The object holding the track.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
_disposeTrack(micData) {
|
||||
const { jitsiTrack } = micData;
|
||||
|
||||
return jitsiTrack ? jitsiTrack.dispose() : Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current microphone data.
|
||||
* Disposes previously created track and creates a new one.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
async _updateCurrentMicData() {
|
||||
await this._disposeTrack(this.state.currentMicData);
|
||||
|
||||
const currentMicData = await createLocalAudioTrack(
|
||||
this.props.currentMicDeviceId,
|
||||
);
|
||||
|
||||
// In case the component gets unmounted before the track is created
|
||||
// avoid a leak by not setting the state
|
||||
if (this._componentWasUnmounted) {
|
||||
this._disposeTrack(currentMicData);
|
||||
} else {
|
||||
this.setState({
|
||||
currentMicData
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentDidUpdate}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.currentMicDeviceId !== this.props.currentMicDeviceId) {
|
||||
this._updateCurrentMicData();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentDidMount}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidMount() {
|
||||
this._updateCurrentMicData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentWillUnmount}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
this._componentWasUnmounted = true;
|
||||
this._disposeTrack(this.state.currentMicData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
const { microphoneDevices, outputDevices, t } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className = 'audio-preview-content'>
|
||||
<AudioSettingsHeader
|
||||
IconComponent = { IconMicrophoneEmpty }
|
||||
text = { t('settings.selectMic') } />
|
||||
{microphoneDevices.map((data, i) =>
|
||||
this._renderMicrophoneEntry(data, i),
|
||||
)}
|
||||
<AudioSettingsHeader
|
||||
IconComponent = { IconVolumeEmpty }
|
||||
text = { t('settings.speakers') } />
|
||||
{outputDevices.map((data, i) =>
|
||||
this._renderSpeakerEntry(data, i),
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(AudioSettingsContent);
|
||||
@@ -1,53 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Icon, IconCheck, IconExclamationSolid } from '../../../../base/icons';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link AudioSettingsEntry}.
|
||||
*/
|
||||
export type Props = {
|
||||
|
||||
/**
|
||||
* The text for this component.
|
||||
*/
|
||||
children: React$Node,
|
||||
|
||||
/**
|
||||
* Flag indicating an error.
|
||||
*/
|
||||
hasError?: boolean,
|
||||
|
||||
/**
|
||||
* Flag indicating the selection state.
|
||||
*/
|
||||
isSelected: boolean,
|
||||
};
|
||||
|
||||
/**
|
||||
* React {@code Component} representing an entry for the audio settings.
|
||||
*
|
||||
* @returns { ReactElement}
|
||||
*/
|
||||
export default function AudioSettingsEntry({ children, hasError, isSelected }: Props) {
|
||||
const className = `audio-preview-entry ${isSelected
|
||||
? 'audio-preview-entry--selected' : ''}`;
|
||||
|
||||
return (
|
||||
<div className = { className }>
|
||||
{isSelected && (
|
||||
<Icon
|
||||
className = 'audio-preview-icon audio-preview-icon--check'
|
||||
color = '#1C2025'
|
||||
size = { 14 }
|
||||
src = { IconCheck } />
|
||||
)}
|
||||
<span className = 'audio-preview-entry-text'>{children}</span>
|
||||
{hasError && <Icon
|
||||
className = 'audio-preview-icon audio-preview-icon--exclamation'
|
||||
size = { 16 }
|
||||
src = { IconExclamationSolid } />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Icon } from '../../../../base/icons';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link AudioSettingsHeader}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The Icon used for the Header.
|
||||
*/
|
||||
IconComponent: Function,
|
||||
|
||||
/**
|
||||
* The text of the Header.
|
||||
*/
|
||||
text: string,
|
||||
};
|
||||
|
||||
/**
|
||||
* React {@code Component} representing the Header of an audio option group.
|
||||
*
|
||||
* @returns { ReactElement}
|
||||
*/
|
||||
export default function AudioSettingsHeader({ IconComponent, text }: Props) {
|
||||
return (
|
||||
<div className = 'audio-preview-header'>
|
||||
<div className = 'audio-preview-header-icon'>
|
||||
{ <Icon
|
||||
color = '#A4B8D1'
|
||||
size = { 24 }
|
||||
src = { IconComponent } />}
|
||||
</div>
|
||||
<div className = 'audio-preview-header-text'>{text}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import InlineDialog from '@atlaskit/inline-dialog';
|
||||
|
||||
import AudioSettingsContent, { type Props as AudioSettingsContentProps } from './AudioSettingsContent';
|
||||
import { toggleAudioSettings } from '../../../actions';
|
||||
import {
|
||||
getAudioInputDeviceData,
|
||||
getAudioOutputDeviceData,
|
||||
setAudioInputDevice as setAudioInputDeviceAction,
|
||||
setAudioOutputDevice as setAudioOutputDeviceAction
|
||||
} from '../../../../base/devices';
|
||||
import { connect } from '../../../../base/redux';
|
||||
import { getAudioSettingsVisibility } from '../../../functions';
|
||||
import {
|
||||
getCurrentMicDeviceId,
|
||||
getCurrentOutputDeviceId
|
||||
} from '../../../../base/settings';
|
||||
|
||||
|
||||
type Props = AudioSettingsContentProps & {
|
||||
|
||||
/**
|
||||
* Component's children (the audio button).
|
||||
*/
|
||||
children: React$Node,
|
||||
|
||||
/**
|
||||
* Flag controlling the visibility of the popup.
|
||||
*/
|
||||
isOpen: boolean,
|
||||
|
||||
/**
|
||||
* Callback executed when the popup closes.
|
||||
*/
|
||||
onClose: Function,
|
||||
}
|
||||
|
||||
/**
|
||||
* Popup with audio settings.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
function AudioSettingsPopup({
|
||||
children,
|
||||
currentMicDeviceId,
|
||||
currentOutputDeviceId,
|
||||
isOpen,
|
||||
microphoneDevices,
|
||||
setAudioInputDevice,
|
||||
setAudioOutputDevice,
|
||||
onClose,
|
||||
outputDevices
|
||||
}: Props) {
|
||||
return (
|
||||
<div className = 'audio-preview'>
|
||||
<InlineDialog
|
||||
content = { <AudioSettingsContent
|
||||
currentMicDeviceId = { currentMicDeviceId }
|
||||
currentOutputDeviceId = { currentOutputDeviceId }
|
||||
microphoneDevices = { microphoneDevices }
|
||||
outputDevices = { outputDevices }
|
||||
setAudioInputDevice = { setAudioInputDevice }
|
||||
setAudioOutputDevice = { setAudioOutputDevice } /> }
|
||||
isOpen = { isOpen }
|
||||
onClose = { onClose }
|
||||
position = 'top left'>
|
||||
{children}
|
||||
</InlineDialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that maps parts of Redux state tree into component props.
|
||||
*
|
||||
* @param {Object} state - Redux state.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
currentMicDeviceId: getCurrentMicDeviceId(state),
|
||||
currentOutputDeviceId: getCurrentOutputDeviceId(state),
|
||||
isOpen: getAudioSettingsVisibility(state),
|
||||
microphoneDevices: getAudioInputDeviceData(state),
|
||||
outputDevices: getAudioOutputDeviceData(state)
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
onClose: toggleAudioSettings,
|
||||
setAudioInputDevice: setAudioInputDeviceAction,
|
||||
setAudioOutputDevice: setAudioOutputDeviceAction
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AudioSettingsPopup);
|
||||
@@ -1,45 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Icon, IconMeter } from '../../../../base/icons';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Own class name for the component.
|
||||
*/
|
||||
className: string,
|
||||
|
||||
/**
|
||||
* Flag indicating whether the component is greyed out/disabled.
|
||||
*/
|
||||
isDisabled?: boolean,
|
||||
|
||||
/**
|
||||
* The level of the meter.
|
||||
* Should be between 0 and 7 as per the used SVG.
|
||||
*/
|
||||
level: number,
|
||||
};
|
||||
|
||||
/**
|
||||
* React {@code Component} representing an audio level meter.
|
||||
*
|
||||
* @returns { ReactElement}
|
||||
*/
|
||||
export default function({ className, isDisabled, level }: Props) {
|
||||
let ownClassName;
|
||||
|
||||
if (level > -1) {
|
||||
ownClassName = `metr metr-l-${level}`;
|
||||
} else {
|
||||
ownClassName = `metr ${isDisabled ? 'metr--disabled' : ''}`;
|
||||
}
|
||||
|
||||
return (
|
||||
<Icon
|
||||
className = { `${ownClassName} ${className}` }
|
||||
size = { 12 }
|
||||
src = { IconMeter } />
|
||||
);
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import AudioSettingsEntry, { type Props as AudioSettingsEntryProps } from './AudioSettingsEntry';
|
||||
import JitsiMeetJS from '../../../../base/lib-jitsi-meet/_';
|
||||
import Meter from './Meter';
|
||||
|
||||
const JitsiTrackEvents = JitsiMeetJS.events.track;
|
||||
|
||||
type Props = AudioSettingsEntryProps & {
|
||||
|
||||
/**
|
||||
* The deviceId of the microphone.
|
||||
*/
|
||||
deviceId: string,
|
||||
|
||||
/**
|
||||
* Flag indicating if there is a problem with the device.
|
||||
*/
|
||||
hasError?: boolean,
|
||||
|
||||
/**
|
||||
* The audio track for the current entry.
|
||||
*/
|
||||
jitsiTrack: Object,
|
||||
|
||||
/**
|
||||
* Click handler for component.
|
||||
*/
|
||||
onClick: Function,
|
||||
}
|
||||
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* The audio level.
|
||||
*/
|
||||
level: number,
|
||||
}
|
||||
|
||||
/**
|
||||
* React {@code Component} representing an entry for the microphone audio settings.
|
||||
*
|
||||
* @param {Props} props - The props of the component.
|
||||
* @returns { ReactElement}
|
||||
*/
|
||||
export default class MicrophoneEntry extends Component<Props, State> {
|
||||
/**
|
||||
* Initializes a new {@code MicrophoneEntry} instance.
|
||||
*
|
||||
* @param {Object} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
level: -1
|
||||
};
|
||||
this._onClick = this._onClick.bind(this);
|
||||
this._updateLevel = this._updateLevel.bind(this);
|
||||
}
|
||||
|
||||
_onClick: () => void;
|
||||
|
||||
/**
|
||||
* Click handler for the entry.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_onClick() {
|
||||
this.props.onClick(this.props.deviceId);
|
||||
}
|
||||
|
||||
_updateLevel: (number) => void;
|
||||
|
||||
/**
|
||||
* Updates the level of the meter.
|
||||
*
|
||||
* @param {number} num - The audio level provided by the jitsiTrack.
|
||||
* @returns {void}
|
||||
*/
|
||||
_updateLevel(num) {
|
||||
this.setState({
|
||||
level: Math.floor(num / 0.125)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes to audio level chanages comming from the jitsiTrack.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_startListening() {
|
||||
const { jitsiTrack } = this.props;
|
||||
|
||||
jitsiTrack && jitsiTrack.on(
|
||||
JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,
|
||||
this._updateLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribes from chanages comming from the jitsiTrack.
|
||||
*
|
||||
* @param {Object} jitsiTrack - The jitsiTrack to unsubscribe from.
|
||||
* @returns {void}
|
||||
*/
|
||||
_stopListening(jitsiTrack) {
|
||||
jitsiTrack && jitsiTrack.off(
|
||||
JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,
|
||||
this._updateLevel);
|
||||
this.setState({
|
||||
level: -1
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentDidUpdate}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
if (prevProps.jitsiTrack !== this.props.jitsiTrack) {
|
||||
this._stopListening(prevProps.jitsiTrack);
|
||||
this._startListening();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentDidMount}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidMount() {
|
||||
this._startListening();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentWillUnmount}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
compmonentWillUnmount() {
|
||||
this._stopListening(this.props.jitsiTrack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
const { children, hasError, isSelected } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className = 'audio-preview-microphone'
|
||||
onClick = { this._onClick }>
|
||||
<AudioSettingsEntry
|
||||
hasError = { hasError }
|
||||
isSelected = { isSelected }>
|
||||
{children}
|
||||
</AudioSettingsEntry>
|
||||
<Meter
|
||||
className = 'audio-preview-meter-mic'
|
||||
isDisabled = { hasError }
|
||||
level = { this.state.level } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import AudioSettingsEntry from './AudioSettingsEntry';
|
||||
import logger from '../../../logger';
|
||||
import TestButton from './TestButton';
|
||||
|
||||
const TEST_SOUND_PATH = 'sounds/ring.wav';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link SpeakerEntry}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The text label for the entry.
|
||||
*/
|
||||
children: React$Node,
|
||||
|
||||
/**
|
||||
* Flag controlling the selection state of the entry.
|
||||
*/
|
||||
isSelected: boolean,
|
||||
|
||||
/**
|
||||
* The deviceId of the speaker.
|
||||
*/
|
||||
deviceId: string,
|
||||
|
||||
/**
|
||||
* Click handler for the component.
|
||||
*/
|
||||
onClick: Function,
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a React {@link Component} which displays an audio
|
||||
* output settings entry. The user can click and play a test sound.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
export default class SpeakerEntry extends Component<Props> {
|
||||
/**
|
||||
* A React ref to the HTML element containing the {@code audio} instance.
|
||||
*/
|
||||
audioRef: Object;
|
||||
|
||||
/**
|
||||
* Initializes a new {@code SpeakerEntry} instance.
|
||||
*
|
||||
* @param {Object} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.audioRef = React.createRef();
|
||||
this._onTestButtonClick = this._onTestButtonClick.bind(this);
|
||||
this._onClick = this._onClick.bind(this);
|
||||
}
|
||||
|
||||
_onClick: () => void;
|
||||
|
||||
/**
|
||||
* Click handler for the entry.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_onClick() {
|
||||
this.props.onClick(this.props.deviceId);
|
||||
}
|
||||
|
||||
_onTestButtonClick: Object => void;
|
||||
|
||||
/**
|
||||
* Click handler for Test button.
|
||||
* Sets the current audio output id and plays a sound.
|
||||
*
|
||||
* @param {Object} e - The sythetic event.
|
||||
* @returns {void}
|
||||
*/
|
||||
async _onTestButtonClick(e) {
|
||||
e.stopPropagation();
|
||||
|
||||
try {
|
||||
await this.audioRef.current.setSinkId(this.props.deviceId);
|
||||
this.audioRef.current.play();
|
||||
} catch (err) {
|
||||
logger.log('Could not set sink id', err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
const { children, isSelected, deviceId } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className = 'audio-preview-speaker'
|
||||
onClick = { this._onClick }>
|
||||
<AudioSettingsEntry
|
||||
isSelected = { isSelected }
|
||||
key = { deviceId }>
|
||||
{children}
|
||||
</AudioSettingsEntry>
|
||||
<TestButton onClick = { this._onTestButtonClick } />
|
||||
<audio
|
||||
preload = 'auto'
|
||||
ref = { this.audioRef }
|
||||
src = { TEST_SOUND_PATH } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Click handler for the button.
|
||||
*/
|
||||
onClick: Function,
|
||||
};
|
||||
|
||||
/**
|
||||
* React {@code Component} representing an button used for testing output sound.
|
||||
*
|
||||
* @returns { ReactElement}
|
||||
*/
|
||||
export default function TestButton({ onClick }: Props) {
|
||||
return (
|
||||
<div
|
||||
className = 'audio-preview-test-button'
|
||||
onClick = { onClick }>
|
||||
Test
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,2 @@
|
||||
export { default as SettingsButton } from './SettingsButton';
|
||||
export { default as SettingsDialog } from './SettingsDialog';
|
||||
export { default as AudioSettingsPopup } from './audio/AudioSettingsPopup';
|
||||
export { default as VideoSettingsPopup } from './video/VideoSettingsPopup';
|
||||
|
||||
@@ -1,220 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { equals } from '../../../../base/redux';
|
||||
import Video from '../../../../base/media/components/Video';
|
||||
import { createLocalVideoTracks } from '../../../functions';
|
||||
|
||||
|
||||
const videoClassName = 'video-preview-video flipVideoX';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link VideoSettingsContent}.
|
||||
*/
|
||||
export type Props = {
|
||||
|
||||
/**
|
||||
* The deviceId of the camera device currently being used.
|
||||
*/
|
||||
currentCameraDeviceId: string,
|
||||
|
||||
/**
|
||||
* Callback invoked to change current camera.
|
||||
*/
|
||||
setVideoInputDevice: Function,
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: Function,
|
||||
|
||||
/**
|
||||
* Callback invoked to toggle the settings popup visibility.
|
||||
*/
|
||||
toggleVideoSettings: Function,
|
||||
|
||||
/**
|
||||
* All the camera device ids currently connected.
|
||||
*/
|
||||
videoDeviceIds: string[],
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} state of {@link VideoSettingsContent}.
|
||||
*/
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* An array of all the jitsiTracks and eventual errors.
|
||||
*/
|
||||
trackData: Object[],
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a React {@link Component} which displays a list of video
|
||||
* previews to choose from.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
class VideoSettingsContent extends Component<Props, State> {
|
||||
_componentWasUnmounted: boolean;
|
||||
|
||||
/**
|
||||
* Initializes a new {@code VideoSettingsContent} instance.
|
||||
*
|
||||
* @param {Object} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
trackData: new Array(props.videoDeviceIds.length).fill({
|
||||
jitsiTrack: null
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and updates the track data.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
async _setTracks() {
|
||||
this._disposeTracks(this.state.trackData);
|
||||
|
||||
const trackData = await createLocalVideoTracks(
|
||||
this.props.videoDeviceIds,
|
||||
);
|
||||
|
||||
// In case the component gets unmounted before the tracks are created
|
||||
// avoid a leak by not setting the state
|
||||
if (this._componentWasUnmounted) {
|
||||
this._disposeTracks(trackData);
|
||||
} else {
|
||||
this.setState({
|
||||
trackData
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys all the tracks from trackData object.
|
||||
*
|
||||
* @param {Object[]} trackData - An array of tracks that are to be disposed.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
_disposeTracks(trackData) {
|
||||
trackData.forEach(({ jitsiTrack }) => {
|
||||
jitsiTrack && jitsiTrack.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the click handler used when selecting the video preview.
|
||||
*
|
||||
* @param {string} deviceId - The id of the camera device.
|
||||
* @returns {Function}
|
||||
*/
|
||||
_onEntryClick(deviceId) {
|
||||
return () => {
|
||||
this.props.setVideoInputDevice(deviceId);
|
||||
this.props.toggleVideoSettings();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a preview entry.
|
||||
*
|
||||
* @param {Object} data - The track data.
|
||||
* @param {number} index - The index of the entry.
|
||||
* @returns {React$Node}
|
||||
*/
|
||||
_renderPreviewEntry(data, index) {
|
||||
const { error, jitsiTrack, deviceId } = data;
|
||||
const { currentCameraDeviceId, t } = this.props;
|
||||
const isSelected = deviceId === currentCameraDeviceId;
|
||||
const key = `vp-${index}`;
|
||||
const className = 'video-preview-entry';
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div
|
||||
className = { className }
|
||||
key = { key }>
|
||||
<div className = 'video-preview-error'>{t(error)}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const props: Object = {
|
||||
className,
|
||||
key
|
||||
};
|
||||
|
||||
if (isSelected) {
|
||||
props.className = `${className} video-preview-entry--selected`;
|
||||
} else {
|
||||
props.onClick = this._onEntryClick(deviceId);
|
||||
}
|
||||
|
||||
return (
|
||||
<div { ...props }>
|
||||
<div className = 'video-preview-overlay' />
|
||||
<Video
|
||||
className = { videoClassName }
|
||||
videoTrack = {{ jitsiTrack }} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentDidMount}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidMount() {
|
||||
this._setTracks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentWillUnmount}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
this._componentWasUnmounted = true;
|
||||
this._disposeTracks(this.state.trackData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentDidUpdate}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidUpdate(prevProps) {
|
||||
if (!equals(this.props.videoDeviceIds, prevProps.videoDeviceIds)) {
|
||||
this._setTracks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
const { trackData } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{trackData.map((data, i) => this._renderPreviewEntry(data, i))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default translate(VideoSettingsContent);
|
||||
@@ -1,85 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import InlineDialog from '@atlaskit/inline-dialog';
|
||||
|
||||
import { toggleVideoSettings } from '../../../actions';
|
||||
import {
|
||||
getVideoDeviceIds,
|
||||
setVideoInputDevice as setVideoInputDeviceAction
|
||||
} from '../../../../base/devices';
|
||||
import { getVideoSettingsVisibility } from '../../../functions';
|
||||
import { connect } from '../../../../base/redux';
|
||||
import { getCurrentCameraDeviceId } from '../../../../base/settings';
|
||||
import VideoSettingsContent, { type Props as VideoSettingsProps } from './VideoSettingsContent';
|
||||
|
||||
|
||||
type Props = VideoSettingsProps & {
|
||||
|
||||
/**
|
||||
* Component children (the Video button).
|
||||
*/
|
||||
children: React$Node,
|
||||
|
||||
/**
|
||||
* Flag controlling the visibility of the popup.
|
||||
*/
|
||||
isOpen: boolean,
|
||||
|
||||
/**
|
||||
* Callback executed when the popup closes.
|
||||
*/
|
||||
onClose: Function,
|
||||
}
|
||||
|
||||
/**
|
||||
* Popup with a preview of all the video devices.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
function VideoSettingsPopup({
|
||||
currentCameraDeviceId,
|
||||
children,
|
||||
isOpen,
|
||||
onClose,
|
||||
setVideoInputDevice,
|
||||
videoDeviceIds
|
||||
}: Props) {
|
||||
return (
|
||||
<div className = 'video-preview'>
|
||||
<InlineDialog
|
||||
content = { <VideoSettingsContent
|
||||
currentCameraDeviceId = { currentCameraDeviceId }
|
||||
setVideoInputDevice = { setVideoInputDevice }
|
||||
toggleVideoSettings = { onClose }
|
||||
videoDeviceIds = { videoDeviceIds } /> }
|
||||
isOpen = { isOpen }
|
||||
onClose = { onClose }
|
||||
position = 'top right'>
|
||||
{ children }
|
||||
</InlineDialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to the associated {@code VideoSettingsPopup}'s
|
||||
* props.
|
||||
*
|
||||
* @param {Object} state - Redux state.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
currentCameraDeviceId: getCurrentCameraDeviceId(state),
|
||||
isOpen: getVideoSettingsVisibility(state),
|
||||
videoDeviceIds: getVideoDeviceIds(state)
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
onClose: toggleVideoSettings,
|
||||
setVideoInputDevice: setVideoInputDeviceAction
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(VideoSettingsPopup);
|
||||
@@ -2,7 +2,6 @@
|
||||
import { toState } from '../base/redux';
|
||||
import { parseStandardURIString } from '../base/util';
|
||||
import { i18next, DEFAULT_LANGUAGE, LANGUAGES } from '../base/i18n';
|
||||
import { createLocalTrack } from '../base/lib-jitsi-meet/functions';
|
||||
import {
|
||||
getLocalParticipant,
|
||||
isLocalParticipantModerator
|
||||
@@ -131,73 +130,3 @@ export function getProfileTabProps(stateful: Object | Function) {
|
||||
email: localParticipant.email
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a promise which resolves with a list of objects containing
|
||||
* all the video jitsiTracks and appropriate errors for the given device ids.
|
||||
*
|
||||
* @param {string[]} ids - The list of the camera ids for wich to create tracks.
|
||||
*
|
||||
* @returns {Promise<Object[]>}
|
||||
*/
|
||||
export function createLocalVideoTracks(ids: string[]) {
|
||||
return Promise.all(ids.map(deviceId => createLocalTrack('video', deviceId)
|
||||
.then(jitsiTrack => {
|
||||
return {
|
||||
jitsiTrack,
|
||||
deviceId
|
||||
};
|
||||
})
|
||||
.catch(() => {
|
||||
return {
|
||||
jitsiTrack: null,
|
||||
deviceId,
|
||||
error: 'deviceSelection.previewUnavailable'
|
||||
};
|
||||
})));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a promise which resolves with an object containing the corresponding
|
||||
* the audio jitsiTrack/error.
|
||||
*
|
||||
* @param {string} deviceId - The deviceId for the current microphone.
|
||||
*
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export function createLocalAudioTrack(deviceId: string) {
|
||||
return createLocalTrack('audio', deviceId)
|
||||
.then(jitsiTrack => {
|
||||
return {
|
||||
hasError: false,
|
||||
jitsiTrack
|
||||
};
|
||||
})
|
||||
.catch(() => {
|
||||
return {
|
||||
hasError: true,
|
||||
jitsiTrack: null
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the visibility state of the audio settings.
|
||||
*
|
||||
* @param {Object} state - The state of the application.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function getAudioSettingsVisibility(state: Object) {
|
||||
return state['features/settings'].audioSettingsVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the visibility state of the video settings.
|
||||
*
|
||||
* @param {Object} state - The state of the application.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function getVideoSettingsVisibility(state: Object) {
|
||||
return state['features/settings'].videoSettingsVisible;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
|
||||
import { ReducerRegistry } from '../base/redux';
|
||||
|
||||
import {
|
||||
SET_AUDIO_SETTINGS_VISIBILITY,
|
||||
SET_SETTINGS_VIEW_VISIBLE,
|
||||
SET_VIDEO_SETTINGS_VISIBILITY
|
||||
} from './actionTypes';
|
||||
import { SET_SETTINGS_VIEW_VISIBLE } from './actionTypes';
|
||||
|
||||
ReducerRegistry.register('features/settings', (state = {}, action) => {
|
||||
switch (action.type) {
|
||||
@@ -15,16 +11,6 @@ ReducerRegistry.register('features/settings', (state = {}, action) => {
|
||||
...state,
|
||||
visible: action.visible
|
||||
};
|
||||
case SET_AUDIO_SETTINGS_VISIBILITY:
|
||||
return {
|
||||
...state,
|
||||
audioSettingsVisible: action.value
|
||||
};
|
||||
case SET_VIDEO_SETTINGS_VISIBILITY:
|
||||
return {
|
||||
...state,
|
||||
videoSettingsVisible: action.value
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import { getFeatureFlag, CLOSE_CAPTIONS_ENABLED } from '../../base/flags';
|
||||
import { translate } from '../../base/i18n';
|
||||
import { IconClosedCaption } from '../../base/icons';
|
||||
import { connect } from '../../base/redux';
|
||||
@@ -20,5 +21,24 @@ class ClosedCaptionButton
|
||||
toggledLabel = 'transcribing.stop';
|
||||
}
|
||||
|
||||
export default translate(connect(_abstractMapStateToProps)(
|
||||
ClosedCaptionButton));
|
||||
/**
|
||||
* Maps (parts of) the redux state to the associated props for this component.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @param {Object} ownProps - The properties explicitly passed to the component
|
||||
* instance.
|
||||
* @private
|
||||
* @returns {Props}
|
||||
*/
|
||||
export function mapStateToProps(state: Object, ownProps: Object) {
|
||||
const { transcribingEnabled } = state['features/base/config'];
|
||||
const enabled = getFeatureFlag(state, CLOSE_CAPTIONS_ENABLED, true) && transcribingEnabled;
|
||||
const { visible = enabled } = ownProps;
|
||||
|
||||
return {
|
||||
..._abstractMapStateToProps(state, ownProps),
|
||||
visible
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(mapStateToProps)(ClosedCaptionButton));
|
||||
|
||||
@@ -22,5 +22,4 @@ class ClosedCaptionButton
|
||||
toggledLabel = 'toolbar.stopSubtitles';
|
||||
}
|
||||
|
||||
export default translate(connect(_abstractMapStateToProps)(
|
||||
ClosedCaptionButton));
|
||||
export default translate(connect(_abstractMapStateToProps)(ClosedCaptionButton));
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import AudioMuteButton from '../AudioMuteButton';
|
||||
import { hasAvailableDevices } from '../../../base/devices';
|
||||
import { IconArrowDown } from '../../../base/icons';
|
||||
import JitsiMeetJS from '../../../base/lib-jitsi-meet/_';
|
||||
import { ToolboxButtonWithIcon } from '../../../base/toolbox';
|
||||
import { connect } from '../../../base/redux';
|
||||
|
||||
import { AudioSettingsPopup, toggleAudioSettings } from '../../../settings';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Click handler for the small icon. Opens audio options.
|
||||
*/
|
||||
onAudioOptionsClick: Function,
|
||||
|
||||
/**
|
||||
* If the user has audio input or audio output devices.
|
||||
*/
|
||||
hasDevices: boolean,
|
||||
|
||||
/**
|
||||
* Flag controlling the visibility of the button.
|
||||
*/
|
||||
visible: boolean,
|
||||
};
|
||||
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* If there are permissions for audio devices.
|
||||
*/
|
||||
hasPermissions: boolean,
|
||||
}
|
||||
|
||||
/**
|
||||
* Button used for audio & audio settings.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
class AudioSettingsButton extends Component<Props, State> {
|
||||
/**
|
||||
* Initializes a new {@code AudioSettingsButton} instance.
|
||||
*
|
||||
* @param {Object} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
hasPermissions: false
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates device permissions.
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async _updatePermissions() {
|
||||
const hasPermissions = await JitsiMeetJS.mediaDevices.isDevicePermissionGranted(
|
||||
'audio',
|
||||
);
|
||||
|
||||
this.setState({
|
||||
hasPermissions
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentDidMount}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidMount() {
|
||||
this._updatePermissions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
const { hasDevices, onAudioOptionsClick, visible } = this.props;
|
||||
const settingsDisabled = !this.state.hasPermissions || !hasDevices;
|
||||
|
||||
return visible ? (
|
||||
<AudioSettingsPopup>
|
||||
<ToolboxButtonWithIcon
|
||||
icon = { IconArrowDown }
|
||||
iconDisabled = { settingsDisabled }
|
||||
onIconClick = { onAudioOptionsClick }>
|
||||
<AudioMuteButton />
|
||||
</ToolboxButtonWithIcon>
|
||||
</AudioSettingsPopup>
|
||||
) : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that maps parts of Redux state tree into component props.
|
||||
*
|
||||
* @param {Object} state - Redux state.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
hasDevices:
|
||||
hasAvailableDevices(state, 'audioInput')
|
||||
|| hasAvailableDevices(state, 'audioOutput')
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
onAudioOptionsClick: toggleAudioSettings
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
)(AudioSettingsButton);
|
||||
@@ -64,11 +64,12 @@ function _mapStateToProps(state: Object, ownProps: Props) {
|
||||
const localParticipant = getLocalParticipant(state);
|
||||
const isModerator = localParticipant.role === PARTICIPANT_ROLE.MODERATOR;
|
||||
const { visible } = ownProps;
|
||||
const { disableRemoteMute } = state['features/base/config'];
|
||||
|
||||
return {
|
||||
isModerator,
|
||||
localParticipantId: localParticipant.id,
|
||||
visible: visible && isModerator
|
||||
visible: visible && isModerator && !disableRemoteMute
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@ import {
|
||||
setToolbarHovered
|
||||
} from '../../actions';
|
||||
import AudioMuteButton from '../AudioMuteButton';
|
||||
import AudioSettingsButton from './AudioSettingsButton';
|
||||
import DownloadButton from '../DownloadButton';
|
||||
import { isToolboxVisible } from '../../functions';
|
||||
import HangupButton from '../HangupButton';
|
||||
@@ -82,7 +81,6 @@ import OverflowMenuProfileItem from './OverflowMenuProfileItem';
|
||||
import MuteEveryoneButton from './MuteEveryoneButton';
|
||||
import ToolbarButton from './ToolbarButton';
|
||||
import VideoMuteButton from '../VideoMuteButton';
|
||||
import VideoSettingsButton from './VideoSettingsButton';
|
||||
import {
|
||||
ClosedCaptionButton
|
||||
} from '../../../subtitles';
|
||||
@@ -128,11 +126,6 @@ type Props = {
|
||||
*/
|
||||
_fullScreen: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the prejoin page is enabled.
|
||||
*/
|
||||
_prejoinPageEnabled: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the tile view is enabled.
|
||||
*/
|
||||
@@ -1123,40 +1116,6 @@ class Toolbox extends Component<Props, State> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Audio controlling button.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderAudioButton() {
|
||||
return this._shouldShowButton('microphone')
|
||||
? this.props._prejoinPageEnabled
|
||||
? <AudioSettingsButton
|
||||
key = 'asb'
|
||||
visible = { true } />
|
||||
: <AudioMuteButton
|
||||
key = 'amb'
|
||||
visible = { true } />
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Video controlling button.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderVideoButton() {
|
||||
return this._shouldShowButton('camera')
|
||||
? this.props._prejoinPageEnabled
|
||||
? <VideoSettingsButton
|
||||
key = 'vsb'
|
||||
visible = { true } />
|
||||
: <VideoMuteButton
|
||||
key = 'vmb'
|
||||
visible = { true } />
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the toolbox content.
|
||||
*
|
||||
@@ -1275,10 +1234,12 @@ class Toolbox extends Component<Props, State> {
|
||||
}
|
||||
</div>
|
||||
<div className = 'button-group-center'>
|
||||
{ this._renderAudioButton() }
|
||||
<AudioMuteButton
|
||||
visible = { this._shouldShowButton('microphone') } />
|
||||
<HangupButton
|
||||
visible = { this._shouldShowButton('hangup') } />
|
||||
{ this._renderVideoButton() }
|
||||
<VideoMuteButton
|
||||
visible = { this._shouldShowButton('camera') } />
|
||||
</div>
|
||||
<div className = 'button-group-right'>
|
||||
{ buttonsRight.indexOf('localrecording') !== -1
|
||||
@@ -1342,9 +1303,7 @@ function _mapStateToProps(state) {
|
||||
let { desktopSharingEnabled } = state['features/base/conference'];
|
||||
const {
|
||||
callStatsID,
|
||||
enableFeaturesBasedOnToken,
|
||||
iAmRecorder,
|
||||
prejoinPageEnabled
|
||||
iAmRecorder
|
||||
} = state['features/base/config'];
|
||||
const sharedVideoStatus = state['features/shared-video'].status;
|
||||
const {
|
||||
@@ -1359,7 +1318,7 @@ function _mapStateToProps(state) {
|
||||
|
||||
let desktopSharingDisabledTooltipKey;
|
||||
|
||||
if (enableFeaturesBasedOnToken) {
|
||||
if (state['features/base/config'].enableFeaturesBasedOnToken) {
|
||||
// we enable desktop sharing if any participant already have this
|
||||
// feature enabled
|
||||
desktopSharingEnabled = getParticipants(state)
|
||||
@@ -1395,7 +1354,6 @@ function _mapStateToProps(state) {
|
||||
_localParticipantID: localParticipant.id,
|
||||
_localRecState: localRecordingStates,
|
||||
_overflowMenuVisible: overflowMenuVisible,
|
||||
_prejoinPageEnabled: prejoinPageEnabled,
|
||||
_raisedHand: localParticipant.raisedHand,
|
||||
_screensharing: localVideo && localVideo.videoType === 'desktop',
|
||||
_sharingVideo: sharedVideoStatus === 'playing'
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { toggleVideoSettings, VideoSettingsPopup } from '../../../settings';
|
||||
import VideoMuteButton from '../VideoMuteButton';
|
||||
import JitsiMeetJS from '../../../base/lib-jitsi-meet/_';
|
||||
import { hasAvailableDevices } from '../../../base/devices';
|
||||
import { IconArrowDown } from '../../../base/icons';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { ToolboxButtonWithIcon } from '../../../base/toolbox';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Click handler for the small icon. Opens video options.
|
||||
*/
|
||||
onVideoOptionsClick: Function,
|
||||
|
||||
/**
|
||||
* If the user has any video devices.
|
||||
*/
|
||||
hasDevices: boolean,
|
||||
|
||||
/**
|
||||
* Flag controlling the visibility of the button.
|
||||
*/
|
||||
visible: boolean,
|
||||
};
|
||||
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* Whether the app has video permissions or not.
|
||||
*/
|
||||
hasPermissions: boolean,
|
||||
};
|
||||
|
||||
/**
|
||||
* Button used for video & video settings.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
class VideoSettingsButton extends Component<Props, State> {
|
||||
/**
|
||||
* Initializes a new {@code VideoSettingsButton} instance.
|
||||
*
|
||||
* @param {Object} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
hasPermissions: false
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates device permissions.
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async _updatePermissions() {
|
||||
const hasPermissions = await JitsiMeetJS.mediaDevices.isDevicePermissionGranted(
|
||||
'video',
|
||||
);
|
||||
|
||||
this.setState({
|
||||
hasPermissions
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentDidMount}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidMount() {
|
||||
this._updatePermissions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
const { hasDevices, onVideoOptionsClick, visible } = this.props;
|
||||
const iconDisabled = !this.state.hasPermissions || !hasDevices;
|
||||
|
||||
return visible ? (
|
||||
<VideoSettingsPopup>
|
||||
<ToolboxButtonWithIcon
|
||||
icon = { IconArrowDown }
|
||||
iconDisabled = { iconDisabled }
|
||||
onIconClick = { onVideoOptionsClick }>
|
||||
<VideoMuteButton />
|
||||
</ToolboxButtonWithIcon>
|
||||
</VideoSettingsPopup>
|
||||
) : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that maps parts of Redux state tree into component props.
|
||||
*
|
||||
* @param {Object} state - Redux state.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
hasDevices: hasAvailableDevices(state, 'videoInput')
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
onVideoOptionsClick: toggleVideoSettings
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
)(VideoSettingsButton);
|
||||
@@ -40,8 +40,6 @@ export function isToolboxVisible(state: Object) {
|
||||
timeoutID,
|
||||
visible
|
||||
} = state['features/toolbox'];
|
||||
const { audioSettingsVisible, videoSettingsVisible } = state['features/settings'];
|
||||
|
||||
return Boolean(!iAmSipGateway && (timeoutID || visible || alwaysVisible
|
||||
|| audioSettingsVisible || videoSettingsVisible));
|
||||
return Boolean(!iAmSipGateway && (timeoutID || visible || alwaysVisible));
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { Dispatch } from 'redux';
|
||||
import { createWelcomePageEvent, sendAnalytics } from '../../analytics';
|
||||
import { appNavigate } from '../../app';
|
||||
import { isCalendarEnabled } from '../../calendar-sync';
|
||||
import { isRoomValid } from '../../base/conference';
|
||||
import { isRecentListEnabled } from '../../recent-list/functions';
|
||||
|
||||
/**
|
||||
* {@code AbstractWelcomePage}'s React {@code Component} prop types.
|
||||
@@ -19,6 +19,11 @@ type Props = {
|
||||
*/
|
||||
_calendarEnabled: boolean,
|
||||
|
||||
/**
|
||||
* Whether the recent list is enabled
|
||||
*/
|
||||
_recentListEnabled: Boolean,
|
||||
|
||||
/**
|
||||
* Room name to join to.
|
||||
*/
|
||||
@@ -155,18 +160,6 @@ export class AbstractWelcomePage extends Component<Props, *> {
|
||||
clearTimeout(this.state.updateTimeoutId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the 'Join' button is (to be) disabled i.e. There's no
|
||||
* valid room name typed into the respective text input field.
|
||||
*
|
||||
* @protected
|
||||
* @returns {boolean} If the 'Join' button is (to be) disabled, true;
|
||||
* otherwise, false.
|
||||
*/
|
||||
_isJoinDisabled() {
|
||||
return this.state.joining || !isRoomValid(this.state.room);
|
||||
}
|
||||
|
||||
_onJoin: () => void;
|
||||
|
||||
/**
|
||||
@@ -252,6 +245,7 @@ export class AbstractWelcomePage extends Component<Props, *> {
|
||||
export function _mapStateToProps(state: Object) {
|
||||
return {
|
||||
_calendarEnabled: isCalendarEnabled(state),
|
||||
_recentListEnabled: isRecentListEnabled(),
|
||||
_room: state['features/base/conference'].room,
|
||||
_settings: state['features/base/settings']
|
||||
};
|
||||
|
||||
@@ -75,6 +75,8 @@ class WelcomePage extends AbstractWelcomePage {
|
||||
componentDidMount() {
|
||||
super.componentDidMount();
|
||||
|
||||
this._updateRoomname();
|
||||
|
||||
const { dispatch } = this.props;
|
||||
|
||||
if (this.props._settings.startAudioOnly) {
|
||||
@@ -227,19 +229,12 @@ class WelcomePage extends AbstractWelcomePage {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const buttonDisabled = this._isJoinDisabled();
|
||||
|
||||
return (
|
||||
<TouchableHighlight
|
||||
accessibilityLabel =
|
||||
{ t('welcomepage.accessibilityLabel.join') }
|
||||
disabled = { buttonDisabled }
|
||||
onPress = { this._onJoin }
|
||||
style = { [
|
||||
styles.button,
|
||||
buttonDisabled ? styles.buttonDisabled : null
|
||||
] }
|
||||
style = { styles.button }
|
||||
underlayColor = { ColorPalette.white }>
|
||||
{ children }
|
||||
</TouchableHighlight>
|
||||
@@ -268,6 +263,9 @@ class WelcomePage extends AbstractWelcomePage {
|
||||
</Header>
|
||||
<SafeAreaView style = { styles.roomContainer } >
|
||||
<View style = { styles.joinControls } >
|
||||
<Text style = { styles.enterRoomText }>
|
||||
{ t('welcomepage.roomname') }
|
||||
</Text>
|
||||
<TextInput
|
||||
accessibilityLabel = { t(roomnameAccLabel) }
|
||||
autoCapitalize = 'none'
|
||||
@@ -278,10 +276,8 @@ class WelcomePage extends AbstractWelcomePage {
|
||||
onChangeText = { this._onRoomChange }
|
||||
onFocus = { this._onFieldFocus }
|
||||
onSubmitEditing = { this._onJoin }
|
||||
placeholder = { t('welcomepage.roomname') }
|
||||
placeholderTextColor = {
|
||||
PLACEHOLDER_TEXT_COLOR
|
||||
}
|
||||
placeholder = { this.state.roomPlaceholder }
|
||||
placeholderTextColor = { PLACEHOLDER_TEXT_COLOR }
|
||||
returnKeyType = { 'go' }
|
||||
style = { styles.textInput }
|
||||
underlineColorAndroid = 'transparent'
|
||||
|
||||
@@ -285,7 +285,7 @@ class WelcomePage extends AbstractWelcomePage {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { _calendarEnabled, t } = this.props;
|
||||
const { _calendarEnabled, _recentListEnabled, t } = this.props;
|
||||
|
||||
const tabs = [];
|
||||
|
||||
@@ -296,10 +296,16 @@ class WelcomePage extends AbstractWelcomePage {
|
||||
});
|
||||
}
|
||||
|
||||
tabs.push({
|
||||
label: t('welcomepage.recentList'),
|
||||
content: <RecentList />
|
||||
});
|
||||
if (_recentListEnabled) {
|
||||
tabs.push({
|
||||
label: t('welcomepage.recentList'),
|
||||
content: <RecentList />
|
||||
});
|
||||
}
|
||||
|
||||
if (tabs.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
|
||||
@@ -4,7 +4,7 @@ import { StyleSheet } from 'react-native';
|
||||
|
||||
import { BoxModel, ColorPalette } from '../../base/styles';
|
||||
|
||||
export const PLACEHOLDER_TEXT_COLOR = 'rgba(255, 255, 255, 0.3)';
|
||||
export const PLACEHOLDER_TEXT_COLOR = 'rgba(255, 255, 255, 0.5)';
|
||||
|
||||
export const SIDEBAR_AVATAR_SIZE = 100;
|
||||
|
||||
@@ -64,14 +64,6 @@ export default {
|
||||
paddingHorizontal: 20
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders the button visually disabled.
|
||||
*/
|
||||
buttonDisabled: {
|
||||
backgroundColor: '#cccccc',
|
||||
borderColor: '#999999'
|
||||
},
|
||||
|
||||
/**
|
||||
* Join button text style.
|
||||
*/
|
||||
@@ -91,6 +83,12 @@ export default {
|
||||
textAlign: 'center'
|
||||
},
|
||||
|
||||
enterRoomText: {
|
||||
color: TEXT_COLOR,
|
||||
fontSize: 18,
|
||||
marginBottom: BoxModel.margin
|
||||
},
|
||||
|
||||
/**
|
||||
* The welcome screen header style.
|
||||
*/
|
||||
|
||||