Compare commits
28 Commits
7755
...
jitsi-meet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba7ed83d48 | ||
|
|
5a96050973 | ||
|
|
7e8c1fd99a | ||
|
|
6e6433e2d9 | ||
|
|
4ff2422e3c | ||
|
|
cfbcfdc857 | ||
|
|
3074b1741f | ||
|
|
00503d163a | ||
|
|
f847a3e2e0 | ||
|
|
93d0ee710b | ||
|
|
0102efd2d0 | ||
|
|
8afdebca08 | ||
|
|
d2bfb464ba | ||
|
|
5f3233b9a6 | ||
|
|
3c32d9c552 | ||
|
|
f51d8d54e4 | ||
|
|
ac26dce0a5 | ||
|
|
7a23625752 | ||
|
|
4cb4a4db00 | ||
|
|
05e484c4aa | ||
|
|
5871e50a20 | ||
|
|
95ad04b19c | ||
|
|
36fab239cc | ||
|
|
92492dc482 | ||
|
|
51c3658205 | ||
|
|
418d333caf | ||
|
|
7f3f2f7034 | ||
|
|
bd3012f110 |
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
@@ -73,6 +73,13 @@ jobs:
|
||||
node-version: 16
|
||||
cache: 'npm'
|
||||
- run: npm install
|
||||
- name: Install Pods
|
||||
run: |
|
||||
pod --version
|
||||
cd ios
|
||||
pod install --repo-update
|
||||
- name: Check if the git repository is clean
|
||||
run: $(exit $(git status --porcelain --untracked-files=no | head -255 | wc -l)) || (echo "Dirty git tree"; git diff; exit 1)
|
||||
- run: npx react-native bundle --entry-file react/index.native.js --platform ios --bundle-output /tmp/ios.bundle --reset-cache
|
||||
debian-build:
|
||||
name: Test Debian packages build
|
||||
|
||||
@@ -87,6 +87,7 @@ class AudioDeviceHandlerGeneric implements
|
||||
devices.add(AudioModeModule.DEVICE_EARPIECE);
|
||||
break;
|
||||
case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER:
|
||||
case AudioDeviceInfo.TYPE_HDMI:
|
||||
devices.add(AudioModeModule.DEVICE_SPEAKER);
|
||||
break;
|
||||
case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
|
||||
|
||||
16
config.js
16
config.js
@@ -413,9 +413,6 @@ var config = {
|
||||
// // ./src/react/features/transcribing/transcriber-langs.json.
|
||||
// preferredLanguage: 'en-US',
|
||||
|
||||
// // Disable start transcription for all participants.
|
||||
// disableStartForAll: false,
|
||||
|
||||
// // Enables automatic turning on transcribing when recording is started
|
||||
// autoTranscribeOnRecord: false,
|
||||
// },
|
||||
@@ -1197,9 +1194,17 @@ var config = {
|
||||
// https://firebase.google.com/docs/dynamic-links/create-manually
|
||||
// deeplinking: {
|
||||
//
|
||||
// // The desktop deeplinking config.
|
||||
// // The desktop deeplinking config, disabled by default.
|
||||
// desktop: {
|
||||
// appName: 'Jitsi Meet'
|
||||
// appName: 'Jitsi Meet',
|
||||
// appScheme: 'jitsi-meet,
|
||||
// download: {
|
||||
// linux:
|
||||
// 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet-x86_64.AppImage',
|
||||
// macos: 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet.dmg',
|
||||
// windows: 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet.exe'
|
||||
// },
|
||||
// enabled: false
|
||||
// },
|
||||
// // If true, any checks to handoff to another application will be prevented
|
||||
// // and instead the app will continue to display in the current browser.
|
||||
@@ -1421,7 +1426,6 @@ var config = {
|
||||
// 'conference-timer',
|
||||
// 'participants-count',
|
||||
// 'e2ee',
|
||||
// 'transcribing',
|
||||
// 'video-quality',
|
||||
// 'insecure-room',
|
||||
// 'highlight-moment',
|
||||
|
||||
@@ -38,9 +38,9 @@ apt install token-generator
|
||||
|
||||
mkdir -p /etc/jitsi/meet/jaas
|
||||
|
||||
VPASS_COOKIE=$(echo -n ${JAAS_KEY_ID}| cut -d/ -f1)
|
||||
VPAAS_COOKIE=$(echo -n ${JAAS_KEY_ID}| cut -d/ -f1)
|
||||
cp /usr/share/jitsi-meet-web-config/nginx-jaas.conf /etc/jitsi/meet/jaas
|
||||
sed -i "s/jaas_magic_cookie/${VPASS_COOKIE}/g" /etc/jitsi/meet/jaas/nginx-jaas.conf
|
||||
sed -i "s/jaas_magic_cookie/${VPAAS_COOKIE}/g" /etc/jitsi/meet/jaas/nginx-jaas.conf
|
||||
|
||||
cp /usr/share/jitsi-meet-web-config/8x8.vc-config.js /etc/jitsi/meet/jaas/
|
||||
echo "set \$config_js_location /etc/jitsi/meet/jaas/8x8.vc-config.js;" >> /etc/jitsi/meet/jaas/jaas-vars
|
||||
|
||||
@@ -447,10 +447,10 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-splash-screen (3.3.0):
|
||||
- React-Core
|
||||
- react-native-video (6.0.0-alpha.7):
|
||||
- react-native-video (6.0.0-alpha.11):
|
||||
- React-Core
|
||||
- react-native-video/Video (= 6.0.0-alpha.7)
|
||||
- react-native-video/Video (6.0.0-alpha.7):
|
||||
- react-native-video/Video (= 6.0.0-alpha.11)
|
||||
- react-native-video/Video (6.0.0-alpha.11):
|
||||
- PromisesSwift
|
||||
- React-Core
|
||||
- react-native-webrtc (118.0.0):
|
||||
@@ -880,7 +880,7 @@ SPEC CHECKSUMS:
|
||||
react-native-safe-area-context: 9697629f7b2cda43cf52169bb7e0767d330648c2
|
||||
react-native-slider: 1cdd6ba29675df21f30544253bf7351d3c2d68c4
|
||||
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
|
||||
react-native-video: 967eead48aaa42c25a9e1d65c3b1ab30762a88df
|
||||
react-native-video: 472b7c366eaaaa0207e546d9a50410df89790bcf
|
||||
react-native-webrtc: c8d9ad3c152105b2720ca2851d04b49659551992
|
||||
react-native-webview: 8baa0f5c6d336d6ba488e942bcadea5bf51f050a
|
||||
React-NativeModulesApple: 4225ac31a26696c02c54b471052b3e85e74a9a0c
|
||||
|
||||
@@ -209,7 +209,7 @@
|
||||
"appNotInstalled": "Sie benötigen die „{{app}}“-App, um der Konferenz auf dem Smartphone beizutreten.",
|
||||
"description": "Nichts passiert? Wir haben versucht, die Konferenz in {{app}} zu öffnen. Versuchen Sie es erneut oder treten Sie der Konferenz in {{app}} im Web bei.",
|
||||
"descriptionNew": "Nichts passiert? Wir haben versucht, die Konferenz in {{app}} zu öffnen. <br /><br /> Versuchen Sie es erneut oder treten Sie der Konferenz im Web bei.",
|
||||
"descriptionWithoutWeb": "Ist nichts passiert? Wir haben versucht, Ihre Besprechung in der „{{app}}“-Desktop-App zu starten.",
|
||||
"descriptionWithoutWeb": "Ist nichts passiert? Wir haben versucht, Ihre Konferenz in der „{{app}}“-Desktop-App zu starten.",
|
||||
"downloadApp": "App herunterladen",
|
||||
"downloadMobileApp": "Aus dem App Store herunterladen",
|
||||
"ifDoNotHaveApp": "Wenn Sie die App noch nicht haben:",
|
||||
@@ -219,11 +219,13 @@
|
||||
"joinInBrowser": "Im Browser",
|
||||
"launchMeetingLabel": "Wie möchten Sie an der Konferenz teilnehmen?",
|
||||
"launchWebButton": "Im Web öffnen",
|
||||
"noDesktopApp": "Sie haben die App noch nicht installiert?",
|
||||
"noMobileApp": "Sie haben die App noch nicht installiert?",
|
||||
"termsAndConditions": "Indem Sie fortfahren, stimmen Sie underen<a href='{{termsAndConditionsLink}}' rel='noopener noreferrer' target='_blank'>Nutzungsbedingungen</a> zu.",
|
||||
"or": "oder",
|
||||
"termsAndConditions": "Indem Sie fortfahren, stimmen Sie unseren <a href='{{termsAndConditionsLink}}' rel='noopener noreferrer' target='_blank'>Nutzungsbedingungen</a> zu.",
|
||||
"title": "Die Konferenz wird in {{app}} geöffnet …",
|
||||
"titleNew": "Konferenz starten ...",
|
||||
"tryAgainButton": "Erneut mit der nativen Applikation versuchen",
|
||||
"tryAgainButton": "Erneut versuchen",
|
||||
"unsupportedBrowser": "Sie verwenden einen Browser, der noch nicht unterstützt wird."
|
||||
},
|
||||
"defaultLink": "Bsp.: {{url}}",
|
||||
@@ -534,7 +536,7 @@
|
||||
"conferenceURL": "Link:",
|
||||
"copyNumber": "Nummer kopieren",
|
||||
"country": "Land",
|
||||
"dialANumber": "Um am Meeting teilzunehmen, müssen Sie eine dieser Nummern wählen und dann die PIN eingeben.",
|
||||
"dialANumber": "Um an der Konferenz teilzunehmen, müssen Sie eine dieser Nummern wählen und dann die PIN eingeben.",
|
||||
"dialInConferenceID": "PIN:",
|
||||
"dialInNotSupported": "Entschuldigung, leider wird das Einwählen derzeit nicht unterstützt.",
|
||||
"dialInNumber": "Einwählen:",
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"addPeople": {
|
||||
"accessibilityLabel": {
|
||||
"meetingLink": "Lien de la réunion: {{url}}"
|
||||
},
|
||||
"add": "Inviter",
|
||||
"addContacts": "Inviter vos contacts",
|
||||
"contacts": "contacts",
|
||||
@@ -39,6 +42,18 @@
|
||||
"audioOnly": {
|
||||
"audioOnly": "Bande passante faible"
|
||||
},
|
||||
"bandwidthSettings": {
|
||||
"assumedBandwidthBps": "p. ex. 10000000 pour 10 Mbps ",
|
||||
"assumedBandwidthBpsWarning": "Des valeurs élevées peuvent provoquer des problèmes réseaux.",
|
||||
"customValue": "valeur personnalisée",
|
||||
"customValueEffect": "Positionner la valeur actuelle en bps",
|
||||
"leaveEmpty": "Laisser vide",
|
||||
"leaveEmptyEffect": "Autoriser l'utilisation de l'estimation",
|
||||
"possibleValues": "Valeurs possibles",
|
||||
"setAssumedBandwidthBps": "Bande passante estimée",
|
||||
"title": "Réglage de bande passante",
|
||||
"zeroEffect": "Désactiver la vidéo"
|
||||
},
|
||||
"breakoutRooms": {
|
||||
"actions": {
|
||||
"add": "Ajouter salle annexe",
|
||||
@@ -48,15 +63,22 @@
|
||||
"leaveBreakoutRoom": "Quitter la salle annexe",
|
||||
"more": "Plus",
|
||||
"remove": "Supprimer",
|
||||
"rename": "Renommer",
|
||||
"renameBreakoutRoom": "Renommer la salle annexe",
|
||||
"sendToBreakoutRoom": "Envoyer le participant dans:"
|
||||
},
|
||||
"breakoutList": "Liste des salles annexes",
|
||||
"buttonLabel": "Salles annexes",
|
||||
"defaultName": "Salle annexe #{{index}}",
|
||||
"hideParticipantList": "Masquer la liste des participants",
|
||||
"mainRoom": "Salle principale",
|
||||
"notifications": {
|
||||
"joined": "Entrée en salle annexe \"{{name}}\"",
|
||||
"joinedMainRoom": "Retour à la salle principalem",
|
||||
"joinedTitle": "Salles annexes"
|
||||
}
|
||||
},
|
||||
"showParticipantList": "Afficher la liste des participants",
|
||||
"title": "Salles annexes"
|
||||
},
|
||||
"calendarSync": {
|
||||
"addMeetingURL": "Ajouter un lien de conférence",
|
||||
@@ -118,7 +140,7 @@
|
||||
"buttonText": "Installer l'extension Chrome",
|
||||
"buttonTextEdge": "Installer l’extension Edge",
|
||||
"close": "Fermer",
|
||||
"dontShowAgain": "Ne plus me montrer ceci",
|
||||
"dontShowAgain": "Ne plus m'afficher ceci",
|
||||
"installExtensionText": "Installer l'extension pour l'intégration de Google Calendar et Office 365"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
@@ -149,13 +171,14 @@
|
||||
"connectedTo": "Connecté à :",
|
||||
"e2eeVerified": "E2EE vérifié",
|
||||
"framerate": "Images par seconde :",
|
||||
"less": "Cacher les détails",
|
||||
"less": "Masquer les détails",
|
||||
"localaddress": "Adresse locale :",
|
||||
"localaddress_plural": "Adresses locales :",
|
||||
"localport": "Port local :",
|
||||
"localport_plural": "Ports locaux :",
|
||||
"maxEnabledResolution": "débit max",
|
||||
"more": "Montrer les détails",
|
||||
"more": "Afficher les détails",
|
||||
"no": "non",
|
||||
"packetloss": "Perte de paquets :",
|
||||
"participant_id": "ID du participant:",
|
||||
"quality": {
|
||||
@@ -174,7 +197,8 @@
|
||||
"status": "Connexion :",
|
||||
"transport": "Transport :",
|
||||
"transport_plural": "Transports :",
|
||||
"video_ssrc": "Video SSRC :"
|
||||
"video_ssrc": "Video SSRC :",
|
||||
"yes": "oui"
|
||||
},
|
||||
"dateUtils": {
|
||||
"earlier": "Plus tôt",
|
||||
@@ -237,9 +261,12 @@
|
||||
"Share": "Partager",
|
||||
"Submit": "Soumettre",
|
||||
"WaitForHostMsg": "La conférence n'a pas encore commencé. Si vous en êtes l'hôte, veuillez vous authentifier. Sinon, veuillez attendre son arrivée.",
|
||||
"WaitingForHostButton": "Attendre l'hôte",
|
||||
"WaitingForHostTitle": "En attente de l'hôte ...",
|
||||
"Yes": "Oui",
|
||||
"accessibilityLabel": {
|
||||
"Cancel": "Annuler (quiter la popup)",
|
||||
"Ok": "Ok (Sauvegarder et quiter la popup)",
|
||||
"close": "Fermer la popup",
|
||||
"liveStreaming": "Diffusion en direct",
|
||||
"sharingTabs": "Options de partage"
|
||||
@@ -248,6 +275,8 @@
|
||||
"addMeetingNote": "Ajouter une note à cette conférence",
|
||||
"addOptionalNote": "Ajouter une note (optionnel):",
|
||||
"allow": "Autoriser",
|
||||
"allowToggleCameraDialog": "Autorisez-vous {{initiatorName}} à changer votre mode de caméra ?",
|
||||
"allowToggleCameraTitle": "Autoriser-vous le changement de mode de caméra ?",
|
||||
"alreadySharedVideoMsg": "Un autre participant est en train de partager sa vidéo. Cette conférence ne permet de partager qu'une seule vidéo à la fois.",
|
||||
"alreadySharedVideoTitle": "Une seule vidéo partagée est autorisée à la fois",
|
||||
"applicationWindow": "Fenêtre d'application",
|
||||
@@ -288,8 +317,8 @@
|
||||
"gracefulShutdown": "Notre service est actuellement en maintenance. Veuillez réessayer plus tard.",
|
||||
"grantModeratorDialog": "Êtes-vous sûr de vouloir rendre ce participant modérateur ?",
|
||||
"grantModeratorTitle": "Nommer modérateur",
|
||||
"hide": "Cacher",
|
||||
"hideShareAudioHelper": "Ne pas montrer ce dialogue à nouveau",
|
||||
"hide": "Masquer",
|
||||
"hideShareAudioHelper": "Ne pas afficher ce dialogue à nouveau",
|
||||
"incorrectPassword": "Nom d'utilisateur ou mot de passe incorrect",
|
||||
"incorrectRoomLockPassword": "Mot de passe incorrect",
|
||||
"internalError": "Oups ! Quelque chose s'est mal passée. L'erreur suivante s'est produite : {{error}}",
|
||||
@@ -308,6 +337,7 @@
|
||||
"lockRoom": "Ajouter un $t(lockRoomPassword) à la réunion ",
|
||||
"lockTitle": "Échec du verrouillage",
|
||||
"login": "Connexion",
|
||||
"loginQuestion": "Voulez-vous vraiment vous connecter et quitter la conférence ?",
|
||||
"logoutQuestion": "Voulez-vous vraiment vous déconnecter et arrêter la conférence ?",
|
||||
"logoutTitle": "Déconnexion",
|
||||
"maxUsersLimitReached": "Le nombre maximal de participants est atteint. Le conférence est complète. Merci de contacter l'organisateur de la réunion ou réessayer plus tard !",
|
||||
@@ -351,8 +381,6 @@
|
||||
"permissionCameraRequiredError": "L'autorisation caméra est nécessaire pour participer aux réunions avec vidéo. Merci de l'accorder dans les paramètres",
|
||||
"permissionErrorTitle": "Permission nécessaire",
|
||||
"permissionMicRequiredError": "L'autorisation microphone est nécessaire pour participer aux réunions avec son. Merci de l'accorder dans les paramètres",
|
||||
"popupError": "Votre navigateur bloque les fenêtres pop-up. Veuillez autoriser les fenêtres pop-up dans les paramètres de votre navigateur.",
|
||||
"popupErrorTitle": "Pop-up bloquée",
|
||||
"readMore": "plus",
|
||||
"recentlyUsedObjects": "Vos objets récemment utilisés",
|
||||
"recording": "Enregistrement",
|
||||
@@ -369,6 +397,8 @@
|
||||
"removePassword": "Supprimer le $t(lockRoomPassword)",
|
||||
"removeSharedVideoMsg": "Voulez-vous vraiment supprimer votre vidéo partagée ?",
|
||||
"removeSharedVideoTitle": "Supprimer la vidéo partagée",
|
||||
"renameBreakoutRoomLabel": "Nom de la salle annexe",
|
||||
"renameBreakoutRoomTitle": "Renommer la salle annexe",
|
||||
"reservationError": "Erreur du système de réservation",
|
||||
"reservationErrorMsg": "Code d'erreur: {{code}}, message: {{msg}}",
|
||||
"retry": "Réessayer",
|
||||
@@ -388,8 +418,10 @@
|
||||
"sendPrivateMessageTitle": "Envoyer en privé ?",
|
||||
"serviceUnavailable": "Service indisponible",
|
||||
"sessTerminated": "Appel terminé",
|
||||
"sessTerminatedReason": "L'appel a été terminé",
|
||||
"sessionRestarted": "L'appel est relancé par la passerelle",
|
||||
"shareAudio": "Continuer",
|
||||
"shareAudioAltText": "Pour partager le contenu voulu, naviguer vers \"Onglet du Navigateur\", sélectionner le contenu, activer le bouton \"partager l’audio\" et enfin cliquer sur le bouton \"partager\"",
|
||||
"shareAudioTitle": "Comment partager le son",
|
||||
"shareAudioWarningD1": "vous devez cesser le partage d'écran avant de partager votre son.",
|
||||
"shareAudioWarningD2": "viys devez partager votre écran à nouveau et cocher l'ootion \"Partager l'audio\".",
|
||||
@@ -419,12 +451,30 @@
|
||||
"thankYou": "Merci d'avoir utilisé {{appName}} !",
|
||||
"token": "jeton",
|
||||
"tokenAuthFailed": "Désolé, vous n'êtes pas autorisé à rejoindre cette conversation.",
|
||||
"tokenAuthFailedReason": {
|
||||
"audInvalid": "Valeur `aud` invalide. Cela doit être `jitsi`.",
|
||||
"contextNotFound": "L'objet `context` est absent du payload.",
|
||||
"expInvalid": "Valeur `exp` invalide.",
|
||||
"featureInvalid": "Fonctionnalité invalide: {{feature}}, probablement pas encore implémentée.",
|
||||
"featureValueInvalid": "Valeur invalide pour la fonctionnalité: {{feature}}.",
|
||||
"featuresNotFound": "L'objet `feature` est absent du payload.",
|
||||
"headerNotFound": "Header non trouvé.",
|
||||
"issInvalid": "Valeur `iss` invalide. Cela doit être `chat`.",
|
||||
"kidMismatch": "Key ID (kid) ne correspond pas au sub.",
|
||||
"kidNotFound": "Key ID (kid) manquant.",
|
||||
"nbfFuture": "La valeur `nbf` est dans le futur.",
|
||||
"nbfInvalid": "Valeur `nbf` invalide.",
|
||||
"payloadNotFound": "Payload non trouvé",
|
||||
"tokenExpired": "Jeton expiré"
|
||||
},
|
||||
"tokenAuthFailedTitle": "Échec de l'authentification",
|
||||
"tokenAuthFailedWithReasons": "Désolé, vous n’êtes pas autorisé à rejoindre l’appel. La raison possible : {{reason}}.",
|
||||
"tokenAuthUnsupported": "Token URL n'est pas supporté.",
|
||||
"transcribing": "Transcription",
|
||||
"unlockRoom": "Supprimer le $t(lockRoomPassword) de la réunion",
|
||||
"user": "Utilisateur",
|
||||
"userIdentifier": "Identifiant utilisateur",
|
||||
"userPassword": "mot de passe utilisateur",
|
||||
"userPassword": "Mot de passe utilisateur",
|
||||
"verifyParticipantConfirm": "Ils correspondent",
|
||||
"verifyParticipantDismiss": "Ils ne correspondent pas",
|
||||
"verifyParticipantQuestion": "EXPÉRIMENTAL: Demander au participant {{participantName}} s'il voit le même contenu dans le même ordre. ",
|
||||
@@ -433,6 +483,10 @@
|
||||
"viewUpgradeOptions": "Voir les options de mise à jour",
|
||||
"viewUpgradeOptionsContent": "Pour obtenir un accès illimité à des capacités premium comme l'enregistrement, les transcriptions, diffusion RTMP et plus, vous devez mettre à jour votre plan.",
|
||||
"viewUpgradeOptionsTitle": "Vous avez découvert une capacité premium !",
|
||||
"whiteboardLimitContent": "Désolé, la limite d’utilisateur du tableau blanc a été atteinte.",
|
||||
"whiteboardLimitReference": "Pour plus d’informations merci de visiter",
|
||||
"whiteboardLimitReferenceUrl": "notre site web",
|
||||
"whiteboardLimitTitle": "Utilisation du tableau blanc limitée",
|
||||
"yourEntireScreen": "Votre écran entier"
|
||||
},
|
||||
"documentSharing": {
|
||||
@@ -445,6 +499,9 @@
|
||||
"title": "Intégrer cette réunion"
|
||||
},
|
||||
"feedback": {
|
||||
"accessibilityLabel": {
|
||||
"yourChoice": "Votre choix: {{rating}}"
|
||||
},
|
||||
"average": "Moyen",
|
||||
"bad": "Mauvais",
|
||||
"detailsLabel": "Dites nous en plus à ce sujet.",
|
||||
@@ -505,6 +562,7 @@
|
||||
"password": "$t(lockRoomPasswordUppercase) :",
|
||||
"reachedLimit": "Vous avez atteint la limite de votre abonnement.",
|
||||
"sip": "adresse SIP",
|
||||
"sipAudioOnly": "Adresse SIP en audio uniquement",
|
||||
"title": "Partager",
|
||||
"tooltip": "Partager le lien et les informations de connexion pour cette conférence",
|
||||
"upgradeOptions": "Veuillez vérifier les options de mise à niveau"
|
||||
@@ -544,7 +602,7 @@
|
||||
},
|
||||
"largeVideo": {
|
||||
"screenIsShared": "Vous êtes en train de partager votre écran",
|
||||
"showMeWhatImSharing": "Me montrer ce que je partage"
|
||||
"showMeWhatImSharing": "M'afficher ce que je partage"
|
||||
},
|
||||
"liveStreaming": {
|
||||
"busy": "Nous tentons de libérer des ressources de diffusion. Veuillez réessayez dans quelques minutes.",
|
||||
@@ -609,13 +667,13 @@
|
||||
"knockingParticipantList": "Liste des participants en attente",
|
||||
"lobbyChatStartedNotification": "Un modérateur dialogue en salle d'attente avec {{attendee}}",
|
||||
"lobbyChatStartedTitle": "Un modérateur dialogue en salle d'attente avec vous.",
|
||||
"lobbyClosed": "La salle d'attente a été fermée.",
|
||||
"nameField": "Saisissez votre nom",
|
||||
"notificationLobbyAccessDenied": "{{targetParticipantName}} a été refusé par {{originParticipantName}}",
|
||||
"notificationLobbyAccessGranted": "{{targetParticipantName}} a été accepté par {{originParticipantName}}",
|
||||
"notificationLobbyDisabled": "Le mode salle d'attente a été désactivé par {{originParticipantName}}",
|
||||
"notificationLobbyEnabled": "Le mode salle d'attente a été activé par {{originParticipantName}}",
|
||||
"notificationTitle": "Salle d'attente",
|
||||
"passwordField": "Veuillez saisir le mot de passe de la réunion",
|
||||
"passwordJoinButton": "Rejoindre",
|
||||
"title": "Salle d'attente",
|
||||
"toggleLabel": "Activer la salle d'attente"
|
||||
@@ -648,6 +706,8 @@
|
||||
"sessionToken": "Token de la session",
|
||||
"start": "Démarrer l'enregistrement",
|
||||
"stop": "Arrêter l'enregistrement",
|
||||
"stopping": "Arrêt de l'enregistrement",
|
||||
"wait": "Patienter pendant la sauvegarde de votre enregistrement.",
|
||||
"yes": "Oui"
|
||||
},
|
||||
"lockRoomPassword": "mot de passe",
|
||||
@@ -669,8 +729,11 @@
|
||||
"connectedTwoMembers": "{{first}} et {{second}} ont rejoint la réunion",
|
||||
"dataChannelClosed": "Qualité vidéo dégradée",
|
||||
"dataChannelClosedDescription": "Le canal de communication avec le Bridge a été interrompu, la qualité vidéo se trouve limitée à sa valeur la plus faible.",
|
||||
"disabledIframe": "L'intégration Iframe est uniquement destinée à des démos, cet appel se terminera dans {{timeout}} minutes.",
|
||||
"disabledIframeSecondary": "L'intégration Iframe de {{domaine}} est uniquement destinée à des démos, cet appel se terminera dans {{timeout}} minutes.",
|
||||
"disconnected": "déconnecté",
|
||||
"displayNotifications": "Afficher les notifications pour",
|
||||
"dontRemindMe": "Ne pas me le rappeler",
|
||||
"focus": "Focus de conférence",
|
||||
"focusFail": "{{component}} n'est pas disponible - réessayez dans {{ms}} sec",
|
||||
"gifsMenu": "GIPHY",
|
||||
@@ -679,6 +742,7 @@
|
||||
"invitedOneMember": "{{name}} a été invité(e)",
|
||||
"invitedThreePlusMembers": "{{name}} et {{count}} autres ont été invités",
|
||||
"invitedTwoMembers": "{{first}} et {{second}} ont été invités",
|
||||
"joinMeeting": "Rejoindre",
|
||||
"kickParticipant": "{{kicked}} a été expulsé par {{kicker}}",
|
||||
"leftOneMember": "{{name}} a quitté la réunion",
|
||||
"leftThreePlusMembers": "{{name}} et beaucoup d'autres ont quitté la réunion",
|
||||
@@ -713,7 +777,6 @@
|
||||
"newDeviceCameraTitle": "Nouvelle caméra détectée",
|
||||
"noiseSuppressionDesktopAudioDescription": "La suppression de bruit ne peut pas être activée en même temps que la partage audio du système, veuillez le désactiver et réessayer.",
|
||||
"noiseSuppressionFailedTitle": "Échec du démarrage de la suppression de bruit",
|
||||
"noiseSuppressionNoTrackDescription": "Veuillez activer votre microphone d'abord.",
|
||||
"noiseSuppressionStereoDescription": "La suppression de bruit d’une source stéréo n’est pas encore supportée.",
|
||||
"oldElectronClientDescription1": "Vous semblez utiliser une ancienne version du client Jitsi Meet qui présente des failles de sécurité connues. Veuillez vous assurer de mettre à jour vers notre ",
|
||||
"oldElectronClientDescription2": "dernière build",
|
||||
@@ -743,7 +806,9 @@
|
||||
"videoUnmuteBlockedDescription": "Le rétablissement de la vidéo a été bloqué temporairement en raison de limites système.",
|
||||
"videoUnmuteBlockedTitle": "Rétablissement de la caméra bloqué !",
|
||||
"viewLobby": "Voir la salle d'attente",
|
||||
"waitingParticipants": "{{waitingParticipants}} personnes"
|
||||
"waitingParticipants": "{{waitingParticipants}} personnes",
|
||||
"whiteboardLimitDescription": "Veuillez sauvegarder votre progression, car la limite d’utilisation du tableau blanc sera bientôt atteinte et celui-ci sera fermé.",
|
||||
"whiteboardLimitTitle": "Utiilisation du tableau blanc"
|
||||
},
|
||||
"participantsPane": {
|
||||
"actions": {
|
||||
@@ -754,6 +819,7 @@
|
||||
"askUnmute": "Demander de réactiver le micro",
|
||||
"audioModeration": "Rouvrir leur micro",
|
||||
"blockEveryoneMicCamera": "Bloquer tous les micros et caméras",
|
||||
"breakoutRooms": "Salles annexes",
|
||||
"invite": "Inviter quelqu'un",
|
||||
"moreModerationActions": "Options de modération supplémentaires",
|
||||
"moreModerationControls": "Options de modération supplémentaires",
|
||||
@@ -771,6 +837,7 @@
|
||||
"headings": {
|
||||
"lobby": "Salle d'attente ({{count}})",
|
||||
"participantsList": "Participants de la réunion ({{count}})",
|
||||
"visitorRequests": "(Demande {{count}} )",
|
||||
"visitors": "Visiteurs {{count}}",
|
||||
"waitingLobby": "Dans la salle d'attente ({{count}})"
|
||||
},
|
||||
@@ -805,8 +872,8 @@
|
||||
"results": {
|
||||
"changeVote": "Changer le vote",
|
||||
"empty": "Il n'y a pas encore de sondages dans cette réunion. Démarrez un sondage ici !",
|
||||
"hideDetailedResults": "Cacher les détails",
|
||||
"showDetailedResults": "Montrer les détails",
|
||||
"hideDetailedResults": "Masquer les détails",
|
||||
"showDetailedResults": "Afficher les détails",
|
||||
"vote": "Voter"
|
||||
}
|
||||
},
|
||||
@@ -864,9 +931,11 @@
|
||||
"lookGood": "Il semble que votre microphone fonctionne correctement",
|
||||
"or": "ou",
|
||||
"premeeting": "Pré-séance",
|
||||
"proceedAnyway": "Continuer quand même",
|
||||
"screenSharingError": "Erreur de partage d'écran:",
|
||||
"showScreen": "Activer l'écran de pré-séance",
|
||||
"startWithPhone": "Commencez avec l'audio du téléphone",
|
||||
"unsafeRoomConsent": "Je comprends les risques et je veux quand même rejoindre cette réunion",
|
||||
"videoOnlyError": "Erreur vidéo:",
|
||||
"videoTrackError": "Impossible de créer une piste vidéo.",
|
||||
"viewAllNumbers": "voir tous les numéros"
|
||||
@@ -929,7 +998,6 @@
|
||||
"limitNotificationDescriptionNative": "En raison d'une forte demande, votre enregistrement sera limité à {{limit}} min. Pour des enregistrements illimités, essayez <3> {{app}} </3>.",
|
||||
"limitNotificationDescriptionWeb": "En raison d'une forte demande, votre enregistrement sera limité à {{limit}} min. Pour des enregistrements illimités, essayez <a href={{url}} rel='noopener noreferrer' target='_blank'> {{app}} </a>.",
|
||||
"linkGenerated": "Nous avons généré un lien à votre enregistrement.",
|
||||
"live": "DIRECT",
|
||||
"localRecordingNoNotificationWarning": "Le démarrage de l’enregistrement ne sera pas annoncé aux autres participants. Vous devrez les informer par vous-même que la réunion sera enregistrée.",
|
||||
"localRecordingNoVideo": "La vidéo n'est pas en cours d’enregistrement",
|
||||
"localRecordingStartWarning": "Assurez-vous d’arrêter l’enregistrement vidéo avant de quitter la réunion afin de pouvoir le sauvegarder.",
|
||||
@@ -946,13 +1014,15 @@
|
||||
"onBy": "{{name}} a démarré l'enregistrement",
|
||||
"onlyRecordSelf": "Enregistrer seulement mon audio et ma vidéo.",
|
||||
"pending": "Préparation de l'enregistrement de la réunion ...",
|
||||
"rec": "REC",
|
||||
"recordAudioAndVideo": "Enregistrer l'audio et la vidéo",
|
||||
"recordTranscription": "Enregistrer la transcription",
|
||||
"saveLocalRecording": "Sauvegarder l’enregistrement local (Beta)",
|
||||
"serviceDescription": "Votre enregistrement sera enregistré par le service dédié",
|
||||
"serviceDescriptionCloud": "Enregistrement Cloud",
|
||||
"serviceDescriptionCloudInfo": "Les conférences enregistrées sont automatiquement supprimées 24h après leur heure d'enregistrement.",
|
||||
"serviceName": "Service d'enregistrement",
|
||||
"sessionAlreadyActive": "Cette session est déjà en cours d'enregistrement ou de diffusion.",
|
||||
"showAdvancedOptions": "Afficher les options avancées",
|
||||
"signIn": "Se connecter",
|
||||
"signOut": "Se déconnecter",
|
||||
"surfaceError": "Veuillez sélectionner l’onglet courant.",
|
||||
@@ -968,8 +1038,14 @@
|
||||
"security": {
|
||||
"about": "Vous pouvez ajouter un mot de passe à votre réunion. Les participants devront fournir le mot de passe avant de pouvoir rejoindre la réunion.",
|
||||
"aboutReadOnly": "Les modérateurs peuvent ajouter un mot de passe à la réunion. Les participants devront fournir le mot de passe avant de pouvoir rejoindre la réunion.",
|
||||
"insecureRoomNameWarning": "Le nom de la salle est peu sûr. Des participants non désirés peuvent rejoindre votre réunion. Pensez à sécuriser votre réunion en cliquant sur le bouton de sécurité.",
|
||||
"title": "Options de sécurité"
|
||||
"insecureRoomNameWarningNative": "Le nom de la réunion n’est pas sûr. Des participants non voulus pourraient rejoindre cette réunion. {{recommendAction}} En apprendre plus sur la sécurisation des réunions.",
|
||||
"insecureRoomNameWarningWeb": "Le nom de la réunion n’est pas sûr. Des participants non voulus pourraient rejoindre cette réunion. {{recommendAction}} En apprendre plus sur la sécurisation des réunions <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">here</a>.",
|
||||
"title": "Options de sécurité",
|
||||
"unsafeRoomActions": {
|
||||
"meeting": "Envisagez de sécuriser votre réunion en utilisant le bouton options de sécurité.",
|
||||
"prejoin": "Envisagez d'utiliser un nom plus unique",
|
||||
"welcome": "Envisagez d'utiliser un nom plus unique ou choisissez en un parmi ceux suggérés"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"audio": "Audio",
|
||||
@@ -1002,7 +1078,7 @@
|
||||
"participantKnocking": "un participant en salle d’attente",
|
||||
"participantLeft": "un participant quitte",
|
||||
"playSounds": "Jouer un son quand",
|
||||
"reactions": "il y a une réaction à la réunion",
|
||||
"reactions": "Il y a une réaction à la réunion",
|
||||
"sameAsSystem": "Identique au système ({{label}})",
|
||||
"selectAudioOutput": "Sortie audio",
|
||||
"selectCamera": "Caméra",
|
||||
@@ -1023,6 +1099,7 @@
|
||||
"alertOk": "D'accord",
|
||||
"alertTitle": "Avertissement",
|
||||
"alertURLText": "L'URL du serveur est invalide",
|
||||
"apply": "Appliquer",
|
||||
"buildInfoSection": "Informations de build",
|
||||
"conferenceSection": "Conférence",
|
||||
"disableCallIntegration": "Désactiver l'intégration d'appels native",
|
||||
@@ -1033,12 +1110,14 @@
|
||||
"displayNamePlaceholderText": "Ex : Jean Dupond",
|
||||
"email": "Email",
|
||||
"emailPlaceholderText": "email@example..com",
|
||||
"gavatarMessage": "Si votre email est associé à un compte Gravatar, nous allons l’utiliser pour afficher votre image de profil.",
|
||||
"goTo": "Aller à",
|
||||
"header": "Paramètres",
|
||||
"help": "Aide",
|
||||
"links": "Liens",
|
||||
"privacy": "Confidentialité",
|
||||
"profileSection": "Profil",
|
||||
"sdkVersion": "Version du SDK",
|
||||
"serverURL": "URL du serveur",
|
||||
"showAdvanced": "Afficher les paramètres avancés",
|
||||
"startCarModeInLowBandwidthMode": "Commencer le mode voiture en mode bande passante réduite",
|
||||
@@ -1091,17 +1170,26 @@
|
||||
"audioOnly": "Activer / Désactiver le mode voix uniquement",
|
||||
"audioRoute": "Sélectionner la source audio",
|
||||
"boo": "Hou",
|
||||
"breakoutRoom": "Rejoindre/quitter une salle annexe",
|
||||
"breakoutRooms": "Rejoindre / quitter une salle annexe",
|
||||
"callQuality": "Ajuster la qualité vidéo",
|
||||
"carmode": "Mode voiture",
|
||||
"cc": "Activer / Désactiver les sous-titres",
|
||||
"chat": "Afficher / Masquer la discussion instantanée",
|
||||
"clap": "Applaudir",
|
||||
"closeChat": "Fermer la discussion instantanée",
|
||||
"closeMoreActions": "Fermer le menu plus d'actions",
|
||||
"closeParticipantsPane": "Fermer le panneau des participants",
|
||||
"collapse": "Plier",
|
||||
"document": "Activer / Désactiver le document partagé",
|
||||
"documentClose": "Fermer le document partagé",
|
||||
"documentOpen": "Ouvrir le document partagé",
|
||||
"download": "Télécharger nos applications",
|
||||
"embedMeeting": "Intégrer la réunion",
|
||||
"endConference": "Terminer la réunion pour tout le monde",
|
||||
"enterFullScreen": "Passer en mode plein écran",
|
||||
"enterTileView": "Passer en vue mosaïque",
|
||||
"exitFullScreen": "Quitter le mode plein écran",
|
||||
"exitTileView": "Quitter la vue mosaïque",
|
||||
"expand": "Développer",
|
||||
"feedback": "Laisser des commentaires",
|
||||
"fullScreen": "Activer / Désactiver le plein écran",
|
||||
@@ -1110,6 +1198,7 @@
|
||||
"hangup": "Quitter la conversation",
|
||||
"heading": "Barre d'outils",
|
||||
"help": "Aide",
|
||||
"hideWhiteboard": "Masquer le tableau blanc",
|
||||
"invite": "Inviter des participants",
|
||||
"kick": "Expulser le participant",
|
||||
"laugh": "Rire",
|
||||
@@ -1119,6 +1208,7 @@
|
||||
"lobbyButton": "Activer / Désactiver le mode salle d'attente",
|
||||
"localRecording": "Activer / Désactiver les contrôles d'enregistrement local",
|
||||
"lockRoom": "Activer / Désactiver le mot de passe de la réunion",
|
||||
"lowerHand": "Baisser la main",
|
||||
"moreActions": "Activer / Désactiver le menu d'actions supplémentaires",
|
||||
"moreActionsMenu": "Menu d'actions supplémentaires",
|
||||
"moreOptions": "Voir plus d'options",
|
||||
@@ -1127,12 +1217,15 @@
|
||||
"muteEveryoneElse": "Couper le micro de tous les autres",
|
||||
"muteEveryoneElsesVideoStream": "Couper la caméra de tous les autres",
|
||||
"muteEveryonesVideoStream": "Couper la caméra de tout le monde",
|
||||
"muteGUMPending": "Connection de votre microphone",
|
||||
"noiseSuppression": "Suppression du bruit",
|
||||
"openChat": "Ouvrir le chat",
|
||||
"participants": "Participants",
|
||||
"pip": "Activer / Désactiver le mode Picture in Picture",
|
||||
"privateMessage": "Envoyer un message privé",
|
||||
"profile": "Éditer votre profil",
|
||||
"raiseHand": "Lever la main",
|
||||
"reactions": "Réactions",
|
||||
"reactionsMenu": "Ouvrir / fermer le menu réactions",
|
||||
"recording": "Activer / Désactiver l'enregistrement",
|
||||
"remoteMute": "Couper le micro du participant",
|
||||
@@ -1146,15 +1239,20 @@
|
||||
"sharedvideo": "Démarrer / Arrêter le partage de vidéo",
|
||||
"shortcuts": "Afficher / Masquer les raccourcis",
|
||||
"show": "Afficher en premier plan",
|
||||
"showWhiteboard": "Afficher le tableux blanc",
|
||||
"silence": "Silence",
|
||||
"speakerStats": "Afficher / Cacher les statistiques de parole",
|
||||
"speakerStats": "Afficher / Masquer les statistiques de parole",
|
||||
"stopScreenSharing": "Arrêter le partage d'écran",
|
||||
"stopSharedVideo": "Arrêter la vidéo partagée",
|
||||
"surprised": "Surpris",
|
||||
"tileView": "Activer / Désactiver la vue mosaïque",
|
||||
"toggleCamera": "Changer de caméra",
|
||||
"toggleFilmstrip": "Afficher ou masquer les vignettes vidéo",
|
||||
"unmute": "Rétablir le son",
|
||||
"videoblur": "Activer / désactiver le floutage",
|
||||
"videomute": "Activer / Couper la vidéo",
|
||||
"whiteboard": "Afficher / Cacher le tableau blanc"
|
||||
"videomuteGUMPending": "Connexion de votre caméra",
|
||||
"videounmute": "Démarrer la vidéo"
|
||||
},
|
||||
"addPeople": "Ajouter des personnes à votre appel",
|
||||
"audioOnlyOff": "Désactiver le mode bande passante réduite",
|
||||
@@ -1167,6 +1265,7 @@
|
||||
"chat": "Ouvrir / Fermer le chat",
|
||||
"clap": "Applaudir",
|
||||
"closeChat": "Fermer le chat",
|
||||
"closeParticipantsPane": "Fermer le panneau des participants",
|
||||
"closeReactionsMenu": "Fermer le menu réactions",
|
||||
"disableNoiseSuppression": "Arrêter la suppression du bruit",
|
||||
"disableReactionSounds": "Vous pouvez interdire les réactions sonores à cette réunion",
|
||||
@@ -1185,7 +1284,7 @@
|
||||
"giphy": "Activer/désactiver le menu GIPHY",
|
||||
"hangup": "Quitter",
|
||||
"help": "Aide",
|
||||
"hideWhiteboard": "Cacher le tableau blanc",
|
||||
"hideWhiteboard": "Masquer le tableau blanc",
|
||||
"invite": "Inviter des participants",
|
||||
"joinBreakoutRoom": "Rejoindre salle annexe",
|
||||
"laugh": "Rire",
|
||||
@@ -1203,6 +1302,7 @@
|
||||
"mute": "Muet / Actif",
|
||||
"muteEveryone": "Couper le micro à tout le monde",
|
||||
"muteEveryonesVideo": "Couper la caméra de tout le monde",
|
||||
"muteGUMPending": "Connection de votre microphone",
|
||||
"noAudioSignalDesc": "Si vous n'avez pas délibérément coupé le son des paramètres du système ou du matériel, envisagez de changer de périphérique utilisé.",
|
||||
"noAudioSignalDescSuggestion": "Si vous n'avez pas délibérément coupé le son des paramètres du système ou du matériel, pensez à utiliser le périphérique suivant :",
|
||||
"noAudioSignalDialInDesc": "Vous pouvez également appeler en utilisant :",
|
||||
@@ -1225,6 +1325,7 @@
|
||||
"reactionLike": "Envoyer réaction approuver",
|
||||
"reactionSilence": "Envoyer réaction silence",
|
||||
"reactionSurprised": "Envoyer réaction surprise",
|
||||
"reactions": "Reactions",
|
||||
"security": "Options de sécurité",
|
||||
"selectBackground": "Sélectionner un arrière-plan",
|
||||
"shareRoom": "Inviter quelqu'un",
|
||||
@@ -1244,8 +1345,11 @@
|
||||
"talkWhileMutedPopup": "Vous voulez parler ? Votre micro est coupé.",
|
||||
"tileViewToggle": "Activer / Désactiver la vue mosaïque",
|
||||
"toggleCamera": "Changer de caméra",
|
||||
"unmute": "Rétablir le son",
|
||||
"videoSettings": "Paramètres vidéo",
|
||||
"videomute": "Démarrer / Arrêter la caméra"
|
||||
"videomute": "Arrêter la caméra",
|
||||
"videomuteGUMPending": "Connexion de votre caméra",
|
||||
"videounmute": "Démarrer la caméra"
|
||||
},
|
||||
"transcribing": {
|
||||
"ccButtonTooltip": "Activer / Désactiver les sous-titres",
|
||||
@@ -1253,7 +1357,8 @@
|
||||
"expandedLabel": "La transcription est actuellement activée",
|
||||
"failedToStart": "Échec de démarrage de la transcription",
|
||||
"labelToolTip": "La transcription de la réunion est en cours",
|
||||
"off": "La transcription désactivée",
|
||||
"off": "La transcription est désactivée",
|
||||
"on": "La transcription est activée",
|
||||
"pending": "Préparation de la transcription de la réunion ...",
|
||||
"sourceLanguageDesc": "Actuellement, la langue de la réunion est sélectionnée à <b>{{sourceLanguage}}</b>. <br/> Vous pouvez la changer à partir de ",
|
||||
"sourceLanguageHere": "ici",
|
||||
@@ -1316,7 +1421,7 @@
|
||||
"domuteVideoOfOthers": "Couper la caméra des autres",
|
||||
"flip": "Miroir",
|
||||
"grantModerator": "Donner des droits de modérateur",
|
||||
"hideSelfView": "Cacher l'affichage de votre propre vidéo",
|
||||
"hideSelfView": "Masquer l'affichage de votre propre vidéo",
|
||||
"kick": "Exclure",
|
||||
"mirrorVideo": "Inverser ma vidéo",
|
||||
"moderator": "Modérateur",
|
||||
@@ -1326,13 +1431,17 @@
|
||||
"remoteControl": "Démarrer / Arrêter le contrôle à distance",
|
||||
"screenSharing": "Cette personne partage son écran",
|
||||
"show": "Afficher en premier plan",
|
||||
"showSelfView": "Montrer votre propre vidéo",
|
||||
"showSelfView": "Afficher votre propre vidéo",
|
||||
"unpinFromStage": "Ne plus garder affiché",
|
||||
"verify": "Vérifier le participant",
|
||||
"videoMuted": "Caméra coupée",
|
||||
"videomute": "Le participant a arrêté la caméra"
|
||||
},
|
||||
"virtualBackground": {
|
||||
"accessibilityLabel": {
|
||||
"currentBackground": "Arrière-plan actuel: {{background}}",
|
||||
"selectBackground": "Sélectionner un arrière-plan"
|
||||
},
|
||||
"addBackground": "Ajouter un arrière-plan",
|
||||
"apply": "Appliquer",
|
||||
"backgroundEffectError": "Erreur dans l'application de l'effet d'arrière-plan.",
|
||||
@@ -1356,7 +1465,14 @@
|
||||
"webAssemblyWarning": "WebAssembly non supporté",
|
||||
"webAssemblyWarningDescription": "WebAssembly invalidé ou non supporté par ce navigateur"
|
||||
},
|
||||
"visitorsLabel": "Nombre de visiteurs: {{count}}",
|
||||
"visitors": {
|
||||
"chatIndicator": "(visiteur)",
|
||||
"labelTooltip": "Nombre de Visiteurs",
|
||||
"notification": {
|
||||
"description": "Pour participer lever la main.",
|
||||
"title": "Vous êtes visiteur dans cette réunion"
|
||||
}
|
||||
},
|
||||
"volumeSlider": "Curseur de volume",
|
||||
"welcomepage": {
|
||||
"accessibilityLabel": {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -222,6 +222,7 @@
|
||||
"Share": "Paylaş",
|
||||
"Submit": "Gönder",
|
||||
"WaitForHostMsg": "Toplantısı henüz başlamadı. Toplantı sahibi sizseniz, lütfen kimlik doğrulaması yapın. Değilseniz lütfen toplantı sahibinin gelmesini bekleyin.",
|
||||
"WaitingForHostButton": "Toplantı sahibini bekle",
|
||||
"WaitingForHostTitle": "Toplantı sahibi bekleniyor ...",
|
||||
"Yes": "Evet",
|
||||
"accessibilityLabel": {
|
||||
|
||||
@@ -219,7 +219,9 @@
|
||||
"joinInBrowser": "Join in browser",
|
||||
"launchMeetingLabel": "How do you want to join this meeting?",
|
||||
"launchWebButton": "Launch in web",
|
||||
"noDesktopApp": "You don’t have the app?",
|
||||
"noMobileApp": "You don’t have the app?",
|
||||
"or": "OR",
|
||||
"termsAndConditions": "By continuing you agree to our <a href='{{termsAndConditionsLink}}' rel='noopener noreferrer' target='_blank'>terms & conditions.</a>",
|
||||
"title": "Launching your meeting in {{app}}...",
|
||||
"titleNew": "Launching your meeting ...",
|
||||
@@ -615,7 +617,7 @@
|
||||
"errorAPI": "An error occurred while accessing your YouTube broadcasts. Please try logging in again.",
|
||||
"errorLiveStreamNotEnabled": "Live Streaming is not enabled on {{email}}. Please enable live streaming or log into an account with live streaming enabled.",
|
||||
"expandedOff": "The live streaming has stopped",
|
||||
"expandedOn": "The meeting is currently being streamed to YouTube.",
|
||||
"expandedOn": "The meeting is currently being live streamed",
|
||||
"expandedPending": "The live streaming is being started...",
|
||||
"failedToStart": "Live Streaming failed to start",
|
||||
"getStreamKeyManually": "We weren’t able to fetch any live streams. Try getting your live stream key from YouTube.",
|
||||
@@ -985,7 +987,7 @@
|
||||
"error": "Recording failed. Please try again.",
|
||||
"errorFetchingLink": "Error fetching recording link.",
|
||||
"expandedOff": "Recording has stopped",
|
||||
"expandedOn": "The meeting is currently being recorded.",
|
||||
"expandedOn": "The meeting is currently being recorded",
|
||||
"expandedPending": "Recording is being started...",
|
||||
"failedToStart": "Recording failed to start",
|
||||
"fileSharingdescription": "Share the recording link with the meeting participants",
|
||||
@@ -1353,13 +1355,9 @@
|
||||
},
|
||||
"transcribing": {
|
||||
"ccButtonTooltip": "Start / Stop subtitles",
|
||||
"error": "Transcribing failed. Please try again.",
|
||||
"expandedLabel": "Transcribing is currently on",
|
||||
"failedToStart": "Transcribing failed to start",
|
||||
"labelToolTip": "The meeting is being transcribed",
|
||||
"off": "Transcribing stopped",
|
||||
"on": "Transcribing started",
|
||||
"pending": "Preparing to transcribe the meeting...",
|
||||
"sourceLanguageDesc": "Currently the meeting language is set to <b>{{sourceLanguage}}</b>. <br/> You can change it from ",
|
||||
"sourceLanguageHere": "here",
|
||||
"start": "Start showing subtitles",
|
||||
|
||||
@@ -229,6 +229,9 @@ export default class LargeVideoManager {
|
||||
|
||||
preUpdate.then(() => {
|
||||
const { id, stream, videoType, resolve } = this.newStreamData;
|
||||
|
||||
this.newStreamData = null;
|
||||
|
||||
const state = APP.store.getState();
|
||||
const shouldHideSelfView = getHideSelfView(state);
|
||||
const localId = getLocalParticipant(state)?.id;
|
||||
@@ -239,8 +242,6 @@ export default class LargeVideoManager {
|
||||
// the video container type (Etherpad, SharedVideo, VideoContainer).
|
||||
const isVideoContainer = LargeVideoManager.isVideoContainer(videoType);
|
||||
|
||||
this.newStreamData = null;
|
||||
|
||||
logger.debug(`Scheduled large video update for ${id}`);
|
||||
this.state = videoType;
|
||||
// eslint-disable-next-line no-shadow
|
||||
@@ -287,10 +288,6 @@ export default class LargeVideoManager {
|
||||
|| streamingStatusActive
|
||||
);
|
||||
|
||||
this.videoTrack?.jitsiTrack?.getVideoType() === VIDEO_TYPE.DESKTOP
|
||||
&& logger.debug(`Remote track ${videoTrack?.jitsiTrack}, isVideoMuted=${isVideoMuted},`
|
||||
+ ` streamingStatusActive=${streamingStatusActive}, isVideoRenderable=${isVideoRenderable}`);
|
||||
|
||||
const isAudioOnly = APP.conference.isAudioOnly();
|
||||
|
||||
// Multi-stream is not supported on plan-b endpoints even if its is enabled via config.js. A virtual
|
||||
@@ -303,6 +300,10 @@ export default class LargeVideoManager {
|
||||
= isVideoContainer
|
||||
&& ((isAudioOnly && videoType !== VIDEO_TYPE.DESKTOP) || !isVideoRenderable || legacyScreenshare);
|
||||
|
||||
logger.debug(`scheduleLargeVideoUpdate: Remote track ${videoTrack?.jitsiTrack}, isVideoMuted=${
|
||||
isVideoMuted}, streamingStatusActive=${streamingStatusActive}, isVideoRenderable=${
|
||||
isVideoRenderable}, showAvatar=${showAvatar}`);
|
||||
|
||||
let promise;
|
||||
|
||||
// do not show stream if video is muted
|
||||
|
||||
@@ -26,6 +26,13 @@ const FADE_DURATION_MS = 300;
|
||||
|
||||
const logger = Logger.getLogger(__filename);
|
||||
|
||||
/**
|
||||
* List of container events that we are going to process for the large video.
|
||||
*
|
||||
* NOTE: Currently used only for logging for debug purposes.
|
||||
*/
|
||||
const containerEvents = [ 'abort', 'canplaythrough', 'ended', 'error', 'stalled', 'suspend', 'waiting' ];
|
||||
|
||||
/**
|
||||
* Returns an array of the video dimensions, so that it keeps it's aspect
|
||||
* ratio and fits available area with it's larger dimension. This method
|
||||
@@ -242,11 +249,18 @@ export class VideoContainer extends LargeContainer {
|
||||
this.wrapperParent = document.getElementById('largeVideoElementsContainer');
|
||||
this.avatarHeight = document.getElementById('dominantSpeakerAvatarContainer').getBoundingClientRect().height;
|
||||
this.video.onplaying = function(event) {
|
||||
logger.debug('Large video is playing!');
|
||||
if (typeof resizeContainer === 'function') {
|
||||
resizeContainer(event);
|
||||
}
|
||||
};
|
||||
|
||||
containerEvents.forEach(event => {
|
||||
this.video.addEventListener(event, () => {
|
||||
logger.debug(`${event} handler was called for the large video.`);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* A Set of functions to invoke when the video element resizes.
|
||||
*
|
||||
@@ -255,6 +269,7 @@ export class VideoContainer extends LargeContainer {
|
||||
this._resizeListeners = new Set();
|
||||
|
||||
this.video.onresize = this._onResize.bind(this);
|
||||
this._play = this._play.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -455,6 +470,30 @@ export class VideoContainer extends LargeContainer {
|
||||
this._resizeListeners.delete(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the large video element.
|
||||
*
|
||||
* @param {number} retries - Number of retries to play the large video if play fails.
|
||||
* @returns {void}
|
||||
*/
|
||||
_play(retries = 0) {
|
||||
this.video.play()
|
||||
.then(() => {
|
||||
logger.debug(`Successfully played large video after ${retries + 1} retries!`);
|
||||
})
|
||||
.catch(e => {
|
||||
if (retries < 3) {
|
||||
logger.debug(`Error while trying to playing the large video. Will retry after 1s. Retries: ${
|
||||
retries}. Error: ${e}`);
|
||||
window.setTimeout(() => {
|
||||
this._play(retries + 1);
|
||||
}, 1000);
|
||||
} else {
|
||||
logger.error(`Error while trying to playing the large video after 3 retries: ${e}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update video stream.
|
||||
* @param {string} userID
|
||||
@@ -464,6 +503,8 @@ export class VideoContainer extends LargeContainer {
|
||||
setStream(userID, stream, videoType) {
|
||||
this.userId = userID;
|
||||
if (this.stream === stream && !stream?.forceStreamToReattach) {
|
||||
logger.debug(`SetStream on the large video for user ${userID} ignored: the stream is not changed!`);
|
||||
|
||||
// Handles the use case for the remote participants when the
|
||||
// videoType is received with delay after turning on/off the
|
||||
// desktop sharing.
|
||||
@@ -488,22 +529,28 @@ export class VideoContainer extends LargeContainer {
|
||||
this.videoType = videoType;
|
||||
|
||||
if (!stream) {
|
||||
logger.debug('SetStream on the large video is called without a stream argument!');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.video) {
|
||||
logger.debug(`Attaching a remote track to the large video for user ${userID}`);
|
||||
stream.attach(this.video).catch(error => {
|
||||
logger.error(`Attaching the remote track ${stream} has failed with `, error);
|
||||
logger.error(`Attaching the remote track ${stream} to large video has failed with `, error);
|
||||
});
|
||||
|
||||
// Ensure large video gets play() called on it when a new stream is attached to it. This is necessary in the
|
||||
// case of Safari as autoplay doesn't kick-in automatically on Safari 15 and newer versions.
|
||||
browser.isWebKitBased() && this.video.play();
|
||||
browser.isWebKitBased() && this._play();
|
||||
|
||||
const flipX = stream.isLocal() && this.localFlipX && !this.isScreenSharing();
|
||||
|
||||
this.video.style.transform = flipX ? 'scaleX(-1)' : 'none';
|
||||
this._updateBackground();
|
||||
} else {
|
||||
logger.debug(`SetStream on the large video won't attach a track for ${
|
||||
userID} because no large video element was found!`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -154,6 +154,8 @@ const VideoLayout = {
|
||||
|
||||
updateLargeVideo(id, forceUpdate, forceStreamToReattach = false) {
|
||||
if (!largeVideo) {
|
||||
logger.debug(`Ignoring large video update with user id ${id}: large video not initialized yet!`);
|
||||
|
||||
return;
|
||||
}
|
||||
const currentContainer = largeVideo.getCurrentContainer();
|
||||
|
||||
10
package-lock.json
generated
10
package-lock.json
generated
@@ -60,7 +60,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/v1759.0.0+fc2f2490/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1761.0.0+f470b5f4/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -12904,8 +12904,8 @@
|
||||
},
|
||||
"node_modules/lib-jitsi-meet": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1759.0.0+fc2f2490/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-YCFcx5SxyFDJXc0zeTIvF8jxlwgqgFlEq8UFCa2c68gpEwOE5iSOVn9tQT9jXXk9FAJhN9aUr5e2ar34sUYl3w==",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1761.0.0+f470b5f4/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-Ig7zATGaajDlqx76JOWCb0DK6KQL1yVUriwdXQI/MxOMf6EQJ9Z9dPqGRxZRVk3mkJ59GHI/tf2ERfip1zHhdQ==",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@@ -29472,8 +29472,8 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1759.0.0+fc2f2490/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-YCFcx5SxyFDJXc0zeTIvF8jxlwgqgFlEq8UFCa2c68gpEwOE5iSOVn9tQT9jXXk9FAJhN9aUr5e2ar34sUYl3w==",
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1761.0.0+f470b5f4/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-Ig7zATGaajDlqx76JOWCb0DK6KQL1yVUriwdXQI/MxOMf6EQJ9Z9dPqGRxZRVk3mkJ59GHI/tf2ERfip1zHhdQ==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "2.2.1",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
|
||||
@@ -66,7 +66,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/v1759.0.0+fc2f2490/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1761.0.0+f470b5f4/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
|
||||
@@ -131,19 +131,30 @@ export interface IMobileDynamicLink {
|
||||
|
||||
export interface IDeeplinkingPlatformConfig {
|
||||
appName: string;
|
||||
appScheme: string;
|
||||
}
|
||||
|
||||
export interface IDeeplinkingMobileConfig extends IDeeplinkingPlatformConfig {
|
||||
appPackage?: string;
|
||||
appScheme: string;
|
||||
downloadLink: string;
|
||||
dynamicLink?: IMobileDynamicLink;
|
||||
fDroidUrl?: string;
|
||||
}
|
||||
|
||||
export interface IDesktopDownloadConfig {
|
||||
linux?: string;
|
||||
macos?: string;
|
||||
windows?: string;
|
||||
}
|
||||
|
||||
export interface IDeeplinkingDesktopConfig extends IDeeplinkingPlatformConfig {
|
||||
download?: IDesktopDownloadConfig;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface IDeeplinkingConfig {
|
||||
android?: IDeeplinkingMobileConfig;
|
||||
desktop?: IDeeplinkingPlatformConfig;
|
||||
desktop?: IDeeplinkingDesktopConfig;
|
||||
disabled?: boolean;
|
||||
hideLogo?: boolean;
|
||||
ios?: IDeeplinkingMobileConfig;
|
||||
@@ -583,7 +594,6 @@ export interface IConfig {
|
||||
transcribingEnabled?: boolean;
|
||||
transcription?: {
|
||||
autoTranscribeOnRecord?: boolean;
|
||||
disableStartForAll?: boolean;
|
||||
enabled?: boolean;
|
||||
preferredLanguage?: string;
|
||||
translationLanguages?: Array<string>;
|
||||
|
||||
@@ -5,8 +5,8 @@ import { NOTIFY_CLICK_MODE } from '../../toolbox/constants';
|
||||
import {
|
||||
IConfig,
|
||||
IDeeplinkingConfig,
|
||||
IDeeplinkingDesktopConfig,
|
||||
IDeeplinkingMobileConfig,
|
||||
IDeeplinkingPlatformConfig,
|
||||
NotifyClickButton,
|
||||
ToolbarButton
|
||||
} from './configType';
|
||||
@@ -94,13 +94,21 @@ export function areAudioLevelsEnabled(state: IReduxState): boolean {
|
||||
* @returns {void}
|
||||
*/
|
||||
export function _setDeeplinkingDefaults(deeplinking: IDeeplinkingConfig) {
|
||||
const {
|
||||
desktop = {} as IDeeplinkingPlatformConfig,
|
||||
android = {} as IDeeplinkingMobileConfig,
|
||||
ios = {} as IDeeplinkingMobileConfig
|
||||
} = deeplinking;
|
||||
deeplinking.desktop = deeplinking.desktop || {} as IDeeplinkingDesktopConfig;
|
||||
deeplinking.android = deeplinking.android || {} as IDeeplinkingMobileConfig;
|
||||
deeplinking.ios = deeplinking.ios || {} as IDeeplinkingMobileConfig;
|
||||
|
||||
const { android, desktop, ios } = deeplinking;
|
||||
|
||||
desktop.appName = desktop.appName || 'Jitsi Meet';
|
||||
desktop.appScheme = desktop.appScheme || 'jitsi-meet';
|
||||
desktop.download = desktop.download || {};
|
||||
desktop.download.windows = desktop.download.windows
|
||||
|| 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet.exe';
|
||||
desktop.download.macos = desktop.download.macos
|
||||
|| 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet.dmg';
|
||||
desktop.download.linux = desktop.download.linux
|
||||
|| 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet-x86_64.AppImage';
|
||||
|
||||
ios.appName = ios.appName || 'Jitsi Meet';
|
||||
ios.appScheme = ios.appScheme || 'org.jitsi.meet';
|
||||
|
||||
@@ -14,8 +14,8 @@ import {
|
||||
import {
|
||||
IConfig,
|
||||
IDeeplinkingConfig,
|
||||
IDeeplinkingDesktopConfig,
|
||||
IDeeplinkingMobileConfig,
|
||||
IDeeplinkingPlatformConfig,
|
||||
IMobileDynamicLink,
|
||||
ToolbarButton
|
||||
} from './configType';
|
||||
@@ -295,7 +295,7 @@ function _translateInterfaceConfig(oldValue: IConfig) {
|
||||
} else {
|
||||
const disabled = Boolean(oldValue.disableDeepLinking);
|
||||
const deeplinking: IDeeplinkingConfig = {
|
||||
desktop: {} as IDeeplinkingPlatformConfig,
|
||||
desktop: {} as IDeeplinkingDesktopConfig,
|
||||
hideLogo: false,
|
||||
disabled,
|
||||
android: {} as IDeeplinkingMobileConfig,
|
||||
|
||||
@@ -90,6 +90,12 @@ export const HELP_BUTTON_ENABLED = 'help.enabled';
|
||||
*/
|
||||
export const INVITE_ENABLED = 'invite.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if dial-in invite functionality should be enabled.
|
||||
* Default: enabled (true).
|
||||
*/
|
||||
export const INVITE_DIAL_IN_ENABLED = 'invite-dial-in.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if recording should be enabled in iOS.
|
||||
* Default: disabled (false).
|
||||
|
||||
@@ -683,7 +683,7 @@ function _participantJoinedOrUpdated(store: IStore, next: Function, action: AnyA
|
||||
|
||||
// Only run this if the config is populated, otherwise we preload external resources
|
||||
// even if disableThirdPartyRequests is set to true in config
|
||||
if (Object.keys(getState()['features/base/config']).length) {
|
||||
if (getState()['features/base/config']?.hosts) {
|
||||
const { disableThirdPartyRequests } = getState()['features/base/config'];
|
||||
|
||||
if (!disableThirdPartyRequests && (avatarURL || email || id || name)) {
|
||||
|
||||
@@ -10,6 +10,8 @@ if (userAgent.match(/Android/i)) {
|
||||
OS = 'macos';
|
||||
} else if (userAgent.match(/Windows/i)) {
|
||||
OS = 'windows';
|
||||
} else if (userAgent.match(/Linux/i)) {
|
||||
OS = 'linux';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import React, { Component } from 'react';
|
||||
import { TouchableOpacity, View, ViewStyle } from 'react-native';
|
||||
|
||||
import TranscribingLabel from '../../../transcribing/components/TranscribingLabel.native';
|
||||
import VideoQualityLabel from '../../../video-quality/components/VideoQualityLabel.native';
|
||||
|
||||
import InsecureRoomNameLabel from './InsecureRoomNameLabel';
|
||||
import { LABEL_ID_INSECURE_ROOM_NAME, LABEL_ID_QUALITY, LABEL_ID_TRANSCRIBING, LabelHitSlop } from './constants';
|
||||
import { LABEL_ID_INSECURE_ROOM_NAME, LABEL_ID_QUALITY, LabelHitSlop } from './constants';
|
||||
import styles from './styles';
|
||||
|
||||
interface IProps {
|
||||
@@ -33,13 +32,6 @@ class Labels extends Component<IProps> {
|
||||
<View
|
||||
pointerEvents = 'box-none'
|
||||
style = { styles.indicatorContainer as ViewStyle }>
|
||||
<TouchableOpacity
|
||||
hitSlop = { LabelHitSlop }
|
||||
onPress = {
|
||||
this.props.createOnPress(LABEL_ID_TRANSCRIBING)
|
||||
} >
|
||||
<TranscribingLabel />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
hitSlop = { LabelHitSlop }
|
||||
onPress = {
|
||||
|
||||
@@ -2,7 +2,6 @@ import React from 'react';
|
||||
|
||||
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
|
||||
import RecordingExpandedLabel from '../../../recording/components/native/RecordingExpandedLabel';
|
||||
import TranscribingExpandedLabel from '../../../transcribing/components/TranscribingExpandedLabel.native';
|
||||
import VideoQualityExpandedLabel from '../../../video-quality/components/VideoQualityExpandedLabel.native';
|
||||
|
||||
import InsecureRoomNameExpandedLabel from './InsecureRoomNameExpandedLabel';
|
||||
@@ -23,7 +22,6 @@ export const EXPANDED_LABEL_TIMEOUT = 5000;
|
||||
export const LABEL_ID_QUALITY = 'quality';
|
||||
export const LABEL_ID_RECORDING = 'recording';
|
||||
export const LABEL_ID_STREAMING = 'streaming';
|
||||
export const LABEL_ID_TRANSCRIBING = 'transcribing';
|
||||
export const LABEL_ID_INSECURE_ROOM_NAME = 'insecure-room-name';
|
||||
export const LABEL_ID_RAISED_HANDS_COUNT = 'raised-hands-count';
|
||||
export const LABEL_ID_VISITORS_COUNT = 'visitors-count';
|
||||
@@ -58,9 +56,6 @@ export const EXPANDED_LABELS: {
|
||||
},
|
||||
alwaysOn: true
|
||||
},
|
||||
[LABEL_ID_TRANSCRIBING]: {
|
||||
component: TranscribingExpandedLabel
|
||||
},
|
||||
[LABEL_ID_INSECURE_ROOM_NAME]: {
|
||||
component: InsecureRoomNameExpandedLabel
|
||||
},
|
||||
|
||||
@@ -9,7 +9,6 @@ import HighlightButton from '../../../recording/components/Recording/web/Highlig
|
||||
import RecordingLabel from '../../../recording/components/web/RecordingLabel';
|
||||
import { showToolbox } from '../../../toolbox/actions.web';
|
||||
import { isToolboxVisible } from '../../../toolbox/functions.web';
|
||||
import TranscribingLabel from '../../../transcribing/components/TranscribingLabel.web';
|
||||
import VideoQualityLabel from '../../../video-quality/components/VideoQualityLabel.web';
|
||||
import VisitorsCountLabel from '../../../visitors/components/web/VisitorsCountLabel';
|
||||
import ConferenceTimer from '../ConferenceTimer';
|
||||
@@ -83,10 +82,6 @@ const COMPONENTS: Array<{
|
||||
Component: RaisedHandsCountLabel,
|
||||
id: 'raised-hands-count'
|
||||
},
|
||||
{
|
||||
Component: TranscribingLabel,
|
||||
id: 'transcribing'
|
||||
},
|
||||
{
|
||||
Component: VideoQualityLabel,
|
||||
id: 'video-quality'
|
||||
|
||||
@@ -11,6 +11,7 @@ import { IDeeplinkingConfig } from '../../base/config/configType';
|
||||
import { getLegalUrls } from '../../base/config/functions.any';
|
||||
import { isSupportedBrowser } from '../../base/environment/environment';
|
||||
import { translate, translateToHTML } from '../../base/i18n/functions';
|
||||
import Platform from '../../base/react/Platform.web';
|
||||
import { withPixelLineHeight } from '../../base/styles/functions.web';
|
||||
import Button from '../../base/ui/components/web/Button';
|
||||
import { BUTTON_TYPES } from '../../base/ui/constants.any';
|
||||
@@ -85,6 +86,14 @@ const DeepLinkingDesktopPage: React.FC<WithTranslation> = ({ t }) => {
|
||||
const deeplinkingCfg = useSelector((state: IReduxState) =>
|
||||
state['features/base/config']?.deeplinking || {} as IDeeplinkingConfig);
|
||||
|
||||
const generateDownloadURL = useCallback(() => {
|
||||
const downloadCfg = deeplinkingCfg.desktop?.download;
|
||||
|
||||
if (downloadCfg) {
|
||||
return downloadCfg[Platform.OS as keyof typeof downloadCfg];
|
||||
}
|
||||
}, [ deeplinkingCfg ]);
|
||||
|
||||
const legalUrls = useSelector(getLegalUrls);
|
||||
|
||||
const { hideLogo, desktop } = deeplinkingCfg;
|
||||
@@ -134,6 +143,16 @@ const DeepLinkingDesktopPage: React.FC<WithTranslation> = ({ t }) => {
|
||||
: t(`${_TNS}.descriptionWithoutWeb`, { app: desktop?.appName })
|
||||
}
|
||||
</div>
|
||||
<div className = { styles.descriptionLabel }>
|
||||
{
|
||||
t(`${_TNS}.noDesktopApp`)
|
||||
}
|
||||
<a href = { generateDownloadURL() }>
|
||||
{
|
||||
t(`${_TNS}.downloadApp`)
|
||||
}
|
||||
</a>
|
||||
</div>
|
||||
<div className = { styles.buttonsContainer }>
|
||||
<Button
|
||||
label = { t(`${_TNS}.tryAgainButton`) }
|
||||
|
||||
@@ -211,7 +211,7 @@ const DeepLinkingMobilePage: React.FC<WithTranslation> = ({ t }) => {
|
||||
</a>
|
||||
{isSupportedMobileBrowser() ? (
|
||||
<div className = { styles.supportedBrowserContent }>
|
||||
<div className = { styles.labelOr }>OR</div>
|
||||
<div className = { styles.labelOr }>{ t(`${_TNS}.or`) }</div>
|
||||
<a
|
||||
className = { styles.linkWrapper }
|
||||
onClick = { onLaunchWeb }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IReduxState } from '../app/types';
|
||||
import { isMobileBrowser } from '../base/environment/utils';
|
||||
import { browser } from '../base/lib-jitsi-meet';
|
||||
import Platform from '../base/react/Platform';
|
||||
import { URI_PROTOCOL_PATTERN } from '../base/util/uri';
|
||||
import { isVpaasMeeting } from '../jaas/functions';
|
||||
@@ -63,6 +64,7 @@ export function getDeepLinkingPage(state: IReduxState) {
|
||||
if (launchInWeb
|
||||
|| !room
|
||||
|| state['features/base/config'].deeplinking?.disabled
|
||||
|| browser.isElectron()
|
||||
|| (isVpaasMeeting(state) && (!appScheme || appScheme === 'com.8x8.meet'))) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { IReduxState } from '../app/types';
|
||||
import { URI_PROTOCOL_PATTERN } from '../base/util/uri';
|
||||
|
||||
/**
|
||||
* Opens the desktop app.
|
||||
*
|
||||
@@ -6,5 +9,17 @@
|
||||
* with false otherwise.
|
||||
*/
|
||||
export function _openDesktopApp(_state: Object) {
|
||||
const state = _state as IReduxState;
|
||||
const deeplinkingDesktop = state['features/base/config'].deeplinking?.desktop;
|
||||
|
||||
if (deeplinkingDesktop?.enabled) {
|
||||
const { appScheme } = deeplinkingDesktop;
|
||||
const regex = new RegExp(URI_PROTOCOL_PATTERN, 'gi');
|
||||
|
||||
window.location.href = window.location.href.replace(regex, `${appScheme}:`);
|
||||
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ const ConferenceID: React.FC<IProps> = ({ conferenceID, t }) => {
|
||||
return (
|
||||
<div className = { styles.container }>
|
||||
<div className = { styles.descriptionLabel }>
|
||||
To join the meeting via phone, dial one of these numbers and then enter the pin
|
||||
{ t('info.dialANumber') }
|
||||
</div>
|
||||
<div className = { styles.separator } />
|
||||
<div className = { styles.pinLabel }>
|
||||
|
||||
@@ -571,12 +571,13 @@ export function searchDirectory( // eslint-disable-line max-params
|
||||
* @param {IReduxState} state - The current state.
|
||||
* @param {string} inviteUrl - The conference/location URL.
|
||||
* @param {boolean} useHtml - Whether to return html text.
|
||||
* @param {boolean} skipDialIn - Whether to skip dial-in options or not.
|
||||
* @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: IReduxState, inviteUrl: string, useHtml?: boolean): Promise<string> {
|
||||
export function getShareInfoText(
|
||||
state: IReduxState, inviteUrl: string, useHtml?: boolean, skipDialIn?: boolean): Promise<string> {
|
||||
let roomUrl = _decodeRoomURI(inviteUrl);
|
||||
const includeDialInfo = state['features/base/config'] !== undefined;
|
||||
|
||||
if (useHtml) {
|
||||
roomUrl = `<a href="${roomUrl}">${roomUrl}</a>`;
|
||||
@@ -584,85 +585,72 @@ export function getShareInfoText(state: IReduxState, inviteUrl: string, useHtml?
|
||||
|
||||
let infoText = i18next.t('share.mainText', { roomUrl });
|
||||
|
||||
if (includeDialInfo) {
|
||||
const { room } = parseURIString(inviteUrl);
|
||||
let numbersPromise;
|
||||
let hasPaymentError = false;
|
||||
const { room } = parseURIString(inviteUrl);
|
||||
const { dialInConfCodeUrl, dialInNumbersUrl, hosts } = state['features/base/config'];
|
||||
const { locationURL = {} } = state['features/base/connection'];
|
||||
const mucURL = hosts?.muc;
|
||||
|
||||
if (state['features/invite'].numbers
|
||||
&& state['features/invite'].conferenceID) {
|
||||
numbersPromise = Promise.resolve(state['features/invite']);
|
||||
} else {
|
||||
// we are requesting numbers and conferenceId directly
|
||||
// not using updateDialInNumbers, because custom room
|
||||
// is specified and we do not want to store the data
|
||||
// in the state
|
||||
const { dialInConfCodeUrl, dialInNumbersUrl, hosts }
|
||||
= state['features/base/config'];
|
||||
const { locationURL = {} } = state['features/base/connection'];
|
||||
const mucURL = hosts?.muc;
|
||||
|
||||
if (!dialInConfCodeUrl || !dialInNumbersUrl || !mucURL) {
|
||||
// URLs for fetching dial in numbers not defined
|
||||
return Promise.resolve(infoText);
|
||||
}
|
||||
|
||||
numbersPromise = Promise.all([
|
||||
getDialInNumbers(dialInNumbersUrl, room, mucURL), // @ts-ignore
|
||||
getDialInConferenceID(dialInConfCodeUrl, room, mucURL, locationURL)
|
||||
]).then(([ numbers, {
|
||||
conference, id, message } ]) => {
|
||||
|
||||
if (!conference || !id) {
|
||||
return Promise.reject(message);
|
||||
}
|
||||
|
||||
return {
|
||||
numbers,
|
||||
conferenceID: id
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return numbersPromise.then(
|
||||
({ conferenceID, numbers }) => {
|
||||
const phoneNumber = _getDefaultPhoneNumber(numbers) || '';
|
||||
|
||||
return `${
|
||||
i18next.t('info.dialInNumber')} ${
|
||||
phoneNumber} ${
|
||||
i18next.t('info.dialInConferenceID')} ${
|
||||
conferenceID}#\n\n`;
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('Error fetching numbers or conferenceID', error);
|
||||
hasPaymentError = error?.status === StatusCode.PaymentRequired;
|
||||
})
|
||||
.then(defaultDialInNumber => {
|
||||
if (hasPaymentError) {
|
||||
infoText += `${
|
||||
i18next.t('info.dialInNumber')} ${i18next.t('info.reachedLimit')} ${
|
||||
i18next.t('info.upgradeOptions')} ${UPGRADE_OPTIONS_TEXT}`;
|
||||
|
||||
return infoText;
|
||||
}
|
||||
|
||||
let dialInfoPageUrl = getDialInfoPageURL(state, room);
|
||||
|
||||
if (useHtml) {
|
||||
dialInfoPageUrl
|
||||
= `<a href="${dialInfoPageUrl}">${dialInfoPageUrl}</a>`;
|
||||
}
|
||||
|
||||
infoText += i18next.t('share.dialInfoText', {
|
||||
defaultDialInNumber,
|
||||
dialInfoPageUrl });
|
||||
|
||||
return infoText;
|
||||
});
|
||||
if (skipDialIn || !dialInConfCodeUrl || !dialInNumbersUrl || !mucURL) {
|
||||
// URLs for fetching dial in numbers not defined.
|
||||
return Promise.resolve(infoText);
|
||||
}
|
||||
|
||||
return Promise.resolve(infoText);
|
||||
let hasPaymentError = false;
|
||||
|
||||
// We are requesting numbers and conferenceId directly
|
||||
// not using updateDialInNumbers, because custom room
|
||||
// is specified and we do not want to store the data
|
||||
// in the state.
|
||||
const numbersPromise = Promise.all([
|
||||
getDialInNumbers(dialInNumbersUrl, room, mucURL), // @ts-ignore
|
||||
getDialInConferenceID(dialInConfCodeUrl, room, mucURL, locationURL)
|
||||
]).then(([ numbers, {
|
||||
conference, id, message } ]) => {
|
||||
|
||||
if (!conference || !id) {
|
||||
return Promise.reject(message);
|
||||
}
|
||||
|
||||
return {
|
||||
numbers,
|
||||
conferenceID: id
|
||||
};
|
||||
});
|
||||
|
||||
return numbersPromise.then(({ conferenceID, numbers }) => {
|
||||
const phoneNumber = _getDefaultPhoneNumber(numbers) || '';
|
||||
|
||||
return `${
|
||||
i18next.t('info.dialInNumber')} ${
|
||||
phoneNumber} ${
|
||||
i18next.t('info.dialInConferenceID')} ${
|
||||
conferenceID}#\n\n`;
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('Error fetching numbers or conferenceID', error);
|
||||
hasPaymentError = error?.status === StatusCode.PaymentRequired;
|
||||
})
|
||||
.then(defaultDialInNumber => {
|
||||
if (hasPaymentError) {
|
||||
infoText += `${
|
||||
i18next.t('info.dialInNumber')} ${i18next.t('info.reachedLimit')} ${
|
||||
i18next.t('info.upgradeOptions')} ${UPGRADE_OPTIONS_TEXT}`;
|
||||
|
||||
return infoText;
|
||||
}
|
||||
|
||||
let dialInfoPageUrl = getDialInfoPageURL(state, room);
|
||||
|
||||
if (useHtml) {
|
||||
dialInfoPageUrl = `<a href="${dialInfoPageUrl}">${dialInfoPageUrl}</a>`;
|
||||
}
|
||||
|
||||
infoText += i18next.t('share.dialInfoText', {
|
||||
defaultDialInNumber,
|
||||
dialInfoPageUrl });
|
||||
|
||||
return infoText;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,14 +5,7 @@ import { IReduxState } from '../../app/types';
|
||||
import { JitsiRecordingConstants } from '../../base/lib-jitsi-meet';
|
||||
import { getSessionStatusToShow } from '../functions';
|
||||
|
||||
/**
|
||||
* NOTE: Web currently renders multiple indicators if multiple recording
|
||||
* sessions are running. This is however may not be a good UX as it's not
|
||||
* obvious why there are multiple similar 'REC' indicators rendered. Mobile
|
||||
* only renders one indicator if there is at least one recording session
|
||||
* running. These boolean are shared across the two components to make it
|
||||
* easier to align web's behaviour to mobile's later if necessary.
|
||||
*/
|
||||
|
||||
interface IProps extends WithTranslation {
|
||||
|
||||
/**
|
||||
@@ -20,6 +13,11 @@ interface IProps extends WithTranslation {
|
||||
*/
|
||||
_iAmRecorder: boolean;
|
||||
|
||||
/**
|
||||
* Whether this meeting is being transcribed.
|
||||
*/
|
||||
_isTranscribing: boolean;
|
||||
|
||||
/**
|
||||
* The status of the higher priority session.
|
||||
*/
|
||||
@@ -119,7 +117,7 @@ export default class AbstractRecordingLabel extends Component<IProps, IState> {
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
return this.props._status && !this.state.staleLabel && !this.props._iAmRecorder
|
||||
return (this.props._status || this.props._isTranscribing) && !this.state.staleLabel && !this.props._iAmRecorder
|
||||
? this._renderLabel() : null;
|
||||
}
|
||||
|
||||
@@ -177,6 +175,7 @@ export function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
|
||||
return {
|
||||
_iAmRecorder: Boolean(state['features/base/config'].iAmRecorder),
|
||||
_isTranscribing: state['features/transcribing'].isTranscribing,
|
||||
_status: getSessionStatusToShow(state, mode)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -125,6 +125,7 @@ export default class AbstractRecordButton<P extends IProps> extends AbstractButt
|
||||
* }}
|
||||
*/
|
||||
export function _mapStateToProps(state: IReduxState) {
|
||||
const _isTranscribing = state['features/transcribing'].isTranscribing;
|
||||
const {
|
||||
disabled: _disabled,
|
||||
tooltip: _tooltip,
|
||||
@@ -134,7 +135,7 @@ export function _mapStateToProps(state: IReduxState) {
|
||||
return {
|
||||
_disabled,
|
||||
_isRecordingRunning: Boolean(getActiveSession(state, JitsiRecordingConstants.mode.FILE))
|
||||
|| LocalRecordingManager.isRecordingLocally(),
|
||||
|| LocalRecordingManager.isRecordingLocally() || _isTranscribing,
|
||||
_tooltip,
|
||||
visible
|
||||
};
|
||||
|
||||
@@ -196,7 +196,7 @@ class AbstractStartRecordingDialogContent extends Component<IProps, IState> {
|
||||
this._onToggleShowOptions = this._onToggleShowOptions.bind(this);
|
||||
|
||||
this.state = {
|
||||
showAdvancedOptions: false
|
||||
showAdvancedOptions: true
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { IReduxState, IStore } from '../../../app/types';
|
||||
import { IJitsiConference } from '../../../base/conference/reducer';
|
||||
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
|
||||
import { setVideoMuted } from '../../../base/media/actions';
|
||||
import { setRequestingSubtitles } from '../../../subtitles/actions.any';
|
||||
import { stopLocalVideoRecording } from '../../actions';
|
||||
import { getActiveSession } from '../../functions';
|
||||
import { ISessionData } from '../../reducer';
|
||||
@@ -89,6 +90,9 @@ export default class AbstractStopRecordingDialog<P extends IProps>
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this should be an action in transcribing. -saghul
|
||||
this.props.dispatch(setRequestingSubtitles(false, false, null));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,11 @@ import { getSessionStatusToShow } from '../../functions';
|
||||
|
||||
interface IProps extends AbstractProps {
|
||||
|
||||
/**
|
||||
* Whether this meeting is being transcribed.
|
||||
*/
|
||||
_isTranscribing: boolean;
|
||||
|
||||
/**
|
||||
* The status of the highermost priority session.
|
||||
*/
|
||||
@@ -60,7 +65,13 @@ class RecordingExpandedLabel extends ExpandedLabel<IProps> {
|
||||
break;
|
||||
}
|
||||
|
||||
return t(`${prefix}.${postfix}`);
|
||||
let content = t(`${prefix}.${postfix}`);
|
||||
|
||||
if (_status === JitsiRecordingConstants.status.ON && this.props._isTranscribing) {
|
||||
content += ` \u00B7 ${t('transcribing.labelToolTip')}`;
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +90,7 @@ function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const { mode } = ownProps;
|
||||
|
||||
return {
|
||||
_isTranscribing: state['features/transcribing'].isTranscribing,
|
||||
_status: getSessionStatusToShow(state, mode)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,17 +38,25 @@ class RecordingLabel extends AbstractRecordingLabel {
|
||||
* @inheritdoc
|
||||
*/
|
||||
_renderLabel() {
|
||||
if (this.props._status !== JitsiRecordingConstants.status.ON) {
|
||||
// Since there are no expanded labels on web, we only render this
|
||||
// label when the recording status is ON.
|
||||
const { _isTranscribing, _status, classes, mode, t } = this.props;
|
||||
const isRecording = mode === JitsiRecordingConstants.mode.FILE;
|
||||
const icon = isRecording || _isTranscribing ? IconRecord : IconSites;
|
||||
let content;
|
||||
|
||||
if (_status === JitsiRecordingConstants.status.ON) {
|
||||
content = t(isRecording || _isTranscribing ? 'videoStatus.recording' : 'videoStatus.streaming');
|
||||
|
||||
if (_isTranscribing) {
|
||||
content += ` \u00B7 ${t('transcribing.labelToolTip')}`;
|
||||
}
|
||||
} else if (mode === JitsiRecordingConstants.mode.STREAM) {
|
||||
return null;
|
||||
} else if (_isTranscribing) {
|
||||
content = t('transcribing.labelToolTip');
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { classes, mode, t } = this.props;
|
||||
const isRecording = mode === JitsiRecordingConstants.mode.FILE;
|
||||
const icon = isRecording ? IconRecord : IconSites;
|
||||
const content = t(isRecording ? 'videoStatus.recording' : 'videoStatus.streaming');
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content = { content }
|
||||
|
||||
@@ -2,6 +2,8 @@ import { Share } from 'react-native';
|
||||
|
||||
import { getName } from '../app/functions.native';
|
||||
import { IStore } from '../app/types';
|
||||
import { INVITE_DIAL_IN_ENABLED } from '../base/flags/constants';
|
||||
import { getFeatureFlag } from '../base/flags/functions';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import { getShareInfoText } from '../invite/functions';
|
||||
|
||||
@@ -35,7 +37,9 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
* @returns {void}
|
||||
*/
|
||||
function _shareRoom(roomURL: string, { dispatch, getState }: IStore) {
|
||||
getShareInfoText(getState(), roomURL)
|
||||
const dialInEnabled = getFeatureFlag(getState(), INVITE_DIAL_IN_ENABLED, true);
|
||||
|
||||
getShareInfoText(getState(), roomURL, false /* useHtml */, !dialInEnabled /* skipDialIn */)
|
||||
.then(message => {
|
||||
const title = `${getName()} Conference`;
|
||||
const onFulfilled
|
||||
@@ -53,14 +57,15 @@ function _shareRoom(roomURL: string, { dispatch, getState }: IStore) {
|
||||
.then(
|
||||
/* onFulfilled */ value => {
|
||||
onFulfilled(value.action === Share.sharedAction);
|
||||
dispatch(toggleShareDialog(false));
|
||||
},
|
||||
/* onRejected */ reason => {
|
||||
dispatch(toggleShareDialog(false));
|
||||
logger.error(
|
||||
`Failed to share conference/room URL ${roomURL}:`,
|
||||
reason);
|
||||
onFulfilled(false);
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
dispatch(toggleShareDialog(false));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
import { showErrorNotification, showNotification } from '../notifications/actions';
|
||||
import {
|
||||
NOTIFICATION_TIMEOUT_TYPE,
|
||||
TRANSCRIBING_NOTIFICATION_ID
|
||||
} from '../notifications/constants';
|
||||
|
||||
import {
|
||||
_POTENTIAL_TRANSCRIBER_JOINED,
|
||||
_TRANSCRIBER_JOINED,
|
||||
@@ -57,59 +51,3 @@ export function potentialTranscriberJoined(participantId: string) {
|
||||
transcriberJID: participantId
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that the pending transcribing notification should be shown on the
|
||||
* screen.
|
||||
*
|
||||
* @returns {showNotification}
|
||||
*/
|
||||
export function showPendingTranscribingNotification() {
|
||||
return showNotification({
|
||||
descriptionKey: 'transcribing.pending',
|
||||
titleKey: 'dialog.transcribing',
|
||||
uid: TRANSCRIBING_NOTIFICATION_ID
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.LONG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that the started transcribing notification should be shown on the
|
||||
* screen.
|
||||
*
|
||||
* @returns {showNotification}
|
||||
*/
|
||||
export function showStartedTranscribingNotification() {
|
||||
return showNotification({
|
||||
descriptionKey: 'transcribing.on',
|
||||
titleKey: 'dialog.transcribing',
|
||||
uid: TRANSCRIBING_NOTIFICATION_ID
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.SHORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that the stopped transcribing notification should be shown on the
|
||||
* screen.
|
||||
*
|
||||
* @returns {showNotification}
|
||||
*/
|
||||
export function showStoppedTranscribingNotification() {
|
||||
return showNotification({
|
||||
descriptionKey: 'transcribing.off',
|
||||
titleKey: 'dialog.transcribing',
|
||||
uid: TRANSCRIBING_NOTIFICATION_ID
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.SHORT);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Signals that the transcribing error notification should be shown.
|
||||
*
|
||||
* @returns {showErrorNotification}
|
||||
*/
|
||||
export function showTranscribingError() {
|
||||
return showErrorNotification({
|
||||
descriptionKey: 'transcribing.error',
|
||||
titleKey: 'transcribing.failedToStart',
|
||||
uid: TRANSCRIBING_NOTIFICATION_ID
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.LONG);
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
|
||||
import { translate } from '../../base/i18n/functions';
|
||||
import ExpandedLabel, { IProps as AbstractProps } from '../../base/label/components/native/ExpandedLabel';
|
||||
|
||||
type Props = AbstractProps & WithTranslation;
|
||||
|
||||
/**
|
||||
* A react {@code Component} that implements an expanded label as tooltip-like
|
||||
* component to explain the meaning of the {@code TranscribingLabel}.
|
||||
*/
|
||||
class TranscribingExpandedLabel extends ExpandedLabel<Props> {
|
||||
/**
|
||||
* Returns the label specific text of this {@code ExpandedLabel}.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
_getLabel() {
|
||||
return this.props.t('transcribing.expandedLabel');
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(TranscribingExpandedLabel);
|
||||
@@ -1,59 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../app/types';
|
||||
import { translate } from '../../base/i18n/functions';
|
||||
import Label from '../../base/label/components/native/Label';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link TranscribingLabel}.
|
||||
*/
|
||||
export interface IProps extends WithTranslation {
|
||||
|
||||
/**
|
||||
* True if the label needs to be rendered, false otherwise.
|
||||
*/
|
||||
_showLabel: boolean;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* React {@code Component} for displaying a label when a transcriber is in the
|
||||
* conference.
|
||||
*
|
||||
* @augments Component
|
||||
*/
|
||||
class TranscribingLabel extends Component<IProps> {
|
||||
|
||||
/**
|
||||
* Renders the platform-specific label component.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
if (!this.props._showLabel) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <Label text = { this.props.t('transcribing.tr') } />;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to the associated props of the
|
||||
* {@link AbstractTranscribingLabel} {@code Component}.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _showLabel: boolean
|
||||
* }}
|
||||
*/
|
||||
export function _mapStateToProps(state: IReduxState) {
|
||||
return {
|
||||
_showLabel: state['features/transcribing'].isTranscribing
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(TranscribingLabel));
|
||||
@@ -1,28 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../app/types';
|
||||
import Label from '../../base/label/components/web/Label';
|
||||
import Tooltip from '../../base/tooltip/components/Tooltip';
|
||||
|
||||
const TranscribingLabel = () => {
|
||||
const _showLabel = useSelector((state: IReduxState) => state['features/transcribing'].isTranscribing);
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!_showLabel) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content = { t('transcribing.labelToolTip') }
|
||||
position = { 'left' }>
|
||||
<Label
|
||||
className = 'recording-label'
|
||||
text = { t('transcribing.tr') } />
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
export default TranscribingLabel;
|
||||
@@ -1,11 +1,20 @@
|
||||
import { batch } from 'react-redux';
|
||||
|
||||
import { IStore } from '../app/types';
|
||||
import { JitsiRecordingConstants } from '../base/lib-jitsi-meet';
|
||||
import {
|
||||
HIDDEN_PARTICIPANT_JOINED,
|
||||
HIDDEN_PARTICIPANT_LEFT,
|
||||
PARTICIPANT_UPDATED
|
||||
} from '../base/participants/actionTypes';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import { SET_REQUESTING_SUBTITLES } from '../subtitles/actionTypes';
|
||||
import { toggleRequestingSubtitles } from '../subtitles/actions.any';
|
||||
import { playSound } from '../base/sounds/actions';
|
||||
import { showNotification } from '../notifications/actions';
|
||||
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
|
||||
import {
|
||||
RECORDING_OFF_SOUND_ID,
|
||||
RECORDING_ON_SOUND_ID
|
||||
} from '../recording/constants';
|
||||
|
||||
import {
|
||||
_TRANSCRIBER_JOINED,
|
||||
@@ -13,9 +22,6 @@ import {
|
||||
} from './actionTypes';
|
||||
import {
|
||||
potentialTranscriberJoined,
|
||||
showPendingTranscribingNotification,
|
||||
showStartedTranscribingNotification,
|
||||
showStoppedTranscribingNotification,
|
||||
transcriberJoined,
|
||||
transcriberLeft
|
||||
} from './actions';
|
||||
@@ -31,38 +37,21 @@ const TRANSCRIBER_DISPLAY_NAME = 'Transcriber';
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
const {
|
||||
isTranscribing,
|
||||
transcriberJID,
|
||||
potentialTranscriberJIDs
|
||||
} = getState()['features/transcribing'];
|
||||
|
||||
switch (action.type) {
|
||||
case _TRANSCRIBER_JOINED: {
|
||||
case _TRANSCRIBER_JOINED:
|
||||
notifyTranscribingStatusChanged(true);
|
||||
dispatch(showStartedTranscribingNotification());
|
||||
maybeEmitRecordingNotification(dispatch, getState, true);
|
||||
|
||||
const state = getState();
|
||||
const { transcription } = state['features/base/config'];
|
||||
const { _requestingSubtitles } = state['features/subtitles'];
|
||||
|
||||
if (!_requestingSubtitles && !transcription?.disableStartForAll) {
|
||||
dispatch(toggleRequestingSubtitles());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case _TRANSCRIBER_LEFT: {
|
||||
case _TRANSCRIBER_LEFT:
|
||||
notifyTranscribingStatusChanged(false);
|
||||
dispatch(showStoppedTranscribingNotification());
|
||||
maybeEmitRecordingNotification(dispatch, getState, false);
|
||||
|
||||
const state = getState();
|
||||
const { transcription } = state['features/base/config'];
|
||||
const { _requestingSubtitles } = state['features/subtitles'];
|
||||
|
||||
if (_requestingSubtitles && !transcription?.disableStartForAll) {
|
||||
dispatch(toggleRequestingSubtitles());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HIDDEN_PARTICIPANT_JOINED:
|
||||
if (action.displayName === TRANSCRIBER_DISPLAY_NAME) {
|
||||
dispatch(transcriberJoined(action.id));
|
||||
@@ -85,18 +74,41 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
|
||||
break;
|
||||
}
|
||||
case SET_REQUESTING_SUBTITLES:
|
||||
if (action.enabled && !isTranscribing) {
|
||||
dispatch(showPendingTranscribingNotification());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return next(action);
|
||||
});
|
||||
|
||||
/**
|
||||
* Emit a recording started / stopped notification if the transcription started / stopped. Only
|
||||
* if there is no recording in progress.
|
||||
*
|
||||
* @param {Dispatch} dispatch - The Redux dispatch function.
|
||||
* @param {Function} getState - The Redux state.
|
||||
* @param {boolean} on - Whether the transcription is on or not.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function maybeEmitRecordingNotification(dispatch: IStore['dispatch'], getState: IStore['getState'], on: boolean) {
|
||||
const state = getState();
|
||||
const { sessionDatas } = state['features/recording'];
|
||||
const { status: statusConstants } = JitsiRecordingConstants;
|
||||
|
||||
if (sessionDatas.some(sd => sd.mode !== statusConstants.OFF)) {
|
||||
// If a recording is still ongoing, don't send any notification.
|
||||
return;
|
||||
}
|
||||
|
||||
batch(() => {
|
||||
dispatch(showNotification({
|
||||
descriptionKey: on ? 'recording.on' : 'recording.off',
|
||||
titleKey: 'dialog.recording'
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.SHORT));
|
||||
dispatch(playSound(on ? RECORDING_ON_SOUND_ID : RECORDING_OFF_SOUND_ID));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that transcribing has started or stopped.
|
||||
*
|
||||
|
||||
@@ -65,18 +65,22 @@ module:hook("pre-iq/full", function(event)
|
||||
end
|
||||
end
|
||||
|
||||
local feature = dial.attr.to == 'jitsi_meet_transcribe' and 'transcription' or 'outbound-call';
|
||||
local is_session_allowed = is_feature_allowed(session.jitsi_meet_context_features, feature);
|
||||
|
||||
-- if current user is not allowed, but was granted moderation by a user
|
||||
-- that is allowed by its features we want to allow it
|
||||
local is_granting_session_allowed = false;
|
||||
if (session.granted_jitsi_meet_context_features) then
|
||||
is_granting_session_allowed = is_feature_allowed(session.granted_jitsi_meet_context_features, feature);
|
||||
end
|
||||
|
||||
if (token == nil
|
||||
or roomName == nil
|
||||
or not token_util:verify_room(session, room_jid_match_rewrite(roomName))
|
||||
or not is_feature_allowed(session.jitsi_meet_context_features,
|
||||
(dial.attr.to == 'jitsi_meet_transcribe' and 'transcription' or 'outbound-call')))
|
||||
-- if current user is not allowed, but was granted moderation by a user
|
||||
-- that is allowed by its features we want to allow it
|
||||
and not is_feature_allowed(session.granted_jitsi_meet_context_features,
|
||||
(dial.attr.to == 'jitsi_meet_transcribe' and 'transcription' or 'outbound-call'))
|
||||
or not (is_session_allowed or is_granting_session_allowed))
|
||||
then
|
||||
module:log("warn",
|
||||
"Filtering stanza dial, stanza:%s", tostring(stanza));
|
||||
module:log("warn", "Filtering stanza dial, stanza:%s", tostring(stanza));
|
||||
session.send(st.error_reply(stanza, "auth", "forbidden"));
|
||||
return true;
|
||||
end
|
||||
|
||||
@@ -193,8 +193,8 @@ module:hook('muc-broadcast-presence', function (event)
|
||||
local session = sessions[occupant.jid];
|
||||
local identity = session and session.jitsi_meet_context_user;
|
||||
|
||||
if is_vpaas(room.jid) and identity then
|
||||
-- in case of moderator in vpass meeting we want to do auto-promotion
|
||||
if is_vpaas(room) and identity then
|
||||
-- in case of moderator in vpaas meeting we want to do auto-promotion
|
||||
local is_vpaas_moderator = identity.moderator;
|
||||
if is_vpaas_moderator == 'true' or is_vpaas_moderator == true then
|
||||
is_moderator = true;
|
||||
|
||||
@@ -57,7 +57,7 @@ end
|
||||
-- process join_rate_presence_queue in the room and pops element passing them to handle_normal_presence
|
||||
-- returns 1 if we want to reschedule it after 1 second
|
||||
local function timer_process_queue_elements (rate, queue, process, queue_empty_cb)
|
||||
if not queue or queue:count() == 0 then
|
||||
if not queue or queue:count() == 0 or queue.empty then
|
||||
return;
|
||||
end
|
||||
|
||||
@@ -152,7 +152,12 @@ end, 9); -- as we will rate limit joins we need to be the first to execute
|
||||
|
||||
-- clear queue on room destroy so timer will skip next run if any
|
||||
module:hook('muc-room-destroyed',function(event)
|
||||
event.room.join_rate_presence_queue = nil;
|
||||
if event.room.join_rate_presence_queue then
|
||||
event.room.join_rate_presence_queue.empty = true;
|
||||
end
|
||||
if event.room.leave_rate_presence_queue then
|
||||
event.room.leave_rate_presence_queue.empty = true;
|
||||
end
|
||||
end);
|
||||
|
||||
module:hook('muc-occupant-pre-leave', function (event)
|
||||
|
||||
@@ -216,8 +216,8 @@ local function stanza_handler(event)
|
||||
end
|
||||
|
||||
local force_promote = request_promotion.attr.forcePromote;
|
||||
if force_promote == 'true' and not is_vpaas(room.jid) then
|
||||
module:log('warn', 'Received promotion request for non vpass room (%s) with forced promotion: ',
|
||||
if force_promote == 'true' and not is_vpaas(room) then
|
||||
module:log('warn', 'Received promotion request for non vpaas room (%s) with forced promotion: ',
|
||||
room.jid, stanza);
|
||||
return true; -- stop processing
|
||||
end
|
||||
|
||||
@@ -416,25 +416,35 @@ function is_moderated(room_jid)
|
||||
return false;
|
||||
end
|
||||
|
||||
-- check if the room tenant starts with
|
||||
-- vpaas-magic-cookie-
|
||||
function is_vpaas(room_jid)
|
||||
local node, host = jid.split(room_jid);
|
||||
-- check if the room tenant starts with vpaas-magic-cookie-
|
||||
-- @param room the room to check
|
||||
function is_vpaas(room)
|
||||
if not room then
|
||||
return false;
|
||||
end
|
||||
|
||||
-- stored check in room object if it exist
|
||||
if room.is_vpaas ~= nil then
|
||||
return room.is_vpaas;
|
||||
end
|
||||
|
||||
room.is_vpaas = false;
|
||||
|
||||
local node, host = jid.split(room.jid);
|
||||
if host ~= muc_domain or not node then
|
||||
module:log('debug', 'Not the same host');
|
||||
return false;
|
||||
end
|
||||
local tenant, conference_name = node:match('^%[([^%]]+)%](.+)$');
|
||||
if not (tenant and conference_name) then
|
||||
module:log('debug', 'Not a vpaas room %s', room_jid);
|
||||
return false;
|
||||
end
|
||||
local vpaas_prefix, _ = tenant:match('^(vpaas%-magic%-cookie%-)(.*)$')
|
||||
if vpaas_prefix ~= 'vpaas-magic-cookie-' then
|
||||
module:log('debug', 'Not a vpaas room %s', room_jid);
|
||||
return false
|
||||
|
||||
if not starts_with(tenant, 'vpaas-magic-cookie-') then
|
||||
return false;
|
||||
end
|
||||
return true
|
||||
|
||||
room.is_vpaas = true;
|
||||
return true;
|
||||
end
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user