Compare commits

...

85 Commits

Author SHA1 Message Date
Saúl Ibarra Corretgé
5e3463735b fix(polls) use medium timeout for poll notifications 2022-01-05 16:42:07 +01:00
tmoldovan8x8
7dd9785e48 fix(rn, recording) adds _toggleScreenshotCapture function to AbstractStopRecordingDialog 2022-01-05 16:52:20 +02:00
Hamza KHAIT
315c884f0d fix(lang) update French translation 2022-01-05 11:33:36 +01:00
José Luís Andrade
8590315244 fix(lang) update Portuguese Translation 2022-01-05 11:20:39 +01:00
Horatiu Muresan
6b260c27a5 fix(aot) Let jitsi-meet-electron-sdk do the close (#10679) 2022-01-04 13:21:30 +02:00
Horatiu Muresan
197dbfbbcb feat(toolbar-button-clicked) Enhance toolbar buttons with notify click
- add possibility to allow execution of the button's routine besides triggering
`toolbarButtonClicked` API event
- keep backwards compatibility
- get rid of `ToolbarButton`
2022-01-04 13:21:00 +02:00
Calin Chitu
847dc2a7bb fix(participants-pane) fix search value clear when closing pane 2022-01-04 10:52:42 +02:00
Christoph Settgast
7f26e7f927 fix(lang) update German translation 2021-12-28 07:15:37 +01:00
Mejans
6247d45b9e fix(lang) update Occitan translation 2021-12-24 17:30:52 +01:00
Дамян Минков
04f9ad32e1 fix(breakout-rooms): Adds few nil checks in lua code. 2021-12-23 14:40:39 -06:00
Дамян Минков
348414cc84 fix: Fixes muted state for moderators when login (secure-domain). 2021-12-23 13:47:25 -06:00
Robert Pintilii
804573e9aa fix(title-bar) Updated animation duration (#10688) 2021-12-23 15:06:14 +02:00
gpatel-fr
9dd3941388 fix(lang) make fr language file format consistent 2021-12-23 13:15:28 +01:00
Boris Grozev
f341a4e4eb fix: Add ipv6 networks to coturn's deny list. 2021-12-22 17:35:06 -06:00
Palych56
1c462996f5 Added translation of toolbar icons (#10563)
* Added translation of toolbar icons

* fix the indentation
2021-12-22 17:34:36 -06:00
Дамян Минков
1316c48964 chore(deps) lib-jitsi-meet@latest
* fix: Drop unused region info from presence.
* fix: Reads lobby jid from correct location in the error. (#1830)
* feat: Adjust setReceiverConstraints to use new format (#1813)

63c3e1f869...55a03ac1b5
2021-12-22 17:33:48 -06:00
Björn Broer
1080404de9 Add Dutch translations Participants Pane and Chat/Polls 2021-12-22 17:33:41 -06:00
Mariusz Krzaczkowski
55ef73875e [i18n] Update for Polish (#10643)
* [i18n] Update for Polish

* [i18n] Update for Polish

* [i18n] Update for Polish

* [i18n] Update for Polish

* [i18n] Update for Polish
2021-12-22 17:33:28 -06:00
Ali Alhaidary
afeb3e0e69 Update main-ar.json 2021-12-22 17:33:18 -06:00
gpatel-fr
ca227df7ec fix(lang) update french translation 2021-12-22 17:33:10 -06:00
Alexey Matveev
fb843a7ecf fix(lang) updated Russian translation 2021-12-22 17:32:53 -06:00
JohnProv
af985d8fd8 Update main-nl.json
Fix wrong change (e-mail > email)
2021-12-22 17:32:45 -06:00
Дамян Минков
8d62e010e0 feat: Skips notifications for messages from history (the messages on join). 2021-12-22 16:13:12 -06:00
Дамян Минков
1c4283eeca feat: Edits messages display name on breakout info received. Fixes #10671. 2021-12-22 16:13:12 -06:00
Дамян Минков
c64d1a97c1 feat: Adds internal action for editing chat messages. 2021-12-22 16:13:12 -06:00
Дамян Минков
6159504478 feat: Adds id to chat messages internal state. 2021-12-22 16:13:12 -06:00
Дамян Минков
f2efdfcbc1 feat: Drop unused constants. 2021-12-22 16:13:12 -06:00
Дамян Минков
6682167800 fix: Fixes showing user region. 2021-12-22 15:39:33 -06:00
Дамян Минков
b084aae212 fix: Generates correct join error for lobby. (#10673)
* fix: Drops wrong x tag.

* fix: Generates correct join error for lobby.

We were adding lobbyroom element in a location that violates the rfc and xmpp errors.
We add now and the correct one and will drop the wrong node when all clients are updated.
https://datatracker.ietf.org/doc/html/draft-ietf-xmpp-3920bis#section-8.3.2

* squash: Add todo comment.

* squash: Updates namespace.
2021-12-22 14:40:20 -06:00
Calin Chitu
a436a889a9 fix(base) fixed text going out of share meeting container 2021-12-21 15:24:38 +02:00
Robert Pintilii
9816be4745 fix(participants-pane) Make search work with breakout rooms (#10668)
Web and native
2021-12-21 14:51:39 +02:00
Gabriel Borlea
b9e182b7cc feat(facial-expressions): send facial expressions to webhook endpoint (#10585) 2021-12-21 13:46:54 +02:00
Robert Pintilii
da2b920dbe feat(conference-info) Updated title bar (#10670)
Updated animations
Added raised hands counter
Added max width to title bar
2021-12-21 12:22:30 +02:00
Horatiu Muresan
d22d95e8a5 fix(prejoin) Consider user selection for prejoin only on mount 2021-12-20 11:34:40 +02:00
Robert Pintilii
d44660527b fix(thumbnail) Update tile resizing constraints (#10645)
disableTileEnlargement config now uses old behaviour (small tiles, not just small video in the tiles)
Update Firefox scrollbar style to match webkit
Show more rows when height allows it instead of stretching a fixed number of rows, but make sure we always try to fill the whole viewport
Added constraints for how narrow portrait tiles can be and how wide landscape tiles can be
Video should cover whole tile in tile view unless disableTileEnlargement is set or video is portrait
Added min height in px for tiles
2021-12-20 11:32:31 +02:00
Mihaela Dumitru
5cc3fade8f feat(config): add flag to hide the participant display name (#10650) 2021-12-20 10:46:47 +02:00
Gabriel Borlea
f8340bfd41 fix(speaker-stats): responsiveness of facial expressions (#10664) 2021-12-20 10:45:54 +02:00
Robert Pintilii
a7bf037363 feat(raise-hand) Update raised hand design (#10651)
Updated indicator color and background color
Added border on thumbnails
Web and Native
2021-12-20 10:44:22 +02:00
Robert Pintilii
a42483c84b fix(rn, tileview) Add SafeAreaView to Tile View (#10642) 2021-12-20 10:27:55 +02:00
tmoldovan8x8
476ddeac41 fix(rn, recording) adds _toggleScreenshotCapture function to AbstractStartRecordingDialog 2021-12-20 08:41:29 +02:00
Hristo Terezov
12bc054386 feat(Avatar): CORS mode support. 2021-12-17 14:41:11 -06:00
Дамян Минков
32aa40b396 fix(breakout-rooms): Fix polls usage. 2021-12-17 13:53:00 -06:00
Ali Alhaidary
11bbedf9ac fix(lang) updated Arabic translation 2021-12-17 17:57:06 +01:00
Robert Pintilii
56883f0a65 fix(theme) Update colors (#10649) 2021-12-17 15:05:12 +02:00
Mihaela Dumitru
8e9034601d feat(chat/settings) - add ephemeral chat notifications with user settings support (#10617) 2021-12-17 14:39:15 +02:00
wfleischer
ce0a044742 fix(breakout-rooms): close option shown to non-moderators (#10648)
Co-authored-by: Werner Fleischer <70745309+wernf@users.noreply.github.com>
2021-12-17 14:11:01 +02:00
Mihaela Dumitru
39e0dc84e0 feat(external-api): add local subject command (#10636)
* feat(external-api): add local subject command

* add to whitelist

* apply config value
2021-12-17 09:38:15 +02:00
Дамян Минков
09613167a6 fix(breakout-rooms): Adds a check for missing room. 2021-12-16 12:04:53 -06:00
William Liang
5461bb52c8 feat: Update video receiver constraints to use source names (#10527)
* feat: Use source name based receiver constraints

* add sourceNameSignaling feature flag to config

* move source name specific variables into if block

* ensure sourceName is defined in constraints

* use source name for selectedSources

* use selector to find video track by participant id

* add selector to encapsulate logic to get track source name

* refactor getTrackSourceNameByMediaTypeAndParticipant selector

* rename variable

* move flags config into Feature Flags section

* do not set constraints for local large video

* rename prioritizedSources to onStageSources

* fix flow error

* refactor visibleRemoteTrackSourceNames to a constant

* use selector to get feature flags

* rename selector function

* fix flow error

* add selector for sourceNameSignaling feature flag
2021-12-16 11:49:36 -06:00
Дамян Минков
5dee37dd82 Self view refactor (#10620)
* feat: Drops hide self-view setting from profile tab.

* feat: Moves function for disableSelfView value in base/settings.

* squash: Drops notification.

* feat: Move hide self view option in more tab.

* feat: Move hide self view option in more tab.

* feat: Adds option to disable self view UI settings.

* squash: Disable settings when controlled from config.
2021-12-16 10:55:45 -06:00
Luis Guzman
2a236b9327 fix(lang) update Spanish translation 2021-12-16 17:40:44 +01:00
Дамян Минков
e7bac3ad44 fix: Fixes emitting conference left event in iframeAPI.
Moving to breakout room and back in main room do not fire videoConferenceLeft events.
And the videoConferenceJoined was reporting wrong conference name on join.
2021-12-16 09:40:14 -06:00
Avram Tudor
ffe74ca68b fix(tile-view) fix screensharing size in self view (#10634)
clean-up overriden css for tileview video tags
2021-12-16 15:33:30 +02:00
Дамян Минков
c8b5043d6b fix: Fixes destroying main room when breakout rooms are enabled.
By the time the timer is fired the room maybe recreated (destroyed and created again) and we do not want to destroy it again. The timer was keeping a reference to the old room and is destroying it without notifying the future occupants(jicofo).
Drop save, as we do not need it before destroying, check lobby.
2021-12-15 21:59:23 -06:00
Shawn
8fa22ce059 fix: participant join notifications 2021-12-15 21:59:14 -06:00
jan-di-cgm
a6ec9e9f5d Fix default values for hideConferenceSubject/-Timer 2021-12-15 20:06:21 -06:00
Jaya Allamsetty
ea2407191a chore(deps) lib-jitsi-meet@latest
* fix(xmpp): fix race in p2p set codecs

d630bc32a1...63c3e1f869
2021-12-15 16:28:30 -05:00
José Luís Andrade
ea485f9974 fix(lang) update Portuguese translation 2021-12-15 16:12:47 +01:00
Robert Pintilii
91437c50e3 feat(thumbnail) Video thumbnails redesign and refactor (#10351)
Update video thumbnail design
Update design of indicators
In filmstrip view move Screen Sharing indicator to the top
Removed dominant speaker indicator
Use ContextMenu component for the connection stats popover
Combine Remove video menu and Meeting participant context menu into one component
Moved some styles from SCSS to JSS
Fix mobile avatars too big
Fix mobile horizontal scroll
Created button for Send to breakout room action
2021-12-15 15:18:41 +02:00
Jasper
0503a83667 fix(lang) update Dutch translations 2021-12-15 08:18:50 +01:00
Дамян Минков
648b22bb6d fix: Use default remote display name in speaker stats when one is missing. 2021-12-14 09:29:41 -06:00
Дамян Минков
715b22bfb5 fix: Respects disable reactions moderation flag for popups. 2021-12-14 09:29:41 -06:00
Robert Pintilii
913945e820 fix(overflow-menu) Use fixed height only on drawer (#10612) 2021-12-14 13:39:01 +02:00
Ashiq Hassan
0e717d8388 fix(config.js) Added missing participant left notification key. 2021-12-14 12:07:10 +01:00
Vlad Piersec
d2619b4dd3 fix(Prejoin): Allow changing 'Enable pre meeting screen' option while prejoin screen visible 2021-12-14 10:52:28 +02:00
Vlad Piersec
35b76a2f7c fix(Avatar): Fix initials when avatar contains multiple special characters 2021-12-14 10:47:05 +02:00
Дамян Минков
f620d101ba fix: Fixes disable moderation sounds in meeting. (#10604)
* fix: Fixes disable moderation sounds in meeting.

Moderators in the meeting were sending presence update after one moderator turn it on, which even my result a inconsistent state and flipping the state between moderators several times.

* squash: Adds option to disable reaction moderation.
2021-12-13 13:46:05 -06:00
Horatiu Muresan
70d8a46c05 feat(profile-settings): Hide email field under profile settings 2021-12-13 17:17:38 +02:00
Gabriel Borlea
40844afb60 fix(speaker-stats): prevent search from closing when enter pressed and from keeping previous state (#10597)
* fix(speaker-stats): prevent search from closing when enter pressed and from keeping previous state

* fix(speaker-stats): remove unnecessary blank lines

* fix(speaker-stats): add empty dependencies to prevent dismiss callback

* add(speaker-stats): reset search criteria action
2021-12-13 16:11:07 +02:00
Robert Pintilii
a6a24fa973 fix(overflow-menu) Pin reactions on menu bottom on mobile web (#10599)
Move some styles from SCSS to JSS
2021-12-13 15:51:05 +02:00
Vlad Piersec
69cbb7e103 fix(Polls): Calculate vote percentage based on total number of votes
Percentage was previously calculated based on number of voters
2021-12-13 12:54:36 +02:00
Vlad Piersec
f20a50d8a6 feat(i18n): Allow label rewrite via advanced branding 2021-12-13 12:02:34 +02:00
Saúl Ibarra Corretgé
df3545d287 fix(rn) fix broken mobile build
Importing the entire feature triggers web UI imports.
2021-12-11 16:55:46 +01:00
Christoph Settgast
22d782f61f fix(lang) update German translation 2021-12-11 12:44:09 +01:00
Дамян Минков
ce195d82d6 chore(deps) lib-jitsi-meet@latest
* fix: Fixes set effect and correct presence state.

8a95fda259...d630bc32a1
2021-12-10 15:39:51 -06:00
Jaya Allamsetty
229e65133c feat(media) Disable desktopshare when the video sender limit is reached. 2021-12-10 14:58:55 -05:00
Jaya Allamsetty
11eb6689dc chore(deps) lib-jitsi-meet@latest
* fix(presence): Do not sent presence if there is no active media session.
* fix: server-side callstats is never enabled (#1823)
* fix(JitsiConference) squelch bogus p2p session end error

8aa35dae40...8a95fda259
2021-12-10 12:23:43 -05:00
Calinteodor
bf3cc65f4c feat(security) created SecurityOptions React Navigation screen (#10509)
* feat(security) Security Options screen
2021-12-10 18:23:27 +02:00
Hristo Terezov
75e6dd389f feat(index.html): Add fonts.html SSI. 2021-12-10 10:20:54 -06:00
Rokixy
076113940b typo fix
dekstopAudioStream --> desktopAudioStream
2021-12-10 09:03:18 -06:00
Saúl Ibarra Corretgé
e6accd40e1 fix(breakout-rooms) ensure we use the same media types when joining
Only audio and video are considered. Screen sharing won't be preserved.
2021-12-10 15:51:06 +01:00
Saúl Ibarra Corretgé
7f0cfed981 fix(rn,breakout-rooms) create desired local tracks when joining rooms 2021-12-10 15:50:11 +01:00
Saúl Ibarra Corretgé
9279586e8c fix(tracks) fix disposing of local tracks
Don't just clear the storage for them, local tracks must be disposed, in order
for RN capturer to be freed for example.
2021-12-10 15:49:44 +01:00
Robert Pintilii
f8908c143e fix(disableSelfView) Fix issue with remote participant video (#10582)
Fix issue where last participant is shown as inactive when the self view is hidden
2021-12-10 15:16:02 +02:00
Saúl Ibarra Corretgé
c705dbaa2f fix(rn,breakout-rooms) fix not rendering display names 2021-12-10 13:37:59 +01:00
285 changed files with 5344 additions and 4208 deletions

View File

@@ -68,6 +68,7 @@ dependencies {
implementation project(':react-native-async-storage')
implementation project(':react-native-background-timer')
implementation project(':react-native-calendar-events')
implementation project(':react-native-community_clipboard')
implementation project(':react-native-community_netinfo')
implementation project(':react-native-default-preference')
implementation project(':react-native-gesture-handler')

View File

@@ -180,6 +180,7 @@ class ReactInstanceManagerHolder {
new com.calendarevents.CalendarEventsPackage(),
new com.corbt.keepawake.KCKeepAwakePackage(),
new com.facebook.react.shell.MainReactPackage(),
new com.reactnativecommunity.clipboard.ClipboardPackage(),
new com.reactnativecommunity.netinfo.NetInfoPackage(),
new com.oblador.performance.PerformancePackage(),
new com.reactnativecommunity.slider.ReactSliderPackage(),

View File

@@ -9,6 +9,8 @@ include ':react-native-background-timer'
project(':react-native-background-timer').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-background-timer/android')
include ':react-native-calendar-events'
project(':react-native-calendar-events').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-calendar-events/android')
include ':react-native-community_clipboard'
project(':react-native-community_clipboard').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/clipboard/android')
include ':react-native-community_netinfo'
project(':react-native-community_netinfo').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/netinfo/android')
include ':react-native-default-preference'

View File

@@ -135,7 +135,6 @@ import { mediaPermissionPromptVisibilityChanged, toggleSlowGUMOverlay } from './
import { suspendDetected } from './react/features/power-monitor';
import {
initPrejoin,
isPrejoinPageEnabled,
isPrejoinPageVisible,
makePrecallTest,
setJoiningInProgress,
@@ -797,7 +796,7 @@ export default {
logger.warn('initial device list initialization failed', error);
}
if (isPrejoinPageEnabled(APP.store.getState())) {
if (isPrejoinPageVisible(APP.store.getState())) {
_connectionPromise = connect(roomName).then(c => {
// we want to initialize it early, in case of errors to be able
// to gather logs
@@ -1333,18 +1332,19 @@ export default {
/**
* Used by the Breakout Rooms feature to join a breakout room or go back to the main room.
*/
async joinRoom(roomName) {
async joinRoom(roomName, options) {
// Reset VideoLayout. It's destroyed in features/video-layout/middleware.web.js so re-initialize it.
VideoLayout.initLargeVideo();
VideoLayout.resizeVideoArea();
// Destroy old tracks.
APP.store.dispatch(destroyLocalTracks());
// Restore initial state.
this._localTracksInitialized = false;
this.isSharingScreen = false;
this.localPresenterVideo = null;
this.roomName = roomName;
const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks();
const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(options);
const localTracks = await tryCreateLocalTracks;
this._displayErrorsForCreateInitialLocalTracks(errors);
@@ -1710,10 +1710,10 @@ export default {
= this._turnScreenSharingOff.bind(this, didHaveVideo);
const desktopVideoStream = desktopStreams.find(stream => stream.getType() === MEDIA_TYPE.VIDEO);
const dekstopAudioStream = desktopStreams.find(stream => stream.getType() === MEDIA_TYPE.AUDIO);
const desktopAudioStream = desktopStreams.find(stream => stream.getType() === MEDIA_TYPE.AUDIO);
if (dekstopAudioStream) {
dekstopAudioStream.on(
if (desktopAudioStream) {
desktopAudioStream.on(
JitsiTrackEvents.LOCAL_TRACK_STOPPED,
() => {
logger.debug(`Local screensharing audio track stopped. ${this.isSharingScreen}`);

122
config.js
View File

@@ -74,18 +74,30 @@ var config = {
// callStatsThreshold: 5 // enable callstats for 5% of the users.
},
// Feature Flags.
flags: {
// Enables source names in the signaling.
// sourceNameSignaling: false,
},
// Disables moderator indicators.
// disableModeratorIndicator: false,
// Disables the reactions feature.
// disableReactions: true,
// Disables the reactions moderation feature.
// disableReactionsModeration: false,
// Disables polls feature.
// disablePolls: false,
// Disables self-view tile. (hides it from tile view and from filmstrip)
// disableSelfView: false,
// Disables self-view settings in UI
// disableSelfViewSettings: false,
// Disables ICE/UDP by filtering out local and remote UDP candidates in
// signalling.
// webrtcIceUdpDisable: false,
@@ -478,12 +490,18 @@ var config = {
// Default remote name to be displayed
// defaultRemoteDisplayName: 'Fellow Jitster',
// Hides the display name from the participant thumbnail
// hideDisplayName: false
// Default language for the user interface.
// defaultLanguage: 'en',
// Disables profile and the edit of all fields from the profile settings (display name and email)
// disableProfile: false,
// Hides the email section under profile settings.
// hideEmailInSettings: false,
// Whether or not some features are checked based on token.
// enableFeaturesBasedOnToken: false,
@@ -528,6 +546,9 @@ var config = {
// Document should be focused for this option to work
// enableAutomaticUrlCopy: false,
// Array with avatar URL prefixes that need to use CORS.
// corsAvatarURLs: [ 'https://www.gravatar.com/avatar/' ],
// Base URL for a Gravatar-compatible service. Defaults to libravatar.
// gravatarBaseURL: 'https://seccdn.libravatar.org/avatar/',
@@ -594,41 +615,61 @@ var config = {
// alwaysVisible: false
// },
// Toolbar buttons which have their click event exposed through the API on
// `toolbarButtonClicked` event instead of executing the normal click routine.
// Toolbar buttons which have their click/tap event exposed through the API on
// `toolbarButtonClicked`. Passing a string for the button key will
// prevent execution of the click/tap routine; passing an object with `key` and
// `preventExecution` flag on false will not prevent execution of the click/tap
// routine. Below array with mixed mode for passing the buttons.
// buttonsWithNotifyClick: [
// 'camera',
// 'chat',
// 'closedcaptions',
// 'desktop',
// 'download',
// 'embedmeeting',
// 'etherpad',
// 'feedback',
// 'filmstrip',
// 'fullscreen',
// 'hangup',
// 'help',
// 'invite',
// 'livestreaming',
// 'microphone',
// 'mute-everyone',
// 'mute-video-everyone',
// 'participants-pane',
// 'profile',
// 'raisehand',
// 'recording',
// 'security',
// 'select-background',
// 'settings',
// 'shareaudio',
// 'sharedvideo',
// 'shortcuts',
// 'stats',
// 'tileview',
// 'toggle-camera',
// 'videoquality',
// '__end'
// 'camera',
// {
// key: 'chat',
// preventExecution: false
// },
// {
// key: 'closedcaptions',
// preventExecution: true
// },
// 'desktop',
// 'download',
// 'embedmeeting',
// 'etherpad',
// 'feedback',
// 'filmstrip',
// 'fullscreen',
// 'hangup',
// 'help',
// {
// key: 'invite',
// preventExecution: false
// },
// 'livestreaming',
// 'microphone',
// 'mute-everyone',
// 'mute-video-everyone',
// 'participants-pane',
// 'profile',
// {
// key: 'raisehand',
// preventExecution: true
// },
// 'recording',
// 'security',
// 'select-background',
// 'settings',
// 'shareaudio',
// 'sharedvideo',
// 'shortcuts',
// 'stats',
// 'tileview',
// 'toggle-camera',
// 'videoquality',
// // The add passcode button from the security dialog.
// {
// key: 'add-passcode',
// preventExecution: false
// }
// '__end'
// ],
// List of pre meeting screens buttons to hide. The values must be one or more of the 5 allowed buttons:
@@ -1011,7 +1052,7 @@ var config = {
// If a label's id is not in any of the 2 arrays, it will not be visible at all on the header.
// conferenceInfo: {
// // those labels will not be hidden in tandem with the toolbox.
// alwaysVisible: ['recording', 'local-recording'],
// alwaysVisible: ['recording', 'local-recording', 'raised-hands-count'],
// // those labels will be auto-hidden in tandem with the toolbox buttons.
// autoHide: [
// 'subject',
@@ -1025,10 +1066,10 @@ var config = {
// },
// Hides the conference subject
// hideConferenceSubject: true,
// hideConferenceSubject: false,
// Hides the conference timer.
// hideConferenceTimer: true,
// hideConferenceTimer: false,
// Hides the recording label
// hideRecordingLabel: false,
@@ -1039,6 +1080,9 @@ var config = {
// Sets the conference subject
// subject: 'Conference Subject',
// Sets the conference local subject
// localSubject: 'Conference Local Subject',
// This property is related to the use case when jitsi-meet is used via the IFrame API. When the property is true
// jitsi-meet will use the local storage of the host page instead of its own. This option is useful if the browser
// is not persisting the local storage inside the iframe.
@@ -1143,10 +1187,14 @@ var config = {
// 'lobby.joinRejectedMessage', // shown when while in a lobby, user's request to join is rejected
// 'lobby.notificationTitle', // shown when lobby is toggled and when join requests are allowed / denied
// 'localRecording.localRecording', // shown when a local recording is started
// 'notify.chatMessages', // shown when receiving chat messages while the chat window is closed
// 'notify.disconnected', // shown when a participant has left
// 'notify.connectedOneMember', // show when a participant joined
// 'notify.connectedTwoMembers', // show when two participants joined simultaneously
// 'notify.connectedThreePlusMembers', // show when more than 2 participants joined simultaneously
// 'notify.leftOneMember', // show when a participant left
// 'notify.leftTwoMembers', // show when two participants left simultaneously
// 'notify.leftThreePlusMembers', // show when more than 2 participants left simultaneously
// 'notify.grantedTo', // shown when moderator rights were granted to a participant
// 'notify.invitedOneMember', // shown when 1 participant has been invited
// 'notify.invitedThreePlusMembers', // shown when 3+ participants have been invited

View File

@@ -24,14 +24,6 @@
bottom: calc(#{$newToolbarSizeWithPadding}) !important;
}
/**
* Override @atlaskit/theme styling for the top toolbar so it displays over
* the video thumbnail while obscuring as little as possible.
*/
.videocontainer__toptoolbar > div > div {
background: none;
}
/**
* Keep overflow menu within screen vertical bounds and make it scrollable.

View File

@@ -6,6 +6,10 @@
* {
-webkit-user-select: none;
user-select: none;
// Firefox only
scrollbar-width: thin;
scrollbar-color: rgba(0, 0, 0, .5) transparent;
}
input,

View File

@@ -24,10 +24,9 @@
}
.drawer-menu {
max-height: calc(80vh - 64px);
background: #242528;
border-radius: 16px 16px 0 0;
overflow-y: scroll;
overflow-y: auto;
margin-bottom: env(safe-area-inset-bottom, 0);
width: 100%;
@@ -43,15 +42,6 @@
}
}
.popupmenu {
margin: auto;
width: 100%;
}
.popupmenu__item {
height: 48px;
}
&#{&} .overflow-menu {
margin: auto;
font-size: 1.2em;

View File

@@ -43,10 +43,5 @@
.popover {
margin: -16px -24px;
padding: 16px 24px;
z-index: $popoverZ;
}
.padded-content {
padding: 4px 8px;
}

View File

@@ -2,122 +2,18 @@
* Initialize
**/
.popupmenu {
background-color: $menuBG;
border-radius: 3px;
list-style-type: none;
min-width: 150px;
text-align: left;
padding: 0px;
white-space: nowrap;
.popupmenu__contents {
.popupmenu__volume-slider {
&::-webkit-slider-runnable-track {
background-color: $popupSliderColor;
}
&__item {
list-style-type: none;
height: 35px;
}
&::-moz-range-track {
background-color: $popupSliderColor;
}
// Link Appearance
&__link,
&__contents {
display: block;
box-sizing: border-box;
text-decoration: none;
height: 100%;
font-size: 9pt;
width: 100%;
cursor: pointer;
padding: 0 5px;
color: $popupMenuColor;
&:hover {
background-color: $popupMenuHoverBackground;
color: $popupMenuHoverColor;
}
&.disabled {
pointer-events: none;
}
}
&__list {
margin: 0;
padding: 0;
}
&__text {
display: inline-block;
margin-left: 8px;
vertical-align: middle;
}
&__link {
i {
cursor: pointer;
}
}
&__contents {
display: flex;
/**
* Positioning styles on the slider and its container are used to make
* the container fit the popup width, by removing the slider from the
* page flow, and then making the slider fit the container.
*/
.popupmenu__slider_container {
position: relative;
width: 100%;
.popupmenu__slider {
position: absolute;
top: 50%;
transform: translate(0, -50%);
width: 100%;
&::-webkit-slider-runnable-track {
background-color: $popupSliderColor;
}
&::-moz-range-track {
background-color: $popupSliderColor;
}
&::-ms-fill-lower {
background-color: $popupSliderColor;
}
&::-ms-fill-lower {
background-color: $popupSliderColor;
}
}
}
&__icon {
vertical-align: middle;
position: relative;
display: inline-block;
min-width: 20px;
height: 100%;
padding-right: 10px;
> * {
@include absoluteAligning();
}
}
.icon-kick,
.icon-play,
.icon-stop {
font-size: 8pt;
}
}
/**
* Override reset css styling modifying all lists and set negative margin to
* reduce the visibility of padding on AtlasKit
* InlineDialogs.
*/
ul.popupmenu {
margin: -16px -24px;
}
span.localvideomenu:hover ul.popupmenu, span.remotevideomenu:hover ul.popupmenu, ul.popupmenu:hover {
display:block !important;
}

View File

@@ -8,12 +8,6 @@
padding: 16px;
&.overflow {
width: auto;
padding-bottom: max(env(safe-area-inset-bottom, 0), 16px);
background-color: #141414;
box-shadow: none;
border-radius: 0;
position: relative;
.toolbox-icon {
width: 48px;

View File

@@ -1,11 +1,25 @@
.subject {
color: #fff;
margin-top: -120px;
transition: margin-top .3s ease-in;
transition: opacity .6s ease-in-out;
z-index: $zindex3;
margin-top: 20px;
opacity: 0;
&.visible {
margin-top: 20px;
opacity: 1;
}
&#autoHide.with-always-on {
overflow: hidden;
animation: hideSubject forwards .6s ease-out;
& > .subject-info-container {
justify-content: flex-start;
}
&.visible {
animation: showSubject forwards .6s ease-out;
}
}
}
@@ -36,10 +50,7 @@
line-height: 28px;
padding: 0 16px;
height: 28px;
@media (max-width: 700px) {
max-width: 100px;
}
max-width: 324px;
@media (max-width: 300px) {
display: none;
@@ -74,8 +85,29 @@
position: absolute;
top: 0;
height: 48px;
max-width: calc(100% - 24px);
}
.shift-right .details-container {
margin-left: calc(#{$sidebarWidth} / 2);
}
@keyframes hideSubject {
0% {
max-width: 100%;
}
100% {
max-width: 0;
}
}
@keyframes showSubject {
0% {
max-width: 0%;
}
100% {
max-width: 100%;
}
}

View File

@@ -13,9 +13,6 @@ $hangupFontSize: 2em;
*/
// Video layout.
$thumbnailToolbarHeight: 22px;
$thumbnailIndicatorBorder: 2px;
$thumbnailIndicatorSize: $thumbnailToolbarHeight;
$thumbnailVideoMargin: 2px;
$thumbnailsBorder: 2px;
$thumbnailVideoBorder: 2px;
@@ -56,19 +53,12 @@ $overflowMenuItemBackground: #36383C;
/**
* Video layout
*/
$videoThumbnailHovered: rgba(22, 94, 204, .4);
$videoThumbnailSelected: #165ECC;
$participantNameColor: #fff;
$thumbnailPictogramColor: #fff;
$dominantSpeakerBg: #165ecc;
$raiseHandBg: #F8AE1A;
$audioLevelBg: #44A5FF;
$connectionIndicatorBg: #165ecc;
$audioLevelShadow: rgba(9, 36, 77, 0.9);
$videoStateIndicatorColor: $defaultColor;
$videoStateIndicatorBackground: $toolbarBackground;
$videoStateIndicatorSize: 40px;
$remoteVideoMenuIconMargin: initial;
/**
* Feedback Modal
@@ -102,7 +92,6 @@ $sidebarWidth: 315px;
* Misc.
*/
$borderRadius: 4px;
$popoverMenuPadding: 13px;
$happySoftwareBackground: transparent;
$desktopAppDragBarHeight: 25px;
$scrollHeight: 7px;
@@ -118,7 +107,6 @@ $toolbarBackgroundZ: 4;
$labelsZ: 5;
$subtitlesZ: 7;
$popoverZ: 8;
$zindex10: 10;
$reloadZ: 20;
$poweredByZ: 100;
$ringingZ: 300;

View File

@@ -43,165 +43,7 @@
.videocontainer {
position: relative;
text-align: center;
&__background {
@include topLeft();
background-color: black;
border-radius: $borderRadius;
width: 100%;
height: 100%;
}
/**
* The toolbar of the video thumbnail.
*/
&__toolbar,
&__toptoolbar {
position: absolute;
left: 0;
pointer-events: none;
z-index: $zindex10;
width: 100%;
box-sizing: border-box; // Includes the padding in the 100% width.
/**
* FIXME (lenny): Disabling pointer-events is a pretty big sin that
* sidesteps the problems. There are z-index wars occurring within
* videocontainer and AtlasKit Tooltips rely on their parent z-indexe
* being higher than whatever they need to appear over. So set a higher
* z-index for the tooltip containers but make any empty space not block
* mouse overs for various mouseover triggers.
*/
pointer-events: none;
* {
pointer-events: auto;
}
.indicator-container {
display: inline-block;
float: left;
pointer-events: all;
}
}
&__toolbar {
bottom: 0;
padding: 0 5px 0 5px;
}
&__toptoolbar {
$toolbarIconMargin: 5px;
top: 0;
padding-bottom: 0;
/**
* Override text-align center as icons need to be left justified.
*/
text-align: left;
/**
* Intentionally use margin on the icon itself as AtlasKit InlineDialog
* positioning depends on the trigger (indicator icon).
*/
.indicator {
margin-left: 5px;
margin-top: $toolbarIconMargin;
}
.indicator-container:nth-child(1) .indicator {
margin-left: $toolbarIconMargin;
}
.indicator-container {
display: inline-block;
vertical-align: top;
.popover-trigger {
display: inline-block;
}
}
.connection-indicator,
.indicator {
position: relative;
font-size: 8px;
text-align: center;
line-height: $thumbnailIndicatorSize;
padding: 0;
@include circle($thumbnailIndicatorSize);
box-sizing: border-box;
z-index: $zindex3;
background: $dominantSpeakerBg;
color: $thumbnailPictogramColor;
border: $thumbnailIndicatorBorder solid $thumbnailPictogramColor;
.indicatoricon {
@include absoluteAligning();
}
.connection {
position: relative;
display: inline-block;
margin: 0 auto;
left: 0;
@include transform(translate(0, -50%));
&_empty,
&_lost
{
color: #8B8B8B;/*#FFFFFF*/
overflow: hidden;
}
&_full
{
@include topLeft();
color: #FFFFFF;/*#15A1ED*/
overflow: hidden;
}
&_ninja
{
font-size: 1.5em;
}
}
.icon-gsm-bars {
cursor: pointer;
font-size: 1em;
}
}
.hide-connection-indicator {
display: none;
}
}
&__hoverOverlay {
background: rgba(0,0,0,.6);
border-radius: $borderRadius;
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
visibility: hidden;
z-index: $zindex2;
}
&__participant-name {
color: #fff;
background-color: rgba(0,0,0,.4);
padding: 3px 7px;
border-radius: 3px;
max-width: calc(100% - 32px);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
height: 16px;
display: inline-block;
text-align: right;
}
overflow: 'hidden';
@media (min-width: 581px) {
&.shift-right {
@@ -288,16 +130,6 @@
z-index: $zindex0;
}
/**
* Positions video thumbnail display name and editor.
*/
#alwaysOnTop .displayname,
.videocontainer .displayname,
.videocontainer .editdisplayname {
font-weight: 100;
color: $participantNameColor;
}
#alwaysOnTop .displayname {
font-size: 15px;
position: inherit;
@@ -307,146 +139,6 @@
margin-top: 10px;
}
/**
* Positions video thumbnail display name editor.
*/
.videocontainer .editdisplayname {
outline: none;
border: none;
background: none;
box-shadow: none;
padding: 0;
}
#localVideoContainer .displayname:hover {
cursor: text;
}
.videocontainer .displayname {
pointer-events: none;
padding: 0 3px 0 3px;
}
.videocontainer .editdisplayname {
height: auto;
}
#localDisplayName {
pointer-events: auto !important;
}
.videocontainer>a.displayname {
display: inline-block;
position: absolute;
color: #FFFFFF;
bottom: 0;
right: 0;
padding: 3px 5px;
font-size: 9pt;
cursor: pointer;
z-index: $zindex2;
}
/**
* Video thumbnail toolbar icon.
*/
.videocontainer .toolbar-icon {
font-size: 8pt;
text-align: center;
text-shadow: 0px 1px 0px rgba(255,255,255,.3), 0px -1px 0px rgba(0,0,0,.7);
color: #FFFFFF;
width: 12px;
line-height: $thumbnailToolbarHeight;
height: $thumbnailToolbarHeight;
padding: 0;
border: 0;
margin: 0px 5px 0px 0px;
}
/**
* Toolbar icon internal i elements (font icons).
*/
.toolbar-icon>div {
height: $thumbnailToolbarHeight;
display: flex;
flex-direction: column;
justify-content: center;
}
/**
* Toolbar icons positioned on the right.
*/
.moderator-icon {
display: inline-block;
&.right {
float: right;
margin: 0px 0px 0px 5px;
}
.toolbar-icon {
margin: 0;
}
}
.raisehandindicator {
background: $raiseHandBg !important;
}
.connection-indicator {
background: $connectionIndicatorBg;
&.status-high {
background: green;
}
&.status-med {
background: #FFD740;
}
&.status-lost {
background: gray;
}
&.status-low {
background: #BF2117;
}
&.status-other {
background: $connectionIndicatorBg;
}
&.status-disabled {
background: transparent;
border: none
}
}
.local-video-menu-trigger,
.remote-video-menu-trigger,
.localvideomenu,
.remotevideomenu
{
display: inline-block;
position: absolute;
top: 0px;
right: 0;
z-index: $zindex2;
width: 18px;
height: 18px;
color: #FFF;
font-size: 10pt;
margin-right: $remoteVideoMenuIconMargin;
>i{
cursor: hand;
}
}
.local-video-menu-trigger,
.remote-video-menu-trigger {
margin-top: 7px;
}
/**
* Audio indicator on video thumbnails.
*/
@@ -623,74 +315,11 @@
display: none;
}
.display-avatar-with-name {
.avatar-container {
visibility: visible;
}
.displayNameContainer {
visibility: visible;
}
.videocontainer__hoverOverlay {
visibility: visible;
}
video {
visibility: hidden;
}
}
.display-name-on-black {
.avatar-container {
visibility: hidden;
}
.displayNameContainer {
visibility: visible;
}
.videocontainer__hoverOverlay {
visibility: hidden;
}
video {
opacity: 0.2;
visibility: visible;
}
}
.display-video {
.avatar-container {
visibility: hidden;
}
.displayNameContainer {
visibility: hidden;
}
.videocontainer__hoverOverlay {
visibility: hidden;
}
video {
visibility: visible;
}
}
.display-name-on-video {
.avatar-container {
visibility: hidden;
}
.displayNameContainer {
visibility: visible;
}
.videocontainer__hoverOverlay {
visibility: visible;
}
video {
visibility: visible;
}
@@ -701,14 +330,6 @@
visibility: visible;
}
.displayNameContainer {
visibility: hidden;
}
.videocontainer__hoverOverlay {
visibility: hidden;
}
video {
visibility: hidden;
}

View File

@@ -6,37 +6,10 @@
border-radius: $borderRadius;
margin: 0 $thumbnailVideoMargin;
&.videoContainerFocused, &:hover {
&:hover {
cursor: hand;
}
/**
* Focused video thumbnail.
*/
&.videoContainerFocused {
border: $thumbnailVideoBorder solid $videoThumbnailSelected;
box-shadow: inset 0 0 3px $videoThumbnailSelected,
0 0 3px $videoThumbnailSelected;
}
.remotevideomenu > .icon-menu, .localvideomenu > .icon-menu {
display: none;
}
/**
* Hovered video thumbnail.
*/
&:hover:not(.videoContainerFocused):not(.active-speaker) {
cursor: hand;
border: $thumbnailVideoBorder solid $videoThumbnailHovered;
box-shadow: inset 0 0 3px $videoThumbnailHovered,
0 0 3px $videoThumbnailHovered;
.remotevideomenu > .icon-menu, .localvideomenu > .icon-menu {
display: inline-block;
}
}
& > video {
cursor: hand;
border-radius: $borderRadius;

View File

@@ -2,13 +2,6 @@
* CSS styles that are specific to the filmstrip that shows the thumbnail tiles.
*/
.tile-view {
/**
* Add a border around the active speaker to make the thumbnail easier to
* see.
*/
.active-speaker {
box-shadow: 0px 0px 1px 1.5px black, 0px 0px 1.3px 4px $videoThumbnailSelected;
}
.remote-videos {
align-items: center;
@@ -106,19 +99,6 @@
display: block;
margin: 2px;
}
video {
object-fit: contain;
}
/**
* Max-width corresponding to the ASPECT_RATIO_BREAKPOINT from features/filmstrip/constants.
*/
@media only screen and (max-width: 500px) {
video {
object-fit: cover;
}
}
}
}
}
@@ -134,7 +114,3 @@
}
}
}
.indicator-icon-container {
display: inline-block;
}

View File

@@ -35,16 +35,4 @@
#remotePresenceMessage {
display: none !important;
}
/**
* Thumbnail popover menus can overlap other thumbnails. Setting an auto
* z-index will allow AtlasKit InlineDialog's large z-index to be
* respected and thereby display over elements in other thumbnails,
* specifically the various status icons.
*/
.remotevideomenu,
.localvideomenu,
.videocontainer__toptoolbar {
z-index: auto;
}
}

View File

@@ -19,72 +19,6 @@
* Overrides for small videos in vertical filmstrip mode.
*/
.vertical-filmstrip .filmstrip__videos .videocontainer {
/**
* Move status icons to the bottom right of the thumbnail.
*/
.videocontainer__toolbar {
/**
* FIXME: disable pointer to allow any elements moved below to still
* be clickable. The real fix would to make sure those moved elements
* are actually part of the toolbar instead of positioning being faked.
*/
pointer-events: none;
text-align: right;
> div {
pointer-events: none;
}
.right {
float: none;
margin: auto;
}
.toolbar-icon {
pointer-events: all;
}
}
/**
* Apply hardware acceleration to prevent flickering on scroll. The
* selectors are specific to icon wrappers to prevent fixed position dialogs
* and tooltips from getting a new location context due to translate3d.
*/
.connection-indicator,
.local-video-menu-trigger,
.remote-video-menu-trigger,
.indicator-icon-container {
transform: translate3d(0, 0, 0);
}
.indicator-icon-container {
display: inline-block;
}
.indicator-container {
float: none;
}
/**
* Move the remote video menu trigger to the bottom left of the video
* thumbnail.
*/
.localvideomenu,
.remotevideomenu,
.local-video-menu-trigger,
.remote-video-menu-trigger {
bottom: 0;
left: 0;
top: auto;
right: auto;
}
.local-video-menu-trigger,
.remote-video-menu-trigger {
margin-bottom: 3px;
margin-left: $remoteVideoMenuIconMargin;
}
.self-view-mobile-portrait video {
object-fit: contain;
}

View File

@@ -48,7 +48,7 @@
}
.profile-edit-field {
flex: 1;
flex: .5;
}
.settings-sub-pane {
flex: 1;

View File

@@ -75,11 +75,7 @@ $errorColor: #c61600;
$feedbackCancelFontColor: #333;
// Popover colors
$popoverBg: initial;
$popoverFontColor: #ffffff !important;
$popupMenuColor: #ffffff !important;
$popupMenuHoverColor: #ffffff !important;
$popupMenuHoverBackground: rgba(255, 255, 255, 0.1);
$popupSliderColor: #0376da;
// Toolbar

View File

@@ -124,4 +124,5 @@ Component "lobby.jitmeet.example.com" "muc"
muc_room_default_public_jids = true
modules_enabled = {
"muc_rate_limit";
"polls";
}

View File

@@ -32,4 +32,12 @@ denied-peer-ip=198.18.0.0-198.19.255.255
denied-peer-ip=198.51.100.0-198.51.100.255
denied-peer-ip=203.0.113.0-203.0.113.255
denied-peer-ip=240.0.0.0-255.255.255.255
denied-peer-ip=::1
denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff
denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255
denied-peer-ip=100::-100::ffff:ffff:ffff:ffff
denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff
syslog

0
fonts.html Normal file
View File

View File

@@ -9,6 +9,7 @@
<link rel="apple-touch-icon" href="images/apple-touch-icon.png">
<link rel="stylesheet" href="css/all.css">
<!--#include virtual="fonts.html"-->
<link rel="manifest" id="manifest-placeholder">
<script>

View File

@@ -26,7 +26,7 @@ var interfaceConfig = {
CLOSE_PAGE_GUEST_HINT: false, // A html text to be shown to guests on the close page, false disables it
DEFAULT_BACKGROUND: '#474747',
DEFAULT_BACKGROUND: '#040404',
DEFAULT_LOGO_URL: 'images/watermark.svg',
DEFAULT_WELCOME_PAGE_LOGO_URL: 'images/watermark.svg',

View File

@@ -61,23 +61,24 @@ target 'JitsiMeetSDK' do
pod 'react-native-keep-awake', :path => '../node_modules/react-native-keep-awake'
pod 'react-native-netinfo', :path => '../node_modules/@react-native-community/netinfo'
pod 'react-native-performance', :path => '../node_modules/react-native-performance/ios'
pod 'react-native-safe-area-context', :path => '../node_modules/react-native-safe-area-context'
pod 'react-native-slider', :path => '../node_modules/@react-native-community/slider'
pod 'react-native-splash-screen', :path => '../node_modules/react-native-splash-screen'
pod 'react-native-video', :path => '../node_modules/react-native-video/react-native-video.podspec'
pod 'react-native-webview', :path => '../node_modules/react-native-webview'
pod 'react-native-webrtc', :path => '../node_modules/react-native-webrtc'
pod 'RNCAsyncStorage', :path => '../node_modules/@react-native-async-storage/async-storage'
pod 'RNCClipboard', :path => '../node_modules/@react-native-community/clipboard'
pod 'RNCMaskedView', :path => '../node_modules/@react-native-masked-view/masked-view'
pod 'RNDefaultPreference', :path => '../node_modules/react-native-default-preference'
pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info'
pod 'RNGestureHandler', :path => '../node_modules/react-native-gesture-handler'
pod 'RNGoogleSignin', :path => '../node_modules/@react-native-community/google-signin'
pod 'RNReanimated', :path => '../node_modules/react-native-reanimated'
pod 'RNScreens', :path => '../node_modules/react-native-screens'
pod 'RNSound', :path => '../node_modules/react-native-sound'
pod 'RNSVG', :path => '../node_modules/react-native-svg'
pod 'RNWatch', :path => '../node_modules/react-native-watch-connectivity'
pod 'RNDefaultPreference', :path => '../node_modules/react-native-default-preference'
pod 'RNGestureHandler', :path => '../node_modules/react-native-gesture-handler'
pod 'RNReanimated', :path => '../node_modules/react-native-reanimated'
pod 'RNScreens', :path => '../node_modules/react-native-screens'
pod 'react-native-safe-area-context', :path => '../node_modules/react-native-safe-area-context'
pod 'RNCMaskedView', :path => '../node_modules/@react-native-masked-view/masked-view'
# Native pod dependencies
#

View File

@@ -363,6 +363,8 @@ PODS:
- ReactCommon/turbomodule/core (= 0.61.5-jitsi.2)
- RNCAsyncStorage (1.15.5):
- React-Core
- RNCClipboard (1.5.1):
- React-Core
- RNCMaskedView (0.2.6):
- React-Core
- RNDefaultPreference (1.4.2):
@@ -435,6 +437,7 @@ DEPENDENCIES:
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
- ReactCommon/turbomodule (from `../node_modules/react-native/ReactCommon`)
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "RNCClipboard (from `../node_modules/@react-native-community/clipboard`)"
- "RNCMaskedView (from `../node_modules/@react-native-masked-view/masked-view`)"
- RNDefaultPreference (from `../node_modules/react-native-default-preference`)
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
@@ -547,6 +550,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon"
RNCAsyncStorage:
:path: "../node_modules/@react-native-async-storage/async-storage"
RNCClipboard:
:path: "../node_modules/@react-native-community/clipboard"
RNCMaskedView:
:path: "../node_modules/@react-native-masked-view/masked-view"
RNDefaultPreference:
@@ -629,6 +634,7 @@ SPEC CHECKSUMS:
React-RCTVibration: c1041024893fdfdb8371e7c720c437751b711676
ReactCommon: 18014e1d98dbeb9141e935cfe35fc93bd511ffb6
RNCAsyncStorage: 56a3355a10b5d660c48c6e37325ac85ebfd09885
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
RNCMaskedView: c298b644a10c0c142055b3ae24d83879ecb13ccd
RNDefaultPreference: 1f8133ec0bc0f9453cdada578564ba1ef551fb44
RNDeviceInfo: 87d2d175c760f6bcf58acd036f887e8b2392802c
@@ -641,6 +647,6 @@ SPEC CHECKSUMS:
RNWatch: a5320c959c75e72845c07985f3e935e58998f1d3
Yoga: 96b469c5e81ff51b917b92e8c3390642d4ded30c
PODFILE CHECKSUM: 836d4804218c0608e1326471ec83fe31cfa9c86d
PODFILE CHECKSUM: 0cfc1f35e2872ceb0a86252e14e226bd489a2602
COCOAPODS: 1.11.2

View File

@@ -1,33 +1,55 @@
{
"en": "angielski",
"af": "afrykanerski",
"af": "Afrikaans",
"ar": "arabski",
"bg": "bułgarski",
"ca": "kataloński",
"cs": "czeski",
"da": "duński",
"de": "niemiecki",
"el": "grecki",
"enGB": "angielski (Zjednoczone Królestwo)",
"enGB": "Angielski (Zjednoczone Królestwo)",
"eo": "esperanto",
"es": "hiszpański",
"esUS": "hiszpański (Ameryka Łacińska)",
"et": "estoński",
"eu": "baskijski",
"fi": "fiński",
"fr": "francuski",
"frCA": "francuski (kanadyjski)",
"he": "hebrajski",
"hi": "hindi",
"mr":"Marathi",
"hr": "chorwacki",
"hu": "węgierski",
"hy": "ormiański",
"id": "indonezyjski",
"it": "włoski",
"ja": "japoński",
"kab": "Kabyle",
"ko": "koreański",
"lt": "litewski",
"ml": "malajalam",
"lv": "łotewski",
"nl": "holenderski",
"oc": "oksytański",
"oc": "prowansalski",
"fa": "perski",
"pl": "polski",
"ptBR": "portugalski (brazylijski)",
"pt": "portugalski",
"ptBR": "portugalski (Brazylia)",
"ru": "rosyjski",
"ro": "rumuński",
"sc": "sardyński",
"sk": "słowacki",
"sl": "słoweński",
"sr": "serbski",
"sq": "albański",
"sv": "szwedzki",
"te": "telugu",
"th": "tajski",
"tr": "turecki",
"uk": "ukraiński",
"vi": "wietnamski",
"zhCN": "chiński (Chiny)",
"zhTW": "chiński (Tajwan)"
}
}

View File

@@ -57,7 +57,7 @@
},
"notifications": {
"joinedTitle": "غرف جانبية",
"joined": " الغرفة الجانبيةالانضمام إلى\"{{name}}\"",
"joined": " الغرفة الجانبيةالانضمام إلى {{index}}",
"joinedMainRoom": "الانضمام للغرفة الرئيسية"
}
},
@@ -180,7 +180,8 @@
"joinInApp": "انضم للاجتماع عبر تطبيق الجوال",
"launchWebButton": "افتح تطبيق الويب",
"title": "قيد عقد اجتماعك في {{app}}...",
"tryAgainButton": "جرب مرة أخرى في تطبيق الحاسوب"
"tryAgainButton": "جرب مرة أخرى في تطبيق الحاسوب",
"unsupportedBrowser": "يبدو أنك تستخدم متصفحًا لا ندعمه."
},
"defaultLink": "{{url}} مثلًا",
"defaultNickname": "محمد علي مثلًا",
@@ -418,6 +419,7 @@
"desktopShareError": "تعذر إنشاء مشاركة سطح المكتب",
"desktopShare": "مشاركة سطح المكتب",
"webAssemblyWarning": "WebAssembly غير مدعوم",
"webAssemblyWarningDescription": "تم تعطيل WebAssembly أو عدم دعمه بواسطة هذا المستعرض",
"backgroundEffectError": "فشل تطبيق تأثير الخلفية."
},
"feedback": {
@@ -579,10 +581,12 @@
"allowedUnmute": "يمكنك إعادة صوت الميكروفون و بدء تشغيل الكاميرا أو مشاركة شاشتك.",
"audioUnmuteBlockedTitle": "تم حظر إعادة صوت الميكروفون!",
"audioUnmuteBlockedDescription": "تم حظر عملية إلغاء كتم صوت الميكروفون مؤقتًا بسبب قيود النظام.",
"chatMessages": "رسائل الدردشة",
"connectedOneMember": "انضم {{name}} للاجتماع",
"connectedThreePlusMembers": "انضم {{name}} وعدد {{count}} غيره إلى الاجتماع",
"connectedTwoMembers": "انضم {{first}} و {{second}} إلى الاجتماع",
"disconnected": "انقطع الاتصال",
"displayNotifications": "عرض الإخطارات لـ",
"focus": "التركيز على المؤتمر",
"focusFail": "إنَّ {{component}} غير متاح. ستعاد المحاولة مرة أخرى خلال {{ms}} ثانية.",
"hostAskedUnmute": "The moderator would like you to speak",
@@ -607,6 +611,7 @@
"raisedHands": "{{participantName}} و {{raisedHands}}المزيد من الناس",
"screenShareNoAudio": "لم يتم تحديد مربع مشاركة الصوت في شاشة تحديد النافذة.",
"screenShareNoAudioTitle": "تعذرت مشاركة صوت النظام!",
"selfViewTitle": "يمكنك دائمًا إلغاء إخفاء العرض الذاتي من الإعدادات",
"somebody": "شخص ما",
"startSilentTitle": "انضممت دون مخرج للصوت!",
"startSilentDescription": "أنضم مجدَّدًا للاجتماع لتفعيل الصوت",
@@ -821,8 +826,8 @@
"security": {
"about": "يمكنك إضافة $t(lockRoomPassword) إلى الاجتماع. سيتوجب على المشاركين إدخال $t(lockRoomPassword) قبل السماح لهم بالانضمام إلى الاجتماع.",
"aboutReadOnly": "المشاركون بصفة رئيس الجلسة يمكنهم إضافة $t(lockRoomPassword) إلى الاجتماع. سيتوجب على المشاركين إدخال $t(lockRoomPassword) قبل السماح لهم بالانضمام إلى الاجتماع.",
"insecureRoomNameWarning": "اسم الغرفة غير آمن، فقد ينضم عبره مشاركون غرباء إلى الاجتماع. ننصحك بتأمين الاجتماع عبر وسائل الحماية التي يوفرها زر الحماية.",
"securityOptions": "خيارات الحماية"
"header": "خيارات الأمان",
"insecureRoomNameWarning": "اسم الغرفة غير آمن، فقد ينضم عبره مشاركون غرباء إلى الاجتماع. ننصحك بتأمين الاجتماع عبر وسائل الحماية التي يوفرها زر الحماية."
},
"settings": {
"calendar": {
@@ -854,6 +859,7 @@
"selectAudioOutput": "خرج الصوت",
"selectCamera": "الكاميرا",
"selectMic": "المجهار (المايكروفون)",
"selfView": "عرض ذاتي",
"sounds": "اصوات",
"speakers": "المذياع (مكبر الصوت)",
"startAudioMuted": "بدء الجميع مكتومي الصوت",
@@ -890,20 +896,20 @@
},
"speaker": "المتحدث",
"speakerStats": {
"search": حث",
"angry": "غاضب",
"disgusted": "مشمئز",
"fearful": "خائف",
"happy": "سعيد",
"hours": "{{count}}س",
"minutes": "{{count}}د",
"name": "الاسم",
"seconds": "{{count}}ثا",
"speakerStats": "حالة المتحدث",
"speakerTime": "وقت المتحدث",
"happy": "سعيد",
"neutral": "حيادي",
"sad": "حزين",
"surprised": "مندهش",
"angry": "غاضب",
"fearful": "خائف",
"disgusted": "مشمئز"
"search": "بحث",
"seconds": "{{count}}ثا",
"speakerTime": "وقت المتحدث",
"speakerStats": "حالة المتحدث",
"surprised": "مندهش"
},
"startupoverlay": {
"policyText": " ",
@@ -946,8 +952,8 @@
"mute": "اظهِر/اخفِ كتم الصوت",
"muteEveryone": "كتم الجميع",
"muteEveryoneElse": "كتم صوت الآخرين",
"muteEveryonesVideo": "تعطيل كاميرا الجميع",
"muteEveryoneElsesVideo": "تعطيل كاميرا الآخرين",
"muteEveryonesVideoStream": "وقّف فيديو الجميع",
"muteEveryoneElsesVideoStream": "وقّف فيديو أي شخص آخر",
"participants": "مشاركون",
"pip": "استعمل/اخرج من وضع صورة-في-صورة",
"privateMessage": "أرسل رسالة خاصة",
@@ -1123,6 +1129,7 @@
"domuteVideoOfOthers": "تعطيل الكاميرا للآخرين",
"flip": "قلب",
"grantModerator": "امنح صلاحيات رئيس الجلسة",
"hideSelfView": "إخفاء المنظر الذاتي",
"kick": "طرد خارجًا",
"moderator": "رئيس الجلسة",
"mute": "المشارك مكتوم الصوت",

View File

@@ -180,7 +180,8 @@
"joinInApp": "Mit der App am Meeting teilnehmen",
"launchWebButton": "Im Web öffnen",
"title": "Die Konferenz wird in {{app}} geöffnet …",
"tryAgainButton": "Erneut mit der nativen Applikation versuchen"
"tryAgainButton": "Erneut mit der nativen Applikation versuchen",
"unsupportedBrowser": "Sie verwenden einen Browser, der noch nicht unterstützt wird."
},
"defaultLink": "Bsp.: {{url}}",
"defaultNickname": "Z. B. Jane Pink",
@@ -418,7 +419,8 @@
"desktopShareError": "Desktop konnte nicht freigegeben werden",
"desktopShare": "Desktopfreigabe",
"webAssemblyWarning": "WebAssembly wird nicht unterstützt",
"backgroundEffectError": "Failed to apply background effect."
"webAssemblyWarningDescription": "WebAssembly ist deaktiviert oder wird in diesem Browser nicht unterstützt",
"backgroundEffectError": "Hintergrund konnte nicht aktiviert werden."
},
"feedback": {
"average": "Durchschnittlich",
@@ -579,10 +581,12 @@
"allowedUnmute": "Sie können die Stummschaltung aufheben, Ihre Kamera einschalten oder Ihren Bildschirm teilen.",
"audioUnmuteBlockedTitle": "Stummschaltung kann nicht aufgehoben werden!",
"audioUnmuteBlockedDescription": "Díe Stummschaltung kann aus Überlastungsschutzgründen temporär nicht aufgehoben werden.",
"chatMessages": "Chatnachrichten",
"connectedOneMember": "{{name}} nimmt am Meeting teil",
"connectedThreePlusMembers": "{{name}} und {{count}} andere Personen nehmen am Meeting teil",
"connectedTwoMembers": "{{first}} und {{second}} nehmen am Meeting teil",
"disconnected": "getrennt",
"displayNotifications": "Benachrichtigungen anzeigen für",
"focus": "Konferenzleitung",
"focusFail": "{{component}} ist im Moment nicht verfügbar wiederholen in {{ms}} Sekunden",
"hostAskedUnmute": "Die Moderation bittet Sie, das Mikrofon zu aktivieren",
@@ -607,6 +611,7 @@
"raisedHands": "{{participantName}} und {{raisedHands}} weitere möchten sprechen",
"screenShareNoAudio": "Die Option \"Audio freigeben\" wurde bei der Auswahl des Fensters nicht ausgewählt.",
"screenShareNoAudioTitle": "Share audio was not checked",
"selfViewTitle": "Sie können die eigene Ansicht immer in den Einstellungen reaktivieren",
"somebody": "Jemand",
"startSilentTitle": "Sie sind ohne Audioausgabe beigetreten!",
"startSilentDescription": "Treten Sie dem Meeting noch einmal bei, um Ihr Audio zu aktivieren",
@@ -635,8 +640,8 @@
"reactionSounds": "Interaktionstöne deaktivieren",
"reactionSoundsForAll": "Interaktionstöne für alle deaktivieren",
"groupTitle": "Benachrichtigungen",
"videoUnmuteBlockedTitle": "Kamera kann nicht aktiviert werden!",
"videoUnmuteBlockedDescription": "Die Kamera kann aus Überlastungsschutzgründen temporär nicht eingeschaltet werden."
"videoUnmuteBlockedTitle": "Kamera und Bildschirmfreigabe kann nicht aktiviert werden!",
"videoUnmuteBlockedDescription": "Die Kamera und Bildschirmfreigabe kann aus Überlastungsschutzgründen temporär nicht eingeschaltet werden."
},
"participantsPane": {
"close": "Schließen",
@@ -661,7 +666,8 @@
"stopEveryonesVideo": "Alle Kameras ausschalten",
"stopVideo": "Kamera ausschalten",
"unblockEveryoneMicCamera": "Kamera und Mikrofon von allen entsperren",
"videoModeration": "Kamera einschalten"
"videoModeration": "Kamera einschalten",
"moreModerationControls": "Weitere Moderationsoptionen"
},
"search": "Suche Anwesende"
},
@@ -778,6 +784,7 @@
"title": "Profil"
},
"raisedHand": "Ich möchte sprechen",
"raisedHandsLabel": "Anzahl gehobener Hände",
"recording": {
"limitNotificationDescriptionWeb": "Wegen hoher Nachfrage ist Ihre Aufnahme auf {{limit}} Min. begrenzt. Für unlimitierte Aufnahmen nutzen Sie bitte <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
"limitNotificationDescriptionNative": "Wegen hoher Nachfrage ist Ihre Aufnahme auf {{limit}} Min. begrenzt. Für unlimitierte Aufnahmen nutzen Sie bitte <3>{{app}}</3>.",
@@ -820,8 +827,8 @@
"security": {
"about": "Sie können Ihre Konferenz mit einem Passwort sichern. Teilnehmer müssen dieses eingeben, bevor sie an der Sitzung teilnehmen dürfen.",
"aboutReadOnly": "Mit Moderationsrechten kann die Konferenz mit einem Passwort gesichert werden. Personen müssen dieses eingeben, bevor sie an der Sitzung teilnehmen dürfen.",
"insecureRoomNameWarning": "Der Raumname ist unsicher. Unerwünschte Teilnehmer könnten Ihrer Konferenz beitreten",
"securityOptions": "Sicherheitsoptionen"
"header": "Sicherheitsoptionen",
"insecureRoomNameWarning": "Der Raumname ist unsicher. Unerwünschte Teilnehmer könnten Ihrer Konferenz beitreten"
},
"settings": {
"calendar": {
@@ -853,6 +860,7 @@
"selectAudioOutput": "Audioausgabe",
"selectCamera": "Kamera",
"selectMic": "Mikrofon",
"selfView": "Eigene Ansicht",
"sounds": "Hinweistöne",
"speakers": "Lautsprecher",
"startAudioMuted": "Alle Personen treten stummgeschaltet bei",
@@ -889,20 +897,20 @@
},
"speaker": "Sprecher/-in",
"speakerStats": {
"search": "Suche",
"angry": "Sauer",
"disgusted": "Angeekelt",
"fearful": "Ängstlich",
"happy": "Fröhlich",
"hours": "{{count}} Std. ",
"minutes": "{{count}} Min. ",
"name": "Name",
"seconds": "{{count}} Sek.",
"speakerStats": "Sprechstatistik",
"speakerTime": "Sprechzeit",
"happy": "Fröhlich",
"neutral": "Neutral",
"sad": "Traurig",
"surprised": "Überrascht",
"angry": "Sauer",
"fearful": "Ängstlich",
"disgusted": "Angeekelt"
"search": "Suche",
"seconds": "{{count}} Sek.",
"speakerTime": "Sprechzeit",
"speakerStats": "Sprechstatistik",
"surprised": "Überrascht"
},
"startupoverlay": {
"policyText": " ",
@@ -1122,6 +1130,7 @@
"domuteVideoOfOthers": "Alle anderen Kameras auschalten",
"flip": "Spiegeln",
"grantModerator": "Moderationsrechte vergeben",
"hideSelfView": "Eigene Ansicht ausblenden",
"kick": "Hinauswerfen",
"moderator": "Moderation",
"mute": "Person ist stumm geschaltet",

View File

@@ -1005,7 +1005,7 @@
"surprised": "Compartir audio",
"talkWhileMutedPopup": "¿Intentas hablar? Estás silenciado.",
"tileViewToggle": "Activar o desactivar vista en cuadrícula",
"toggleCamera": "Activar o desactivar cámara",
"toggleCamera": "Alternar cámara",
"videomute": "Iniciar o detener cámara",
"selectBackground": "Seleccionar fondo"
},
@@ -1169,4 +1169,4 @@
"rejectAll": "Rechazar todo",
"toggleLabel": "Activar sala de espera"
}
}
}

View File

@@ -40,25 +40,25 @@
"audioOnly": "Bande passante faible"
},
"blankPage": {
"meetingEnded": "Réunion terminée."
"meetingEnded": "Réunion terminée."
},
"breakoutRooms": {
"defaultName": "Salle annexe #{{index}}",
"mainRoom": "Salle principale",
"actions": {
"add": "Ajouter salle annexe",
"autoAssign": "Assigner automatiquement aux salles annexes",
"close": "Fermer",
"join": "Rejoindre",
"leaveBreakoutRoom": "Quitter la salle annexe",
"more": "Plus",
"remove": "Supprimer",
"sendToBreakoutRoom": "Envoyer le participant dans:"
"add": "Ajouter salle annexe",
"autoAssign": "Assigner automatiquement aux salles annexes",
"close": "Fermer",
"join": "Rejoindre",
"leaveBreakoutRoom": "Quitter la salle annexe",
"more": "Plus",
"remove": "Supprimer",
"sendToBreakoutRoom": "Envoyer le participant dans:"
},
"notifications": {
"joinedTitle": "Salles annexes",
"joined": "Entrée en salle annexe \"{{name}}\"",
"joinedMainRoom": "Retour à la salle principalem"
"joinedTitle": "Salles annexes",
"joined": "Entrée en salle annexe \"{{name}}\"",
"joinedMainRoom": "Retour à la salle principalem"
}
},
"calendarSync": {
@@ -180,7 +180,8 @@
"joinInApp": "Rejoindre la réunion en utilisant l'application",
"launchWebButton": "Lancer dans le navigateur",
"title": "Lancement de votre réunion dans {{app}} en cours ...",
"tryAgainButton": "Réessayez sur le bureau"
"tryAgainButton": "Réessayez sur le bureau",
"unsupportedBrowser": "Il semble que vous utilisez un navigateur non supporté."
},
"defaultLink": "ex. {{url}}",
"defaultNickname": "ex. Jean Dupont",
@@ -244,8 +245,8 @@
"gracefulShutdown": "Notre service est actuellement en maintenance. Veuillez réessayer plus tard.",
"grantModeratorDialog": "Êtes-vous sûr de vouloir rendre ce participant modérateur ?",
"grantModeratorTitle": "Nommer modérateur",
"IamHost": "Je suis l'hôte",
"hideShareAudioHelper": "Ne pas montrer ce dialogue à nouveau",
"IamHost": "Je suis l'hôte",
"incorrectRoomLockPassword": "Mot de passe incorrect",
"incorrectPassword": "Nom d'utilisateur ou mot de passe incorrect",
"internalError": "Oups ! Quelque chose s'est mal passée. L'erreur suivante s'est produite : {{error}}",
@@ -261,8 +262,8 @@
"lockMessage": "Impossible de verrouiller la conférence.",
"lockRoom": "Ajouter un $t(lockRoomPassword) à la réunion ",
"lockTitle": "Échec du verrouillage",
"login": "Connexion",
"logoutQuestion": "Voulez-vous vraiment vous déconnecter et arrêter la conférence ?",
"login": "Connexion",
"logoutTitle": "Déconnexion",
"maxUsersLimitReached": "Le nombre maximal de participants est atteint. Le conférence est complète. Merci de contacter l'organisateur de la réunion ou réessayer plus tard !",
"maxUsersLimitReachedTitle": "Le nombre maximal de participants est atteint",
@@ -340,7 +341,7 @@
"sessionRestarted": "L'appel est relancé par la passerelle",
"Share": "Partager",
"shareAudio": "Continuer",
"shareAudioTitle" : "Comment partager le son",
"shareAudioTitle": "Comment partager le son",
"shareAudioWarningTitle": "Vous devez cesser de partager l'écran avant de partager l'audio",
"shareAudioWarningH1": "Si vous voulez partager uniquement de l'audio:",
"shareAudioWarningD1": "vous devez cesser le partage d'écran avant de partager votre son.",
@@ -408,16 +409,17 @@
"none": "Rien",
"uploadedImage": "Image téléversée {{index}}",
"deleteImage": "Supprimer l'image",
"image1" : "Plage",
"image2" : "Mur blanc neutre",
"image3" : "Pièce vide blanche",
"image4" : "Lampadaire noir",
"image5" : "Montagne",
"image6" : "Forêt ",
"image7" : "Lever de soleil",
"image1": "Plage",
"image2": "Mur blanc neutre",
"image3": "Pièce vide blanche",
"image4": "Lampadaire noir",
"image5": "Montagne",
"image6": "Forêt ",
"image7": "Lever de soleil",
"desktopShareError": "Impossible de créer le partage de bureau",
"desktopShare":"Partage de bureau",
"desktopShare": "Partage de bureau",
"webAssemblyWarning": "WebAssembly non supporté",
"webAssemblyWarningDescription": "WebAssembly invalidé ou non supporté par ce navigateur",
"backgroundEffectError": "Erreur dans l'application de l'effet d'arrière-plan."
},
"feedback": {
@@ -445,7 +447,7 @@
"country": "Pays",
"dialANumber": "Pour rejoindre votre réunion, composez l'un de ces numéros, puis saisissez le code confidentiel.",
"dialInConferenceID": "PIN :",
"copyNumber":"Copier le numéro",
"copyNumber": "Copier le numéro",
"dialInNotSupported": "Désolé, l'accès par téléphone n'est pas pris en charge pour l'instant.",
"dialInNumber": "Composer :",
"dialInSummaryError": "Erreur lors de la récupération des informations de numérotation. Veuillez réessayer plus tard.",
@@ -579,10 +581,12 @@
"allowedUnmute": "Vous pouvez réactiver votre écran, votre caméra ou partager votre écran.",
"audioUnmuteBlockedTitle": "Rétablissement du son bloqué !",
"audioUnmuteBlockedDescription": "Le rétablissement du son a été bloqué temporairement en raison de limites système.",
"chatMessages": "Messages de chat",
"connectedOneMember": "{{name}} a rejoint la réunion",
"connectedThreePlusMembers": "{{name}} et {{count}} autres personnes ont rejoint la réunion",
"connectedTwoMembers": "{{first}} et {{second}} ont rejoint la réunion",
"disconnected": "déconnecté",
"displayNotifications": "Afficher les notifications pour",
"focus": "Focus de conférence",
"focusFail": "{{component}} n'est pas disponible - réessayez dans {{ms}} sec",
"hostAskedUnmute": "Le modérateur souhaite vous donner la parole",
@@ -604,9 +608,10 @@
"passwordRemovedRemotely": "Le $t(lockRoomPassword) a été supprimé par un autre participant",
"passwordSetRemotely": "Un $t(lockRoomPassword) a été défini par un autre participant",
"raisedHand": "{{name}} aimerait prendre la parole.",
"raisedHands": "{{participantName}} et {{raisedHands}} autres personnes",
"raisedHands": "{{participantName}} et {{raisedHands}} autres personnes",
"screenShareNoAudio": " La case Partager l'audio n'a pas été cochée dans l'écran de sélection de la fenêtre.",
"screenShareNoAudioTitle": "La case Partager l'audio n'a pas été cochée",
"selfViewTitle": "Vous pouvez toujours rétablir l'affichage de votre propre vidéo dans les paramètres",
"somebody": "Quelqu'un",
"startSilentTitle": "Vous avez rejoint sans sortie audio !",
"startSilentDescription": "Rejoignez la réunion de nouveau pour activer l'audio",
@@ -633,7 +638,7 @@
"moderationToggleDescription": "par {{participantDisplayName}}",
"raiseHandAction": "Lever la main",
"reactionSounds": "Bloquer les réactions sonores",
"reactionSoundsForAll": "Bloquer les réactions sonores pour tous",
"reactionSoundsForAll": "Bloquer les réactions sonores pour tous",
"groupTitle": "Notifications",
"videoUnmuteBlockedTitle": "Rétablissement de la caméra bloqué !",
"videoUnmuteBlockedDescription": "Le rétablissement de la vidéo a été bloqué temporairement en raison de limites système."
@@ -649,7 +654,7 @@
"actions": {
"allow": "Autoriser les participants à:",
"allowVideo": "permettre la vidéo",
"audioModeration": "ouvrir leur micro",
"audioModeration": "Rouvrir leur micro",
"blockEveryoneMicCamera": "Bloquer tous les micros et caméras",
"invite": "Inviter quelqu'un",
"askUnmute": "Demander de réactiver le micro",
@@ -662,7 +667,7 @@
"stopVideo": "Couper la vidéo",
"unblockEveryoneMicCamera": "Débloquer tous les micros et caméras",
"videoModeration": "Démarrer leur vidéo",
"moreModerationControls": "Options de modération supplémentaires"
"moreModerationControls": "Options de modération supplémentaires"
},
"search": "Rechercher des participants"
},
@@ -675,8 +680,8 @@
"answerPlaceholder": "Option {{index}}",
"create": "Créer un sondage",
"cancel": "Annuler",
"pollOption" : "Option {{index}}",
"pollQuestion" : "Question du sondage",
"pollOption": "Option {{index}}",
"pollQuestion": "Question du sondage",
"questionPlaceholder": "Poser une question",
"removeOption": "Supprimer l'option",
"send": "Envoyer"
@@ -750,8 +755,8 @@
"or": "ou",
"premeeting": "Pré-séance",
"showScreen": "Activer l'écran de pré-séance",
"keyboardShortcuts": "Activer les raccourcis clavier",
"startWithPhone": "Commencez avec l'audio du téléphone",
"keyboardShortcuts" : "Activer les raccourcis clavier",
"screenSharingError": "Erreur de partage d'écran:",
"videoOnlyError": "Erreur vidéo:",
"videoTrackError": "Impossible de créer une piste vidéo.",
@@ -779,6 +784,7 @@
"title": "Profil"
},
"raisedHand": "Aimerait prendre la parole",
"raisedHandsLabel": "Nombre de mains levées",
"recording": {
"limitNotificationDescriptionWeb": "En raison d'une forte demande, votre enregistrement sera limité à {{limit}} min. Pour des enregistrements illimités, essayez <a href={{url}} rel='noopener noreferrer' target='_blank'> {{app}} </a>.",
"limitNotificationDescriptionNative": "En raison d'une forte demande, votre enregistrement sera limité à {{limit}} min. Pour des enregistrements illimités, essayez <3> {{app}} </3>.",
@@ -821,8 +827,8 @@
"security": {
"about": "Vous pouvez ajouter un mot de passe à votre réunion. Les participants devront fournir le mot de passe avant de pouvoir rejoindre la réunion.",
"aboutReadOnly": "Les modérateurs peuvent ajouter un mot de passe à la réunion. Les participants devront fournir le mot de passe avant de pouvoir rejoindre la réunion.",
"insecureRoomNameWarning": "Le nom de la salle est peu sûr. Des participants non désirés peuvent rejoindre votre réunion. Pensez à sécuriser votre réunion en cliquant sur le bouton de sécurité.",
"securityOptions": "Options de sécurité"
"header": "Options de sécurité",
"insecureRoomNameWarning": "Le nom de la salle est peu sûr. Des participants non désirés peuvent rejoindre votre réunion. Pensez à sécuriser votre réunion en cliquant sur le bouton de sécurité."
},
"settings": {
"calendar": {
@@ -854,10 +860,11 @@
"selectAudioOutput": "Sortie audio",
"selectCamera": "Caméra",
"selectMic": "Microphone",
"selfView": "Affichage de votre propre vidéo",
"sounds": "Sons",
"speakers": "Haut-parleurs",
"startAudioMuted": "Tout le monde commence en muet",
"startReactionsMuted": "Tout le monde commence avec les réactions sonores bloquées",
"startReactionsMuted": "Tout le monde commence avec les réactions sonores bloquées",
"startVideoMuted": "Tout le monde commence sans vidéo",
"talkWhileMuted": "vous parlez en étant muet",
"title": "Paramètres"
@@ -890,20 +897,20 @@
},
"speaker": "Haut-parleur",
"speakerStats": {
"search": "Recherche",
"angry": "En colère",
"disgusted": "Dégoûté",
"fearful": "Effrayé",
"happy": "Content",
"hours": "{{count}}h",
"minutes": "{{count}}m",
"name": "Nom",
"seconds": "{{count}}s",
"speakerStats": "Statistiques de l'interlocuteur",
"speakerTime": "Temps de l'interlocuteur",
"happy": "Content",
"neutral": "Indifférent",
"sad": "Triste",
"surprised": "Surpris",
"angry": "En colère",
"fearful": "Effrayé",
"disgusted": "Dégoûté"
"search": "Recherche",
"seconds": "{{count}}s",
"speakerTime": "Temps de l'interlocuteur",
"speakerStats": "Statistiques de l'interlocuteur",
"surprised": "Surpris"
},
"startupoverlay": {
"policyText": " ",
@@ -946,8 +953,8 @@
"mute": "Activer / Désactiver l'audio",
"muteEveryone": "Couper le micro de tout le monde",
"muteEveryoneElse": "Couper le micro de tous les autres",
"muteEveryonesVideo": "Couper la caméra de tout le monde",
"muteEveryoneElsesVideo": "Couper la caméra de tout les autres",
"muteEveryonesVideoStream": "Couper la caméra de tout le monde",
"muteEveryoneElsesVideoStream": "Couper la caméra de tous les autres",
"participants": "Participants",
"pip": "Activer / Désactiver le mode Picture in Picture",
"privateMessage": "Envoyer un message privé",
@@ -1123,6 +1130,7 @@
"domuteVideoOfOthers": "Couper la caméra des autres",
"flip": "Balancer",
"grantModerator": "Donner des droits de modérateur",
"hideSelfView": "Cacher l'affichage de votre propre vidéo",
"kick": "Exclure",
"moderator": "Modérateur",
"mute": "Un participant a coupé son micro",
@@ -1171,13 +1179,13 @@
"startMeeting": "Démarrer la conférence",
"terms": "Termes",
"title": "Système de vidéoconférence sécurisé, riche en fonctionnalités et gratuit",
"logo":{
"calendar":"Logo Calendar",
"microsoftLogo":"Logo Microsoft",
"logoDeepLinking":"Logo Jitsi meet",
"desktopPreviewThumbnail":"Miniature d'aperçu du bureau",
"googleLogo":"Logo Google",
"policyLogo":"Logo de la politique"
"logo": {
"calendar": "Logo Calendar",
"microsoftLogo": "Logo Microsoft",
"logoDeepLinking": "Logo Jitsi meet",
"desktopPreviewThumbnail": "Miniature d'aperçu du bureau",
"googleLogo": "Logo Google",
"policyLogo": "Logo de la politique"
}
},
"lonelyMeetingExperience": {

View File

@@ -7,11 +7,11 @@
"copyStream": "Link naar livestream kopiëren",
"countryNotSupported": "Deze bestemming wordt nog niet ondersteund.",
"countryReminder": "Belt u buiten de Verenigde Staten? Vergeet dan niet met de landcode te beginnen.",
"defaultEmail": "Uw Standaard Email",
"defaultEmail": "Uw standaard e-mail",
"disabled": "U kunt geen personen uitnodigen.",
"failedToAdd": "Het toevoegen van deelnemers is mislukt",
"footerText": "Uitgaande oproepen zijn uitgeschakeld.",
"googleEmail": "Google Email",
"googleEmail": "Google e-mail",
"inviteMoreHeader": "U bent de enige in de vergadering",
"inviteMoreMailSubject": "Deelnemen aan {{appName}}-vergadering",
"inviteMorePrompt": "Nodig meer personen uit",
@@ -21,7 +21,7 @@
"loadingPeople": "Personen om uit te nodigen aan het zoeken",
"noResults": "Geen resultaten die overeenkomen met de zoekopdracht",
"noValidNumbers": "Voer een telefoonnummer in",
"outlookEmail": "Outlook Email",
"outlookEmail": "Outlook e-mail",
"searchNumbers": "Telefoonnummers toevoegen",
"searchPeople": "Personen zoeken",
"searchPeopleAndNumbers": "Personen zoeken of hun telefoonnummers toevoegen",
@@ -30,7 +30,7 @@
"shareStream": "Deel de link naar de livestream",
"telephone": "Telefoon: {{number}}",
"title": "Personen uitnodigen voor deze vergadering",
"yahooEmail": "Yahoo Email"
"yahooEmail": "Yahoo e-mail"
},
"audioDevices": {
"bluetooth": "Bluetooth",
@@ -73,9 +73,17 @@
"titleWithPolls": "Voer een bijnaam in om chat te gebruiken"
},
"privateNotice": "Privébericht aan {{recipient}}",
"title": "Chat",
"titleWithPolls": "Chat",
"you": "u"
"message": "Bericht",
"messageAccessibleTitle": "{{user}} zegt:",
"messageAccessibleTitleMe": "ik zeg:",
"smileysPanel": "Smiley paneel",
"tabs": {
"chat": "Gesprek",
"polls": "Peilingen"
},
"title": "Gesprek",
"titleWithPolls": "Gesprek",
"you": "U"
},
"chromeExtensionBanner": {
"installExtensionText": "Installeer de extensie voor Google Calendar en Office 365 integratie",
@@ -526,6 +534,35 @@
},
"passwordSetRemotely": "ingesteld door een andere deelnemer",
"passwordDigitsOnly": "Maximaal {{number}} cijfers",
"polls": {
"by": "Door {{ name }}",
"create": {
"addOption": "Voeg optie toe",
"answerPlaceholder": "Optie {{index}}",
"create": "Creeër een peiling",
"cancel": "Annuleer",
"pollOption" : "Peiling optie {{index}}",
"pollQuestion" : "Peiling vraag",
"questionPlaceholder": "Stel een vraag",
"removeOption": "Verwijder optie",
"send": "Verstuur"
},
"answer": {
"skip": "Sla over",
"submit": "Verzend"
},
"results": {
"vote": "Stem",
"changeVote": "Verander stem",
"empty": "Er zijn nog geen peilingen in deze vergadering. Start hier een peiling!",
"hideDetailedResults": "Verberg details",
"showDetailedResults": "Toon details"
},
"notification": {
"title": "Een nieuwe peiling is aangemaakt in deze vergadering",
"description": "Open het peilingen tabblad om te stemmen"
}
},
"poweredby": "mogelijk gemaakt door",
"prejoin": {
"audioAndVideoError": "Audio- en videofout:",
@@ -586,8 +623,8 @@
},
"profile": {
"setDisplayNameLabel": "Uw weergavenaam instellen",
"setEmailInput": "Voer emailadres in",
"setEmailLabel": "Uw Gravatar email instellen",
"setEmailInput": "Voer e-mailadres in",
"setEmailLabel": "Uw Gravatar e-mail instellen",
"title": "Profiel"
},
"raisedHand": "Zou graag willen spreken",
@@ -849,17 +886,21 @@
"pending": "{{displayName}} is uitgenodigd"
},
"videoStatus": {
"adjustFor": "Aanpassen voor:",
"audioOnly": "AUD",
"audioOnlyExpanded": "U bent in lage bandbreedte-modus. In deze modus ontvangt u alleen audio en schermdeling.",
"bestPerformance": "Beste prestatie",
"callQuality": "Videokwaliteit",
"hd": "HD",
"hdTooltip": "U bekijkt video in hoge resolutie",
"highDefinition": "Hoge resolutie",
"highestQuality": "Hoogste kwaliteit",
"labelTooiltipNoVideo": "Geen video",
"labelTooltipAudioOnly": "Lage bandbreedte-modus ingeschakeld",
"ld": "LD",
"ldTooltip": "U bekijkt video in lage resolutie",
"lowDefinition": "Lage resolutie",
"performanceSettings": "Prestatie instellingen",
"sd": "SD",
"sdTooltip": "U bekijkt video in standaard resolutie",
"standardDefinition": "Standaard resolutie"
@@ -931,7 +972,7 @@
"dialogTitle": "Lobby-modus",
"disableDialogContent": "Lobby-modus is momenteel ingeschakeld. Deze functie zorgt ervoor dat ongewenste deelnemers niet aan uw vergadering kunnen deelnemen. Wilt u het uitschakelen?",
"disableDialogSubmit": "Uitschakelen",
"emailField": "Voer uw emailadres in",
"emailField": "Voer uw e-mailadres in",
"enableDialogPasswordField": "Stel wachtwoord in (optioneel)",
"enableDialogSubmit": "Inschakelen",
"enableDialogText": "Met de lobby-modus kunt u uw vergadering beveiligen, door deelnemers alleen toe te laten na een formele goedkeuring van een moderator.",

View File

@@ -158,7 +158,8 @@
"joinInApp": "Rejónher la conferéncia en utilizant laplicacion",
"launchWebButton": "Lançar del navigador",
"title": "Aviada de vòstra conferéncia dins {{app}}…",
"tryAgainButton": "Tornar ensajar del burèu"
"tryAgainButton": "Tornar ensajar del burèu",
"unsupportedBrowser": "Sembla quutilizatz un navigador que prenèm pas en carga."
},
"defaultLink": "ex. {{url}}",
"defaultNickname": "ex. Joan Delpuèch",
@@ -421,7 +422,7 @@
"noPassword": "Pas cap",
"noRoom": "Cap de sala pas donada per la jónher.",
"numbers": "Sonar de numèros",
"password": "$t(lockRoomPasswordUppercase):",
"password": "$t(lockRoomPasswordUppercase): ",
"title": "Partejar",
"tooltip": "Partejar lo ligam e las informacions daquesta conferéncia",
"copyNumber": "Copiar lo numèro",
@@ -627,9 +628,17 @@
"moderationInEffectCSDescription": "Volgatz levar la man se volètz partejar vòstre ecran.",
"moderationInEffectVideoDescription": "Volgatz levar la man se volètz aviar vòstra camèra.",
"audioUnmuteBlockedTitle": "Restabliment del son del microfòn blocat!",
"videoUnmuteBlockedTitle": "Restabliment de la camèra blocat!",
"videoUnmuteBlockedTitle": "Restabliment de la camèra e del partiment de burèu blocat !",
"audioUnmuteBlockedDescription": "Las operacion de restabliment del son microfòn son estadas blocadas pel moment a causa de limitas sistèma.",
"videoUnmuteBlockedDescription": "Las operacion de restabliment de la camèra son estadas blocadas pel moment a causa de limitas sistèma."
"videoUnmuteBlockedDescription": "Las operacion de restabliment de la camèra e del partiment del burèu son estadas blocadas pel moment a causa de limitas sistèma.",
"chatMessages": "Messatges del chat",
"displayNotifications": "Afichar las notificacions per",
"leftOneMember": "{{name}} a quitat la conferéncia",
"leftThreePlusMembers": "{{name}} e un molon dautres an quitat la conferéncia",
"leftTwoMembers": "{{first}} e {{second}} an quitat la conferéncia",
"raisedHands": "{{participantName}} e {{raisedHands}} autres",
"selfViewTitle": "Podètz totjorn quitar damagar vòstra pròpria vista a partir dels paramètres",
"reactionSoundsForAll": "Desactivar los sons per totes"
},
"passwordDigitsOnly": "Fins a {{number}} chifras",
"passwordSetRemotely": "causit per qualqu'un mai",
@@ -758,7 +767,7 @@
"about": "Podètz ajustar un $t(lockRoomPassword) per rejónher una conferéncia. Los participants deuràn fornir lo $t(lockRoomPassword) abans dobténer lautorizacion de dintrar dins la conferéncia.",
"aboutReadOnly": "Los participants que son moderators pòdon ajustar un $t(lockRoomPassword) a la conferéncia. Los participants deuràn fornir lo $t(lockRoomPassword) abans daver lautorizacion de rejónher la conferéncia.",
"insecureRoomNameWarning": "Lo nom de la sala es pas segur. De monde indesirables poirián rejónher vòstra conferéncia.",
"securityOptions": "Opcions de seguretat"
"header": "Opcions de seguretat"
},
"settings": {
"calendar": {
@@ -795,7 +804,9 @@
"talkWhileMuted": "Parlar en mut",
"desktopShareHighFpsWarning": "Una frequéncia dimatge mai nauta pel partiment burèu pòt afectar la benda passanta. Devètz reaviar lo partiment decran per aplicar los paramètres novèls.",
"desktopShareWarning": "Devètz reaviar lo partiment decran per prendre en compte las modificacions.",
"incomingMessage": "Messatge dintrant"
"incomingMessage": "Messatge dintrant",
"selfView": "Vista de se",
"startReactionsMuted": "Començan totes amb las reaccions sonòras amudidas"
},
"settingsView": {
"advanced": "Avançat",
@@ -898,7 +909,6 @@
"clap": "Picar de las mans",
"laugh": "Rire",
"like": "Levar lo det gròs",
"muteEveryonesVideo": "Copar la vidèo del monde",
"muteEveryoneElsesVideo": "Copar la vidèo de los demai",
"participants": "Participants",
"remoteVideoMute": "Copar la camèra del participant",
@@ -910,7 +920,9 @@
"collapse": "Plegar",
"muteEveryoneElse": "Copar lo microfòn dels autres",
"reactionsMenu": "Dobrir / Tampar lo menú de reaccions",
"breakoutRoom": "Rejónher/quitar la sala de reünion"
"breakoutRoom": "Rejónher/quitar la sala de reünion",
"muteEveryoneElsesVideoStream": "Arrestar la vidèo de totes los autres",
"muteEveryonesVideoStream": "Arrestar la vidèo de tot lo monde"
},
"addPeople": "Ajustar de monde a vòstra sonada",
"audioOnlyOff": "Desactivar lo mòde connexion febla",
@@ -1064,7 +1076,8 @@
"videomute": "Lo participant a arrestat la camèra",
"domuteVideo": "Desactivar la camèra",
"domuteVideoOfOthers": "Desactivar la camèra dels demai",
"videoMuted": "Camèra desactivada"
"videoMuted": "Camèra desactivada",
"hideSelfView": "Amagar pròpria vista"
},
"welcomepage": {
"accessibilityLabel": {
@@ -1135,7 +1148,8 @@
"image6": "Forèst ",
"desktopShareError": "Creacion impossibla dun partiment de burèu",
"desktopShare": "Partiment de burèu",
"webAssemblyWarning": "WebAssembly pas pres en carga"
"webAssemblyWarning": "WebAssembly pas pres en carga",
"webAssemblyWarningDescription": "WebAssembly es desactivat o pas pres en carga per aqueste navigador"
},
"participantsPane": {
"headings": {
@@ -1160,7 +1174,8 @@
"videoModeration": "Aviar lor vidèo",
"allowVideo": "Autorizar la vidèo",
"moreModerationActions": "Mai dopcions de moderacion",
"moreParticipantOptions": "Mai dopcions de participant"
"moreParticipantOptions": "Mai dopcions de participant",
"moreModerationControls": "Opcions de moderacion suplementàrias"
},
"search": "Cercar participants"
},
@@ -1207,7 +1222,12 @@
"autoAssign": "Atribucion auto a las salas de reünion"
},
"defaultName": "Sala de reünion #{{index}}",
"mainRoom": "Sala principala"
"mainRoom": "Sala principala",
"notifications": {
"joinedMainRoom": "Retorn a la sala principala",
"joinedTitle": "Salas suplementàrias",
"joined": "Dintrada a la sala suplementària « {{name}} »"
}
},
"privacyView": {
"header": "Confidencialitat"
@@ -1217,5 +1237,6 @@
},
"blankPage": {
"meetingEnded": "Conferéncia acabada."
}
},
"raisedHandsLabel": "Nombre de mans levadas"
}

View File

@@ -39,6 +39,28 @@
"audioOnly": {
"audioOnly": "Niska przepustowość"
},
"blankPage": {
"meetingEnded": "Spotkanie zakończone."
},
"breakoutRooms": {
"defaultName": "Pokój podgrupy #{{index}}",
"mainRoom": "Główny pokój",
"actions": {
"add": "Dodaj pokój podgrupy",
"autoAssign": "Automatycznie przypisuj do pokoi podgrup",
"close": "Blisko",
"join": "Dołącz",
"leaveBreakoutRoom": "Opuść pokój spotkań",
"more": "Więcej",
"remove": "Usuń",
"sendToBreakoutRoom": "Wyślij uczestnika do:"
},
"notifications": {
"joinedTitle": "Pokoje podgrup",
"joined": "Dołączanie do pokoju podgrup \"{{name}}\" ",
"joinedMainRoom": "Dołączanie do głównego pokoju"
}
},
"calendarSync": {
"addMeetingURL": "Dodaj odnośnik do spotkania",
"confirmAddLink": "Czy chcesz dodać odnośnik Jitsi do tego wydarzenia?",
@@ -158,7 +180,8 @@
"joinInApp": "Dołącz do spotkania używając aplikacji",
"launchWebButton": "Uruchom przez przeglądarkę",
"title": "Trwa uruchamianie Twojego spotkania w {{app}}…",
"tryAgainButton": "Spróbuj ponownie w aplikacji stacjonarnej"
"tryAgainButton": "Spróbuj ponownie w aplikacji stacjonarnej",
"unsupportedBrowser": "Wygląda na to, że używasz przeglądarki, której nie wspieramy."
},
"defaultLink": "np. {{url}}",
"defaultNickname": "np. Jan Kowalski",
@@ -206,14 +229,16 @@
"connectErrorWithMsg": "Upsss! Coś poszło nie tak i nie możemy podłączyć się do tej konferencji: {{msg}}",
"connecting": "Nawiązywanie połączenia",
"contactSupport": "Skontaktuj się ze wsparciem",
"copy": "Kopiuj",
"copied": "Skopiowano",
"copy": "Kopiuj",
"dismiss": "Odrzuć",
"displayNameRequired": "Cześć! Jak się nazywasz?",
"done": "Zrobione",
"e2eeDescription": "Szyfrowanie End-to-End jest aktualnie w fazie EKSPERYMENTALNEJ. Proszę mieć na uwadze fakt, że szyfrowanie end-to-end wyłączy oferowane przez serwer usługi takie jak: nagrywanie, streaming na żywo i dołączanie uczestników przez telefon. Proszę mieć również na uwadze fakt, że takie spotkanie będą działać tylko dla uczestników korzystających z przeglądarek wspierających wstawiane strumienie.",
"e2eeLabel": "Klucz E2EE",
"e2eeLabel": "Włącz szyfrowanie E2EE",
"e2eeDisabledDueToMaxModeDescription": "Nie można włączyć szyfrowania End-to-End z powodu dużej liczby uczestników konferencji.",
"e2eeWarning": "UWAGA: Niektórzy uczestnicy tego spotkania nie mają włączonej obsługi szyfrowania E2EE. Jeśli włączysz tą funkcję ci uczestnicy nie będą mieli z tobą kontaktu.",
"e2eeWillDisableDueToMaxModeDescription": "UWAGA: Szyfrowanie typu end-to-end zostanie automatycznie wyłączone, jeśli do konferencji dołączy więcej uczestników.",
"enterDisplayName": "Wpisz tutaj swoje imię",
"embedMeeting": "Osadź spotkanie",
"error": "Błąd",
@@ -249,25 +274,29 @@
"micPermissionDeniedError": "Nie udzieliłeś pozwolenia na użycie twojego mikrofonu. Nadal możesz uczestniczyc w konferencji ale inni nie będą cię słyszeli. Użyj przycisku kamera aby to naprawić.",
"micTimeoutError": "Nie udało się uruchomić źródła dźwięku. Przekroczono limit czasu",
"micUnknownError": "Z nieznanej przyczyny nie można użyć mikrofonu.",
"moderationAudioLabel": "Zezwalaj uczestnikom na wyłączanie wyciszenia",
"moderationVideoLabel": "Zezwalaj uczestnikom na rozpoczęcie wideo",
"muteEveryoneElseDialog": "Gdy wyciszysz wszystkich nie będziesz miał możliwości wyłączyć ich wyciszenia, ale oni będą mogli samodzielnie wyłączyć wyciszenie w dowolnym momencie.",
"muteEveryoneElseTitle": "Wyciszyć wszystkich za wyjątkiem {{whom}}?",
"muteEveryoneElsesVideoDialog": "Po dezaktywacji kamery nie można jej ponownie aktywować, ale uczestnicy mogą to zmienić samodzielnie w dowolnym momencie.",
"muteEveryoneDialog": "Uczestnicy mogą w dowolnym momencie wyłączyć wyciszenie.",
"muteEveryoneDialogModerationOn": "Uczestnicy mogą w każdej chwili wysłać prośbę o zabranie głosu.",
"muteEveryoneTitle": "Wyciszyć wszystkich?",
"muteEveryoneElsesVideoDialog": "Po wyłączeniu kamery nie będzie można go ponownie włączyć, ale można go ponownie włączyć w dowolnym momencie.",
"muteEveryoneElsesVideoTitle": "Wyłączyć kamerę wszystkim oprócz {{whom}}?",
"muteEveryonesVideoDialog": "Czy na pewno chcesz wyłączyć kamery wszystkich uczestników? Nie możesz ponownie włączyć kamer, ale uczestnicy mogą to zmienić samodzielnie w dowolnym momencie.",
"muteEveryonesVideoDialog": "Uczestnicy mogą w każdej chwili włączyć swoje wideo.",
"muteEveryonesVideoDialogModerationOn": "Uczestnicy mogą w dowolnym momencie wysłać prośbę o włączenie ich wideo.",
"muteEveryonesVideoDialogOk": "Wyłącz",
"muteEveryonesVideoTitle": "Wyłączyć kamery pozostałych uczestników?",
"muteEveryoneDialog": "Czy na pewno wyciszyć wszystkich? Nie będziesz miał możliwości wyłączyć ich wyciszenia, ale oni będą mogli samodzielnie wyłączyć wyciszenie w dowolnym momencie.",
"muteEveryoneTitle": "Wyciszyć wszystkich?",
"muteEveryoneSelf": "siebie",
"muteEveryoneStartMuted": "Od tego momentu wszyscy są wyciszeni",
"muteParticipantBody": "Nie możesz wyłączyć ich wyciszenia, ale oni mogą samodzielnie wyłączyć wyciszenie w dowolnym momencie.",
"muteParticipantButton": "Wycisz",
"muteParticipantDialog": "Czy na pewno wyciszyć tego uczestnika? Nie będziesz mógł wyłączyć wyciszenia uczestników, ale oni mogą samodzielnie wyłączyć wyciszenie w dowolnym momencie.",
"muteParticipantsVideoDialog": "Czy na pewno chcesz wyłączyć kamerę tego uczestnika? Nie będziesz mógł ponownie włączyć jego kamery, ale będzie on mógł samodzielnie włączyć kamerę w dowolnym momencie.",
"muteParticipantTitle": "Wyciszyć tego uczestnika?",
"muteParticipantsVideoDialogModerationOn": "Czy na pewno chcesz wyłączyć kamerę tego uczestnika? Nie będziesz w stanie ponownie włączyć aparatu i oni też nie.",
"muteParticipantsVideoButton": "Wyłącz kamerę",
"muteParticipantsVideoTitle": "Wyłączyć kamerę tego uczestnika?",
"muteParticipantsVideoBody": "Nie będziesz mógł włączyć jego kamery ponownie, ale uczestnik samodzielnie może włączyć kamerę w dowolnym momencie.",
"muteParticipantsVideoBodyModerationOn": "Nie będziesz w stanie ponownie włączyć kamery i oni też nie.",
"noDropboxToken": "Brak poprawnego tokenu Dropbox",
"Ok": "OK",
"password": "$t(lockRoomPasswordUppercase)",
@@ -329,6 +358,7 @@
"shareScreenWarningH1": "Kiedy chcesz udostępniać wyłącznie swój ekran:",
"shareScreenWarningD1": "musisz zatrzymać udostępnianie dźwięku przed udostępnieniem ekranu.",
"shareScreenWarningD2": "musisz zatrzymać udostępnianie dźwięku, rozpocząć udostępnianie ekranu i zaznaczyć opcję \"udostępnij dźwięk\".",
"sharedVideoLinkPlaceholder": "Link do YouTube lub bezpośredni link do wideo",
"stopLiveStreaming": "Zatrzymaj transmisję na żywo",
"stopRecording": "Zatrzymaj nagrywanie",
"stopRecordingWarning": "Naprawdę chcesz zatrzymać nagrywanie?",
@@ -388,7 +418,9 @@
"image7": "Wschód słońca",
"desktopShareError": "Nie można udostępnić pulpitu",
"desktopShare": "Udostępnianie pulpitu",
"webAssemblyWarning": "WebAssembly nie jest obsługiwany"
"webAssemblyWarning": "WebAssembly nie jest obsługiwany",
"webAssemblyWarningDescription": "WebAssembly wyłączony lub nieobsługiwany przez tę przeglądarkę",
"backgroundEffectError": "Nie udało się zastosować efektu tła."
},
"feedback": {
"average": "Średnio",
@@ -493,6 +525,7 @@
"expandedPending": "Transmisja na żywo rozpoczyna się…",
"failedToStart": "Transmitowanie na żywo nie uruchomiło się",
"getStreamKeyManually": "Nie byliśmy w stanie pobrać żadnych transmisji na żywo. Spróbuj uzyskać klucz do transmisji na żywo z YouTube.",
"inProgress": "Trwa nagrywanie lub transmisja na żywo",
"invalidStreamKey": "Klucz transmisji na żywo może być nieprawidłowy.",
"off": "Transmitowanie na żywo zostało zatrzymane",
"offBy": "{{name}} zatrzymał transmisję na żywo",
@@ -500,6 +533,7 @@
"onBy": "{{name}} rozpoczął transmisję na żywo",
"pending": "Start strumieniowania live…",
"serviceName": "Usługa transmisji na żywo",
"sessionAlreadyActive": "Ta sesja jest już nagrywana lub transmitowana na żywo.",
"signedInAs": "Jesteś obecnie zalogowany jako:",
"signIn": "Zaloguj się z Google",
"signInCTA": "Zaloguj się lub wpisz swój klucz do transmisji na żywo YouTube.",
@@ -543,18 +577,24 @@
"lockRoomPasswordUppercase": "Hasło",
"me": "to ja",
"notify": {
"allowAction": "Zezwól",
"allowedUnmute": "Możesz wyłączyć wyciszenie mikrofonu, uruchomić aparat lub udostępnić ekran.",
"audioUnmuteBlockedTitle": "Zablokowano wyciszenie mikrofonu!",
"audioUnmuteBlockedDescription": "Operacja wyłączania wyciszenia mikrofonu została tymczasowo zablokowana z powodu ograniczeń systemu.",
"connectedOneMember": "{{name}} dołączył do spotkania",
"connectedThreePlusMembers": "{{name}} i {{count}} innych osób dołączyło do spotkania",
"connectedTwoMembers": "{{first}} i {{second}} dołączyli do spotkania",
"disconnected": "Rozłączono",
"focus": "Fokus konferencji",
"focusFail": "{{component}} jest niedostępny - ponowienie w ciągu {{ms}} sec",
"grantedTo": "Prawa moderatora przyznane dla {{to}}!",
"hostAskedUnmute": "Gospodarz prosi Cię o wyłączenie wyciszenia",
"invitedOneMember": "{{name}} został zaproszony",
"invitedThreePlusMembers": "{{name}} i {{count}} innych osób zostało zaproszone",
"invitedTwoMembers": "{{first}} i {{second}} zostali zaproszeni",
"kickParticipant": "{{kicked}} został usunięty przez {{kicker}}",
"leftOneMember": "{{name}} opuścił spotkanie",
"leftThreePlusMembers": "{{name}} i wielu innych opuściło spotkanie",
"leftTwoMembers": "{{first}} i {{second}} opuścił spotkanie",
"me": "To ja",
"moderator": "Prawa moderatora przydzielone!",
"muted": "Rozpoczęto wyciszenie konwersacji.",
@@ -566,8 +606,10 @@
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) usunięte przez innego uczestnika",
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) ustawiony przez innego uczestnika",
"raisedHand": "{{name}} chce mówić.",
"raisedHands": "{{participantName}} i {{raisedHands}} więcej osób",
"screenShareNoAudio": "Opcja \"Udostępnij dźwięk\" nie została zaznaczona podczas wyboru okna.",
"screenShareNoAudioTitle": "Nie można udostępnić dźwięku",
"selfViewTitle": "Zawsze możesz odkryć własny podgląd w ustawieniach",
"somebody": "Ktoś",
"startSilentTitle": "Dołączyłeś bez wyjścia dźwiękowego!",
"startSilentDescription": "Ponownie dołącz do spotkania, aby włączyć dźwięk",
@@ -594,7 +636,10 @@
"moderationToggleDescription": "przez {{participantDisplayName}}",
"raiseHandAction": "Podnieś rękę",
"reactionSounds": "Wyłącz dźwięki",
"groupTitle": "Powiadomienia"
"reactionSoundsForAll": "Wyłącz dźwięki dla wszystkich",
"groupTitle": "Powiadomienia",
"videoUnmuteBlockedTitle": "Wyłączenie wyciszenia kamery i udostępnianie pulpitu zablokowane!",
"videoUnmuteBlockedDescription": "Operacje wyłączania wyciszenia kamery i udostępniania pulpitu zostały tymczasowo zablokowane z powodu ograniczeń systemu."
},
"participantsPane": {
"close": "Zamknij",
@@ -606,21 +651,28 @@
},
"actions": {
"allow": "Zezwól uczestnikom na:",
"allowVideo": "Zezwól na wideo",
"audioModeration": "Wyłącz wyciszenie",
"blockEveryoneMicCamera": "Zablokuj wszystkim kamerę i mikrofon",
"invite": "Zaproś",
"askUnmute": "Poproś o wyłączenie wyciszenia",
"moreModerationActions": "Więcej opcji moderatora",
"moreParticipantOptions": "Więcej opcji dla uczestników",
"mute": "Wycisz",
"muteAll": "Wycisz wszystkich",
"muteEveryoneElse": "Wycisz pozostałych",
"startModeration": "Wyłącz wyciszenie lub rozpocznij wideo",
"stopEveryonesVideo": "Wyłącz wszystkie kamery",
"stopVideo": "Wyłącz kamerę",
"unblockEveryoneMicCamera": "Odblokuj wszystkim kamerę i mikrofon"
}
"unblockEveryoneMicCamera": "Odblokuj wszystkim kamerę i mikrofon",
"videoModeration": "Włącz kamerę",
"moreModerationControls": "Więcej kontroli moderacji"
},
"search": "Wyszukaj uczestników"
},
"passwordSetRemotely": "wybrane przez innego uczestnika",
"passwordSetRemotely": "Ustawione przez innego uczestnika",
"passwordDigitsOnly": "Do {{number}} cyfr",
"polls": {
"by": "Przez {{ name }}",
"create": {
"addOption": "Dodaj opcję",
"answerPlaceholder": "Opcja {{index}}",
@@ -688,6 +740,7 @@
"errorDialOutFailed": "Nie udało się wybrać numeru. Połączenie nieudane",
"errorDialOutStatus": "Błąd podczas uzyskiwania stanu połączenia",
"errorMissingName": "Podaj imię, aby dołączyć do spotkania",
"errorNoPermissions": "Musisz włączyć dostęp do mikrofonu i kamery",
"errorStatusCode": "Błąd wybierania, kod statusu: {{status}}",
"errorValidation": "Weryfikacja numeru zakończona niepowodzeniem",
"iWantToDialIn": "Chcę się wdzwonić",
@@ -745,6 +798,7 @@
"expandedPending": "Nagrywanie się rozpoczyna…",
"failedToStart": "Nagrywanie nie jest możliwe",
"fileSharingdescription": "Udostępnij nagranie uczestnikom spotkania",
"inProgress": "Trwa nagrywanie lub transmisja na żywo",
"linkGenerated": "Wygenerowano link do nagrania.",
"live": "NA ŻYWO",
"loggedIn": "Zalogowano jako {{userName}}",
@@ -757,6 +811,7 @@
"serviceDescription": "Twoje nagranie zostanie zapisane przez usługę nagrywania",
"serviceDescriptionCloud": "Nagrywanie w chmurze",
"serviceName": "Usługa nagrywania",
"sessionAlreadyActive": "Ta sesja jest już nagrywana lub transmitowana na żywo.",
"signIn": "Zaloguj się",
"signOut": "Wyloguj się",
"unavailable": "Ups! {{serviceName}} w tej chwili niedostępny. Próbujemy rozwiązać ten problem. Spróbuj ponownie później.",
@@ -769,8 +824,8 @@
"security": {
"about": "Możesz dodać $t(lockRoomPassword) do spotkania. Uczestnicy będą musieli wprowadzić $t(lockRoomPassword) przed dołączeniem do spotkania.",
"aboutReadOnly": "Uczestnicy posiadający uprawnienia do moderacji mogą ustawić $t(lockRoomPassword) do spotkania. Uczestnicy będą musieli wprowadzić $t(lockRoomPassword) zanim zostaną dołączeni do spotkania.",
"insecureRoomNameWarning": "Nazwa pokoju nie jest bezpieczna. Niepowołaniu uczestnicy mogą dołączyć do spotkania. Proszę rozważyć ustawienie hasła spotkania używając przycisku Opcje zabezpieczeń.",
"securityOptions": "Opcje zabezpieczeń"
"header": "Opcje zabezpieczeń",
"insecureRoomNameWarning": "Nazwa pokoju nie jest bezpieczna. Niepowołaniu uczestnicy mogą dołączyć do spotkania. Proszę rozważyć ustawienie hasła spotkania używając przycisku Opcje zabezpieczeń."
},
"settings": {
"calendar": {
@@ -790,7 +845,6 @@
"language": "Język",
"loggedIn": "Zalogowano jako {{name}}",
"microphones": "Mikrofony",
"sounds": "Dźwięki",
"moderator": "Moderacja",
"more": "Więcej",
"name": "Nazwa",
@@ -803,8 +857,11 @@
"selectAudioOutput": "Wyjście audio",
"selectCamera": "Kamera",
"selectMic": "Mikrofon",
"selfView": "Własnego podgląd",
"sounds": "Dźwięki",
"speakers": "Głośniki",
"startAudioMuted": "Wycisz wszystkich dołączających",
"startReactionsMuted": "Wycisz dźwięki reakcji dla wszystkich",
"startVideoMuted": "Ukryj wszystkich dołączających",
"talkWhileMuted": "Jesteś wyciszony",
"title": "Ustawienia"
@@ -837,13 +894,20 @@
},
"speaker": "Mówca",
"speakerStats": {
"search": "Wyszukaj",
"angry": "Zły",
"disgusted": "Oburzony",
"fearful": "Przerażony",
"happy": "Szczęśliwy",
"hours": "{{count}} godz.",
"minutes": "{{count}} min.",
"name": "Nazwa",
"neutral": "Neutralny",
"sad": "Smutny",
"search": "Wyszukaj",
"seconds": "{{count}} sek.",
"speakerTime": "Czas mówcy",
"speakerStats": "Statystyki mówców",
"speakerTime": "Czas mówcy"
"surprised": "Zdziwiony"
},
"startupoverlay": {
"policyText": " ",
@@ -860,6 +924,7 @@
"audioOnly": "Przełączanie tylko audio",
"audioRoute": "Wybierz urządzenie dźwiękowe",
"boo": "Buczenie",
"breakoutRoom": "Dołącz/opuść pokój podgrupy",
"callQuality": "Zarządzanie jakością obrazu",
"cc": "Przełączanie napisów",
"chat": "Przełączanie okna rozmowy",
@@ -943,7 +1008,9 @@
"hangup": "Opuść spotkanie",
"help": "Pomoc",
"invite": "Zaproś uczestników",
"joinBreakoutRoom": "Dołącz do pokoju podgrupy",
"laugh": "Śmiech",
"leaveBreakoutRoom": "Opuść pokój spotkań",
"like": "Kciuk w górę",
"lobbyButtonDisable": "Wyłącz tryb lobby",
"lobbyButtonEnable": "Włącz tryb lobby",
@@ -1033,7 +1100,10 @@
"pending": "{{displayName}} został zaproszony"
},
"videoStatus": {
"adjustFor": "Dostosuj do:",
"audioOnly": "DŹW",
"bestPerformance": "Najlepsza wydajność",
"highestQuality": "Najwyższa jakość",
"audioOnlyExpanded": "Jesteś w trybie słabego łącza. W tym trybie będziesz otrzymywać tylko dźwięk i udostępnianie ekranu.",
"callQuality": "Jakość obrazu",
"hd": "HD",
@@ -1044,6 +1114,7 @@
"ld": "LD",
"ldTooltip": "Podgląd obrazu w niskiej rozdzielczości",
"lowDefinition": "Niska rozdzielczość",
"performanceSettings": "Ustawienia wydajności",
"sd": "SD",
"sdTooltip": "Podgląd obrazu w standardowej rozdzielczości",
"standardDefinition": "Standardowa rozdzielczość"
@@ -1056,14 +1127,15 @@
"domuteVideoOfOthers": "Wyłącz kamerę pozostałym",
"flip": "Odwrócenie",
"grantModerator": "Przyznaj prawa moderatora",
"hideSelfView": "Ukryj widok własnego podglądu",
"kick": "Wyrzuć",
"moderator": "Moderator",
"mute": "Uczestnik ma wyciszone audio",
"muted": "Wyciszony",
"videoMuted": "Kamera wyłączona",
"remoteControl": "Kontrola zdalna",
"show": "Pokaż na scenie",
"videomute": "Uczestnik zatrzymał kamerę",
"videoMuted": "Kamera wyłączona"
"videomute": "Uczestnik zatrzymał kamerę"
},
"welcomepage": {
"addMeetingName": "Dodaj nazwę spotkania",

View File

@@ -13,7 +13,7 @@
"failedToAdd": "Falha ao adicionar participantes",
"footerText": "A marcação está desactivada.",
"googleEmail": "Email do Google",
"inviteMoreHeader": "Você é o único na reunião",
"inviteMoreHeader": "É o único na reunião",
"inviteMoreMailSubject": "Participar na reunião {{appName}}",
"inviteMorePrompt": "Convidar mais pessoas",
"linkCopied": "Link copiado para a área de transferência",
@@ -43,7 +43,7 @@
"meetingEnded": "A reunião terminou."
},
"breakoutRooms": {
"defaultName": "Salas simultâneas #{{index}}",
"defaultName": "Sala #{{index}}",
"mainRoom": "Sala principal",
"actions": {
"add": "Adicionar salas simultâneas",
@@ -57,7 +57,7 @@
},
"notifications": {
"joinedTitle": "Salas simultâneas",
"joined": "Entrada do \"{{name}}\" na sala",
"joined": "Entrada na sala \"{{name}}\"",
"joinedMainRoom": "Entrada na sala principal"
}
},
@@ -94,7 +94,7 @@
"privateNotice": "Mensagem privada para {{recipient}}",
"message": "Mensagem",
"messageAccessibleTitle": "{{user}} disse:",
"messageAccessibleTitleMe": "Você disse:",
"messageAccessibleTitleMe": "Eu disse:",
"smileysPanel": "Painel de Emojis",
"tabs": {
"chat": "Chat",
@@ -180,7 +180,8 @@
"joinInApp": "Participe nesta reunião utilizando a aplicação",
"launchWebButton": "Iniciar na web",
"title": "A iniciar a sua reunião na {{app}}...",
"tryAgainButton": "Tente novamente no desktop"
"tryAgainButton": "Tente novamente no desktop",
"unsupportedBrowser": "Parece que está a usar um browser que não suportamos."
},
"defaultLink": "ex.: {{url}}",
"defaultNickname": "ex.: João Pedro",
@@ -418,6 +419,7 @@
"desktopShareError": "Não foi possível partilhar a área de trabalho",
"desktopShare":"Partilhar área de trabalho",
"webAssemblyWarning": "WebAssembly não suportado",
"webAssemblyWarningDescription": "WebAssembly desactivado ou não suportado por este navegador",
"backgroundEffectError": "Falha ao aplicar efeito de fundo."
},
"feedback": {
@@ -468,7 +470,7 @@
"noPassword": "Nenhum",
"noRoom": "Não foi especificado nenhuma sala para ligar.",
"numbers": "Números para entrar por chamada telefónica",
"password": "$t(lockRoomPasswordUppercase):",
"password": "$t(lockRoomPasswordUppercase): ",
"sip": "Endereços SIP",
"title": "Partilhar",
"tooltip": "Partilhar link e acesso telefónico para esta reunião",
@@ -513,7 +515,7 @@
"busyTitle": "Todas as transmissões estão atualmente ocupadas",
"changeSignIn": "Alternar contas.",
"choose": "Escolha uma transmissão em direto",
"chooseCTA": "Escolha uma opção de transmissão. Você está conectado atualmente como {{email}}.",
"chooseCTA": "Escolha uma opção de transmissão. Está conectado atualmente como {{email}}.",
"enterStreamKey": "Insira sua chave de transmissão em direto do YouTube aqui.",
"error": "Falha na transmissão em direto. Tente de novo.",
"errorAPI": "Ocorreu um erro ao acessar suas transmissões do YouTube. Por favor tente logar novamente.",
@@ -532,7 +534,7 @@
"pending": "Iniciando Transmissão em Direto...",
"serviceName": "Serviço de Transmissão em Direto",
"sessionAlreadyActive": "Esta sessão já está a ser gravada ou transmitida em direto.",
"signedInAs": "Você está conectado como:",
"signedInAs": "Está conectado como:",
"signIn": "Faça login no Google",
"signInCTA": "Faça login ou insira sua chave de transmissão em Direto do YouTube.",
"signOut": "Sair",
@@ -560,7 +562,7 @@
"engaged": "Gravação local iniciada.",
"finished": "Sessão de gravação {{token}} terminada. Por favor, envie o arquivo gravado para o moderador.",
"finishedModerator": "Sessão de gravação {{token}} terminada. A gravação da faixa local foi salva. Por favor, peça aos outros participantes para enviar suas gravações.",
"notModerator": "Você não é o moderador. Você não pode iniciar ou parar a gravação local."
"notModerator": "Não é o moderador. Não pode iniciar ou parar a gravação local."
},
"moderator": "Moderador",
"no": "Não",
@@ -579,10 +581,12 @@
"allowedUnmute": "Pode ligar o seu microfone, ligar a sua câmara ou partilhar o seu ecrã.",
"audioUnmuteBlockedTitle": "Ligar microfone bloqueado!",
"audioUnmuteBlockedDescription": "A operação de ligar o microfone foi temporariamente bloqueada devido aos limites do sistema.",
"chatMessages": "Mensagens de chat",
"connectedOneMember": "{{name}} entrou na reunião",
"connectedThreePlusMembers": "{{name}} e muitos outros entraram na reunião",
"connectedTwoMembers": "{{first}} e {{second}} entraram na reunião",
"disconnected": "desconectado",
"displayNotifications": "Mostrar notificações para",
"focus": "Foco da conferência",
"focusFail": "{{component}} não disponĩvel - tente em {{ms}} seg.",
"hostAskedUnmute": "O moderador gostaria que você falasse",
@@ -595,8 +599,8 @@
"leftTwoMembers": "{{first}} e {{second}} deixaram a reunião",
"me": "Eu",
"moderator": "É agora um moderador",
"muted": "Você iniciou uma conversa com o microfone desativado.",
"mutedTitle": "Você está silenciado!",
"muted": "Iniciou uma conversa com o microfone desativado.",
"mutedTitle": "Está silenciado!",
"mutedRemotelyTitle": "Foi silenciado pelo {{participantDisplayName}}",
"mutedRemotelyDescription": "Pode sempre voltar a ativar o microfone quando estiver pronto para falar. Silencie de volta quando estiver pronto para manter o barulho afastado da reunião.",
"videoMutedRemotelyTitle": "A sua câmara foi desligada pelo {{participantDisplayName}}.",
@@ -607,8 +611,9 @@
"raisedHands": "{{participantName}} e mais {{raisedHands}} pessoas",
"screenShareNoAudio": " A caixa de compartilhar áudio não foi marcada no ecrã de seleção da janela.",
"screenShareNoAudioTitle": "Não foi possível partilhar o áudio do sistema!",
"selfViewTitle": "Pode sempre reexibir a autovisualização a partir das definições",
"somebody": "Alguém",
"startSilentTitle": "Você entrou sem saída de áudio!",
"startSilentTitle": "Entrou sem saída de áudio!",
"startSilentDescription": "Volte à reunião para habilitar o áudio",
"suboptimalBrowserWarning": "Tememos que sua experiência de reunião não seja tão boa aqui. Estamos procurando maneiras de melhorar isso, mas até então, tente usar um dos <a href='{{recommendedBrowserPageLink}}' target='_blank'>navegadores completamente suportados</a>.",
"suboptimalExperienceTitle": "Alerta do navegador",
@@ -635,8 +640,8 @@
"reactionSounds": "Desactivar sons",
"reactionSoundsForAll": "Desativar sons para todos",
"groupTitle": "Notificações",
"videoUnmuteBlockedTitle": "Ligar câmara bloqueada!",
"videoUnmuteBlockedDescription": "A operação de ligar a câmara foi temporariamente bloqueada devido aos limites do sistema."
"videoUnmuteBlockedTitle": "Está bloqueado ligar a câmara e partilhar o ambiente de trabalho!",
"videoUnmuteBlockedDescription": "A operação de ligar a câmara e partilhar o ambiente de trabalho foi temporariamente bloqueada devido aos limites do sistema."
},
"participantsPane": {
"close": "Fechar",
@@ -649,7 +654,7 @@
"actions": {
"allow": "Permitir aos participantes:",
"allowVideo": "Permitir vídeo",
"audioModeration": "Ativarem o microfone deles",
"audioModeration": "Ativar o microfone deles",
"blockEveryoneMicCamera": "Bloquear o microfone e a câmara de todos",
"invite": "Convidar alguém",
"askUnmute": "Pedir para ligar o microfone",
@@ -661,7 +666,7 @@
"stopEveryonesVideo": "Desligar a câmara de todos",
"stopVideo": "Desligar a câmara",
"unblockEveryoneMicCamera": "Desbloquear o microfone e a câmara de todos",
"videoModeration": "Ligarem a câmara deles",
"videoModeration": "Ligar a câmara deles",
"moreModerationControls": "Mais controlos de moderação"
},
"search": "Pesquisar participantes"
@@ -779,6 +784,7 @@
"title": "Perfil"
},
"raisedHand": "Gostaria de falar",
"raisedHandsLabel": "Número de mãos levantadas",
"recording": {
"limitNotificationDescriptionWeb": "Devido à grande procura, a sua gravação será limitada a {{limit}} min. For unlimited recordings try <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
"limitNotificationDescriptionNative": "Due to high demand your recording will be limited to {{limit}} min. Para gravações ilimitadas tente <3>{{app}}</3>.",
@@ -821,8 +827,8 @@
"security": {
"about": "Pode adicionar uma $t(lockRoomPassword) à sua reunião. Os participantes terão de fornecer a $t(lockRoomPassword) antes de serem autorizados a participar na reunião.",
"aboutReadOnly": "Os participantes moderadores podem acrescentar uma $t(lockRoomPassword) à reunião. Os participantes terão de fornecer a $t(lockRoomPassword) antes de serem autorizados a participar na reunião.",
"insecureRoomNameWarning": "O nome da sala é inseguro. Participantes indesejados podem juntar-se à sua conferência. Considere proteger a sua reunião utilizando o botão de segurança.",
"securityOptions": "Opções de segurança"
"header": "Opções de segurança",
"insecureRoomNameWarning": "O nome da sala é inseguro. Participantes indesejados podem juntar-se à sua conferência. Considere proteger a sua reunião utilizando o botão de segurança."
},
"settings": {
"calendar": {
@@ -854,6 +860,7 @@
"selectAudioOutput": "Saída de áudio",
"selectCamera": "Câmara",
"selectMic": "Microfone",
"selfView": "Autovisualização",
"sounds": "Sons",
"speakers": "Participantes",
"startAudioMuted": "Todos começam com microfone desligado",
@@ -890,20 +897,20 @@
},
"speaker": "Participante",
"speakerStats": {
"search": "Pesquisar",
"angry": "Zangado",
"disgusted": "Desgostoso",
"fearful": "Temeroso",
"happy": "Feliz",
"hours": "{{count}}h",
"minutes": "{{count}}m",
"name": "Nome",
"seconds": "{{count}}s",
"speakerStats": "Estatísticas dos Participantes",
"speakerTime": "Tempo do Participante",
"happy": "Feliz",
"neutral": "Neutro",
"sad": "Triste",
"surprised": "Surpreendido",
"angry": "Zangado",
"fearful": "Temeroso",
"disgusted": "Desgostoso"
"search": "Pesquisar",
"seconds": "{{count}}s",
"speakerTime": "Tempo do Participante",
"speakerStats": "Estatísticas dos Participantes",
"surprised": "Surpreendido"
},
"startupoverlay": {
"policyText": " ",
@@ -946,8 +953,8 @@
"mute": "Ativar / Desativar microfone",
"muteEveryone": "Silenciar a todos",
"muteEveryoneElse": "Silenciar todos os outros",
"muteEveryonesVideo": "Desativar o vídeo de todos",
"muteEveryoneElsesVideo": "Desativar o vídeo de todos os outros",
"muteEveryonesVideo": "Parar o vídeo de todos",
"muteEveryoneElsesVideo": "Parar o vídeo de todos os outros",
"participants": "Participantes",
"pip": "Mudar para o modo Picture-in-Picture",
"privateMessage": "Enviar mensagem privada",
@@ -1123,6 +1130,7 @@
"domuteVideoOfOthers": "Desactivar a câmara de todos os outros",
"flip": "Inverter",
"grantModerator": "Conceder direitos de moderador",
"hideSelfView": "Ocultar a autovisualização",
"kick": "Expulsar",
"moderator": "Moderador",
"mute": "Participante está sem som",
@@ -1138,7 +1146,7 @@
"join": "Toque para entrar",
"roomname": "Digite o nome da sala"
},
"appDescription": "Vá em frente, converse por vídeo com toda a equipa. Na verdade, convide todos os que conhece. {{app}} é uma solução de videoconferência totalmente criptografada e 100% de código aberto que você pode usar todos os dias, a cada dia, gratuitamente — sem necessidade de conta.",
"appDescription": "Vá em frente, converse por vídeo com toda a equipa. Na verdade, convide todos os que conhece. {{app}} é uma solução de videoconferência totalmente criptografada e 100% de código aberto que pode usar todos os dias, a cada dia, gratuitamente — sem necessidade de conta.",
"audioVideoSwitch": {
"audio": "Voz",
"video": "Vídeo"
@@ -1162,7 +1170,7 @@
"privacy": "Política de Privacidade",
"recentList": "Recente",
"recentListDelete": "Remover",
"recentListEmpty": "Sua lista recente está vazia. As reuniões que você realizar serão exibidas aqui.",
"recentListEmpty": "A sua lista recente está atualmente vazia. Converse com a sua equipa e encontrará aqui todas as suas reuniões recentes.",
"reducedUIText": "Bem-vindo ao {{app}}!",
"roomNameAllowedChars": "Nome da reunião não deve conter qualquer um destes caracteres: ?. &, :, ', \", %, #.",
"roomname": "Digite o nome da sala",

View File

@@ -102,10 +102,13 @@
},
"connectionindicator": {
"address": "Адрес:",
"audio_ssrc": "Аудио SSRC:",
"bandwidth": "Средняя скорость:",
"bitrate": "Битрейт:",
"bridgeCount": "Количество серверов: ",
"codecs": "Кодеки (A/V): ",
"connectedTo": "Подключен к:",
"e2e_rtt": "E2E RTT:",
"framerate": "Частота кадров:",
"less": "Краткая информация",
"localaddress_0": "Локальный адрес:",
@@ -114,6 +117,7 @@
"localport_0": "Локальный порт:",
"localport_1": "Локальных порта:",
"localport_2": "Локальных портов:",
"maxEnabledResolution": "Максимальное разрешение",
"more": "Подробная информация",
"packetloss": "Потери пакетов:",
"quality": {
@@ -130,10 +134,13 @@
"remoteport_1": "Удаленных порта:",
"remoteport_2": "Удаленных портов:",
"resolution": "Разрешение:",
"savelogs": "Сохранить логи",
"participant_id": "id участника:",
"status": "Связь:",
"transport_0": "Метод отправки:",
"transport_1": "Метода отправки:",
"transport_2": "Методов отправки:"
"transport_2": "Методов отправки:",
"video_ssrc": "Видео SSRC:"
},
"dateUtils": {
"earlier": "Ранее",
@@ -559,6 +566,30 @@
"suboptimalExperienceTitle": "Предупреждение браузера",
"unmute": "Включить микрофон"
},
"participantsPane": {
"close": "Закрыть",
"header": "Участники",
"headings": {
"lobby": "Лобби ({{count}})",
"participantsList": "Список участников ({{count}})",
"waitingLobby": "Ожидают в лобби ({{count}})"
},
"actions": {
"allow": "Разрешить",
"allowVideo": "Разрешить видео",
"audioModeration": "Разрешить выключить микрофон",
"blockEveryoneMicCamera": "Заблокировать у всех микрофон и камеру",
"invite": "Пригласить",
"askUnmute": "Попросить разрешение включить микрофон",
"mute": "Выключить звук",
"muteAll": "Выключить звук у всех",
"muteEveryoneElse": "Выключить микрофон у остальных",
"stopEveryonesVideo": "Выключить у всех камеру",
"stopVideo": "Остановить видео",
"unblockEveryoneMicCamera": "Разблокировать у всех микрофон и камеру",
"videoModeration": "Разрешить видео"
}
},
"passwordDigitsOnly": "До {{number}} цифр",
"passwordSetRemotely": "установлен другим участником",
"poweredby": "работает на",
@@ -744,7 +775,7 @@
"hangup": "Завершить звонок",
"help": "Справка",
"invite": "Пригласить",
"kick": "Выкинуть участника",
"kick": "Отключить участника",
"lobbyButton": "Вкл/Выкл режим лобби",
"localRecording": "Вкл/Выкл кнопки записи",
"lockRoom": "Установить пароль",
@@ -774,13 +805,18 @@
"videomute": "Вкл/Выкл видео"
},
"addPeople": "Добавить людей к вашему сеансу связи",
"audioSettings": "Настройка звука",
"videoSettings": "Настройка видео",
"audioOnlyOff": "Отключить режим экономии пропускной способности",
"audioOnlyOn": "Включить режим экономии пропускной способности",
"audioRoute": "Выбрать аудиоустройство",
"authenticate": "Аутентифицировать",
"boo": "Освистывать",
"callQuality": "Качество связи",
"chat": "Чат",
"clap": "Аплодисменты",
"closeChat": "Закрыть чат",
"closeReactionsMenu": "Закрыть меню реакций",
"documentClose": "Закрыть общий документ",
"documentOpen": "Открыть общий документ",
"download": "Скачать приложение",
@@ -794,6 +830,8 @@
"hangup": "Выход",
"help": "Справка",
"invite": "Пригласить",
"laugh": "Смеяться",
"like": "Мне нравится",
"lobbyButtonDisable": "Отключить режим лобби",
"lobbyButtonEnable": "Включить режим лобби",
"login": "Войти",
@@ -812,6 +850,7 @@
"noisyAudioInputTitle": "Похоже, ваш микрофон создает шум!",
"noisyAudioInputDesc": "Возможно, ваш микрофон создает шум. Вы можете выключить его или смените устройство.",
"openChat": "Открыть чат",
"openReactionsMenu": "Открыть меню реакций",
"participants": "Участники",
"pip": "Вкл режим Картинка-в-картинке",
"privateMessage": "Отправить личное сообщение",
@@ -819,9 +858,12 @@
"raiseHand": "Хочу говорить",
"raiseYourHand": "Поднять руку",
"security": "Настройки безопасности",
"selectBackground": "Выбрать фоновое изображение",
"shareRoom": "Отправить приглашение",
"shareaudio": "Предоставить доступ к звуку",
"sharedvideo": "Видео YouTube",
"shortcuts": "Комбинации клавиш",
"silence": "Молчание",
"speakerStats": "Статистика",
"startScreenSharing": "Начать трансляцию с экрана",
"startSubtitles": "Включить субтитры",
@@ -830,6 +872,7 @@
"stopSharedVideo": "Остановить видео на YouTube",
"stopSubtitles": "Отключить субтитры",
"stopvideoblur": "Отключить размытие фона",
"surprised": "Удивиться",
"talkWhileMutedPopup": "Пытаетесь говорить? У вас отключен звук.",
"tileViewToggle": "Вкл/выкл плитку",
"toggleCamera": "Переключить камеру",
@@ -887,17 +930,21 @@
"standardDefinition": "Стандартное качество (SD)"
},
"videothumbnail": {
"connectionInfo": "Информация о соединении",
"domute": "Выключить звук",
"domuteOthers": "Выключить остальных",
"domuteVideo": "Выключить видео",
"domuteOthers": "Выключить звук остальным",
"domuteVideoOfOthers": "Выключить видео остальным",
"flip": "Отразить",
"grantModerator": "Сделать модератором",
"kick": "Выкинуть",
"kick": "Отключить",
"moderator": "Модератор",
"mute": "Без звука",
"muted": "Звук выключен",
"videoMuted": "Камера выключена",
"remoteControl": "Начать / Остановить дистанционный контроль",
"show": "Показать крупным планом",
"videomute": "Участник отключил камеру"
"videomute": "Участник выключил камеру"
},
"welcomepage": {
"accessibilityLabel": {
@@ -934,4 +981,4 @@
"terms": "Условия",
"title": "Защищенная, полнофункциональная и совершенно бесплатная система видеоконференций"
}
}
}

View File

@@ -470,7 +470,7 @@
"noPassword": "None",
"noRoom": "No room was specified to dial-in into.",
"numbers": "Dial-in Numbers",
"password": "$t(lockRoomPasswordUppercase):",
"password": "$t(lockRoomPasswordUppercase): ",
"sip": "SIP address",
"title": "Share",
"tooltip": "Share link and dial-in info for this meeting",
@@ -581,10 +581,12 @@
"allowedUnmute": "You can unmute your microphone, start your camera or share your screen.",
"audioUnmuteBlockedTitle": "Mic unmute blocked!",
"audioUnmuteBlockedDescription": "Mic unmute operation has been temporarily blocked because of system limits.",
"chatMessages": "Chat messages",
"connectedOneMember": "{{name}} joined the meeting",
"connectedThreePlusMembers": "{{name}} and many others joined the meeting",
"connectedTwoMembers": "{{first}} and {{second}} joined the meeting",
"disconnected": "disconnected",
"displayNotifications": "Display notifications for",
"focus": "Conference focus",
"focusFail": "{{component}} not available - retry in {{ms}} sec",
"hostAskedUnmute": "The moderator would like you to speak",
@@ -638,8 +640,8 @@
"reactionSounds": "Disable sounds",
"reactionSoundsForAll": "Disable sounds for all",
"groupTitle": "Notifications",
"videoUnmuteBlockedTitle": "Camera unmute blocked!",
"videoUnmuteBlockedDescription": "Camera unmute operation has been temporarily blocked because of system limits."
"videoUnmuteBlockedTitle": "Camera unmute and desktop sharing blocked!",
"videoUnmuteBlockedDescription": "Camera unmute and desktop sharing operation have been temporarily blocked because of system limits."
},
"participantsPane": {
"close": "Close",
@@ -782,6 +784,7 @@
"title": "Profile"
},
"raisedHand": "Would like to speak",
"raisedHandsLabel": "Number of raised hands",
"recording": {
"limitNotificationDescriptionWeb": "Due to high demand your recording will be limited to {{limit}} min. For unlimited recordings try <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
"limitNotificationDescriptionNative": "Due to high demand your recording will be limited to {{limit}} min. For unlimited recordings try <3>{{app}}</3>.",
@@ -824,8 +827,8 @@
"security": {
"about": "You can add a $t(lockRoomPassword) to your meeting. Participants will need to provide the $t(lockRoomPassword) before they are allowed to join the meeting.",
"aboutReadOnly": "Moderator participants can add a $t(lockRoomPassword) to the meeting. Participants will need to provide the $t(lockRoomPassword) before they are allowed to join the meeting.",
"insecureRoomNameWarning": "The room name is unsafe. Unwanted participants may join your conference. Consider securing your meeting using the security button.",
"securityOptions": "Security options"
"header": "Security Options",
"insecureRoomNameWarning": "The room name is unsafe. Unwanted participants may join your conference. Consider securing your meeting using the security button."
},
"settings": {
"calendar": {
@@ -857,6 +860,7 @@
"selectAudioOutput": "Audio output",
"selectCamera": "Camera",
"selectMic": "Microphone",
"selfView": "Self view",
"sounds": "Sounds",
"speakers": "Speakers",
"startAudioMuted": "Everyone starts muted",
@@ -893,20 +897,20 @@
},
"speaker": "Speaker",
"speakerStats": {
"search": "Search",
"angry": "Angry",
"disgusted": "Disgusted",
"fearful": "Fearful",
"happy": "Happy",
"hours": "{{count}}h",
"minutes": "{{count}}m",
"name": "Name",
"seconds": "{{count}}s",
"speakerStats": "Speaker Stats",
"speakerTime": "Speaker Time",
"happy": "Happy",
"neutral": "Neutral",
"sad": "Sad",
"surprised": "Surprised",
"angry": "Angry",
"fearful": "Fearful",
"disgusted": "Disgusted"
"search": "Search",
"seconds": "{{count}}s",
"speakerTime": "Speaker Time",
"speakerStats": "Speaker Stats",
"surprised": "Surprised"
},
"startupoverlay": {
"policyText": " ",
@@ -949,8 +953,8 @@
"mute": "Mute / Unmute",
"muteEveryone": "Mute everyone",
"muteEveryoneElse": "Mute everyone else",
"muteEveryonesVideo": "Disable everyone's video",
"muteEveryoneElsesVideo": "Disable everyone else's video",
"muteEveryonesVideoStream": "Stop everyone's video",
"muteEveryoneElsesVideoStream": "Stop everyone else's video",
"participants": "Participants",
"pip": "Toggle Picture-in-Picture mode",
"privateMessage": "Send private message",

View File

@@ -21,6 +21,7 @@ import {
getCurrentConference,
sendTones,
setFollowMe,
setLocalSubject,
setPassword,
setSubject
} from '../../react/features/base/conference';
@@ -136,6 +137,10 @@ function initCommands() {
sendAnalytics(createApiEvent('display.name.changed'));
APP.conference.changeLocalDisplayName(displayName);
},
'local-subject': localSubject => {
sendAnalytics(createApiEvent('local.subject.changed'));
APP.store.dispatch(setLocalSubject(localSubject));
},
'mute-everyone': mediaType => {
const muteMediaType = mediaType ? mediaType : MEDIA_TYPE.AUDIO;
@@ -1516,12 +1521,14 @@ class API {
* Notify external application ( if API is enabled) that a toolbar button was clicked.
*
* @param {string} key - The key of the toolbar button.
* @param {boolean} preventExecution - Whether execution of the button click was prevented or not.
* @returns {void}
*/
notifyToolbarButtonClicked(key: string) {
notifyToolbarButtonClicked(key: string, preventExecution: boolean) {
this._sendEvent({
name: 'toolbar-button-clicked',
key
key,
preventExecution
});
}

View File

@@ -38,6 +38,7 @@ const commands = {
toggleLobby: 'toggle-lobby',
hangup: 'video-hangup',
initiatePrivateChat: 'initiate-private-chat',
localSubject: 'local-subject',
kickParticipant: 'kick-participant',
muteEveryone: 'mute-everyone',
overwriteConfig: 'overwrite-config',

27
package-lock.json generated
View File

@@ -36,6 +36,7 @@
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
"@microsoft/microsoft-graph-client": "1.1.0",
"@react-native-async-storage/async-storage": "1.15.5",
"@react-native-community/clipboard": "1.5.1",
"@react-native-community/google-signin": "3.0.1",
"@react-native-community/netinfo": "4.1.5",
"@react-native-community/slider": "3.0.3",
@@ -65,7 +66,7 @@
"jquery-i18next": "1.2.1",
"js-md5": "0.6.1",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#8aa35dae401f32a7eafe2b7dec159827c4bb2a84",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#55a03ac1b52f85dcbd9bfe339690ad88436ac029",
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"lodash": "4.17.21",
"moment": "2.29.1",
@@ -4097,6 +4098,15 @@
"node": ">=8"
}
},
"node_modules/@react-native-community/clipboard": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@react-native-community/clipboard/-/clipboard-1.5.1.tgz",
"integrity": "sha512-AHAmrkLEH5UtPaDiRqoULERHh3oNv7Dgs0bTC0hO5Z2GdNokAMPT5w8ci8aMcRemcwbtdHjxChgtjbeA38GBdA==",
"peerDependencies": {
"react": ">=16.0",
"react-native": ">=0.57.0"
}
},
"node_modules/@react-native-community/google-signin": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/google-signin/-/google-signin-3.0.1.tgz",
@@ -12509,8 +12519,8 @@
},
"node_modules/lib-jitsi-meet": {
"version": "0.0.0",
"resolved": "git+ssh://git@github.com/jitsi/lib-jitsi-meet.git#8aa35dae401f32a7eafe2b7dec159827c4bb2a84",
"integrity": "sha512-i2cP4DaCj4sdf4dFDQTO3FO+Ds6/JgiSvboHj1pBS+L74767qWVhoVjDQ0LO76g+JhVoXECR9MEkr2CGgSKA8Q==",
"resolved": "git+ssh://git@github.com/jitsi/lib-jitsi-meet.git#55a03ac1b52f85dcbd9bfe339690ad88436ac029",
"integrity": "sha512-0ZNhG4ZPzcH+2R7K5xa5tSNVK8CKrKVCGP/bjr07XtiV3pcY65OWI2mH+QzlMIMDOXqgqQtry9RHv4vmzy5pIg==",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
@@ -23388,6 +23398,11 @@
"resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-3.0.0.tgz",
"integrity": "sha512-ng6Tm537E/M42GjE4TRUxQyL8sRfClcL7bQWblOCoxPZzJ2J3bdALsjeG3vDnVCIfI/R0AeFalN9KjMt0+Z/Zg=="
},
"@react-native-community/clipboard": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@react-native-community/clipboard/-/clipboard-1.5.1.tgz",
"integrity": "sha512-AHAmrkLEH5UtPaDiRqoULERHh3oNv7Dgs0bTC0hO5Z2GdNokAMPT5w8ci8aMcRemcwbtdHjxChgtjbeA38GBdA=="
},
"@react-native-community/google-signin": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/google-signin/-/google-signin-3.0.1.tgz",
@@ -29978,9 +29993,9 @@
}
},
"lib-jitsi-meet": {
"version": "git+ssh://git@github.com/jitsi/lib-jitsi-meet.git#8aa35dae401f32a7eafe2b7dec159827c4bb2a84",
"integrity": "sha512-i2cP4DaCj4sdf4dFDQTO3FO+Ds6/JgiSvboHj1pBS+L74767qWVhoVjDQ0LO76g+JhVoXECR9MEkr2CGgSKA8Q==",
"from": "lib-jitsi-meet@github:jitsi/lib-jitsi-meet#8aa35dae401f32a7eafe2b7dec159827c4bb2a84",
"version": "git+ssh://git@github.com/jitsi/lib-jitsi-meet.git#55a03ac1b52f85dcbd9bfe339690ad88436ac029",
"integrity": "sha512-0ZNhG4ZPzcH+2R7K5xa5tSNVK8CKrKVCGP/bjr07XtiV3pcY65OWI2mH+QzlMIMDOXqgqQtry9RHv4vmzy5pIg==",
"from": "lib-jitsi-meet@github:jitsi/lib-jitsi-meet#55a03ac1b52f85dcbd9bfe339690ad88436ac029",
"requires": {
"@jitsi/js-utils": "2.0.0",
"@jitsi/logger": "2.0.0",

View File

@@ -41,6 +41,7 @@
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
"@microsoft/microsoft-graph-client": "1.1.0",
"@react-native-async-storage/async-storage": "1.15.5",
"@react-native-community/clipboard": "1.5.1",
"@react-native-community/google-signin": "3.0.1",
"@react-native-community/netinfo": "4.1.5",
"@react-native-community/slider": "3.0.3",
@@ -70,7 +71,7 @@
"jquery-i18next": "1.2.1",
"js-md5": "0.6.1",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#8aa35dae401f32a7eafe2b7dec159827c4bb2a84",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#55a03ac1b52f85dcbd9bfe339690ad88436ac029",
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"lodash": "4.17.21",
"moment": "2.29.1",

View File

@@ -23,6 +23,5 @@ export default class HangupButton extends AbstractHangupButton<Props, *> {
*/
_doHangup() {
api.executeCommand('hangup');
window.close();
}
}

View File

@@ -1,6 +1,7 @@
// @flow
import '../authentication/middleware';
import '../base/i18n/middleware';
import '../base/devices/middleware';
import '../dynamic-branding/middleware';
import '../e2ee/middleware';
@@ -16,6 +17,7 @@ import '../prejoin/middleware';
import '../remote-control/middleware';
import '../screen-share/middleware';
import '../shared-video/middleware';
import '../settings/middleware';
import '../talk-while-muted/middleware';
import '../virtual-background/middleware';
import '../facial-recognition/middleware';

View File

@@ -19,6 +19,11 @@ export type Props = {
*/
onAvatarLoadError?: Function,
/**
* Additional parameters to be passed to onAvatarLoadError function.
*/
onAvatarLoadErrorParams?: Object,
/**
* Expected size of the avatar.
*/

View File

@@ -4,12 +4,17 @@ import React, { PureComponent } from 'react';
import { getParticipantById } from '../../participants';
import { connect } from '../../redux';
import { getAvatarColor, getInitials } from '../functions';
import { getAvatarColor, getInitials, isCORSAvatarURL } from '../functions';
import { StatelessAvatar } from '.';
export type Props = {
/**
* The URL patterns for URLs that needs to be handled with CORS.
*/
_corsAvatarURLs: Array<string>,
/**
* Custom avatar backgrounds from branding.
*/
@@ -25,6 +30,11 @@ export type Props = {
*/
_loadableAvatarUrl: ?string,
/**
* Indicates whether _loadableAvatarUrl should use CORS or not.
*/
_loadableAvatarUrlUseCORS: ?boolean,
/**
* A prop to maintain compatibility with web.
*/
@@ -76,10 +86,16 @@ export type Props = {
* URL of the avatar, if any.
*/
url: ?string,
/**
* Indicates whether to load the avatar using CORS or not.
*/
useCORS?: ?boolean
}
type State = {
avatarFailed: boolean
avatarFailed: boolean,
isUsingCORS: boolean
}
export const DEFAULT_SIZE = 65;
@@ -105,8 +121,15 @@ class Avatar<P: Props> extends PureComponent<P, State> {
constructor(props: P) {
super(props);
const {
_corsAvatarURLs,
url,
useCORS
} = props;
this.state = {
avatarFailed: false
avatarFailed: false,
isUsingCORS: Boolean(useCORS) || Boolean(url && isCORSAvatarURL(url, _corsAvatarURLs))
};
this._onAvatarLoadError = this._onAvatarLoadError.bind(this);
@@ -118,7 +141,9 @@ class Avatar<P: Props> extends PureComponent<P, State> {
* @inheritdoc
*/
componentDidUpdate(prevProps: P) {
if (prevProps.url !== this.props.url) {
const { _corsAvatarURLs, url } = this.props;
if (prevProps.url !== url) {
// URI changed, so we need to try to fetch it again.
// Eslint doesn't like this statement, but based on the React doc, it's safe if it's
@@ -126,7 +151,8 @@ class Avatar<P: Props> extends PureComponent<P, State> {
// eslint-disable-next-line react/no-did-update-set-state
this.setState({
avatarFailed: false
avatarFailed: false,
isUsingCORS: Boolean(this.props.useCORS) || Boolean(url && isCORSAvatarURL(url, _corsAvatarURLs))
});
}
}
@@ -141,6 +167,7 @@ class Avatar<P: Props> extends PureComponent<P, State> {
_customAvatarBackgrounds,
_initialsBase,
_loadableAvatarUrl,
_loadableAvatarUrlUseCORS,
className,
colorBase,
dynamicColor,
@@ -150,7 +177,7 @@ class Avatar<P: Props> extends PureComponent<P, State> {
testId,
url
} = this.props;
const { avatarFailed } = this.state;
const { avatarFailed, isUsingCORS } = this.state;
const avatarProps = {
className,
@@ -158,19 +185,26 @@ class Avatar<P: Props> extends PureComponent<P, State> {
id,
initials: undefined,
onAvatarLoadError: undefined,
onAvatarLoadErrorParams: undefined,
size,
status,
testId,
url: undefined
url: undefined,
useCORS: isUsingCORS
};
// _loadableAvatarUrl is validated that it can be loaded, but uri (if present) is not, so
// we still need to do a check for that. And an explicitly provided URI is higher priority than
// an avatar URL anyhow.
const effectiveURL = (!avatarFailed && url) || _loadableAvatarUrl;
const useReduxLoadableAvatarURL = avatarFailed || !url;
const effectiveURL = useReduxLoadableAvatarURL ? _loadableAvatarUrl : url;
if (effectiveURL) {
avatarProps.onAvatarLoadError = this._onAvatarLoadError;
if (useReduxLoadableAvatarURL) {
avatarProps.onAvatarLoadErrorParams = { dontRetry: true };
avatarProps.useCORS = _loadableAvatarUrlUseCORS;
}
avatarProps.url = effectiveURL;
}
@@ -195,12 +229,24 @@ class Avatar<P: Props> extends PureComponent<P, State> {
/**
* Callback to handle the error while loading of the avatar URI.
*
* @param {Object} params - An object with parameters.
* @param {boolean} params.dontRetry - If false we will retry to load the Avatar with different CORS mode.
* @returns {void}
*/
_onAvatarLoadError() {
this.setState({
avatarFailed: true
});
_onAvatarLoadError(params = {}) {
const { dontRetry = false } = params;
if (Boolean(this.props.useCORS) === this.state.isUsingCORS && !dontRetry) {
// try different mode of loading the avatar.
this.setState({
isUsingCORS: !this.state.isUsingCORS
});
} else {
// we already have tried loading the avatar with and without CORS and it failed.
this.setState({
avatarFailed: true
});
}
}
}
@@ -215,11 +261,14 @@ export function _mapStateToProps(state: Object, ownProps: Props) {
const { colorBase, displayName, participantId } = ownProps;
const _participant: ?Object = participantId && getParticipantById(state, participantId);
const _initialsBase = _participant?.name ?? displayName;
const { corsAvatarURLs } = state['features/base/config'];
return {
_customAvatarBackgrounds: state['features/dynamic-branding'].avatarBackgrounds,
_corsAvatarURLs: corsAvatarURLs,
_initialsBase,
_loadableAvatarUrl: _participant?.loadableAvatarUrl,
_loadableAvatarUrlUseCORS: _participant?.loadableAvatarUrlUseCORS,
colorBase
};
}

View File

@@ -29,6 +29,18 @@ type Props = AbstractProps & {
* props.
*/
export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
/**
* Instantiates a new {@code Component}.
*
* @inheritdoc
*/
constructor(props: Props) {
super(props);
this._onAvatarLoadError = this._onAvatarLoadError.bind(this);
}
/**
* Implements {@code Component#render}.
*
@@ -164,4 +176,22 @@ export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
style = { styles.avatarContent(size) } />
);
}
_onAvatarLoadError: () => void;
/**
* Handles avatar load errors.
*
* @returns {void}
*/
_onAvatarLoadError() {
const { onAvatarLoadError, onAvatarLoadErrorParams = {} } = this.props;
if (onAvatarLoadError) {
onAvatarLoadError({
...onAvatarLoadErrorParams,
dontRetry: true
});
}
}
}

View File

@@ -3,7 +3,6 @@
import React from 'react';
import { Icon } from '../../../icons';
import { isGravatarURL } from '../../functions';
import AbstractStatelessAvatar, { type Props as AbstractProps } from '../AbstractStatelessAvatar';
type Props = AbstractProps & {
@@ -31,7 +30,12 @@ type Props = AbstractProps & {
/**
* TestId of the element, if any.
*/
testId?: string
testId?: string,
/**
* Indicates whether to load the avatar using CORS or not.
*/
useCORS?: ?boolean
};
/**
@@ -39,13 +43,25 @@ type Props = AbstractProps & {
* props.
*/
export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
/**
* Instantiates a new {@code Component}.
*
* @inheritdoc
*/
constructor(props: Props) {
super(props);
this._onAvatarLoadError = this._onAvatarLoadError.bind(this);
}
/**
* Implements {@code Component#render}.
*
* @inheritdoc
*/
render() {
const { initials, url } = this.props;
const { initials, url, useCORS } = this.props;
if (this._isIcon(url)) {
return (
@@ -67,10 +83,10 @@ export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
<img
alt = 'avatar'
className = { this._getAvatarClassName() }
crossOrigin = { isGravatarURL(url) ? '' : undefined }
crossOrigin = { useCORS ? '' : undefined }
data-testid = { this.props.testId }
id = { this.props.id }
onError = { this.props.onAvatarLoadError }
onError = { this._onAvatarLoadError }
src = { url }
style = { this._getAvatarStyle() } />
</div>
@@ -160,4 +176,19 @@ export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
}
_isIcon: (?string | ?Object) => boolean;
_onAvatarLoadError: () => void;
/**
* Handles avatar load errors.
*
* @returns {void}
*/
_onAvatarLoadError() {
const { onAvatarLoadError, onAvatarLoadErrorParams } = this.props;
if (typeof onAvatarLoadError === 'function') {
onAvatarLoadError(onAvatarLoadErrorParams);
}
}
}

View File

@@ -3,8 +3,6 @@
import GraphemeSplitter from 'grapheme-splitter';
import _ from 'lodash';
import { GRAVATAR_BASE_URL } from './constants';
const AVATAR_COLORS = [
'#6A50D3',
'#FF9B42',
@@ -16,7 +14,7 @@ const AVATAR_COLORS = [
'#2AA076',
'#00A8B3'
];
const wordSplitRegex = (/\s+|\.+|_+|;+|-+|,+|\|+|\/+|\\+/);
const wordSplitRegex = (/\s+|\.+|_+|;+|-+|,+|\|+|\/+|\\+|"+|'+|\(+|\)+|#+|&+/);
const splitter = new GraphemeSplitter();
/**
@@ -68,17 +66,18 @@ function getFirstGraphemeUpper(word) {
export function getInitials(s: ?string) {
// We don't want to use the domain part of an email address, if it is one
const initialsBasis = _.split(s, '@')[0];
const [ firstWord, secondWord ] = initialsBasis.split(wordSplitRegex);
const [ firstWord, secondWord ] = initialsBasis.split(wordSplitRegex).filter(Boolean);
return getFirstGraphemeUpper(firstWord) + getFirstGraphemeUpper(secondWord);
}
/**
* Checks if the passed URL is pointing to the gravatar service.
* Checks if the passed URL should be loaded with CORS.
*
* @param {string} url - The URL.
* @param {Array<string>} corsURLs - The URL pattern that matches a URL that needs to be handled with CORS.
* @returns {void}
*/
export function isGravatarURL(url: string = '') {
return url.startsWith(GRAVATAR_BASE_URL);
export function isCORSAvatarURL(url: string | any = '', corsURLs: Array<string> = []) {
return corsURLs.some(pattern => url.startsWith(pattern));
}

View File

@@ -45,7 +45,7 @@ const styles = theme => {
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
maxWidth: 292,
marginRight: 16,
marginRight: theme.spacing(3),
'&.selected': {
fontWeight: 600
@@ -186,8 +186,8 @@ function CopyButton({ classes, className, displayedText, textToCopy, textOnHover
return (
<>
<div className = { `${classes.copyButton}-content` }>
{ isHovered ? textOnHover : displayedText }
<div className = { clsx(classes.content) }>
<span> { isHovered ? textOnHover : displayedText } </span>
</div>
<Icon src = { IconCopy } />
</>

View File

@@ -19,7 +19,7 @@ type Props = {
/**
* Class name for context menu. Used to overwrite default styles.
*/
className?: string,
className?: ?string,
/**
* The entity for which the context menu is displayed.
@@ -31,10 +31,15 @@ type Props = {
*/
hidden?: boolean,
/**
* Whether or not the menu is already in a drawer.
*/
inDrawer?: ?boolean,
/**
* Whether or not drawer should be open.
*/
isDrawerOpen: boolean,
isDrawerOpen?: boolean,
/**
* Target elements against which positioning calculations are made.
@@ -49,7 +54,7 @@ type Props = {
/**
* Callback for drawer close.
*/
onDrawerClose: Function,
onDrawerClose?: Function,
/**
* Callback for the mouse entering the component.
@@ -59,7 +64,7 @@ type Props = {
/**
* Callback for the mouse leaving the component.
*/
onMouseLeave: Function
onMouseLeave?: Function
};
const useStyles = makeStyles(theme => {
@@ -106,6 +111,7 @@ const ContextMenu = ({
className,
entity,
hidden,
inDrawer,
isDrawerOpen,
offsetTarget,
onClick,
@@ -147,6 +153,14 @@ const ContextMenu = ({
}
}, [ hidden ]);
if (_overflowDrawer && inDrawer) {
return (<div
className = { styles.drawer }
onClick = { onDrawerClose }>
{children}
</div>);
}
return _overflowDrawer
? <JitsiPortal>
<Drawer

View File

@@ -0,0 +1,129 @@
// @flow
import { makeStyles } from '@material-ui/styles';
import clsx from 'clsx';
import React from 'react';
import { useSelector } from 'react-redux';
import { showOverflowDrawer } from '../../../toolbox/functions.web';
import { Icon } from '../../icons';
export type Props = {
/**
* Label used for accessibility.
*/
accessibilityLabel: string,
/**
* CSS class name used for custom styles.
*/
className?: string,
/**
* Custom icon. If used, the icon prop is ignored.
* Used to allow custom children instead of just the default icons.
*/
customIcon?: React$Node,
/**
* Whether or not the action is disabled.
*/
disabled?: boolean,
/**
* Id of the action container.
*/
id?: string,
/**
* Default icon for action.
*/
icon?: Function,
/**
* Click handler.
*/
onClick?: Function,
/**
* Action text.
*/
text: string,
/**
* Class name for the text.
*/
textClassName?: string
}
const useStyles = makeStyles(theme => {
return {
contextMenuItem: {
alignItems: 'center',
cursor: 'pointer',
display: 'flex',
minHeight: '40px',
padding: '10px 16px',
boxSizing: 'border-box',
'& > *:not(:last-child)': {
marginRight: `${theme.spacing(3)}px`
},
'&:hover': {
backgroundColor: theme.palette.ui04
}
},
contextMenuItemDisabled: {
pointerEvents: 'none'
},
contextMenuItemDrawer: {
padding: '12px 16px'
},
contextMenuItemIcon: {
'& svg': {
fill: theme.palette.icon01
}
}
};
});
const ContextMenuItem = ({
accessibilityLabel,
className,
customIcon,
disabled,
id,
icon,
onClick,
text,
textClassName }: Props) => {
const styles = useStyles();
const _overflowDrawer = useSelector(showOverflowDrawer);
return (
<div
aria-label = { accessibilityLabel }
className = { clsx(styles.contextMenuItem,
_overflowDrawer && styles.contextMenuItemDrawer,
disabled && styles.contextMenuItemDisabled,
className
) }
id = { id }
key = { text }
onClick = { onClick }>
{customIcon ? customIcon
: icon && <Icon
className = { styles.contextMenuItemIcon }
size = { 20 }
src = { icon } />}
<span className = { textClassName ?? '' }>{text}</span>
</div>
);
};
export default ContextMenuItem;

View File

@@ -1,50 +1,8 @@
// @flow
import { makeStyles } from '@material-ui/core';
import clsx from 'clsx';
import React from 'react';
import { useSelector } from 'react-redux';
import { showOverflowDrawer } from '../../../toolbox/functions.web';
import { Icon } from '../../icons';
export type Action = {
/**
* Label used for accessibility.
*/
accessibilityLabel: string,
/**
* CSS class name used for custom styles.
*/
className?: string,
/**
* Custom icon. If used, the icon prop is ignored.
* Used to allow custom children instead of just the default icons.
*/
customIcon?: React$Node,
/**
* Id of the action container.
*/
id?: string,
/**
* Default icon for action.
*/
icon?: Function,
/**
* Click handler.
*/
onClick?: Function,
/**
* Action text.
*/
text: string
}
import ContextMenuItem, { type Props as Action } from './ContextMenuItem';
type Props = {
@@ -59,7 +17,6 @@ type Props = {
children?: React$Node,
};
const useStyles = makeStyles(theme => {
return {
contextMenuItemGroup: {
@@ -70,33 +27,6 @@ const useStyles = makeStyles(theme => {
'& + &:not(:empty)': {
borderTop: `1px solid ${theme.palette.ui04}`
}
},
contextMenuItem: {
alignItems: 'center',
cursor: 'pointer',
display: 'flex',
minHeight: '40px',
padding: '10px 16px',
boxSizing: 'border-box',
'& > *:not(:last-child)': {
marginRight: `${theme.spacing(3)}px`
},
'&:hover': {
backgroundColor: theme.palette.ui04
}
},
contextMenuItemDrawer: {
padding: '12px 16px'
},
contextMenuItemIcon: {
'& svg': {
fill: theme.palette.icon01
}
}
};
});
@@ -106,28 +36,14 @@ const ContextMenuItemGroup = ({
children
}: Props) => {
const styles = useStyles();
const _overflowDrawer = useSelector(showOverflowDrawer);
return (
<div className = { styles.contextMenuItemGroup }>
{children}
{actions && actions.map(({ accessibilityLabel, className, customIcon, id, icon, onClick, text }) => (
<div
aria-label = { accessibilityLabel }
className = { clsx(styles.contextMenuItem,
_overflowDrawer && styles.contextMenuItemDrawer,
className
) }
id = { id }
key = { text }
onClick = { onClick }>
{customIcon ? customIcon
: icon && <Icon
className = { styles.contextMenuItemIcon }
size = { 20 }
src = { icon } />}
<span>{text}</span>
</div>
{actions && actions.map(actionProps => (
<ContextMenuItem
key = { actionProps.text }
{ ...actionProps } />
))}
</div>
);

View File

@@ -43,6 +43,16 @@ export const CONFERENCE_JOINED = 'CONFERENCE_JOINED';
export const CONFERENCE_LEFT = 'CONFERENCE_LEFT';
/**
* The type of (redux) action, which indicates conference local subject changes.
*
* {
* type: CONFERENCE_LOCAL_SUBJECT_CHANGED
* subject: string
* }
*/
export const CONFERENCE_LOCAL_SUBJECT_CHANGED = 'CONFERENCE_LOCAL_SUBJECT_CHANGED';
/**
* The type of (redux) action, which indicates conference subject changes.
*
* {

View File

@@ -41,6 +41,7 @@ import {
CONFERENCE_FAILED,
CONFERENCE_JOINED,
CONFERENCE_LEFT,
CONFERENCE_LOCAL_SUBJECT_CHANGED,
CONFERENCE_SUBJECT_CHANGED,
CONFERENCE_TIMESTAMP_CHANGED,
CONFERENCE_UNIQUE_ID_SET,
@@ -670,15 +671,17 @@ export function setFollowMe(enabled: boolean) {
* Enables or disables the Mute reaction sounds feature.
*
* @param {boolean} muted - Whether or not reaction sounds should be muted for all participants.
* @param {boolean} updateBackend - Whether or not the moderator should notify all participants for the new setting.
* @returns {{
* type: SET_START_REACTIONS_MUTED,
* muted: boolean
* }}
*/
export function setStartReactionsMuted(muted: boolean) {
export function setStartReactionsMuted(muted: boolean, updateBackend: boolean = false) {
return {
type: SET_START_REACTIONS_MUTED,
muted
muted,
updateBackend
};
}
@@ -790,7 +793,7 @@ export function setStartMutedPolicy(
}
/**
* Changing conference subject.
* Sets the conference subject.
*
* @param {string} subject - The new subject.
* @returns {void}
@@ -809,3 +812,19 @@ export function setSubject(subject: string) {
}
};
}
/**
* Sets the conference local subject.
*
* @param {string} localSubject - The new local subject.
* @returns {{
* type: CONFERENCE_LOCAL_SUBJECT_CHANGED,
* localSubject: string
* }}
*/
export function setLocalSubject(localSubject: string) {
return {
type: CONFERENCE_LOCAL_SUBJECT_CHANGED,
localSubject
};
}

View File

@@ -180,9 +180,9 @@ export function getConferenceName(stateful: Function | Object): string {
const state = toState(stateful);
const { callee } = state['features/base/jwt'];
const { callDisplayName } = state['features/base/config'];
const { pendingSubjectChange, room, subject } = getConferenceState(state);
const { localSubject, room, subject } = getConferenceState(state);
return pendingSubjectChange
return localSubject
|| subject
|| callDisplayName
|| (callee && callee.name)

View File

@@ -39,6 +39,7 @@ import {
conferenceFailed,
conferenceWillLeave,
createConference,
setLocalSubject,
setSubject
} from './actions';
import { TRIGGER_READY_TO_CLOSE_REASONS } from './constants';
@@ -484,11 +485,12 @@ function _sendTones({ getState }, next, action) {
*/
function _setRoom({ dispatch, getState }, next, action) {
const state = getState();
const { subject } = state['features/base/config'];
const { localSubject, subject } = state['features/base/config'];
const { room } = action;
if (room) {
// Set the stored subject.
dispatch(setLocalSubject(localSubject));
dispatch(setSubject(subject));
}

View File

@@ -10,6 +10,7 @@ import {
CONFERENCE_FAILED,
CONFERENCE_JOINED,
CONFERENCE_LEFT,
CONFERENCE_LOCAL_SUBJECT_CHANGED,
CONFERENCE_SUBJECT_CHANGED,
CONFERENCE_TIMESTAMP_CHANGED,
CONFERENCE_WILL_JOIN,
@@ -56,6 +57,9 @@ ReducerRegistry.register(
case CONFERENCE_SUBJECT_CHANGED:
return set(state, 'subject', action.subject);
case CONFERENCE_LOCAL_SUBJECT_CHANGED:
return set(state, 'localSubject', action.localSubject);
case CONFERENCE_TIMESTAMP_CHANGED:
return set(state, 'conferenceTimestamp', action.conferenceTimestamp);

View File

@@ -108,12 +108,14 @@ export default [
'disablePolls',
'disableProfile',
'disableReactions',
'disableReactionsModeration',
'disableRecordAudioNotification',
'disableRemoteControl',
'disableRemoteMute',
'disableResponsiveTiles',
'disableRtx',
'disableSelfView',
'disableSelfViewSettings',
'disableScreensharingVirtualBackground',
'disableShortcuts',
'disableShowMoreStats',
@@ -160,11 +162,13 @@ export default [
'googleApiApplicationClientID',
'hiddenPremeetingButtons',
'hideConferenceSubject',
'hideDisplayName',
'hideRecordingLabel',
'hideParticipantsStats',
'hideConferenceTimer',
'hiddenDomain',
'hideAddRoomButton',
'hideEmailInSettings',
'hideLobbyButton',
'hosts',
'iAmRecorder',
@@ -174,6 +178,7 @@ export default [
'inviteAppName',
'liveStreamingEnabled',
'localRecording',
'localSubject',
'maxFullResolutionParticipants',
'mouseMoveCallbackInterval',
'notifications',

View File

@@ -56,3 +56,14 @@ export const PREMEETING_BUTTONS = [ 'microphone', 'camera', 'select-background',
* The toolbar buttons to show on 3rdParty prejoin screen.
*/
export const THIRD_PARTY_PREJOIN_BUTTONS = [ 'microphone', 'camera', 'select-background' ];
/**
* The set of feature flags.
*
* @enum {string}
*/
export const FEATURE_FLAGS = {
SOURCE_NAME_SIGNALING: 'sourceNameSignaling'
};

View File

@@ -7,7 +7,7 @@ import _ from 'lodash';
import { parseURLParams } from '../util';
import CONFIG_WHITELIST from './configWhitelist';
import { _CONFIG_STORE_PREFIX } from './constants';
import { _CONFIG_STORE_PREFIX, FEATURE_FLAGS } from './constants';
import INTERFACE_CONFIG_WHITELIST from './interfaceConfigWhitelist';
import logger from './logger';
@@ -49,6 +49,29 @@ export function getMeetingRegion(state: Object) {
return state['features/base/config']?.deploymentInfo?.region || '';
}
/**
* Selector used to get the sourceNameSignaling feature flag.
*
* @param {Object} state - The global state.
* @returns {boolean}
*/
export function getSourceNameSignalingFeatureFlag(state: Object) {
return getFeatureFlag(state, FEATURE_FLAGS.SOURCE_NAME_SIGNALING);
}
/**
* Selector used to get a feature flag.
*
* @param {Object} state - The global state.
* @param {string} featureFlag - The name of the feature flag.
* @returns {boolean}
*/
export function getFeatureFlag(state: Object, featureFlag: string) {
const featureFlags = state['features/base/config']?.flags || {};
return Boolean(featureFlags[featureFlag]);
}
/**
* Selector used to get the disableRemoveRaisedHandOnFocus.
*

View File

@@ -1,4 +1,5 @@
export * from './actions';
export * from './actionTypes';
export { default as CONFIG_WHITELIST } from './configWhitelist';
export * from './constants';
export * from './functions';

View File

@@ -125,12 +125,6 @@ function _setConfig({ dispatch, getState }, next, action) {
}));
}
if (action.config.disableSelfView) {
dispatch(updateSettings({
disableSelfView: true
}));
}
dispatch(updateConfig(config));
// FIXME On Web we rely on the global 'config' variable which gets altered

View File

@@ -0,0 +1,11 @@
// @flow
/**
* The type of (redux) action which signals that i18next has been initialized.
*/
export const I18NEXT_INITIALIZED = 'I18NEXT_INITIALIZED';
/**
* The type of (redux) action which signals that language has been changed.
*/
export const LANGUAGE_CHANGED = 'LANGUAGE_CHANGED';

View File

@@ -1,6 +1,24 @@
// @flow
import React from 'react';
import { withTranslation } from 'react-i18next';
import i18next from './i18next';
/**
* Changes the main translation bundle.
*
* @param {string} language - The language e.g. 'en', 'fr'.
* @param {string} url - The url of the translation bundle.
* @returns {void}
*/
export async function changeLanguageBundle(language: string, url: string) {
const res = await fetch(url);
const bundle = await res.json();
i18next.addResourceBundle(language, 'main', bundle, true, true);
}
/**
* Wraps a specific React Component in order to enable translations in it.
*
@@ -8,7 +26,7 @@ import { withTranslation } from 'react-i18next';
* @returns {Component} The React Component which wraps {@link component} and
* enables translations in it.
*/
export function translate(component) {
export function translate(component: any) {
// Use the default list of namespaces.
return withTranslation([ 'main', 'languages', 'countries' ])(component);
}
@@ -23,7 +41,7 @@ export function translate(component) {
* @returns {ReactElement} A ReactElement which depicts the translated HTML
* text.
*/
export function translateToHTML(t, key, options = {}) {
export function translateToHTML(t: Function, key: string, options: Object = {}) {
// eslint-disable-next-line react/no-danger
return <span dangerouslySetInnerHTML = {{ __html: t(key, options) }} />;
}

View File

@@ -1,5 +1,7 @@
// @flow
declare var APP: Object;
import COUNTRIES_RESOURCES from 'i18n-iso-countries/langs/en.json';
import i18next from 'i18next';
import I18nextXHRBackend from 'i18next-xhr-backend';
@@ -7,6 +9,7 @@ import I18nextXHRBackend from 'i18next-xhr-backend';
import LANGUAGES_RESOURCES from '../../../../lang/languages.json';
import MAIN_RESOURCES from '../../../../lang/main.json';
import { I18NEXT_INITIALIZED, LANGUAGE_CHANGED } from './actionTypes';
import languageDetector from './languageDetector';
/**
@@ -46,6 +49,8 @@ const options = {
load: 'languageOnly',
ns: [ 'main', 'languages', 'countries' ],
react: {
// re-render when a new resource bundle is added
bindI18nStore: 'added',
useSuspense: false
},
returnEmptyString: false,
@@ -87,4 +92,15 @@ i18next.addResourceBundle(
// since i18next is not yet initialized at that point.
require('./BuiltinLanguages');
// Label change through dynamic branding is available only for web
if (typeof APP !== 'undefined') {
i18next.on('initialized', () => {
APP.store.dispatch({ type: I18NEXT_INITIALIZED });
});
i18next.on('languageChanged', () => {
APP.store.dispatch({ type: LANGUAGE_CHANGED });
});
}
export default i18next;

View File

@@ -0,0 +1,5 @@
// @flow
import { getLogger } from '../logging/functions';
export default getLogger('features/base/i18n');

View File

@@ -0,0 +1,39 @@
// @flow
import { SET_DYNAMIC_BRANDING_DATA } from '../../dynamic-branding/actionTypes';
import { MiddlewareRegistry } from '../redux';
import { I18NEXT_INITIALIZED, LANGUAGE_CHANGED } from './actionTypes';
import { changeLanguageBundle } from './functions';
import i18next from './i18next';
import logger from './logger';
/**
* Implements the entry point of the middleware of the feature base/i18n.
*
* @param {Store} store - The redux store.
* @returns {Function}
*/
MiddlewareRegistry.register(store => next => async action => {
switch (action.type) {
case I18NEXT_INITIALIZED:
case LANGUAGE_CHANGED:
case SET_DYNAMIC_BRANDING_DATA: {
const { language } = i18next;
const { labels } = action.type === SET_DYNAMIC_BRANDING_DATA
? action.value
: store.getState()['features/dynamic-branding'];
if (language && labels && labels[language]) {
try {
await changeLanguageBundle(language, labels[language]);
} catch (err) {
logger.log('Error setting dynamic language bundle', err);
}
}
break;
}
}
return next(action);
});

View File

@@ -15,7 +15,7 @@ type Props = {
/**
* Color of the icon (if not provided by the style object).
*/
color?: string,
color?: ?string,
/**
* Id prop (mainly for autotests).
@@ -35,7 +35,7 @@ type Props = {
/**
* The size of the icon (if not provided by the style object).
*/
size?: number | string,
size?: ?number | string,
/**
* The preloaded icon component to render.

View File

@@ -1,3 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14 4C14 4.85739 13.4605 5.58876 12.7024 5.87317L14.2286 9.94296L14.9455 11.8546C15.0074 11.9292 15.0708 11.9292 15.1098 11.8902L16.5535 10.4465L18.5858 8.41421C18.2239 8.05228 18 7.55228 18 7C18 5.89543 18.8954 5 20 5C21.1046 5 22 5.89543 22 7C22 8.10457 21.1046 9 20 9C19.9441 9 19.8887 8.9977 19.8339 8.9932L19 19C19 20.1046 18.1046 21 17 21H7C5.89543 21 5 20.1046 5 19L4.1661 8.9932C4.11133 8.9977 4.05593 9 4 9C2.89543 9 2 8.10457 2 7C2 5.89543 2.89543 5 4 5C5.10457 5 6 5.89543 6 7C6 7.55228 5.77614 8.05228 5.41421 8.41421L7.44654 10.4465L8.89019 11.8902C8.9775 11.9325 9.03514 11.9063 9.05453 11.8546L9.77139 9.94296L11.2976 5.87317C10.5395 5.58876 10 4.85739 10 4C10 2.89543 10.8954 2 12 2C13.1046 2 14 2.89543 14 4ZM6.84027 17L6.44651 12.2749L7.47597 13.3044C7.68795 13.5164 7.94285 13.6805 8.22354 13.7858C9.30949 14.193 10.52 13.6428 10.9272 12.5568L12 9.696L13.0728 12.5568C13.1781 12.8375 13.3422 13.0924 13.5542 13.3044C14.3743 14.1245 15.7039 14.1245 16.524 13.3044L17.5535 12.2749L17.1597 17H6.84027Z"/>
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.75 2.5C8.75 3.03587 8.41281 3.49298 7.93902 3.67073L8.89288 6.21435L9.34092 7.40912C9.37965 7.45577 9.41923 7.45577 9.44363 7.43137L10.3459 6.52909L11.6161 5.25888C11.3899 5.03268 11.25 4.72018 11.25 4.375C11.25 3.68464 11.8096 3.125 12.5 3.125C13.1904 3.125 13.75 3.68464 13.75 4.375C13.75 5.06536 13.1904 5.625 12.5 5.625C12.465 5.625 12.4304 5.62356 12.3962 5.62075L11.875 11.875C11.875 12.5654 11.3154 13.125 10.625 13.125H4.375C3.68464 13.125 3.125 12.5654 3.125 11.875L2.60381 5.62075C2.56958 5.62356 2.53496 5.625 2.5 5.625C1.80964 5.625 1.25 5.06536 1.25 4.375C1.25 3.68464 1.80964 3.125 2.5 3.125C3.19036 3.125 3.75 3.68464 3.75 4.375C3.75 4.72018 3.61009 5.03268 3.38388 5.25888L4.65409 6.52909L5.55637 7.43137C5.61094 7.45781 5.64696 7.44144 5.65908 7.40912L6.10712 6.21435L7.06098 3.67073C6.58719 3.49298 6.25 3.03587 6.25 2.5C6.25 1.80964 6.80964 1.25 7.5 1.25C8.19036 1.25 8.75 1.80964 8.75 2.5ZM4.27517 10.625L4.02907 7.67184L4.67248 8.31525C4.80497 8.44773 4.96428 8.55032 5.13971 8.6161C5.81843 8.87063 6.57497 8.52674 6.82949 7.84802L7.5 6.06L8.17051 7.84802C8.23629 8.02345 8.33888 8.18277 8.47136 8.31525C8.98392 8.82781 9.81495 8.82781 10.3275 8.31525L10.9709 7.67184L10.7248 10.625H4.27517Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,11 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6 13.078V15C6 16.3999 6.9589 17.5759 8.25572 17.907C8.25195 17.9374 8.25 17.9685 8.25 18V19.4378C6.12171 19.0807 4.5 17.2297 4.5 15C4.5 14.5858 4.16421 14.25 3.75 14.25C3.33579 14.25 3 14.5858 3 15C3 18.0597 5.29027 20.5845 8.25 20.9536V21.75C8.25 22.1642 8.58579 22.5 9 22.5C9.41421 22.5 9.75 22.1642 9.75 21.75V20.9536C10.8412 20.8175 11.8415 20.3884 12.6694 19.7475L15.1986 22.2766C15.4964 22.5744 15.9791 22.5745 16.2768 22.2768C16.5745 21.9791 16.5744 21.4964 16.2766 21.1986L13.7475 18.6694C13.7502 18.6659 13.753 18.6623 13.7557 18.6588L12.6831 17.5861C12.6805 17.5898 12.6779 17.5935 12.6753 17.5972L11.5911 16.513C11.5934 16.5091 11.5957 16.5051 11.598 16.5011L10.4566 15.3596C10.4554 15.3647 10.4541 15.3697 10.4528 15.3748L7.5 12.422V12.403L6 10.903V10.922L2.80143 7.72339C2.50364 7.4256 2.02091 7.42553 1.72322 7.72322C1.42553 8.02091 1.4256 8.50364 1.72339 8.80143L6 13.078ZM7.5 14.578V15C7.5 15.8284 8.17157 16.5 9 16.5C9.1294 16.5 9.25498 16.4836 9.37476 16.4528L7.5 14.578ZM10.513 17.5911C10.2756 17.73 10.0175 17.8372 9.74428 17.907C9.74805 17.9374 9.75 17.9685 9.75 18V19.4378C10.4295 19.3238 11.0573 19.0575 11.5972 18.6753L10.513 17.5911ZM12 14.747L10.5 13.247V10.5C10.5 9.67157 9.82843 9 9 9C8.25144 9 7.63095 9.54832 7.51827 10.2652L6.34845 9.09541C6.85223 8.14635 7.85064 7.5 9 7.5C10.6569 7.5 12 8.84315 12 10.5V14.747ZM13.3623 16.1092L14.5462 17.2932C14.8386 16.5867 15 15.8122 15 15C15 14.5858 14.6642 14.25 14.25 14.25C13.8358 14.25 13.5 14.5858 13.5 15C13.5 15.3828 13.4522 15.7544 13.3623 16.1092Z" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 4.71869V6C16 6.93329 16.6393 7.71727 17.5038 7.93797C17.5013 7.95829 17.5 7.97899 17.5 8V8.95852C16.0811 8.72048 15 7.4865 15 6C15 5.72386 14.7761 5.5 14.5 5.5C14.2239 5.5 14 5.72386 14 6C14 8.03981 15.5268 9.723 17.5 9.96905V10.5C17.5 10.7761 17.7239 11 18 11C18.2761 11 18.5 10.7761 18.5 10.5V9.96905C19.2275 9.87834 19.8943 9.59227 20.4463 9.16499L22.1324 10.8511C22.3309 11.0496 22.6527 11.0496 22.8512 10.8512C23.0496 10.6527 23.0496 10.3309 22.8511 10.1324L21.165 8.4463C21.1668 8.44393 21.1687 8.44155 21.1705 8.43918L20.4554 7.7241C20.4537 7.72656 20.4519 7.72903 20.4502 7.73149L19.7274 7.00869C19.7289 7.00603 19.7305 7.00338 19.732 7.00072L18.9711 6.23977C18.9702 6.24313 18.9694 6.24649 18.9685 6.24984L17 4.28131V4.26869L16 3.26869V3.28131L13.8676 1.14893C13.6691 0.950402 13.3473 0.950351 13.1488 1.14881C12.9504 1.34727 12.9504 1.6691 13.1489 1.86762L16 4.71869ZM17 5.71869V6C17 6.55228 17.4477 7 18 7C18.0863 7 18.17 6.98908 18.2498 6.96854L17 5.71869ZM19.0087 7.72738C18.8504 7.81999 18.6783 7.89148 18.4962 7.93797C18.4987 7.95829 18.5 7.97899 18.5 8V8.95852C18.953 8.88252 19.3715 8.70502 19.7315 8.45019L19.0087 7.72738ZM20 5.83131L19 4.83131V3C19 2.44772 18.5523 2 18 2C17.501 2 17.0873 2.36555 17.0122 2.84348L16.2323 2.06361C16.5682 1.4309 17.2338 1 18 1C19.1046 1 20 1.89543 20 3V5.83131ZM20.9082 6.73948L21.6975 7.52877C21.8924 7.05778 22 6.54145 22 6C22 5.72386 21.7761 5.5 21.5 5.5C21.2239 5.5 21 5.72386 21 6C21 6.25519 20.9681 6.50294 20.9082 6.73948Z" />
</g>
<defs>
<clipPath id="clip0">
<rect width="24" height="24"/>
</clipPath>
</defs>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 10.8984V12.5C5 13.6666 5.79908 14.6466 6.87977 14.9225C6.87662 14.9479 6.875 14.9737 6.875 15V16.1982C5.10143 15.9006 3.75 14.3581 3.75 12.5C3.75 12.1548 3.47018 11.875 3.125 11.875C2.77982 11.875 2.5 12.1548 2.5 12.5C2.5 15.0498 4.40856 17.1538 6.875 17.4613V18.125C6.875 18.4702 7.15482 18.75 7.5 18.75C7.84518 18.75 8.125 18.4702 8.125 18.125V17.4613C9.03436 17.3479 9.86788 16.9903 10.5579 16.4562L12.6655 18.5638C12.9136 18.812 13.3159 18.8121 13.564 18.564C13.8121 18.3159 13.812 17.9136 13.5638 17.6655L11.4562 15.5579C11.4585 15.5549 11.4608 15.5519 11.4631 15.549L10.5693 14.6551C10.5671 14.6582 10.5649 14.6613 10.5627 14.6644L9.65923 13.7609C9.66117 13.7575 9.6631 13.7542 9.66503 13.7509L8.71384 12.7997C8.7128 12.8039 8.71175 12.8081 8.71067 12.8123L6.25 10.3516V10.3359L5 9.08587V9.10163L2.33453 6.43616C2.08637 6.188 1.68409 6.18794 1.43602 6.43602C1.18794 6.68409 1.188 7.08637 1.43616 7.33453L5 10.8984ZM6.25 12.1484V12.5C6.25 13.1904 6.80964 13.75 7.5 13.75C7.60783 13.75 7.71248 13.7363 7.8123 13.7107L6.25 12.1484ZM8.76086 14.6592C8.56304 14.775 8.34788 14.8643 8.12023 14.9225C8.12338 14.9479 8.125 14.9737 8.125 15V16.1982C8.69123 16.1032 9.21443 15.8813 9.66436 15.5627L8.76086 14.6592ZM10 12.2891L8.75 11.0391V8.75C8.75 8.05964 8.19036 7.5 7.5 7.5C6.8762 7.5 6.35913 7.95693 6.26522 8.55435L5.29038 7.57951C5.71019 6.78863 6.5422 6.25 7.5 6.25C8.88071 6.25 10 7.36929 10 8.75V12.2891ZM11.1352 13.4243L12.1218 14.411C12.3655 13.8222 12.5 13.1768 12.5 12.5C12.5 12.1548 12.2202 11.875 11.875 11.875C11.5298 11.875 11.25 12.1548 11.25 12.5C11.25 12.819 11.2102 13.1287 11.1352 13.4243Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.3333 3.93224V5C13.3333 5.77774 13.8661 6.43106 14.5865 6.61497C14.5844 6.63191 14.5833 6.64916 14.5833 6.66666V7.46543C13.401 7.26706 12.5 6.23874 12.5 4.99999C12.5 4.76988 12.3135 4.58333 12.0833 4.58333C11.8532 4.58333 11.6667 4.76988 11.6667 4.99999C11.6667 6.69984 12.939 8.1025 14.5833 8.30754V8.74999C14.5833 8.98011 14.7699 9.16666 15 9.16666C15.2301 9.16666 15.4167 8.98011 15.4167 8.74999V8.30754C16.0229 8.23194 16.5786 7.99355 17.0386 7.63749L18.4437 9.04256C18.6091 9.20799 18.8773 9.20804 19.0427 9.04265C19.2081 8.87727 19.208 8.60908 19.0426 8.44364L17.6375 7.03857C17.639 7.0366 17.6406 7.03462 17.6421 7.03264L17.0462 6.43674C17.0447 6.4388 17.0433 6.44085 17.0418 6.4429L16.4395 5.84057C16.4408 5.83836 16.4421 5.83614 16.4434 5.83392L15.8092 5.1998C15.8085 5.2026 15.8078 5.2054 15.8071 5.2082L14.1667 3.56775V3.55724L13.3333 2.72391V2.73442L11.5564 0.957435C11.3909 0.791997 11.1227 0.791954 10.9574 0.957339C10.792 1.12272 10.792 1.39091 10.9574 1.55635L13.3333 3.93224ZM14.1667 4.76557V4.99999C14.1667 5.46023 14.5398 5.83333 15 5.83333C15.0719 5.83333 15.1417 5.82422 15.2082 5.80711L14.1667 4.76557ZM15.8406 6.43948C15.7087 6.51666 15.5653 6.57623 15.4135 6.61497C15.4156 6.63191 15.4167 6.64916 15.4167 6.66666V7.46543C15.7942 7.4021 16.143 7.25417 16.4429 7.04182L15.8406 6.43948ZM16.6667 4.85942L15.8333 4.02608V2.49999C15.8333 2.03976 15.4602 1.66666 15 1.66666C14.5841 1.66666 14.2394 1.97128 14.1768 2.36956L13.5269 1.71967C13.8068 1.19241 14.3615 0.833328 15 0.833328C15.9205 0.833328 16.6667 1.57952 16.6667 2.49999V4.85942ZM17.4235 5.61623L18.0812 6.27397C18.2437 5.88148 18.3333 5.45121 18.3333 4.99999C18.3333 4.76988 18.1468 4.58333 17.9167 4.58333C17.6866 4.58333 17.5 4.76988 17.5 4.99999C17.5 5.21265 17.4735 5.41911 17.4235 5.61623Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -1,3 +1,3 @@
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg width="22" height="22" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.9167 3.20834L11.9167 4.83334L11.9167 11L11.9167 11.9167C11.9167 12.4229 12.3271 12.8333 12.8333 12.8333C13.3396 12.8333 13.75 12.4229 13.75 11.9167V11V4.83334C13.75 4.73632 13.9183 4.58334 14.2083 4.58334C14.4984 4.58334 14.6667 4.73632 14.6667 4.83334L14.6667 6.875L14.6667 11.9167C14.6667 12.4229 15.0771 12.8333 15.5833 12.8333C16.0896 12.8333 16.5 12.4229 16.5 11.9167L16.5 6.875C16.5 6.62187 16.7052 6.41667 16.9583 6.41667C17.2115 6.41667 17.4167 6.62187 17.4167 6.875V13.788C17.1671 16.3395 14.9919 18.3333 12.375 18.3333C10.6569 18.3333 9.09297 17.4675 8.17032 16.0753L8.16703 16.0762L4.67206 10.8208C4.50437 10.5805 4.55476 10.2948 4.76211 10.1496C4.96947 10.0044 5.25526 10.0548 5.40045 10.2621L6.57295 12.015L6.57177 12.0158C6.85487 12.4355 7.42461 12.5463 7.84432 12.2632C8.09767 12.0923 8.23844 11.8169 8.24797 11.5332L8.25 11.5338V5.04167C8.25 4.78854 8.4552 4.58334 8.70833 4.58334C8.96124 4.58334 9.1663 4.78818 9.16667 5.041L9.16667 5.04167L9.16667 11L9.16667 11.9167C9.16667 12.4229 9.57707 12.8333 10.0833 12.8333C10.5896 12.8333 11 12.4229 11 11.9167V11V5.04167V3.20834C11 2.95521 11.2052 2.75001 11.4583 2.75001C11.7115 2.75001 11.9167 2.95521 11.9167 3.20834ZM19.2337 13.7686L19.25 13.7605V13.2917V6.875C19.25 5.60935 18.224 4.58334 16.9583 4.58334C16.7976 4.58334 16.6408 4.59988 16.4894 4.63136C16.3776 3.57554 15.399 2.75001 14.2083 2.75001C14.0384 2.75001 13.8729 2.76681 13.7135 2.7987C13.5204 1.72851 12.5842 0.916672 11.4583 0.916672C10.3309 0.916672 9.39356 1.73088 9.20233 2.80339C9.04323 2.76843 8.87793 2.75001 8.70833 2.75001C7.44268 2.75001 6.41667 3.77602 6.41667 5.04167V8.70352C5.64445 8.11321 4.54919 8.06056 3.71056 8.64778C2.67379 9.37373 2.42183 10.8027 3.14778 11.8395L6.44893 16.7791C7.64459 18.8065 9.85095 20.1667 12.375 20.1667C16.0117 20.1667 18.9888 17.3431 19.2337 13.7686Z" />
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

4
react/features/base/icons/svg/share-desktop.svg Executable file → Normal file
View File

@@ -1,3 +1,3 @@
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.66671 2.75H18.3334C19.3459 2.75 20.1667 3.57081 20.1667 4.58333V15.5833C20.1667 16.5959 19.3459 17.4167 18.3334 17.4167H15.5834C16.0896 17.4167 16.5 17.8271 16.5 18.3333C16.5 18.8396 16.0896 19.25 15.5834 19.25H6.41671C5.91045 19.25 5.50004 18.8396 5.50004 18.3333C5.50004 17.8271 5.91045 17.4167 6.41671 17.4167H3.66671C2.65419 17.4167 1.83337 16.5959 1.83337 15.5833V4.58333C1.83337 3.57081 2.65419 2.75 3.66671 2.75ZM3.66671 4.58333V15.5833H18.3334V4.58333H3.66671ZM11.9167 8.25C8.16671 8.25 6.41671 9.85417 6.41671 14.6667C8.41671 10.7708 11.9167 11 11.9167 11V12.274C11.9167 12.6941 12.4034 12.9269 12.7305 12.6633L16.017 10.0143C16.2654 9.81413 16.2654 9.43582 16.017 9.23568L12.7305 6.5867C12.4034 6.32307 11.9167 6.55589 11.9167 6.97599V8.25Z" />
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.5 1.875H12.5C13.1904 1.875 13.75 2.43464 13.75 3.125V10.625C13.75 11.3154 13.1904 11.875 12.5 11.875H10.625C10.9702 11.875 11.25 12.1548 11.25 12.5C11.25 12.8452 10.9702 13.125 10.625 13.125H4.375C4.02982 13.125 3.75 12.8452 3.75 12.5C3.75 12.1548 4.02982 11.875 4.375 11.875H2.5C1.80964 11.875 1.25 11.3154 1.25 10.625V3.125C1.25 2.43464 1.80964 1.875 2.5 1.875ZM2.5 3.125V10.625H12.5V3.125H2.5ZM8.125 5.625C5.56818 5.625 4.375 6.71875 4.375 10C5.73864 7.34375 8.125 7.5 8.125 7.5V8.03605C8.125 8.45615 8.61169 8.68897 8.93877 8.42534L10.767 6.95178C11.0153 6.75164 11.0153 6.37333 10.767 6.17319L8.93877 4.69963C8.61169 4.436 8.125 4.66882 8.125 5.08892V5.625Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 910 B

After

Width:  |  Height:  |  Size: 834 B

View File

@@ -34,6 +34,11 @@ type Props = AbstractProps & {
*/
id: string,
/**
* Color for the icon.
*/
iconColor?: string,
/**
* Click handler if any.
*/
@@ -103,6 +108,7 @@ class Label extends AbstractLabel<Props, *> {
className,
color,
icon,
iconColor,
id,
onClick,
text
@@ -120,6 +126,7 @@ class Label extends AbstractLabel<Props, *> {
id = { id }
onClick = { onClick }>
{ icon && <Icon
color = { iconColor }
size = '16'
src = { icon } /> }
{ text && <span className = { icon && classes.withIcon }>{text}</span> }

View File

@@ -13,6 +13,7 @@ import {
showWarningNotification
} from '../../notifications';
import { isForceMuted } from '../../participants-pane/functions';
import { isScreenMediaShared } from '../../screen-share/functions';
import { SET_AUDIO_ONLY, setAudioOnly } from '../audio-only';
import { isRoomValid, SET_ROOM } from '../conference';
import { getLocalParticipant } from '../participants';
@@ -114,8 +115,9 @@ MiddlewareRegistry.register(store => next => action => {
const state = store.getState();
const tracks = state['features/base/tracks'];
const isVideoMuted = isLocalTrackMuted(tracks, MEDIA_TYPE.VIDEO);
const isMediaShared = isScreenMediaShared(state);
if (blocked && isVideoMuted) {
if (blocked && isVideoMuted && !isMediaShared) {
store.dispatch(showWarningNotification({
descriptionKey: 'notify.videoUnmuteBlockedDescription',
titleKey: 'notify.videoUnmuteBlockedTitle'

View File

@@ -540,20 +540,23 @@ export function pinParticipant(id) {
*
* @param {string} participantId - The ID of the participant.
* @param {string} url - The new URL.
* @param {boolean} useCORS - Indicates whether we need to use CORS for this URL.
* @returns {{
* type: SET_LOADABLE_AVATAR_URL,
* participant: {
* id: string,
* loadableAvatarUrl: string
* loadableAvatarUrl: string,
* loadableAvatarUrlUseCORS: boolean
* }
* }}
*/
export function setLoadableAvatarUrl(participantId, url) {
export function setLoadableAvatarUrl(participantId, url, useCORS) {
return {
type: SET_LOADABLE_AVATAR_URL,
participant: {
id: participantId,
loadableAvatarUrl: url
loadableAvatarUrl: url,
loadableAvatarUrlUseCORS: useCORS
}
};
}

View File

@@ -3,7 +3,7 @@
import { getGravatarURL } from '@jitsi/js-utils/avatar';
import type { Store } from 'redux';
import { GRAVATAR_BASE_URL } from '../avatar';
import { GRAVATAR_BASE_URL, isCORSAvatarURL } from '../avatar';
import { JitsiParticipantConnectionStatus } from '../lib-jitsi-meet';
import { MEDIA_TYPE, shouldRenderVideoTrack } from '../media';
import { toState } from '../redux';
@@ -56,7 +56,7 @@ export function getFirstLoadableAvatarUrl(participant: Object, store: Store<any,
const deferred = createDeferred();
const fullPromise = deferred.promise
.then(() => _getFirstLoadableAvatarUrl(participant, store))
.then(src => {
.then(result => {
if (AVATAR_QUEUE.length) {
const next = AVATAR_QUEUE.shift();
@@ -64,7 +64,7 @@ export function getFirstLoadableAvatarUrl(participant: Object, store: Store<any,
next.resolve();
}
return src;
return result;
});
if (AVATAR_QUEUE.length) {
@@ -432,18 +432,33 @@ async function _getFirstLoadableAvatarUrl(participant, store) {
if (url !== null) {
if (AVATAR_CHECKED_URLS.has(url)) {
if (AVATAR_CHECKED_URLS.get(url)) {
return url;
const { isLoadable, isUsingCORS } = AVATAR_CHECKED_URLS.get(url) || {};
if (isLoadable) {
return {
isUsingCORS,
src: url
};
}
} else {
try {
const finalUrl = await preloadImage(url);
const { corsAvatarURLs } = store.getState()['features/base/config'];
const { isUsingCORS, src } = await preloadImage(url, isCORSAvatarURL(url, corsAvatarURLs));
AVATAR_CHECKED_URLS.set(finalUrl, true);
AVATAR_CHECKED_URLS.set(src, {
isLoadable: true,
isUsingCORS
});
return finalUrl;
return {
isUsingCORS,
src
};
} catch (e) {
AVATAR_CHECKED_URLS.set(url, false);
AVATAR_CHECKED_URLS.set(url, {
isLoadable: false,
isUsingCORS: false
});
}
}
}

View File

@@ -289,6 +289,12 @@ StateListenerRegistry.register(
})),
'raisedHand': (participant, value) =>
_raiseHandUpdated(store, conference, participant.getId(), value),
'region': (participant, value) =>
store.dispatch(participantUpdated({
conference,
id: participant.getId(),
region: value
})),
'remoteControlSessionStatus': (participant, value) =>
store.dispatch(participantUpdated({
conference,
@@ -488,8 +494,8 @@ function _participantJoinedOrUpdated(store, next, action) {
const updatedParticipant = getParticipantById(getState(), participantId);
getFirstLoadableAvatarUrl(updatedParticipant, store)
.then(url => {
dispatch(setLoadableAvatarUrl(participantId, url));
.then(urlData => {
dispatch(setLoadableAvatarUrl(participantId, urlData?.src, urlData?.isUsingCORS));
});
}
}

View File

@@ -11,12 +11,17 @@ import { isIconUrl } from './functions';
* @param {string | Object} src - Source of the avatar.
* @returns {Promise}
*/
export function preloadImage(src: string | Object): Promise<string> {
export function preloadImage(src: string | Object): Promise<Object> {
if (isIconUrl(src)) {
return Promise.resolve(src);
}
return new Promise((resolve, reject) => {
Image.prefetch(src).then(() => resolve(src), reject);
Image.prefetch(src).then(
() => resolve({
src,
isUsingCORS: false
}),
reject);
});
}

View File

@@ -1,29 +1,45 @@
// @flow
import { isGravatarURL } from '../avatar';
import { isIconUrl } from './functions';
/**
* Tries to preload an image.
*
* @param {string | Object} src - Source of the avatar.
* @param {boolean} useCORS - Whether to use CORS or not.
* @param {boolean} tryOnce - If true we try to load the image only using the specified CORS mode. Otherwise both modes
* (CORS and no CORS) will be used to load the image if the first atempt fails.
* @returns {Promise}
*/
export function preloadImage(src: string | Object): Promise<string> {
export function preloadImage(
src: string | Object,
useCORS: ?boolean = false,
tryOnce: ?boolean = false
): Promise<Object> {
if (isIconUrl(src)) {
return Promise.resolve(src);
return Promise.resolve({ src });
}
return new Promise((resolve, reject) => {
const image = document.createElement('img');
if (isGravatarURL(src)) {
if (useCORS) {
image.setAttribute('crossOrigin', '');
}
image.onload = () => resolve(src);
image.onerror = reject;
image.onload = () => resolve({
src,
isUsingCORS: useCORS
});
image.onerror = error => {
if (tryOnce) {
reject(error);
} else {
preloadImage(src, !useCORS, true)
.then(resolve)
.catch(reject);
}
};
// $FlowExpectedError
image.referrerPolicy = 'no-referrer';

View File

@@ -1,5 +1,4 @@
/* @flow */
import clsx from 'clsx';
import React, { Component } from 'react';
import { Drawer, JitsiPortal, DialogPortal } from '../../../toolbox/components/web';
@@ -60,11 +59,6 @@ type Props = {
*/
position: string,
/**
* Whether the content show have some padding.
*/
paddedContent: ?boolean,
/**
* Whether the popover is visible or not.
*/
@@ -79,7 +73,7 @@ type State = {
/**
* The style to apply to the context menu in order to position it correctly.
*/
contextMenuStyle: Object
contextMenuStyle: Object
};
/**
@@ -364,15 +358,11 @@ class Popover extends Component<Props, State> {
* @returns {ReactElement}
*/
_renderContent() {
const { content, paddedContent } = this.props;
const className = clsx(
'popover popupmenu',
paddedContent && 'padded-content'
);
const { content } = this.props;
return (
<div
className = { className }
className = 'popover'
onKeyDown = { this._onEscKey }>
{ content }
{!isMobileBrowser() && (

View File

@@ -26,6 +26,11 @@ type Props = {
*/
icon: string,
/**
* Size of icon.
*/
iconSize: ?number,
/**
* Additional style to be applied to the icon element.
*/
@@ -43,7 +48,7 @@ export default class BaseIndicator extends Component<Props> {
* @inheritdoc
*/
render() {
const { highlight, icon, iconStyle, backgroundColor } = this.props;
const { highlight, icon, iconStyle, backgroundColor, iconSize } = this.props;
const highlightedIndicator = { ...styles.highlightedIndicator };
if (backgroundColor) {
@@ -55,6 +60,7 @@ export default class BaseIndicator extends Component<Props> {
style = { [ BASE_INDICATOR,
highlight ? highlightedIndicator : null ] }>
<Icon
size = { iconSize }
src = { icon }
style = { [
styles.indicator,

View File

@@ -8,8 +8,8 @@ export default {
*/
highlightedIndicator: {
backgroundColor: ColorPalette.blue,
borderRadius: 16,
padding: 4
borderRadius: 4,
padding: 2
},
/**

View File

@@ -1,6 +1,7 @@
/* @flow */
import React, { Component } from 'react';
import { makeStyles } from '@material-ui/core';
import React from 'react';
import { translate } from '../../../i18n';
import { Icon } from '../../../icons';
@@ -12,7 +13,7 @@ import { Tooltip } from '../../../tooltip';
type Props = {
/**
* Additional CSS class names to set on the icon container.
* Additional CSS class name.
*/
className: string,
@@ -26,6 +27,11 @@ type Props = {
*/
iconClassName: string,
/**
* The color of the icon.
*/
iconColor: ?string,
/**
* Id of the icon to be rendered.
*/
@@ -59,66 +65,60 @@ type Props = {
tooltipPosition: string
};
const useStyles = makeStyles(() => {
return {
indicator: {
width: '20px',
height: '20px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}
};
});
/**
* React {@code Component} for showing an icon with a tooltip.
*
* @augments Component
* @returns {ReactElement}
*/
class BaseIndicator extends Component<Props> {
/**
* Default values for {@code BaseIndicator} component's properties.
*
* @static
*/
static defaultProps = {
className: '',
id: '',
tooltipPosition: 'top'
};
const BaseIndicator = ({
className = '',
icon,
iconClassName,
iconColor,
iconId,
iconSize,
id = '',
t,
tooltipKey,
tooltipPosition = 'top'
}: Props) => {
const styles = useStyles();
const style = {};
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const {
className,
icon,
iconClassName,
iconId,
iconSize,
id,
t,
tooltipKey,
tooltipPosition
} = this.props;
const iconContainerClassName = `indicator-icon-container ${className}`;
const style = {};
if (iconSize) {
style.fontSize = iconSize;
}
return (
<div className = 'indicator-container'>
<Tooltip
content = { t(tooltipKey) }
position = { tooltipPosition }>
<span
className = { iconContainerClassName }
id = { id }>
<Icon
className = { iconClassName }
id = { iconId }
src = { icon }
style = { style } />
</span>
</Tooltip>
</div>
);
if (iconSize) {
style.fontSize = iconSize;
}
}
return (
<div className = { styles.indicator }>
<Tooltip
content = { t(tooltipKey) }
position = { tooltipPosition }>
<span
className = { className }
id = { id }>
<Icon
className = { iconClassName }
color = { iconColor }
id = { iconId }
src = { icon }
style = { style } />
</span>
</Tooltip>
</div>
);
};
export default translate(BaseIndicator);

View File

@@ -0,0 +1,86 @@
// @flow
import React, { Component } from 'react';
import { toArray } from 'react-emoji-render';
import Linkify from './Linkify';
type Props = {
/**
* The body of the message.
*/
text: string
};
/**
* Renders the content of a chat message.
*/
class Message extends Component<Props> {
/**
* Initializes a new {@code Message} instance.
*
* @param {Props} props - The props of the component.
* @inheritdoc
*/
constructor(props: Props) {
super(props);
// Bind event handlers so they are only bound once for every instance
this._processMessage = this._processMessage.bind(this);
}
/**
* Parses and builds the message tokens to include emojis and urls.
*
* @returns {Array<string|ReactElement>}
*/
_processMessage() {
const { text } = this.props;
const message = [];
// Tokenize the text in order to avoid emoji substitution for URLs
const tokens = text ? text.split(' ') : [];
const content = [];
for (const token of tokens) {
if (token.includes('://')) {
// Bypass the emojification when urls are involved
content.push(token);
} else {
content.push(...toArray(token, { className: 'smiley' }));
}
content.push(' ');
}
content.forEach(token => {
if (typeof token === 'string' && token !== ' ') {
message.push(<Linkify key = { token }>{ token }</Linkify>);
} else {
message.push(token);
}
});
return message;
}
_processMessage: () => Array<string | React$Element<*>>;
/**
* Implements React's {@link Component#render()}.
*
* @returns {ReactElement}
*/
render() {
return (
<>
{ this._processMessage() }
</>
);
}
}
export default Message;

View File

@@ -1,5 +1,6 @@
// @flow
import { CONFIG_WHITELIST } from '../config';
import { getParticipantCount } from '../participants';
import { toState } from '../redux';
import { parseURLParams } from '../util';
@@ -256,3 +257,23 @@ export function shouldHideShareAudioHelper(state: Object): boolean {
return state['features/base/settings'].hideShareAudioHelper;
}
/**
* Whether we should hide self view.
*
* @param {Object} state - Redux state.
* @returns {boolean}
*/
export function shouldHideSelfView(state: Object) {
return getParticipantCount(state) === 1 ? false : getHideSelfView(state);
}
/**
* Gets the disable self view setting.
*
* @param {Object} state - Redux state.
* @returns {boolean}
*/
export function getHideSelfView(state: Object) {
return state['features/base/config'].disableSelfView || state['features/base/settings'].disableSelfView;
}

View File

@@ -2,6 +2,7 @@
import _ from 'lodash';
import { PREJOIN_INITIALIZED } from '../../prejoin/actionTypes';
import { setPrejoinPageVisibility } from '../../prejoin/actions';
import { APP_WILL_MOUNT } from '../app';
import { setAudioOnly } from '../audio-only';
import { SET_LOCATION_URL } from '../connection/actionTypes'; // minimize imports to avoid circular imports
@@ -29,6 +30,7 @@ MiddlewareRegistry.register(store => next => action => {
switch (action.type) {
case APP_WILL_MOUNT:
_initializeCallIntegration(store);
_initializeShowPrejoin(store);
break;
case PREJOIN_INITIALIZED: {
_maybeUpdateDisplayName(store);
@@ -48,6 +50,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 }) {
const { userSelectedSkipPrejoin } = getState()['features/base/settings'];
if (userSelectedSkipPrejoin) {
dispatch(setPrejoinPageVisibility(false));
}
}
/**
* Initializes the audio device handler based on the `disableCallIntegration` setting.
*

View File

@@ -41,6 +41,9 @@ const DEFAULT_STATE = {
userSelectedMicDeviceId: undefined,
userSelectedAudioOutputDeviceLabel: undefined,
userSelectedCameraDeviceLabel: undefined,
userSelectedNotifications: {
'notify.chatMessages': true
},
userSelectedMicDeviceLabel: undefined,
userSelectedSkipPrejoin: undefined
};

View File

@@ -23,14 +23,6 @@ export default class AbstractAudioMuteButton<P: Props, S: *>
* @returns {void}
*/
_handleClick() {
const { handleClick } = this.props;
if (handleClick) {
handleClick();
return;
}
this._setAudioMuted(!this._isAudioMuted());
}

View File

@@ -2,6 +2,7 @@
import React, { Component } from 'react';
import { NOTIFY_CLICK_MODE } from '../../../toolbox/constants';
import { combineStyles } from '../../styles';
import type { Styles } from './AbstractToolboxItem';
@@ -14,6 +15,11 @@ export type Props = {
*/
afterClick: ?Function,
/**
* The button's key.
*/
buttonKey?: string,
/**
* Extra styles which will be applied in conjunction with `styles` or
* `toggledStyles` when the button is disabled;.
@@ -25,6 +31,12 @@ export type Props = {
*/
handleClick?: Function,
/**
* Notify mode for `toolbarButtonClicked` event -
* whether to only notify or to also prevent button click routine.
*/
notifyMode?: string,
/**
* Whether to show the label or not.
*/
@@ -51,6 +63,8 @@ export type Props = {
visible: boolean
};
declare var APP: Object;
/**
* Default style for disabled buttons.
*/
@@ -134,6 +148,17 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
this._onClick = this._onClick.bind(this);
}
/**
* Helper function to be implemented by subclasses, which should be used
* to handle a key being down.
*
* @protected
* @returns {void}
*/
_onKeyDown() {
// To be implemented by subclass.
}
/**
* Helper function to be implemented by subclasses, which should be used
* to handle the button being clicked / pressed.
@@ -248,17 +273,29 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
_onClick: (*) => void;
/**
* Handles clicking / pressing the button, and toggles the audio mute state
* accordingly.
* Handles clicking / pressing the button.
*
* @param {Object} e - Event.
* @private
* @returns {void}
*/
_onClick(e) {
const { afterClick } = this.props;
const { afterClick, handleClick, notifyMode, buttonKey } = this.props;
if (typeof APP !== 'undefined' && notifyMode) {
APP.API.notifyToolbarButtonClicked(
buttonKey, notifyMode === NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY
);
}
if (notifyMode !== NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY) {
if (handleClick) {
handleClick();
}
this._handleClick();
}
this._handleClick();
afterClick && afterClick(e);
// blur after click to release focus from button to allow PTT.
@@ -288,6 +325,7 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
<ToolboxItem
disabled = { this._isDisabled() }
onClick = { this._onClick }
onKeyDown = { this._onKeyDown }
{ ...props } />
);
}

View File

@@ -22,14 +22,6 @@ export default class AbstractVideoMuteButton<P : Props, S : *>
* @returns {void}
*/
_handleClick() {
const { handleClick } = this.props;
if (handleClick) {
handleClick();
return;
}
this._setVideoMuted(!this._isVideoMuted());
}

View File

@@ -6,7 +6,15 @@ import { Icon } from '../../icons';
import { Tooltip } from '../../tooltip';
import AbstractToolboxItem from './AbstractToolboxItem';
import type { Props } from './AbstractToolboxItem';
import type { Props as AbstractToolboxItemProps } from './AbstractToolboxItem';
type Props = AbstractToolboxItemProps & {
/**
* On key down handler.
*/
onKeyDown: Function
};
/**
* Web implementation of {@code AbstractToolboxItem}.
@@ -53,6 +61,7 @@ export default class ToolboxItem extends AbstractToolboxItem<Props> {
disabled,
elementAfter,
onClick,
onKeyDown,
showLabel,
tooltipPosition,
toggled
@@ -64,6 +73,7 @@ export default class ToolboxItem extends AbstractToolboxItem<Props> {
'aria-label': this.accessibilityLabel,
className: className + (disabled ? ' disabled' : ''),
onClick: disabled ? undefined : onClick,
onKeyDown: disabled ? undefined : onKeyDown,
onKeyPress: this._onKeyPress,
tabIndex: 0,
role: showLabel ? 'menuitem' : 'button'

View File

@@ -2,11 +2,17 @@
import React from 'react';
import { NOTIFY_CLICK_MODE } from '../../../../toolbox/constants';
import { Icon } from '../../../icons';
import { Tooltip } from '../../../tooltip';
type Props = {
/**
* The button's key.
*/
buttonKey?: string,
/**
* The decorated component (ToolboxButton).
*/
@@ -22,6 +28,12 @@ type Props = {
*/
iconDisabled: boolean,
/**
* Notify mode for `toolbarButtonClicked` event -
* whether to only notify or to also prevent button click routine.
*/
notifyMode?: string,
/**
* Click handler for the small icon.
*/
@@ -68,6 +80,8 @@ type Props = {
iconId: string
};
declare var APP: Object;
/**
* Displays the `ToolboxButtonWithIcon` component.
*
@@ -80,6 +94,8 @@ export default function ToolboxButtonWithIcon(props: Props) {
icon,
iconDisabled,
iconTooltip,
buttonKey,
notifyMode,
onIconClick,
onIconKeyDown,
styles,
@@ -97,7 +113,17 @@ export default function ToolboxButtonWithIcon(props: Props) {
= 'settings-button-small-icon settings-button-small-icon--disabled';
} else {
iconProps.className = 'settings-button-small-icon';
iconProps.onClick = onIconClick;
iconProps.onClick = () => {
if (typeof APP !== 'undefined' && notifyMode) {
APP.API.notifyToolbarButtonClicked(
buttonKey, notifyMode === NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY
);
}
if (notifyMode !== NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY) {
onIconClick();
}
};
iconProps.onKeyDown = onIconKeyDown;
iconProps.role = 'button';
iconProps.tabIndex = 0;

View File

@@ -399,6 +399,26 @@ export function getTrackByMediaTypeAndParticipant(
);
}
/**
* Returns track source name of specified media type for specified participant id.
*
* @param {Track[]} tracks - List of all tracks.
* @param {MEDIA_TYPE} mediaType - Media type.
* @param {string} participantId - Participant ID.
* @returns {(string|undefined)}
*/
export function getTrackSourceNameByMediaTypeAndParticipant(
tracks,
mediaType,
participantId) {
const track = getTrackByMediaTypeAndParticipant(
tracks,
mediaType,
participantId);
return track?.jitsiTrack?.getSourceName();
}
/**
* Returns the track if any which corresponds to a specific instance
* of JitsiLocalTrack or JitsiRemoteTrack.

View File

@@ -31,6 +31,7 @@ import {
} from './actionTypes';
import {
createLocalTracksA,
destroyLocalTracks,
showNoDataFromSourceVideoError,
toggleScreensharing,
trackRemoved,
@@ -215,12 +216,16 @@ MiddlewareRegistry.register(store => next => action => {
StateListenerRegistry.register(
state => getCurrentConference(state),
(conference, { dispatch, getState }, prevConference) => {
if (prevConference && !conference) {
// conference keep flipping while we are authenticating, skip clearing while we are in that process
if (prevConference && !conference && !getState()['features/base/conference'].authRequired) {
// Clear all tracks.
const tracks = getState()['features/base/tracks'];
const remoteTracks = getState()['features/base/tracks'].filter(t => !t.local);
batch(() => {
for (const track of tracks) {
dispatch(destroyLocalTracks());
for (const track of remoteTracks) {
dispatch(trackRemoved(track.jitsiTrack));
}
});

View File

@@ -19,6 +19,7 @@ export const colors = {
primary09: '#CCDDF9',
primary10: '#17A0DB',
primary11: '#1081B2',
primary12: '#B8C7E0',
surface00: '#111111',
surface01: '#040404',
@@ -40,8 +41,7 @@ export const colors = {
success05: '#1EC26A',
warning05: '#F8AE1A',
warning06: '#ED9E1B',
warning07: '#D77976',
warning06: '#FFD600',
disabled01: '#00000040',
@@ -158,6 +158,9 @@ export const colorMap = {
// Text for drawer menu displayed name
text05: 'surface06',
// Text for saved input values
text06: 'surface03',
// error messages
textError: 'error06',
@@ -226,6 +229,8 @@ export const colorMap = {
// Line separators
border03: 'surface04',
border04: 'primary12',
// Color for error border & message
borderError: 'error06',
@@ -252,9 +257,6 @@ export const colorMap = {
// Color for indicating a raised hand
warning02: 'warning06',
// Color for insecure room
warning03: 'warning07',
// Color for disabled tab
tab01Disabled: 'disabled01',

View File

@@ -11,8 +11,18 @@ import {
createConference,
getCurrentConference
} from '../base/conference';
import { setAudioMuted, setVideoMuted } from '../base/media';
import {
MEDIA_TYPE,
setAudioMuted,
setVideoMuted
} from '../base/media';
import { getRemoteParticipants } from '../base/participants';
import {
getLocalTracks,
isLocalCameraTrackMuted,
isLocalTrackMuted
} from '../base/tracks';
import { createDesiredLocalTracks } from '../base/tracks/actions';
import {
NOTIFICATION_TIMEOUT_TYPE,
clearNotifications,
@@ -216,16 +226,26 @@ export function moveToRoom(roomId?: string) {
dispatch(createConference(_roomId));
dispatch(setAudioMuted(audio.muted));
dispatch(setVideoMuted(video.muted));
dispatch(createDesiredLocalTracks());
} else {
const localTracks = getLocalTracks(getState()['features/base/tracks']);
const isAudioMuted = isLocalTrackMuted(localTracks, MEDIA_TYPE.AUDIO);
const isVideoMuted = isLocalCameraTrackMuted(localTracks);
try {
await APP.conference.leaveRoom(false /* doDisconnect */);
// all places we fire notifyConferenceLeft we pass the room name from APP.conference
await APP.conference.leaveRoom(false /* doDisconnect */).then(
() => APP.API.notifyConferenceLeft(APP.conference.roomName));
} catch (error) {
logger.warn('APP.conference.leaveRoom() rejected with:', error);
// TODO: revisit why we don't dispatch CONFERENCE_LEFT here.
}
APP.conference.joinRoom(_roomId);
APP.conference.joinRoom(_roomId, {
startWithAudioMuted: isAudioMuted,
startWithVideoMuted: isVideoMuted
});
}
if (goToMainRoom) {

View File

@@ -62,23 +62,24 @@ const BreakoutRoomContextMenu = ({ room }: Props) => {
<Text style = { styles.contextMenuItemText }>{t('breakoutRooms.actions.join')}</Text>
</TouchableOpacity>
{!room?.isMainRoom && isLocalModerator
&& !(room?.participants && Object.keys(room.participants).length > 0)
? <TouchableOpacity
onPress = { onRemoveBreakoutRoom }
style = { styles.contextMenuItem }>
<Icon
size = { 24 }
src = { IconClose } />
<Text style = { styles.contextMenuItemText }>{t('breakoutRooms.actions.remove')}</Text>
</TouchableOpacity>
: <TouchableOpacity
onPress = { onCloseBreakoutRoom }
style = { styles.contextMenuItem }>
<Icon
size = { 24 }
src = { IconClose } />
<Text style = { styles.contextMenuItemText }>{t('breakoutRooms.actions.close')}</Text>
</TouchableOpacity>
&& (room?.participants && Object.keys(room.participants).length > 0
? <TouchableOpacity
onPress = { onCloseBreakoutRoom }
style = { styles.contextMenuItem }>
<Icon
size = { 24 }
src = { IconClose } />
<Text style = { styles.contextMenuItemText }>{t('breakoutRooms.actions.close')}</Text>
</TouchableOpacity>
: <TouchableOpacity
onPress = { onRemoveBreakoutRoom }
style = { styles.contextMenuItem }>
<Icon
size = { 24 }
src = { IconClose } />
<Text style = { styles.contextMenuItemText }>{t('breakoutRooms.actions.remove')}</Text>
</TouchableOpacity>
)
}
</BottomSheet>
);

View File

@@ -7,6 +7,7 @@ import { useDispatch } from 'react-redux';
import { openDialog } from '../../../base/dialog';
import { Icon, IconArrowDown, IconArrowUp } from '../../../base/icons';
import { participantMatchesSearch } from '../../../participants-pane/functions';
import BreakoutRoomContextMenu from './BreakoutRoomContextMenu';
import BreakoutRoomParticipantItem from './BreakoutRoomParticipantItem';
@@ -17,7 +18,12 @@ type Props = {
/**
* Room to display.
*/
room: Object
room: Object,
/**
* Participants search string.
*/
searchString: string
}
/**
@@ -31,7 +37,7 @@ function _keyExtractor(item: Object) {
}
export const CollapsibleRoom = ({ room }: Props) => {
export const CollapsibleRoom = ({ room, searchString }: Props) => {
const dispatch = useDispatch();
const [ collapsed, setCollapsed ] = useState(false);
const { t } = useTranslation();
@@ -65,7 +71,8 @@ export const CollapsibleRoom = ({ room }: Props) => {
horizontal = { false }
keyExtractor = { _keyExtractor }
// eslint-disable-next-line react/jsx-no-bind
renderItem = { item => <BreakoutRoomParticipantItem item = { item } /> }
renderItem = { ({ item: participant }) => participantMatchesSearch(participant, searchString)
&& <BreakoutRoomParticipantItem item = { participant } /> }
showsHorizontalScrollIndicator = { false }
windowSize = { 2 } />}
</View>

View File

@@ -10,6 +10,7 @@ import { ListItem } from '../../../base/components';
import { Icon, IconArrowDown, IconArrowUp } from '../../../base/icons';
import ParticipantItem from '../../../participants-pane/components/web/ParticipantItem';
import { ACTION_TRIGGER } from '../../../participants-pane/constants';
import { participantMatchesSearch } from '../../../participants-pane/functions';
type Props = {
@@ -42,6 +43,11 @@ type Props = {
* Room reference.
*/
room: Object,
/**
* Participants search string.
*/
searchString: string
}
const useStyles = makeStyles(theme => {
@@ -78,7 +84,8 @@ export const CollapsibleRoom = ({
isHighlighted,
onRaiseMenu,
onLeave,
room
room,
searchString
}: Props) => {
const { t } = useTranslation();
const styles = useStyles();
@@ -116,13 +123,14 @@ export const CollapsibleRoom = ({
textChildren = { roomName }
trigger = { actionsTrigger } />
{!collapsed && room?.participants
&& Object.values(room?.participants || {}).map((p: Object) => (
<ParticipantItem
displayName = { p.displayName || defaultRemoteDisplayName }
key = { p.jid }
local = { false }
participantID = { p.jid } />
))
&& Object.values(room?.participants || {}).map((p: Object) =>
participantMatchesSearch(p, searchString) && (
<ParticipantItem
displayName = { p.displayName || defaultRemoteDisplayName }
key = { p.jid }
local = { false }
participantID = { p.jid } />
))
}
</>
);

Some files were not shown because too many files have changed in this diff Show More