Compare commits
37 Commits
6843
...
token-veri
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a49b6140e0 | ||
|
|
c30d1e7479 | ||
|
|
cbbe58a1ec | ||
|
|
aef5328aeb | ||
|
|
f5ac1b6271 | ||
|
|
ca9f0a6788 | ||
|
|
e7c5ae5936 | ||
|
|
c43a319576 | ||
|
|
585c9aa0d2 | ||
|
|
768f10d966 | ||
|
|
704740969b | ||
|
|
d444a45f00 | ||
|
|
9fbbe05d6c | ||
|
|
3445c513ba | ||
|
|
6a4276b4c8 | ||
|
|
338b02a6b6 | ||
|
|
ef2631e95a | ||
|
|
226ef9f33d | ||
|
|
91ec5307ab | ||
|
|
fe0b7d3acc | ||
|
|
9533650594 | ||
|
|
d7bedb2e07 | ||
|
|
33e4da32e2 | ||
|
|
9a8a8ef7ad | ||
|
|
703ed731c8 | ||
|
|
83dfb67f23 | ||
|
|
51bdf67cf2 | ||
|
|
3adbda791c | ||
|
|
924bb0e7ff | ||
|
|
4c9bfe3d4d | ||
|
|
1139311809 | ||
|
|
2ad2e6ff0e | ||
|
|
46cc2e37ae | ||
|
|
0ebac2ac6d | ||
|
|
90e33ee799 | ||
|
|
be982ae996 | ||
|
|
56114fe863 |
15
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "Jitsi Meet Dev Container",
|
||||
"image": "mcr.microsoft.com/devcontainers/universal:2",
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/node:1": {
|
||||
"version": "16"
|
||||
}
|
||||
},
|
||||
"hostRequirements": {
|
||||
"cpus": 4,
|
||||
"memory": "8gb",
|
||||
"storage": "32gb"
|
||||
},
|
||||
"postCreateCommand": "bash -i -c 'nvm use && npm install && cp tsconfig.web.json tsconfig.json'"
|
||||
}
|
||||
@@ -141,7 +141,7 @@ react/features/sample/
|
||||
```
|
||||
|
||||
The middleware must be imported in `react/features/app/` specifically
|
||||
in `middlewares.any`, `middlewares.native.js` or `middlewares.web.js` where appropriate.
|
||||
in `middlewares.any.ts`, `middlewares.native.ts` or `middlewares.web.ts` where appropriate.
|
||||
Likewise for the reducer.
|
||||
|
||||
An `index.js` file must not be provided for exporting actions, action types and
|
||||
|
||||
|
Before Width: | Height: | Size: 659 B |
|
Before Width: | Height: | Size: 379 B |
|
Before Width: | Height: | Size: 960 B |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
BIN
android/sdk/src/main/res/drawable-hdpi/ic_notification.png
Normal file
|
After Width: | Height: | Size: 699 B |
BIN
android/sdk/src/main/res/drawable-mdpi/ic_notification.png
Normal file
|
After Width: | Height: | Size: 406 B |
BIN
android/sdk/src/main/res/drawable-xhdpi/ic_notification.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
android/sdk/src/main/res/drawable-xxhdpi/ic_notification.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
android/sdk/src/main/res/drawable-xxxhdpi/ic_notification.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
@@ -47,6 +47,7 @@ import {
|
||||
dataChannelClosed,
|
||||
dataChannelOpened,
|
||||
e2eRttChanged,
|
||||
generateVisitorConfig,
|
||||
getConferenceOptions,
|
||||
kickedOut,
|
||||
lockStateChanged,
|
||||
@@ -277,7 +278,8 @@ class ConferenceConnector {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
constructor(resolve, reject) {
|
||||
constructor(resolve, reject, conference) {
|
||||
this._conference = conference;
|
||||
this._resolve = resolve;
|
||||
this._reject = reject;
|
||||
this.reconnectTimeout = null;
|
||||
@@ -336,6 +338,26 @@ class ConferenceConnector {
|
||||
break;
|
||||
}
|
||||
|
||||
case JitsiConferenceErrors.REDIRECTED: {
|
||||
generateVisitorConfig(APP.store.getState(), params);
|
||||
|
||||
connection.disconnect().then(() => {
|
||||
connect(this._conference.roomName).then(con => {
|
||||
const localTracks = getLocalTracks(APP.store.getState()['features/base/tracks']);
|
||||
|
||||
const jitsiTracks = localTracks.map(t => t.jitsiTrack);
|
||||
|
||||
// visitors connect muted
|
||||
jitsiTracks.forEach(t => t.mute());
|
||||
|
||||
// TODO disable option to unmute audio or video
|
||||
this._conference.startConference(con, jitsiTracks);
|
||||
});
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case JitsiConferenceErrors.GRACEFUL_SHUTDOWN:
|
||||
APP.UI.notifyGracefulShutdown();
|
||||
break;
|
||||
@@ -459,6 +481,11 @@ export default {
|
||||
*/
|
||||
_localTracksInitialized: false,
|
||||
|
||||
/**
|
||||
* Flag used to prevent the creation of another local video track in this.muteVideo if one is already in progress.
|
||||
*/
|
||||
isCreatingLocalTrack: false,
|
||||
|
||||
isSharingScreen: false,
|
||||
|
||||
/**
|
||||
@@ -727,7 +754,7 @@ export default {
|
||||
// XXX The API will take care of disconnecting from the XMPP
|
||||
// server (and, thus, leaving the room) on unload.
|
||||
return new Promise((resolve, reject) => {
|
||||
new ConferenceConnector(resolve, reject).connect();
|
||||
new ConferenceConnector(resolve, reject, this).connect();
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1028,11 +1055,13 @@ export default {
|
||||
|
||||
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
|
||||
|
||||
if (!localVideo && !mute) {
|
||||
if (!localVideo && !mute && !this.isCreatingLocalTrack) {
|
||||
const maybeShowErrorDialog = error => {
|
||||
showUI && APP.store.dispatch(notifyCameraError(error));
|
||||
};
|
||||
|
||||
this.isCreatingLocalTrack = true;
|
||||
|
||||
// Try to create local video if there wasn't any.
|
||||
// This handles the case when user joined with no video
|
||||
// (dismissed screen sharing screen or in audio only mode), but
|
||||
@@ -1054,6 +1083,9 @@ export default {
|
||||
logger.debug(`muteVideo: calling useVideoStream for track: ${videoTrack}`);
|
||||
|
||||
return this.useVideoStream(videoTrack);
|
||||
})
|
||||
.finally(() => {
|
||||
this.isCreatingLocalTrack = false;
|
||||
});
|
||||
} else {
|
||||
// FIXME show error dialog if it fails (should be handled by react)
|
||||
@@ -1339,7 +1371,7 @@ export default {
|
||||
this._createRoom(localTracks);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
new ConferenceConnector(resolve, reject).connect();
|
||||
new ConferenceConnector(resolve, reject, this).connect();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
14
config.js
@@ -580,9 +580,19 @@ var config = {
|
||||
// Require users to always specify a display name.
|
||||
// requireDisplayName: true,
|
||||
|
||||
// DEPRECATED! Use 'welcomePage.disabled' instead.
|
||||
// Whether to use a welcome page or not. In case it's false a random room
|
||||
// will be joined when no room is specified.
|
||||
enableWelcomePage: true,
|
||||
// enableWelcomePage: true,
|
||||
|
||||
// Configs for welcome page.
|
||||
// welcomePage: {
|
||||
// // Whether to disable welcome page. In case it's disabled a random room
|
||||
// // will be joined when no room is specified.
|
||||
// disabled: false,
|
||||
// // If set,landing page will redirect to this URL.
|
||||
// customUrl: ''
|
||||
// },
|
||||
|
||||
// Disable app shortcuts that are registered upon joining a conference
|
||||
// disableShortcuts: false,
|
||||
@@ -701,7 +711,6 @@ var config = {
|
||||
// 'chat',
|
||||
// 'closedcaptions',
|
||||
// 'desktop',
|
||||
// 'dock-iframe',
|
||||
// 'download',
|
||||
// 'embedmeeting',
|
||||
// 'etherpad',
|
||||
@@ -729,7 +738,6 @@ var config = {
|
||||
// 'stats',
|
||||
// 'tileview',
|
||||
// 'toggle-camera',
|
||||
// 'undock-iframe',
|
||||
// 'videoquality',
|
||||
// 'whiteboard',
|
||||
// ],
|
||||
|
||||
@@ -121,13 +121,6 @@ ol.poll-result-list {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.poll-dragged {
|
||||
opacity: 0.5;
|
||||
* {
|
||||
cursor: grabbing !important;
|
||||
}
|
||||
}
|
||||
|
||||
.poll-question {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
|
||||
@@ -2,7 +2,8 @@ $sidePanelWidth: 300px;
|
||||
|
||||
.prejoin-third-party {
|
||||
flex-direction: column-reverse;
|
||||
|
||||
z-index: auto;
|
||||
|
||||
.content {
|
||||
height: auto;
|
||||
margin: 0 auto;
|
||||
|
||||
4
debian/jitsi-meet-web-config.postinst
vendored
@@ -176,6 +176,10 @@ case "$1" in
|
||||
fi
|
||||
|
||||
# Fixes multi-stream flags to workaround problem with mobile joining a multi-stream call with multi-stream disabled
|
||||
FIX_MSG="//Enables multi-stream, do not delete me"
|
||||
if ! grep -q "^${FIX_MSG}" $JITSI_MEET_CONFIG; then
|
||||
sed -i "s#config.flags.sourceNameSignaling#${FIX_MSG}\nconfig.flags = config.flags || {};\nconfig.flags.sourceNameSignaling#g" $JITSI_MEET_CONFIG
|
||||
fi
|
||||
if ! grep -q "^config.flags.sourceNameSignaling*" $JITSI_MEET_CONFIG; then
|
||||
echo "config.flags.sourceNameSignaling = true;" >> $JITSI_MEET_CONFIG
|
||||
fi
|
||||
|
||||
@@ -15,6 +15,17 @@ upstream jvb1 {
|
||||
server 127.0.0.1:9090;
|
||||
keepalive 2;
|
||||
}
|
||||
map $arg_vnode $prosody_node {
|
||||
default prosody;
|
||||
v1 v1;
|
||||
v2 v2;
|
||||
v3 v3;
|
||||
v4 v4;
|
||||
v5 v5;
|
||||
v6 v6;
|
||||
v7 v7;
|
||||
v8 v8;
|
||||
}
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
@@ -95,7 +106,7 @@ server {
|
||||
|
||||
# BOSH
|
||||
location = /http-bind {
|
||||
proxy_pass http://prosody/http-bind?prefix=$prefix&$args;
|
||||
proxy_pass http://$prosody_node/http-bind?prefix=$prefix&$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header Host $http_host;
|
||||
@@ -104,7 +115,7 @@ server {
|
||||
|
||||
# xmpp websockets
|
||||
location = /xmpp-websocket {
|
||||
proxy_pass http://prosody/xmpp-websocket?prefix=$prefix&$args;
|
||||
proxy_pass http://$prosody_node/xmpp-websocket?prefix=$prefix&$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
1
globals.d.ts
vendored
@@ -24,6 +24,7 @@ declare global {
|
||||
JITSI_MEET_LITE_SDK?: boolean;
|
||||
interfaceConfig?: any;
|
||||
JitsiMeetJS?: any;
|
||||
JitsiMeetElectron?: any;
|
||||
}
|
||||
|
||||
const config: IConfig;
|
||||
|
||||
@@ -385,7 +385,7 @@ PODS:
|
||||
- react-native-video/Video (6.0.0-alpha.1):
|
||||
- PromisesSwift
|
||||
- React-Core
|
||||
- react-native-webrtc (1.106.1):
|
||||
- react-native-webrtc (106.0.0):
|
||||
- JitsiWebRTC (~> 106.0.0)
|
||||
- React-Core
|
||||
- react-native-webview (11.15.1):
|
||||
@@ -755,7 +755,7 @@ SPEC CHECKSUMS:
|
||||
react-native-slider: 6e9b86e76cce4b9e35b3403193a6432ed07e0c81
|
||||
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
|
||||
react-native-video: bb6f12a7198db53b261fefb5d609dc77417acc8b
|
||||
react-native-webrtc: 4a4c31be61f88d1d3356526eebce72f462a6760e
|
||||
react-native-webrtc: 0a407105bf428c9157f2e8d4d6f7c844dc185933
|
||||
react-native-webview: ea4899a1056c782afa96dd082179a66cbebf5504
|
||||
React-perflogger: 0458a87ea9a7342079e7a31b0d32b3734fb8415f
|
||||
React-RCTActionSheet: 22538001ea2926dea001111dd2846c13a0730bc9
|
||||
|
||||
@@ -1061,7 +1061,6 @@
|
||||
"chat": "اظهِر/اخفِ نافذة الدردشة",
|
||||
"clap": "تصفيق",
|
||||
"collapse": "قلّص",
|
||||
"dock": "إرساء في النافذة الرئيسية",
|
||||
"document": "اظهِر/اخفِ الملف المشارك",
|
||||
"download": "نزِّل التطبيق",
|
||||
"embedMeeting": "ضمِّن المُلتقى",
|
||||
@@ -1115,7 +1114,6 @@
|
||||
"tileView": "اظهِر/اخفِ عرض العنوان",
|
||||
"toggleCamera": "بدِّل الكاميرا",
|
||||
"toggleFilmstrip": "بدِّل وضع الشريط السينمائي (filmstrip)",
|
||||
"undock": "فك في نافذة منفصلة",
|
||||
"videoblur": "استعمل/اخرج من وضع تغبيش خلفية الفيديو",
|
||||
"videomute": "بدِّل وضع اخفاء الفيديو"
|
||||
},
|
||||
@@ -1133,7 +1131,6 @@
|
||||
"closeReactionsMenu": "إغلاق قائمة ردود الفعل",
|
||||
"disableNoiseSuppression": "قم بتعطيل خاصية منع الضوضاء",
|
||||
"disableReactionSounds": "يمكنك تعطيل أصوات ردود الفعل لهذا المُلتقى",
|
||||
"dock": "إرساء في النافذة الرئيسية",
|
||||
"documentClose": "أغلق الملف المشارك",
|
||||
"documentOpen": "افتح الملف المشارك",
|
||||
"download": "نزِّل التطبيق",
|
||||
@@ -1205,7 +1202,6 @@
|
||||
"talkWhileMutedPopup": "أتحاول التحدث؟ الميكروفون لديك مكتوم.",
|
||||
"tileViewToggle": "بدِّل عنوان العرض",
|
||||
"toggleCamera": "بدِّل الكاميرا",
|
||||
"undock": "فك في نافذة منفصلة",
|
||||
"videoSettings": "اعدادات الفيديو",
|
||||
"videomute": "استعمل / أوقف الكاميرا"
|
||||
},
|
||||
|
||||
@@ -1027,7 +1027,6 @@
|
||||
"chat": "Obre o tanca el xat",
|
||||
"clap": "Picament de mans",
|
||||
"collapse": "Col·lapsa",
|
||||
"dock": "Acobla a la finestra principal",
|
||||
"document": "Activa o desactiva el document compartit",
|
||||
"download": "Baixeu les nostres aplicacions",
|
||||
"embedMeeting": "Insereix la reunió",
|
||||
@@ -1079,7 +1078,6 @@
|
||||
"tileView": "Activa o desactiva el mode mosaic",
|
||||
"toggleCamera": "Activa o desactiva la càmera",
|
||||
"toggleFilmstrip": "Mostra o amaga la cinta",
|
||||
"undock": "Desacobla en una finestra separada",
|
||||
"videoblur": "Activa o desactiva el desenfocament del vídeo",
|
||||
"videomute": "Activa o desactiva la càmera"
|
||||
},
|
||||
@@ -1096,7 +1094,6 @@
|
||||
"closeChat": "Tanca el xat",
|
||||
"closeReactionsMenu": "Tanca el menú de reaccions",
|
||||
"disableReactionSounds": "Podeu desactivar els sons de reacció per a aquesta reunió",
|
||||
"dock": "Acobla en la finestra principal",
|
||||
"documentClose": "Tanca el document compartit",
|
||||
"documentOpen": "Obre el document compartit",
|
||||
"download": "Baixeu les nostres aplicacions",
|
||||
@@ -1166,7 +1163,6 @@
|
||||
"talkWhileMutedPopup": "Intenteu parlar? Esteu silenciat.",
|
||||
"tileViewToggle": "Activa o desactiva el mode mosaic",
|
||||
"toggleCamera": "Activa o desactiva la càmera",
|
||||
"undock": "Desacobla en una finestra principal",
|
||||
"videoSettings": "Paràmetres de vídeo",
|
||||
"videomute": "Inicia o atura la càmera"
|
||||
},
|
||||
|
||||
@@ -1060,7 +1060,6 @@
|
||||
"chat": "Přepnout okno zpráv",
|
||||
"clap": "Tleskat",
|
||||
"collapse": "Zabalit",
|
||||
"dock": "Dokovat v hlavním okně",
|
||||
"document": "Přepnout sdílený dokument",
|
||||
"download": "Stáhnout naše aplikace",
|
||||
"embedMeeting": "Vložit setkání",
|
||||
@@ -1114,7 +1113,6 @@
|
||||
"tileView": "Přepnout dlaždicové zobrazení",
|
||||
"toggleCamera": "Přepnout kameru",
|
||||
"toggleFilmstrip": "Přepnout video náhledy",
|
||||
"undock": "Oddokovat do samostatného okna",
|
||||
"videoblur": "Přepnout rozmazání videa",
|
||||
"videomute": "Přepnout ztišení videa"
|
||||
},
|
||||
@@ -1132,7 +1130,6 @@
|
||||
"closeReactionsMenu": "Zavrít menu reakcí",
|
||||
"disableNoiseSuppression": "Vypnout potlačení šumu",
|
||||
"disableReactionSounds": "Vypnout zvuky reakcí",
|
||||
"dock": "Dokovat v hlavním okně",
|
||||
"documentClose": "Zavřít sdílený dokument",
|
||||
"documentOpen": "Otevřít sdílený dokument",
|
||||
"download": "Stáhnout naše aplikace",
|
||||
@@ -1204,7 +1201,6 @@
|
||||
"talkWhileMutedPopup": "Snažíte se mluvit? Máte ztišený mikrofon.",
|
||||
"tileViewToggle": "Přepnout dlaždicové zobrazení",
|
||||
"toggleCamera": "Přepnout kameru",
|
||||
"undock": "",
|
||||
"videoSettings": "",
|
||||
"videomute": "Zapnout / Vypnout kameru"
|
||||
},
|
||||
|
||||
@@ -1066,7 +1066,6 @@
|
||||
"chat": "Chatfenster öffnen / schließen",
|
||||
"clap": "Klatschen",
|
||||
"collapse": "Einklappen",
|
||||
"dock": "In Hauptfenster einbinden",
|
||||
"document": "Geteiltes Dokument schließen",
|
||||
"download": "Unsere Apps herunterladen",
|
||||
"embedMeeting": "Konferenz einbetten",
|
||||
@@ -1120,7 +1119,6 @@
|
||||
"tileView": "Kachelansicht ein-/ausschalten",
|
||||
"toggleCamera": "Kamera wechseln",
|
||||
"toggleFilmstrip": "Miniaturansichten ein-/ausschalten",
|
||||
"undock": "In eigenem Fenster anzeigen",
|
||||
"videoblur": "Unscharfer Hintergrund ein-/ausschalten",
|
||||
"videomute": "„Video stummschalten“ ein-/ausschalten",
|
||||
"whiteboard": "Whiteboard ein-/ausschalten"
|
||||
@@ -1139,7 +1137,6 @@
|
||||
"closeReactionsMenu": "Interaktionsmenü schließen",
|
||||
"disableNoiseSuppression": "Rauschunterdrückung deaktivieren",
|
||||
"disableReactionSounds": "Sie können die Interaktionstöne für diese Konferenz deaktivieren",
|
||||
"dock": "In Hauptfenster einbinden",
|
||||
"documentClose": "Geteiltes Dokument schließen",
|
||||
"documentOpen": "Geteiltes Dokument öffnen",
|
||||
"download": "Unsere Apps herunterladen",
|
||||
@@ -1213,7 +1210,6 @@
|
||||
"talkWhileMutedPopup": "Versuchen Sie zu sprechen? Ihr Mikrofon ist stummgeschaltet.",
|
||||
"tileViewToggle": "Kachelansicht ein-/ausschalten",
|
||||
"toggleCamera": "Kamera wechseln",
|
||||
"undock": "In eigenem Fenster anzeigen",
|
||||
"videoSettings": "Kameraeinstellungen",
|
||||
"videomute": "Kamera starten / stoppen"
|
||||
},
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "Otvori/Zatvori chat",
|
||||
"clap": "Plješći",
|
||||
"collapse": "Sklopi",
|
||||
"dock": "Prikvači u glavni prozor",
|
||||
"document": "Uključi/Isključi dijeljeni dokument",
|
||||
"download": "Preuzmi naše aplikacije",
|
||||
"embedMeeting": "Ugradi sastanak",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "Uključi/Isključi pločasti prikaz",
|
||||
"toggleCamera": "Uključi/Isključi kameru",
|
||||
"toggleFilmstrip": "Uključi/Isključi slike videa",
|
||||
"undock": "Odspoji u zasebni prozor",
|
||||
"videoblur": "Uključi/Isključi zamućenje videa",
|
||||
"videomute": "Pokreni/Prekini kameru",
|
||||
"whiteboard": "Pokaži/Sakrij ploču za prezentacije"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "Zatvori izbornik reakcija",
|
||||
"disableNoiseSuppression": "Isključi suzbijanje šumova",
|
||||
"disableReactionSounds": "Za ovaj sastanak možeš isključiti zvukove reakcija",
|
||||
"dock": "Prikvači u glavni prozor",
|
||||
"documentClose": "Zatvori dijeljeni dokument",
|
||||
"documentOpen": "Otvori dijeljeni dokument",
|
||||
"download": "Preuzmi naše aplikacije",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "Pokušavaš govoriti? Tvoj zvuk je isključen.",
|
||||
"tileViewToggle": "Uključi/Isključi pločasti prikaz",
|
||||
"toggleCamera": "Uključi/Isključi kameru",
|
||||
"undock": "Odspoji u zasebni prozor",
|
||||
"videoSettings": "Videopostavke",
|
||||
"videomute": "Pokreni/Prekini kameru"
|
||||
},
|
||||
|
||||
@@ -1033,7 +1033,6 @@
|
||||
"chat": "chat-woknješko pokazać/schować",
|
||||
"clap": "placać",
|
||||
"collapse": "pomjeńšić",
|
||||
"dock": "we hłownej wobrazowce fiksěrować",
|
||||
"document": "dźěleny dokument začinić",
|
||||
"download": "naše aplikacije downloadować ",
|
||||
"embedMeeting": "konferencu integrować",
|
||||
@@ -1085,7 +1084,6 @@
|
||||
"tileView": "kachlicowy napohlad zapnyć/hasnyć",
|
||||
"toggleCamera": "kameru měnić",
|
||||
"toggleFilmstrip": "miniaturowy napohlad zapnyć/hasnyć ",
|
||||
"undock": "rozwjazać",
|
||||
"videoblur": "njejasny widejo zapnyć/hasnyć ",
|
||||
"videomute": "„něme šaltowanje wideja zapnyć/hasnyć "
|
||||
},
|
||||
@@ -1102,7 +1100,6 @@
|
||||
"closeChat": "chat začinić",
|
||||
"closeReactionsMenu": "meni za interakcije začinić",
|
||||
"disableReactionSounds": "Móžeće zwuki za interakcije za tutu konferencu deaktiwěrować.",
|
||||
"dock": "fiksěrować",
|
||||
"documentClose": "dźěleny dokument začinić",
|
||||
"documentOpen": "dźěleny dokument wočinić",
|
||||
"download": "naše aplikacije downloadować",
|
||||
@@ -1172,7 +1169,6 @@
|
||||
"talkWhileMutedPopup": "Spytaće Wy rěčeć? Waš mikrofon je němy.",
|
||||
"tileViewToggle": " kachlicowy napohlad zapnyć/hasnyć ",
|
||||
"toggleCamera": "kameru měnić",
|
||||
"undock": "rozwjazać",
|
||||
"videoSettings": "nastajenja za widejo",
|
||||
"videomute": "kameru startować/hasnyć"
|
||||
},
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "Conversazione",
|
||||
"clap": "Applaudi",
|
||||
"collapse": "Riduci",
|
||||
"dock": "Aggancia alla finestra principale",
|
||||
"document": "Documenti condivisi",
|
||||
"download": "Scarica le nostre app",
|
||||
"embedMeeting": "Incorpora riunione altrove",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "Vedi tutti i partecipanti, o uno solo",
|
||||
"toggleCamera": "Cambia videocamera",
|
||||
"toggleFilmstrip": "Pellicola",
|
||||
"undock": "Sgancia in una finestra separata",
|
||||
"videoblur": "Sfoca video",
|
||||
"videomute": "Videocamera",
|
||||
"whiteboard": "Usa lavagna"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "Chiudi il menù reazioni",
|
||||
"disableNoiseSuppression": "Interrompi riduzione rumore",
|
||||
"disableReactionSounds": "Puoi disattivare i suoni delle reaction, in questa riunione",
|
||||
"dock": "Aggancia nella finestra principale",
|
||||
"documentClose": "Chiudi documento condiviso",
|
||||
"documentOpen": "Apri documento condiviso",
|
||||
"download": "Scarica le nostre app",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "Stai provando a parlare? Il microfono è disattivato.",
|
||||
"tileViewToggle": "Vedi tutti i partecipanti insieme, o uno solo",
|
||||
"toggleCamera": "Cambia videocamera",
|
||||
"undock": "Sgancia in una finestra separata",
|
||||
"videoSettings": "Impostazioni video",
|
||||
"videomute": "Videocamera"
|
||||
},
|
||||
|
||||
@@ -1057,7 +1057,6 @@
|
||||
"chat": "Przełączanie okna rozmowy",
|
||||
"clap": "Klaskanie",
|
||||
"collapse": "Zwiń",
|
||||
"dock": "Zadokuj w głównym oknie",
|
||||
"document": "Przełączanie wspólnego dokumentu",
|
||||
"download": "Pobierz nasze aplikacje",
|
||||
"embedMeeting": "Osadź spotkanie",
|
||||
@@ -1109,7 +1108,6 @@
|
||||
"tileView": "Przełącz widok kafelkowy",
|
||||
"toggleCamera": "Przełączanie kamery",
|
||||
"toggleFilmstrip": "Przełącz filmstrip",
|
||||
"undock": "Oddokuj w osobnym oknie",
|
||||
"videoblur": "Przełącz rozmazanie obrazu",
|
||||
"videomute": "Przełączanie wyciszonego filmu wideo"
|
||||
},
|
||||
@@ -1127,7 +1125,6 @@
|
||||
"closeReactionsMenu": "Zamknij reakcje",
|
||||
"disableNoiseSuppression": "Wyłącz tłumienie szumów",
|
||||
"disableReactionSounds": "Wyłącz dźwięki reakcji dla tego spotkania",
|
||||
"dock": "Zadokuj w głównym oknie",
|
||||
"documentClose": "Zamknij udostępniony dokument",
|
||||
"documentOpen": "Otwarty udostępniony dokument",
|
||||
"download": "Pobierz nasze aplikacje",
|
||||
@@ -1197,7 +1194,6 @@
|
||||
"talkWhileMutedPopup": "Próbujesz mówić? Jesteś wyciszony.",
|
||||
"tileViewToggle": "Przełączanie kafelkowego widoku",
|
||||
"toggleCamera": "Przełączanie kamery",
|
||||
"undock": "Oddokuj w osobnym oknie",
|
||||
"videoSettings": "Ustawienia video",
|
||||
"videomute": "Włącz / Wyłącz kamerę"
|
||||
},
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "Abrir / Fechar chat",
|
||||
"clap": "Aplausos",
|
||||
"collapse": "Colapsar",
|
||||
"dock": "Ancorar na janela principal",
|
||||
"document": "Mudar para documento partilhado",
|
||||
"download": "Descarregar as nossas aplicações",
|
||||
"embedMeeting": "Reunião incorporada",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "Mudar a vista em quadrícula",
|
||||
"toggleCamera": "Mudar a câmara",
|
||||
"toggleFilmstrip": "Mudar a película de filme",
|
||||
"undock": "Desancorar numa janela separada",
|
||||
"videoblur": "Mudar o desfoque de vídeo",
|
||||
"videomute": "Iniciar / Parar câmara",
|
||||
"whiteboard": "Mostrar / Esconder quadro branco"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "Fechar menu de reações",
|
||||
"disableNoiseSuppression": "Desativar a supressão de ruído",
|
||||
"disableReactionSounds": "Pode desactivar os sons de reacção para esta reunião",
|
||||
"dock": "Ancorar na janela principal",
|
||||
"documentClose": "Fechar documento partilhado",
|
||||
"documentOpen": "Abrir documento partilhado",
|
||||
"download": "Descarregar as nossas aplicações",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "Está a tentar falar? Está com o microfone desativado.",
|
||||
"tileViewToggle": "Mudar para vista em quadrícula",
|
||||
"toggleCamera": "Mudar a câmara",
|
||||
"undock": "Desancorar numa janela separada",
|
||||
"videoSettings": "Definições de vídeo",
|
||||
"videomute": "Iniciar / Parar câmara"
|
||||
},
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "Öppna eller stäng chattfönster",
|
||||
"clap": "Klappa",
|
||||
"collapse": "Kollaps",
|
||||
"dock": "Docka i huvudfönstret",
|
||||
"document": "Öppna eller stäng delat dokument",
|
||||
"download": "Ladda ner app",
|
||||
"embedMeeting": "Bädda in möte",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "Öppna eller stäng panelvyn",
|
||||
"toggleCamera": "Växla kamera",
|
||||
"toggleFilmstrip": "Växla filmremsa",
|
||||
"undock": "Lossa till ett separat fönster",
|
||||
"videoblur": "Växla videooskärpa",
|
||||
"videomute": "Sätt på eller stäng av mikrofonen",
|
||||
"whiteboard": "Visa/dölj whiteboardtavlan"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "Stäng meny för reaktioner",
|
||||
"disableNoiseSuppression": "Inaktivera brusreducering",
|
||||
"disableReactionSounds": "Du kan inaktivera reaktionsljud för det här mötet",
|
||||
"dock": "Docka i huvudfönstret",
|
||||
"documentClose": "Stäng delat dokument",
|
||||
"documentOpen": "Öppna delat dokument",
|
||||
"download": "Ladda ner vår app",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "Försöker du tala? Din mikrofon är tystad.",
|
||||
"tileViewToggle": "Öppna eller stäng panelvyn",
|
||||
"toggleCamera": "Byta kamera",
|
||||
"undock": "Lossa till ett separat fönster",
|
||||
"videoSettings": "Video inställningar",
|
||||
"videomute": "Aktivera / avaktivera kameran"
|
||||
},
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "Mesajlaşma penceresini aç/kapat",
|
||||
"clap": "Alkış",
|
||||
"collapse": "Daralt",
|
||||
"dock": "Ana pencerede sabitleyin",
|
||||
"document": "Paylaşılan dokümanı aç/kapat",
|
||||
"download": "Uygulamalarımızı indirin",
|
||||
"embedMeeting": "Toplantıyı yerleştir",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "Döşeme görünümünü aç/kapat",
|
||||
"toggleCamera": "Kamerayı değiştir",
|
||||
"toggleFilmstrip": "Film şeridini aç/kapat",
|
||||
"undock": "Ayrı pencereye çıkarın",
|
||||
"videoblur": "Video bulanıklaştırma aç/kapat",
|
||||
"videomute": "Sessiz videoyu aç/kapat",
|
||||
"whiteboard": "Beyaztahtayı Göster / Gizle"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "Reaksiyon menüsünü kapat",
|
||||
"disableNoiseSuppression": "",
|
||||
"disableReactionSounds": "Toplantı için reaksiyon seslerini devre dışı bırak",
|
||||
"dock": "Ana pencerede sabitleyin",
|
||||
"documentClose": "Paylaşılan dokümanı kapat",
|
||||
"documentOpen": "Paylaşılan dokümanı aç",
|
||||
"download": "Uygulamalarımızı indirin",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "Bir şey mi dediniz? Mikrofonunuz kapalı.",
|
||||
"tileViewToggle": "Döşeme görünümünü aç/kapat",
|
||||
"toggleCamera": "Kamerayı değiştir",
|
||||
"undock": "Ayrı pencereye çıkarın",
|
||||
"videoSettings": "Video ayarları",
|
||||
"videomute": "Kamera başlat / durdur"
|
||||
},
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "Показати/приховати чат",
|
||||
"clap": "Овації",
|
||||
"collapse": "Згорнути",
|
||||
"dock": "Закріпити в головному вікні",
|
||||
"document": "Відкрити/закрити спільний документ",
|
||||
"download": "Звантажити мобільний застосунок",
|
||||
"embedMeeting": "Вставити зустріч",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "Увімкнути/вимкнути плитки",
|
||||
"toggleCamera": "Увімкнути/вимкнути камеру",
|
||||
"toggleFilmstrip": "Показати/приховати панель видів",
|
||||
"undock": "Відкріпити в окремому вікні",
|
||||
"videoblur": "Увімкнути/вимкнути розмиття фону",
|
||||
"videomute": "Увімкнути/вимкнути камеру",
|
||||
"whiteboard": "Показати/приховати дошку"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "Закрити меню реакцій",
|
||||
"disableNoiseSuppression": "Вимкнути придушення шуму",
|
||||
"disableReactionSounds": "Ви можете вимкнути звуки реакції для цієї зустрічі",
|
||||
"dock": "Закріпити в головному вікні",
|
||||
"documentClose": "Закрити спільний документ",
|
||||
"documentOpen": "Відкрити спільний документ",
|
||||
"download": "Звантажити мобільний застосунок",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "Намагаєтесь говорити? Ваш мікрофон вимкнено.",
|
||||
"tileViewToggle": "Плитки",
|
||||
"toggleCamera": "Увімкнути/вимкнути камеру",
|
||||
"undock": "Відкріпити в окремому вікні",
|
||||
"videoSettings": "Налаштування камери",
|
||||
"videomute": "Камера"
|
||||
},
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "打开/关闭聊天窗口",
|
||||
"clap": "鼓掌",
|
||||
"collapse": "收起",
|
||||
"dock": "在主窗口停靠",
|
||||
"document": "开启/关闭文件共享",
|
||||
"download": "下载应用",
|
||||
"embedMeeting": "嵌入会议",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "开启/关闭画廊视图",
|
||||
"toggleCamera": "开启/关闭摄像头",
|
||||
"toggleFilmstrip": "开启/关闭幻灯片",
|
||||
"undock": "取消停靠到单独的窗口",
|
||||
"videoblur": "开启/关闭视频模糊",
|
||||
"videomute": "启动/停止摄像头",
|
||||
"whiteboard": "显示/隐藏白板"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "关闭反应菜单",
|
||||
"disableNoiseSuppression": "关闭噪音抑制",
|
||||
"disableReactionSounds": "你可以禁用此会议的反应声音",
|
||||
"dock": "在主窗口停靠",
|
||||
"documentClose": "关闭文件共享",
|
||||
"documentOpen": "开启文件共享",
|
||||
"download": "下载我们的APP",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "你在尝试发言吗? 当前你是静音状态。",
|
||||
"tileViewToggle": "画面模式",
|
||||
"toggleCamera": "开启/关闭摄像头",
|
||||
"undock": "取消停靠到单独的窗口",
|
||||
"videoSettings": "视频设置",
|
||||
"videomute": "开启/关闭摄像头"
|
||||
},
|
||||
|
||||
@@ -1067,7 +1067,6 @@
|
||||
"chat": "打開/關閉聊天視窗",
|
||||
"clap": "鼓掌",
|
||||
"collapse": "收回",
|
||||
"dock": "停靠在主視窗中",
|
||||
"document": "啟用/停用分享文檔",
|
||||
"download": "下載我們的應用程式",
|
||||
"embedMeeting": "嵌入會議",
|
||||
@@ -1121,7 +1120,6 @@
|
||||
"tileView": "啟用/停用畫廊檢視",
|
||||
"toggleCamera": "啟用/停用網路攝影機",
|
||||
"toggleFilmstrip": "啟用/停用簡報",
|
||||
"undock": "取消停靠到單獨的视窗",
|
||||
"videoblur": "啟用/停用畫面模糊",
|
||||
"videomute": "啟用/停用網路攝影機",
|
||||
"whiteboard": "啟用/停用白板"
|
||||
@@ -1140,7 +1138,6 @@
|
||||
"closeReactionsMenu": "關閉反應選單",
|
||||
"disableNoiseSuppression": "停用雜訊抑制",
|
||||
"disableReactionSounds": "您可以停用此會議的反應音效",
|
||||
"dock": "停靠在主視窗中",
|
||||
"documentClose": "關閉分享檔案欄",
|
||||
"documentOpen": "開啟分享檔案欄",
|
||||
"download": "下載我們的應用程式",
|
||||
@@ -1214,7 +1211,6 @@
|
||||
"talkWhileMutedPopup": "您要發言嗎?目前您處於靜音。",
|
||||
"tileViewToggle": "啟動/停用畫廊檢視",
|
||||
"toggleCamera": "啟動/停用網路攝影機",
|
||||
"undock": "取消停靠到單獨的视窗",
|
||||
"videoSettings": "視訊設定",
|
||||
"videomute": "啟動/停用網路攝影機"
|
||||
},
|
||||
|
||||
@@ -147,6 +147,7 @@
|
||||
"bridgeCount": "Server count: ",
|
||||
"codecs": "Codecs (A/V): ",
|
||||
"connectedTo": "Connected to:",
|
||||
"e2eeVerified": "E2EE verified:",
|
||||
"framerate": "Frame rate:",
|
||||
"less": "Show less",
|
||||
"localaddress": "Local address:",
|
||||
@@ -408,6 +409,10 @@
|
||||
"user": "User",
|
||||
"userIdentifier": "User identifier",
|
||||
"userPassword": "User password",
|
||||
"verifyParticipantConfirm": "They match",
|
||||
"verifyParticipantDismiss": "They do not match",
|
||||
"verifyParticipantQuestion": "EXPERIMENTAL: Ask participant {{participantName}} if they see the same content, in the same order.",
|
||||
"verifyParticipantTitle": "User verification",
|
||||
"videoLink": "Video link",
|
||||
"viewUpgradeOptions": "View upgrade options",
|
||||
"viewUpgradeOptionsContent": "To get unlimited access to premium features like recording, transcriptions, RTMP Streaming & more, you'll need to upgrade your plan.",
|
||||
@@ -1069,7 +1074,6 @@
|
||||
"chat": "Open / Close chat",
|
||||
"clap": "Clap",
|
||||
"collapse": "Collapse",
|
||||
"dock": "Dock in main window",
|
||||
"document": "Toggle shared document",
|
||||
"download": "Download our apps",
|
||||
"embedMeeting": "Embed meeting",
|
||||
@@ -1123,7 +1127,6 @@
|
||||
"tileView": "Toggle tile view",
|
||||
"toggleCamera": "Toggle camera",
|
||||
"toggleFilmstrip": "Toggle filmstrip",
|
||||
"undock": "Undock into separate window",
|
||||
"videoblur": "Toggle video blur",
|
||||
"videomute": "Start / Stop camera",
|
||||
"whiteboard": "Show / Hide whiteboard"
|
||||
@@ -1142,7 +1145,6 @@
|
||||
"closeReactionsMenu": "Close reactions menu",
|
||||
"disableNoiseSuppression": "Disable noise suppression",
|
||||
"disableReactionSounds": "You can disable reaction sounds for this meeting",
|
||||
"dock": "Dock in main window",
|
||||
"documentClose": "Close shared document",
|
||||
"documentOpen": "Open shared document",
|
||||
"download": "Download our apps",
|
||||
@@ -1216,7 +1218,6 @@
|
||||
"talkWhileMutedPopup": "Trying to speak? You are muted.",
|
||||
"tileViewToggle": "Toggle tile view",
|
||||
"toggleCamera": "Toggle camera",
|
||||
"undock": "Undock into separate window",
|
||||
"videoSettings": "Video settings",
|
||||
"videomute": "Start / Stop camera"
|
||||
},
|
||||
@@ -1297,6 +1298,7 @@
|
||||
"show": "Show on stage",
|
||||
"showSelfView": "Show self view",
|
||||
"unpinFromStage": "Unpin",
|
||||
"verify": "Verify participant",
|
||||
"videoMuted": "Camera disabled",
|
||||
"videomute": "Participant has stopped the camera"
|
||||
},
|
||||
|
||||
@@ -1671,22 +1671,6 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that the iframe
|
||||
* docked state has been changed. The responsibility for implementing
|
||||
* the dock / undock functionality lies with the external application.
|
||||
*
|
||||
* @param {boolean} docked - Whether or not the iframe has been set to
|
||||
* be docked or undocked.
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyIframeDockStateChanged(docked: boolean) {
|
||||
this._sendEvent({
|
||||
name: 'iframe-dock-state-changed',
|
||||
docked
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application of a participant, remote or local, being
|
||||
* removed from the conference by another participant.
|
||||
|
||||
1
modules/API/external/external_api.js
vendored
@@ -117,7 +117,6 @@ const events = {
|
||||
'feedback-submitted': 'feedbackSubmitted',
|
||||
'feedback-prompt-displayed': 'feedbackPromptDisplayed',
|
||||
'filmstrip-display-changed': 'filmstripDisplayChanged',
|
||||
'iframe-dock-state-changed': 'iframeDockStateChanged',
|
||||
'incoming-message': 'incomingMessage',
|
||||
'knocking-participant': 'knockingParticipant',
|
||||
'log': 'log',
|
||||
|
||||
106
package-lock.json
generated
@@ -28,10 +28,10 @@
|
||||
"@giphy/react-native-sdk": "1.7.0",
|
||||
"@hapi/bourne": "2.0.0",
|
||||
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.12/jitsi-excalidraw-0.0.12.tgz",
|
||||
"@jitsi/js-utils": "2.0.4",
|
||||
"@jitsi/js-utils": "2.0.5",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
"@jitsi/rnnoise-wasm": "0.1.0",
|
||||
"@jitsi/rtcstats": "9.5.0",
|
||||
"@jitsi/rtcstats": "9.5.1",
|
||||
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
|
||||
"@microsoft/microsoft-graph-client": "3.0.1",
|
||||
"@mui/material": "5.10.2",
|
||||
@@ -74,7 +74,7 @@
|
||||
"js-md5": "0.6.1",
|
||||
"js-sha512": "0.8.0",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1541.0.0+9b34e0f7/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1557.0.0+8df33524/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -114,14 +114,14 @@
|
||||
"react-native-url-polyfill": "1.3.0",
|
||||
"react-native-video": "https://git@github.com/react-native-video/react-native-video#7c48ae7c8544b2b537fb60194e9620b9fcceae52",
|
||||
"react-native-watch-connectivity": "1.0.11",
|
||||
"react-native-webrtc": "1.106.1",
|
||||
"react-native-webrtc": "106.0.0",
|
||||
"react-native-webview": "11.15.1",
|
||||
"react-native-youtube-iframe": "2.2.1",
|
||||
"react-redux": "7.1.0",
|
||||
"react-textarea-autosize": "8.3.0",
|
||||
"react-transition-group": "2.4.0",
|
||||
"react-window": "1.8.6",
|
||||
"react-youtube": "7.13.1",
|
||||
"react-youtube": "10.1.0",
|
||||
"redux": "4.0.4",
|
||||
"redux-thunk": "2.4.1",
|
||||
"resemblejs": "4.0.0",
|
||||
@@ -3756,9 +3756,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jitsi/js-utils": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-2.0.4.tgz",
|
||||
"integrity": "sha512-voXa8Y8srv/q3gD9wWOGMPVqOWT4s0n4B/ApkPDAIN8EG/6mpzAfHNMi4BIOQeeo2P0srIdcD6Y/1S/ftjuhYQ==",
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-2.0.5.tgz",
|
||||
"integrity": "sha512-Aa7lt/sGsDymWnKJtM1RePmR2b2J5TwY3QLv5iOmzMDYR+5RE0NyYc/vKW51JeatDVSkj+LT7kpUDvtJua0rmQ==",
|
||||
"dependencies": {
|
||||
"bowser": "2.7.0",
|
||||
"js-md5": "0.7.3"
|
||||
@@ -3780,9 +3780,9 @@
|
||||
"integrity": "sha512-JujivPbOUvdRYa2xqByHYKfKGNGa7ZPyNLaNuh8hEp9XsiNfjaJAHdboq6M1VY9TP+765nyxC0LjpAw1VkikOQ=="
|
||||
},
|
||||
"node_modules/@jitsi/rtcstats": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.5.0.tgz",
|
||||
"integrity": "sha512-jKB+1IzKuqynA2etmWAA4uDFF0oAFUZWxRq+m+rOt8FfBp6pXojWbWA7xblcjxerj/3njGc8nEQbcK9qck1How==",
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.5.1.tgz",
|
||||
"integrity": "sha512-UDcsNwPvweQ6owV/chwabd6DsQd2aB4qjqrOB+BlJnETZ+zssGYAey3ezaiNK6nxevwBkbHj980/S9v+2y4btg==",
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "^2.0.0",
|
||||
"sdp": "^3.0.3",
|
||||
@@ -13497,8 +13497,8 @@
|
||||
},
|
||||
"node_modules/lib-jitsi-meet": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1541.0.0+9b34e0f7/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-A+QkH3v0XzLSxumHC7LHWXLmFHTqrJ/1YCbWFd/eHjDGXVyFCPeazYBpsNdGZMHfEBzG9FLdQCEOxyzBY7yIAA==",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1557.0.0+8df33524/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-LH24V3aCAyNxrXkYsr4Syz9G+hDyfGo7JUu3suEbh1bS5Y4w8mwzTBHyGazLnD7/NDG5F783DY19/yCzR7stSQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
@@ -16501,13 +16501,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-webrtc": {
|
||||
"version": "1.106.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.106.1.tgz",
|
||||
"integrity": "sha512-955gqWFdISARz9D4hmnPzKQwpaU+AGqUbU+vBjzLCozUseSJ69tTQg2cShyPCBH6A1rwJQE+mrdjcpkeGbx3pQ==",
|
||||
"version": "106.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-106.0.0.tgz",
|
||||
"integrity": "sha512-nFl8WSNGMNxuIiaNAiJvILRcEC65yRxPOWTexLrM+vo44syt/4chEvzN9eOqXiPsOmsECQmwZupCUGR5XABUNg==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"adm-zip": "0.5.9",
|
||||
"base64-js": "1.5.1",
|
||||
"debug": "4.3.4",
|
||||
"event-target-shim": "6.0.2",
|
||||
"tar": "6.1.11"
|
||||
},
|
||||
@@ -16766,36 +16767,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-youtube": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-youtube/-/react-youtube-7.13.1.tgz",
|
||||
"integrity": "sha512-b++TLHmHDpd0ZBS1wcbYabbuchU+W4jtx5A2MUQX0BINNKKsaIQX29sn/aLvZ9v5luwAoceia3VGtyz9blaB9w==",
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-youtube/-/react-youtube-10.1.0.tgz",
|
||||
"integrity": "sha512-ZfGtcVpk0SSZtWCSTYOQKhfx5/1cfyEW1JN/mugGNfAxT3rmVJeMbGpA9+e78yG21ls5nc/5uZJETE3cm3knBg==",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "3.1.3",
|
||||
"prop-types": "15.7.2",
|
||||
"prop-types": "15.8.1",
|
||||
"youtube-player": "5.5.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.x"
|
||||
"node": ">= 14.x"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=0.14.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-youtube/node_modules/prop-types": {
|
||||
"version": "15.7.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-youtube/node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
@@ -23182,9 +23168,9 @@
|
||||
"integrity": "sha512-WFzaH5GCZLA5DTSZ6ReqAz9g53mSgi+211zTC7AFZUYZme5tzKpPg55AKkJZA3ZIRikkbKaEfP/dC4QOH5NMmA=="
|
||||
},
|
||||
"@jitsi/js-utils": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-2.0.4.tgz",
|
||||
"integrity": "sha512-voXa8Y8srv/q3gD9wWOGMPVqOWT4s0n4B/ApkPDAIN8EG/6mpzAfHNMi4BIOQeeo2P0srIdcD6Y/1S/ftjuhYQ==",
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-2.0.5.tgz",
|
||||
"integrity": "sha512-Aa7lt/sGsDymWnKJtM1RePmR2b2J5TwY3QLv5iOmzMDYR+5RE0NyYc/vKW51JeatDVSkj+LT7kpUDvtJua0rmQ==",
|
||||
"requires": {
|
||||
"bowser": "2.7.0",
|
||||
"js-md5": "0.7.3"
|
||||
@@ -23208,9 +23194,9 @@
|
||||
"integrity": "sha512-JujivPbOUvdRYa2xqByHYKfKGNGa7ZPyNLaNuh8hEp9XsiNfjaJAHdboq6M1VY9TP+765nyxC0LjpAw1VkikOQ=="
|
||||
},
|
||||
"@jitsi/rtcstats": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.5.0.tgz",
|
||||
"integrity": "sha512-jKB+1IzKuqynA2etmWAA4uDFF0oAFUZWxRq+m+rOt8FfBp6pXojWbWA7xblcjxerj/3njGc8nEQbcK9qck1How==",
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.5.1.tgz",
|
||||
"integrity": "sha512-UDcsNwPvweQ6owV/chwabd6DsQd2aB4qjqrOB+BlJnETZ+zssGYAey3ezaiNK6nxevwBkbHj980/S9v+2y4btg==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "^2.0.0",
|
||||
"sdp": "^3.0.3",
|
||||
@@ -30510,8 +30496,8 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1541.0.0+9b34e0f7/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-A+QkH3v0XzLSxumHC7LHWXLmFHTqrJ/1YCbWFd/eHjDGXVyFCPeazYBpsNdGZMHfEBzG9FLdQCEOxyzBY7yIAA==",
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1557.0.0+8df33524/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-LH24V3aCAyNxrXkYsr4Syz9G+hDyfGo7JUu3suEbh1bS5Y4w8mwzTBHyGazLnD7/NDG5F783DY19/yCzR7stSQ==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
@@ -32804,12 +32790,13 @@
|
||||
}
|
||||
},
|
||||
"react-native-webrtc": {
|
||||
"version": "1.106.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.106.1.tgz",
|
||||
"integrity": "sha512-955gqWFdISARz9D4hmnPzKQwpaU+AGqUbU+vBjzLCozUseSJ69tTQg2cShyPCBH6A1rwJQE+mrdjcpkeGbx3pQ==",
|
||||
"version": "106.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-106.0.0.tgz",
|
||||
"integrity": "sha512-nFl8WSNGMNxuIiaNAiJvILRcEC65yRxPOWTexLrM+vo44syt/4chEvzN9eOqXiPsOmsECQmwZupCUGR5XABUNg==",
|
||||
"requires": {
|
||||
"adm-zip": "0.5.9",
|
||||
"base64-js": "1.5.1",
|
||||
"debug": "4.3.4",
|
||||
"event-target-shim": "6.0.2",
|
||||
"tar": "6.1.11"
|
||||
},
|
||||
@@ -32978,30 +32965,13 @@
|
||||
}
|
||||
},
|
||||
"react-youtube": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-youtube/-/react-youtube-7.13.1.tgz",
|
||||
"integrity": "sha512-b++TLHmHDpd0ZBS1wcbYabbuchU+W4jtx5A2MUQX0BINNKKsaIQX29sn/aLvZ9v5luwAoceia3VGtyz9blaB9w==",
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-youtube/-/react-youtube-10.1.0.tgz",
|
||||
"integrity": "sha512-ZfGtcVpk0SSZtWCSTYOQKhfx5/1cfyEW1JN/mugGNfAxT3rmVJeMbGpA9+e78yG21ls5nc/5uZJETE3cm3knBg==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "3.1.3",
|
||||
"prop-types": "15.7.2",
|
||||
"prop-types": "15.8.1",
|
||||
"youtube-player": "5.5.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"prop-types": {
|
||||
"version": "15.7.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.8.1"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
|
||||
10
package.json
@@ -33,10 +33,10 @@
|
||||
"@giphy/react-native-sdk": "1.7.0",
|
||||
"@hapi/bourne": "2.0.0",
|
||||
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.12/jitsi-excalidraw-0.0.12.tgz",
|
||||
"@jitsi/js-utils": "2.0.4",
|
||||
"@jitsi/js-utils": "2.0.5",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
"@jitsi/rnnoise-wasm": "0.1.0",
|
||||
"@jitsi/rtcstats": "9.5.0",
|
||||
"@jitsi/rtcstats": "9.5.1",
|
||||
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
|
||||
"@microsoft/microsoft-graph-client": "3.0.1",
|
||||
"@mui/material": "5.10.2",
|
||||
@@ -79,7 +79,7 @@
|
||||
"js-md5": "0.6.1",
|
||||
"js-sha512": "0.8.0",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1541.0.0+9b34e0f7/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1557.0.0+8df33524/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -119,14 +119,14 @@
|
||||
"react-native-url-polyfill": "1.3.0",
|
||||
"react-native-video": "https://git@github.com/react-native-video/react-native-video#7c48ae7c8544b2b537fb60194e9620b9fcceae52",
|
||||
"react-native-watch-connectivity": "1.0.11",
|
||||
"react-native-webrtc": "1.106.1",
|
||||
"react-native-webrtc": "106.0.0",
|
||||
"react-native-webview": "11.15.1",
|
||||
"react-native-youtube-iframe": "2.2.1",
|
||||
"react-redux": "7.1.0",
|
||||
"react-textarea-autosize": "8.3.0",
|
||||
"react-transition-group": "2.4.0",
|
||||
"react-window": "1.8.6",
|
||||
"react-youtube": "7.13.1",
|
||||
"react-youtube": "10.1.0",
|
||||
"redux": "4.0.4",
|
||||
"redux-thunk": "2.4.1",
|
||||
"resemblejs": "4.0.0",
|
||||
|
||||
@@ -21,6 +21,7 @@ import { isVpaasMeeting } from '../jaas/functions';
|
||||
import { clearNotifications, showNotification } from '../notifications/actions';
|
||||
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
|
||||
import { setFatalError } from '../overlay/actions';
|
||||
import { isWelcomePageEnabled } from '../welcome/functions';
|
||||
|
||||
import {
|
||||
redirectToStaticPage,
|
||||
@@ -203,7 +204,7 @@ export function maybeRedirectToWelcomePage(options: { feedbackSubmitted?: boolea
|
||||
|
||||
// if Welcome page is enabled redirect to welcome page after 3 sec, if
|
||||
// there is a thank you message to be shown, 0.5s otherwise.
|
||||
if (getState()['features/base/config'].enableWelcomePage) {
|
||||
if (isWelcomePageEnabled(getState())) {
|
||||
setTimeout(
|
||||
() => {
|
||||
dispatch(redirectWithStoredParams('/'));
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Conference } from '../conference';
|
||||
import { getDeepLinkingPage } from '../deep-linking';
|
||||
import { UnsupportedDesktopBrowser } from '../unsupported-browser';
|
||||
import { BlankPage, WelcomePage } from '../welcome';
|
||||
import { isWelcomePageEnabled } from '../welcome/functions';
|
||||
import { getCustomLandingPageURL, isWelcomePageEnabled } from '../welcome/functions';
|
||||
|
||||
/**
|
||||
* Determines which route is to be rendered in order to depict a specific Redux
|
||||
@@ -75,7 +75,13 @@ function _getWebWelcomePageRoute(state) {
|
||||
|
||||
if (isWelcomePageEnabled(state)) {
|
||||
if (isSupportedBrowser()) {
|
||||
route.component = WelcomePage;
|
||||
const customLandingPage = getCustomLandingPageURL(state);
|
||||
|
||||
if (customLandingPage) {
|
||||
route.href = customLandingPage;
|
||||
} else {
|
||||
route.component = WelcomePage;
|
||||
}
|
||||
} else {
|
||||
route.component = UnsupportedDesktopBrowser;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import '../base/media/middleware';
|
||||
import '../base/net-info/middleware';
|
||||
import '../base/participants/middleware';
|
||||
import '../base/responsive-ui/middleware';
|
||||
import '../base/redux/middleware';
|
||||
import '../base/settings/middleware';
|
||||
import '../base/sounds/middleware';
|
||||
import '../base/testing/middleware';
|
||||
@@ -2,7 +2,6 @@ import '../authentication/middleware';
|
||||
import '../base/i18n/middleware';
|
||||
import '../base/devices/middleware';
|
||||
import '../base/media/middleware';
|
||||
import '../base/redux/middleware';
|
||||
import '../dynamic-branding/middleware';
|
||||
import '../e2ee/middleware';
|
||||
import '../external-api/middleware';
|
||||
@@ -252,6 +252,34 @@ export function getConferenceOptions(stateful: IStateful) {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object aggregating the conference options.
|
||||
*
|
||||
* @param {IStateful} stateful - The redux store state.
|
||||
* @param {Array<string>} params - The received parameters.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function generateVisitorConfig(stateful: IStateful, params: Array<string>) {
|
||||
const [ vnode, focusJid ] = params;
|
||||
|
||||
const config = toState(stateful)['features/base/config'];
|
||||
|
||||
if (!config || !config.hosts) {
|
||||
logger.warn('Wrong configuration, missing hosts.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const oldDomain = config.hosts.domain;
|
||||
|
||||
config.hosts.domain = `${vnode}.meet.jitsi`;
|
||||
config.hosts.muc = config.hosts.muc.replace(oldDomain, config.hosts.domain);
|
||||
config.hosts.visitorFocus = focusJid;
|
||||
|
||||
config.bosh += `?vnode=${vnode}`;
|
||||
config.websocket += `?vnode=${vnode}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UTC timestamp when the first participant joined the conference.
|
||||
*
|
||||
|
||||
@@ -46,6 +46,7 @@ export interface IJitsiConference {
|
||||
avModerationApprove: Function;
|
||||
avModerationReject: Function;
|
||||
createVideoSIPGWSession: Function;
|
||||
dial: Function;
|
||||
disableAVModeration: Function;
|
||||
enableAVModeration: Function;
|
||||
end: Function;
|
||||
@@ -59,6 +60,7 @@ export interface IJitsiConference {
|
||||
grantOwner: Function;
|
||||
isAVModerationSupported: Function;
|
||||
isCallstatsEnabled: Function;
|
||||
isE2EEEnabled: Function;
|
||||
isEndConferenceSupported: Function;
|
||||
isLobbySupported: Function;
|
||||
isSIPCallingSupported: Function;
|
||||
@@ -73,6 +75,7 @@ export interface IJitsiConference {
|
||||
myUserId: Function;
|
||||
off: Function;
|
||||
on: Function;
|
||||
options: any;
|
||||
removeTrack: Function;
|
||||
replaceTrack: Function;
|
||||
room: IJitsiConferenceRoom;
|
||||
@@ -89,6 +92,7 @@ export interface IJitsiConference {
|
||||
setReceiverConstraints: Function;
|
||||
setSenderVideoConstraint: Function;
|
||||
setSubject: Function;
|
||||
startVerification: Function;
|
||||
}
|
||||
|
||||
export interface IConferenceState {
|
||||
|
||||
@@ -2,7 +2,6 @@ type ToolbarButtons = 'camera' |
|
||||
'chat' |
|
||||
'closedcaptions' |
|
||||
'desktop' |
|
||||
'dock-iframe' |
|
||||
'download' |
|
||||
'embedmeeting' |
|
||||
'etherpad' |
|
||||
@@ -29,7 +28,6 @@ type ToolbarButtons = 'camera' |
|
||||
'stats' |
|
||||
'tileview' |
|
||||
'toggle-camera' |
|
||||
'undock-iframe' |
|
||||
'videoquality' |
|
||||
'__end';
|
||||
|
||||
@@ -129,6 +127,7 @@ export interface IConfig {
|
||||
preventExecution: boolean;
|
||||
}>;
|
||||
callDisplayName?: string;
|
||||
callFlowsEnabled?: boolean;
|
||||
callStatsConfigParams?: {
|
||||
additionalIDs?: {
|
||||
customerID?: string;
|
||||
@@ -341,10 +340,13 @@ export interface IConfig {
|
||||
domain: string;
|
||||
focus?: string;
|
||||
muc: string;
|
||||
visitorFocus: string;
|
||||
};
|
||||
iAmRecorder?: boolean;
|
||||
iAmSipGateway?: boolean;
|
||||
inviteAppName?: string | null;
|
||||
inviteServiceCallFlowsUrl?: string;
|
||||
inviteServiceUrl?: string;
|
||||
jaasActuatorUrl?: string;
|
||||
jaasFeedbackMetadataURL?: string;
|
||||
jaasTokenUrl?: string;
|
||||
@@ -506,6 +508,10 @@ export interface IConfig {
|
||||
webrtcIceUdpDisable?: boolean;
|
||||
websocket?: string;
|
||||
websocketKeepAliveUrl?: string;
|
||||
welcomePage?: {
|
||||
customUrl?: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
whiteboard?: {
|
||||
collabServerBaseUrl?: string;
|
||||
enabled?: boolean;
|
||||
|
||||
@@ -60,7 +60,7 @@ export function getMeetingRegion(state: IReduxState) {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function getMultipleVideoSendingSupportFeatureFlag(state: IReduxState) {
|
||||
return navigator.product !== 'ReactNative' && isUnifiedPlanEnabled(state);
|
||||
return isUnifiedPlanEnabled(state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -338,6 +338,13 @@ function _translateLegacyConfig(oldValue: IConfig) {
|
||||
});
|
||||
}
|
||||
|
||||
newValue.welcomePage = oldValue.welcomePage || {};
|
||||
if (oldValue.hasOwnProperty('enableWelcomePage')
|
||||
&& !newValue.welcomePage.hasOwnProperty('disabled')
|
||||
) {
|
||||
newValue.welcomePage.disabled = !oldValue.enableWelcomePage;
|
||||
}
|
||||
|
||||
newValue.prejoinConfig = oldValue.prejoinConfig || {};
|
||||
if (oldValue.hasOwnProperty('prejoinPageEnabled')
|
||||
&& !newValue.prejoinConfig.hasOwnProperty('enabled')
|
||||
|
||||
@@ -4,6 +4,7 @@ import WaitForOwnerDialog from '../../authentication/components/web/WaitForOwner
|
||||
import ChatPrivacyDialog from '../../chat/components/web/ChatPrivacyDialog';
|
||||
import DesktopPicker from '../../desktop-picker/components/DesktopPicker';
|
||||
import DisplayNamePrompt from '../../display-name/components/web/DisplayNamePrompt';
|
||||
import ParticipantVerificationDialog from '../../e2ee/components/ParticipantVerificationDialog';
|
||||
import EmbedMeetingDialog from '../../embed-meeting/components/EmbedMeetingDialog';
|
||||
// @ts-ignore
|
||||
import FeedbackDialog from '../../feedback/components/FeedbackDialog.web';
|
||||
@@ -49,7 +50,7 @@ const NEW_DIALOG_LIST = [ KeyboardShortcutsDialog, ChatPrivacyDialog, DisplayNam
|
||||
SharedVideoDialog, SpeakerStats, LanguageSelectorDialog, MuteEveryoneDialog, MuteEveryonesVideoDialog,
|
||||
GrantModeratorDialog, KickRemoteParticipantDialog, MuteRemoteParticipantsVideoDialog, VideoQualityDialog,
|
||||
VirtualBackgroundDialog, LoginDialog, WaitForOwnerDialog, DesktopPicker, RemoteControlAuthorizationDialog,
|
||||
LogoutDialog, SalesforceLinkDialog ];
|
||||
LogoutDialog, SalesforceLinkDialog, ParticipantVerificationDialog ];
|
||||
|
||||
// This function is necessary while the transition from @atlaskit dialog to our component is ongoing.
|
||||
const isNewDialog = (component: any) => NEW_DIALOG_LIST.some(comp => comp === component);
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.3332 3.33329C18.3332 2.41282 17.587 1.66663 16.6665 1.66663H8.33317C7.4127 1.66663 6.6665 2.41282 6.6665 3.33329V4.99996H3.33317C2.4127 4.99996 1.6665 5.74615 1.6665 6.66663V16.6666C1.6665 17.5871 2.4127 18.3333 3.33317 18.3333H13.3332C14.2536 18.3333 14.9998 17.5871 14.9998 16.6666V15H16.6665C17.587 15 18.3332 14.2538 18.3332 13.3333V3.33329ZM8.33317 3.33329H16.6665L16.6665 13.3333H14.9998V6.66663C14.9998 5.74615 14.2536 4.99996 13.3332 4.99996H8.33317V3.33329ZM3.33317 6.66663V16.6666H13.3332V6.66663H3.33317ZM6.6665 12.1024V9.99996C6.6665 9.53972 6.29341 9.16663 5.83317 9.16663C5.37293 9.16663 4.99984 9.53972 4.99984 9.99996V14.1296V14.1666C4.99984 14.5693 5.28549 14.9053 5.66523 14.983C5.71947 14.9941 5.77564 15 5.83317 15L5.83356 14.9992C5.83397 14.9992 5.83439 14.9992 5.8348 14.9992L5.83445 15H5.87022H9.99984C10.4601 15 10.8332 14.6269 10.8332 14.1666C10.8332 13.7064 10.4601 13.3333 9.99984 13.3333H7.89741L11.4116 9.81913C11.7515 9.47922 11.7515 8.92813 11.4116 8.58822C11.0717 8.24832 10.5206 8.24832 10.1807 8.58822L6.6665 12.1024Z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -22,7 +22,6 @@ export { default as IconConnectionInactive } from './ninja.svg';
|
||||
export { default as IconCopy } from './copy.svg';
|
||||
export { default as IconCrown } from './host.svg';
|
||||
export { default as IconDeviceHeadphone } from './headset.svg';
|
||||
export { default as IconDock } from './dock.svg';
|
||||
export { default as IconDotsHorizontal } from './dots-horizontal.svg';
|
||||
export { default as IconDownload } from './download.svg';
|
||||
export { default as IconE2EE } from './e2ee.svg';
|
||||
@@ -88,7 +87,6 @@ export { default as IconStopScreenshare } from './stop-screenshare.svg';
|
||||
export { default as IconSubtitles } from './subtitles.svg';
|
||||
export { default as IconTileView } from './tile-view.svg';
|
||||
export { default as IconTrash } from './trash.svg';
|
||||
export { default as IconUndock } from './undock.svg';
|
||||
export { default as IconUserDeleted } from './user-deleted.svg';
|
||||
export { default as IconUserGroups } from './user-groups.svg';
|
||||
export { default as IconUsers } from './users.svg';
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.6665 1.66663H6.6665C5.74603 1.66663 4.99984 2.41282 4.99984 3.33329V4.99996H3.33317C2.4127 4.99996 1.6665 5.74615 1.6665 6.66663V16.6666C1.6665 17.5871 2.4127 18.3333 3.33317 18.3333H13.3332C14.2536 18.3333 14.9998 17.5871 14.9998 16.6666V15H16.6665C17.587 15 18.3332 14.2538 18.3332 13.3333V3.33329C18.3332 2.41282 17.587 1.66663 16.6665 1.66663ZM13.3332 16.6666V15H6.6665C5.74603 15 4.99984 14.2538 4.99984 13.3333V6.66663H3.33317V16.6666H13.3332ZM6.6665 3.33329V13.3333H16.6665V3.33329H6.6665ZM9.99984 4.99996C9.5396 4.99996 9.1665 5.37306 9.1665 5.83329C9.1665 6.29353 9.5396 6.66663 9.99984 6.66663H12.1023L8.5881 10.1808C8.24819 10.5207 8.24819 11.0718 8.5881 11.4117C8.928 11.7516 9.4791 11.7516 9.819 11.4117L13.3332 7.89753V9.99996C13.3332 10.4602 13.7063 10.8333 14.1665 10.8333C14.6267 10.8333 14.9998 10.4602 14.9998 9.99996V5.83329C14.9998 5.37306 14.6267 4.99996 14.1665 4.99996H14.1295H9.99984Z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
@@ -43,7 +43,8 @@ export const VIDEO_MUTISM_AUTHORITY = {
|
||||
AUDIO_ONLY: 1 << 0,
|
||||
BACKGROUND: 1 << 1,
|
||||
USER: 1 << 2,
|
||||
CAR_MODE: 1 << 3
|
||||
CAR_MODE: 1 << 3,
|
||||
SCREEN_SHARE: 1 << 4
|
||||
};
|
||||
|
||||
/* eslint-enable no-bitwise */
|
||||
|
||||
@@ -13,6 +13,8 @@ export interface IParticipant {
|
||||
dominantSpeaker?: boolean;
|
||||
e2eeEnabled?: boolean;
|
||||
e2eeSupported?: boolean;
|
||||
e2eeVerificationAvailable?: boolean;
|
||||
e2eeVerified?: boolean;
|
||||
email?: string;
|
||||
fakeParticipant?: FakeParticipant;
|
||||
features?: {
|
||||
|
||||
@@ -4,9 +4,17 @@ import { IReduxState, IStore } from '../../app/types';
|
||||
import { setPictureInPictureEnabled } from '../../mobile/picture-in-picture/functions';
|
||||
import { setAudioOnly } from '../audio-only/actions';
|
||||
import JitsiMeetJS from '../lib-jitsi-meet';
|
||||
import {
|
||||
setScreenshareMuted,
|
||||
setVideoMuted
|
||||
} from '../media/actions';
|
||||
import {
|
||||
MEDIA_TYPE,
|
||||
VIDEO_MUTISM_AUTHORITY
|
||||
} from '../media/constants';
|
||||
|
||||
import { destroyLocalDesktopTrackIfExists, replaceLocalTrack } from './actions.any';
|
||||
import { getLocalVideoTrack, isLocalVideoTrackDesktop } from './functions';
|
||||
import { addLocalTrack, replaceLocalTrack } from './actions.any';
|
||||
import { getLocalDesktopTrack, getTrackState, isLocalVideoTrackDesktop } from './functions.native';
|
||||
|
||||
export * from './actions.any';
|
||||
|
||||
@@ -31,7 +39,8 @@ export function toggleScreensharing(enabled: boolean, _ignore1?: boolean, _ignor
|
||||
_startScreenSharing(dispatch, state);
|
||||
}
|
||||
} else {
|
||||
dispatch(destroyLocalDesktopTrackIfExists());
|
||||
dispatch(setScreenshareMuted(true));
|
||||
dispatch(setVideoMuted(false, MEDIA_TYPE.VIDEO, VIDEO_MUTISM_AUTHORITY.SCREEN_SHARE));
|
||||
setPictureInPictureEnabled(true);
|
||||
}
|
||||
};
|
||||
@@ -47,26 +56,33 @@ export function toggleScreensharing(enabled: boolean, _ignore1?: boolean, _ignor
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _startScreenSharing(dispatch: Function, state: IReduxState) {
|
||||
async function _startScreenSharing(dispatch: Function, state: IReduxState) {
|
||||
setPictureInPictureEnabled(false);
|
||||
|
||||
JitsiMeetJS.createLocalTracks({ devices: [ 'desktop' ] })
|
||||
.then((tracks: any[]) => {
|
||||
try {
|
||||
const tracks: any[] = await JitsiMeetJS.createLocalTracks({ devices: [ 'desktop' ] });
|
||||
const track = tracks[0];
|
||||
const currentLocalTrack = getLocalVideoTrack(state['features/base/tracks']);
|
||||
const currentJitsiTrack = currentLocalTrack?.jitsiTrack;
|
||||
const currentLocalDesktopTrack = getLocalDesktopTrack(getTrackState(state));
|
||||
const currentJitsiTrack = currentLocalDesktopTrack?.jitsiTrack;
|
||||
|
||||
dispatch(replaceLocalTrack(currentJitsiTrack, track));
|
||||
// The first time the user shares the screen we add the track and create the transceiver.
|
||||
// Afterwards, we just replace the old track, so the transceiver will be reused.
|
||||
if (currentJitsiTrack) {
|
||||
dispatch(replaceLocalTrack(currentJitsiTrack, track));
|
||||
} else {
|
||||
dispatch(addLocalTrack(track));
|
||||
}
|
||||
|
||||
dispatch(setVideoMuted(true, MEDIA_TYPE.VIDEO, VIDEO_MUTISM_AUTHORITY.SCREEN_SHARE));
|
||||
|
||||
const { enabled: audioOnly } = state['features/base/audio-only'];
|
||||
|
||||
if (audioOnly) {
|
||||
dispatch(setAudioOnly(false));
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
} catch (error: any) {
|
||||
console.log('ERROR creating ScreeSharing stream ', error);
|
||||
|
||||
setPictureInPictureEnabled(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,9 +313,9 @@ export function isLocalTrackMuted(tracks: ITrack[], mediaType: MediaType) {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isLocalVideoTrackDesktop(state: IReduxState) {
|
||||
const videoTrack = getLocalVideoTrack(getTrackState(state));
|
||||
const desktopTrack = getLocalDesktopTrack(getTrackState(state));
|
||||
|
||||
return videoTrack && videoTrack.videoType === VIDEO_TYPE.DESKTOP;
|
||||
return desktopTrack !== undefined && !desktopTrack.muted;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ const useStyles = makeStyles()(theme => {
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'flex-start',
|
||||
zIndex: 301,
|
||||
animation: `${keyframes`
|
||||
0% {
|
||||
opacity: 0.4;
|
||||
|
||||
@@ -3,6 +3,10 @@ import React, { Component, ComponentType } from 'react';
|
||||
|
||||
import { IReduxState } from '../../../../app/types';
|
||||
import { IReactionEmojiProps } from '../../../../reactions/constants';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { JitsiPortal } from '../../../../toolbox/components/web';
|
||||
import { showOverflowDrawer } from '../../../../toolbox/functions.web';
|
||||
import { connect } from '../../../redux/functions';
|
||||
|
||||
import DialogTransition from './DialogTransition';
|
||||
@@ -24,6 +28,11 @@ interface IProps {
|
||||
*/
|
||||
_isNewDialog: boolean;
|
||||
|
||||
/**
|
||||
* Whether the overflow drawer should be used.
|
||||
*/
|
||||
_overflowDrawer: boolean;
|
||||
|
||||
/**
|
||||
* Array of reactions to be displayed.
|
||||
*/
|
||||
@@ -69,7 +78,9 @@ class DialogContainer extends Component<IProps> {
|
||||
render() {
|
||||
return this.props._isNewDialog ? (
|
||||
<DialogTransition>
|
||||
{this._renderDialogContent()}
|
||||
{this.props._overflowDrawer
|
||||
? <JitsiPortal>{this._renderDialogContent()}</JitsiPortal>
|
||||
: this._renderDialogContent() }
|
||||
</DialogTransition>
|
||||
) : (
|
||||
<ModalTransition>
|
||||
@@ -90,11 +101,13 @@ class DialogContainer extends Component<IProps> {
|
||||
function mapStateToProps(state: IReduxState) {
|
||||
const stateFeaturesBaseDialog = state['features/base/dialog'];
|
||||
const { reducedUI } = state['features/base/responsive-ui'];
|
||||
const overflowDrawer = showOverflowDrawer(state);
|
||||
|
||||
return {
|
||||
_component: stateFeaturesBaseDialog.component,
|
||||
_componentProps: stateFeaturesBaseDialog.componentProps,
|
||||
_isNewDialog: stateFeaturesBaseDialog.isNewDialog,
|
||||
_overflowDrawer: overflowDrawer,
|
||||
_reducedUI: reducedUI
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import { getLogger } from '../base/logging/functions';
|
||||
|
||||
export default getLogger('features/chrome-banner');
|
||||
@@ -189,6 +189,7 @@ class ConnectionIndicatorContent extends AbstractConnectionIndicator<Props, Stat
|
||||
codec = { codec }
|
||||
connectionSummary = { this._getConnectionStatusTip() }
|
||||
disableShowMoreStats = { this.props._disableShowMoreStats }
|
||||
e2eeVerified = { this.props._isE2EEVerified }
|
||||
enableSaveLogs = { this.props._enableSaveLogs }
|
||||
framerate = { framerate }
|
||||
isLocalVideo = { this.props._isLocalVideo }
|
||||
@@ -328,6 +329,7 @@ export function _mapStateToProps(state: Object, ownProps: Props) {
|
||||
_disableShowMoreStats: state['features/base/config'].disableShowMoreStats,
|
||||
_isConnectionStatusInactive,
|
||||
_isConnectionStatusInterrupted,
|
||||
_isE2EEVerified: participant?.e2eeVerified,
|
||||
_isVirtualScreenshareParticipant: isScreenShareParticipant(participant),
|
||||
_isLocalVideo: participant?.local,
|
||||
_region: participant?.region,
|
||||
|
||||
@@ -73,6 +73,11 @@ interface IProps extends WithTranslation {
|
||||
*/
|
||||
disableShowMoreStats: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not the participant was verified.
|
||||
*/
|
||||
e2eeVerified: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not should display the "Save Logs" link.
|
||||
*/
|
||||
@@ -486,6 +491,31 @@ class ConnectionStatsTable extends Component<IProps> {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a a table row as a ReactElement for displaying e2ee verication status, if present.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderE2EEVerified() {
|
||||
const { e2eeVerified, t } = this.props;
|
||||
|
||||
if (e2eeVerified === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const status = e2eeVerified ? '\u{2705}' : '\u{274C}';
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<span>{ t('connectionindicator.e2eeVerified') }</span>
|
||||
</td>
|
||||
<td>{ status }</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a table row as a ReactElement for displaying a summary message
|
||||
@@ -726,6 +756,7 @@ class ConnectionStatsTable extends Component<IProps> {
|
||||
{ this._renderResolution() }
|
||||
{ this._renderFrameRate() }
|
||||
{ this._renderCodecs() }
|
||||
{ this._renderE2EEVerified() }
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { openDialog } from '../base/dialog';
|
||||
import { openDialog } from '../base/dialog/actions';
|
||||
|
||||
// @ts-ignore
|
||||
import { DesktopPicker } from './components';
|
||||
|
||||
/**
|
||||
@@ -10,7 +11,7 @@ import { DesktopPicker } from './components';
|
||||
* a DesktopCapturerSource has been chosen.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function showDesktopPicker(options = {}, onSourceChoose) {
|
||||
export function showDesktopPicker(options: { desktopSharingSources?: any; } = {}, onSourceChoose: Function) {
|
||||
const { desktopSharingSources } = options;
|
||||
|
||||
return openDialog(DesktopPicker, {
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import logger from './logger';
|
||||
|
||||
/**
|
||||
@@ -11,8 +10,8 @@ import logger from './logger';
|
||||
* return native image object used for the preview image of the source.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function obtainDesktopSources(types, options = {}) {
|
||||
const capturerOptions = {
|
||||
export function obtainDesktopSources(types: string[], options: { thumbnailSize?: Object; } = {}) {
|
||||
const capturerOptions: any = {
|
||||
types
|
||||
};
|
||||
|
||||
@@ -23,10 +22,10 @@ export function obtainDesktopSources(types, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const { JitsiMeetElectron } = window;
|
||||
|
||||
if (JitsiMeetElectron && JitsiMeetElectron.obtainDesktopStreams) {
|
||||
if (JitsiMeetElectron?.obtainDesktopStreams) {
|
||||
JitsiMeetElectron.obtainDesktopStreams(
|
||||
sources => resolve(_separateSourcesByType(sources)),
|
||||
error => {
|
||||
(sources: Array<{ id: string; }>) => resolve(_separateSourcesByType(sources)),
|
||||
(error: Error) => {
|
||||
logger.error(
|
||||
`Error while obtaining desktop sources: ${error}`);
|
||||
reject(error);
|
||||
@@ -54,8 +53,8 @@ export function obtainDesktopSources(types, options = {}) {
|
||||
* @returns {Object} An object with the sources split into separate arrays based
|
||||
* on source type.
|
||||
*/
|
||||
function _separateSourcesByType(sources = []) {
|
||||
const sourcesByType = {
|
||||
function _separateSourcesByType(sources: Array<{ id: string; }> = []) {
|
||||
const sourcesByType: any = {
|
||||
screen: [],
|
||||
window: []
|
||||
};
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import { getLogger } from '../base/logging/functions';
|
||||
|
||||
export default getLogger('features/desktop-picker');
|
||||
@@ -32,10 +32,13 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
inviteDomain
|
||||
};
|
||||
|
||||
// TODO: implement support for gradients.
|
||||
action.value.avatarBackgrounds = avatarBackgrounds.filter(
|
||||
(color: string) => !color.includes('linear-gradient')
|
||||
);
|
||||
// The backend may send an empty string, make sure we skip that.
|
||||
if (Array.isArray(avatarBackgrounds)) {
|
||||
// TODO: implement support for gradients.
|
||||
action.value.avatarBackgrounds = avatarBackgrounds.filter(
|
||||
(color: string) => !color.includes('linear-gradient')
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -156,6 +156,7 @@ export interface IDynamicBrandingState {
|
||||
logoImageUrl: string;
|
||||
muiBrandedTheme?: boolean;
|
||||
premeetingBackground: string;
|
||||
showGiphyIntegration?: boolean;
|
||||
useDynamicBrandingData: boolean;
|
||||
virtualBackgrounds: Array<Image>;
|
||||
}
|
||||
@@ -178,6 +179,7 @@ ReducerRegistry.register<IDynamicBrandingState>(STORE_NAME, (state = DEFAULT_STA
|
||||
logoImageUrl,
|
||||
muiBrandedTheme,
|
||||
premeetingBackground,
|
||||
showGiphyIntegration,
|
||||
virtualBackgrounds
|
||||
} = action.value;
|
||||
|
||||
@@ -193,6 +195,7 @@ ReducerRegistry.register<IDynamicBrandingState>(STORE_NAME, (state = DEFAULT_STA
|
||||
logoImageUrl,
|
||||
muiBrandedTheme,
|
||||
premeetingBackground,
|
||||
showGiphyIntegration,
|
||||
customizationFailed: false,
|
||||
customizationReady: true,
|
||||
useDynamicBrandingData: true,
|
||||
|
||||
@@ -43,3 +43,7 @@ export const SET_MAX_MODE = 'SET_MAX_MODE';
|
||||
* }
|
||||
*/
|
||||
export const SET_MEDIA_ENCRYPTION_KEY = 'SET_MEDIA_ENCRYPTION_KEY';
|
||||
|
||||
export const START_VERIFICATION = 'START_VERIFICATION';
|
||||
|
||||
export const PARTICIPANT_VERIFIED = 'PARTICIPANT_VERIFIED';
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import {
|
||||
PARTICIPANT_VERIFIED,
|
||||
SET_EVERYONE_ENABLED_E2EE,
|
||||
SET_EVERYONE_SUPPORT_E2EE,
|
||||
SET_MAX_MODE,
|
||||
SET_MEDIA_ENCRYPTION_KEY,
|
||||
START_VERIFICATION,
|
||||
TOGGLE_E2EE } from './actionTypes';
|
||||
|
||||
/**
|
||||
@@ -80,3 +82,38 @@ export function setMediaEncryptionKey(keyInfo: Object) {
|
||||
keyInfo
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an action to start participant e2ee verficiation process.
|
||||
*
|
||||
* @param {string} pId - The participant id.
|
||||
* @returns {{
|
||||
* type: START_VERIFICATION,
|
||||
* pId: string
|
||||
* }}
|
||||
*/
|
||||
export function startVerification(pId: string) {
|
||||
return {
|
||||
type: START_VERIFICATION,
|
||||
pId
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an action to set participant e2ee verification status.
|
||||
*
|
||||
* @param {string} pId - The participant id.
|
||||
* @param {boolean} isVerified - The verifcation status.
|
||||
* @returns {{
|
||||
* type: PARTICIPANT_VERIFIED,
|
||||
* pId: string,
|
||||
* isVerified: boolean
|
||||
* }}
|
||||
*/
|
||||
export function participantVerified(pId: string, isVerified: boolean) {
|
||||
return {
|
||||
type: PARTICIPANT_VERIFIED,
|
||||
pId,
|
||||
isVerified
|
||||
};
|
||||
}
|
||||
|
||||
166
react/features/e2ee/components/ParticipantVerificationDialog.tsx
Normal file
@@ -0,0 +1,166 @@
|
||||
import { withStyles } from '@mui/styles';
|
||||
import React, { Component } from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
|
||||
import { IReduxState, IStore } from '../../app/types';
|
||||
import { translate } from '../../base/i18n/functions';
|
||||
import { getParticipantById } from '../../base/participants/functions';
|
||||
import { connect } from '../../base/redux/functions';
|
||||
import Dialog from '../../base/ui/components/web/Dialog';
|
||||
import { participantVerified } from '../actions';
|
||||
import { ISas } from '../reducer';
|
||||
|
||||
interface IProps extends WithTranslation {
|
||||
classes: any;
|
||||
decimal: string;
|
||||
dispatch: IStore['dispatch'];
|
||||
emoji: string;
|
||||
pId: string;
|
||||
participantName: string;
|
||||
sas: ISas;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the styles for the component.
|
||||
*
|
||||
* @param {Object} theme - The current UI theme.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
const styles = () => {
|
||||
return {
|
||||
container: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
margin: '16px'
|
||||
},
|
||||
row: {
|
||||
alignSelf: 'center',
|
||||
display: 'flex'
|
||||
},
|
||||
item: {
|
||||
textAlign: 'center',
|
||||
margin: '16px'
|
||||
},
|
||||
emoji: {
|
||||
fontSize: '40px',
|
||||
margin: '12px'
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class for the dialog displayed for E2EE sas verification.
|
||||
*/
|
||||
export class ParticipantVerificationDialog extends Component<IProps> {
|
||||
/**
|
||||
* Instantiates a new instance.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this._onConfirmed = this._onConfirmed.bind(this);
|
||||
this._onDismissed = this._onDismissed.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { emoji } = this.props.sas;
|
||||
const { participantName } = this.props;
|
||||
|
||||
const { classes, t } = this.props;
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
cancel = {{ translationKey: 'dialog.verifyParticipantDismiss' }}
|
||||
ok = {{ translationKey: 'dialog.verifyParticipantConfirm' }}
|
||||
onCancel = { this._onDismissed }
|
||||
onSubmit = { this._onConfirmed }
|
||||
titleKey = 'dialog.verifyParticipantTitle'>
|
||||
<div>
|
||||
{ t('dialog.verifyParticipantQuestion', { participantName }) }
|
||||
</div>
|
||||
|
||||
<div className = { classes.container }>
|
||||
<div className = { classes.row }>
|
||||
{/* @ts-ignore */}
|
||||
{emoji.slice(0, 4).map((e: Array<string>) =>
|
||||
(<div
|
||||
className = { classes.item }
|
||||
key = { e.toString() }>
|
||||
<div className = { classes.emoji }>{ e[0] }</div>
|
||||
<div>{ e[1].charAt(0).toUpperCase() + e[1].slice(1) }</div>
|
||||
</div>))}
|
||||
</div>
|
||||
|
||||
<div className = { classes.row }>
|
||||
{/* @ts-ignore */}
|
||||
{emoji.slice(4, 7).map((e: Array<string>) =>
|
||||
(<div
|
||||
className = { classes.item }
|
||||
key = { e.toString() }>
|
||||
<div className = { classes.emoji }>{ e[0] } </div>
|
||||
<div>{ e[1].charAt(0).toUpperCase() + e[1].slice(1) }</div>
|
||||
</div>))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies this ParticipantVerificationDialog that it has been dismissed by cancel.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onDismissed() {
|
||||
this.props.dispatch(participantVerified(this.props.pId, false));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies this ParticipantVerificationDialog that it has been dismissed with confirmation.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onConfirmed() {
|
||||
this.props.dispatch(participantVerified(this.props.pId, true));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps part of the Redux store to the props of this component.
|
||||
*
|
||||
* @param {IReduxState} state - The Redux state.
|
||||
* @param {IProps} ownProps - The own props of the component.
|
||||
* @returns {IProps}
|
||||
*/
|
||||
export function _mapStateToProps(state: IReduxState, ownProps: IProps) {
|
||||
const participant = getParticipantById(state, ownProps.pId);
|
||||
|
||||
return {
|
||||
sas: ownProps.sas,
|
||||
pId: ownProps.pId,
|
||||
participantName: participant?.name
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(
|
||||
|
||||
// @ts-ignore
|
||||
withStyles(styles)(ParticipantVerificationDialog)));
|
||||
@@ -1,7 +1,9 @@
|
||||
import { IReduxState } from '../app/types';
|
||||
import { IStateful } from '../base/app/types';
|
||||
import { getParticipantCount } from '../base/participants/functions';
|
||||
import { getParticipantById, getParticipantCount } from '../base/participants/functions';
|
||||
import { toState } from '../base/redux/functions';
|
||||
|
||||
|
||||
import { MAX_MODE_LIMIT, MAX_MODE_THRESHOLD } from './constants';
|
||||
|
||||
/**
|
||||
@@ -55,3 +57,19 @@ export function isMaxModeThresholdReached(stateful: IStateful) {
|
||||
|
||||
return participantCount >= MAX_MODE_LIMIT + MAX_MODE_THRESHOLD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether e2ee is enabled by the backend.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @param {string} pId - The participant id.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function displayVerification(state: IReduxState, pId: string) {
|
||||
const { conference } = state['features/base/conference'];
|
||||
const participant = getParticipantById(state, pId);
|
||||
|
||||
return Boolean(conference?.isE2EEEnabled()
|
||||
&& participant?.e2eeVerificationAvailable
|
||||
&& participant?.e2eeVerified === undefined);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import { IStore } from '../app/types';
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes';
|
||||
import { CONFERENCE_JOINED } from '../base/conference/actionTypes';
|
||||
import { getCurrentConference } from '../base/conference/functions';
|
||||
import { openDialog } from '../base/dialog/actions';
|
||||
import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
|
||||
import { PARTICIPANT_JOINED, PARTICIPANT_LEFT, PARTICIPANT_UPDATED } from '../base/participants/actionTypes';
|
||||
import { participantUpdated } from '../base/participants/actions';
|
||||
import {
|
||||
@@ -17,13 +19,15 @@ import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import StateListenerRegistry from '../base/redux/StateListenerRegistry';
|
||||
import { playSound, registerSound, unregisterSound } from '../base/sounds/actions';
|
||||
|
||||
import { SET_MEDIA_ENCRYPTION_KEY, TOGGLE_E2EE } from './actionTypes';
|
||||
import { PARTICIPANT_VERIFIED, SET_MEDIA_ENCRYPTION_KEY, START_VERIFICATION, TOGGLE_E2EE } from './actionTypes';
|
||||
import { setE2EEMaxMode, setEveryoneEnabledE2EE, setEveryoneSupportE2EE, toggleE2EE } from './actions';
|
||||
import ParticipantVerificationDialog from './components/ParticipantVerificationDialog';
|
||||
import { E2EE_OFF_SOUND_ID, E2EE_ON_SOUND_ID, MAX_MODE } from './constants';
|
||||
import { isMaxModeReached, isMaxModeThresholdReached } from './functions';
|
||||
import logger from './logger';
|
||||
import { E2EE_OFF_SOUND_FILE, E2EE_ON_SOUND_FILE } from './sounds';
|
||||
|
||||
|
||||
/**
|
||||
* Middleware that captures actions related to E2EE.
|
||||
*
|
||||
@@ -239,6 +243,18 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PARTICIPANT_VERIFIED: {
|
||||
const { isVerified, pId } = action;
|
||||
|
||||
conference?.markParticipantVerified(pId, isVerified);
|
||||
break;
|
||||
}
|
||||
|
||||
case START_VERIFICATION: {
|
||||
conference?.startVerification(action.pId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return next(action);
|
||||
@@ -254,6 +270,31 @@ StateListenerRegistry.register(
|
||||
if (previousConference) {
|
||||
dispatch(toggleE2EE(false));
|
||||
}
|
||||
|
||||
if (conference) {
|
||||
conference.on(JitsiConferenceEvents.E2EE_VERIFICATION_AVAILABLE, (pId: string) => {
|
||||
dispatch(participantUpdated({
|
||||
e2eeVerificationAvailable: true,
|
||||
id: pId
|
||||
}));
|
||||
});
|
||||
|
||||
conference.on(JitsiConferenceEvents.E2EE_VERIFICATION_READY, (pId: string, sas: object) => {
|
||||
dispatch(openDialog(ParticipantVerificationDialog, { pId,
|
||||
sas }));
|
||||
});
|
||||
|
||||
conference.on(JitsiConferenceEvents.E2EE_VERIFICATION_COMPLETED,
|
||||
(pId: string, success: boolean, message: string) => {
|
||||
if (message) {
|
||||
logger.warn('E2EE_VERIFICATION_COMPLETED warning', message);
|
||||
}
|
||||
dispatch(participantUpdated({
|
||||
e2eeVerified: success,
|
||||
id: pId
|
||||
}));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,6 +20,10 @@ export interface IE2EEState {
|
||||
maxMode: string;
|
||||
}
|
||||
|
||||
export interface ISas {
|
||||
emoji: Array<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces the Redux actions of the feature features/e2ee.
|
||||
*/
|
||||
|
||||
@@ -68,12 +68,13 @@ export function getGifAPIKey(state: IReduxState) {
|
||||
export function isGifEnabled(state: IReduxState) {
|
||||
const { disableThirdPartyRequests } = state['features/base/config'];
|
||||
const { giphy } = state['features/base/config'];
|
||||
const showGiphyIntegration = state['features/dynamic-branding']?.showGiphyIntegration !== false;
|
||||
|
||||
if (navigator.product === 'ReactNative' && window.JITSI_MEET_LITE_SDK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Boolean(!disableThirdPartyRequests && giphy?.enabled && Boolean(giphy?.sdkKey));
|
||||
return showGiphyIntegration && Boolean(!disableThirdPartyRequests && giphy?.enabled && Boolean(giphy?.sdkKey));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
// @flow
|
||||
|
||||
/**
|
||||
* Utility class with no dependencies. Used in components that are stripped in separate bundles
|
||||
* and requires as less dependencies as possible.
|
||||
*/
|
||||
|
||||
import { getURLWithoutParams } from '../base/connection/utils';
|
||||
import { doGetJSON } from '../base/util';
|
||||
import { doGetJSON } from '../base/util/httpUtils';
|
||||
|
||||
/**
|
||||
* Formats the conference pin in readable way for UI to display it.
|
||||
@@ -49,7 +47,7 @@ export function getDialInConferenceID(
|
||||
roomName: string,
|
||||
mucURL: string,
|
||||
url: URL
|
||||
): Promise<Object> {
|
||||
): Promise<any> {
|
||||
const separator = baseUrl.includes('?') ? '&' : '?';
|
||||
const conferenceIDURL
|
||||
= `${baseUrl}${separator}conference=${roomName}@${mucURL}&url=${getURLWithoutParams(url).href}`;
|
||||
@@ -75,7 +73,7 @@ export function getDialInNumbers(
|
||||
url: string,
|
||||
roomName: string,
|
||||
mucURL: string
|
||||
): Promise<*> {
|
||||
): Promise<any> {
|
||||
const separator = url.includes('?') ? '&' : '?';
|
||||
|
||||
// when roomName and mucURL are available
|
||||
@@ -1,10 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { getInviteURL } from '../base/connection';
|
||||
import { getLocalParticipant, getParticipantCount } from '../base/participants';
|
||||
import { inviteVideoRooms } from '../videosipgw';
|
||||
import { IStore } from '../app/types';
|
||||
import { getInviteURL } from '../base/connection/functions';
|
||||
import { getLocalParticipant, getParticipantCount } from '../base/participants/functions';
|
||||
import { inviteVideoRooms } from '../videosipgw/actions';
|
||||
|
||||
import { getDialInConferenceID, getDialInNumbers } from './_utils';
|
||||
import {
|
||||
@@ -22,6 +19,7 @@ import {
|
||||
inviteSipEndpoints
|
||||
} from './functions';
|
||||
import logger from './logger';
|
||||
import { IInvitee } from './types';
|
||||
|
||||
/**
|
||||
* Creates a (redux) action to signal that a click/tap has been performed on
|
||||
@@ -64,11 +62,11 @@ export function hideAddPeopleDialog() {
|
||||
* of invitees who were not invited (i.e. Invites were not sent to them).
|
||||
*/
|
||||
export function invite(
|
||||
invitees: Array<Object>,
|
||||
showCalleeInfo: boolean = false) {
|
||||
invitees: IInvitee[],
|
||||
showCalleeInfo = false) {
|
||||
return (
|
||||
dispatch: Dispatch<any>,
|
||||
getState: Function): Promise<Array<Object>> => {
|
||||
dispatch: IStore['dispatch'],
|
||||
getState: IStore['getState']): Promise<Array<Object>> => {
|
||||
const state = getState();
|
||||
const participantsCount = getParticipantCount(state);
|
||||
const { calleeInfoVisible } = state['features/invite'];
|
||||
@@ -89,12 +87,12 @@ export function invite(
|
||||
return new Promise(resolve => {
|
||||
dispatch(addPendingInviteRequest({
|
||||
invitees,
|
||||
callback: failedInvitees => resolve(failedInvitees)
|
||||
callback: (failedInvitees: any) => resolve(failedInvitees)
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
let allInvitePromises = [];
|
||||
let allInvitePromises: Promise<any>[] = [];
|
||||
let invitesLeftToSend = [ ...invitees ];
|
||||
|
||||
const {
|
||||
@@ -105,8 +103,8 @@ export function invite(
|
||||
const inviteUrl = getInviteURL(state);
|
||||
const { sipInviteUrl } = state['features/base/config'];
|
||||
const { locationURL } = state['features/base/connection'];
|
||||
const { jwt } = state['features/base/jwt'];
|
||||
const { name: displayName } = getLocalParticipant(state);
|
||||
const { jwt = '' } = state['features/base/jwt'];
|
||||
const { name: displayName } = getLocalParticipant(state) ?? {};
|
||||
|
||||
// First create all promises for dialing out.
|
||||
const phoneNumbers
|
||||
@@ -123,7 +121,7 @@ export function invite(
|
||||
= invitesLeftToSend.filter(
|
||||
invitee => invitee !== item);
|
||||
})
|
||||
.catch(error =>
|
||||
.catch((error: Error) =>
|
||||
logger.error('Error inviting phone number:', error));
|
||||
});
|
||||
|
||||
@@ -138,8 +136,8 @@ export function invite(
|
||||
// filter all rooms and users from {@link invitesLeftToSend}.
|
||||
const peopleInvitePromise
|
||||
= invitePeopleAndChatRooms(
|
||||
callFlowsEnabled
|
||||
? inviteServiceCallFlowsUrl : inviteServiceUrl,
|
||||
(callFlowsEnabled
|
||||
? inviteServiceCallFlowsUrl : inviteServiceUrl) ?? '',
|
||||
inviteUrl,
|
||||
jwt,
|
||||
usersAndRooms)
|
||||
@@ -173,6 +171,8 @@ export function invite(
|
||||
|
||||
conference && inviteSipEndpoints(
|
||||
sipEndpoints,
|
||||
|
||||
// @ts-ignore
|
||||
locationURL,
|
||||
sipInviteUrl,
|
||||
jwt,
|
||||
@@ -196,12 +196,12 @@ export function invite(
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function updateDialInNumbers() {
|
||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
const { dialInConfCodeUrl, dialInNumbersUrl, hosts }
|
||||
= state['features/base/config'];
|
||||
const { numbersFetched } = state['features/invite'];
|
||||
const mucURL = hosts && hosts.muc;
|
||||
const mucURL = hosts?.muc;
|
||||
|
||||
if (numbersFetched || !dialInConfCodeUrl || !dialInNumbersUrl || !mucURL) {
|
||||
// URLs for fetching dial in numbers not defined
|
||||
@@ -209,10 +209,10 @@ export function updateDialInNumbers() {
|
||||
}
|
||||
|
||||
const { locationURL = {} } = state['features/base/connection'];
|
||||
const { room } = state['features/base/conference'];
|
||||
const { room = '' } = state['features/base/conference'];
|
||||
|
||||
Promise.all([
|
||||
getDialInNumbers(dialInNumbersUrl, room, mucURL),
|
||||
getDialInNumbers(dialInNumbersUrl, room, mucURL), // @ts-ignore
|
||||
getDialInConferenceID(dialInConfCodeUrl, room, mucURL, locationURL)
|
||||
])
|
||||
.then(([ dialInNumbers, { conference, id, message, sipUri } ]) => {
|
||||
@@ -251,7 +251,7 @@ export function updateDialInNumbers() {
|
||||
*/
|
||||
export function setCalleeInfoVisible(
|
||||
calleeInfoVisible: boolean,
|
||||
initialCalleeInfo: ?Object) {
|
||||
initialCalleeInfo?: Object) {
|
||||
return {
|
||||
type: SET_CALLEE_INFO_VISIBLE,
|
||||
calleeInfoVisible,
|
||||
@@ -269,7 +269,7 @@ export function setCalleeInfoVisible(
|
||||
* }}
|
||||
*/
|
||||
export function addPendingInviteRequest(
|
||||
request: { invitees: Array<Object>, callback: Function }) {
|
||||
request: { callback: Function; invitees: Array<Object>; }) {
|
||||
return {
|
||||
type: ADD_PENDING_INVITE_REQUEST,
|
||||
request
|
||||
@@ -1,11 +1,13 @@
|
||||
// @flow
|
||||
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { ADD_PEOPLE_ENABLED, getFeatureFlag } from '../base/flags';
|
||||
/* eslint-disable lines-around-comment */
|
||||
import { IStore } from '../app/types';
|
||||
import { ADD_PEOPLE_ENABLED } from '../base/flags/constants';
|
||||
import { getFeatureFlag } from '../base/flags/functions';
|
||||
// @ts-ignore
|
||||
import { navigate } from '../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
// @ts-ignore
|
||||
import { screen } from '../mobile/navigation/routes';
|
||||
import { beginShareRoom } from '../share-room';
|
||||
import { beginShareRoom } from '../share-room/actions';
|
||||
/* eslint-enable lines-around-comment */
|
||||
|
||||
import { isAddPeopleEnabled, isDialOutEnabled } from './functions';
|
||||
|
||||
@@ -18,7 +20,7 @@ export * from './actions.any';
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function doInvitePeople() {
|
||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
const addPeopleEnabled = getFeatureFlag(state, ADD_PEOPLE_ENABLED, true)
|
||||
&& (isAddPeopleEnabled(state) || isDialOutEnabled(state));
|
||||
@@ -205,7 +205,7 @@ function mapStateToProps(state: IReduxState, ownProps: Partial<IProps>) {
|
||||
const addPeopleEnabled = isAddPeopleEnabled(state);
|
||||
const dialOutEnabled = isDialOutEnabled(state);
|
||||
const hideInviteContacts = iAmRecorder || (!addPeopleEnabled && !dialOutEnabled);
|
||||
const dialIn = state['features/invite'];
|
||||
const dialIn = state['features/invite']; // @ts-ignore
|
||||
const phoneNumber = dialIn?.numbers ? _getDefaultPhoneNumber(dialIn.numbers) : undefined;
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
// @flow
|
||||
|
||||
import { getActiveSession } from '../../features/recording/functions';
|
||||
import { getRoomName } from '../base/conference';
|
||||
import { getInviteURL } from '../base/connection';
|
||||
import { IReduxState } from '../app/types';
|
||||
import { IStateful } from '../base/app/types';
|
||||
import { getRoomName } from '../base/conference/functions';
|
||||
import { getInviteURL } from '../base/connection/functions';
|
||||
import { isIosMobileBrowser } from '../base/environment/utils';
|
||||
import { i18next } from '../base/i18n';
|
||||
import i18next from '../base/i18n/i18next';
|
||||
import { isJwtFeatureEnabled } from '../base/jwt/functions';
|
||||
import { JitsiRecordingConstants } from '../base/lib-jitsi-meet';
|
||||
import { getLocalParticipant, isLocalParticipantModerator } from '../base/participants';
|
||||
import { toState } from '../base/redux';
|
||||
import {
|
||||
appendURLParam,
|
||||
parseURIString,
|
||||
parseURLParams
|
||||
} from '../base/util';
|
||||
import { getLocalParticipant, isLocalParticipantModerator } from '../base/participants/functions';
|
||||
import { toState } from '../base/redux/functions';
|
||||
import { parseURLParams } from '../base/util/parseURLParams';
|
||||
import { appendURLParam, parseURIString } from '../base/util/uri';
|
||||
import { isVpaasMeeting } from '../jaas/functions';
|
||||
import { getActiveSession } from '../recording/functions';
|
||||
|
||||
import { getDialInConferenceID, getDialInNumbers } from './_utils';
|
||||
import {
|
||||
@@ -24,8 +21,7 @@ import {
|
||||
} from './constants';
|
||||
import logger from './logger';
|
||||
|
||||
declare var $: Function;
|
||||
declare var interfaceConfig: Object;
|
||||
declare let $: any;
|
||||
|
||||
export const sharingFeatures = {
|
||||
email: 'email',
|
||||
@@ -44,7 +40,7 @@ export const sharingFeatures = {
|
||||
export function checkDialNumber(
|
||||
dialNumber: string,
|
||||
dialOutAuthUrl: string
|
||||
): Promise<Object> {
|
||||
): Promise<{ allow?: boolean; country?: string; phone?: string; }> {
|
||||
const fullUrl = `${dialOutAuthUrl}?phone=${dialNumber}`;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -61,7 +57,7 @@ export function checkDialNumber(
|
||||
* numbers.
|
||||
* @returns {string} A string with only numbers.
|
||||
*/
|
||||
export function getDigitsOnly(text: string = ''): string {
|
||||
export function getDigitsOnly(text = ''): string {
|
||||
return text.replace(/\D/g, '');
|
||||
}
|
||||
|
||||
@@ -70,41 +66,41 @@ export function getDigitsOnly(text: string = ''): string {
|
||||
*/
|
||||
export type GetInviteResultsOptions = {
|
||||
|
||||
/**
|
||||
* The endpoint to use for checking phone number validity.
|
||||
*/
|
||||
dialOutAuthUrl: string,
|
||||
|
||||
/**
|
||||
* Whether or not to search for people.
|
||||
*/
|
||||
addPeopleEnabled: boolean,
|
||||
addPeopleEnabled: boolean;
|
||||
|
||||
/**
|
||||
* The endpoint to use for checking phone number validity.
|
||||
*/
|
||||
dialOutAuthUrl: string;
|
||||
|
||||
/**
|
||||
* Whether or not to check phone numbers.
|
||||
*/
|
||||
dialOutEnabled: boolean,
|
||||
dialOutEnabled: boolean;
|
||||
|
||||
/**
|
||||
* The jwt token to pass to the search service.
|
||||
*/
|
||||
jwt: string;
|
||||
|
||||
/**
|
||||
* Array with the query types that will be executed -
|
||||
* "conferenceRooms" | "user" | "room".
|
||||
*/
|
||||
peopleSearchQueryTypes: Array<string>,
|
||||
peopleSearchQueryTypes: Array<string>;
|
||||
|
||||
/**
|
||||
* The url to query for people.
|
||||
*/
|
||||
peopleSearchUrl: string,
|
||||
peopleSearchUrl: string;
|
||||
|
||||
/**
|
||||
* Whether or not to check sip invites.
|
||||
*/
|
||||
sipInviteEnabled: boolean,
|
||||
|
||||
/**
|
||||
* The jwt token to pass to the search service.
|
||||
*/
|
||||
jwt: string
|
||||
sipInviteEnabled: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -118,8 +114,7 @@ export type GetInviteResultsOptions = {
|
||||
export function getInviteResultsForQuery(
|
||||
query: string,
|
||||
options: GetInviteResultsOptions
|
||||
): Promise<*> {
|
||||
|
||||
): Promise<any> {
|
||||
const text = query.trim();
|
||||
|
||||
const {
|
||||
@@ -183,12 +178,12 @@ export function getInviteResultsForQuery(
|
||||
phone: text
|
||||
});
|
||||
} else {
|
||||
phoneNumberPromise = Promise.resolve({});
|
||||
phoneNumberPromise = Promise.resolve<{ allow?: boolean; country?: string; phone?: string; }>({});
|
||||
}
|
||||
|
||||
return Promise.all([ peopleSearchPromise, phoneNumberPromise ])
|
||||
.then(([ peopleResults, phoneResults ]) => {
|
||||
const results = [
|
||||
const results: any[] = [
|
||||
...peopleResults
|
||||
];
|
||||
|
||||
@@ -233,7 +228,7 @@ export function getInviteTextiOS({
|
||||
state,
|
||||
phoneNumber,
|
||||
t
|
||||
}: Object) {
|
||||
}: { phoneNumber?: string | null; state: IReduxState; t?: Function; }) {
|
||||
if (!isIosMobileBrowser()) {
|
||||
return '';
|
||||
}
|
||||
@@ -246,23 +241,23 @@ export function getInviteTextiOS({
|
||||
const inviteURL = _decodeRoomURI(inviteUrl);
|
||||
|
||||
let invite = localParticipantName
|
||||
? t('info.inviteTextiOSPersonal', { name: localParticipantName })
|
||||
: t('info.inviteURLFirstPartGeneral');
|
||||
? t?.('info.inviteTextiOSPersonal', { name: localParticipantName })
|
||||
: t?.('info.inviteURLFirstPartGeneral');
|
||||
|
||||
invite += ' ';
|
||||
|
||||
invite += t('info.inviteTextiOSInviteUrl', { inviteUrl });
|
||||
invite += t?.('info.inviteTextiOSInviteUrl', { inviteUrl });
|
||||
invite += ' ';
|
||||
|
||||
if (shouldDisplayDialIn(dialIn) && isSharingEnabled(sharingFeatures.dialIn)) {
|
||||
invite += t('info.inviteTextiOSPhone', {
|
||||
invite += t?.('info.inviteTextiOSPhone', {
|
||||
number: phoneNumber,
|
||||
conferenceID: dialIn.conferenceID,
|
||||
didUrl: getDialInfoPageURL(state)
|
||||
});
|
||||
}
|
||||
invite += ' ';
|
||||
invite += t('info.inviteTextiOSJoinSilent', { silentUrl: `${inviteURL}#config.startSilent=true` });
|
||||
invite += t?.('info.inviteTextiOSJoinSilent', { silentUrl: `${inviteURL}#config.startSilent=true` });
|
||||
|
||||
return invite;
|
||||
}
|
||||
@@ -276,27 +271,25 @@ export function getInviteText({
|
||||
state,
|
||||
phoneNumber,
|
||||
t
|
||||
}: Object) {
|
||||
}: { phoneNumber?: string | null; state: IReduxState; t?: Function; }) {
|
||||
const dialIn = state['features/invite'];
|
||||
const inviteUrl = getInviteURL(state);
|
||||
const currentLiveStreamingSession = getActiveSession(state, JitsiRecordingConstants.mode.STREAM);
|
||||
const liveStreamViewURL
|
||||
= currentLiveStreamingSession
|
||||
&& currentLiveStreamingSession.liveStreamViewURL;
|
||||
const liveStreamViewURL = currentLiveStreamingSession?.liveStreamViewURL;
|
||||
const localParticipant = getLocalParticipant(state);
|
||||
const localParticipantName = localParticipant?.name;
|
||||
|
||||
const inviteURL = _decodeRoomURI(inviteUrl);
|
||||
let invite = localParticipantName
|
||||
? t('info.inviteURLFirstPartPersonal', { name: localParticipantName })
|
||||
: t('info.inviteURLFirstPartGeneral');
|
||||
? t?.('info.inviteURLFirstPartPersonal', { name: localParticipantName })
|
||||
: t?.('info.inviteURLFirstPartGeneral');
|
||||
|
||||
invite += t('info.inviteURLSecondPart', {
|
||||
invite += t?.('info.inviteURLSecondPart', {
|
||||
url: inviteURL
|
||||
});
|
||||
|
||||
if (liveStreamViewURL) {
|
||||
const liveStream = t('info.inviteLiveStream', {
|
||||
const liveStream = t?.('info.inviteLiveStream', {
|
||||
url: liveStreamViewURL
|
||||
});
|
||||
|
||||
@@ -304,11 +297,11 @@ export function getInviteText({
|
||||
}
|
||||
|
||||
if (shouldDisplayDialIn(dialIn) && isSharingEnabled(sharingFeatures.dialIn)) {
|
||||
const dial = t('info.invitePhone', {
|
||||
const dial = t?.('info.invitePhone', {
|
||||
number: phoneNumber,
|
||||
conferenceID: dialIn.conferenceID
|
||||
});
|
||||
const moreNumbers = t('info.invitePhoneAlternatives', {
|
||||
const moreNumbers = t?.('info.invitePhoneAlternatives', {
|
||||
url: getDialInfoPageURL(state),
|
||||
silentUrl: `${inviteURL}#config.startSilent=true`
|
||||
});
|
||||
@@ -328,8 +321,8 @@ export function getInviteText({
|
||||
* @returns {Object} An object with keys as user types and values as the number
|
||||
* of invites for that type.
|
||||
*/
|
||||
export function getInviteTypeCounts(inviteItems: Array<Object> = []) {
|
||||
const inviteTypeCounts = {};
|
||||
export function getInviteTypeCounts(inviteItems: Array<{ type: string; }> = []) {
|
||||
const inviteTypeCounts: any = {};
|
||||
|
||||
inviteItems.forEach(({ type }) => {
|
||||
if (!inviteTypeCounts[type]) {
|
||||
@@ -352,51 +345,51 @@ export function getInviteTypeCounts(inviteItems: Array<Object> = []) {
|
||||
* items to invite.
|
||||
* @returns {Promise} - The promise created by the request.
|
||||
*/
|
||||
export function invitePeopleAndChatRooms( // eslint-disable-line max-params
|
||||
export function invitePeopleAndChatRooms(
|
||||
inviteServiceUrl: string,
|
||||
inviteUrl: string,
|
||||
jwt: string,
|
||||
inviteItems: Array<Object>
|
||||
): Promise<void> {
|
||||
): Promise<any> {
|
||||
|
||||
if (!inviteItems || inviteItems.length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return fetch(
|
||||
`${inviteServiceUrl}?token=${jwt}`,
|
||||
{
|
||||
body: JSON.stringify({
|
||||
'invited': inviteItems,
|
||||
'url': inviteUrl
|
||||
}),
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
`${inviteServiceUrl}?token=${jwt}`,
|
||||
{
|
||||
body: JSON.stringify({
|
||||
'invited': inviteItems,
|
||||
'url': inviteUrl
|
||||
}),
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if adding people is currently enabled.
|
||||
*
|
||||
* @param {boolean} state - Current state.
|
||||
* @param {IReduxState} state - Current state.
|
||||
* @returns {boolean} Indication of whether adding people is currently enabled.
|
||||
*/
|
||||
export function isAddPeopleEnabled(state: Object): boolean {
|
||||
export function isAddPeopleEnabled(state: IReduxState): boolean {
|
||||
const { peopleSearchUrl } = state['features/base/config'];
|
||||
|
||||
return state['features/base/jwt'].jwt && Boolean(peopleSearchUrl) && !isVpaasMeeting(state);
|
||||
return Boolean(state['features/base/jwt'].jwt && Boolean(peopleSearchUrl) && !isVpaasMeeting(state));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if dial out is currently enabled or not.
|
||||
*
|
||||
* @param {boolean} state - Current state.
|
||||
* @param {IReduxState} state - Current state.
|
||||
* @returns {boolean} Indication of whether dial out is currently enabled.
|
||||
*/
|
||||
export function isDialOutEnabled(state: Object): boolean {
|
||||
export function isDialOutEnabled(state: IReduxState): boolean {
|
||||
const { conference } = state['features/base/conference'];
|
||||
|
||||
return isLocalParticipantModerator(state)
|
||||
@@ -406,10 +399,10 @@ export function isDialOutEnabled(state: Object): boolean {
|
||||
/**
|
||||
* Determines if inviting sip endpoints is enabled or not.
|
||||
*
|
||||
* @param {Object} state - Current state.
|
||||
* @param {IReduxState} state - Current state.
|
||||
* @returns {boolean} Indication of whether dial out is currently enabled.
|
||||
*/
|
||||
export function isSipInviteEnabled(state: Object): boolean {
|
||||
export function isSipInviteEnabled(state: IReduxState): boolean {
|
||||
const { sipInviteUrl } = state['features/base/config'];
|
||||
|
||||
return isJwtFeatureEnabled(state, 'sip-outbound-call') && Boolean(sipInviteUrl);
|
||||
@@ -473,7 +466,7 @@ export function searchDirectory( // eslint-disable-line max-params
|
||||
jwt: string,
|
||||
text: string,
|
||||
queryTypes: Array<string> = [ 'conferenceRooms', 'user', 'room' ]
|
||||
): Promise<Array<Object>> {
|
||||
): Promise<Array<{ type: string; }>> {
|
||||
|
||||
const query = encodeURIComponent(text);
|
||||
const queryTypesString = encodeURIComponent(JSON.stringify(queryTypes));
|
||||
@@ -502,14 +495,13 @@ export function searchDirectory( // eslint-disable-line max-params
|
||||
* Returns descriptive text that can be used to invite participants to a meeting
|
||||
* (share via mobile or use it for calendar event description).
|
||||
*
|
||||
* @param {Object} state - The current state.
|
||||
* @param {IReduxState} state - The current state.
|
||||
* @param {string} inviteUrl - The conference/location URL.
|
||||
* @param {boolean} useHtml - Whether to return html text.
|
||||
* @returns {Promise<string>} A {@code Promise} resolving with a
|
||||
* descriptive text that can be used to invite participants to a meeting.
|
||||
*/
|
||||
export function getShareInfoText(
|
||||
state: Object, inviteUrl: string, useHtml: ?boolean): Promise<string> {
|
||||
export function getShareInfoText(state: IReduxState, inviteUrl: string, useHtml?: boolean): Promise<string> {
|
||||
let roomUrl = _decodeRoomURI(inviteUrl);
|
||||
const includeDialInfo = state['features/base/config'] !== undefined;
|
||||
|
||||
@@ -534,7 +526,7 @@ export function getShareInfoText(
|
||||
const { dialInConfCodeUrl, dialInNumbersUrl, hosts }
|
||||
= state['features/base/config'];
|
||||
const { locationURL = {} } = state['features/base/connection'];
|
||||
const mucURL = hosts && hosts.muc;
|
||||
const mucURL = hosts?.muc;
|
||||
|
||||
if (!dialInConfCodeUrl || !dialInNumbersUrl || !mucURL) {
|
||||
// URLs for fetching dial in numbers not defined
|
||||
@@ -542,7 +534,7 @@ export function getShareInfoText(
|
||||
}
|
||||
|
||||
numbersPromise = Promise.all([
|
||||
getDialInNumbers(dialInNumbersUrl, room, mucURL),
|
||||
getDialInNumbers(dialInNumbersUrl, room, mucURL), // @ts-ignore
|
||||
getDialInConferenceID(dialInConfCodeUrl, room, mucURL, locationURL)
|
||||
]).then(([ numbers, {
|
||||
conference, id, message } ]) => {
|
||||
@@ -592,16 +584,16 @@ export function getShareInfoText(
|
||||
/**
|
||||
* Generates the URL for the static dial in info page.
|
||||
*
|
||||
* @param {Object} state - The state from the Redux store.
|
||||
* @param {IReduxState} state - The state from the Redux store.
|
||||
* @param {string?} roomName - The conference name. Optional name, if missing will be extracted from state.
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getDialInfoPageURL(state: Object, roomName: ?string) {
|
||||
export function getDialInfoPageURL(state: IReduxState, roomName?: string) {
|
||||
const { didPageUrl } = state['features/dynamic-branding'];
|
||||
const conferenceName = roomName ?? getRoomName(state);
|
||||
const { locationURL } = state['features/base/connection'];
|
||||
const { href } = locationURL;
|
||||
const room = _decodeRoomURI(conferenceName);
|
||||
const { href = '' } = locationURL ?? {};
|
||||
const room = _decodeRoomURI(conferenceName ?? '');
|
||||
|
||||
const url = didPageUrl || `${href.substring(0, href.lastIndexOf('/'))}/${DIAL_IN_INFO_PAGE_PATH_NAME}`;
|
||||
|
||||
@@ -615,7 +607,7 @@ export function getDialInfoPageURL(state: Object, roomName: ?string) {
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getDialInfoPageURLForURIString(
|
||||
uri: ?string) {
|
||||
uri?: string) {
|
||||
if (!uri) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -637,7 +629,7 @@ export function getDialInfoPageURLForURIString(
|
||||
* @param {Object} dialIn - Dial in information.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function shouldDisplayDialIn(dialIn: Object) {
|
||||
export function shouldDisplayDialIn(dialIn: any) {
|
||||
const { conferenceID, numbers, numbersEnabled } = dialIn;
|
||||
const phoneNumber = _getDefaultPhoneNumber(numbers);
|
||||
|
||||
@@ -656,7 +648,7 @@ export function shouldDisplayDialIn(dialIn: Object) {
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function hasMultipleNumbers(dialInNumbers: ?Object) {
|
||||
export function hasMultipleNumbers(dialInNumbers?: { numbers: Object; } | string[]) {
|
||||
if (!dialInNumbers) {
|
||||
return false;
|
||||
}
|
||||
@@ -682,7 +674,7 @@ export function hasMultipleNumbers(dialInNumbers: ?Object) {
|
||||
* @returns {string|null}
|
||||
*/
|
||||
export function _getDefaultPhoneNumber(
|
||||
dialInNumbers: ?Object): ?string {
|
||||
dialInNumbers?: { numbers: any; } | Array<{ default: string; formattedNumber: string; }>): string | null {
|
||||
|
||||
if (!dialInNumbers) {
|
||||
return null;
|
||||
@@ -743,22 +735,23 @@ export function _decodeRoomURI(url: string) {
|
||||
/**
|
||||
* Returns the stored conference id.
|
||||
*
|
||||
* @param {Object | Function} stateful - The Object or Function that can be
|
||||
* @param {IStateful} stateful - The Object or Function that can be
|
||||
* resolved to a Redux state object with the toState function.
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getConferenceId(stateful: Object | Function) {
|
||||
export function getConferenceId(stateful: IStateful) {
|
||||
return toState(stateful)['features/invite'].conferenceID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default dial in number from the store.
|
||||
*
|
||||
* @param {Object | Function} stateful - The Object or Function that can be
|
||||
* @param {IStateful} stateful - The Object or Function that can be
|
||||
* resolved to a Redux state object with the toState function.
|
||||
* @returns {string | null}
|
||||
*/
|
||||
export function getDefaultDialInNumber(stateful: Object | Function) {
|
||||
export function getDefaultDialInNumber(stateful: IStateful) {
|
||||
// @ts-ignore
|
||||
return _getDefaultPhoneNumber(toState(stateful)['features/invite'].numbers);
|
||||
}
|
||||
|
||||
@@ -831,14 +824,14 @@ export function isSharingEnabled(sharingFeature: string) {
|
||||
* @returns {Promise} - The promise created by the request.
|
||||
*/
|
||||
export function inviteSipEndpoints( // eslint-disable-line max-params
|
||||
inviteItems: Array<Object>,
|
||||
inviteItems: Array<{ address: string; }>,
|
||||
locationURL: URL,
|
||||
sipInviteUrl: string,
|
||||
jwt: string,
|
||||
roomName: string,
|
||||
roomPassword: String,
|
||||
displayName: string
|
||||
): Promise<void> {
|
||||
): Promise<any> {
|
||||
if (inviteItems.length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
@@ -851,26 +844,26 @@ export function inviteSipEndpoints( // eslint-disable-line max-params
|
||||
});
|
||||
|
||||
return fetch(
|
||||
sipInviteUrl,
|
||||
{
|
||||
body: JSON.stringify({
|
||||
callParams: {
|
||||
callUrlInfo: {
|
||||
baseUrl,
|
||||
callName: roomName
|
||||
},
|
||||
passcode: roomPassword
|
||||
},
|
||||
sipClientParams: {
|
||||
displayName,
|
||||
sipAddress: inviteItems.map(item => item.address)
|
||||
}
|
||||
}),
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${jwt}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
sipInviteUrl,
|
||||
{
|
||||
body: JSON.stringify({
|
||||
callParams: {
|
||||
callUrlInfo: {
|
||||
baseUrl,
|
||||
callName: roomName
|
||||
},
|
||||
passcode: roomPassword
|
||||
},
|
||||
sipClientParams: {
|
||||
displayName,
|
||||
sipAddress: inviteItems.map(item => item.address)
|
||||
}
|
||||
}),
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${jwt}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1,27 +1,28 @@
|
||||
// @flow
|
||||
import { AnyAction } from 'redux';
|
||||
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
|
||||
import {
|
||||
CONFERENCE_JOINED
|
||||
} from '../base/conference';
|
||||
import { IStore } from '../app/types';
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes';
|
||||
import { CONFERENCE_JOINED } from '../base/conference/actionTypes';
|
||||
import {
|
||||
PARTICIPANT_JOINED,
|
||||
PARTICIPANT_JOINED_SOUND_ID,
|
||||
PARTICIPANT_LEFT,
|
||||
PARTICIPANT_UPDATED,
|
||||
PARTICIPANT_UPDATED
|
||||
} from '../base/participants/actionTypes';
|
||||
import { pinParticipant } from '../base/participants/actions';
|
||||
import { PARTICIPANT_JOINED_SOUND_ID } from '../base/participants/constants';
|
||||
import {
|
||||
getLocalParticipant,
|
||||
getParticipantCount,
|
||||
getParticipantPresenceStatus,
|
||||
getRemoteParticipants,
|
||||
pinParticipant
|
||||
} from '../base/participants';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
getRemoteParticipants
|
||||
} from '../base/participants/functions';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import {
|
||||
playSound,
|
||||
registerSound,
|
||||
stopSound,
|
||||
unregisterSound
|
||||
} from '../base/sounds';
|
||||
} from '../base/sounds/actions';
|
||||
import {
|
||||
CALLING,
|
||||
CONNECTED_USER,
|
||||
@@ -29,7 +30,7 @@ import {
|
||||
INVITED,
|
||||
REJECTED,
|
||||
RINGING
|
||||
} from '../presence-status';
|
||||
} from '../presence-status/constants';
|
||||
|
||||
import {
|
||||
SET_CALLEE_INFO_VISIBLE,
|
||||
@@ -49,8 +50,6 @@ import {
|
||||
import logger from './logger';
|
||||
import { sounds } from './sounds';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
/**
|
||||
* Maps the presence status with the ID of the sound that will be played when
|
||||
* the status is received.
|
||||
@@ -84,7 +83,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
|
||||
if (action.type === SET_CALLEE_INFO_VISIBLE) {
|
||||
if (action.calleeInfoVisible) {
|
||||
dispatch(pinParticipant(getLocalParticipant(state).id));
|
||||
dispatch(pinParticipant(getLocalParticipant(state)?.id));
|
||||
} else {
|
||||
// unpin participant
|
||||
dispatch(pinParticipant());
|
||||
@@ -124,10 +123,10 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
|
||||
const oldSoundId
|
||||
= oldParticipantPresence
|
||||
&& statusToRingtone[oldParticipantPresence];
|
||||
&& statusToRingtone[oldParticipantPresence as keyof typeof statusToRingtone];
|
||||
const newSoundId
|
||||
= newParticipantPresence
|
||||
&& statusToRingtone[newParticipantPresence];
|
||||
&& statusToRingtone[newParticipantPresence as keyof typeof statusToRingtone];
|
||||
|
||||
|
||||
if (oldSoundId === newSoundId) {
|
||||
@@ -159,10 +158,10 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
* (not poltergeist, shared video, etc.) participants in the call.
|
||||
*
|
||||
* @param {Object} action - The redux action.
|
||||
* @param {ReduxStore} store - The redux store.
|
||||
* @param {IStore} store - The redux store.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _maybeHideCalleeInfo(action, store) {
|
||||
function _maybeHideCalleeInfo(action: AnyAction, store: IStore) {
|
||||
const state = store.getState();
|
||||
|
||||
if (!state['features/invite'].calleeInfoVisible) {
|
||||
@@ -188,10 +187,10 @@ function _maybeHideCalleeInfo(action, store) {
|
||||
/**
|
||||
* Executes the pending invitation requests if any.
|
||||
*
|
||||
* @param {ReduxStore} store - The redux store.
|
||||
* @param {IStore} store - The redux store.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _onConferenceJoined(store) {
|
||||
function _onConferenceJoined(store: IStore) {
|
||||
const { dispatch, getState } = store;
|
||||
|
||||
const pendingInviteRequests
|
||||
@@ -1,10 +1,11 @@
|
||||
// @flow
|
||||
import { AnyAction } from 'redux';
|
||||
|
||||
import { hideDialog, openDialog } from '../base/dialog';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import { IStore } from '../app/types';
|
||||
import { hideDialog, openDialog } from '../base/dialog/actions';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
|
||||
import { BEGIN_ADD_PEOPLE, HIDE_ADD_PEOPLE_DIALOG } from './actionTypes';
|
||||
import { AddPeopleDialog } from './components';
|
||||
import AddPeopleDialog from './components/add-people-dialog/web/AddPeopleDialog';
|
||||
import './middleware.any';
|
||||
|
||||
/**
|
||||
@@ -37,7 +38,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
* @private
|
||||
* @returns {*} The value returned by {@code next(action)}.
|
||||
*/
|
||||
function _beginAddPeople({ dispatch }, next, action) {
|
||||
function _beginAddPeople({ dispatch }: IStore, next: Function, action: AnyAction) {
|
||||
const result = next(action);
|
||||
|
||||
dispatch(openDialog(AddPeopleDialog));
|
||||
@@ -58,7 +59,7 @@ function _beginAddPeople({ dispatch }, next, action) {
|
||||
* @private
|
||||
* @returns {*} The value returned by {@code next(action)}.
|
||||
*/
|
||||
function _hideAddPeopleDialog({ dispatch }, next, action) {
|
||||
function _hideAddPeopleDialog({ dispatch }: IStore, next: Function, action: AnyAction) {
|
||||
dispatch(hideDialog(AddPeopleDialog));
|
||||
|
||||
return next(action);
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
UPDATE_DIAL_IN_NUMBERS_SUCCESS
|
||||
} from './actionTypes';
|
||||
import logger from './logger';
|
||||
import { IInvitee } from './types';
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
/**
|
||||
@@ -27,12 +28,12 @@ export interface IInviteState {
|
||||
conferenceID?: string | number;
|
||||
error?: Error;
|
||||
initialCalleeInfo?: Object;
|
||||
numbers?: string;
|
||||
numbers?: string[];
|
||||
numbersEnabled: boolean;
|
||||
numbersFetched: boolean;
|
||||
pendingInviteRequests: Array<{
|
||||
callback: Function;
|
||||
invitees: Array<Object>;
|
||||
invitees: IInvitee[];
|
||||
}>;
|
||||
sipUri?: string;
|
||||
}
|
||||
|
||||
5
react/features/invite/types.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface IInvitee {
|
||||
address: string;
|
||||
number: string;
|
||||
type: string;
|
||||
}
|
||||
@@ -2,8 +2,6 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import Icon from '../../../base/icons/components/Icon';
|
||||
import { IconBurger } from '../../../base/icons/svg';
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Button from '../../../base/ui/components/web/Button';
|
||||
@@ -26,7 +24,6 @@ const PollCreate = ({
|
||||
addAnswer,
|
||||
answers,
|
||||
isSubmitDisabled,
|
||||
moveAnswer,
|
||||
onSubmit,
|
||||
question,
|
||||
removeAnswer,
|
||||
@@ -142,37 +139,6 @@ const PollCreate = ({
|
||||
}
|
||||
}, [ answers, addAnswer, removeAnswer, requestFocus ]);
|
||||
|
||||
const [ grabbing, setGrabbing ] = useState(null);
|
||||
|
||||
const interchangeHeights = (i: number, j: number) => {
|
||||
const h = answerInputs.current[i].scrollHeight;
|
||||
|
||||
answerInputs.current[i].style.height = `${answerInputs.current[j].scrollHeight}px`;
|
||||
answerInputs.current[j].style.height = `${h}px`;
|
||||
};
|
||||
|
||||
const onGrab = useCallback((i, ev) => {
|
||||
if (ev.button !== 0) {
|
||||
return;
|
||||
}
|
||||
setGrabbing(i);
|
||||
window.addEventListener('mouseup', () => {
|
||||
setGrabbing(_grabbing => {
|
||||
requestFocus(_grabbing);
|
||||
|
||||
return null;
|
||||
});
|
||||
}, { once: true });
|
||||
}, []);
|
||||
|
||||
const onMouseOver = useCallback(i => {
|
||||
if (grabbing !== null && grabbing !== i) {
|
||||
interchangeHeights(i, grabbing);
|
||||
moveAnswer(grabbing, i);
|
||||
setGrabbing(i);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const autogrow = (ev: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
const el = ev.target;
|
||||
|
||||
@@ -207,9 +173,8 @@ const PollCreate = ({
|
||||
<ol className = 'poll-answer-field-list'>
|
||||
{answers.map((answer: any, i: number) =>
|
||||
(<li
|
||||
className = { `poll-answer-field${grabbing === i ? ' poll-dragged' : ''}` }
|
||||
key = { i }
|
||||
onMouseOver = { () => onMouseOver(i) }>
|
||||
className = 'poll-answer-field'
|
||||
key = { i }>
|
||||
<span className = 'poll-create-label'>
|
||||
{ t('polls.create.pollOption', { index: i + 1 })}
|
||||
</span>
|
||||
@@ -225,13 +190,6 @@ const PollCreate = ({
|
||||
required = { true }
|
||||
rows = { 1 }
|
||||
value = { answer } />
|
||||
<button
|
||||
className = 'poll-drag-handle'
|
||||
onMouseDown = { ev => onGrab(i, ev) }
|
||||
tabIndex = { -1 }
|
||||
type = 'button'>
|
||||
<Icon src = { IconBurger } />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{ answers.length > 2
|
||||
|
||||
@@ -92,7 +92,7 @@ function pollForStatus(
|
||||
return;
|
||||
}
|
||||
|
||||
const res = await executeDialOutStatusRequest(getDialOutStatusUrl(state), reqId);
|
||||
const res = await executeDialOutStatusRequest(getDialOutStatusUrl(state) ?? '', reqId);
|
||||
|
||||
switch (res) {
|
||||
case DIAL_OUT_STATUS.INITIATED:
|
||||
@@ -153,7 +153,7 @@ export function dialOut(onSuccess: Function, onFail: Function) {
|
||||
return async function(dispatch: IStore['dispatch'], getState: IStore['getState']) {
|
||||
const state = getState();
|
||||
const reqId = uuidv4();
|
||||
const url = getDialOutUrl(state);
|
||||
const url = getDialOutUrl(state) ?? '';
|
||||
const conferenceUrl = getDialOutConferenceUrl(state);
|
||||
const phoneNumber = getFullDialOutNumber(state);
|
||||
const countryCode = getDialOutCountry(state).code.toUpperCase();
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import {
|
||||
DELETE_RECENT_LIST_ENTRY,
|
||||
_STORE_CURRENT_CONFERENCE,
|
||||
@@ -1,9 +1,13 @@
|
||||
import {
|
||||
getLocalizedDateFormatter,
|
||||
getLocalizedDurationFormatter
|
||||
} from '../base/i18n';
|
||||
} from '../base/i18n/dateUtil';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { NavigateSectionList } from '../base/react';
|
||||
import { parseURIString, safeDecodeURIComponent } from '../base/util';
|
||||
import { parseURIString, safeDecodeURIComponent } from '../base/util/uri';
|
||||
|
||||
import { IRecentItem } from './types';
|
||||
|
||||
/**
|
||||
* Creates a displayable list item of a recent list entry.
|
||||
@@ -14,7 +18,8 @@ import { parseURIString, safeDecodeURIComponent } from '../base/util';
|
||||
* @param {Function} t - The translate function.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function toDisplayableItem(item, defaultServerURL, t) {
|
||||
function toDisplayableItem(item: IRecentItem,
|
||||
defaultServerURL: string, t: Function) {
|
||||
const location = parseURIString(item.conference);
|
||||
const baseURL = `${location.protocol}//${location.host}`;
|
||||
const serverName = baseURL === defaultServerURL ? null : location.host;
|
||||
@@ -43,7 +48,7 @@ function toDisplayableItem(item, defaultServerURL, t) {
|
||||
* @param {number} duration - The item's duration.
|
||||
* @returns {string}
|
||||
*/
|
||||
function _toDurationString(duration) {
|
||||
function _toDurationString(duration: number) {
|
||||
if (duration) {
|
||||
return getLocalizedDurationFormatter(duration);
|
||||
}
|
||||
@@ -59,7 +64,7 @@ function _toDurationString(duration) {
|
||||
* @param {Function} t - The translate function.
|
||||
* @returns {string}
|
||||
*/
|
||||
function _toDateString(itemDate, t) {
|
||||
function _toDateString(itemDate: number, t: Function) {
|
||||
const m = getLocalizedDateFormatter(itemDate);
|
||||
const date = new Date(itemDate);
|
||||
const dateInMs = date.getTime();
|
||||
@@ -90,7 +95,8 @@ function _toDateString(itemDate, t) {
|
||||
* @param {string} defaultServerURL - The default server URL.
|
||||
* @returns {Array<Object>}
|
||||
*/
|
||||
export function toDisplayableList(recentList, t, defaultServerURL) {
|
||||
export function toDisplayableList(recentList: IRecentItem[],
|
||||
t: Function, defaultServerURL: string) {
|
||||
const { createSection } = NavigateSectionList;
|
||||
const todaySection = createSection(t('dateUtils.today'), 'today');
|
||||
const yesterdaySection
|
||||
@@ -1,6 +1,4 @@
|
||||
/* global interfaceConfig */
|
||||
|
||||
import { parseURIString, safeDecodeURIComponent } from '../base/util';
|
||||
import { parseURIString, safeDecodeURIComponent } from '../base/util/uri';
|
||||
|
||||
|
||||
/**
|
||||
@@ -10,7 +8,7 @@ import { parseURIString, safeDecodeURIComponent } from '../base/util';
|
||||
* @param {Array<Object>} recentList - The recent list form the redux store.
|
||||
* @returns {Array<Object>}
|
||||
*/
|
||||
export function toDisplayableList(recentList) {
|
||||
export function toDisplayableList(recentList: Array<{ conference: string; date: Date; duration: number; }>) {
|
||||
return (
|
||||
[ ...recentList ].reverse()
|
||||
.map(item => {
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import { getLogger } from '../base/logging/functions';
|
||||
|
||||
export default getLogger('features/recent-list');
|
||||
@@ -1,21 +1,17 @@
|
||||
// @flow
|
||||
import { AnyAction } from 'redux';
|
||||
|
||||
import { APP_WILL_MOUNT } from '../base/app';
|
||||
import {
|
||||
CONFERENCE_WILL_LEAVE,
|
||||
JITSI_CONFERENCE_URL_KEY,
|
||||
SET_ROOM
|
||||
} from '../base/conference';
|
||||
import { addKnownDomains } from '../base/known-domains';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import { parseURIString } from '../base/util';
|
||||
import { IStore } from '../app/types';
|
||||
import { APP_WILL_MOUNT } from '../base/app/actionTypes';
|
||||
import { CONFERENCE_WILL_LEAVE, SET_ROOM } from '../base/conference/actionTypes';
|
||||
import { JITSI_CONFERENCE_URL_KEY } from '../base/conference/constants';
|
||||
import { addKnownDomains } from '../base/known-domains/actions';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import { inIframe } from '../base/util/iframeUtils';
|
||||
import { parseURIString } from '../base/util/uri';
|
||||
|
||||
import { _storeCurrentConference, _updateConferenceDuration } from './actions';
|
||||
import { isRecentListEnabled } from './functions';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
/**
|
||||
* Middleware that captures joined rooms so they can be saved into
|
||||
* {@code window.localStorage}.
|
||||
@@ -53,7 +49,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
* @private
|
||||
* @returns {*} The result returned by {@code next(action)}.
|
||||
*/
|
||||
function _appWillMount({ dispatch, getState }, next, action) {
|
||||
function _appWillMount({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
|
||||
const result = next(action);
|
||||
|
||||
// It's an opportune time to transfer the feature recent-list's knowledge
|
||||
@@ -86,7 +82,7 @@ function _appWillMount({ dispatch, getState }, next, action) {
|
||||
* @private
|
||||
* @returns {*} The result returned by {@code next(action)}.
|
||||
*/
|
||||
function _conferenceWillLeave({ dispatch, getState }, next, action) {
|
||||
function _conferenceWillLeave({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
|
||||
const { doNotStoreRoom } = getState()['features/base/config'];
|
||||
|
||||
if (!doNotStoreRoom && !inIframe()) {
|
||||
@@ -126,7 +122,7 @@ function _conferenceWillLeave({ dispatch, getState }, next, action) {
|
||||
* @private
|
||||
* @returns {*} The result returned by {@code next(action)}.
|
||||
*/
|
||||
function _setRoom({ dispatch, getState }, next, action) {
|
||||
function _setRoom({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
|
||||
const { doNotStoreRoom } = getState()['features/base/config'];
|
||||
|
||||
if (!doNotStoreRoom && !inIframe() && action.room) {
|
||||
5
react/features/recent-list/types.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface IRecentItem {
|
||||
conference: string;
|
||||
date: number;
|
||||
duration: number;
|
||||
}
|
||||
@@ -44,7 +44,7 @@ const SalesforceLinkDialog = () => {
|
||||
|
||||
const handlePress = useCallback(() => {
|
||||
navigate(screen.conference.main);
|
||||
linkMeeting();
|
||||
selectedRecord && linkMeeting();
|
||||
}, [ navigate, linkMeeting ]);
|
||||
|
||||
const renderSpinner = () => (
|
||||
|
||||
@@ -18,7 +18,7 @@ import { RecordItem } from './RecordItem';
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
container: {
|
||||
minHeight: '450px',
|
||||
height: '450px',
|
||||
overflowY: 'auto',
|
||||
position: 'relative'
|
||||
},
|
||||
@@ -56,23 +56,38 @@ const useStyles = makeStyles()(theme => {
|
||||
spinner: {
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
height: 'calc(100% - 100px)',
|
||||
height: 'calc(100% - 70px)',
|
||||
justifyContent: 'center',
|
||||
width: '100%'
|
||||
width: '100%',
|
||||
|
||||
'@media (max-width: 448px)': {
|
||||
height: 'auto',
|
||||
marginTop: '24px'
|
||||
}
|
||||
},
|
||||
noRecords: {
|
||||
height: 'calc(100% - 150px)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column'
|
||||
flexDirection: 'column',
|
||||
|
||||
'@media (max-width: 448px)': {
|
||||
height: 'auto',
|
||||
marginTop: '24px'
|
||||
}
|
||||
},
|
||||
recordsError: {
|
||||
height: 'calc(100% - 80px)',
|
||||
height: 'calc(100% - 42px)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column'
|
||||
flexDirection: 'column',
|
||||
|
||||
'@media (max-width: 448px)': {
|
||||
height: 'auto',
|
||||
marginTop: '24px'
|
||||
}
|
||||
},
|
||||
recordList: {
|
||||
listStyle: 'none',
|
||||
@@ -145,7 +160,7 @@ function SalesforceLinkDialog() {
|
||||
|
||||
const handleSubmit = useCallback(() => {
|
||||
dispatch(hideDialog());
|
||||
linkMeeting();
|
||||
selectedRecord && linkMeeting();
|
||||
}, [ hideDialog, linkMeeting ]);
|
||||
|
||||
const renderSpinner = () => (
|
||||
|
||||