Compare commits

...

20 Commits

Author SHA1 Message Date
Дамян Минков
5d41da9358 fix: Fixes recording dialog web rendering.
[features/base/app] <APP.componentDidCatch>:  TypeError: Failed to set an indexed property on 'CSSStyleDeclaration': Indexed property setter is not supported.
2022-03-02 13:19:34 -06:00
Pawel Domas
0936a64d3f fix(receiver constraints): source name not found
...when new participant joins.

Repro steps:

1. With p2p disabled and source name signaling enabled.
2. Start a call with 2 tabs.
3. Reload the 2nd tab.
4. The receiver constraints should be updated when the 2nd
   user rejoins. They were not updated, because
   getTrackSourceNameByMediaTypeAndParticipant doesn't have
   the track yet at the time when visibleRemoteParticipants
   are updated. This is fixed by also checking on
   the remote tracks state.
2022-03-02 11:30:38 -05:00
Дамян Минков
c6eccb1a5a Enable polls for breakout rooms by default. 2022-03-02 10:13:10 -06:00
Saúl Ibarra Corretgé
0c042ca720 fix(WaitForOwnerDialog) simplify code
Don't print the room name, which could be long and nondescriptive.
2022-03-02 09:59:55 -06:00
Jaya Allamsetty
feb1b93ce6 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1387.0.0+6ddc054c...v1389.0.0+313e0dd3
2022-03-02 10:37:18 -05:00
Дамян Минков
75d80ad879 fix: Fixes loading web on mobile browser.
Adds missing url prop to DialInSummary and safeguard the URL creation.
2022-03-02 08:53:57 -06:00
Robert Pintilii
8bb5c114f8 fix(filmstrip) Fix resizable filmstrip (#11025)
Re-calculate tile sizes after config loaded
Make local tile always respect the ratio in interface_config
Merge calculate size for vertical view functions into one function
2022-03-02 16:46:20 +02:00
Mihaela Dumitru
936d9b41f1 feat(external-api): expose config for breakout rooms (#11055) 2022-03-02 16:15:18 +02:00
Tudor D. Pop
5d68a53f79 fix(lobby-notifications): Prevent lobby notification to remain on scr… (#11054) 2022-03-01 20:48:05 +01:00
Jaya Allamsetty
7f8c43d477 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1376.0.0+f881b3c7...v1387.0.0+6ddc054c
2022-03-01 12:11:32 -05:00
Jaya Allamsetty
c30038236a fix(screenshare) Add and then mute the camera track after SS stops instead of not adding the track.
This is a follow up for https://github.com/jitsi/lib-jitsi-meet/pull/1944. This is needed to avoid sending a soure-remove followed by a source-add for the same ssrc. This happens when a users mutes camera->starts SS->stops SS->turns on camera on a p2p connection in Unified plan mode. Chrome fails to render the media if the same SSRC is removed and added back to the same m-line.
2022-03-01 10:54:42 -05:00
Calinteodor
577d62ea53 feat(filmstrip/toolbox) mobile ui updates (#11051) 2022-03-01 17:41:45 +02:00
Mihaela Dumitru
c35473d5e4 fix(external-api): dismiss lobby notification after handling the knocking participant (#11049) 2022-03-01 14:17:06 +02:00
hmuresan
c69fdd766c fix(video-devices) Fix video devices not scrollable 2022-03-01 13:22:39 +02:00
Дамян Минков
389d455daa feat: Passing the url to conference mapper (#11013)
* fix: Moves getDialInConferenceID, so we can reuse conf mapper url generation.

* fix: Moves getDialInNumbers, so we can reuse url generation.

* squash: Moves dialInInfo page path to constants.

* feat: Adds the location address as a param to the conf mapper request.

* feat: Adds option conf mapper and numbers urls to contain parameters (?).

* squash: Adds more doc comments.

* squash: Makes sure we strip url params if any, and they do not reach fetch.
2022-02-28 14:03:42 -06:00
Calin Chitu
1ab086247b feat(filmstrip/toolbox) mobile ui undo changes 2022-02-28 17:54:50 +02:00
Shahab
f62dc44f3e feat(screenshare) Allow desktop sharing in audioOnly mode on web.
This is already supported on mobile. The user is allowed to enable their video in audioOnly mode so it doesn't make sense to block screenshare.
2022-02-28 10:45:24 -05:00
Robert Pintilii
06800f88bf fix(thumbnail) Fix pinned participant in the resizable filmstrip (#11042)
Show border on the pinned participant in the vertical filmstrip grid view
2022-02-28 17:03:47 +02:00
Saúl Ibarra Corretgé
c9ea193d04 fix(i18n) fix some country names 2022-02-28 15:29:33 +01:00
Doug
c8895b2d04 feat(ios) Add support to the iOS SDK for the Simulator on M1 2022-02-25 22:20:34 +01:00
100 changed files with 565 additions and 525 deletions

View File

@@ -1612,32 +1612,29 @@ export default {
APP.store.dispatch(setScreenAudioShareState(false));
if (didHaveVideo && !ignoreDidHaveVideo) {
promise = promise.then(() => createLocalTracksF({ devices: [ 'video' ] }))
.then(([ stream ]) => {
logger.debug(`_turnScreenSharingOff using ${stream} for useVideoStream`);
promise = promise.then(() => createLocalTracksF({ devices: [ 'video' ] }))
.then(([ stream ]) => {
logger.debug(`_turnScreenSharingOff using ${stream} for useVideoStream`);
return this.useVideoStream(stream);
})
.catch(error => {
logger.error('failed to switch back to local video', error);
return this.useVideoStream(stream);
})
.catch(error => {
logger.error('failed to switch back to local video', error);
return this.useVideoStream(null).then(() =>
return this.useVideoStream(null).then(() =>
// Still fail with the original err
Promise.reject(error)
);
});
} else {
promise = promise.then(() => {
logger.debug('_turnScreenSharingOff using null for useVideoStream');
return this.useVideoStream(null);
// Still fail with the original err
Promise.reject(error)
);
});
}
return promise.then(
() => {
// Mute the video if camera video needs to be ignored or if video was muted before switching to screen
// share.
if (ignoreDidHaveVideo || !didHaveVideo) {
APP.store.dispatch(setVideoMuted(true, MEDIA_TYPE.VIDEO));
}
this.videoSwitchInProgress = false;
sendAnalytics(createScreenSharingEvent('stopped',
duration === 0 ? null : duration));
@@ -1661,9 +1658,12 @@ export default {
* toggles between screen sharing and camera video.
* @param {Object} [options] - Screen sharing options that will be passed to
* createLocalTracks.
* @param {boolean} [options.audioOnly] - Whether or not audioOnly is enabled.
* @param {Array<string>} [options.desktopSharingSources] - Array with the
* sources that have to be displayed in the desktop picker window ('screen',
* 'window', etc.).
* @param {Object} [options.desktopStream] - An existing desktop stream to
* use instead of creating a new desktop stream.
* @param {boolean} ignoreDidHaveVideo - if true ignore if video was on when sharing started.
* @return {Promise.<T>}
*/
@@ -1676,10 +1676,6 @@ export default {
return Promise.reject('Cannot toggle screen sharing: not supported.');
}
if (this.isAudioOnly()) {
return Promise.reject('No screensharing in audio only mode');
}
if (toggle) {
try {
await this._switchToScreenSharing(options);

View File

@@ -473,6 +473,7 @@ var config = {
// If Lobby is enabled starts knocking automatically.
// autoKnockLobby: false,
// DEPRECATED! Use `breakoutRooms.hideAddRoomButton` instead.
// Hides add breakout room button
// hideAddRoomButton: false,
@@ -1048,6 +1049,14 @@ var config = {
*/
// dynamicBrandingUrl: '',
// Options related to the breakout rooms feature.
// breakoutRooms: {
// // Hides the add breakout room button. This replaces `hideAddRoomButton`.
// hideAddRoomButton: false,
// // Hides the join breakout room button.
// hideJoinRoomButton: false
// },
// When true the user cannot add more images to be used as virtual background.
// Only the default ones from will be available.
// disableAddingBackgroundImages: false,

View File

@@ -1,9 +1,9 @@
.video-preview {
background: none;
display: inline-block;
max-height: 344px;
&-container {
max-height: 344px;
background: $menuBG;
border-radius: 3px;
overflow: auto;

View File

@@ -83,6 +83,7 @@ Component "breakout.jitmeet.example.com" "muc"
"muc_domain_mapper";
--"token_verification";
"muc_rate_limit";
"polls";
}
admins = { "focusUser@auth.jitmeet.example.com" }
muc_room_locking = false

View File

@@ -35,7 +35,6 @@ xcodebuild archive \
-sdk iphonesimulator \
-destination='generic/platform=iOS Simulator' \
-archivePath ios/sdk/out/ios-simulator \
VALID_ARCHS=x86_64 \
ENABLE_BITCODE=NO \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
@@ -46,7 +45,6 @@ xcodebuild archive \
-sdk iphoneos \
-destination='generic/platform=iOS' \
-archivePath ios/sdk/out/ios-device \
VALID_ARCHS=arm64 \
ENABLE_BITCODE=NO \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES

View File

@@ -141,7 +141,6 @@
"Share": "Deel",
"Submit": "Dien in",
"WaitForHostMsg": "",
"WaitForHostMsgWOk": "",
"WaitingForHost": "Wag tans vir die gasheer …",
"Yes": "Ja",
"accessibilityLabel": {

View File

@@ -208,8 +208,7 @@
"Remove": "أزل",
"Share": "شارك",
"Submit": "أرسل",
"WaitForHostMsg": "لم يبدأ المؤتمر <b>{{room}}</b> بعد. إن كنت المضيف والراعي، فنرجو تأكيد ذلك عبر الاستيثاق أو انتظر وصول المضيف رجاءً. ",
"WaitForHostMsgWOk": "لم يبدأ المؤتمر <b>{{room}}</b> بعد. إن كنت المضيف والراعي، فاضغط على «تمام» للاستيثاق أو انتظر وصول المضيف رجاءً.",
"WaitForHostMsg": "لم يبدأ المؤتمر بعد. إن كنت المضيف والراعي، فنرجو تأكيد ذلك عبر الاستيثاق أو انتظر وصول المضيف رجاءً. ",
"WaitingForHostTitle": "في انتظار المضيف ...",
"Yes": "نعم",
"accessibilityLabel": {

View File

@@ -160,8 +160,7 @@
"Remove": "Выдаліць",
"Share": "Падзяліцца",
"Submit": "Адправіць",
"WaitForHostMsg": "Канферэнцыя <b>{{room}}</b> яшчэ не пачалася. Калі вы з'яўляецеся гаспадаром, калі ласка, падтвердіце сапраўднасць. У адваротным выпадку, калі ласка, пачакайце з'яўлення гаспадара.",
"WaitForHostMsgWOk": "Канферэнцыя <b>{{room}}</b> яшчэ не пачалася. Калі Вы арганізатар, калі ласка, націсніце Ok для аўтэнтыфікацыі. У адваротным выпадку, дачакайцеся арганізатара.",
"WaitForHostMsg": "Канферэнцыя яшчэ не пачалася. Калі вы з'яўляецеся гаспадаром, калі ласка, падтвердіце сапраўднасць. У адваротным выпадку, калі ласка, пачакайце з'яўлення гаспадара.",
"WaitingForHost": "Чакаем арганізатара …",
"Yes": "Так",
"accessibilityLabel": {

View File

@@ -167,8 +167,7 @@
"Remove": "Премахване",
"Share": "Споделяне",
"Submit": "Изпращане",
"WaitForHostMsg": "Конференцията <b>{{room}}</b> все още не е започнала. Ако сте домакинът, тогава се идентифицирайте. В противен случай изчакайте докато домакинът пристигне.",
"WaitForHostMsgWOk": "Конференцията <b>{{room}}</b> все още не е започнала. Ако сте домакинът, тогава натиснете бутона, за да се идентифицирате. В противен случай изчакайте докато домакинът пристигне.",
"WaitForHostMsg": "Конференцията все още не е започнала. Ако сте домакинът, тогава се идентифицирайте. В противен случай изчакайте докато домакинът пристигне.",
"WaitingForHost": "Чакаме домакина...",
"Yes": "Да",
"accessibilityLabel": {

View File

@@ -208,8 +208,7 @@
"Remove": "Elimina",
"Share": "Comparteix",
"Submit": "Tramet",
"WaitForHostMsg": "La conferència <b>{{room}}</b> encara no ha començat. Si en sou l'amfitrió autentiqueu-vos. Altrament, espereu que arribi l'amfitrió.",
"WaitForHostMsgWOk": "La conferència <b>{{room}}</b> encara no ha començat. Si sou l'amfitrió, aleshores pitgeu «D'acord» per a autenticar-vos. Altrament, espereu que arribi l'amfitrió.",
"WaitForHostMsg": "La conferència encara no ha començat. Si en sou l'amfitrió autentiqueu-vos. Altrament, espereu que arribi l'amfitrió.",
"WaitingForHostTitle": "S'està esperant l'amfitrió...",
"Yes": "Sí",
"accessibilityLabel": {

View File

@@ -196,8 +196,7 @@
"Remove": "Odstranit",
"Share": "Sdílet",
"Submit": "Potvrdit",
"WaitForHostMsg": "Konference <b>{{room}}</b> ještě nezačala. Pokud jste hostitel, přihlaste se. Jinak prosím počkejte, až hostitel dorazí.",
"WaitForHostMsgWOk": "Konference <b>{{room}}</b> ještě nezačala. Pokud jste hostitel, prosím přihlaste se kliknutím na OK. Jinak prosím počkejte, až hostitel dorazí.",
"WaitForHostMsg": "Konference ještě nezačala. Pokud jste hostitel, přihlaste se. Jinak prosím počkejte, až hostitel dorazí.",
"WaitingForHost": "Čeká se na hostitele…",
"Yes": "Ano",
"accessibilityLabel": {

View File

@@ -156,8 +156,7 @@
"Remove": "Fjern",
"Share": "Del",
"Submit": "Gem",
"WaitForHostMsg": "Mødet <b>{{room}}</b> er ikke startet endnu. Hvis du er værten, log venligst ind. Ellers vent på at værten kommer",
"WaitForHostMsgWOk": "Mødet <b>{{room}}</b> er ikke startet endnu. Hvis du er værten, tryk venligst på OK for at logge ind. Ellers vent på at værten kommer.",
"WaitForHostMsg": "Mødet er ikke startet endnu. Hvis du er værten, log venligst ind. Ellers vent på at værten kommer",
"WaitingForHost": "Venter på vært …",
"Yes": "Ja",
"accessibilityLabel": {

View File

@@ -208,8 +208,7 @@
"Remove": "Entfernen",
"Share": "Teilen",
"Submit": "OK",
"WaitForHostMsg": "Die Konferenz <b>{{room}}</b> wurde noch nicht gestartet. Falls Sie die Konferenz leiten, authentifizieren Sie sich bitte. Warten Sie andernfalls, bis die Konferenz gestartet wird.",
"WaitForHostMsgWOk": "Die Konferenz <b>{{room}}</b> wurde noch nicht gestartet. Falls Sie die Konferenz leiten, authentifizieren Sie sich bitte. Warten Sie andernfalls, bis die Konferenz gestartet wird.",
"WaitForHostMsg": "Die Konferenz wurde noch nicht gestartet. Falls Sie die Konferenz leiten, authentifizieren Sie sich bitte. Warten Sie andernfalls, bis die Konferenz gestartet wird.",
"WaitingForHostTitle": "Warten auf den Beginn der Konferenz …",
"Yes": "Ja",
"accessibilityLabel": {

View File

@@ -172,8 +172,7 @@
"Remove": "Αφαίρεση",
"Share": "Μοιραστείτε",
"Submit": "Υποβολή",
"WaitForHostMsg": "Η διάσκεψη <b>{{room}}</b> δεν έχει ακόμη αρχίσει. Αν είστε ο οικοδεσπότης, τότε παρακαλούμε να πιστοποιήσετε τον εαυτό σας. Διαφορετικά, σας παρακαλώ να περιμένετε να συνδεθεί ο οικοδεσπότης.",
"WaitForHostMsgWOk": "Η διάσκεψη <b>{{room}}</b> δεν έχει ακόμη αρχίσει. Αν είστε ο οικοδεσπότης, τότε παρακαλούμε πατήστε ΟΚ για να πιστοποιήσετε τον εαυτό σας. Διαφορετικά, σας παρακαλώ να περιμένετε να συνδεθεί ο οικοδεσπότης.",
"WaitForHostMsg": "Η διάσκεψη δεν έχει ακόμη αρχίσει. Αν είστε ο οικοδεσπότης, τότε παρακαλούμε να πιστοποιήσετε τον εαυτό σας. Διαφορετικά, σας παρακαλώ να περιμένετε να συνδεθεί ο οικοδεσπότης.",
"WaitingForHost": "Αναμονή για τον οικοδεσπότη ...",
"Yes": "Ναι",
"accessibilityLabel": {

View File

@@ -160,8 +160,7 @@
"Remove": "Remove",
"Share": "Share",
"Submit": "Submit",
"WaitForHostMsg": "The conference <b>{{room}}</b> has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
"WaitForHostMsgWOk": "The conference <b>{{room}}</b> has not yet started. If you are the host then please press Ok to authenticate. Otherwise, please wait for the host to arrive.",
"WaitForHostMsg": "The conference has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
"WaitingForHost": "Waiting for the host …",
"Yes": "Yes",
"accessibilityLabel": {

View File

@@ -155,8 +155,7 @@
"Remove": "Forigi",
"Share": "Kundividi",
"Submit": "Sendi",
"WaitForHostMsg": "La kunveno <b>{{room}}</b> ankoraŭ ne komencis. Se vi estas la gastiganto, bonvolu aŭtentiĝi. Alikaze atendu, ĝis la gastiganto venos.",
"WaitForHostMsgWOk": "La kunveno <b>{{room}}</b> ankoraŭ ne komencis. Se vi estas la gastiganto, bonvolu puŝi “Bone” por aŭtentiĝi. Alikaze atendu, ĝis la gastiganto venos.",
"WaitForHostMsg": "La kunveno ankoraŭ ne komencis. Se vi estas la gastiganto, bonvolu aŭtentiĝi. Alikaze atendu, ĝis la gastiganto venos.",
"WaitingForHost": "Atendo de la gastiga komputilo…",
"Yes": "Jes",
"accessibilityLabel": {

View File

@@ -185,8 +185,7 @@
"Remove": "Eliminar",
"Share": "Compartir",
"Submit": "Enviar",
"WaitForHostMsg": "La conferencia <b>{{room}}</b> aún no ha comenzado. Si eres el anfitrión, inicia sesión. De lo contrario, espera a que llegue el anfitrión.",
"WaitForHostMsgWOk": "La conferencia <b>{{room}}</b> aún no ha comenzado. Si eres el anfitrión, presiona Aceptar para autenticar. De lo contrario, espera a que llegue el anfitrión.",
"WaitForHostMsg": "La conferencia aún no ha comenzado. Si eres el anfitrión, inicia sesión. De lo contrario, espera a que llegue el anfitrión.",
"WaitingForHostTitle": "Esperando al anfitrión...",
"Yes": "Sí",
"accessibilityLabel": {

View File

@@ -194,8 +194,7 @@
"Remove": "Eliminar",
"Share": "Compartir",
"Submit": "Enviar",
"WaitForHostMsg": "La conferencia <b>{{room}}</b> aún no ha comenzado. Si eres el anfitrión, inicia sesión. De lo contrario, espera a que llegue el anfitrión.",
"WaitForHostMsgWOk": "La conferencia <b>{{room}}</b> aún no ha comenzado. Si eres el anfitrión, presiona Aceptar para autenticar. De lo contrario, espera a que llegue el anfitrión.",
"WaitForHostMsg": "La conferencia aún no ha comenzado. Si eres el anfitrión, inicia sesión. De lo contrario, espera a que llegue el anfitrión.",
"WaitingForHost": "Esperando al anfitrión…",
"WaitingForHostTitle": "Esperando al anfitrión...",
"Yes": "Sí",

View File

@@ -155,8 +155,7 @@
"Remove": "Eemalda",
"Share": "Jaga",
"Submit": "Esita",
"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.",
"WaitForHostMsg": "Kõne ei ole veel alanud. Autendi ennast, kui oled võõrustaja. Külalisena oota, kuni võõrustaja saabub.",
"WaitingForHost": "Võõrustaja ootamine…",
"Yes": "Jah",
"accessibilityLabel": {

View File

@@ -181,8 +181,7 @@
"Remove": "Kendu",
"Share": "Partekatu",
"Submit": "Bidali",
"WaitForHostMsg": "<b>{{room}}</b> konferentzia oraindik ez da hasi. Ostalaria bazara, autentifikatu. Bestela, itxaron ostalaria iritsi arte.",
"WaitForHostMsgWOk": "<b>{{room}}</b> konferentzia oraindik ez da hasi. Ostalaria bazara, sakatu Ados autentifikatu ahal izateko. Bestela, itxaron ostalaria iritsi arte.",
"WaitForHostMsg": "Konferentzia oraindik ez da hasi. Ostalaria bazara, autentifikatu. Bestela, itxaron ostalaria iritsi arte.",
"WaitingForHostTitle": "Antolatzailearen zain...",
"Yes": "Bai",
"accessibilityLabel": {

View File

@@ -208,8 +208,7 @@
"Remove": "حذف کردن",
"Share": "به اشتراک گذاری",
"Submit": "ارسال",
"WaitForHostMsg": "کنفرانس <b>{{room}}</b> هنوز شروع نشده است، اگر میزبان هستید وارد شوید، در غیر اینصورت تا رسیدن میزبان و شروع جلسه منتظر بمانید",
"WaitForHostMsgWOk": "کنفرانس <b>{{room}}</b> هنوز شروع نشده است، اگر میزبان هستید برای احراز هویت تایید را بزنید، در غیر اینصورت تا رسیدن میزبان و شروع جلسه منتظر بمانید",
"WaitForHostMsg": "کنفرانس هنوز شروع نشده است، اگر میزبان هستید وارد شوید، در غیر اینصورت تا رسیدن میزبان و شروع جلسه منتظر بمانید",
"WaitingForHostTitle": "در حال انتظار برای میزبان...",
"Yes": "بله",
"accessibilityLabel": {

View File

@@ -140,8 +140,7 @@
"Remove": "Poista",
"Share": "Jaa",
"Submit": "Lähetä",
"WaitForHostMsg": "Kokous <b>{{room}}</b> ei ole vielä alkanut. Jos olet vetäjä, todenna henkilöllisyytesi. Muussa tapauksessa odota vetäjän saapumista.",
"WaitForHostMsgWOk": "Kokous <b>{{room}}</b> ei ole vielä alkanut. Jos olet vetäjä, todenna henkilöllisyytesi OK-painikkeella. Muussa tapauksessa odota vetäjän saapumista.",
"WaitForHostMsg": "Kokous ei ole vielä alkanut. Jos olet vetäjä, todenna henkilöllisyytesi. Muussa tapauksessa odota vetäjän saapumista.",
"WaitingForHost": "Odotetaan vetäjää…",
"Yes": "Kyllä",
"accessibilityLabel": {

View File

@@ -208,8 +208,7 @@
"Remove": "Supprimer",
"Share": "Partager",
"Submit": "Soumettre",
"WaitForHostMsg": "La conférence <b>{{room}}</b> n'a pas encore commencé. Si vous en êtes l'hôte, veuillez vous authentifier. Sinon, veuillez attendre son arrivée.",
"WaitForHostMsgWOk": "La conférence <b>{{room}}</b> n'a pas encore commencé. Si vous en êtes l'hôte, veuillez appuyer sur Ok pour vous authentifier. Sinon, veuillez attendre son arrivée.",
"WaitForHostMsg": "La conférence n'a pas encore commencé. Si vous en êtes l'hôte, veuillez vous authentifier. Sinon, veuillez attendre son arrivée.",
"WaitingForHostTitle": "En attente de l'hôte ...",
"Yes": "Oui",
"accessibilityLabel": {

View File

@@ -146,8 +146,7 @@
"Remove": "Supprimer",
"Share": "Oui",
"Submit": "Envoyer",
"WaitForHostMsg": "La conférence <b>{{room}}</b> n'a pas encore démarré. Si vous êtes l'hôte, veuillez vous authentifier. Sinon, veuillez attendre que l'hôte arrive.",
"WaitForHostMsgWOk": "La conférence <b>{{room}}</b> n'a pas encore démarré. Si vous êtes l'hôte, veuillez appuyer sur OK pour vous authentifier. Sinon, veuillez attendre que l'hôte arrive.",
"WaitForHostMsg": "La conférence n'a pas encore démarré. Si vous êtes l'hôte, veuillez vous authentifier. Sinon, veuillez attendre que l'hôte arrive.",
"WaitingForHost": "En attente de l'hôte…",
"Yes": "Oui",
"accessibilityLabel": {

View File

@@ -151,8 +151,7 @@
"Remove": "Retirar",
"Share": "Compartir",
"Submit": "Enviar",
"WaitForHostMsg": "A sala <b>{{room}}</b> aínda non comezou. Se vostede é o anfitrión, autentíquese. Se non, agarde a que o anfitrión chegue.",
"WaitForHostMsgWOk": "A sala <b>{{room}}</b> aínda non comezou. Se vostede é o anfitrión, prema en Aceptar para autenticar. Se non, agarde a que o anfitrión chegue.",
"WaitForHostMsg": "A sala aínda non comezou. Se vostede é o anfitrión, autentíquese. Se non, agarde a que o anfitrión chegue.",
"WaitingForHost": "Agardando polo anfitrión…",
"Yes": "Si",
"accessibilityLabel": {

View File

@@ -155,8 +155,7 @@
"Remove": "הסר",
"Share": "שתף",
"Submit": "שלח",
"WaitForHostMsg": "הועידה <b>{{room}}</b> טרם החלה. אם אתה המארח אז בצע אימות. אחרת, אנא המתן שהמארח יגיע.",
"WaitForHostMsgWOk": "הועידה <b>{{room}}</b> טרם החלה. אם אתה המארח אז לחץ אישור לביצוע אימות. אחרת, אנא המתן שהמארח יגיע.",
"WaitForHostMsg": "הועידה טרם החלה. אם אתה המארח אז בצע אימות. אחרת, אנא המתן שהמארח יגיע.",
"WaitingForHost": "ממתין למארח ...",
"Yes": "כן",
"accessibilityLabel": {

View File

@@ -180,8 +180,7 @@
"Remove": "निकालें",
"Share": "Share",
"Submit": "सबमिट करें",
"WaitForHostMsg": "सम्मेलन <b>{{room}}</b> अभी तक शुरू नहीं हुआ है। यदि आप मेजबान हैं तो कृपया प्रमाणित करें। अन्यथा, कृपया मेजबान के आने की प्रतीक्षा करें।",
"WaitForHostMsgWOk": "सम्मेलन <b>{{room}}</b> अभी तक शुरू नहीं हुआ है। यदि आप मेजबान हैं तो कृपया प्रमाणित करने के लिए ओके दबाएं। अन्यथा, कृपया मेजबान के आने की प्रतीक्षा करें।",
"WaitForHostMsg": "सम्मेलन अभी तक शुरू नहीं हुआ है। यदि आप मेजबान हैं तो कृपया प्रमाणित करें। अन्यथा, कृपया मेजबान के आने की प्रतीक्षा करें।",
"WaitingForHostTitle": "होस्ट की प्रतीक्षा कर रहा है ...",
"Yes": "हाँ",
"accessibilityLabel": {

View File

@@ -146,7 +146,6 @@
"Share": "",
"Submit": "Pošalji",
"WaitForHostMsg": "",
"WaitForHostMsgWOk": "",
"WaitingForHost": "",
"Yes": "Da",
"accessibilityLabel": {

View File

@@ -156,8 +156,7 @@
"Remove": "Eltávolítás",
"Share": "Megosztás",
"Submit": "Elküldés",
"WaitForHostMsg": "A <b>{{room}}</b> konferencia még nem kezdődött meg. Ha Ön a házigazda, akkor hitelesítse magát. Ellenkező esetben, kérjük várjon a házigazda érkezésére.",
"WaitForHostMsgWOk": "A <b>{{room}}</b> konferencia még nem kezdődött meg. Ha Ön a házigazda, kérjük az „OK” gombra kattintva hitelesítse magát. Ellenkező esetben, kérjük várjon a házigazda érkezésére.",
"WaitForHostMsg": "A konferencia még nem kezdődött meg. Ha Ön a házigazda, akkor hitelesítse magát. Ellenkező esetben, kérjük várjon a házigazda érkezésére.",
"WaitingForHost": "Várakozás a házigazdára…",
"Yes": "Igen",
"accessibilityLabel": {

View File

@@ -136,7 +136,6 @@
"Share": "Տարածել",
"Submit": "Ներմուծել",
"WaitForHostMsg": "",
"WaitForHostMsgWOk": "",
"WaitingForHost": "Սպասում է հյուրընկալողի …",
"Yes": "Այո",
"accessibilityLabel": {

View File

@@ -155,8 +155,7 @@
"Remove": "Remove",
"Share": "Share",
"Submit": "Submit",
"WaitForHostMsg": "The conference <b>{{room}}</b> has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
"WaitForHostMsgWOk": "The conference <b>{{room}}</b> has not yet started. If you are the host then please press Ok to authenticate. Otherwise, please wait for the host to arrive.",
"WaitForHostMsg": "The conference has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
"WaitingForHost": "Waiting for the host ...",
"Yes": "Yes",
"accessibilityLabel": {

View File

@@ -155,8 +155,7 @@
"Remove": "Fjarlægja",
"Share": "Deila",
"Submit": "Senda inn",
"WaitForHostMsg": "Fjarfundurinn <b>{{room}}</b> er ekki byrjaður. Ef þú ert gestgjafinn skaltu auðkenna þig. Annars ættiðu að bíða eftir að gestgjafinn skrái sig inn.",
"WaitForHostMsgWOk": "Fjarfundurinn <b>{{room}}</b> er ekki byrjaður. Ef þú ert gestgjafinn skaltu ýta á 'Í lagi' til að auðkenna þig. Annars ættiðu að bíða eftir að gestgjafinn skrái sig inn.",
"WaitForHostMsg": "Fjarfundurinn er ekki byrjaður. Ef þú ert gestgjafinn skaltu auðkenna þig. Annars ættiðu að bíða eftir að gestgjafinn skrái sig inn.",
"WaitingForHost": "Bíð eftir að gestgjafanum ...",
"Yes": "Já",
"accessibilityLabel": {

View File

@@ -185,8 +185,7 @@
"Remove": "Rimuovi",
"Share": "Condividi",
"Submit": "Invia",
"WaitForHostMsg": "La riunione <b>{{room}}</b> non è ancora cominciata. Se sei l'organizzatore, per favore autenticati. Altrimenti, aspetta l'arrivo dell'organizzatore.",
"WaitForHostMsgWOk": "La riunione <b>{{room}}</b> non è ancora cominciata. Se sei l'organizzatore, allora premi OK per autenticarti. Altrimenti, aspetta l'arrivo dell'organizzatore.",
"WaitForHostMsg": "La riunione non è ancora cominciata. Se sei l'organizzatore, per favore autenticati. Altrimenti, aspetta l'arrivo dell'organizzatore.",
"WaitingForHost": "In attesa dell'organizzatore...",
"Yes": "Sì",
"accessibilityLabel": {

View File

@@ -208,8 +208,7 @@
"Remove": "除去",
"Share": "共有",
"Submit": "投稿",
"WaitForHostMsg": "ミーティング <b>{{room}}</b> はまだ開始されていません。あなたがホストの場合は、認証を行ってください。それ以外の場合は、ホストの到着をお待ちください。",
"WaitForHostMsgWOk": "ミーティング <b>{{room}}</b> はまだ開始されていません。あなたがホストの場合は、OKを押して認証を行ってください。それ以外の場合は、ホストの到着をお待ちください。",
"WaitForHostMsg": "ミーティング はまだ開始されていません。あなたがホストの場合は、認証を行ってください。それ以外の場合は、ホストの到着をお待ちください。",
"WaitingForHostTitle": "ホストの到着を待っています...",
"Yes": "はい",
"accessibilityLabel": {

View File

@@ -185,8 +185,7 @@
"Remove": "Sfeḍ",
"Share": "Bḍu",
"Submit": "Azen",
"WaitForHostMsg": "Asarag <b>{{room}}</b> mazal ur yebdi ara. Ma yella d kečč·kemm i d asenneftaɣ, ttxil-k·m ilaq usesteb. Ma yella xaṭi, ttxil-k·m rǧu asenneftaɣ ad d-yaweḍ.",
"WaitForHostMsgWOk": "Asarag <b>{{room}}</b> mazal ur yebdi ara. Ma yella d kečč·kemm i d asenneftaɣ, ttxil-k·m sit ɣef Ih i usesteb. Ma yella xaṭi, ttxil-k·m rǧu asenneftaɣ ad d-yaweḍ.",
"WaitForHostMsg": "Asarag mazal ur yebdi ara. Ma yella d kečč·kemm i d asenneftaɣ, ttxil-k·m ilaq usesteb. Ma yella xaṭi, ttxil-k·m rǧu asenneftaɣ ad d-yaweḍ.",
"WaitingForHostTitle": "Aṛaǧu n usenneftaɣ ...",
"Yes": "Ih",
"accessibilityLabel": {

View File

@@ -168,8 +168,7 @@
"Remove": "제거",
"Share": "공유",
"Submit": "제출",
"WaitForHostMsg": "<b>{{room}}</b> 회의가 시작되지 않았습니다. 호스트인 경우 인증하십시오. 그렇지 않으면 호스트가 도착할 때까지 기다리십시오.",
"WaitForHostMsgWOk": "<b>{{room}}</b> 회의가 아직 시작되지 않았습니다. 호스트인 경우 확인을 눌러 인증하십시오. 그렇지 않으면 호스트가 도착할 때까지 기다리십시오.",
"WaitForHostMsg": "회의가 시작되지 않았습니다. 호스트인 경우 인증하십시오. 그렇지 않으면 호스트가 도착할 때까지 기다리십시오.",
"WaitingForHost": "호스트를 기다리는 중입니다…",
"Yes": "예",
"accessibilityLabel": {

View File

@@ -155,8 +155,7 @@
"Remove": "Pašalinti",
"Share": "Dalintis",
"Submit": "Pateikti",
"WaitForHostMsg": "Konferencija <b>{{room}}</b> dar neprasidėjo. Jei jūs organizatorius, prašome tai patvirtinti. Jei ne, prašome palaukti organizatoriaus.",
"WaitForHostMsgWOk": "Konferencija <b>{{room}}</b> dar neprasidėjo. Jei jūs organizatorius, prašome tai patvirtinti. Jei ne, prašome palaukti organizatoriaus.",
"WaitForHostMsg": "Konferencija dar neprasidėjo. Jei jūs organizatorius, prašome tai patvirtinti. Jei ne, prašome palaukti organizatoriaus.",
"WaitingForHost": "Laukiama organizatoriaus ...",
"Yes": "Taip",
"accessibilityLabel": {

View File

@@ -155,8 +155,7 @@
"Remove": "Noņemt",
"Share": "Kopīgot",
"Submit": "ОК",
"WaitForHostMsg": "Sapulce <b>{{room}}</b> vēl nav sākusies. Ja esat sapulces rīkotājs, lūdzu autorizējaties. Ja nē, sagaidiet rīkotāju.",
"WaitForHostMsgWOk": "Sapulce <b>{{room}}</b> vēl nav sākusies. Ja esat sapulces rīkotājs, lūdzu nospiediet |Ok|, lai autentificētos. Ja nē, sagaidiet rīkotāju.",
"WaitForHostMsg": "Sapulce vēl nav sākusies. Ja esat sapulces rīkotājs, lūdzu autorizējaties. Ja nē, sagaidiet rīkotāju.",
"WaitingForHost": "Gaidām rīkotāju...",
"Yes": "Jā",
"accessibilityLabel": {

View File

@@ -174,8 +174,7 @@
"Remove": "നീക്കംചെയ്യുക",
"Share": "പങ്കിടുക",
"Submit": "സമർപ്പിക്കുക",
"WaitForHostMsg": "The conference <b>{{room}}</b> has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
"WaitForHostMsgWOk": "The conference <b>{{room}}</b> has not yet started. If you are the host then please press Ok to authenticate. Otherwise, please wait for the host to arrive.",
"WaitForHostMsg": "The conference has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
"WaitingForHost": "ഹോസ്റ്റിനായി കാത്തിരിക്കുന്നു ...",
"Yes": "അതെ",
"accessibilityLabel": {

View File

@@ -155,8 +155,7 @@
"Remove": "Устгах",
"Share": "Хуваалцах",
"Submit": "Илгээх",
"WaitForHostMsg": "<b>{{room}}</b> хурал хараахан эхлээгүй байна. Хэрэв та хост байгаа бол нэвтэрнэ үү. Үгүй бол хост ирэхийг хүлээнэ үү.",
"WaitForHostMsgWOk": "<b>{{room}}</b> хурал хараахан эхлээгүй байна. Хэрэв та хост эзэмшигч бол баталгаажуулахын тулд Ok дээр дарна уу. Үгүй бол хост ирэхийг хүлээнэ үү.",
"WaitForHostMsg": "Xурал хараахан эхлээгүй байна. Хэрэв та хост байгаа бол нэвтэрнэ үү. Үгүй бол хост ирэхийг хүлээнэ үү.",
"WaitingForHost": "Хостыг хүлээж байна ...",
"Yes": "Тийм",
"accessibilityLabel": {

View File

@@ -155,8 +155,7 @@
"Remove": "काढा",
"Share": "सामायिक करा",
"Submit": "प्रस्तुत करणे",
"WaitForHostMsg": "परिषद <b>{{room}}</b>अद्याप सुरू झाले नाही. आपण होस्ट असल्यास कृपया अधिकृत करा. अन्यथा, कृपया होस्ट येण्याची प्रतीक्षा करा.",
"WaitForHostMsgWOk": "परिषद <b>{{room}}</b> अद्याप सुरू झाले नाही. आपण होस्ट असल्यास कृपया प्रमाणीकरणासाठी ओके दाबा. अन्यथा, कृपया होस्ट येण्याची प्रतीक्षा करा.",
"WaitForHostMsg": "परिषद अद्याप सुरू झाले नाही. आपण होस्ट असल्यास कृपया अधिकृत करा. अन्यथा, कृपया होस्ट येण्याची प्रतीक्षा करा.",
"WaitingForHost": " होस्टची प्रतीक्षा करीत आहे ...",
"Yes": "होय",
"accessibilityLabel": {

View File

@@ -135,7 +135,6 @@
"Share": "Del",
"Submit": "Send inn",
"WaitForHostMsg": "",
"WaitForHostMsgWOk": "",
"WaitingForHost": "",
"Yes": "Ja",
"accessibilityLabel": {

View File

@@ -206,8 +206,7 @@
"Remove": "Verwijderen",
"Share": "Delen",
"Submit": "Verzenden",
"WaitForHostMsg": "De vergadering <b>{{room}}</b> is nog niet gestart. Authenticeer uzelf als u de host bent. Anders wacht u tot de host aanwezig is.",
"WaitForHostMsgWOk": "De vergadering <b>{{room}}</b> is nog niet gestart. Als u de host bent, drukt u op 'OK' om uzelf te authenticeren. Anders wacht u tot de host aanwezig is.",
"WaitForHostMsg": "De vergadering is nog niet gestart. Authenticeer uzelf als u de host bent. Anders wacht u tot de host aanwezig is.",
"Yes": "Ja",
"accessibilityLabel": {
"liveStreaming": "Livestream"

View File

@@ -208,8 +208,7 @@
"Remove": "Suprimir",
"Share": "Partejar",
"Submit": "Validar",
"WaitForHostMsg": "La conferéncia <b>{{room}}</b> a pas encara començat. Se sètz lòst volgatz ben vos identificar. Autrament esperatz quarribe lòste.",
"WaitForHostMsgWOk": "La conferéncia <b>{{room}}</b> a pas encara començat. Se sètz lòst volgatz ben clicar Ok per vos identificar. Autrament esperatz quarribe lòste.",
"WaitForHostMsg": "La conferéncia a pas encara començat. Se sètz lòst volgatz ben vos identificar. Autrament esperatz quarribe lòste.",
"WaitingForHostTitle": "En espèra de lòste...",
"Yes": "Òc",
"accessibilityLabel": {

View File

@@ -208,8 +208,7 @@
"Remove": "Usuń",
"Share": "Udostępnij",
"Submit": "Wyślij",
"WaitForHostMsg": "Spotkanie <b>{{room}}</b> jeszcze się nie rozpoczęło. Jeśli jesteś gospodarzem, prosimy o uwierzytelnienie. Jeśli nie, prosimy czekać na przybycie gospodarza.",
"WaitForHostMsgWOk": "Spotkanie <b>{{room}}</b> jeszcze się nie rozoczęło. Jeśli jesteś jej gospodarzem, wybierz Ok, aby się uwierzytelnić. Jeśli nie, prosimy czekać na przybycie gospodarza.",
"WaitForHostMsg": "Spotkanie jeszcze się nie rozpoczęło. Jeśli jesteś gospodarzem, prosimy o uwierzytelnienie. Jeśli nie, prosimy czekać na przybycie gospodarza.",
"WaitingForHostTitle": "Oczekiwanie na gospodarza...",
"Yes": "Tak",
"accessibilityLabel": {

View File

@@ -208,8 +208,7 @@
"Remove": "Remover",
"Share": "Partilhar",
"Submit": "Submeter",
"WaitForHostMsg": "A conferência <b>{{room}}</b> ainda não começou. Se for o anfitrião, por favor autentique. Caso contrário, por favor aguarde que o anfitrião chegue.",
"WaitForHostMsgWOk": "A conferência <b>{{room}}</b> ainda não começou. Se for o anfitrião, por favor prima Ok para autenticar. Caso contrário, por favor aguarde que o anfitrião chegue.",
"WaitForHostMsg": "A conferência ainda não começou. Se for o anfitrião, por favor autentique. Caso contrário, por favor aguarde que o anfitrião chegue.",
"WaitingForHostTitle": "À espera do anfitrião ...",
"Yes": "Sim",
"accessibilityLabel": {

View File

@@ -185,8 +185,7 @@
"Remove": "Remover",
"Share": "Compartilhar",
"Submit": "Enviar",
"WaitForHostMsg": "A conferência <b>{{room}}</b> ainda não começou. Se você é o anfitrião, faça a autenticação. Do contrário, aguarde a chegada do anfitrião.",
"WaitForHostMsgWOk": "A conferência <b>{{room}}</b> ainda não começou. Se você é o anfitrião, pressione OK para autenticar. Do contrário, aguarde a chegada do anfitrião.",
"WaitForHostMsg": "A conferência ainda não começou. Se você é o anfitrião, faça a autenticação. Do contrário, aguarde a chegada do anfitrião.",
"WaitingForHostTitle": "Esperando o anfitrião...",
"Yes": "Sim",
"accessibilityLabel": {

View File

@@ -159,8 +159,7 @@
"Remove": "Eliminați",
"Share": "Partajare",
"Submit": "Trimiteți",
"WaitForHostMsg": "Conferința {{room}} nu a început. Daca sunteți moderatorul conferinței, vă rugăm să vă autentificați. Dacă nu, așteptați ca moderatorul să înceapă conferința.",
"WaitForHostMsgWOk": "Conferința {{room}} nu a început. Daca sunteți moderatorul, apăsați butonul OK pentru autentificare. Dacă nu, așteptați ca moderatorul să înceapă conferința.",
"WaitForHostMsg": "Conferința nu a început. Daca sunteți moderatorul conferinței, vă rugăm să vă autentificați. Dacă nu, așteptați ca moderatorul să înceapă conferința.",
"WaitingForHost": "Așteptare moderator conferință ...",
"Yes": "Da",
"accessibilityLabel": {

View File

@@ -185,8 +185,7 @@
"Remove": "Удалить",
"Share": "Поделиться",
"Submit": "ОК",
"WaitForHostMsg": "Конференция <b>{{room}}</b> еще не началась. Если вы организатор, пожалуйста, авторизируйтесь. В противном случае дождитесь организатора.",
"WaitForHostMsgWOk": "Конференция <b>{{room}}</b> еще не началась. Если вы организатор, пожалуйста, нажмите Ok для аутентификации. В противном случае, дождитесь организатора.",
"WaitForHostMsg": "Конференция еще не началась. Если вы организатор, пожалуйста, авторизируйтесь. В противном случае дождитесь организатора.",
"WaitingForHost": "Ждем организатора...",
"Yes": "Да",
"accessibilityLabel": {

View File

@@ -155,8 +155,7 @@
"Remove": "Boga",
"Share": "Cumpartzi",
"Submit": "Imbia",
"WaitForHostMsg": "Sa cunferèntzia <b>{{room}}</b> no est cumintzada. Si ses mere de custa cunferèntzia, autèntica·ti. Si nono, iseta chi arribet.",
"WaitForHostMsgWOk": "Sa cunferèntzia <b>{{room}}</b> no est cumintzada. Si ses mere, incarca AB pro ti autenticare. Si nono, iseta chi arribet.",
"WaitForHostMsg": "Sa cunferèntzia no est cumintzada. Si ses mere de custa cunferèntzia, autèntica·ti. Si nono, iseta chi arribet.",
"WaitingForHost": "Isetende mere...",
"Yes": "Eja",
"accessibilityLabel": {

View File

@@ -174,8 +174,7 @@
"Remove": "Odstrániť",
"Share": "Zdieľať",
"Submit": "OK",
"WaitForHostMsg": "Konferencia <b>{{room}}</b> sa ešte nezačala. Autorizujte sa prosím ak ste hostiteľ. V opačnom prípade čakajte na hostiteľa.",
"WaitForHostMsgWOk": "Konferencia <b>{{room}}</b> sa ešte nezačala. Ak ste hostiteľ autorizujte sa stlačením Ok. V opačnom prípade čakajte na hostiteľa.",
"WaitForHostMsg": "Konferencia sa ešte nezačala. Autorizujte sa prosím ak ste hostiteľ. V opačnom prípade čakajte na hostiteľa.",
"WaitingForHost": "Čakám na hostiteľa ...",
"Yes": "Áno",
"accessibilityLabel": {

View File

@@ -185,8 +185,7 @@
"Remove": "Odstrani",
"Share": "Deli",
"Submit": "Pošlji",
"WaitForHostMsg": "Konferenca v sobi <b>{{room}}</b> se še ni začela. Če ste gostitelj, se prosimo prijavite, sicer pa počakajte na gostitelja srečanja.",
"WaitForHostMsgWOk": "Konferenca v sobi <b>{{room}}</b> se še ni začela. Če ste gostitelj, prisisnite OK in se prijavite, sicer pa počakajte na gostitelja srečanja.",
"WaitForHostMsg": "Konferenca v sobi se še ni začela. Če ste gostitelj, se prosimo prijavite, sicer pa počakajte na gostitelja srečanja.",
"WaitingForHostTitle": "Čakanje gostitelja ...",
"Yes": "Da",
"accessibilityLabel": {

View File

@@ -208,8 +208,7 @@
"Remove": "Hiqe",
"Share": "Ndaje",
"Submit": "Parashtroje",
"WaitForHostMsg": "Konferenca <b>{{room}}</b> ska nisur ende. Nëse jeni organizatori, ju lutemi, bëni mirëfilltësimin. Përndryshe, ju lutemi, pritni që të mbërrijë organizatori.",
"WaitForHostMsgWOk": "Konferenca <b>{{room}}</b> ska nisur ende. Nëse jeni organizatori, ju lutemi, shtypni OK që të bëhet mirëfilltësimi. Përndryshe, ju lutemi, pritni që të mbërrijë organizatori.",
"WaitForHostMsg": "Konferenca ska nisur ende. Nëse jeni organizatori, ju lutemi, bëni mirëfilltësimin. Përndryshe, ju lutemi, pritni që të mbërrijë organizatori.",
"WaitingForHostTitle": "Po pritet për organizatorin…",
"Yes": "Po",
"accessibilityLabel": {

View File

@@ -144,7 +144,6 @@
"Share": "",
"Submit": "Пошаљи",
"WaitForHostMsg": "",
"WaitForHostMsgWOk": "",
"WaitingForHost": "",
"Yes": "Да",
"accessibilityLabel": {

View File

@@ -195,8 +195,7 @@
"Remove": "Ta bort",
"Share": "Dela",
"Submit": "Skicka",
"WaitForHostMsg": "Konferensen <b>{{room}}</b> har inte börjat än. Autentisera konferensen om du är värd. Vänta annars på att värden startar konferensen.",
"WaitForHostMsgWOk": "Konferensen <b>{{room}}</b> har inte börjat än. Om du är värd, autentisera konferensen genom att trycka på Ok. Vänta annars på att värden startar konferensen.",
"WaitForHostMsg": "Konferensen har inte börjat än. Autentisera konferensen om du är värd. Vänta annars på att värden startar konferensen.",
"WaitingForHost": "Väntar på värden ...",
"WaitingForHostTitle": "Väntar på värden ...",
"Yes": "Ja",

View File

@@ -180,8 +180,7 @@
"Remove": "తీసివేయి",
"Share": "పంచుకోండి",
"Submit": "దాఖలుచేయి",
"WaitForHostMsg": "The conference <b>{{room}}</b> has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
"WaitForHostMsgWOk": "The conference <b>{{room}}</b> has not yet started. If you are the host then please press Ok to authenticate. Otherwise, please wait for the host to arrive.",
"WaitForHostMsg": "The conference has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
"WaitingForHostTitle": "అతిథేయి కోసం వేచివున్నాం ...",
"Yes": "అవును",
"accessibilityLabel": {

View File

@@ -195,8 +195,7 @@
"Remove": "Kaldır",
"Share": "Paylaş",
"Submit": "Gönder",
"WaitForHostMsg": "<b>{{room}}</b> toplantısı henüz başlamadı. Toplantı sahibi sizseniz, lütfen kimlik doğrulaması yapın. Değilseniz lütfen toplantı sahibinin gelmesini bekleyin.",
"WaitForHostMsgWOk": "<b>{{room}}</b> toplantısı henüz başlamadı. Toplantı sahibi sizseniz, kimlik doğrulaması için Tamam butonuna basın. Değilseniz lütfen toplantı sahibinin gelmesini bekleyin.",
"WaitForHostMsg": "Toplantısı henüz başlamadı. Toplantı sahibi sizseniz, lütfen kimlik doğrulaması yapın. Değilseniz lütfen toplantı sahibinin gelmesini bekleyin.",
"WaitingForHost": "Toplantı sahibi bekleniyor...",
"WaitingForHostTitle": "Toplantı sahibi bekleniyor ...",
"Yes": "Evet",

View File

@@ -177,8 +177,7 @@
"Remove": "Вилучити",
"Share": "Поділитися",
"Submit": "Гаразд",
"WaitForHostMsg": "Конференція <b>{{room}}</b> ще не почалася. Якщо ви є організатором, будь ласка, авторизуйтеся або дочекайтеся організатора.",
"WaitForHostMsgWOk": "Конференція <b>{{room}}</b> ще не почалася. Якщо ви є організатором, будь ласка, клацніть на кнопку \"Гаразд\" для авторизації або дочекайтеся організатора.",
"WaitForHostMsg": "Конференція ще не почалася. Якщо ви є організатором, будь ласка, авторизуйтеся або дочекайтеся організатора.",
"WaitingForHost": "Чекаємо на організатора...",
"Yes": "Так",
"accessibilityLabel": {

View File

@@ -146,8 +146,7 @@
"Remove": "Xóa",
"Share": "Chia sẻ",
"Submit": "Đăng ký",
"WaitForHostMsg": "Cuộc họp <b>{{room}}</b> chưa được khởi tạo. Nếu bạn là chủ nghị vui lòng xác thực. Nếu không, vui lòng đợi chủ nghị.",
"WaitForHostMsgWOk": "Cuộc họp <b>{{room}}</b> chưa được khởi tạo. Nếu bạn là chủ nghị vui lòng nhấn OK để xác thực. Nếu không, vui lòng đợi chủ nghị.",
"WaitForHostMsg": "Cuộc họp chưa được khởi tạo. Nếu bạn là chủ nghị vui lòng xác thực. Nếu không, vui lòng đợi chủ nghị.",
"WaitingForHost": "Đang đợi chủ nghị …",
"Yes": "Có",
"accessibilityLabel": {

View File

@@ -174,8 +174,7 @@
"Remove": "移除",
"Share": "分享",
"Submit": "提交",
"WaitForHostMsg": "会议<b>{{room}}</b>尚未开始。如果您是主持人,请进行身份验证。否则,请等待主持人的到来。",
"WaitForHostMsgWOk": "会议<b>{{room}}</b>尚未开始。如果您是主持人,请进行身份验证。否则,请等待主持人的到来。",
"WaitForHostMsg": "会议 尚未开始。如果您是主持人,请进行身份验证。否则,请等待主持人的到来。",
"WaitingForHost": "等待主持人。。。",
"Yes": "是",
"accessibilityLabel": {

View File

@@ -207,8 +207,7 @@
"Remove": "移除",
"Share": "分享",
"Submit": "提交",
"WaitForHostMsg": "此會議 <b>{{room}}</b> 尚未啟動。如果您是會議主人,請進行認證;否則,請等待會議主人到達。",
"WaitForHostMsgWOk": "此會議 <b>{{room}}</b> 尚未啟動。如果您是會議主人,請按 [確定] 進行認證;否則,請等待會議主人到達。",
"WaitForHostMsg": "此會議 尚未啟動。如果您是會議主人,請進行認證;否則,請等待會議主人到達。",
"WaitingForHost": "等侯主辦人...",
"Yes": "是的",
"accessibilityLabel": {

View File

@@ -208,8 +208,7 @@
"Remove": "Remove",
"Share": "Share",
"Submit": "Submit",
"WaitForHostMsg": "The conference <b>{{room}}</b> has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
"WaitForHostMsgWOk": "The conference <b>{{room}}</b> has not yet started. If you are the host then please press Ok to authenticate. Otherwise, please wait for the host to arrive.",
"WaitForHostMsg": "The conference has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
"WaitingForHostTitle": "Waiting for the host ...",
"Yes": "Yes",
"accessibilityLabel": {

View File

@@ -72,7 +72,7 @@ import {
captureLargeVideoScreenshot,
resizeLargeVideo
} from '../../react/features/large-video/actions.web';
import { toggleLobbyMode, setKnockingParticipantApproval } from '../../react/features/lobby/actions';
import { toggleLobbyMode, answerKnockingParticipant } from '../../react/features/lobby/actions';
import {
close as closeParticipantsPane,
open as openParticipantsPane
@@ -140,7 +140,7 @@ function initCommands() {
APP.store.dispatch(createBreakoutRoom(name));
},
'answer-knocking-participant': (id, approved) => {
APP.store.dispatch(setKnockingParticipantApproval(id, approved));
APP.store.dispatch(answerKnockingParticipant(id, approved));
},
'approve-video': participantId => {
if (!isLocalParticipantModerator(APP.store.getState())) {

10
package-lock.json generated
View File

@@ -67,7 +67,7 @@
"jquery-i18next": "1.2.1",
"js-md5": "0.6.1",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1376.0.0+f881b3c7/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1389.0.0+313e0dd3/lib-jitsi-meet.tgz",
"libflacjs": "https://git@github.com/mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"lodash": "4.17.21",
"moment": "2.29.1",
@@ -11496,8 +11496,8 @@
},
"node_modules/lib-jitsi-meet": {
"version": "0.0.0",
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1376.0.0+f881b3c7/lib-jitsi-meet.tgz",
"integrity": "sha512-+aPY24SwVELcpkYOMPqdroj4LPRJfr+WJfzGEB4cg3hpbZa71zISout1SvfdLxrFuHqWWozuaUbO0s0auGYWwg==",
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1389.0.0+313e0dd3/lib-jitsi-meet.tgz",
"integrity": "sha512-+SDQ2xqBg1eO0b6vQCm+Lqxff9M+/SLK5LGg05dFDaZ3ih94yZ9v2qcSfZxD1pu/QPok4ioV48n/FeRFNNRByQ==",
"license": "Apache-2.0",
"dependencies": {
"@jitsi/js-utils": "2.0.0",
@@ -28078,8 +28078,8 @@
}
},
"lib-jitsi-meet": {
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1376.0.0+f881b3c7/lib-jitsi-meet.tgz",
"integrity": "sha512-+aPY24SwVELcpkYOMPqdroj4LPRJfr+WJfzGEB4cg3hpbZa71zISout1SvfdLxrFuHqWWozuaUbO0s0auGYWwg==",
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1389.0.0+313e0dd3/lib-jitsi-meet.tgz",
"integrity": "sha512-+SDQ2xqBg1eO0b6vQCm+Lqxff9M+/SLK5LGg05dFDaZ3ih94yZ9v2qcSfZxD1pu/QPok4ioV48n/FeRFNNRByQ==",
"requires": {
"@jitsi/js-utils": "2.0.0",
"@jitsi/logger": "2.0.0",

View File

@@ -72,7 +72,7 @@
"jquery-i18next": "1.2.1",
"js-md5": "0.6.1",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1376.0.0+f881b3c7/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1389.0.0+313e0dd3/lib-jitsi-meet.tgz",
"libflacjs": "https://git@github.com/mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"lodash": "4.17.21",
"moment": "2.29.1",

View File

@@ -13,11 +13,6 @@ import { openLoginDialog, cancelWaitForOwner } from '../../actions.native';
*/
type Props = {
/**
* The name of the conference room (without the domain part).
*/
_room: string,
/**
* Redux store dispatch function.
*/
@@ -57,20 +52,11 @@ class WaitForOwnerDialog extends Component<Props> {
* @returns {ReactElement}
*/
render() {
const {
_room: room
} = this.props;
return (
<ConfirmDialog
cancelLabel = 'dialog.Cancel'
confirmLabel = 'dialog.IamHost'
descriptionKey = {
{
key: 'dialog.WaitForHostMsgWOk',
params: { room }
}
}
descriptionKey = 'dialog.WaitForHostMsg'
onCancel = { this._onCancel }
onSubmit = { this._onLogin } />
);
@@ -101,20 +87,4 @@ class WaitForOwnerDialog extends Component<Props> {
}
}
/**
* Maps (parts of) the Redux state to the associated props for the
* {@code WaitForOwnerDialog} component.
*
* @param {Object} state - The Redux state.
* @private
* @returns {Props}
*/
function _mapStateToProps(state) {
const { authRequired } = state['features/base/conference'];
return {
_room: authRequired && authRequired.getName()
};
}
export default translate(connect(_mapStateToProps)(WaitForOwnerDialog));
export default translate(connect()(WaitForOwnerDialog));

View File

@@ -4,9 +4,8 @@ import React, { PureComponent } from 'react';
import type { Dispatch } from 'redux';
import { Dialog } from '../../../base/dialog';
import { translate, translateToHTML } from '../../../base/i18n';
import { translate } from '../../../base/i18n';
import { connect } from '../../../base/redux';
import { safeDecodeURIComponent } from '../../../base/util';
import { cancelWaitForOwner } from '../../actions.web';
/**
@@ -14,11 +13,6 @@ import { cancelWaitForOwner } from '../../actions.web';
*/
type Props = {
/**
* The name of the conference room (without the domain part).
*/
_room: string,
/**
* Redux store dispatch method.
*/
@@ -89,7 +83,6 @@ class WaitForOwnerDialog extends PureComponent<Props> {
*/
render() {
const {
_room: room,
t
} = this.props;
@@ -103,30 +96,11 @@ class WaitForOwnerDialog extends PureComponent<Props> {
titleKey = { t('dialog.WaitingForHostTitle') }
width = { 'small' }>
<span>
{
translateToHTML(
t, 'dialog.WaitForHostMsg', { room })
}
{ t('dialog.WaitForHostMsg') }
</span>
</Dialog>
);
}
}
/**
* Maps (parts of) the Redux state to the associated props for the
* {@code WaitForOwnerDialog} component.
*
* @param {Object} state - The Redux state.
* @private
* @returns {Props}
*/
function mapStateToProps(state) {
const { authRequired } = state['features/base/conference'];
return {
_room: authRequired && safeDecodeURIComponent(authRequired.getName())
};
}
export default translate(connect(mapStateToProps)(WaitForOwnerDialog));
export default translate(connect()(WaitForOwnerDialog));

View File

@@ -22,6 +22,7 @@ export default [
'apiLogLevels',
'avgRtpStatsN',
'backgroundAlpha',
'breakoutRooms',
'buttonsWithNotifyClick',
/**

View File

@@ -342,6 +342,14 @@ function _translateLegacyConfig(oldValue: Object) {
newValue.defaultRemoteDisplayName = interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;
}
if (oldValue.hideAddRoomButton) {
newValue.breakoutRooms = {
/* eslint-disable-next-line no-extra-parens */
...(newValue.breakoutRooms || {}),
hideAddRoomButton: oldValue.hideAddRoomButton
};
}
newValue.defaultRemoteDisplayName
= newValue.defaultRemoteDisplayName || 'Fellow Jitster';

View File

@@ -3,6 +3,8 @@
import { toState } from '../redux';
import { toURLString } from '../util';
import { getURLWithoutParams } from './utils';
/**
* Figures out what's the current conference URL which is supposed to indicate what conference is currently active.
* When not currently in any conference and not trying to join any then 'undefined' is returned.
@@ -79,56 +81,6 @@ export function isInviteURLReady(stateOrGetState: Function | Object): boolean {
return Boolean(state['features/base/connection'].locationURL || state['features/base/config'].locationURL);
}
/**
* Gets a {@link URL} without hash and query/search params from a specific
* {@code URL}.
*
* @param {URL} url - The {@code URL} which may have hash and query/search
* params.
* @returns {URL}
*/
export function getURLWithoutParams(url: URL): URL {
const { hash, search } = url;
if ((hash && hash.length > 1) || (search && search.length > 1)) {
url = new URL(url.href); // eslint-disable-line no-param-reassign
url.hash = '';
url.search = '';
// XXX The implementation of URL at least on React Native appends ? and
// # at the end of the href which is not desired.
let { href } = url;
if (href) {
href.endsWith('#') && (href = href.substring(0, href.length - 1));
href.endsWith('?') && (href = href.substring(0, href.length - 1));
// eslint-disable-next-line no-param-reassign
url.href === href || (url = new URL(href));
}
}
return url;
}
/**
* Gets a URL string without hash and query/search params from a specific
* {@code URL}.
*
* @param {URL} url - The {@code URL} which may have hash and query/search
* params.
* @returns {string}
*/
export function getURLWithoutParamsNormalized(url: URL): string {
const urlWithoutParams = getURLWithoutParams(url).href;
if (urlWithoutParams) {
return urlWithoutParams.toLowerCase();
}
return '';
}
/**
* Converts a specific id to jid if it's not jid yet.
*

View File

@@ -4,3 +4,4 @@ export * from './actions';
export * from './actionTypes';
export * from './constants';
export * from './functions';
export * from './utils';

View File

@@ -0,0 +1,51 @@
/* @flow */
/**
* Gets a {@link URL} without hash and query/search params from a specific
* {@code URL}.
*
* @param {URL} url - The {@code URL} which may have hash and query/search
* params.
* @returns {URL}
*/
export function getURLWithoutParams(url: URL): URL {
const { hash, search } = url;
if ((hash && hash.length > 1) || (search && search.length > 1)) {
url = new URL(url.href); // eslint-disable-line no-param-reassign
url.hash = '';
url.search = '';
// XXX The implementation of URL at least on React Native appends ? and
// # at the end of the href which is not desired.
let { href } = url;
if (href) {
href.endsWith('#') && (href = href.substring(0, href.length - 1));
href.endsWith('?') && (href = href.substring(0, href.length - 1));
// eslint-disable-next-line no-param-reassign
url.href === href || (url = new URL(href));
}
}
return url;
}
/**
* Gets a URL string without hash and query/search params from a specific
* {@code URL}.
*
* @param {URL} url - The {@code URL} which may have hash and query/search
* params.
* @returns {string}
*/
export function getURLWithoutParamsNormalized(url: URL): string {
const urlWithoutParams = getURLWithoutParams(url).href;
if (urlWithoutParams) {
return urlWithoutParams.toLowerCase();
}
return '';
}

View File

@@ -5,6 +5,7 @@ declare var APP: Object;
import COUNTRIES_RESOURCES from 'i18n-iso-countries/langs/en.json';
import i18next from 'i18next';
import I18nextXHRBackend from 'i18next-xhr-backend';
import _ from 'lodash';
import LANGUAGES_RESOURCES from '../../../../lang/languages.json';
import MAIN_RESOURCES from '../../../../lang/main.json';
@@ -12,6 +13,20 @@ import MAIN_RESOURCES from '../../../../lang/main.json';
import { I18NEXT_INITIALIZED, LANGUAGE_CHANGED } from './actionTypes';
import languageDetector from './languageDetector';
/**
* Override certain country names.
*/
const COUNTRIES_RESOURCES_OVERRIDES = {
countries: {
TW: 'Taiwan'
}
};
/**
* Merged country names.
*/
const COUNTRIES = _.merge({}, COUNTRIES_RESOURCES, COUNTRIES_RESOURCES_OVERRIDES);
/**
* The available/supported languages.
*
@@ -68,7 +83,7 @@ i18next
i18next.addResourceBundle(
DEFAULT_LANGUAGE,
'countries',
COUNTRIES_RESOURCES,
COUNTRIES,
/* deep */ true,
/* overwrite */ true);
i18next.addResourceBundle(

View File

@@ -1,5 +1,7 @@
import React, { Component } from 'react';
import { getFixedPlatformStyle } from '../../../styles';
/**
* Implements a React/Web {@link Component} for displaying text similar to React
* Native's {@code Text} in order to facilitate cross-platform source code.
@@ -14,6 +16,12 @@ export default class Text extends Component {
* @returns {ReactElement}
*/
render() {
return React.createElement('span', this.props);
// eslint-disable-next-line react/prop-types
const _style = getFixedPlatformStyle(this.props.style);
return React.createElement('span', {
...this.props,
style: _style
});
}
}

View File

@@ -71,3 +71,17 @@ export const isInBreakoutRoom = (stateful: Function | Object) => {
return conference?.getBreakoutRooms()
?.isBreakoutRoom();
};
/**
* Returns the breakout rooms config.
*
* @param {Function|Object} stateful - The redux store, the redux
* {@code getState} function, or the redux state itself.
* @returns {Object}
*/
export const getBreakoutRoomsConfig = (stateful: Function | Object) => {
const state = toState(stateful);
const { breakoutRooms = {} } = state['features/base/config'];
return breakoutRooms;
};

View File

@@ -40,6 +40,11 @@ type Props = {
*/
_room: string,
/**
* The page current url.
*/
_url: URL,
/**
* Used to dispatch actions from the buttons.
*/
@@ -90,7 +95,7 @@ class DeepLinkingMobilePage extends Component<Props> {
* @returns {ReactElement}
*/
render() {
const { _downloadUrl, _room, t } = this.props;
const { _downloadUrl, _room, t, _url } = this.props;
const { HIDE_DEEP_LINKING_LOGO, NATIVE_APP_NAME, SHOW_DEEP_LINKING_IMAGE } = interfaceConfig;
const downloadButtonClassName
= `${_SNS}__button ${_SNS}__button_primary`;
@@ -181,7 +186,8 @@ class DeepLinkingMobilePage extends Component<Props> {
<DialInSummary
className = 'deep-linking-dial-in'
clickableNumbers = { true }
room = { _room } />
room = { _room }
url = { _url } />
</div>
</div>
);
@@ -274,9 +280,12 @@ class DeepLinkingMobilePage extends Component<Props> {
* @returns {Props}
*/
function _mapStateToProps(state) {
const { locationURL = {} } = state['features/base/connection'];
return {
_downloadUrl: interfaceConfig[`MOBILE_DOWNLOAD_LINK_${Platform.OS.toUpperCase()}`],
_room: decodeURIComponent(state['features/base/conference'].room)
_room: decodeURIComponent(state['features/base/conference'].room),
_url: locationURL
};
}

View File

@@ -26,7 +26,6 @@ import {
calculateThumbnailSizeForHorizontalView,
calculateThumbnailSizeForTileView,
calculateThumbnailSizeForVerticalView,
calculateThumbnailSizeForResizableVerticalView,
isFilmstripResizable,
showGridInVerticalView
} from './functions';
@@ -128,9 +127,7 @@ export function setVerticalViewDimensions() {
width: widthOfFilmstrip
};
} else {
thumbnails = resizableFilmstrip
? calculateThumbnailSizeForResizableVerticalView(clientWidth, filmstripWidth.current)
: calculateThumbnailSizeForVerticalView(clientWidth);
thumbnails = calculateThumbnailSizeForVerticalView(clientWidth, filmstripWidth.current, resizableFilmstrip);
}
dispatch({

View File

@@ -42,7 +42,7 @@ type Props = {
/**
* Whether or not the toolbox is displayed.
*/
_isToolboxVisible: Boolean,
_toolboxVisible: Boolean,
_localParticipantId: string,
@@ -97,7 +97,7 @@ class Filmstrip extends PureComponent<Props> {
// layer #0 sits behind the window, creates a hole in the window, and
// there we render the LargeVideo; layer #1 is known as media overlay in
// EGL terms, renders on top of layer #0, and, consequently, is for the
// Filmstrip. With the separate LocalThumnail, we should have left the
// Filmstrip. With the separate LocalThumbnail, we should have left the
// remote participants' Thumbnails in layer #1 and utilized layer #2 for
// LocalThumbnail. Unfortunately, layer #2 is not practical (that's why
// I said we had two practical layers only) because it renders on top of
@@ -233,7 +233,7 @@ class Filmstrip extends PureComponent<Props> {
const {
_aspectRatio,
_disableSelfView,
_isToolboxVisible,
_toolboxVisible,
_localParticipantId,
_participants,
_visible
@@ -243,6 +243,7 @@ class Filmstrip extends PureComponent<Props> {
return null;
}
const bottomEdge = Platform.OS === 'ios' && !_toolboxVisible;
const isNarrowAspectRatio = _aspectRatio === ASPECT_RATIO_NARROW;
const filmstripStyle = isNarrowAspectRatio ? styles.filmstripNarrow : styles.filmstripWide;
const { height, width } = this._getDimensions();
@@ -263,12 +264,7 @@ class Filmstrip extends PureComponent<Props> {
return (
<SafeAreaView
edges = { [
!_isToolboxVisible && 'bottom',
'top',
'left',
'right'
].filter(Boolean) }
edges = { [ bottomEdge && 'bottom', 'left', 'right' ].filter(Boolean) }
style = { filmstripStyle }>
{
this._separateLocalThumbnail
@@ -320,9 +316,9 @@ function _mapStateToProps(state) {
_clientHeight: responsiveUI.clientHeight,
_clientWidth: responsiveUI.clientWidth,
_disableSelfView: disableSelfView,
_isToolboxVisible: isToolboxVisible(state),
_localParticipantId: getLocalParticipant(state)?.id,
_participants: showRemoteVideos ? remoteParticipants : NO_REMOTE_VIDEOS,
_toolboxVisible: isToolboxVisible(state),
_visible: enabled && isFilmstripVisible(state)
};
}

View File

@@ -45,7 +45,7 @@ export default {
flexDirection: 'row',
flexGrow: 0,
justifyContent: 'flex-end',
marginBottom: BaseTheme.spacing[1]
margin: 6
},
/**

View File

@@ -562,6 +562,7 @@ class Filmstrip extends PureComponent <Props, State> {
_filmstripHeight,
_filmstripWidth,
_remoteParticipantsLength,
_resizableFilmstrip,
_rows,
_thumbnailHeight,
_thumbnailWidth,
@@ -599,7 +600,7 @@ class Filmstrip extends PureComponent <Props, State> {
const props = {
itemCount: _remoteParticipantsLength,
className: 'filmstrip__videos remote-videos height-transition',
className: `filmstrip__videos remote-videos ${_resizableFilmstrip ? '' : 'height-transition'}`,
height: _filmstripHeight,
itemKey: this._listItemKey,
itemSize: 0,

View File

@@ -2,6 +2,7 @@
import React, { Component } from 'react';
import { shouldComponentUpdate } from 'react-window';
import { getPinnedParticipant } from '../../../base/participants';
import { connect } from '../../../base/redux';
import { shouldHideSelfView } from '../../../base/settings/functions.any';
import { getCurrentLayout, LAYOUTS } from '../../../video-layout';
@@ -90,6 +91,7 @@ class ThumbnailWrapper extends Component<Props> {
if (_participantID === 'local') {
return _disableSelfView ? null : (
<Thumbnail
_isAnyParticipantPinned = { _isAnyParticipantPinned }
horizontalOffset = { _horizontalOffset }
key = 'local'
style = { style } />);
@@ -116,12 +118,12 @@ class ThumbnailWrapper extends Component<Props> {
function _mapStateToProps(state, ownProps) {
const _currentLayout = getCurrentLayout(state);
const { remoteParticipants } = state['features/filmstrip'];
const { remote, local } = state['features/base/participants'];
const remoteParticipantsLength = remoteParticipants.length;
const { testing = {} } = state['features/base/config'];
const disableSelfView = shouldHideSelfView(state);
const enableThumbnailReordering = testing.enableThumbnailReordering ?? true;
const _verticalViewGrid = showGridInVerticalView(state);
const _isAnyParticipantPinned = Boolean(getPinnedParticipant(state));
if (_currentLayout === LAYOUTS.TILE_VIEW || _verticalViewGrid) {
const { columnIndex, rowIndex } = ownProps;
@@ -156,13 +158,15 @@ function _mapStateToProps(state, ownProps) {
return {
_disableSelfView: disableSelfView,
_participantID: 'local',
_horizontalOffset: horizontalOffset
_horizontalOffset: horizontalOffset,
_isAnyParticipantPinned: _verticalViewGrid && _isAnyParticipantPinned
};
}
return {
_participantID: remoteParticipants[remoteIndex],
_horizontalOffset: horizontalOffset
_horizontalOffset: horizontalOffset,
_isAnyParticipantPinned: _verticalViewGrid && _isAnyParticipantPinned
};
}
@@ -172,8 +176,6 @@ function _mapStateToProps(state, ownProps) {
return {};
}
const _isAnyParticipantPinned = Boolean([ ...remote ].find(([ , value ]) => value?.pinned) || local?.pinned);
return {
_participantID: remoteParticipants[index],
_isAnyParticipantPinned

View File

@@ -256,6 +256,11 @@ export const INDICATORS_TOOLTIP_POSITION = {
*/
export const DEFAULT_FILMSTRIP_WIDTH = 120;
/**
* The default aspect ratio for the local tile.
*/
export const DEFAULT_LOCAL_TILE_ASPECT_RATIO = 16 / 9;
/**
* The width of the filmstrip at which it no longer goes above the stage view, but it pushes it.
*/

View File

@@ -22,6 +22,7 @@ import { getCurrentLayout, LAYOUTS } from '../video-layout';
import {
ASPECT_RATIO_BREAKPOINT,
DEFAULT_FILMSTRIP_WIDTH,
DEFAULT_LOCAL_TILE_ASPECT_RATIO,
DISPLAY_AVATAR,
DISPLAY_VIDEO,
FILMSTRIP_GRID_BREAKPOINT,
@@ -161,45 +162,26 @@ export function calculateThumbnailSizeForHorizontalView(clientHeight: number = 0
* Calculates the size for thumbnails when in vertical view layout.
*
* @param {number} clientWidth - The height of the app window.
* @returns {{local: {height, width}, remote: {height, width}}}
*/
export function calculateThumbnailSizeForVerticalView(clientWidth: number = 0) {
const availableWidth = Math.min(
Math.max(clientWidth - VERTICAL_VIEW_HORIZONTAL_MARGIN, 0),
interfaceConfig.FILM_STRIP_MAX_HEIGHT || DEFAULT_FILMSTRIP_WIDTH);
return {
local: {
height: Math.floor(availableWidth / interfaceConfig.LOCAL_THUMBNAIL_RATIO),
width: availableWidth
},
remote: {
height: Math.floor(availableWidth / interfaceConfig.REMOTE_THUMBNAIL_RATIO),
width: availableWidth
}
};
}
/**
* Calculates the size for thumbnails when in vertical view layout
* and the filmstrip is resizable.
*
* @param {number} clientWidth - The height of the app window.
* @param {number} filmstripWidth - The width of the filmstrip.
* @param {boolean} isResizable - Whether the filmstrip is resizable or not.
* @returns {{local: {height, width}, remote: {height, width}}}
*/
export function calculateThumbnailSizeForResizableVerticalView(clientWidth: number = 0, filmstripWidth: number = 0) {
export function calculateThumbnailSizeForVerticalView(clientWidth: number = 0,
filmstripWidth: number = 0, isResizable = false) {
const availableWidth = Math.min(
Math.max(clientWidth - VERTICAL_VIEW_HORIZONTAL_MARGIN, 0),
filmstripWidth || DEFAULT_FILMSTRIP_WIDTH);
(isResizable ? filmstripWidth : interfaceConfig.FILM_STRIP_MAX_HEIGHT) || DEFAULT_FILMSTRIP_WIDTH);
return {
local: {
height: DEFAULT_FILMSTRIP_WIDTH,
height: Math.floor(availableWidth
/ (interfaceConfig.LOCAL_THUMBNAIL_RATIO || DEFAULT_LOCAL_TILE_ASPECT_RATIO)),
width: availableWidth
},
remote: {
height: DEFAULT_FILMSTRIP_WIDTH,
height: isResizable
? DEFAULT_FILMSTRIP_WIDTH
: Math.floor(availableWidth / interfaceConfig.REMOTE_THUMBNAIL_RATIO),
width: availableWidth
}
};

View File

@@ -184,3 +184,12 @@ StateListenerRegistry.register(
/* listener */(_, store) => {
store.dispatch(setVerticalViewDimensions());
});
/**
* Listens for changes in the filmstrip config to determine the size of the tiles.
*/
StateListenerRegistry.register(
/* selector */ state => state['features/base/config'].filmstrip?.disableResizable,
/* listener */(_, store) => {
store.dispatch(setVerticalViewDimensions());
});

View File

@@ -5,6 +5,9 @@
* and requires as less dependencies as possible.
*/
import { getURLWithoutParams } from '../base/connection/utils';
import { doGetJSON } from '../base/util';
/**
* Formats the conference pin in readable way for UI to display it.
* Formats the pin in 3 groups of digits:
@@ -26,3 +29,57 @@ export function _formatConferenceIDPin(conferenceID: Object) {
conferenceIDStr.substring(partLen, 2 * partLen)} ${
conferenceIDStr.substring(2 * partLen, conferenceIDStr.length)}`;
}
/**
* Sends a GET request to obtain the conference ID necessary for identifying
* which conference to join after dialing the dial-in service.
* This function is used not only in the main app bundle but in separate bundles for the dial in numbers page,
* and we do want to limit the dependencies.
*
* @param {string} baseUrl - The url for obtaining the conference ID (pin) for
* dialing into a conference.
* @param {string} roomName - The conference name to find the associated
* conference ID.
* @param {string} mucURL - In which MUC the conference exists.
* @param {URL} url - The address we are loaded in.
* @returns {Promise} - The promise created by the request.
*/
export function getDialInConferenceID(
baseUrl: string,
roomName: string,
mucURL: string,
url: URL
): Promise<Object> {
const separator = baseUrl.includes('?') ? '&' : '?';
const conferenceIDURL
= `${baseUrl}${separator}conference=${roomName}@${mucURL}&url=${getURLWithoutParams(url).href}`;
return doGetJSON(conferenceIDURL, true);
}
/**
* Sends a GET request for phone numbers used to dial into a conference.
* This function is used not only in the main app bundle but in separate bundles for the dial in numbers page,
* and we do want to limit the dependencies.
*
* @param {string} url - The service that returns conference dial-in numbers.
* @param {string} roomName - The conference name to find the associated
* conference ID.
* @param {string} mucURL - In which MUC the conference exists.
* @returns {Promise} - The promise created by the request. The returned numbers
* may be an array of Objects containing numbers, with keys countryCode,
* tollFree, formattedNumber or an object with countries as keys and arrays of
* phone number strings, as the second one should not be used and is deprecated.
*/
export function getDialInNumbers(
url: string,
roomName: string,
mucURL: string
): Promise<*> {
const separator = url.includes('?') ? '&' : '?';
// when roomName and mucURL are available
// provide conference when looking up dial in numbers
return doGetJSON(url + (roomName && mucURL ? `${separator}conference=${roomName}@${mucURL}` : ''), true);
}

View File

@@ -6,6 +6,7 @@ import { getInviteURL } from '../base/connection';
import { getLocalParticipant, getParticipantCount } from '../base/participants';
import { inviteVideoRooms } from '../videosipgw';
import { getDialInConferenceID, getDialInNumbers } from './_utils';
import {
ADD_PENDING_INVITE_REQUEST,
BEGIN_ADD_PEOPLE,
@@ -17,8 +18,6 @@ import {
} from './actionTypes';
import { INVITE_TYPES } from './constants';
import {
getDialInConferenceID,
getDialInNumbers,
invitePeopleAndChatRooms,
inviteSipEndpoints
} from './functions';
@@ -209,11 +208,12 @@ export function updateDialInNumbers() {
return;
}
const { locationURL = {} } = state['features/base/connection'];
const { room } = state['features/base/conference'];
Promise.all([
getDialInNumbers(dialInNumbersUrl, room, mucURL),
getDialInConferenceID(dialInConfCodeUrl, room, mucURL)
getDialInConferenceID(dialInConfCodeUrl, room, mucURL, locationURL)
])
.then(([ dialInNumbers, { conference, id, message, sipUri } ]) => {
if (!conference || !id) {

View File

@@ -5,12 +5,16 @@ import { I18nextProvider } from 'react-i18next';
import { isMobileBrowser } from '../../../base/environment/utils';
import { i18next } from '../../../base/i18n';
import { parseURLParams } from '../../../base/util/parseURLParams';
import { DIAL_IN_INFO_PAGE_PATH_NAME } from '../../constants';
import { DialInSummary } from '../dial-in-summary';
import NoRoomError from './NoRoomError';
document.addEventListener('DOMContentLoaded', () => {
const { room } = parseURLParams(window.location, true, 'search');
const { href } = window.location;
const ix = href.indexOf(DIAL_IN_INFO_PAGE_PATH_NAME);
const url = (ix > 0 ? href.substring(0, ix) : href) + room;
ReactDOM.render(
<I18nextProvider i18n = { i18next }>
@@ -18,7 +22,8 @@ document.addEventListener('DOMContentLoaded', () => {
? <DialInSummary
className = 'dial-in-page'
clickableNumbers = { isMobileBrowser() }
room = { decodeURIComponent(room) } />
room = { decodeURIComponent(room) }
url = { url } />
: <NoRoomError className = 'dial-in-page' /> }
</I18nextProvider>,
document.getElementById('react')

View File

@@ -3,7 +3,7 @@
import React, { Component } from 'react';
import { translate } from '../../../../base/i18n';
import { doGetJSON } from '../../../../base/util';
import { getDialInConferenceID, getDialInNumbers } from '../../../_utils';
import ConferenceID from './ConferenceID';
import NumbersList from './NumbersList';
@@ -30,6 +30,11 @@ type Props = {
*/
room: string,
/**
* The url where we were loaded.
*/
url: URL | string,
/**
* Invoked to obtain translated strings.
*/
@@ -177,7 +182,14 @@ class DialInSummary extends Component<Props, State> {
return Promise.resolve();
}
return doGetJSON(`${dialInConfCodeUrl}?conference=${room}@${mucURL}`, true)
let url = this.props.url || {};
if (typeof url === 'string' || url instanceof String) {
url = new URL(url);
}
return getDialInConferenceID(dialInConfCodeUrl, room, mucURL, url)
.catch(() => Promise.reject(this.props.t('info.genericError')));
}
@@ -191,20 +203,12 @@ class DialInSummary extends Component<Props, State> {
const { room } = this.props;
const { dialInNumbersUrl, hosts } = config;
const mucURL = hosts && hosts.muc;
let URLSuffix = '';
if (!dialInNumbersUrl) {
return Promise.reject(this.props.t('info.dialInNotSupported'));
}
// when room and mucURL are available
// provide conference when looking up dial in numbers
if (room && mucURL) {
URLSuffix = `?conference=${room}@${mucURL}`;
}
return doGetJSON(`${dialInNumbersUrl}${URLSuffix}`, true)
return getDialInNumbers(dialInNumbersUrl, room, mucURL)
.catch(() => Promise.reject(this.props.t('info.genericError')));
}

View File

@@ -1,5 +1,12 @@
// @flow
/**
* The pathName for the dialInInfo page.
*
* @type {string}
*/
export const DIAL_IN_INFO_PAGE_PATH_NAME = 'static/dialInInfo.html';
/**
* Modal ID for the DialInSummary modal.
*/

View File

@@ -8,10 +8,15 @@ import { i18next } from '../base/i18n';
import { JitsiRecordingConstants } from '../base/lib-jitsi-meet';
import { getLocalParticipant, isLocalParticipantModerator } from '../base/participants';
import { toState } from '../base/redux';
import { doGetJSON, parseURIString } from '../base/util';
import { parseURIString } from '../base/util';
import { isVpaasMeeting } from '../jaas/functions';
import { INVITE_TYPES, SIP_ADDRESS_REGEX } from './constants';
import { getDialInConferenceID, getDialInNumbers } from './_utils';
import {
DIAL_IN_INFO_PAGE_PATH_NAME,
INVITE_TYPES,
SIP_ADDRESS_REGEX
} from './constants';
import logger from './logger';
declare var $: Function;
@@ -37,51 +42,6 @@ export function checkDialNumber(
});
}
/**
* Sends a GET request to obtain the conference ID necessary for identifying
* which conference to join after diaing the dial-in service.
*
* @param {string} baseUrl - The url for obtaining the conference ID (pin) for
* dialing into a conference.
* @param {string} roomName - The conference name to find the associated
* conference ID.
* @param {string} mucURL - In which MUC the conference exists.
* @returns {Promise} - The promise created by the request.
*/
export function getDialInConferenceID(
baseUrl: string,
roomName: string,
mucURL: string
): Promise<Object> {
const conferenceIDURL = `${baseUrl}?conference=${roomName}@${mucURL}`;
return doGetJSON(conferenceIDURL, true);
}
/**
* Sends a GET request for phone numbers used to dial into a conference.
*
* @param {string} url - The service that returns conference dial-in numbers.
* @param {string} roomName - The conference name to find the associated
* conference ID.
* @param {string} mucURL - In which MUC the conference exists.
* @returns {Promise} - The promise created by the request. The returned numbers
* may be an array of Objects containing numbers, with keys countryCode,
* tollFree, formattedNumber or an object with countries as keys and arrays of
* phone number strings, as the second one should not be used and is deprecated.
*/
export function getDialInNumbers(
url: string,
roomName: string,
mucURL: string
): Promise<*> {
const fullUrl = `${url}?conference=${roomName}@${mucURL}`;
return doGetJSON(fullUrl, true);
}
/**
* Removes all non-numeric characters from a string.
*
@@ -564,6 +524,7 @@ export function getShareInfoText(
// in the state
const { dialInConfCodeUrl, dialInNumbersUrl, hosts }
= state['features/base/config'];
const { locationURL = {} } = state['features/base/connection'];
const mucURL = hosts && hosts.muc;
if (!dialInConfCodeUrl || !dialInNumbersUrl || !mucURL) {
@@ -573,7 +534,7 @@ export function getShareInfoText(
numbersPromise = Promise.all([
getDialInNumbers(dialInNumbersUrl, room, mucURL),
getDialInConferenceID(dialInConfCodeUrl, room, mucURL)
getDialInConferenceID(dialInConfCodeUrl, room, mucURL, locationURL)
]).then(([ numbers, {
conference, id, message } ]) => {
@@ -633,7 +594,7 @@ export function getDialInfoPageURL(state: Object, roomName: ?string) {
const { href } = locationURL;
const room = _decodeRoomURI(conferenceName);
const url = didPageUrl || `${href.substring(0, href.lastIndexOf('/'))}/static/dialInInfo.html`;
const url = didPageUrl || `${href.substring(0, href.lastIndexOf('/'))}/${DIAL_IN_INFO_PAGE_PATH_NAME}`;
return `${url}?room=${room}`;
}
@@ -651,7 +612,7 @@ export function getDialInfoPageURLForURIString(
}
const { protocol, host, contextRoot, room } = parseURIString(uri);
return `${protocol}//${host}${contextRoot}static/dialInInfo.html?room=${room}`;
return `${protocol}//${host}${contextRoot}${DIAL_IN_INFO_PAGE_PATH_NAME}?room=${room}`;
}
/**

View File

@@ -9,6 +9,7 @@ import {
setPassword
} from '../base/conference';
import { getLocalParticipant } from '../base/participants';
import { hideNotification, LOBBY_NOTIFICATION_ID } from '../notifications';
import {
KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED,
@@ -65,6 +66,20 @@ export function participantIsKnockingOrUpdated(participant: Object) {
};
}
/**
* Handles a knocking participant and dismisses the notification.
*
* @param {string} id - The id of the knocking participant.
* @param {boolean} approved - True if the participant is approved, false otherwise.
* @returns {Function}
*/
export function answerKnockingParticipant(id: string, approved: boolean) {
return async (dispatch: Dispatch<any>) => {
dispatch(setKnockingParticipantApproval(id, approved));
dispatch(hideNotification(LOBBY_NOTIFICATION_ID));
};
}
/**
* Approves (lets in) or rejects a knocking participant.
*

View File

@@ -27,7 +27,7 @@ import { open as openParticipantsPane } from '../participants-pane/actions';
import { getParticipantsPaneOpen } from '../participants-pane/functions';
import { shouldAutoKnock } from '../prejoin/functions';
import { KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED } from './actionTypes';
import { KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED, KNOCKING_PARTICIPANT_LEFT } from './actionTypes';
import {
hideLobbyScreen,
knockingParticipantLeft,
@@ -60,6 +60,15 @@ MiddlewareRegistry.register(store => next => action => {
const result = next(action);
_findLoadableAvatarForKnockingParticipant(store, action.participant);
_handleLobbyNotification(store);
return result;
}
case KNOCKING_PARTICIPANT_LEFT: {
// We need the full update result to be in the store already
const result = next(action);
_handleLobbyNotification(store);
return result;
}
@@ -95,48 +104,11 @@ StateListenerRegistry.register(
if (navigator.product === 'ReactNative' || isParticipantsPaneVisible) {
return;
}
let notificationTitle;
let customActionNameKey;
let customActionHandler;
let descriptionKey;
let icon;
const knockingParticipants = getKnockingParticipants(getState());
const firstParticipant = knockingParticipants[0];
if (knockingParticipants.length > 1) {
descriptionKey = 'notify.participantsWantToJoin';
notificationTitle = i18n.t('notify.waitingParticipants', {
waitingParticipants: knockingParticipants.length
});
icon = NOTIFICATION_ICON.PARTICIPANTS;
customActionNameKey = [ 'notify.viewLobby' ];
customActionHandler = [ () => batch(() => {
dispatch(hideNotification(LOBBY_NOTIFICATION_ID));
dispatch(openParticipantsPane());
}) ];
} else {
descriptionKey = 'notify.participantWantsToJoin';
notificationTitle = firstParticipant.name;
icon = NOTIFICATION_ICON.PARTICIPANT;
customActionNameKey = [ 'lobby.admit', 'lobby.reject' ];
customActionHandler = [ () => batch(() => {
dispatch(hideNotification(LOBBY_NOTIFICATION_ID));
dispatch(approveKnockingParticipant(firstParticipant.id));
}),
() => batch(() => {
dispatch(hideNotification(LOBBY_NOTIFICATION_ID));
dispatch(rejectKnockingParticipant(firstParticipant.id));
}) ];
}
dispatch(showNotification({
title: notificationTitle,
descriptionKey,
uid: LOBBY_NOTIFICATION_ID,
customActionNameKey,
customActionHandler,
icon
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
_handleLobbyNotification({
dispatch,
getState
});
if (typeof APP !== 'undefined') {
APP.API.notifyKnockingParticipant({
@@ -170,6 +142,65 @@ StateListenerRegistry.register(
}
);
/**
* Function to handle the lobby notification.
*
* @param {Object} store - The Redux store.
* @returns {void}
*/
function _handleLobbyNotification(store) {
const { dispatch, getState } = store;
const knockingParticipants = getKnockingParticipants(getState());
if (knockingParticipants.length === 0) {
dispatch(hideNotification(LOBBY_NOTIFICATION_ID));
return;
}
let notificationTitle;
let customActionNameKey;
let customActionHandler;
let descriptionKey;
let icon;
if (knockingParticipants.length === 1) {
const firstParticipant = knockingParticipants[0];
descriptionKey = 'notify.participantWantsToJoin';
notificationTitle = firstParticipant.name;
icon = NOTIFICATION_ICON.PARTICIPANT;
customActionNameKey = [ 'lobby.admit', 'lobby.reject' ];
customActionHandler = [ () => batch(() => {
dispatch(hideNotification(LOBBY_NOTIFICATION_ID));
dispatch(approveKnockingParticipant(firstParticipant.id));
}),
() => batch(() => {
dispatch(hideNotification(LOBBY_NOTIFICATION_ID));
dispatch(rejectKnockingParticipant(firstParticipant.id));
}) ];
} else {
descriptionKey = 'notify.participantsWantToJoin';
notificationTitle = i18n.t('notify.waitingParticipants', {
waitingParticipants: knockingParticipants.length
});
icon = NOTIFICATION_ICON.PARTICIPANTS;
customActionNameKey = [ 'notify.viewLobby' ];
customActionHandler = [ () => batch(() => {
dispatch(hideNotification(LOBBY_NOTIFICATION_ID));
dispatch(openParticipantsPane());
}) ];
}
dispatch(showNotification({
title: notificationTitle,
descriptionKey,
uid: LOBBY_NOTIFICATION_ID,
customActionNameKey,
customActionHandler,
icon
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
}
/**
* Function to handle the conference failed event and navigate the user to the lobby screen
* based on the failure reason.

View File

@@ -4,7 +4,6 @@ import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { useSelector } from 'react-redux';
import { Chat } from '../../../../../chat';
@@ -63,81 +62,79 @@ const ConferenceNavigationContainer = () => {
const { t } = useTranslation();
return (
<SafeAreaProvider>
<NavigationContainer
independent = { true }
ref = { conferenceNavigationRef }
theme = { navigationContainerTheme }>
<ConferenceStack.Navigator
initialRouteName = { screen.conference.main }
screenOptions = {{
presentation: 'modal'
}}>
<ConferenceStack.Screen
component = { Conference }
name = { screen.conference.main }
options = { conferenceScreenOptions } />
<ConferenceStack.Screen
component = { ChatScreen }
name = { chatScreenName }
options = {{
...chatScreenOptions,
title: t(chatTitleString)
}} />
<ConferenceStack.Screen
component = { ParticipantsPane }
name = { screen.conference.participants }
options = {{
...participantsScreenOptions,
title: t('participantsPane.header')
}} />
<ConferenceStack.Screen
component = { SecurityDialog }
name = { screen.conference.security }
options = {{
...securityScreenOptions,
title: t('security.header')
}} />
<ConferenceStack.Screen
component = { StartRecordingDialog }
name = { screen.conference.recording }
options = {{
...recordingScreenOptions
}} />
<ConferenceStack.Screen
component = { StartLiveStreamDialog }
name = { screen.conference.liveStream }
options = {{
...liveStreamScreenOptions
}} />
<ConferenceStack.Screen
component = { SpeakerStats }
name = { screen.conference.speakerStats }
options = {{
...speakerStatsScreenOptions,
title: t('speakerStats.speakerStats')
}} />
<ConferenceStack.Screen
component = { LobbyScreen }
name = { screen.lobby }
options = { lobbyScreenOptions } />
<ConferenceStack.Screen
component = { AddPeopleDialog }
name = { screen.conference.invite }
options = {{
...inviteScreenOptions,
title: t('addPeople.add')
}} />
<ConferenceStack.Screen
component = { SharedDocument }
name = { screen.conference.sharedDocument }
options = {{
...sharedDocumentScreenOptions,
title: t('documentSharing.title')
}} />
</ConferenceStack.Navigator>
</NavigationContainer>
</SafeAreaProvider>
<NavigationContainer
independent = { true }
ref = { conferenceNavigationRef }
theme = { navigationContainerTheme }>
<ConferenceStack.Navigator
initialRouteName = { screen.conference.main }
screenOptions = {{
presentation: 'modal'
}}>
<ConferenceStack.Screen
component = { Conference }
name = { screen.conference.main }
options = { conferenceScreenOptions } />
<ConferenceStack.Screen
component = { ChatScreen }
name = { chatScreenName }
options = {{
...chatScreenOptions,
title: t(chatTitleString)
}} />
<ConferenceStack.Screen
component = { ParticipantsPane }
name = { screen.conference.participants }
options = {{
...participantsScreenOptions,
title: t('participantsPane.header')
}} />
<ConferenceStack.Screen
component = { SecurityDialog }
name = { screen.conference.security }
options = {{
...securityScreenOptions,
title: t('security.header')
}} />
<ConferenceStack.Screen
component = { StartRecordingDialog }
name = { screen.conference.recording }
options = {{
...recordingScreenOptions
}} />
<ConferenceStack.Screen
component = { StartLiveStreamDialog }
name = { screen.conference.liveStream }
options = {{
...liveStreamScreenOptions
}} />
<ConferenceStack.Screen
component = { SpeakerStats }
name = { screen.conference.speakerStats }
options = {{
...speakerStatsScreenOptions,
title: t('speakerStats.speakerStats')
}} />
<ConferenceStack.Screen
component = { LobbyScreen }
name = { screen.lobby }
options = { lobbyScreenOptions } />
<ConferenceStack.Screen
component = { AddPeopleDialog }
name = { screen.conference.invite }
options = {{
...inviteScreenOptions,
title: t('addPeople.add')
}} />
<ConferenceStack.Screen
component = { SharedDocument }
name = { screen.conference.sharedDocument }
options = {{
...sharedDocumentScreenOptions,
title: t('documentSharing.title')
}} />
</ConferenceStack.Navigator>
</NavigationContainer>
);
};

View File

@@ -16,6 +16,7 @@ import {
} from '../../../../../base/icons';
import { isLocalParticipantModerator } from '../../../../../base/participants';
import { closeBreakoutRoom, moveToRoom, removeBreakoutRoom } from '../../../../../breakout-rooms/actions';
import { getBreakoutRoomsConfig } from '../../../../../breakout-rooms/functions';
import styles from '../../../native/styles';
type Props = {
@@ -30,6 +31,7 @@ const BreakoutRoomContextMenu = ({ room }: Props) => {
const dispatch = useDispatch();
const closeDialog = useCallback(() => dispatch(hideDialog()), [ dispatch ]);
const isLocalModerator = useSelector(isLocalParticipantModerator);
const { hideJoinRoomButton } = useSelector(getBreakoutRoomsConfig);
const { t } = useTranslation();
const onJoinRoom = useCallback(() => {
@@ -53,14 +55,18 @@ const BreakoutRoomContextMenu = ({ room }: Props) => {
addScrollViewPadding = { false }
onCancel = { closeDialog }
showSlidingView = { true }>
<TouchableOpacity
onPress = { onJoinRoom }
style = { styles.contextMenuItem }>
<Icon
size = { 24 }
src = { IconRingGroup } />
<Text style = { styles.contextMenuItemText }>{t('breakoutRooms.actions.join')}</Text>
</TouchableOpacity>
{
!hideJoinRoomButton && (
<TouchableOpacity
onPress = { onJoinRoom }
style = { styles.contextMenuItem }>
<Icon
size = { 24 }
src = { IconRingGroup } />
<Text style = { styles.contextMenuItemText }>{t('breakoutRooms.actions.join')}</Text>
</TouchableOpacity>
)
}
{!room?.isMainRoom && isLocalModerator
&& (room?.participants && Object.keys(room.participants).length > 0
? <TouchableOpacity

View File

@@ -6,7 +6,12 @@ import { useSelector } from 'react-redux';
import useContextMenu from '../../../../../base/components/context-menu/useContextMenu';
import { getParticipantCount, isLocalParticipantModerator } from '../../../../../base/participants';
import { equals } from '../../../../../base/redux';
import { getBreakoutRooms, isInBreakoutRoom, getCurrentRoomId } from '../../../../../breakout-rooms/functions';
import {
getBreakoutRooms,
isInBreakoutRoom,
getCurrentRoomId,
getBreakoutRoomsConfig
} from '../../../../../breakout-rooms/functions';
import { showOverflowDrawer } from '../../../../../toolbox/functions';
import { AutoAssignButton } from './AutoAssignButton';
@@ -32,6 +37,7 @@ export const RoomList = ({ searchString }: Props) => {
const inBreakoutRoom = useSelector(isInBreakoutRoom);
const isLocalModerator = useSelector(isLocalParticipantModerator);
const participantsCount = useSelector(getParticipantCount);
const { hideJoinRoomButton } = useSelector(getBreakoutRoomsConfig);
const _overflowDrawer = useSelector(showOverflowDrawer);
const [ lowerMenu, raiseMenu, toggleMenu, menuEnter, menuLeave, raiseContext ] = useContextMenu();
@@ -55,7 +61,7 @@ export const RoomList = ({ searchString }: Props) => {
room = { room }
searchString = { searchString }>
{!_overflowDrawer && <>
<JoinActionButton room = { room } />
{!hideJoinRoomButton && <JoinActionButton room = { room } />}
{isLocalModerator && !room.isMainRoom
&& <RoomActionEllipsis onClick = { toggleMenu(room) } />}
</>}

View File

@@ -13,7 +13,12 @@ import {
isLocalParticipantModerator
} from '../../../base/participants';
import { equals } from '../../../base/redux';
import { getBreakoutRooms, getCurrentRoomId, isInBreakoutRoom } from '../../../breakout-rooms/functions';
import {
getBreakoutRooms,
getBreakoutRoomsConfig,
getCurrentRoomId,
isInBreakoutRoom
} from '../../../breakout-rooms/functions';
import MuteEveryoneDialog
from '../../../video-menu/components/native/MuteEveryoneDialog';
import {
@@ -43,7 +48,7 @@ const ParticipantsPane = () => {
[ dispatch ]);
const { t } = useTranslation();
const { hideAddRoomButton } = useSelector(state => state['features/base/config']);
const { hideAddRoomButton } = useSelector(getBreakoutRoomsConfig);
const { conference } = useSelector(state => state['features/base/conference']);
// $FlowExpectedError

View File

@@ -9,6 +9,7 @@ import { translate } from '../../../base/i18n';
import { Icon, IconClose, IconHorizontalPoints } from '../../../base/icons';
import { isLocalParticipantModerator } from '../../../base/participants';
import { connect } from '../../../base/redux';
import { getBreakoutRoomsConfig } from '../../../breakout-rooms/functions';
import { MuteEveryoneDialog } from '../../../video-menu/components/';
import { close } from '../../actions';
import { classList, findAncestorByClass, getParticipantsPaneOpen } from '../../functions';
@@ -373,7 +374,7 @@ class ParticipantsPane extends Component<Props, State> {
*/
function _mapStateToProps(state: Object) {
const isPaneOpen = getParticipantsPaneOpen(state);
const { hideAddRoomButton } = state['features/base/config'];
const { hideAddRoomButton } = getBreakoutRoomsConfig(state);
const { conference } = state['features/base/conference'];
// $FlowExpectedError

View File

@@ -1,9 +1,11 @@
// @flow
import React from 'react';
import { SafeAreaView, View } from 'react-native';
import { View } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { ColorSchemeRegistry } from '../../../base/color-scheme';
import { Platform } from '../../../base/react';
import { connect } from '../../../base/redux';
import { StyleType } from '../../../base/styles';
import { ChatButton } from '../../../chat';
@@ -26,6 +28,11 @@ import styles from './styles';
*/
type Props = {
/**
* Whether or not the reactions feature is enabled.
*/
_reactionsEnabled: boolean,
/**
* The color-schemed stylesheet of the feature.
*/
@@ -39,12 +46,7 @@ type Props = {
/**
* The width of the screen.
*/
_width: number,
/**
* Whether or not the reactions feature is enabled.
*/
_reactionsEnabled: boolean
_width: number
};
/**
@@ -54,11 +56,13 @@ type Props = {
* @returns {React$Element}.
*/
function Toolbox(props: Props) {
if (!props._visible) {
const { _reactionsEnabled, _styles, _visible, _width } = props;
if (!_visible) {
return null;
}
const { _styles, _width, _reactionsEnabled } = props;
const bottomEdge = Platform.OS === 'ios' && _visible;
const { buttonStylesBorderless, hangupButtonStyles, toggledButtonStyles } = _styles;
const additionalButtons = getMovableButtons(_width);
const backgroundToggledStyle = {
@@ -75,6 +79,7 @@ function Toolbox(props: Props) {
style = { styles.toolboxContainer }>
<SafeAreaView
accessibilityRole = 'toolbar'
edges = { [ bottomEdge && 'bottom' ].filter(Boolean) }
pointerEvents = 'box-none'
style = { styles.toolbox }>
<AudioMuteButton

View File

@@ -18,7 +18,7 @@ const toolbarButton = {
height: BUTTON_SIZE,
justifyContent: 'center',
marginHorizontal: 6,
marginTop: 6,
marginVertical: 6,
width: BUTTON_SIZE
};
@@ -86,9 +86,7 @@ const styles = {
borderTopLeftRadius: 3,
borderTopRightRadius: 3,
flexDirection: 'row',
flexGrow: 0,
justifyContent: 'space-between',
margin: BaseTheme.spacing[2]
justifyContent: 'space-between'
},
/**
@@ -97,16 +95,10 @@ const styles = {
toolboxContainer: {
backgroundColor: BaseTheme.palette.uiBackground,
flexDirection: 'column',
flexGrow: 0,
height: '100%',
width: '100%',
// TODO revisit this
maxHeight: 76,
maxWidth: 580,
marginLeft: 'auto',
marginRight: 'auto'
marginRight: 'auto',
width: '100%'
}
};

View File

@@ -30,6 +30,12 @@ StateListenerRegistry.register(
_updateReceiverVideoConstraints(store);
}, 100));
StateListenerRegistry.register(
/* selector */ state => state['features/base/tracks'],
/* listener */(remoteTracks, store) => {
_updateReceiverVideoConstraints(store);
});
/**
* Handles the use case when the on-stage participant has changed.
*/