mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-09-09 22:58:40 +00:00
Compare commits
15 Commits
8616
...
release-85
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9bbf525060 | ||
|
|
9dcad3e2fb | ||
|
|
cf01abf72f | ||
|
|
6c6442f97d | ||
|
|
2ea866d04e | ||
|
|
4da3648d6e | ||
|
|
33f61e5c23 | ||
|
|
d8e91ad63c | ||
|
|
580a769ee3 | ||
|
|
e200ab64b3 | ||
|
|
434f66030a | ||
|
|
0908a51650 | ||
|
|
c6a49c8697 | ||
|
|
befef4af54 | ||
|
|
7fb29693a2 |
@@ -131,6 +131,7 @@ import {
|
||||
createLocalTracksF,
|
||||
getLocalJitsiAudioTrack,
|
||||
getLocalJitsiVideoTrack,
|
||||
getLocalTracks,
|
||||
getLocalVideoTrack,
|
||||
isLocalTrackMuted,
|
||||
isUserInteractionRequiredForUnmute
|
||||
@@ -1828,6 +1829,35 @@ export default {
|
||||
onStartMutedPolicyChanged(audio, video));
|
||||
}
|
||||
);
|
||||
room.on(JitsiConferenceEvents.STARTED_MUTED, () => {
|
||||
const audioMuted = room.isStartAudioMuted();
|
||||
const videoMuted = room.isStartVideoMuted();
|
||||
const localTracks = getLocalTracks(APP.store.getState()['features/base/tracks']);
|
||||
const promises = [];
|
||||
|
||||
APP.store.dispatch(setAudioMuted(audioMuted));
|
||||
APP.store.dispatch(setVideoMuted(videoMuted));
|
||||
|
||||
// Remove the tracks from the peerconnection.
|
||||
for (const track of localTracks) {
|
||||
// Always add the track on Safari because of a known issue where audio playout doesn't happen
|
||||
// if the user joins audio and video muted, i.e., if there is no local media capture.
|
||||
if (audioMuted && track.jitsiTrack?.getType() === MEDIA_TYPE.AUDIO && !browser.isWebKitBased()) {
|
||||
promises.push(this.useAudioStream(null));
|
||||
}
|
||||
if (videoMuted && track.jitsiTrack?.getType() === MEDIA_TYPE.VIDEO) {
|
||||
promises.push(this.useVideoStream(null));
|
||||
}
|
||||
}
|
||||
|
||||
Promise.allSettled(promises)
|
||||
.then(() => {
|
||||
APP.store.dispatch(showNotification({
|
||||
titleKey: 'notify.mutedTitle',
|
||||
descriptionKey: 'notify.muted'
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.SHORT));
|
||||
});
|
||||
});
|
||||
|
||||
room.on(
|
||||
JitsiConferenceEvents.DATA_CHANNEL_OPENED, () => {
|
||||
@@ -2039,7 +2069,8 @@ export default {
|
||||
_initDeviceList(setDeviceListChangeHandler = false) {
|
||||
const { mediaDevices } = JitsiMeetJS;
|
||||
|
||||
if (mediaDevices.isDeviceChangeAvailable()) {
|
||||
if (mediaDevices.isDeviceListAvailable()
|
||||
&& mediaDevices.isDeviceChangeAvailable()) {
|
||||
if (setDeviceListChangeHandler) {
|
||||
this.deviceChangeListener = devices =>
|
||||
window.setTimeout(() => this._onDeviceListChanged(devices), 0);
|
||||
|
||||
11
config.js
11
config.js
@@ -403,8 +403,6 @@ var config = {
|
||||
// // requireConsent: true,
|
||||
// // If true consent will be skipped for users who are already in the meeting.
|
||||
// // skipConsentInMeeting: true,
|
||||
// // Link for the recording consent dialog's "Learn more" link.
|
||||
// // consentLearnMoreLink: 'https://jitsi.org/meet/consent',
|
||||
// },
|
||||
|
||||
// recordingService: {
|
||||
@@ -613,7 +611,6 @@ var config = {
|
||||
// medium: 5000,
|
||||
// long: 10000,
|
||||
// extraLong: 60000,
|
||||
// sticky: 0,
|
||||
// },
|
||||
|
||||
// // Options for the recording limit notification.
|
||||
@@ -1883,14 +1880,6 @@ var config = {
|
||||
|
||||
// If true remove the tint foreground on focused user camera in filmstrip
|
||||
// disableCameraTintForeground: false,
|
||||
|
||||
// File sharign service.
|
||||
// fileSharing: {
|
||||
// // The URL of the file sharing service API. See resources/file-sharing.yaml for more details.
|
||||
// apiUrl: 'https://example.com',
|
||||
// // Whether the file sharing service is enabled or not.
|
||||
// enabled: true,
|
||||
// },
|
||||
};
|
||||
|
||||
// Set the default values for JaaS customers
|
||||
|
||||
@@ -141,6 +141,32 @@
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.smileys-panel {
|
||||
bottom: 100%;
|
||||
box-sizing: border-box;
|
||||
background-color: rgba(0, 0, 0, .6) !important;
|
||||
height: auto;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
width: calc(#{$sidebarWidth} - 32px);
|
||||
margin-bottom: 5px;
|
||||
margin-left: -5px;
|
||||
|
||||
/**
|
||||
* CSS transitions do not apply for auto dimensions. So to produce the css
|
||||
* accordion effect for showing and hiding the smiley-panel, while allowing
|
||||
* for variable panel, height, use a very large max-height and animate off
|
||||
* of that.
|
||||
*/
|
||||
transition: max-height 0.3s;
|
||||
|
||||
#smileysContainer {
|
||||
background-color: $chatBackgroundColor;
|
||||
border-top: 1px solid #A4B8D1;
|
||||
}
|
||||
}
|
||||
|
||||
#smileysContainer .smiley {
|
||||
font-size: 1.625rem;
|
||||
}
|
||||
|
||||
@@ -4,3 +4,9 @@
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-browser.shift-right {
|
||||
.participants_pane {
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,3 +60,21 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.desktop-browser {
|
||||
&.shift-right {
|
||||
|
||||
@media only screen and (max-width: $verySmallScreen + $sidebarWidth) {
|
||||
|
||||
#videoResolutionLabel {
|
||||
display: none;
|
||||
}
|
||||
.vertical-filmstrip .filmstrip {
|
||||
display: none;
|
||||
}
|
||||
.chrome-extension-banner {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ $newToolbarSizeWithPadding: calc(#{$newToolbarSize} + 24px);
|
||||
* Chat
|
||||
*/
|
||||
$chatBackgroundColor: #131519;
|
||||
$sidebarWidth: 315px;
|
||||
|
||||
/**
|
||||
* Misc.
|
||||
|
||||
@@ -91,3 +91,15 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.shift-right .remote-videos > div {
|
||||
/**
|
||||
* Max-width corresponding to the ASPECT_RATIO_BREAKPOINT from features/filmstrip/constants,
|
||||
* from which we subtract the chat size.
|
||||
*/
|
||||
@media only screen and (max-width: calc(500px + #{$sidebarWidth})) {
|
||||
video {
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -835,6 +835,7 @@
|
||||
"or": "أو",
|
||||
"premeeting": "ما قبل المُلتقى",
|
||||
"screenSharingError": "خطأ في مشاركة الشاشة:",
|
||||
"showScreen": "تفعيل واجهة ما قبل المُلتقى",
|
||||
"startWithPhone": "البدء مع جهاز الصوت من الجوال",
|
||||
"videoOnlyError": "خطأ في الفيديو:",
|
||||
"videoTrackError": "لم نتمكن من إنشاء ملف الفيديو",
|
||||
|
||||
@@ -842,6 +842,7 @@
|
||||
"or": "o",
|
||||
"premeeting": "Prereunió",
|
||||
"screenSharingError": "Error en compartir la pantalla:",
|
||||
"showScreen": "Activa la pantalla de prereunió",
|
||||
"startWithPhone": "Comença amb àudio de telèfon",
|
||||
"videoOnlyError": "Error del vídeo:",
|
||||
"videoTrackError": "No s'ha pogut crear la pista de vídeo.",
|
||||
|
||||
@@ -976,6 +976,7 @@
|
||||
"proceedAnyway": "Přesto pokračujte",
|
||||
"recordingWarning": "Ostatní účastníci mohou tento hovor nahrávat",
|
||||
"screenSharingError": "Chyba sdílení obrazovky:",
|
||||
"showScreen": "Zapnout obrazovku před setkáním",
|
||||
"startWithPhone": "Začít se zvukem přes telefon",
|
||||
"unsafeRoomConsent": "Chápu rizika, chci se připojit k setkání",
|
||||
"videoOnlyError": "Chyba videa:",
|
||||
|
||||
@@ -122,9 +122,7 @@
|
||||
"nickname": {
|
||||
"popover": "Wähle einen Alias",
|
||||
"title": "Geben Sie einen Alias zum Chatten ein",
|
||||
"titleWithCC": "Geben Sie einen Alias zum Chatten und für Untertitel ein",
|
||||
"titleWithPolls": "Geben Sie einen Alias zum Chatten und für Umfragen ein",
|
||||
"titleWithPollsAndCC": "Geben Sie einen Alias zum Chatten, für Umfragen und Untertitel ein"
|
||||
"titleWithPolls": "Geben Sie einen Alias zum Chatten ein"
|
||||
},
|
||||
"noMessagesMessage": "Es gibt noch keine Nachricht in dieser Konferenz. Starten Sie hier eine Unterhaltung!",
|
||||
"privateNotice": "Private Nachricht an {{recipient}}",
|
||||
@@ -133,13 +131,10 @@
|
||||
"systemDisplayName": "System",
|
||||
"tabs": {
|
||||
"chat": "Chatten",
|
||||
"closedCaptions": "Untertitel",
|
||||
"polls": "Umfragen"
|
||||
},
|
||||
"title": "Chatten",
|
||||
"titleWithCC": "Chatten und Untertitel",
|
||||
"titleWithPolls": "Chatten und Umfragen",
|
||||
"titleWithPollsAndCC": "Chatten, Umfragen und Untertitel",
|
||||
"you": "Sie"
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
@@ -149,10 +144,6 @@
|
||||
"dontShowAgain": "Hinweis nicht mehr anzeigen",
|
||||
"installExtensionText": "Installieren Sie die Erweiterung für die Integration von Google Calendar und Office 365"
|
||||
},
|
||||
"closedCaptionsTab": {
|
||||
"emptyState": "Die Untertitel sind verfügbar, sobald sie von der Moderation gestartet wurden",
|
||||
"startClosedCaptionsButton": "Untertitel starten"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
"joiningRoom": "Eine Verbindung zu Ihrer Konferenz wird hergestellt…"
|
||||
},
|
||||
@@ -272,8 +263,7 @@
|
||||
"Remove": "Entfernen",
|
||||
"Share": "Teilen",
|
||||
"Submit": "OK",
|
||||
"Understand": "Verstanden, Stummschaltung beibehalten",
|
||||
"UnderstandAndUnmute": "Verstanden, bitte Stummschaltung aufheben",
|
||||
"Understand": "Verstanden",
|
||||
"WaitForHostMsg": "Die Konferenz wurde noch nicht gestartet. Falls Sie die Konferenz leiten, authentifizieren Sie sich bitte. Warten Sie andernfalls, bis die Konferenz gestartet wird.",
|
||||
"WaitForHostNoAuthMsg": "Die Konferenz wurde noch nicht gestartet. Bitte warten Sie, bis die Konferenz gestartet wird.",
|
||||
"WaitingForHostButton": "Auf Moderation warten",
|
||||
@@ -310,7 +300,6 @@
|
||||
"conferenceReloadMsg": "Wir versuchen das zu beheben. Verbinde in {{seconds}} Sekunden …",
|
||||
"conferenceReloadTitle": "Leider ist etwas schiefgegangen.",
|
||||
"confirm": "Bestätigen",
|
||||
"confirmBack": "Zurück",
|
||||
"confirmNo": "Nein",
|
||||
"confirmYes": "Ja",
|
||||
"connectError": "Oh! Es hat etwas nicht geklappt und der Konferenz konnte nicht beigetreten werden.",
|
||||
@@ -348,7 +337,6 @@
|
||||
"kickParticipantTitle": "Person entfernen?",
|
||||
"kickSystemTitle": "Autsch! Sie wurden aus der Konferenz geworfen",
|
||||
"kickTitle": "Autsch! {{participantDisplayName}} hat Sie aus der Konferenz geworfen",
|
||||
"learnMore": "Mehr erfahren",
|
||||
"linkMeeting": "Konferenz verlinken",
|
||||
"linkMeetingTitle": "Konferenz mit Salesforce verlinken",
|
||||
"liveStreaming": "Livestreaming",
|
||||
@@ -406,9 +394,7 @@
|
||||
"recentlyUsedObjects": "Ihre zuletzt verwendeten Objekte",
|
||||
"recording": "Aufnahme",
|
||||
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Während eines Livestreams nicht möglich",
|
||||
"recordingInProgressDescription": "Diese Konferenz wird aufgezeichnet und von KI analysiert {{learnMore}}. Ihr Ton und Video ist deaktiviert, wenn Sie es aktivieren, stimmen Sie der Aufzeichnung zu.",
|
||||
"recordingInProgressDescriptionFirstHalf": "Diese Konferenz wird aufgezeichnet und von KI analysiert",
|
||||
"recordingInProgressDescriptionSecondHalf": ". Ihr Ton und Video ist deaktiviert, wenn Sie es aktivieren, stimmen Sie der Aufzeichnung zu.",
|
||||
"recordingInProgressDescription": "Diese Konferenz wird aufgezeichnet. Ihr Ton und Video ist deaktiviert, wenn Sie es aktivieren, stimmen Sie der Aufzeichnung zu.",
|
||||
"recordingInProgressTitle": "Aufnahme läuft",
|
||||
"rejoinNow": "Jetzt erneut beitreten",
|
||||
"remoteControlAllowedMessage": "{{user}} hat die Anfrage zur Fernsteuerung angenommen!",
|
||||
@@ -998,6 +984,7 @@
|
||||
"proceedAnyway": "Trotzdem fortsetzen",
|
||||
"recordingWarning": "Diese Konferenz wird möglicherweise von anderen Personen aufgezeichnet",
|
||||
"screenSharingError": "Fehler bei Bildschirmfreigabe:",
|
||||
"showScreen": "Konferenzvorschau aktivieren",
|
||||
"startWithPhone": "Mit Telefonaudio starten",
|
||||
"unsafeRoomConsent": "Ich verstehe das Risiko und möchte der Konferenz beitreten",
|
||||
"videoOnlyError": "Videofehler:",
|
||||
@@ -1152,7 +1139,6 @@
|
||||
"selectMic": "Mikrofon",
|
||||
"selfView": "Eigene Ansicht",
|
||||
"shortcuts": "Tastaturkürzel",
|
||||
"showSubtitlesOnStage": "Untertitel in Hauptansicht anzeigen",
|
||||
"speakers": "Lautsprecher",
|
||||
"startAudioMuted": "Alle Personen treten stummgeschaltet bei",
|
||||
"startReactionsMuted": "Interaktionstöne für alle deaktivieren",
|
||||
@@ -1249,7 +1235,6 @@
|
||||
"closeChat": "Chat schließen",
|
||||
"closeMoreActions": "„Weitere Einstellungen“ schließen",
|
||||
"closeParticipantsPane": "Anwesendenliste schließen",
|
||||
"closedCaptions": "Untertitel",
|
||||
"collapse": "Einklappen",
|
||||
"document": "Geteiltes Dokument schließen",
|
||||
"documentClose": "Geteiltes Dokument schließen",
|
||||
@@ -1340,7 +1325,6 @@
|
||||
"closeChat": "Chat schließen",
|
||||
"closeParticipantsPane": "Anwesenheitsliste schließen",
|
||||
"closeReactionsMenu": "Interaktionsmenü schließen",
|
||||
"closedCaptions": "Untertitel",
|
||||
"disableNoiseSuppression": "Rauschunterdrückung deaktivieren",
|
||||
"disableReactionSounds": "Sie können die Interaktionstöne für diese Konferenz deaktivieren",
|
||||
"documentClose": "Geteiltes Dokument schließen",
|
||||
@@ -1433,16 +1417,13 @@
|
||||
"failed": "Transkribieren fehlgeschlagen",
|
||||
"labelTooltip": "Die Konferenz wird transkribiert",
|
||||
"labelTooltipExtra": "Zusätzlich wird das Transkript später verfügbar sein.",
|
||||
"openClosedCaptions": "Untertitel öffnen",
|
||||
"original": "Original",
|
||||
"sourceLanguageDesc": "Aktuell ist die Sprache der Konferenz auf <b>{{sourceLanguage}}</b> eingestellt. <br/> Sie könne dies hier ",
|
||||
"sourceLanguageHere": "ändern",
|
||||
"start": "Anzeige der Untertitel starten",
|
||||
"stop": "Anzeige der Untertitel stoppen",
|
||||
"subtitles": "Untertitel",
|
||||
"subtitlesOff": "Ausschalten",
|
||||
"tr": "TR",
|
||||
"translateTo": "Übersetzen in"
|
||||
"tr": "TR"
|
||||
},
|
||||
"unpinParticipant": "{{participantName}} - Nicht mehr anheften",
|
||||
"userMedia": {
|
||||
|
||||
@@ -845,6 +845,7 @@
|
||||
"or": "abo",
|
||||
"premeeting": "naglěd",
|
||||
"screenSharingError": "zmólenje pśi sobuźělenju monitora:",
|
||||
"showScreen": "naglěd konferency aktiwěrowaś",
|
||||
"startWithPhone": "zachopiś z telefonowym audio",
|
||||
"videoOnlyError": "zmólenje wideo:",
|
||||
"videoTrackError": "Sćažka wideo njejo mógła se załožyś.",
|
||||
|
||||
@@ -862,6 +862,7 @@
|
||||
"or": "ή",
|
||||
"premeeting": "Προ σύσκεψη",
|
||||
"screenSharingError": "Σφάλμα διαμοιρασμού οθόνης:",
|
||||
"showScreen": "Ενεργοποίηση οθόνης προ σύσκεψης",
|
||||
"startWithPhone": "Ξεκινήστε με ήχο τηλεφώνου",
|
||||
"videoOnlyError": "Σφάλμα βίντεο:",
|
||||
"videoTrackError": "Δεν ήταν δυνατή η δημιουργία κομματιού βίντεο.",
|
||||
|
||||
@@ -935,6 +935,7 @@
|
||||
"premeeting": "Antaŭkunveno",
|
||||
"proceedAnyway": "Daŭrigi",
|
||||
"screenSharingError": "Eraro kun la ekrandividado:",
|
||||
"showScreen": "Ebligu antaŭkunvenon ekranon",
|
||||
"startWithPhone": "Komencu kun la telefona sono",
|
||||
"unsafeRoomConsent": "Akceptu la riskojn, kaj daŭrigi",
|
||||
"videoOnlyError": "Eraro kun la videaĵo:",
|
||||
|
||||
@@ -886,6 +886,7 @@
|
||||
"premeeting": "Pre-reunión",
|
||||
"proceedAnyway": "Continuar de todos modos",
|
||||
"screenSharingError": "Error al compartir pantalla:",
|
||||
"showScreen": "Habilitar pantalla pre-reunión",
|
||||
"startWithPhone": "Iniciar con audio de llamada telefónica",
|
||||
"unsafeRoomConsent": "Comprendo los riesgos, quiero unirme a la reunión",
|
||||
"videoOnlyError": "Error con el vídeo:",
|
||||
|
||||
@@ -759,6 +759,7 @@
|
||||
"or": "o",
|
||||
"premeeting": "Pre-reunión",
|
||||
"screenSharingError": "Error al compartir pantalla:",
|
||||
"showScreen": "Habilitar pantalla pre-reunión",
|
||||
"startWithPhone": "Iniciar con audio de llamada telefónica",
|
||||
"videoOnlyError": "Error con el video:",
|
||||
"videoTrackError": "No se pudo crear la pista de video.",
|
||||
|
||||
@@ -646,6 +646,7 @@
|
||||
"or": "edo",
|
||||
"premeeting": "Aurre-bilera",
|
||||
"screenSharingError": "Errorea pantaila partekatzean:",
|
||||
"showScreen": "Aktibatu bileraren aurreko pantaila",
|
||||
"startWithPhone": "Telefono diearen audioarekin hasi",
|
||||
"videoOnlyError": "Errorea bideoan:",
|
||||
"videoTrackError": "Ezin izan da bideo pista sortu.",
|
||||
|
||||
@@ -894,6 +894,7 @@
|
||||
"premeeting": "پیشجلسه",
|
||||
"proceedAnyway": "در هر صورت انجام شود",
|
||||
"screenSharingError": "خطا در همرسانی صفحه:",
|
||||
"showScreen": "فعالسازی صفحهٔ پیشجلسه",
|
||||
"startWithPhone": "شروع با صدای گوشی",
|
||||
"unsafeRoomConsent": "من خطر احتمالی را درک میکنم؛ میخواهم به جلسه بپیوندم",
|
||||
"videoOnlyError": "خطای ویدیو:",
|
||||
|
||||
@@ -976,6 +976,7 @@
|
||||
"proceedAnyway": "Continuer quand même",
|
||||
"recordingWarning": "D'autres participants peuvent enregistrer cet appel",
|
||||
"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:",
|
||||
|
||||
@@ -954,6 +954,7 @@
|
||||
"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:",
|
||||
|
||||
@@ -622,6 +622,7 @@
|
||||
"or": "या",
|
||||
"premeeting": "प्री मीटिंग",
|
||||
"screenSharingError": "स्क्रीन शेयरिंग त्रुटि:",
|
||||
"showScreen": "प्री मीटिंग स्क्रीन सक्षम करें",
|
||||
"startWithPhone": "फोन ऑडियो से शुरू करें",
|
||||
"videoOnlyError": "वीडियो त्रुटि:",
|
||||
"videoTrackError": "वीडियो ट्रैक नहीं बना सका",
|
||||
|
||||
@@ -840,6 +840,7 @@
|
||||
"or": "ili",
|
||||
"premeeting": "Predsastanak",
|
||||
"screenSharingError": "Greška dijeljenja ekrana:",
|
||||
"showScreen": "Uključi ekran predsastanka",
|
||||
"startWithPhone": "Počni s telefonom",
|
||||
"videoOnlyError": "Greška videa:",
|
||||
"videoTrackError": "Nije bilo moguće stvoriti videosnimku.",
|
||||
|
||||
@@ -824,6 +824,7 @@
|
||||
"or": "abo",
|
||||
"premeeting": "předstwa",
|
||||
"screenSharingError": "zmylk při dopušćenju wužiwanja monitora:",
|
||||
"showScreen": "konferencnu předstwu aktiwěrować",
|
||||
"startWithPhone": "z telefoniskim awdijom startować",
|
||||
"videoOnlyError": "widejowy zmylk:",
|
||||
"videoTrackError": "widejowy trak njebě móžny",
|
||||
|
||||
@@ -683,6 +683,7 @@
|
||||
"or": "vagy",
|
||||
"premeeting": "Csatlakozás előtt",
|
||||
"screenSharingError": "Képernyő megosztás hiba:",
|
||||
"showScreen": "Csatlakozás előtti kamerakép",
|
||||
"startWithPhone": "Kezdés telefonhanggal",
|
||||
"videoOnlyError": "Videó hiba:",
|
||||
"videoTrackError": "Nem sikerült a videó megjelenítés.",
|
||||
|
||||
@@ -955,6 +955,7 @@
|
||||
"proceedAnyway": "Lanjutkan saja",
|
||||
"recordingWarning": "Peserta lain mungkin sedang merekam panggilan ini",
|
||||
"screenSharingError": "Kesalahan berbagi layar:",
|
||||
"showScreen": "Aktifkan layar pra pertemuan",
|
||||
"startWithPhone": "Mulai dengan audio ponsel",
|
||||
"unsafeRoomConsent": "Saya memahami risikonya, saya ingin bergabung dengan pertemuan",
|
||||
"videoOnlyError": "Kesalahan video:",
|
||||
|
||||
@@ -936,6 +936,7 @@
|
||||
"premeeting": "Á undan fundi",
|
||||
"proceedAnyway": "Halda samt áfram",
|
||||
"screenSharingError": "Villa í skjádeilingu:",
|
||||
"showScreen": "Virkja skjá á undan fundi",
|
||||
"startWithPhone": "Byrja með símahljóði",
|
||||
"unsafeRoomConsent": "Ég skil áhættuna, ég vil taka þátt í fundinum",
|
||||
"videoOnlyError": "Villa í myndmerki:",
|
||||
|
||||
1348
lang/main-it.json
1348
lang/main-it.json
File diff suppressed because it is too large
Load Diff
@@ -784,6 +784,7 @@
|
||||
"or": "または",
|
||||
"premeeting": "プレミーティング",
|
||||
"screenSharingError": "画面共有のエラー:",
|
||||
"showScreen": "プレミーティング画面を有効",
|
||||
"startWithPhone": "音声通話を開始",
|
||||
"videoOnlyError": "ビデオのエラー:",
|
||||
"videoTrackError": "ビデオトラックを生成できませんでした。",
|
||||
|
||||
@@ -736,6 +736,7 @@
|
||||
"or": "neɣ",
|
||||
"premeeting": "Timlilit tuzwirt",
|
||||
"screenSharingError": "Tuccḍa deg beṭṭu n ugdil:",
|
||||
"showScreen": "Rmed agdil n temlilit tuzwirt",
|
||||
"startWithPhone": "Bdu s umeslaw n tiliɣri",
|
||||
"videoOnlyError": "Tuccḍa deg tvidyut:",
|
||||
"videoTrackError": "Asnulfu n track n tvidyut ulamek.",
|
||||
|
||||
@@ -975,6 +975,7 @@
|
||||
"proceedAnyway": "그래도 진행",
|
||||
"recordingWarning": "다른 참가자가 이 통화를 녹화하고 있을 수 있습니다",
|
||||
"screenSharingError": "화면 공유 오류:",
|
||||
"showScreen": "회의 전 화면 활성화",
|
||||
"startWithPhone": "전화 오디오로 시작",
|
||||
"unsafeRoomConsent": "위험을 이해하며 회의에 참여하고 싶습니다",
|
||||
"videoOnlyError": "비디오 오류:",
|
||||
|
||||
@@ -122,9 +122,7 @@
|
||||
"nickname": {
|
||||
"popover": "Izvēlieties vārdu",
|
||||
"title": "Ierakstiet vārdu, lai izmantotu tērzēšanā",
|
||||
"titleWithCC": "Ievadiet segvārdu, lai izmantotu tērzēšanā un slēptos subtitros",
|
||||
"titleWithPolls": "Ierakstiet segvārdu, lai izmantotu tērzēšanā un aptaujās",
|
||||
"titleWithPollsAndCC": "Ievadiet segvārdu, lai izmantotu tērzēšanā, aptaujās un slēptos subtitros"
|
||||
"titleWithPolls": "Ierakstiet vārdu, lai izmantotu tērzēšanā un aptaujās"
|
||||
},
|
||||
"noMessagesMessage": "Sapulcē pagaidām nav nevienas ziņas. Uzsāciet saraksti!",
|
||||
"privateNotice": "Privāta ziņa adresātam {{recipient}}",
|
||||
@@ -133,13 +131,10 @@
|
||||
"systemDisplayName": "Sistēma",
|
||||
"tabs": {
|
||||
"chat": "Tērzēšana",
|
||||
"closedCaptions": "Slēptie subtitri",
|
||||
"polls": "Aptaujas"
|
||||
},
|
||||
"title": "Tērzēšana",
|
||||
"titleWithCC": "Tērzēšana un slēptie subtitri",
|
||||
"titleWithPolls": "Tērzēšana un Aptaujas",
|
||||
"titleWithPollsAndCC": "Tērzēšana, Aptaujas un Slēptie subtitri",
|
||||
"you": "jūs"
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
@@ -149,10 +144,6 @@
|
||||
"dontShowAgain": "Nerādīt man šo vēlreiz",
|
||||
"installExtensionText": "Uzstādīt spraudni Google kalendāra un Office 365 integrācijai"
|
||||
},
|
||||
"closedCaptionsTab": {
|
||||
"emptyState": "Slēpto subtitru saturs būs pieejams, tiklīdz moderators uzsāks to.",
|
||||
"startClosedCaptionsButton": "Uzsākt slēptos subtitrus"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
"joiningRoom": "Notiek pieslēgšanās jūsu sapulcei…"
|
||||
},
|
||||
@@ -273,7 +264,6 @@
|
||||
"Share": "Kopīgot",
|
||||
"Submit": "Iesniegt",
|
||||
"Understand": "Saprotu",
|
||||
"UnderstandAndUnmute": "Es saprotu, lūdzu, ieslēdziet skaņu.",
|
||||
"WaitForHostMsg": "Sapulce vēl nav sākusies, jo vēl nav ieradies neviens moderators. Lūdzu, autorizējieties, lai kļūtu par moderatoru. Pretējā gadījumā, lūdzu, uzgaidiet.",
|
||||
"WaitForHostNoAuthMsg": "Sapulce vēl nav sākusies, jo vēl nav ieradies neviens moderators. Lūdzu, uzgaidiet.",
|
||||
"WaitingForHostButton": "Gaidīt rīkotāju",
|
||||
@@ -310,7 +300,6 @@
|
||||
"conferenceReloadMsg": "Cenšamies to labot. Atkārtota savienojuma izveide pēc {{seconds}} sek….",
|
||||
"conferenceReloadTitle": "Diemžēl kaut kas nogāja greizi.",
|
||||
"confirm": "Apstiprināt",
|
||||
"confirmBack": "Atpakaļ",
|
||||
"confirmNo": "Nē",
|
||||
"confirmYes": "Jā",
|
||||
"connectError": "Hmm! Radās problēma, un mēs nevarējām izveidot savienojumu ar sapulci.",
|
||||
@@ -348,7 +337,6 @@
|
||||
"kickParticipantTitle": "Izraidīt šo dalībnieku?",
|
||||
"kickSystemTitle": "Ak! Jūs izraidīja no sapulces",
|
||||
"kickTitle": "Ak! {{participantDisplayName}} izraidīja jūs no sapulces",
|
||||
"learnMore": "uzzināt vairāk",
|
||||
"linkMeeting": "Sasaistīt sapulci",
|
||||
"linkMeetingTitle": "Sasaistīt sapulci ar Salesforce",
|
||||
"liveStreaming": "Tiešraides straumēšana",
|
||||
@@ -407,8 +395,6 @@
|
||||
"recording": "Ieraksts",
|
||||
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Nav iespējams, kamēr ir aktīva tiešraides straume",
|
||||
"recordingInProgressDescription": "Šī sapulce tiek ierakstīta. Jūsu audio un video ir izslēgti. Ja izvēlaties ieslēgt skaņu vai video, jūs piekrītat ierakstīšanai.",
|
||||
"recordingInProgressDescriptionFirstHalf": "Šo sanāksmi ieraksta un analizē mākslīgais intelekts",
|
||||
"recordingInProgressDescriptionSecondHalf": ". Jūsu audio un video skaņa ir izslēgta. Ja izvēlaties ieslēgt skaņu, jūs piekrītat ierakstīšanai.",
|
||||
"recordingInProgressTitle": "Notiek ierakstīšana",
|
||||
"rejoinNow": "Pieslēgties no jauna",
|
||||
"remoteControlAllowedMessage": "{{user}} apstiprināja jūsu attālās pārvaldības pieprasījumu!",
|
||||
@@ -766,8 +752,7 @@
|
||||
"dataChannelClosedDescriptionWithAudio": "Savienojuma kanāls nedarbojas, tāpēc var rasties audio un video traucējumi.",
|
||||
"dataChannelClosedWithAudio": "Audio un video kvalitāte var būt traucēta",
|
||||
"disabledIframe": "Iegulšana ir paredzēta tikai demonstrācijas nolūkiem, tāpēc šis zvans tiks atvienots pēc {{timeout}} minūtēm.",
|
||||
"disabledIframeSecondaryNative": "Domēna {{domain}} iegulšana ir paredzēta tikai demonstrācijas nolūkiem, tāpēc šis zvans tiks pārtraukts pēc {{timeout}} minūtēm.",
|
||||
"disabledIframeSecondaryWeb": "Domēna {{domain}} iegulšana ir paredzēta tikai demonstrācijas nolūkiem, tāpēc šis zvans tiks pārtraukts pēc {{timeout}} minūtēm. Lūdzu, produkcijas videi izmantojiet <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi as a Service</a>!",
|
||||
"disabledIframeSecondary": "{{domain}} iegulšana ir paredzēta tikai demonstrācijas nolūkiem, tāpēc šis zvans tiks atvienots pēc {{timeout}} minūtēm. Lūdzu, izmantojiet <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi kā Pakalpojums</a> produkcijas iegulšanai!",
|
||||
"disconnected": "savienojums pārtraukts",
|
||||
"displayNotifications": "Rādīt paziņojumus",
|
||||
"dontRemindMe": "Neatgādināt man",
|
||||
@@ -895,7 +880,6 @@
|
||||
"waitingLobby": "Gaida vestibilā ({{count}})"
|
||||
},
|
||||
"search": "Meklēt dalībniekus",
|
||||
"searchDescription": "Sāciet rakstīt, lai atlasītu dalībnieks",
|
||||
"title": "Dalībnieki"
|
||||
},
|
||||
"passwordDigitsOnly": "Līdz {{number}} cipariem",
|
||||
@@ -998,6 +982,7 @@
|
||||
"proceedAnyway": "Tik un tā turpināt",
|
||||
"recordingWarning": "Citi dalībnieki var ierakstīt šo zvanu",
|
||||
"screenSharingError": "Ekrāna koplietošanas kļūda:",
|
||||
"showScreen": "Iespējot ekrānu pirms sapulces",
|
||||
"startWithPhone": "Sākt ar tālruņa audio",
|
||||
"unsafeRoomConsent": "Es saprotu riskus, vēlos pievienoties sapulcei",
|
||||
"videoOnlyError": "Video kļūda:",
|
||||
@@ -1122,7 +1107,6 @@
|
||||
"signedIn": "Pašreiz ir piekļuve e-pasta adreses {{email}} kalendāra notikumiem. Noklikšķiniet uz pogas |Atslēgt|, lai izslēgtu piekļuvi šiem kalendāra pasākumiem.",
|
||||
"title": "Kalendārs"
|
||||
},
|
||||
"chatWithPermissions": "Tērzēšanai nepieciešama atļauja",
|
||||
"desktopShareFramerate": "Darbvirsmas koplietošanas kadru ātrums",
|
||||
"desktopShareHighFpsWarning": "Lielāks kadru nomaiņas ātrums darbvirsmas koplietošanai var ietekmēt joslas platumu. Lai jaunie iestatījumi stātos spēkā, ir jārestartē ekrāna kopīgošana.",
|
||||
"desktopShareWarning": "Lai jaunie iestatījumi stātos spēkā, ir jārestartē ekrāna kopīgošana.",
|
||||
@@ -1152,7 +1136,6 @@
|
||||
"selectMic": "Mikrofons",
|
||||
"selfView": "Pašskats",
|
||||
"shortcuts": "Īsceļi",
|
||||
"showSubtitlesOnStage": "Rādīt subtitrus galvenajā skatā",
|
||||
"speakers": "Skaļruņi",
|
||||
"startAudioMuted": "Dalībnieki pievienojas ar izslēgtu mikrofonu",
|
||||
"startReactionsMuted": "Izslēgt reakcijas skaņas visiem",
|
||||
@@ -1212,7 +1195,6 @@
|
||||
"neutral": "Neitrāls",
|
||||
"sad": "Bēdīgs",
|
||||
"search": "Meklēt",
|
||||
"searchDescription": "Sāciet rakstīt, lai atlasītu dalībnieks",
|
||||
"searchHint": "Meklēt dalībniekus",
|
||||
"seconds": "{{count}}s",
|
||||
"speakerStats": "Dalībnieka uzstāšanās statistika",
|
||||
@@ -1249,7 +1231,6 @@
|
||||
"closeChat": "Aizvērt tērzēšanu",
|
||||
"closeMoreActions": "Aizvērt vairāk darbību izvēlni",
|
||||
"closeParticipantsPane": "Aizvērt dalībnieku paneli",
|
||||
"closedCaptions": "Slēptie subtitri",
|
||||
"collapse": "Sakļaut",
|
||||
"document": "Kopīgotais dokuments (iesl./izsl.)",
|
||||
"documentClose": "Aizvērt kopīgoto dokumentu",
|
||||
@@ -1340,7 +1321,6 @@
|
||||
"closeChat": "Aizvērt tērzētavu",
|
||||
"closeParticipantsPane": "Aizvērt dalībnieku paneli",
|
||||
"closeReactionsMenu": "Aizvērt reakciju izvēlni",
|
||||
"closedCaptions": "Slēptie subtitri",
|
||||
"disableNoiseSuppression": "Atspējot trokšņu slāpēšanu",
|
||||
"disableReactionSounds": "Šai sapulcei varat atspējot reakcijas skaņas",
|
||||
"documentClose": "Aizvērt kopīgoto dokumentu",
|
||||
@@ -1433,16 +1413,13 @@
|
||||
"failed": "Atšifrējuma izveide neizdevās",
|
||||
"labelTooltip": "Šajā sapulcē notiek atšifrējuma izveide.",
|
||||
"labelTooltipExtra": "Turklāt vēlāk būs pieejams atšifrējums.",
|
||||
"openClosedCaptions": "Atvērt slēptos subtitrus",
|
||||
"original": "Oriģināls",
|
||||
"sourceLanguageDesc": "Pašlaik sapulces valoda ir iestatīta uz <b>{{sourceLanguage}}</b>. <br/> Varat to mainīt no ",
|
||||
"sourceLanguageHere": "šeit",
|
||||
"start": "Iesl. subtitru rādīšanu",
|
||||
"stop": "Izsl. subtitru rādīšanu",
|
||||
"subtitles": "Subtitri",
|
||||
"subtitlesOff": "Izslēgts",
|
||||
"tr": "TR",
|
||||
"translateTo": "Tulkot uz"
|
||||
"tr": "TR"
|
||||
},
|
||||
"unpinParticipant": "{{participantName}} — atspraust",
|
||||
"userMedia": {
|
||||
|
||||
@@ -602,6 +602,7 @@
|
||||
"or": "അല്ലെങ്കിൽ",
|
||||
"premeeting": "പ്രീ മീറ്റിംഗ്",
|
||||
"screenSharingError": "സ്ക്രീൻ പങ്കിടൽ പിശക്:",
|
||||
"showScreen": "പ്രീ മീറ്റിംഗ് സ്ക്രീൻ പ്രാപ്തമാക്കുക",
|
||||
"startWithPhone": "ഫോൺ ഓഡിയോ ഉപയോഗിച്ച് ആരംഭിക്കുക",
|
||||
"videoOnlyError": "വീഡിയോ പിശക്:",
|
||||
"videoTrackError": "വീഡിയോ ട്രാക്ക് സൃഷ്ടിക്കാൻ കഴിഞ്ഞില്ല.",
|
||||
|
||||
@@ -872,6 +872,7 @@
|
||||
"or": "эсвэл",
|
||||
"premeeting": "Уулзалтын өмнө",
|
||||
"screenSharingError": "Дэлгэц хуваалцахын алдаа:",
|
||||
"showScreen": "Уулзалтын өмгөх дэлгэц идэвхижүүлэх",
|
||||
"startWithPhone": "Утасны дуугаар холбогдох",
|
||||
"videoOnlyError": "Видео дамжуулалтын алдаа:",
|
||||
"videoTrackError": "Видео бичлэг үүсгэж чадсангүй.",
|
||||
|
||||
@@ -976,6 +976,7 @@
|
||||
"proceedAnyway": "Fortsett likevel",
|
||||
"recordingWarning": "Andre deltakere kan ta opp denne samtalen",
|
||||
"screenSharingError": "Feil ved skjermdeling:",
|
||||
"showScreen": "Aktiver skjerm før møtet",
|
||||
"startWithPhone": "Start med telefonlyd",
|
||||
"unsafeRoomConsent": "Jeg forstår risikoen, jeg vil bli med i møtet",
|
||||
"videoOnlyError": "Video feil:",
|
||||
|
||||
@@ -723,6 +723,7 @@
|
||||
"or": "of",
|
||||
"premeeting": "Voorbeeldscherm",
|
||||
"screenSharingError": "Fout bij schermdeling:",
|
||||
"showScreen": "Voorbeeldscherm inschakelen",
|
||||
"startWithPhone": "Starten met telefoonaudio",
|
||||
"videoOnlyError": "Videofout:",
|
||||
"videoTrackError": "Kon videotrack niet aanmaken.",
|
||||
|
||||
@@ -976,6 +976,7 @@
|
||||
"proceedAnyway": "Fortsett likevel",
|
||||
"recordingWarning": "Andre deltakere kan ta opp denne samtalen",
|
||||
"screenSharingError": "Feil ved skjermdeling:",
|
||||
"showScreen": "Aktiver skjerm før møtet",
|
||||
"startWithPhone": "Start med telefonlyd",
|
||||
"unsafeRoomConsent": "Jeg forstår risikoen, jeg vil bli med i møtet",
|
||||
"videoOnlyError": "Video feil:",
|
||||
|
||||
@@ -976,6 +976,7 @@
|
||||
"proceedAnyway": "Contunhar malgrat tot",
|
||||
"recordingWarning": "D'autres participants pòdon enregistrar aquesta sonada",
|
||||
"screenSharingError": "Error de partatge d’ecran :",
|
||||
"showScreen": "Activar l'ecran de prereünion",
|
||||
"startWithPhone": "Començar amb l’àudio del telefòn",
|
||||
"unsafeRoomConsent": "Compreni lo risc e vòli çaquelà participar a la reünion",
|
||||
"videoOnlyError": "Error vidèo :",
|
||||
|
||||
@@ -874,6 +874,7 @@
|
||||
"premeeting": "Przed spotkaniem",
|
||||
"proceedAnyway": "Kontynuuj mimo to",
|
||||
"screenSharingError": "Błąd udostępniania ekranu:",
|
||||
"showScreen": "Tryb osobistej poczekalni przed spotkaniem",
|
||||
"startWithPhone": "Uruchom przez telefon",
|
||||
"unsafeRoomConsent": "Rozumiem ryzyko, chcę dołączyć do spotkania",
|
||||
"videoOnlyError": "Błąd wideo:",
|
||||
|
||||
@@ -964,6 +964,7 @@
|
||||
"proceedAnyway": "Continuar na mesma",
|
||||
"recordingWarning": "Outros participantes podem estar a gravar esta chamada",
|
||||
"screenSharingError": "Erro de partilha de ecrã:",
|
||||
"showScreen": "Ativar o ecrã de pré-reunião",
|
||||
"startWithPhone": "Iniciar com o áudio do telefone",
|
||||
"unsafeRoomConsent": "Compreendo os riscos, quero participar na reunião",
|
||||
"videoOnlyError": "Erro de vídeo:",
|
||||
|
||||
@@ -935,6 +935,7 @@
|
||||
"premeeting": "Pré-reunião",
|
||||
"proceedAnyway": "Prosseguir mesmo assim",
|
||||
"screenSharingError": "Erro de compartilhamento de tela:",
|
||||
"showScreen": "Habilitar tela pré-reunião",
|
||||
"startWithPhone": "Iniciar com o áudio da ligação",
|
||||
"unsafeRoomConsent": "Eu entendo os riscos, desejo ingressar na reunião",
|
||||
"videoOnlyError": "Erro de vídeo:",
|
||||
|
||||
@@ -950,6 +950,7 @@
|
||||
"proceedAnyway": "Продолжить в любом случае",
|
||||
"recordingWarning": "Другие участники могут записывать этот звонок",
|
||||
"screenSharingError": "Ошибка показа экрана:",
|
||||
"showScreen": "Включить экран перед подключением",
|
||||
"startWithPhone": "Начать с телефонной связью",
|
||||
"unsafeRoomConsent": "Я понимаю риски и хочу присоединиться к встрече",
|
||||
"videoOnlyError": "Ошибка видео:",
|
||||
|
||||
@@ -842,6 +842,7 @@
|
||||
"or": "opuru",
|
||||
"premeeting": "Pre-riunione",
|
||||
"screenSharingError": "Faddina in sa cumpartzidura de s'ischermu",
|
||||
"showScreen": "Ativa ischermu de pre-riunione",
|
||||
"startWithPhone": "Avia imperende s'àudio de su telèfonu",
|
||||
"videoOnlyError": "Faddina de vìdeu:",
|
||||
"videoTrackError": "Impossìbile creare una rasta de vìdeu.",
|
||||
|
||||
@@ -737,6 +737,7 @@
|
||||
"or": "ali",
|
||||
"premeeting": "Pred sestanek",
|
||||
"screenSharingError": "Napaka deljenja zaslona:",
|
||||
"showScreen": "Omogoči zaslon pred sestankom",
|
||||
"startWithPhone": "Začni z zvokom telefona",
|
||||
"videoOnlyError": "Napaka videa:",
|
||||
"videoTrackError": "Ni bilo mogoče ustvariti videa.",
|
||||
|
||||
@@ -975,6 +975,7 @@
|
||||
"proceedAnyway": "Vazhdo, sido qoftë",
|
||||
"recordingWarning": "Këtë thirrje pjesëmarrës të tjerë mund ta regjistrojnë",
|
||||
"screenSharingError": "Gabim ndarjeje ekrani me të tjerë:",
|
||||
"showScreen": "Aktivizoni skenë para takimit",
|
||||
"startWithPhone": "Nise me audio telefoni",
|
||||
"unsafeRoomConsent": "I kuptoj rreziqet, dëshiroj të marr pjesë te takimi",
|
||||
"videoOnlyError": "Gabim video:",
|
||||
|
||||
@@ -483,6 +483,7 @@
|
||||
"or": "или",
|
||||
"premeeting": "Пред придруживањем",
|
||||
"screenSharingError": "Грешка дијељења екрана:",
|
||||
"showScreen": "Укључити екран 'пред придруживњем'.",
|
||||
"startWithPhone": "Започети са телефонском везом.",
|
||||
"videoOnlyError": "Грешка видеа:",
|
||||
"videoTrackError": "Креирање видео траке није успјело.",
|
||||
|
||||
@@ -976,6 +976,7 @@
|
||||
"proceedAnyway": "Fortsätt ändå",
|
||||
"recordingWarning": "",
|
||||
"screenSharingError": "Skärmdelningsfel:",
|
||||
"showScreen": "Aktivera skärmen före mötet",
|
||||
"startWithPhone": "Börja med telefonljud",
|
||||
"unsafeRoomConsent": "Jag förstår riskerna, jag vill vara med på mötet",
|
||||
"videoOnlyError": "Videofel:",
|
||||
|
||||
@@ -634,6 +634,7 @@
|
||||
"or": "లేదా",
|
||||
"premeeting": "Pre meeting",
|
||||
"screenSharingError": "Screen sharing error:",
|
||||
"showScreen": "Enable pre meeting screen",
|
||||
"startWithPhone": "Start with phone audio",
|
||||
"videoOnlyError": "Video error:",
|
||||
"videoTrackError": "Could not create video track.",
|
||||
|
||||
@@ -970,6 +970,7 @@
|
||||
"proceedAnyway": "Yine de devam et",
|
||||
"recordingWarning": "Diğer katılımcılar bu çağrıyı kaydediyor olabilir",
|
||||
"screenSharingError": "Ekran paylaşma hatası:",
|
||||
"showScreen": "Toplantı öncesi ekranını etkinleştir",
|
||||
"startWithPhone": "Telefon sesiyle başlayın",
|
||||
"unsafeRoomConsent": "Riskleri anlıyorum, toplantıya katılmak istiyorum",
|
||||
"videoOnlyError": "Video hatası:",
|
||||
|
||||
@@ -870,6 +870,7 @@
|
||||
"or": "або",
|
||||
"premeeting": "Перед приєднанням",
|
||||
"screenSharingError": "Помилка спільного перегляду екрана:",
|
||||
"showScreen": "Увімкнути вхідну панель",
|
||||
"startWithPhone": "Почати в режимі телефону",
|
||||
"videoOnlyError": "Помилка відео:",
|
||||
"videoTrackError": "Не вдалося створити трек відео.",
|
||||
|
||||
@@ -948,6 +948,7 @@
|
||||
"proceedAnyway": "Tiếp tục dù sao",
|
||||
"recordingWarning": "Có thể có người tham gia khác đang ghi lại cuộc gọi này",
|
||||
"screenSharingError": "Lỗi chia sẻ màn hình:",
|
||||
"showScreen": "Kích hoạt màn hình trước cuộc họp",
|
||||
"startWithPhone": "Bắt đầu với âm thanh điện thoại",
|
||||
"unsafeRoomConsent": "Tôi hiểu rủi ro, tôi muốn tham gia cuộc họp",
|
||||
"videoOnlyError": "Lỗi video:",
|
||||
|
||||
@@ -917,6 +917,7 @@
|
||||
"premeeting": "会前",
|
||||
"proceedAnyway": "仍然继续",
|
||||
"screenSharingError": "共享屏幕错误:",
|
||||
"showScreen": "开启会前屏幕",
|
||||
"startWithPhone": "以电话音频开始",
|
||||
"unsafeRoomConsent": "我了解风险,我想加入会议",
|
||||
"videoOnlyError": "视频错误:",
|
||||
|
||||
@@ -934,6 +934,7 @@
|
||||
"premeeting": "會議前",
|
||||
"proceedAnyway": "仍然繼續",
|
||||
"screenSharingError": "螢幕分享錯誤:",
|
||||
"showScreen": "啟用會議前螢幕",
|
||||
"startWithPhone": "使用手機音訊開始",
|
||||
"unsafeRoomConsent": "我了解風險,我想要加入會議",
|
||||
"videoOnlyError": "視訊錯誤:",
|
||||
|
||||
@@ -124,8 +124,7 @@
|
||||
"title": "Enter a nickname to use chat",
|
||||
"titleWithCC": "Enter a nickname to use chat and closed captions",
|
||||
"titleWithPolls": "Enter a nickname to use chat and polls",
|
||||
"titleWithPollsAndCC": "Enter a nickname to use chat, polls and closed captions",
|
||||
"titleWithPollsAndCCAndFileSharing": "Enter a nickname to use chat, polls, closed captions and files"
|
||||
"titleWithPollsAndCC": "Enter a nickname to use chat, polls and closed captions"
|
||||
},
|
||||
"noMessagesMessage": "There are no messages in the meeting yet. Start a conversation here!",
|
||||
"privateNotice": "Private message to {{recipient}}",
|
||||
@@ -135,14 +134,12 @@
|
||||
"tabs": {
|
||||
"chat": "Chat",
|
||||
"closedCaptions": "CC",
|
||||
"fileSharing": "Files",
|
||||
"polls": "Polls"
|
||||
},
|
||||
"title": "Chat",
|
||||
"titleWithCC": "CC",
|
||||
"titleWithFeatures": "Chat and",
|
||||
"titleWithFileSharing": "Files",
|
||||
"titleWithPolls": "Polls",
|
||||
"titleWithCC": "Chat and CC",
|
||||
"titleWithPolls": "Chat and Polls",
|
||||
"titleWithPollsAndCC": "Chat, Polls and CC",
|
||||
"you": "you"
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
@@ -275,8 +272,7 @@
|
||||
"Remove": "Remove",
|
||||
"Share": "Share",
|
||||
"Submit": "Submit",
|
||||
"Understand": "I understand, keep me muted for now",
|
||||
"UnderstandAndUnmute": "I understand, please unmute me",
|
||||
"Understand": "I understand",
|
||||
"WaitForHostMsg": "The conference has not yet started because no moderators have yet arrived. If you'd like to become a moderator please log-in. Otherwise, please wait.",
|
||||
"WaitForHostNoAuthMsg": "The conference has not yet started because no moderators have yet arrived. Please wait.",
|
||||
"WaitingForHostButton": "Wait for moderator",
|
||||
@@ -313,7 +309,6 @@
|
||||
"conferenceReloadMsg": "We're trying to fix this. Reconnecting in {{seconds}} sec…",
|
||||
"conferenceReloadTitle": "Unfortunately, something went wrong.",
|
||||
"confirm": "Confirm",
|
||||
"confirmBack": "Back",
|
||||
"confirmNo": "No",
|
||||
"confirmYes": "Yes",
|
||||
"connectError": "Oops! Something went wrong and we couldn't connect to the conference.",
|
||||
@@ -351,7 +346,6 @@
|
||||
"kickParticipantTitle": "Kick this participant?",
|
||||
"kickSystemTitle": "Ouch! You were kicked out of the meeting",
|
||||
"kickTitle": "Ouch! {{participantDisplayName}} kicked you out of the meeting",
|
||||
"learnMore": "learn more",
|
||||
"linkMeeting": "Link meeting",
|
||||
"linkMeetingTitle": "Link meeting to Salesforce",
|
||||
"liveStreaming": "Live Streaming",
|
||||
@@ -409,9 +403,7 @@
|
||||
"recentlyUsedObjects": "Your recently used objects",
|
||||
"recording": "Recording",
|
||||
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Not possible while a live stream is active",
|
||||
"recordingInProgressDescription": "This meeting is being recorded and analyzed by AI{{learnMore}}. Your audio and video have been muted. If you choose to unmute, you consent to being recorded.",
|
||||
"recordingInProgressDescriptionFirstHalf": "This meeting is being recorded and analyzed by AI",
|
||||
"recordingInProgressDescriptionSecondHalf": ". Your audio and video have been muted. If you choose to unmute, you consent to being recorded.",
|
||||
"recordingInProgressDescription": "This meeting is being recorded. Your audio and video have been muted. If you choose to unmute, you consent to being recorded.",
|
||||
"recordingInProgressTitle": "Recording in progress",
|
||||
"rejoinNow": "Rejoin now",
|
||||
"remoteControlAllowedMessage": "{{user}} accepted your remote control request!",
|
||||
@@ -542,17 +534,6 @@
|
||||
"veryBad": "Very Bad",
|
||||
"veryGood": "Very Good"
|
||||
},
|
||||
"fileSharing": {
|
||||
"downloadFailedDescription": "Please try again.",
|
||||
"downloadFailedTitle": "Download failed",
|
||||
"downloadFile": "Download",
|
||||
"dragAndDrop": "Drag and drop files here",
|
||||
"fileAlreadyUploaded": "File has already been uploaded to this meeting",
|
||||
"removeFile": "Remove",
|
||||
"uploadFailedDescription": "Please try again.",
|
||||
"uploadFailedTitle": "Upload failed",
|
||||
"uploadFile": "Share file"
|
||||
},
|
||||
"filmstrip": {
|
||||
"accessibilityLabel": {
|
||||
"heading": "Video thumbnails"
|
||||
@@ -1012,6 +993,7 @@
|
||||
"proceedAnyway": "Proceed anyway",
|
||||
"recordingWarning": "Other participants may be recording this call",
|
||||
"screenSharingError": "Screen sharing error:",
|
||||
"showScreen": "Enable pre meeting screen",
|
||||
"startWithPhone": "Start with phone audio",
|
||||
"unsafeRoomConsent": "I understand the risks, I want to join the meeting",
|
||||
"videoOnlyError": "Video error:",
|
||||
|
||||
8
modules/API/external/external_api.js
vendored
8
modules/API/external/external_api.js
vendored
@@ -11,6 +11,7 @@ import {
|
||||
getAvailableDevices,
|
||||
getCurrentDevices,
|
||||
isDeviceChangeAvailable,
|
||||
isDeviceListAvailable,
|
||||
isMultipleAudioInputSupported,
|
||||
setAudioInputDevice,
|
||||
setAudioOutputDevice,
|
||||
@@ -988,15 +989,10 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
* Returns Promise that resolves with true if the device list is available
|
||||
* and with false if not.
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
isDeviceListAvailable() {
|
||||
console.warn('isDeviceListAvailable is deprecated and will be removed in the future. '
|
||||
+ 'It always returns true');
|
||||
|
||||
return Promise.resolve(true);
|
||||
return isDeviceListAvailable(this._transport);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
15
modules/API/external/functions.js
vendored
15
modules/API/external/functions.js
vendored
@@ -56,6 +56,21 @@ export function isDeviceChangeAvailable(transport, deviceType) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Promise that resolves with true if the device list is available
|
||||
* and with false if not.
|
||||
*
|
||||
* @param {Transport} transport - The @code{Transport} instance responsible for
|
||||
* the external communication.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function isDeviceListAvailable(transport) {
|
||||
return transport.sendRequest({
|
||||
type: 'devices',
|
||||
name: 'isDeviceListAvailable'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Promise that resolves with true if multiple audio input is supported
|
||||
* and with false if not.
|
||||
|
||||
@@ -478,11 +478,9 @@ export default class LargeVideoManager {
|
||||
if (isOpen && window.innerWidth > 580) {
|
||||
/**
|
||||
* If chat state is open, we re-compute the container width
|
||||
* by subtracting the chat width, which may be resized by the user.
|
||||
* by subtracting the default width of the chat.
|
||||
*/
|
||||
const chatWidth = state['features/chat'].width?.current ?? CHAT_SIZE;
|
||||
|
||||
widthToUse -= chatWidth;
|
||||
widthToUse -= CHAT_SIZE;
|
||||
}
|
||||
|
||||
if (resizableFilmstrip && visible && filmstripWidth.current >= FILMSTRIP_BREAKPOINT) {
|
||||
|
||||
10
package-lock.json
generated
10
package-lock.json
generated
@@ -61,7 +61,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/v1988.0.0+83c2ac30/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1979.0.0+9da20d5f/lib-jitsi-meet.tgz",
|
||||
"lodash-es": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -17091,8 +17091,8 @@
|
||||
},
|
||||
"node_modules/lib-jitsi-meet": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1988.0.0+83c2ac30/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-0vhCwUToOCnT0X8qiW2FyTC6+9DfuB5+1geUYryDlvHgU+LrLM6HFsh/tHHpQFoHY8qZlRMZN4wHDSgu5h2sDQ==",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1979.0.0+9da20d5f/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-Gz3TpqGMdpGbUAaL82SpllprDoz+kWmTK0YUEKy47OwWdd+OYO/SNKTGwLFvw/3fmpJPuD4wPNM2SU3xjqQgJA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "2.2.1",
|
||||
@@ -37723,8 +37723,8 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1988.0.0+83c2ac30/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-0vhCwUToOCnT0X8qiW2FyTC6+9DfuB5+1geUYryDlvHgU+LrLM6HFsh/tHHpQFoHY8qZlRMZN4wHDSgu5h2sDQ==",
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1979.0.0+9da20d5f/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-Gz3TpqGMdpGbUAaL82SpllprDoz+kWmTK0YUEKy47OwWdd+OYO/SNKTGwLFvw/3fmpJPuD4wPNM2SU3xjqQgJA==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "2.2.1",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
|
||||
@@ -67,7 +67,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/v1988.0.0+83c2ac30/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1979.0.0+9da20d5f/lib-jitsi-meet.tgz",
|
||||
"lodash-es": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/node_modules/@giphy/js-analytics/dist/send-pingback.js b/node_modules/@giphy/js-analytics/dist/send-pingback.js
|
||||
index 989f0ff..52471cb 100644
|
||||
index 989f0ff..149e77c 100644
|
||||
--- a/node_modules/@giphy/js-analytics/dist/send-pingback.js
|
||||
+++ b/node_modules/@giphy/js-analytics/dist/send-pingback.js
|
||||
@@ -10,6 +10,9 @@ var global_1 = __importDefault(require("./global"));
|
||||
@@ -22,6 +22,5 @@ import '../toolbox/middleware';
|
||||
import '../face-landmarks/middleware';
|
||||
import '../gifs/middleware';
|
||||
import '../whiteboard/middleware.web';
|
||||
import '../file-sharing/middleware.web';
|
||||
|
||||
import './middlewares.any';
|
||||
|
||||
@@ -17,6 +17,5 @@ import '../screenshot-capture/reducer';
|
||||
import '../talk-while-muted/reducer';
|
||||
import '../virtual-background/reducer';
|
||||
import '../web-hid/reducer';
|
||||
import '../file-sharing/reducer';
|
||||
|
||||
import './reducers.any';
|
||||
|
||||
@@ -38,7 +38,6 @@ import { IE2EEState } from '../e2ee/reducer';
|
||||
import { IEtherpadState } from '../etherpad/reducer';
|
||||
import { IFaceLandmarksState } from '../face-landmarks/reducer';
|
||||
import { IFeedbackState } from '../feedback/reducer';
|
||||
import { IFileSharingState } from '../file-sharing/reducer';
|
||||
import { IFilmstripState } from '../filmstrip/reducer';
|
||||
import { IFollowMeState } from '../follow-me/reducer';
|
||||
import { IGifsState } from '../gifs/reducer';
|
||||
@@ -129,7 +128,6 @@ export interface IReduxState {
|
||||
'features/etherpad': IEtherpadState;
|
||||
'features/face-landmarks': IFaceLandmarksState;
|
||||
'features/feedback': IFeedbackState;
|
||||
'features/file-sharing': IFileSharingState;
|
||||
'features/filmstrip': IFilmstripState;
|
||||
'features/follow-me': IFollowMeState;
|
||||
'features/full-screen': IFullScreenState;
|
||||
|
||||
@@ -72,15 +72,11 @@ export function getInitials(s?: string) {
|
||||
/**
|
||||
* Checks if the passed URL should be loaded with CORS.
|
||||
*
|
||||
* @param {string | Function} url - The URL (on mobile we use a specific Icon component for avatars).
|
||||
* @param {string} url - The URL.
|
||||
* @param {Array<string>} corsURLs - The URL pattern that matches a URL that needs to be handled with CORS.
|
||||
* @returns {boolean}
|
||||
* @returns {void}
|
||||
*/
|
||||
export function isCORSAvatarURL(url: string | Function, corsURLs: Array<string> = []): boolean {
|
||||
if (typeof url === 'function') {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isCORSAvatarURL(url: string, corsURLs: Array<string> = []): boolean {
|
||||
return corsURLs.some(pattern => url.startsWith(pattern));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createStartMutedConfigurationEvent } from '../../analytics/AnalyticsEvents';
|
||||
import { sendAnalytics } from '../../analytics/functions';
|
||||
import { IReduxState, IStore } from '../../app/types';
|
||||
import { readyToClose } from '../../mobile/external-api/actions';
|
||||
import { transcriberJoined, transcriberLeft } from '../../transcribing/actions';
|
||||
import { setIAmVisitor } from '../../visitors/actions';
|
||||
import { iAmVisitor } from '../../visitors/functions';
|
||||
@@ -10,7 +11,9 @@ import { JITSI_CONNECTION_CONFERENCE_KEY } from '../connection/constants';
|
||||
import { hasAvailableDevices } from '../devices/functions.any';
|
||||
import JitsiMeetJS, { JitsiConferenceEvents, JitsiE2ePingEvents } from '../lib-jitsi-meet';
|
||||
import {
|
||||
setAudioMuted,
|
||||
setAudioUnmutePermissions,
|
||||
setVideoMuted,
|
||||
setVideoUnmutePermissions
|
||||
} from '../media/actions';
|
||||
import { MEDIA_TYPE, MediaType } from '../media/constants';
|
||||
@@ -23,11 +26,12 @@ import {
|
||||
participantSourcesUpdated,
|
||||
participantUpdated
|
||||
} from '../participants/actions';
|
||||
import { getLocalParticipant, getNormalizedDisplayName, getParticipantByIdOrUndefined } from '../participants/functions';
|
||||
import { getNormalizedDisplayName, getParticipantByIdOrUndefined } from '../participants/functions';
|
||||
import { IJitsiParticipant } from '../participants/types';
|
||||
import { toState } from '../redux/functions';
|
||||
import {
|
||||
destroyLocalTracks,
|
||||
replaceLocalTrack,
|
||||
trackAdded,
|
||||
trackRemoved
|
||||
} from '../tracks/actions.any';
|
||||
@@ -139,24 +143,7 @@ function _addConferenceListeners(conference: IJitsiConference, dispatch: IStore[
|
||||
|
||||
conference.on(
|
||||
JitsiConferenceEvents.KICKED,
|
||||
(participant: any, reason: any, isReplaced: boolean) => {
|
||||
|
||||
if (isReplaced) {
|
||||
const localParticipant = getLocalParticipant(state);
|
||||
|
||||
dispatch(participantUpdated({
|
||||
conference,
|
||||
|
||||
// @ts-ignore
|
||||
id: localParticipant.id,
|
||||
isReplaced
|
||||
}));
|
||||
|
||||
dispatch(readyToClose());
|
||||
} else {
|
||||
dispatch(kickedOut(conference, participant));
|
||||
}
|
||||
});
|
||||
(participant: any) => dispatch(kickedOut(conference, participant)));
|
||||
|
||||
conference.on(
|
||||
JitsiConferenceEvents.PARTICIPANT_KICKED,
|
||||
@@ -176,6 +163,39 @@ function _addConferenceListeners(conference: IJitsiConference, dispatch: IStore[
|
||||
|
||||
// Dispatches into features/base/media follow:
|
||||
|
||||
conference.on(
|
||||
JitsiConferenceEvents.STARTED_MUTED,
|
||||
() => {
|
||||
const audioMuted = Boolean(conference.isStartAudioMuted());
|
||||
const videoMuted = Boolean(conference.isStartVideoMuted());
|
||||
const localTracks = getLocalTracks(state['features/base/tracks']);
|
||||
|
||||
sendAnalytics(createStartMutedConfigurationEvent('remote', audioMuted, videoMuted));
|
||||
logger.log(`Start muted: ${audioMuted ? 'audio, ' : ''}${videoMuted ? 'video' : ''}`);
|
||||
|
||||
// XXX Jicofo tells lib-jitsi-meet to start with audio and/or video
|
||||
// muted i.e. Jicofo expresses an intent. Lib-jitsi-meet has turned
|
||||
// Jicofo's intent into reality by actually muting the respective
|
||||
// tracks. The reality is expressed in base/tracks already so what
|
||||
// is left is to express Jicofo's intent in base/media.
|
||||
// TODO Maybe the app needs to learn about Jicofo's intent and
|
||||
// transfer that intent to lib-jitsi-meet instead of lib-jitsi-meet
|
||||
// acting on Jicofo's intent without the app's knowledge.
|
||||
dispatch(setAudioMuted(audioMuted));
|
||||
dispatch(setVideoMuted(videoMuted));
|
||||
|
||||
// Remove the tracks from peerconnection as well.
|
||||
for (const track of localTracks) {
|
||||
const trackType = track.jitsiTrack.getType();
|
||||
|
||||
// Do not remove the audio track on RN. Starting with iOS 15 it will fail to unmute otherwise.
|
||||
if ((audioMuted && trackType === MEDIA_TYPE.AUDIO && navigator.product !== 'ReactNative')
|
||||
|| (videoMuted && trackType === MEDIA_TYPE.VIDEO)) {
|
||||
dispatch(replaceLocalTrack(track.jitsiTrack, null, conference));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
conference.on(
|
||||
JitsiConferenceEvents.AUDIO_UNMUTE_PERMISSIONS_CHANGED,
|
||||
(disableAudioMuteChange: boolean) => {
|
||||
@@ -788,8 +808,10 @@ export function nonParticipantMessageReceived(id: string, json: Object) {
|
||||
/**
|
||||
* Updates the known state of start muted policies.
|
||||
*
|
||||
* @param {boolean} audioMuted - Whether or not members will join the conference as audio muted.
|
||||
* @param {boolean} videoMuted - Whether or not members will join the conference as video muted.
|
||||
* @param {boolean} audioMuted - Whether or not members will join the conference
|
||||
* as audio muted.
|
||||
* @param {boolean} videoMuted - Whether or not members will join the conference
|
||||
* as video muted.
|
||||
* @returns {{
|
||||
* type: SET_START_MUTED_POLICY,
|
||||
* startAudioMutedPolicy: boolean,
|
||||
@@ -1000,8 +1022,10 @@ export function setRoom(room?: string) {
|
||||
/**
|
||||
* Sets whether or not members should join audio and/or video muted.
|
||||
*
|
||||
* @param {boolean} startAudioMuted - Whether or not members will join the conference as audio muted.
|
||||
* @param {boolean} startVideoMuted - Whether or not members will join the conference as video muted.
|
||||
* @param {boolean} startAudioMuted - Whether or not members will join the
|
||||
* conference as audio muted.
|
||||
* @param {boolean} startVideoMuted - Whether or not members will join the
|
||||
* conference as video muted.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function setStartMutedPolicy(
|
||||
@@ -1013,6 +1037,9 @@ export function setStartMutedPolicy(
|
||||
audio: startAudioMuted,
|
||||
video: startVideoMuted
|
||||
});
|
||||
|
||||
dispatch(
|
||||
onStartMutedPolicyChanged(startAudioMuted, startVideoMuted));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -295,7 +295,7 @@ export function getVisitorOptions(stateful: IStateful, vnode: string, focusJid:
|
||||
return {
|
||||
hosts: config.oldConfig.hosts,
|
||||
focusUserJid: focusJid,
|
||||
disableLocalStatsBroadcast: false,
|
||||
disableLocalStats: false,
|
||||
bosh: config.oldConfig.bosh && appendURLParam(config.oldConfig.bosh, 'customusername', username),
|
||||
p2p: config.oldConfig.p2p,
|
||||
websocket: config.oldConfig.websocket
|
||||
@@ -330,7 +330,7 @@ export function getVisitorOptions(stateful: IStateful, vnode: string, focusJid:
|
||||
},
|
||||
focusUserJid: focusJid,
|
||||
disableFocus: true, // This flag disables sending the initial conference request
|
||||
disableLocalStatsBroadcast: true,
|
||||
disableLocalStats: true,
|
||||
bosh: config.bosh && appendURLParam(config.bosh, 'vnode', vnode),
|
||||
p2p: {
|
||||
...config.p2p,
|
||||
|
||||
@@ -70,7 +70,6 @@ import {
|
||||
} from './functions';
|
||||
import logger from './logger';
|
||||
import { IConferenceMetadata } from './reducer';
|
||||
import './subscriber';
|
||||
|
||||
/**
|
||||
* Handler for before unload event.
|
||||
|
||||
@@ -54,19 +54,6 @@ const DEFAULT_STATE = {
|
||||
};
|
||||
|
||||
export interface IConferenceMetadata {
|
||||
files: {
|
||||
[fileId: string]: {
|
||||
authorParticipantJid: string;
|
||||
authorParticipantName: string;
|
||||
conferenceFullName: string;
|
||||
fileId: string;
|
||||
fileName: string;
|
||||
fileSize: number;
|
||||
fileType: string;
|
||||
progress?: number;
|
||||
timestamp: number;
|
||||
};
|
||||
};
|
||||
recording?: {
|
||||
isTranscribingEnabled: boolean;
|
||||
};
|
||||
@@ -118,6 +105,8 @@ export interface IJitsiConference {
|
||||
isLobbySupported: Function;
|
||||
isP2PActive: Function;
|
||||
isSIPCallingSupported: Function;
|
||||
isStartAudioMuted: Function;
|
||||
isStartVideoMuted: Function;
|
||||
join: Function;
|
||||
joinLobby: Function;
|
||||
kickParticipant: Function;
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import { IStore } from '../../app/types';
|
||||
import { showNotification } from '../../notifications/actions';
|
||||
import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants';
|
||||
import StateListenerRegistry from '../redux/StateListenerRegistry';
|
||||
import { setAudioMuted, setVideoMuted } from '../media/actions';
|
||||
import { VIDEO_MUTISM_AUTHORITY } from '../media/constants';
|
||||
|
||||
let hasShownNotification = false;
|
||||
|
||||
/**
|
||||
* Handles changes in the start muted policy for audio and video tracks in the meta data set for the conference.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
/* selector */ state => state['features/base/conference'].startAudioMutedPolicy,
|
||||
/* listener */ (startAudioMutedPolicy, store) => {
|
||||
_updateTrackMuteState(store, true);
|
||||
});
|
||||
|
||||
StateListenerRegistry.register(
|
||||
/* selector */ state => state['features/base/conference'].startVideoMutedPolicy,
|
||||
/* listener */(startVideoMutedPolicy, store) => {
|
||||
_updateTrackMuteState(store, false);
|
||||
});
|
||||
|
||||
/**
|
||||
* Updates the mute state of the track based on the start muted policy.
|
||||
*
|
||||
* @param {IStore} store - The redux store.
|
||||
* @param {boolean} isAudio - Whether the track is audio or video.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _updateTrackMuteState(store: IStore, isAudio: boolean) {
|
||||
const { dispatch, getState } = store;
|
||||
const mutedPolicyKey = isAudio ? 'startAudioMutedPolicy' : 'startVideoMutedPolicy';
|
||||
const mutedPolicyValue = getState()['features/base/conference'][mutedPolicyKey];
|
||||
|
||||
// Currently, the policy only supports force muting others, not unmuting them.
|
||||
if (!mutedPolicyValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
let muteStateUpdated = false;
|
||||
const { muted } = isAudio ? getState()['features/base/media'].audio : getState()['features/base/media'].video;
|
||||
|
||||
if (isAudio && !Boolean(muted)) {
|
||||
dispatch(setAudioMuted(mutedPolicyValue, true));
|
||||
muteStateUpdated = true;
|
||||
} else if (!isAudio && !Boolean(muted)) {
|
||||
// TODO: Add a new authority for video mutism for the moderator case.
|
||||
dispatch(setVideoMuted(mutedPolicyValue, VIDEO_MUTISM_AUTHORITY.USER, true));
|
||||
muteStateUpdated = true;
|
||||
}
|
||||
|
||||
if (!hasShownNotification && muteStateUpdated) {
|
||||
hasShownNotification = true;
|
||||
dispatch(showNotification({
|
||||
titleKey: 'notify.mutedTitle',
|
||||
descriptionKey: 'notify.muted'
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.SHORT));
|
||||
}
|
||||
}
|
||||
@@ -387,10 +387,6 @@ export interface IConfig {
|
||||
feedbackPercentage?: number;
|
||||
fileRecordingsServiceEnabled?: boolean;
|
||||
fileRecordingsServiceSharingEnabled?: boolean;
|
||||
fileSharing?: {
|
||||
apiUrl?: string;
|
||||
enabled?: boolean;
|
||||
};
|
||||
filmstrip?: {
|
||||
disableResizable?: boolean;
|
||||
disableStageFilmstrip?: boolean;
|
||||
@@ -442,7 +438,6 @@ export interface IConfig {
|
||||
};
|
||||
iAmRecorder?: boolean;
|
||||
iAmSipGateway?: boolean;
|
||||
iAmSpot?: boolean;
|
||||
ignoreStartMuted?: boolean;
|
||||
inviteAppName?: string | null;
|
||||
inviteServiceCallFlowsUrl?: string;
|
||||
@@ -489,7 +484,6 @@ export interface IConfig {
|
||||
long?: number;
|
||||
medium?: number;
|
||||
short?: number;
|
||||
sticky?: number;
|
||||
};
|
||||
notifications?: Array<string>;
|
||||
notifyOnConferenceDestruction?: boolean;
|
||||
@@ -548,7 +542,6 @@ export interface IConfig {
|
||||
};
|
||||
recordingSharingUrl?: string;
|
||||
recordings?: {
|
||||
consentLearnMoreLink?: string;
|
||||
recordAudioAndVideo?: boolean;
|
||||
requireConsent?: boolean;
|
||||
showPrejoinWarning?: boolean;
|
||||
|
||||
@@ -150,7 +150,6 @@ export default [
|
||||
'enableTcc',
|
||||
'faceLandmarks',
|
||||
'feedbackPercentage',
|
||||
'fileSharing.enabled',
|
||||
'filmstrip',
|
||||
'flags',
|
||||
'forceTurnRelay',
|
||||
@@ -170,7 +169,6 @@ export default [
|
||||
'hideLobbyButton',
|
||||
'iAmRecorder',
|
||||
'iAmSipGateway',
|
||||
'iAmSpot',
|
||||
'ignoreStartMuted',
|
||||
'inviteAppName',
|
||||
'liveStreaming.enabled',
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { appNavigate } from '../../app/actions.native';
|
||||
import { IStore } from '../../app/types';
|
||||
import { getCustomerDetails } from '../../jaas/actions.any';
|
||||
import { isVpaasMeeting, getJaasJWT } from '../../jaas/functions';
|
||||
import { navigateRoot } from '../../mobile/navigation/rootNavigationContainerRef';
|
||||
import { screen } from '../../mobile/navigation/routes';
|
||||
import { setJWT } from '../jwt/actions';
|
||||
import { JitsiConnectionErrors } from '../lib-jitsi-meet';
|
||||
|
||||
import { _connectInternal } from './actions.native';
|
||||
import logger from './logger';
|
||||
import { _connectInternal } from './actions.any';
|
||||
|
||||
export * from './actions.any';
|
||||
|
||||
@@ -20,34 +16,12 @@ export * from './actions.any';
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function connect(id?: string, password?: string) {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
const { jwt } = state['features/base/jwt'];
|
||||
|
||||
if (isVpaasMeeting(state)) {
|
||||
return dispatch(getCustomerDetails())
|
||||
.then(() => {
|
||||
if (!jwt) {
|
||||
return getJaasJWT(state);
|
||||
}
|
||||
})
|
||||
.then(j => {
|
||||
j && dispatch(setJWT(j));
|
||||
|
||||
return dispatch(_connectInternal(id, password));
|
||||
}).catch(e => {
|
||||
logger.error('Connection error', e);
|
||||
});
|
||||
}
|
||||
|
||||
dispatch(_connectInternal(id, password))
|
||||
|
||||
return (dispatch: IStore['dispatch']) => dispatch(_connectInternal(id, password))
|
||||
.catch(error => {
|
||||
if (error === JitsiConnectionErrors.NOT_LIVE_ERROR) {
|
||||
navigateRoot(screen.visitorsQueue);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,7 +11,6 @@ import LocalRecordingManager from '../../recording/components/Recording/LocalRec
|
||||
import { setJWT } from '../jwt/actions';
|
||||
|
||||
import { _connectInternal } from './actions.any';
|
||||
import logger from './logger';
|
||||
|
||||
export * from './actions.any';
|
||||
|
||||
@@ -39,8 +38,6 @@ export function connect(id?: string, password?: string) {
|
||||
j && dispatch(setJWT(j));
|
||||
|
||||
return dispatch(_connectInternal(id, password));
|
||||
}).catch(e => {
|
||||
logger.error('Connection error', e);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -150,7 +150,8 @@ export function getAvailableDevices() {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => new Promise(resolve => {
|
||||
const { mediaDevices } = JitsiMeetJS;
|
||||
|
||||
if (mediaDevices.isDeviceChangeAvailable()) {
|
||||
if (mediaDevices.isDeviceListAvailable()
|
||||
&& mediaDevices.isDeviceChangeAvailable()) {
|
||||
mediaDevices.enumerateDevices((devices: MediaDeviceInfo[]) => {
|
||||
const { filteredDevices, ignoredDevices } = filterIgnoredDevices(devices);
|
||||
const oldDevices = flattenAvailableDevices(getState()['features/base/devices'].availableDevices);
|
||||
|
||||
@@ -40,7 +40,6 @@ export default class AbstractDialog<P extends IProps, S extends IState = IState>
|
||||
super(props);
|
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._onBack = this._onBack.bind(this);
|
||||
this._onCancel = this._onCancel.bind(this);
|
||||
this._onSubmit = this._onSubmit.bind(this);
|
||||
this._onSubmitFulfilled = this._onSubmitFulfilled.bind(this);
|
||||
@@ -76,14 +75,6 @@ export default class AbstractDialog<P extends IProps, S extends IState = IState>
|
||||
return this.props.dispatch(hideDialog());
|
||||
}
|
||||
|
||||
_onBack() {
|
||||
const { backDisabled = false, onBack } = this.props;
|
||||
|
||||
if (!backDisabled && (!onBack || onBack())) {
|
||||
this._hide();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a redux action to hide this dialog when it's canceled.
|
||||
*
|
||||
|
||||
@@ -16,11 +16,6 @@ import styles from './styles';
|
||||
*/
|
||||
interface IProps extends AbstractProps, WithTranslation {
|
||||
|
||||
/**
|
||||
* The i18n key of the text label for the back button.
|
||||
*/
|
||||
backLabel?: string;
|
||||
|
||||
/**
|
||||
* The i18n key of the text label for the cancel button.
|
||||
*/
|
||||
@@ -41,11 +36,6 @@ interface IProps extends AbstractProps, WithTranslation {
|
||||
*/
|
||||
descriptionKey?: string | { key: string; params: string; };
|
||||
|
||||
/**
|
||||
* Whether the back button is hidden.
|
||||
*/
|
||||
isBackHidden?: Boolean;
|
||||
|
||||
/**
|
||||
* Whether the cancel button is hidden.
|
||||
*/
|
||||
@@ -65,11 +55,6 @@ interface IProps extends AbstractProps, WithTranslation {
|
||||
* Dialog title.
|
||||
*/
|
||||
title?: string;
|
||||
|
||||
/**
|
||||
* Renders buttons vertically.
|
||||
*/
|
||||
verticalButtons?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,17 +102,14 @@ class ConfirmDialog extends AbstractDialog<IProps> {
|
||||
*/
|
||||
override render() {
|
||||
const {
|
||||
backLabel,
|
||||
cancelLabel,
|
||||
children,
|
||||
confirmLabel,
|
||||
isBackHidden = true,
|
||||
isCancelHidden,
|
||||
isConfirmDestructive,
|
||||
isConfirmHidden,
|
||||
t,
|
||||
title,
|
||||
verticalButtons
|
||||
title
|
||||
} = this.props;
|
||||
|
||||
const dialogButtonStyle
|
||||
@@ -137,7 +119,6 @@ class ConfirmDialog extends AbstractDialog<IProps> {
|
||||
return (
|
||||
<Dialog.Container
|
||||
coverScreen = { false }
|
||||
verticalButtons = { verticalButtons }
|
||||
visible = { true }>
|
||||
{
|
||||
title && <Dialog.Title>
|
||||
@@ -146,12 +127,6 @@ class ConfirmDialog extends AbstractDialog<IProps> {
|
||||
}
|
||||
{ this._renderDescription() }
|
||||
{ children }
|
||||
{
|
||||
!isBackHidden && <Dialog.Button
|
||||
label = { t(backLabel || 'dialog.confirmBack') }
|
||||
onPress = { this._onBack }
|
||||
style = { styles.dialogButton } />
|
||||
}
|
||||
{
|
||||
!isCancelHidden && <Dialog.Button
|
||||
label = { t(cancelLabel || 'dialog.confirmNo') }
|
||||
|
||||
@@ -2,16 +2,6 @@ import { ReactNode } from 'react';
|
||||
|
||||
export type DialogProps = {
|
||||
|
||||
/**
|
||||
* Whether back button is disabled. Enabled by default.
|
||||
*/
|
||||
backDisabled?: boolean;
|
||||
|
||||
/**
|
||||
* Optional i18n key to change the back button title.
|
||||
*/
|
||||
backKey?: string;
|
||||
|
||||
/**
|
||||
* Whether cancel button is disabled. Enabled by default.
|
||||
*/
|
||||
@@ -37,11 +27,6 @@ export type DialogProps = {
|
||||
*/
|
||||
okKey?: string;
|
||||
|
||||
/**
|
||||
* The handler for onBack event.
|
||||
*/
|
||||
onBack?: Function;
|
||||
|
||||
/**
|
||||
* The handler for onCancel event.
|
||||
*/
|
||||
|
||||
@@ -72,11 +72,6 @@ interface IProps extends IIconProps {
|
||||
*/
|
||||
id?: string;
|
||||
|
||||
/**
|
||||
* On click handler.
|
||||
*/
|
||||
onClick?: (e?: any) => void;
|
||||
|
||||
/**
|
||||
* Keydown handler.
|
||||
*/
|
||||
|
||||
@@ -88,11 +88,6 @@ interface IProps {
|
||||
*/
|
||||
position: string;
|
||||
|
||||
/**
|
||||
* The ARIA role.
|
||||
*/
|
||||
role?: string;
|
||||
|
||||
/**
|
||||
* Whether the trigger for open/ close should be click or hover.
|
||||
*/
|
||||
@@ -488,24 +483,20 @@ class Popover extends Component<IProps, IState> {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderContent() {
|
||||
const { content, position, trigger, headingId, headingLabel, role = 'dialog' } = this.props;
|
||||
const isFocusLockEnabled = this.state.enableFocusLock;
|
||||
const isDialogRole = role === 'dialog';
|
||||
const { content, position, trigger, headingId, headingLabel } = this.props;
|
||||
|
||||
return (
|
||||
<div className = { `popover ${trigger}` }>
|
||||
<div
|
||||
className = { `popover-content ${position.split('-')[0]}` }
|
||||
data-autofocus = { isFocusLockEnabled }
|
||||
data-autofocus = { this.state.enableFocusLock }
|
||||
onKeyDown = { this._onEscKey }
|
||||
{ ...(isFocusLockEnabled && {
|
||||
role,
|
||||
tabIndex: -1
|
||||
}) }
|
||||
{ ...(isFocusLockEnabled && isDialogRole && {
|
||||
{ ...(this.state.enableFocusLock && {
|
||||
'aria-modal': true,
|
||||
'aria-label': !headingId && headingLabel ? headingLabel : undefined,
|
||||
'aria-labelledby': headingId ? headingId : undefined
|
||||
'aria-labelledby': headingId,
|
||||
role: 'dialog',
|
||||
tabIndex: -1
|
||||
}) }>
|
||||
{ content }
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,8 @@ import { batch } from 'react-redux';
|
||||
|
||||
import { IStore } from '../../app/types';
|
||||
import { CHAT_SIZE } from '../../chat/constants';
|
||||
import { getParticipantsPaneWidth } from '../../participants-pane/functions';
|
||||
import { getParticipantsPaneOpen } from '../../participants-pane/functions';
|
||||
import theme from '../components/themes/participantsPaneTheme.json';
|
||||
|
||||
import {
|
||||
CLIENT_RESIZED,
|
||||
@@ -42,23 +43,25 @@ export function clientResized(clientWidth: number, clientHeight: number) {
|
||||
|
||||
if (navigator.product !== 'ReactNative') {
|
||||
const state = getState();
|
||||
const { isOpen: isChatOpen, width } = state['features/chat'];
|
||||
const { isOpen: isChatOpen } = state['features/chat'];
|
||||
const isParticipantsPaneOpen = getParticipantsPaneOpen(state);
|
||||
|
||||
if (isChatOpen) {
|
||||
availableWidth -= width?.current ?? CHAT_SIZE;
|
||||
availableWidth -= CHAT_SIZE;
|
||||
}
|
||||
|
||||
availableWidth -= getParticipantsPaneWidth(state);
|
||||
if (isParticipantsPaneOpen) {
|
||||
availableWidth -= theme.participantsPaneWidth;
|
||||
}
|
||||
}
|
||||
|
||||
batch(() => {
|
||||
dispatch({
|
||||
type: CLIENT_RESIZED,
|
||||
clientHeight,
|
||||
clientWidth,
|
||||
videoSpaceWidth: availableWidth
|
||||
clientWidth: availableWidth
|
||||
});
|
||||
dispatch(setAspectRatio(availableWidth, clientHeight));
|
||||
dispatch(setAspectRatio(clientWidth, clientHeight));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,11 +18,3 @@ export const ASPECT_RATIO_WIDE = Symbol('ASPECT_RATIO_WIDE');
|
||||
* Smallest supported mobile width.
|
||||
*/
|
||||
export const SMALL_MOBILE_WIDTH = '320';
|
||||
|
||||
/**
|
||||
* The width for desktop that we start hiding elements from the UI (video quality label, filmstrip, etc).
|
||||
* This should match the value for $verySmallScreen in _variables.scss.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
export const SMALL_DESKTOP_WIDTH = 500;
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { IStateful } from '../app/types';
|
||||
import { isMobileBrowser } from '../environment/utils';
|
||||
import { toState } from '../redux/functions';
|
||||
import { SMALL_DESKTOP_WIDTH } from './constants';
|
||||
|
||||
/**
|
||||
* Determines if the screen is narrow with the chat panel open. If the function returns true video quality label,
|
||||
* filmstrip, etc will be hidden.
|
||||
*
|
||||
* @param {IStateful} stateful - The stateful object representing the application state.
|
||||
* @returns {boolean} - True if the screen is narrow with the chat panel open, otherwise `false`.
|
||||
*/
|
||||
export function isNarrowScreenWithChatOpen(stateful: IStateful) {
|
||||
const state = toState(stateful);
|
||||
const isDesktopBrowser = !isMobileBrowser();
|
||||
const { isOpen, width } = state['features/chat'];
|
||||
const { clientWidth } = state['features/base/responsive-ui'];
|
||||
|
||||
return isDesktopBrowser && isOpen && (width?.current + SMALL_DESKTOP_WIDTH) > clientWidth;
|
||||
}
|
||||
@@ -29,9 +29,9 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
break;
|
||||
|
||||
case CONFERENCE_JOINED: {
|
||||
const { clientHeight = 0, clientWidth = 0, videoSpaceWidth = 0 } = store.getState()['features/base/responsive-ui'];
|
||||
const { clientHeight = 0, clientWidth = 0 } = store.getState()['features/base/responsive-ui'];
|
||||
|
||||
if (!clientHeight && !clientWidth && !videoSpaceWidth) {
|
||||
if (!clientHeight && !clientWidth) {
|
||||
const {
|
||||
innerHeight,
|
||||
innerWidth
|
||||
|
||||
@@ -25,8 +25,7 @@ const DEFAULT_STATE = {
|
||||
clientWidth: innerWidth,
|
||||
isNarrowLayout: false,
|
||||
reducedUI: false,
|
||||
contextMenuOpened: false,
|
||||
videoSpaceWidth: innerWidth
|
||||
contextMenuOpened: false
|
||||
};
|
||||
|
||||
export interface IResponsiveUIState {
|
||||
@@ -42,7 +41,6 @@ export interface IResponsiveUIState {
|
||||
right: number;
|
||||
top: number;
|
||||
};
|
||||
videoSpaceWidth: number;
|
||||
}
|
||||
|
||||
ReducerRegistry.register<IResponsiveUIState>('features/base/responsive-ui',
|
||||
@@ -52,8 +50,7 @@ ReducerRegistry.register<IResponsiveUIState>('features/base/responsive-ui',
|
||||
return {
|
||||
...state,
|
||||
clientWidth: action.clientWidth,
|
||||
clientHeight: action.clientHeight,
|
||||
videoSpaceWidth: action.videoSpaceWidth
|
||||
clientHeight: action.clientHeight
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { IStore } from '../../app/types';
|
||||
import { PREJOIN_INITIALIZED } from '../../prejoin/actionTypes';
|
||||
import { setPrejoinPageVisibility } from '../../prejoin/actions';
|
||||
import { APP_WILL_MOUNT } from '../app/actionTypes';
|
||||
import { getJwtName } from '../jwt/functions';
|
||||
import { MEDIA_TYPE } from '../media/constants';
|
||||
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
@@ -24,6 +26,9 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
const result = next(action);
|
||||
|
||||
switch (action.type) {
|
||||
case APP_WILL_MOUNT:
|
||||
_initializeShowPrejoin(store);
|
||||
break;
|
||||
case PREJOIN_INITIALIZED:
|
||||
_maybeUpdateDisplayName(store);
|
||||
break;
|
||||
@@ -35,6 +40,21 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
return result;
|
||||
});
|
||||
|
||||
/**
|
||||
* Overwrites the showPrejoin flag based on cached used selection for showing prejoin screen.
|
||||
*
|
||||
* @param {Store} store - The redux store.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
function _initializeShowPrejoin({ dispatch, getState }: IStore) {
|
||||
const { userSelectedSkipPrejoin } = getState()['features/base/settings'];
|
||||
|
||||
if (userSelectedSkipPrejoin) {
|
||||
dispatch(setPrejoinPageVisibility(false));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the display name to the one in JWT if there is one.
|
||||
*
|
||||
|
||||
@@ -48,7 +48,8 @@ const DEFAULT_STATE: ISettingsState = {
|
||||
userSelectedNotifications: {
|
||||
'notify.chatMessages': true
|
||||
},
|
||||
userSelectedMicDeviceLabel: undefined
|
||||
userSelectedMicDeviceLabel: undefined,
|
||||
userSelectedSkipPrejoin: undefined
|
||||
};
|
||||
|
||||
export interface ISettingsState {
|
||||
@@ -87,6 +88,7 @@ export interface ISettingsState {
|
||||
userSelectedNotifications?: {
|
||||
[key: string]: boolean;
|
||||
};
|
||||
userSelectedSkipPrejoin?: boolean;
|
||||
videoSettingsVisible?: boolean;
|
||||
visible?: boolean;
|
||||
}
|
||||
|
||||
@@ -118,8 +118,8 @@ export const colorMap = {
|
||||
|
||||
|
||||
export const font = {
|
||||
weightRegular: '400',
|
||||
weightSemiBold: '600'
|
||||
weightRegular: 400,
|
||||
weightSemiBold: 600
|
||||
};
|
||||
|
||||
export const shape = {
|
||||
@@ -128,7 +128,8 @@ export const shape = {
|
||||
boxShadow: 'inset 0px -1px 0px rgba(255, 255, 255, 0.15)'
|
||||
};
|
||||
|
||||
export const spacing = [ 0, 4, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128 ];
|
||||
export const spacing
|
||||
= [ '0rem', '0.25rem', '0.5rem', '1rem', '1.5rem', '2rem', '2.5rem', '3rem', '3.5rem', '4rem', '4.5rem', '5rem', '5.5rem', '6rem', '6.5rem', '7rem', '7.5rem', '8rem' ];
|
||||
|
||||
export const typography = {
|
||||
labelRegular: 'label01',
|
||||
@@ -136,64 +137,64 @@ export const typography = {
|
||||
labelBold: 'labelBold01',
|
||||
|
||||
bodyShortRegularSmall: {
|
||||
fontSize: 10,
|
||||
lineHeight: 16,
|
||||
fontSize: '0.625rem',
|
||||
lineHeight: '1rem',
|
||||
fontWeight: font.weightRegular,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyShortRegular: {
|
||||
fontSize: 14,
|
||||
lineHeight: 20,
|
||||
fontSize: '0.875rem',
|
||||
lineHeight: '1.25rem',
|
||||
fontWeight: font.weightRegular,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyShortBold: {
|
||||
fontSize: 14,
|
||||
lineHeight: 20,
|
||||
fontSize: '0.875rem',
|
||||
lineHeight: '1.25rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyShortRegularLarge: {
|
||||
fontSize: 16,
|
||||
lineHeight: 22,
|
||||
fontSize: '1rem',
|
||||
lineHeight: '1.375rem',
|
||||
fontWeight: font.weightRegular,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyShortBoldLarge: {
|
||||
fontSize: 16,
|
||||
lineHeight: 22,
|
||||
fontSize: '1rem',
|
||||
lineHeight: '1.375rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyLongRegular: {
|
||||
fontSize: 14,
|
||||
lineHeight: 24,
|
||||
fontSize: '0.875rem',
|
||||
lineHeight: '1.5rem',
|
||||
fontWeight: font.weightRegular,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyLongRegularLarge: {
|
||||
fontSize: 16,
|
||||
lineHeight: 26,
|
||||
fontSize: '1rem',
|
||||
lineHeight: '1.625rem',
|
||||
fontWeight: font.weightRegular,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyLongBold: {
|
||||
fontSize: 14,
|
||||
lineHeight: 24,
|
||||
fontSize: '0.875rem',
|
||||
lineHeight: '1.5rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyLongBoldLarge: {
|
||||
fontSize: 16,
|
||||
lineHeight: 26,
|
||||
fontSize: '1rem',
|
||||
lineHeight: '1.625rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
},
|
||||
@@ -203,29 +204,29 @@ export const typography = {
|
||||
heading2: 'heading02',
|
||||
|
||||
heading3: {
|
||||
fontSize: 32,
|
||||
lineHeight: 40,
|
||||
fontSize: '2rem',
|
||||
lineHeight: '2.5rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
heading4: {
|
||||
fontSize: 28,
|
||||
lineHeight: 36,
|
||||
fontSize: '1.75rem',
|
||||
lineHeight: '2.25rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
heading5: {
|
||||
fontSize: 20,
|
||||
lineHeight: 28,
|
||||
fontSize: '1.25rem',
|
||||
lineHeight: '1.75rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
heading6: {
|
||||
fontSize: 16,
|
||||
lineHeight: 26,
|
||||
fontSize: '1rem',
|
||||
lineHeight: '1.625rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { GestureResponderEvent } from 'react-native';
|
||||
|
||||
import { BUTTON_TYPES } from '../constants.any';
|
||||
|
||||
export interface IButtonProps {
|
||||
@@ -30,7 +32,7 @@ export interface IButtonProps {
|
||||
/**
|
||||
* Click callback.
|
||||
*/
|
||||
onClick?: (e?: any) => void;
|
||||
onClick?: (e?: React.MouseEvent<HTMLButtonElement> | GestureResponderEvent) => void;
|
||||
|
||||
/**
|
||||
* Key press callback.
|
||||
|
||||
@@ -213,7 +213,7 @@ const ContextMenu = ({
|
||||
|
||||
if (offsetTop + height > offsetHeight + scrollTop && height > offsetTop) {
|
||||
// top offset and + padding + border
|
||||
container.style.maxHeight = `${offsetTop - ((spacing[2] * 2) + 2)}px`;
|
||||
container.style.maxHeight = `calc(${offsetTop}px - (${spacing[2]} * 2 + 2px))`;
|
||||
}
|
||||
|
||||
// get the height after style changes
|
||||
|
||||
@@ -224,7 +224,7 @@ const ContextMenuItem = ({
|
||||
tabIndex = selected ? 0 : -1;
|
||||
}
|
||||
|
||||
if ((role === 'button' || role === 'menuitem') && !disabled) {
|
||||
if (role === 'button' && !disabled) {
|
||||
tabIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,11 +15,6 @@ interface IProps {
|
||||
* The children of the component.
|
||||
*/
|
||||
children?: ReactNode;
|
||||
|
||||
/**
|
||||
* The optional role of the component.
|
||||
*/
|
||||
role?: string;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
@@ -46,15 +41,12 @@ const useStyles = makeStyles()(theme => {
|
||||
|
||||
const ContextMenuItemGroup = ({
|
||||
actions,
|
||||
children,
|
||||
...rest
|
||||
children
|
||||
}: IProps) => {
|
||||
const { classes: styles } = useStyles();
|
||||
|
||||
return (
|
||||
<div
|
||||
className = { styles.contextMenuItemGroup }
|
||||
{ ...rest }>
|
||||
<div className = { styles.contextMenuItemGroup }>
|
||||
{children}
|
||||
{actions?.map(actionProps => (
|
||||
<ContextMenuItem
|
||||
|
||||
@@ -173,16 +173,16 @@ const DialogWithTabs = ({
|
||||
const [ selectedTab, setSelectedTab ] = useState<string | undefined>(defaultTab ?? tabs[0].name);
|
||||
const [ userSelected, setUserSelected ] = useState(false);
|
||||
const [ tabStates, setTabStates ] = useState(tabs.map(tab => tab.props));
|
||||
const videoSpaceWidth = useSelector((state: IReduxState) => state['features/base/responsive-ui'].videoSpaceWidth);
|
||||
const clientWidth = useSelector((state: IReduxState) => state['features/base/responsive-ui'].clientWidth);
|
||||
const [ isMobile, setIsMobile ] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (videoSpaceWidth <= MOBILE_BREAKPOINT) {
|
||||
if (clientWidth <= MOBILE_BREAKPOINT) {
|
||||
!isMobile && setIsMobile(true);
|
||||
} else {
|
||||
isMobile && setIsMobile(false);
|
||||
}
|
||||
}, [ videoSpaceWidth, isMobile ]);
|
||||
}, [ clientWidth, isMobile ]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isMobile) {
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { useCallback, useEffect } from 'react';
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import { isMobileBrowser } from '../../../environment/utils';
|
||||
import Icon from '../../../icons/components/Icon';
|
||||
import { withPixelLineHeight } from '../../../styles/functions.web';
|
||||
|
||||
interface ITabProps {
|
||||
@@ -15,9 +14,8 @@ interface ITabProps {
|
||||
controlsId: string;
|
||||
countBadge?: number;
|
||||
disabled?: boolean;
|
||||
icon?: Function;
|
||||
id: string;
|
||||
label?: string;
|
||||
label: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
@@ -76,10 +74,6 @@ const useStyles = makeStyles()(theme => {
|
||||
borderRadius: '100%',
|
||||
backgroundColor: theme.palette.warning01,
|
||||
marginLeft: theme.spacing(2)
|
||||
},
|
||||
|
||||
icon: {
|
||||
marginRight: theme.spacing(1)
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -140,9 +134,6 @@ const Tabs = ({
|
||||
onKeyDown = { onKeyDown(index) }
|
||||
role = 'tab'
|
||||
tabIndex = { selected === tab.id ? undefined : -1 }>
|
||||
{tab.icon && <Icon
|
||||
className = { classes.icon }
|
||||
src = { tab.icon } />}
|
||||
{tab.label}
|
||||
{tab.countBadge && <span className = { classes.badge }>{tab.countBadge}</span>}
|
||||
</button>
|
||||
|
||||
@@ -2,6 +2,47 @@ import { DefaultTheme } from 'react-native-paper';
|
||||
|
||||
import { createColorTokens } from './utils';
|
||||
|
||||
// Base font size in pixels (standard is 16px = 1rem)
|
||||
const BASE_FONT_SIZE = 16;
|
||||
|
||||
/**
|
||||
* Converts rem to pixels.
|
||||
*
|
||||
* @param {string} remValue - The value in rem units (e.g. '0.875rem').
|
||||
* @returns {number}
|
||||
*/
|
||||
function remToPixels(remValue: string): number {
|
||||
const numericValue = parseFloat(remValue.replace('rem', ''));
|
||||
|
||||
return Math.round(numericValue * BASE_FONT_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts all rem to pixels in an object.
|
||||
*
|
||||
* @param {Object} obj - The object to convert rem values in.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function convertRemValues(obj: any): any {
|
||||
const converted: { [key: string]: any; } = {};
|
||||
|
||||
if (typeof obj !== 'object' || obj === null) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
Object.entries(obj).forEach(([ key, value ]) => {
|
||||
if (typeof value === 'string' && value.includes('rem')) {
|
||||
converted[key] = remToPixels(value);
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
converted[key] = convertRemValues(value);
|
||||
} else {
|
||||
converted[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
return converted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a React Native Paper theme based on local UI tokens.
|
||||
*
|
||||
@@ -13,10 +54,10 @@ export function createNativeTheme({ font, colorMap, shape, spacing, typography }
|
||||
...DefaultTheme,
|
||||
palette: createColorTokens(colorMap),
|
||||
shape,
|
||||
spacing,
|
||||
spacing: spacing.map(remToPixels),
|
||||
typography: {
|
||||
font,
|
||||
...typography
|
||||
...convertRemValues(typography)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Theme, adaptV4Theme, createTheme } from '@mui/material/styles';
|
||||
|
||||
import { ITypography, IPalette as Palette1 } from '../ui/types';
|
||||
|
||||
import { createColorTokens, createTypographyTokens } from './utils';
|
||||
import { createColorTokens } from './utils';
|
||||
|
||||
declare module '@mui/material/styles' {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
@@ -18,7 +18,7 @@ interface ThemeProps {
|
||||
colorMap: Object;
|
||||
font: Object;
|
||||
shape: Object;
|
||||
spacing: Array<number>;
|
||||
spacing: Array<number | string>;
|
||||
typography: Object;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ export function createWebTheme({ font, colorMap, shape, spacing, typography, bre
|
||||
typography: {
|
||||
// @ts-ignore
|
||||
font,
|
||||
...createTypographyTokens(typography)
|
||||
...typography
|
||||
},
|
||||
breakpoints
|
||||
}));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
interface ITypographyType {
|
||||
fontSize: number;
|
||||
fontWeight: number; // TODO: revisit this.
|
||||
fontWeight: string;
|
||||
letterSpacing: number;
|
||||
lineHeight: number;
|
||||
}
|
||||
|
||||
@@ -19,24 +19,3 @@ export function createColorTokens(colorMap: Object): any {
|
||||
return Object.assign(result, { [token]: color });
|
||||
}, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the typography tokens based on the typography theme and the association map.
|
||||
*
|
||||
* @param {Object} typography - A map between the token name and the actual typography value.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function createTypographyTokens(typography: Object): any {
|
||||
const allTokens = merge({}, tokens, jitsiTokens);
|
||||
|
||||
return Object.entries(typography)
|
||||
.reduce((result, [ token, value ]: [any, any]) => {
|
||||
let typographyValue = value;
|
||||
|
||||
if (typeof value === 'string') {
|
||||
typographyValue = allTokens[value as keyof typeof allTokens] || value;
|
||||
}
|
||||
|
||||
return Object.assign(result, { [token]: typographyValue });
|
||||
}, {});
|
||||
}
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
import { IReduxState } from '../../app/types';
|
||||
|
||||
/**
|
||||
* Checks if Jitsi Meet is running on Spot TV.
|
||||
*
|
||||
* @param {IReduxState} state - The redux state.
|
||||
* @returns {boolean} Whether or not Jitsi Meet is running on Spot TV.
|
||||
*/
|
||||
export function isSpotTV(state: IReduxState): boolean {
|
||||
const { defaultLocalDisplayName, iAmSpot } = state['features/base/config'] || {};
|
||||
|
||||
return iAmSpot
|
||||
|| navigator.userAgent.includes('JitsiSpot/') // Jitsi Spot app
|
||||
|| navigator.userAgent.includes('8x8MeetingRooms/') // 8x8 Meeting Rooms app
|
||||
|| defaultLocalDisplayName === 'Meeting Room';
|
||||
export function isSpotTV(): boolean {
|
||||
return navigator.userAgent.includes('SpotElectron/');
|
||||
}
|
||||
|
||||
@@ -115,51 +115,23 @@ export const SET_FOCUSED_TAB = 'SET_FOCUSED_TAB';
|
||||
* type: SET_LOBBY_CHAT_RECIPIENT
|
||||
* }
|
||||
*/
|
||||
export const SET_LOBBY_CHAT_RECIPIENT = 'SET_LOBBY_CHAT_RECIPIENT';
|
||||
export const SET_LOBBY_CHAT_RECIPIENT = 'SET_LOBBY_CHAT_RECIPIENT';
|
||||
|
||||
/**
|
||||
* The type of action sets the state of lobby messaging status.
|
||||
*
|
||||
* {
|
||||
* type: SET_LOBBY_CHAT_ACTIVE_STATE
|
||||
* payload: boolean
|
||||
* }
|
||||
*/
|
||||
export const SET_LOBBY_CHAT_ACTIVE_STATE = 'SET_LOBBY_CHAT_ACTIVE_STATE';
|
||||
/**
|
||||
* The type of action sets the state of lobby messaging status.
|
||||
*
|
||||
* {
|
||||
* type: SET_LOBBY_CHAT_ACTIVE_STATE
|
||||
* payload: boolean
|
||||
* }
|
||||
*/
|
||||
export const SET_LOBBY_CHAT_ACTIVE_STATE = 'SET_LOBBY_CHAT_ACTIVE_STATE';
|
||||
|
||||
/**
|
||||
* The type of action removes the lobby messaging from participant.
|
||||
*
|
||||
* {
|
||||
* type: REMOVE_LOBBY_CHAT_PARTICIPANT
|
||||
* }
|
||||
*/
|
||||
export const REMOVE_LOBBY_CHAT_PARTICIPANT = 'REMOVE_LOBBY_CHAT_PARTICIPANT';
|
||||
|
||||
/**
|
||||
* The type of action which signals to set the width of the chat panel.
|
||||
*
|
||||
* {
|
||||
* type: SET_CHAT_WIDTH,
|
||||
* width: number
|
||||
* }
|
||||
*/
|
||||
export const SET_CHAT_WIDTH = 'SET_CHAT_WIDTH';
|
||||
|
||||
/**
|
||||
* The type of action which sets the width for the chat panel (user resized).
|
||||
* {
|
||||
* type: SET_USER_CHAT_WIDTH,
|
||||
* width: number
|
||||
* }
|
||||
*/
|
||||
export const SET_USER_CHAT_WIDTH = 'SET_USER_CHAT_WIDTH';
|
||||
|
||||
/**
|
||||
* The type of action which sets whether the user is resizing the chat panel or not.
|
||||
* {
|
||||
* type: SET_CHAT_IS_RESIZING,
|
||||
* resizing: boolean
|
||||
* }
|
||||
*/
|
||||
export const SET_CHAT_IS_RESIZING = 'SET_CHAT_IS_RESIZING';
|
||||
/**
|
||||
* The type of action removes the lobby messaging from participant.
|
||||
*
|
||||
* {
|
||||
* type: REMOVE_LOBBY_CHAT_PARTICIPANT
|
||||
* }
|
||||
*/
|
||||
export const REMOVE_LOBBY_CHAT_PARTICIPANT = 'REMOVE_LOBBY_CHAT_PARTICIPANT';
|
||||
|
||||
@@ -2,12 +2,7 @@
|
||||
import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
|
||||
import { IStore } from '../app/types';
|
||||
|
||||
import {
|
||||
OPEN_CHAT,
|
||||
SET_CHAT_IS_RESIZING,
|
||||
SET_CHAT_WIDTH,
|
||||
SET_USER_CHAT_WIDTH
|
||||
} from './actionTypes';
|
||||
import { OPEN_CHAT } from './actionTypes';
|
||||
import { closeChat } from './actions.any';
|
||||
|
||||
export * from './actions.any';
|
||||
@@ -50,48 +45,3 @@ export function toggleChat() {
|
||||
VideoLayout.onResize();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chat panel's width.
|
||||
*
|
||||
* @param {number} width - The new width of the chat panel.
|
||||
* @returns {{
|
||||
* type: SET_CHAT_WIDTH,
|
||||
* width: number
|
||||
* }}
|
||||
*/
|
||||
export function setChatWidth(width: number) {
|
||||
return {
|
||||
type: SET_CHAT_WIDTH,
|
||||
width
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chat panel's width and the user preferred width.
|
||||
*
|
||||
* @param {number} width - The new width of the chat panel.
|
||||
* @returns {{
|
||||
* type: SET_USER_CHAT_WIDTH,
|
||||
* width: number
|
||||
* }}
|
||||
*/
|
||||
export function setUserChatWidth(width: number) {
|
||||
return {
|
||||
type: SET_USER_CHAT_WIDTH,
|
||||
width
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the user is resizing the chat panel or not.
|
||||
*
|
||||
* @param {boolean} resizing - Whether the user is resizing or not.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function setChatIsResizing(resizing: boolean) {
|
||||
return {
|
||||
type: SET_CHAT_IS_RESIZING,
|
||||
resizing
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { connect, useSelector } from 'react-redux';
|
||||
import React, { useCallback } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
import { throttle } from 'lodash-es';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import { getLocalParticipant } from '../../../base/participants/functions';
|
||||
import { withPixelLineHeight } from '../../../base/styles/functions.web';
|
||||
import Tabs from '../../../base/ui/components/web/Tabs';
|
||||
import { arePollsDisabled } from '../../../conference/functions.any';
|
||||
import FileSharing from '../../../file-sharing/components/web/FileSharing';
|
||||
import { isFileSharingEnabled } from '../../../file-sharing/functions.any';
|
||||
import PollsPane from '../../../polls/components/web/PollsPane';
|
||||
import { isCCTabEnabled } from '../../../subtitles/functions.any';
|
||||
import { setChatIsResizing, setUserChatWidth, sendMessage, setFocusedTab, toggleChat } from '../../actions.web';
|
||||
import { sendMessage, setFocusedTab, toggleChat } from '../../actions.web';
|
||||
import { CHAT_SIZE, ChatTabs, SMALL_WIDTH_THRESHOLD } from '../../constants';
|
||||
import { IChatProps as AbstractProps } from '../../types';
|
||||
import { IconMessage, IconInfo, IconSubtitles, IconShareDoc } from '../../../base/icons/svg';
|
||||
|
||||
import ChatHeader from './ChatHeader';
|
||||
import ChatInput from './ChatInput';
|
||||
@@ -24,7 +21,6 @@ import DisplayNameForm from './DisplayNameForm';
|
||||
import KeyboardAvoider from './KeyboardAvoider';
|
||||
import MessageContainer from './MessageContainer';
|
||||
import MessageRecipient from './MessageRecipient';
|
||||
import { getChatMaxSize } from '../../functions';
|
||||
|
||||
interface IProps extends AbstractProps {
|
||||
|
||||
@@ -38,11 +34,6 @@ interface IProps extends AbstractProps {
|
||||
*/
|
||||
_isCCTabEnabled: boolean;
|
||||
|
||||
/**
|
||||
* True if file sharing tab is enabled.
|
||||
*/
|
||||
_isFileSharingTabEnabled: boolean;
|
||||
|
||||
/**
|
||||
* Whether the chat is opened in a modal or not (computed based on window width).
|
||||
*/
|
||||
@@ -58,11 +49,6 @@ interface IProps extends AbstractProps {
|
||||
*/
|
||||
_isPollsEnabled: boolean;
|
||||
|
||||
/**
|
||||
* Whether the user is currently resizing the chat panel.
|
||||
*/
|
||||
_isResizing: boolean;
|
||||
|
||||
/**
|
||||
* Number of unread poll messages.
|
||||
*/
|
||||
@@ -98,30 +84,19 @@ interface IProps extends AbstractProps {
|
||||
* Whether or not to block chat access with a nickname input form.
|
||||
*/
|
||||
_showNamePrompt: boolean;
|
||||
|
||||
/**
|
||||
* The current width of the chat panel.
|
||||
*/
|
||||
_width: number;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles<{ _isResizing: boolean; width: number; }>()((theme, { _isResizing, width }) => {
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
container: {
|
||||
backgroundColor: theme.palette.ui01,
|
||||
flexShrink: 0,
|
||||
overflow: 'hidden',
|
||||
position: 'relative',
|
||||
transition: _isResizing ? undefined : 'width .16s ease-in-out',
|
||||
width: `${width}px`,
|
||||
transition: 'width .16s ease-in-out',
|
||||
width: `${CHAT_SIZE}px`,
|
||||
zIndex: 300,
|
||||
|
||||
'&:hover, &:focus-within': {
|
||||
'& .dragHandleContainer': {
|
||||
visibility: 'visible'
|
||||
}
|
||||
},
|
||||
|
||||
'@media (max-width: 580px)': {
|
||||
height: '100dvh',
|
||||
position: 'fixed',
|
||||
@@ -148,8 +123,7 @@ const useStyles = makeStyles<{ _isResizing: boolean; width: number; }>()((theme,
|
||||
alignItems: 'center',
|
||||
boxSizing: 'border-box',
|
||||
color: theme.palette.text01,
|
||||
...theme.typography.heading6,
|
||||
fontWeight: theme.typography.heading6.fontWeight as any,
|
||||
...withPixelLineHeight(theme.typography.heading6),
|
||||
|
||||
'.jitsi-icon': {
|
||||
cursor: 'pointer'
|
||||
@@ -172,48 +146,6 @@ const useStyles = makeStyles<{ _isResizing: boolean; width: number; }>()((theme,
|
||||
pollsPanel: {
|
||||
// extract header + tabs height
|
||||
height: 'calc(100% - 110px)'
|
||||
},
|
||||
|
||||
resizableChat: {
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
width: '100%'
|
||||
},
|
||||
|
||||
dragHandleContainer: {
|
||||
height: '100%',
|
||||
width: '9px',
|
||||
backgroundColor: 'transparent',
|
||||
position: 'absolute',
|
||||
cursor: 'col-resize',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
visibility: 'hidden',
|
||||
right: '4px',
|
||||
top: 0,
|
||||
|
||||
'&:hover': {
|
||||
'& .dragHandle': {
|
||||
backgroundColor: theme.palette.icon01
|
||||
}
|
||||
},
|
||||
|
||||
'&.visible': {
|
||||
visibility: 'visible',
|
||||
|
||||
'& .dragHandle': {
|
||||
backgroundColor: theme.palette.icon01
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
dragHandle: {
|
||||
backgroundColor: theme.palette.icon02,
|
||||
height: '100px',
|
||||
width: '3px',
|
||||
borderRadius: '1px'
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -223,9 +155,7 @@ const Chat = ({
|
||||
_isOpen,
|
||||
_isPollsEnabled,
|
||||
_isCCTabEnabled,
|
||||
_isFileSharingTabEnabled,
|
||||
_focusedTab,
|
||||
_isResizing,
|
||||
_messages,
|
||||
_nbUnreadMessages,
|
||||
_nbUnreadPolls,
|
||||
@@ -234,100 +164,10 @@ const Chat = ({
|
||||
_onToggleChatTab,
|
||||
_onTogglePollsTab,
|
||||
_showNamePrompt,
|
||||
_width,
|
||||
dispatch,
|
||||
t
|
||||
}: IProps) => {
|
||||
const { classes, cx } = useStyles({ _isResizing, width: _width });
|
||||
const [ isMouseDown, setIsMouseDown ] = useState(false);
|
||||
const [ mousePosition, setMousePosition ] = useState<number | null>(null);
|
||||
const [ dragChatWidth, setDragChatWidth ] = useState<number | null>(null);
|
||||
const maxChatWidth = useSelector(getChatMaxSize);
|
||||
|
||||
/**
|
||||
* Handles mouse down on the drag handle.
|
||||
*
|
||||
* @param {MouseEvent} e - The mouse down event.
|
||||
* @returns {void}
|
||||
*/
|
||||
const onDragHandleMouseDown = useCallback((e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
// Store the initial mouse position and chat width
|
||||
setIsMouseDown(true);
|
||||
setMousePosition(e.clientX);
|
||||
setDragChatWidth(_width);
|
||||
|
||||
// Indicate that resizing is in progress
|
||||
dispatch(setChatIsResizing(true));
|
||||
|
||||
// Add visual feedback that we're dragging
|
||||
document.body.style.cursor = 'col-resize';
|
||||
|
||||
// Disable text selection during resize
|
||||
document.body.style.userSelect = 'none';
|
||||
|
||||
console.log('Chat resize: Mouse down', { clientX: e.clientX, initialWidth: _width });
|
||||
}, [ _width, dispatch ]);
|
||||
|
||||
/**
|
||||
* Drag handle mouse up handler.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
const onDragMouseUp = useCallback(() => {
|
||||
if (isMouseDown) {
|
||||
setIsMouseDown(false);
|
||||
dispatch(setChatIsResizing(false));
|
||||
|
||||
// Restore cursor and text selection
|
||||
document.body.style.cursor = '';
|
||||
document.body.style.userSelect = '';
|
||||
|
||||
console.log('Chat resize: Mouse up');
|
||||
}
|
||||
}, [ isMouseDown, dispatch ]);
|
||||
|
||||
/**
|
||||
* Handles drag handle mouse move.
|
||||
*
|
||||
* @param {MouseEvent} e - The mousemove event.
|
||||
* @returns {void}
|
||||
*/
|
||||
const onChatResize = useCallback(throttle((e: MouseEvent) => {
|
||||
// console.log('Chat resize: Mouse move', { clientX: e.clientX, isMouseDown, mousePosition, _width });
|
||||
if (isMouseDown && mousePosition !== null && dragChatWidth !== null) {
|
||||
// For chat panel resizing on the left edge:
|
||||
// - Dragging left (decreasing X coordinate) should make the panel wider
|
||||
// - Dragging right (increasing X coordinate) should make the panel narrower
|
||||
const diff = e.clientX - mousePosition;
|
||||
|
||||
const newWidth = Math.max(
|
||||
Math.min(dragChatWidth + diff, maxChatWidth),
|
||||
CHAT_SIZE
|
||||
);
|
||||
|
||||
// Update the width only if it has changed
|
||||
if (newWidth !== _width) {
|
||||
dispatch(setUserChatWidth(newWidth));
|
||||
}
|
||||
}
|
||||
}, 50, {
|
||||
leading: true,
|
||||
trailing: false
|
||||
}), [ isMouseDown, mousePosition, dragChatWidth, _width, maxChatWidth, dispatch ]);
|
||||
|
||||
// Set up event listeners when component mounts
|
||||
useEffect(() => {
|
||||
document.addEventListener('mouseup', onDragMouseUp);
|
||||
document.addEventListener('mousemove', onChatResize);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mouseup', onDragMouseUp);
|
||||
document.removeEventListener('mousemove', onChatResize);
|
||||
};
|
||||
}, [ onDragMouseUp, onChatResize ]);
|
||||
const { classes, cx } = useStyles();
|
||||
|
||||
/**
|
||||
* Sends a text message.
|
||||
@@ -389,10 +229,7 @@ const Chat = ({
|
||||
aria-labelledby = { ChatTabs.CHAT }
|
||||
className = { cx(
|
||||
classes.chatPanel,
|
||||
!_isPollsEnabled
|
||||
&& !_isCCTabEnabled
|
||||
&& !_isFileSharingTabEnabled
|
||||
&& classes.chatPanelNoTabs,
|
||||
!_isPollsEnabled && !_isCCTabEnabled && classes.chatPanelNoTabs,
|
||||
_focusedTab !== ChatTabs.CHAT && 'hide'
|
||||
) }
|
||||
id = { `${ChatTabs.CHAT}-panel` }
|
||||
@@ -425,14 +262,6 @@ const Chat = ({
|
||||
tabIndex = { 2 }>
|
||||
<ClosedCaptionsTab />
|
||||
</div> }
|
||||
{ _isFileSharingTabEnabled && <div
|
||||
aria-labelledby = { ChatTabs.FILE_SHARING }
|
||||
className = { cx(classes.chatPanel, _focusedTab !== ChatTabs.FILE_SHARING && 'hide') }
|
||||
id = { `${ChatTabs.FILE_SHARING}-panel` }
|
||||
role = 'tabpanel'
|
||||
tabIndex = { 3 }>
|
||||
<FileSharing />
|
||||
</div> }
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -452,7 +281,7 @@ const Chat = ({
|
||||
_focusedTab !== ChatTabs.CHAT && _nbUnreadMessages > 0 ? _nbUnreadMessages : undefined,
|
||||
id: ChatTabs.CHAT,
|
||||
controlsId: `${ChatTabs.CHAT}-panel`,
|
||||
icon: IconMessage
|
||||
label: t('chat.tabs.chat')
|
||||
}
|
||||
];
|
||||
|
||||
@@ -462,7 +291,7 @@ const Chat = ({
|
||||
countBadge: _focusedTab !== ChatTabs.POLLS && _nbUnreadPolls > 0 ? _nbUnreadPolls : undefined,
|
||||
id: ChatTabs.POLLS,
|
||||
controlsId: `${ChatTabs.POLLS}-panel`,
|
||||
icon: IconInfo
|
||||
label: t('chat.tabs.polls')
|
||||
});
|
||||
}
|
||||
|
||||
@@ -472,32 +301,13 @@ const Chat = ({
|
||||
countBadge: undefined,
|
||||
id: ChatTabs.CLOSED_CAPTIONS,
|
||||
controlsId: `${ChatTabs.CLOSED_CAPTIONS}-panel`,
|
||||
icon: IconSubtitles
|
||||
});
|
||||
}
|
||||
|
||||
if (_isFileSharingTabEnabled) {
|
||||
tabs.push({
|
||||
accessibilityLabel: t('chat.tabs.fileSharing'),
|
||||
countBadge: undefined,
|
||||
id: ChatTabs.FILE_SHARING,
|
||||
controlsId: `${ChatTabs.FILE_SHARING}-panel`,
|
||||
icon: IconShareDoc
|
||||
label: t('chat.tabs.closedCaptions')
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
accessibilityLabel = { _isPollsEnabled || _isCCTabEnabled || _isFileSharingTabEnabled
|
||||
? t('chat.titleWithFeatures', {
|
||||
features: [
|
||||
_isPollsEnabled ? t('chat.titleWithPolls') : '',
|
||||
_isCCTabEnabled ? t('chat.titleWithCC') : '',
|
||||
_isFileSharingTabEnabled ? t('chat.titleWithFileSharing') : ''
|
||||
].filter(Boolean).join(', ')
|
||||
})
|
||||
: t('chat.title')
|
||||
}
|
||||
accessibilityLabel = { t(_isPollsEnabled ? 'chat.titleWithPolls' : 'chat.title') }
|
||||
onChange = { onChangeTab }
|
||||
selected = { _focusedTab }
|
||||
tabs = { tabs } />
|
||||
@@ -519,15 +329,6 @@ const Chat = ({
|
||||
isCCTabEnabled = { _isCCTabEnabled }
|
||||
isPollsEnabled = { _isPollsEnabled } />
|
||||
: renderChat()}
|
||||
<div
|
||||
className = { cx(
|
||||
classes.dragHandleContainer,
|
||||
(isMouseDown || _isResizing) && 'visible',
|
||||
'dragHandleContainer'
|
||||
) }
|
||||
onMouseDown = { onDragHandleMouseDown }>
|
||||
<div className = { cx(classes.dragHandle, 'dragHandle') } />
|
||||
</div>
|
||||
</div> : null
|
||||
);
|
||||
};
|
||||
@@ -548,13 +349,11 @@ const Chat = ({
|
||||
* _messages: Array<Object>,
|
||||
* _nbUnreadMessages: number,
|
||||
* _nbUnreadPolls: number,
|
||||
* _showNamePrompt: boolean,
|
||||
* _width: number,
|
||||
* _isResizing: boolean
|
||||
* _showNamePrompt: boolean
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state: IReduxState, _ownProps: any) {
|
||||
const { isOpen, focusedTab, messages, nbUnreadMessages, width, isResizing } = state['features/chat'];
|
||||
const { isOpen, focusedTab, messages, nbUnreadMessages } = state['features/chat'];
|
||||
const { nbUnreadPolls } = state['features/polls'];
|
||||
const _localParticipant = getLocalParticipant(state);
|
||||
|
||||
@@ -563,14 +362,11 @@ function _mapStateToProps(state: IReduxState, _ownProps: any) {
|
||||
_isOpen: isOpen,
|
||||
_isPollsEnabled: !arePollsDisabled(state),
|
||||
_isCCTabEnabled: isCCTabEnabled(state),
|
||||
_isFileSharingTabEnabled: isFileSharingEnabled(state),
|
||||
_focusedTab: focusedTab,
|
||||
_messages: messages,
|
||||
_nbUnreadMessages: nbUnreadMessages,
|
||||
_nbUnreadPolls: nbUnreadPolls,
|
||||
_showNamePrompt: !_localParticipant?.name,
|
||||
_width: width?.current || CHAT_SIZE,
|
||||
_isResizing: isResizing
|
||||
_showNamePrompt: !_localParticipant?.name
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user