mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-01-03 05:12:27 +00:00
Compare commits
86 Commits
8511
...
pr-testing
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17e1774f6e | ||
|
|
249bd3a660 | ||
|
|
23bba927f3 | ||
|
|
7d48ea1bca | ||
|
|
a07a1cfe93 | ||
|
|
16c45c15c8 | ||
|
|
5d5d6c3068 | ||
|
|
19399ec123 | ||
|
|
3c27f15490 | ||
|
|
607073c669 | ||
|
|
f92ee57f9c | ||
|
|
32331d7465 | ||
|
|
88685c43fb | ||
|
|
348573b254 | ||
|
|
1a05991b8c | ||
|
|
c3f2390642 | ||
|
|
7cf8902fdd | ||
|
|
3e4fb82d58 | ||
|
|
057dc0e4d2 | ||
|
|
ce4cbacceb | ||
|
|
af4f122602 | ||
|
|
b7f5b8ecd2 | ||
|
|
d15e51adbd | ||
|
|
affef1ac66 | ||
|
|
7f95dbb6d6 | ||
|
|
8065da61c7 | ||
|
|
b6df08f072 | ||
|
|
73752618a3 | ||
|
|
3c7829a457 | ||
|
|
0b0bbcf194 | ||
|
|
3cd29fd63e | ||
|
|
c486dc07db | ||
|
|
b48772f898 | ||
|
|
21533f0261 | ||
|
|
1ecfa3a78e | ||
|
|
921c27165d | ||
|
|
6fa94b0bb4 | ||
|
|
3f3a074e02 | ||
|
|
ecb57774ed | ||
|
|
1e82f1fb1a | ||
|
|
b4b54108c5 | ||
|
|
6903ccf009 | ||
|
|
6e45643cce | ||
|
|
379b26a753 | ||
|
|
e8faa99ff0 | ||
|
|
62d2c9f633 | ||
|
|
311c404a1a | ||
|
|
b17a3a9d86 | ||
|
|
5477e46489 | ||
|
|
7e170fe0d0 | ||
|
|
bbbc9d1f46 | ||
|
|
084905545f | ||
|
|
d542b05bc4 | ||
|
|
58b73d8dbd | ||
|
|
471853ef15 | ||
|
|
a0070c34f7 | ||
|
|
5bc8bc8b64 | ||
|
|
ea04c5e96e | ||
|
|
d4e2f17acc | ||
|
|
4dcc4b3711 | ||
|
|
80081ce31c | ||
|
|
5314d779ed | ||
|
|
cf7c39d3e5 | ||
|
|
4e4f91f184 | ||
|
|
972a13f3fe | ||
|
|
2ec3cfcb9e | ||
|
|
a3d89ea66f | ||
|
|
487fd5de1f | ||
|
|
bed94e6698 | ||
|
|
939fdf6c8e | ||
|
|
0f5412715a | ||
|
|
dd8f2f53f3 | ||
|
|
92df4bfbbb | ||
|
|
b97798e1ca | ||
|
|
f488ef1e5c | ||
|
|
c4fcfb8666 | ||
|
|
0ccb088c05 | ||
|
|
a7f4d9cadd | ||
|
|
716c6cc567 | ||
|
|
153f67d852 | ||
|
|
8745f07052 | ||
|
|
0a467f78ee | ||
|
|
1e8cc9d085 | ||
|
|
65e7fa571a | ||
|
|
68b471ba29 | ||
|
|
c09a3524c7 |
@@ -1060,6 +1060,14 @@ export default {
|
||||
downloadJSON(logs, filename);
|
||||
},
|
||||
|
||||
/**
|
||||
* Download app state, a function that can be called from console while debugging.
|
||||
* @param filename (optional) specify target filename
|
||||
*/
|
||||
saveState(filename = 'meet-state.json') {
|
||||
downloadJSON(APP.store.getState(), filename);
|
||||
},
|
||||
|
||||
/**
|
||||
* Exposes a Command(s) API on this instance. It is necessitated by (1) the
|
||||
* desire to keep room private to this instance and (2) the need of other
|
||||
@@ -1548,7 +1556,6 @@ export default {
|
||||
}
|
||||
|
||||
APP.store.dispatch(localParticipantRoleChanged(role));
|
||||
APP.API.notifyUserRoleChanged(id, role);
|
||||
} else {
|
||||
APP.store.dispatch(participantRoleChanged(id, role));
|
||||
}
|
||||
@@ -1888,6 +1895,16 @@ export default {
|
||||
}, timeout);
|
||||
}
|
||||
);
|
||||
|
||||
room.on(JitsiConferenceEvents.PERMISSIONS_RECEIVED, p => {
|
||||
const localParticipant = getLocalParticipant(APP.store.getState());
|
||||
|
||||
APP.store.dispatch(participantUpdated({
|
||||
id: localParticipant.id,
|
||||
local: true,
|
||||
features: p
|
||||
}));
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
15
config.js
15
config.js
@@ -49,7 +49,9 @@ var config = {
|
||||
bosh: 'https://jitsi-meet.example.com/' + subdir + 'http-bind',
|
||||
|
||||
// Websocket URL (XMPP)
|
||||
// websocket: 'wss://jitsi-meet.example.com/' + subdir + 'xmpp-websocket',
|
||||
websocket: 'wss://jitsi-meet.example.com/' + subdir + 'xmpp-websocket',
|
||||
|
||||
// websocketKeepAliveUrl: 'https://jitsi-meet.example.com/' + subdir + '_unlock',
|
||||
|
||||
// Whether BOSH should be preferred over WebSocket if both are configured.
|
||||
// preferBosh: false,
|
||||
@@ -87,6 +89,9 @@ var config = {
|
||||
// Enables use of getDisplayMedia in electron
|
||||
// electronUseGetDisplayMedia: false,
|
||||
|
||||
// Enables AV1 codec for FF. Note: By default it is disabled.
|
||||
// enableAV1ForFF: false,
|
||||
|
||||
// Enables the use of the codec selection API supported by the browsers .
|
||||
// enableCodecSelectionAPI: false,
|
||||
|
||||
@@ -518,7 +523,7 @@ var config = {
|
||||
// videoQuality: {
|
||||
//
|
||||
// // Provides a way to set the codec preference on desktop based endpoints.
|
||||
// codecPreferenceOrder: [ 'VP9', 'VP8', 'H264', 'AV1' ],
|
||||
// codecPreferenceOrder: [ 'AV1', 'VP9', 'VP8', 'H264' ],
|
||||
//
|
||||
// // Provides a way to set the codec for screenshare.
|
||||
// screenshareCodec: 'AV1',
|
||||
@@ -595,7 +600,7 @@ var config = {
|
||||
// },
|
||||
//
|
||||
// // Provides a way to set the codec preference on mobile devices, both on RN and mobile browser based endpoint
|
||||
// mobileCodecPreferenceOrder: [ 'VP8', 'VP9', 'H264' ],
|
||||
// mobileCodecPreferenceOrder: [ 'VP8', 'VP9', 'H264', 'AV1' ],
|
||||
// },
|
||||
|
||||
// Notification timeouts
|
||||
@@ -1073,10 +1078,10 @@ var config = {
|
||||
|
||||
// Provides a way to set the codec preference on mobile devices, both on RN and mobile browser based
|
||||
// endpoints.
|
||||
// mobileCodecPreferenceOrder: [ 'H264', 'VP8', 'VP9' ],
|
||||
// mobileCodecPreferenceOrder: [ 'H264', 'VP8', 'VP9', 'AV1' ],
|
||||
//
|
||||
// Provides a way to set the codec preference on desktop based endpoints.
|
||||
// codecPreferenceOrder: [ 'VP9', 'VP8', 'H264 ],
|
||||
// codecPreferenceOrder: [ 'AV1', 'VP9', 'VP8', 'H264 ],
|
||||
|
||||
// Provides a way to set the codec for screenshare.
|
||||
// screenshareCodec: 'AV1',
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
text-align: center;
|
||||
|
||||
h2 {
|
||||
font-size: 48px;
|
||||
font-size: 3rem;
|
||||
color : #f2f2f2;
|
||||
}
|
||||
|
||||
&__message {
|
||||
font-size: 24px;
|
||||
font-size: 1.5rem;
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ body {
|
||||
margin: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 400;
|
||||
overflow: hidden;
|
||||
color: #F1F1F1;
|
||||
@@ -139,7 +139,7 @@ form {
|
||||
position: absolute;
|
||||
left: 25;
|
||||
bottom: 7;
|
||||
font-size: 11pt;
|
||||
font-size: 0.875rem;
|
||||
color: rgba(255,255,255,.50);
|
||||
text-decoration: none;
|
||||
z-index: $watermarkZ;
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
#chatconversation {
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
font-size: 10pt;
|
||||
font-size: 0.75rem;
|
||||
height: calc(100% - 10px);
|
||||
line-height: 20px;
|
||||
line-height: 1.25rem;
|
||||
overflow: auto;
|
||||
padding: 16px;
|
||||
text-align: left;
|
||||
@@ -72,7 +72,7 @@
|
||||
#nickname {
|
||||
text-align: center;
|
||||
color: #9d9d9d;
|
||||
font-size: 16px;
|
||||
font-size: 1rem;
|
||||
margin: auto 0;
|
||||
padding: 0 16px;
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
}
|
||||
|
||||
label {
|
||||
line-height: 24px;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
}
|
||||
|
||||
.chatmessage .usermessage {
|
||||
font-size: 16px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
}
|
||||
|
||||
#smileys {
|
||||
font-size: 20pt;
|
||||
font-size: 1.625rem;
|
||||
margin: auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -168,7 +168,7 @@
|
||||
}
|
||||
|
||||
#smileysContainer .smiley {
|
||||
font-size: 20pt;
|
||||
font-size: 1.625rem;
|
||||
}
|
||||
|
||||
.smileyContainer {
|
||||
@@ -219,8 +219,8 @@
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
|
||||
.jitsi-icon {
|
||||
cursor: pointer;
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
}
|
||||
|
||||
&__checkbox-label {
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.125rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
letter-spacing: -0.006em;
|
||||
@@ -51,8 +51,8 @@
|
||||
}
|
||||
|
||||
&__text-container {
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.125rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
letter-spacing: -0.006em;
|
||||
@@ -84,8 +84,8 @@
|
||||
|
||||
&__button-text {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 40px;
|
||||
font-size: 0.875rem;
|
||||
line-height: 2.5rem;
|
||||
text-align: center;
|
||||
letter-spacing: -0.006em;
|
||||
color: #FFFFFF;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
margin: 17px 0;
|
||||
padding-bottom: 17px;
|
||||
color: #ffffff;
|
||||
font-size: 21px;
|
||||
font-size: 1.25rem;
|
||||
letter-spacing: 0.3px;
|
||||
border-bottom: 1px solid lighten(#FFFFFF, 10%);
|
||||
}
|
||||
@@ -19,12 +19,12 @@
|
||||
color: #ffffff;
|
||||
display: block;
|
||||
margin-top: 22px;
|
||||
font-size: 16px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
margin: 0 10px;
|
||||
font-size: 50px;
|
||||
font-size: 3.125rem;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.meetings-list {
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
color: #253858;
|
||||
line-height: 20px;
|
||||
line-height: 1.25rem;
|
||||
text-align: left;
|
||||
text-overflow: ellipsis;
|
||||
display: flex;
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
.description {
|
||||
color: #2f3237;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.125rem;
|
||||
margin-bottom: 16px;
|
||||
max-width: 436px;
|
||||
}
|
||||
@@ -37,8 +37,8 @@
|
||||
color: #0163FF;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.125rem;
|
||||
margin: 24px 0 32px 0;
|
||||
}
|
||||
|
||||
@@ -101,17 +101,17 @@
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
line-height: 16px;
|
||||
line-height: 1rem;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: #5E6D7A;
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
%navigate-section-list-text {
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
color: $welcomePageTitleColor;
|
||||
text-align: left;
|
||||
font-family: 'open_sanslight', Helvetica, sans-serif;
|
||||
@@ -52,7 +52,7 @@
|
||||
.navigate-section-tile-body {
|
||||
@extend %navigate-section-list-tile-text;
|
||||
font-weight: normal;
|
||||
line-height: 24px;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
.navigate-section-list-tile-info {
|
||||
flex: 1;
|
||||
@@ -61,7 +61,7 @@
|
||||
.navigate-section-tile-title {
|
||||
@extend %navigate-section-list-tile-text;
|
||||
font-weight: bold;
|
||||
line-height: 24px;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
.navigate-section-section-header {
|
||||
@extend %navigate-section-list-text;
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
&__text {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@
|
||||
span.emoji {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 22px;
|
||||
font-size: 1.375rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
@for $i from 1 through 12 {
|
||||
&.increase-#{$i}{
|
||||
font-size: calc(20px + #{$i}px);
|
||||
font-size: calc(1.25rem + #{$i}px);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,8 +96,8 @@
|
||||
span.text {
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5rem;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
@@ -132,8 +132,8 @@ $reactionCount: 20;
|
||||
|
||||
.reaction-emoji {
|
||||
position: absolute;
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
top: 0;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
.recording-title {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
margin-left: 16px;
|
||||
max-width: 70%;
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
.local-recording-warning {
|
||||
margin-top: 8px;
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
padding: 8px 16px;
|
||||
|
||||
&.text {
|
||||
@@ -126,7 +126,7 @@
|
||||
|
||||
.recording-info-title {
|
||||
display: inline-flex;
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
width: 290px
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
/**
|
||||
* Set font-size to be consistent with Atlaskit FieldText.
|
||||
*/
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
|
||||
.broadcast-dropdown {
|
||||
text-align: left;
|
||||
@@ -194,6 +194,6 @@
|
||||
|
||||
.warning-text {
|
||||
color:#FFD740;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
width: 30%;
|
||||
margin: 20% auto;
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
font-size: 1.5rem;
|
||||
|
||||
.thanks-msg {
|
||||
border-bottom: 1px solid #FFFFFF;
|
||||
@@ -10,16 +10,16 @@
|
||||
padding-right: 30px;
|
||||
p {
|
||||
margin: 30px auto;
|
||||
font-size: 24px;
|
||||
line-height: 24px;
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
}
|
||||
.hint-msg {
|
||||
p {
|
||||
margin: 26px auto;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 18px;
|
||||
font-size: 1rem;
|
||||
line-height: 1.125rem;
|
||||
.hint-msg__holder{
|
||||
font-weight: 200;
|
||||
}
|
||||
@@ -33,7 +33,7 @@
|
||||
}
|
||||
.forbidden-msg {
|
||||
p {
|
||||
font-size: 16px;
|
||||
font-size: 1rem;
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ input[type="reset"] {
|
||||
body {
|
||||
color: #333;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.42857142857143;
|
||||
}
|
||||
/* International Font Stacks*/
|
||||
@@ -113,7 +113,7 @@ pre:first-child {
|
||||
/* Headings: desired line height in px / font size = unitless line height */
|
||||
h1 {
|
||||
color: #333;
|
||||
font-size: 32px;
|
||||
font-size: 2rem;
|
||||
font-weight: normal;
|
||||
line-height: 1.25;
|
||||
text-transform: none;
|
||||
@@ -121,7 +121,7 @@ h1 {
|
||||
}
|
||||
h2 {
|
||||
color: #333;
|
||||
font-size: 24px;
|
||||
font-size: 1.5rem;
|
||||
font-weight: normal;
|
||||
line-height: 1.25;
|
||||
text-transform: none;
|
||||
@@ -129,14 +129,14 @@ h2 {
|
||||
}
|
||||
h3 {
|
||||
color: #333;
|
||||
font-size: 20px;
|
||||
font-size: 1.25rem;
|
||||
font-weight: normal;
|
||||
line-height: 1.5;
|
||||
text-transform: none;
|
||||
margin: 30px 0 0 0;
|
||||
}
|
||||
h4 {
|
||||
font-size: 16px;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.25;
|
||||
text-transform: none;
|
||||
@@ -144,7 +144,7 @@ h4 {
|
||||
}
|
||||
h5 {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.42857143;
|
||||
text-transform: none;
|
||||
@@ -152,7 +152,7 @@ h5 {
|
||||
}
|
||||
h6 {
|
||||
color: #707070;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.66666667;
|
||||
text-transform: uppercase;
|
||||
@@ -179,7 +179,7 @@ h5 + h6 {
|
||||
/* Other typographical elements */
|
||||
small {
|
||||
color: #707070;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.33333333333333;
|
||||
}
|
||||
code,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#enter_room {
|
||||
.welcome-page-button {
|
||||
font-size: 16px;
|
||||
font-size: 1rem;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
// Do not inherit the font-family from the toolbar button, because it's an
|
||||
// icon style.
|
||||
font-family: $baseFontFamily;
|
||||
font-size: 9px;
|
||||
font-size: 0.5rem;
|
||||
font-weight: 700;
|
||||
line-height: 13px;
|
||||
line-height: 0.75rem;
|
||||
min-width: 13px;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
@@ -69,8 +69,8 @@
|
||||
|
||||
.badge-round {
|
||||
bottom: -5px;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.25rem;
|
||||
min-width: 20px;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
|
||||
@@ -50,11 +50,11 @@ $filmstripVideosZ: $toolbarZ + 1;
|
||||
$primaryUnsupportedBrowserButtonBgColor: #0052CC;
|
||||
$unsupportedBrowserButtonBgColor: rgba(9, 30, 66, 0.04);
|
||||
$unsupportedBrowserTextColor: #4a4a4a;
|
||||
$unsupportedBrowserTextSmallFontSize: 17px;
|
||||
$unsupportedBrowserTextSmallFontSize: 1rem;
|
||||
$unsupportedBrowserTitleColor: #fff;
|
||||
$unsupportedBrowserTitleFontSize: 24px;
|
||||
$unsupportedBrowserTitleFontSize: 1.5rem;
|
||||
$unsupportedDesktopBrowserTextColor: rgba(255, 255, 255, 0.7);
|
||||
$unsupportedDesktopBrowserTextFontSize: 21px;
|
||||
$unsupportedDesktopBrowserTextFontSize: 1.25rem;
|
||||
|
||||
/**
|
||||
* The size of the default watermark.
|
||||
@@ -89,7 +89,7 @@ $welcomePageHeaderContainerDisplay: flex;
|
||||
$welcomePageHeaderContainerMargin: $welcomePageHeaderContainerMarginTop auto 0;
|
||||
|
||||
$welcomePageHeaderTextTitleMarginBottom: 0;
|
||||
$welcomePageHeaderTextTitleFontSize: 42px;
|
||||
$welcomePageHeaderTextTitleFontSize: 2.625rem;
|
||||
$welcomePageHeaderTextTitleFontWeight: normal;
|
||||
$welcomePageHeaderTextTitleLineHeight: 50px;
|
||||
$welcomePageHeaderTextTitleOpacity: 1;
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
}
|
||||
|
||||
#alwaysOnTop .displayname {
|
||||
font-size: 15px;
|
||||
font-size: 0.875rem;
|
||||
position: inherit;
|
||||
width: 100%;
|
||||
left: 0px;
|
||||
@@ -294,7 +294,7 @@
|
||||
width: auto;
|
||||
z-index: $zindex2;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
text-align: center;
|
||||
color: #FFF;
|
||||
left: 50%;
|
||||
@@ -340,7 +340,7 @@
|
||||
|
||||
.presence-label {
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 100;
|
||||
left: 0;
|
||||
margin: 0 auto;
|
||||
|
||||
@@ -53,9 +53,9 @@ body.welcome-page {
|
||||
|
||||
.header-text-subtitle {
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
line-height: 26px;
|
||||
line-height: 1.625rem;
|
||||
margin: 16px 0 32px 0;
|
||||
text-align: $welcomePageHeaderTextAlign;
|
||||
|
||||
@@ -64,7 +64,7 @@ body.welcome-page {
|
||||
.not-allow-title-character-div {
|
||||
color: #f03e3e;
|
||||
background-color: #fff;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
margin: 10px 0px 5px 0px;
|
||||
text-align: $welcomePageHeaderTextAlign;
|
||||
@@ -147,7 +147,7 @@ body.welcome-page {
|
||||
display: inline-block;
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
padding-left: 10px;
|
||||
|
||||
&.focus-visible {
|
||||
@@ -172,7 +172,7 @@ body.welcome-page {
|
||||
}
|
||||
|
||||
.tab-container {
|
||||
font-size: 16px;
|
||||
font-size: 1rem;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
display: $welcomePageTabContainerDisplay;
|
||||
@@ -191,8 +191,8 @@ body.welcome-page {
|
||||
background-color: #c7ddff;
|
||||
border-radius: 6px;
|
||||
color: #0163FF;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.125rem;
|
||||
margin: 4px;
|
||||
display: $welcomePageTabButtonsDisplay;
|
||||
|
||||
@@ -218,7 +218,7 @@ body.welcome-page {
|
||||
|
||||
.welcome-page-button {
|
||||
border: 0;
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
background: $welcomePageButtonBg;
|
||||
border-radius: 3px;
|
||||
color: #FFFFFF;
|
||||
@@ -246,7 +246,7 @@ body.welcome-page {
|
||||
|
||||
* {
|
||||
cursor: pointer;
|
||||
font-size: 32px;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.toolbox-icon {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
width: 28px;
|
||||
|
||||
i {
|
||||
line-height: 28px;
|
||||
line-height: 1.75rem;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@
|
||||
padding-left: 10px;
|
||||
|
||||
i {
|
||||
line-height: 20px;
|
||||
line-height: 1.25rem;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.info-dialog {
|
||||
cursor: default;
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
|
||||
.info-dialog-column {
|
||||
margin-right: 10px;
|
||||
@@ -53,8 +53,8 @@
|
||||
max-width: 334px;
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.5rem;
|
||||
border-collapse: collapse;
|
||||
|
||||
* {
|
||||
@@ -107,7 +107,7 @@
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
max-height: 100%;
|
||||
overflow: auto;
|
||||
padding: 15pt;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
.invite-more {
|
||||
&-dialog {
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5rem;
|
||||
|
||||
&.separator {
|
||||
margin: 24px 0 24px -20px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.share-screen-warn-dialog {
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
|
||||
.separator-line {
|
||||
margin: 24px 0 24px -20px;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
.security {
|
||||
&-dialog {
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5rem;
|
||||
|
||||
&.password-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.description {
|
||||
font-size: 13px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.password {
|
||||
@@ -24,7 +24,7 @@
|
||||
button {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
color: #6FB1EA;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.lobby-screen {
|
||||
font-size: 16px;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 26px;
|
||||
line-height: 1.625rem;
|
||||
|
||||
&-content {
|
||||
align-items: center;
|
||||
@@ -43,7 +43,7 @@
|
||||
flex-direction: column;
|
||||
|
||||
.description {
|
||||
font-size: 13px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.control-row {
|
||||
@@ -53,7 +53,7 @@
|
||||
margin-top: 15px;
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
@@ -191,9 +191,9 @@
|
||||
.title {
|
||||
flex: 1;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
line-height: 28px;
|
||||
line-height: 1.75rem;
|
||||
letter-spacing: -1.2%;
|
||||
}
|
||||
}
|
||||
@@ -214,8 +214,8 @@
|
||||
border-radius: 6px;
|
||||
box-sizing: border-box;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
margin-bottom: 16px;
|
||||
margin-top: -8px;
|
||||
padding: 4px;
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
line-height: 24px;
|
||||
line-height: 1.5rem;
|
||||
margin-bottom: 16px;
|
||||
padding: 7px 16px;
|
||||
position: relative;
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
&.text {
|
||||
width: auto;
|
||||
font-size: 13px;
|
||||
font-size: 0.75rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
@@ -98,7 +98,7 @@
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
font-size: 16px;
|
||||
font-size: 1rem;
|
||||
margin-bottom: 8px;
|
||||
padding: 11px 16px;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
.reload_overlay_title {
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
font-size: 1rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
.reload_overlay_text {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
line-height: 30px;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.875rem;
|
||||
}
|
||||
|
||||
#reloadProgressBar {
|
||||
|
||||
@@ -34,12 +34,12 @@
|
||||
|
||||
&__status{
|
||||
margin-top: 15px;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
&__name {
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
font-family: Roboto, arial, sans-serif;
|
||||
font-size: 14px;
|
||||
font-size: 0.875rem;
|
||||
padding: 1px;
|
||||
|
||||
.google-cta {
|
||||
@@ -17,7 +17,7 @@
|
||||
/**
|
||||
* Hack the line height for vertical centering of text.
|
||||
*/
|
||||
line-height: 32px;
|
||||
line-height: 2rem;
|
||||
margin: 0 15px;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
.microsoft-cta {
|
||||
display: inline-block;
|
||||
color: #5E5E5E;
|
||||
font-size: 15px;
|
||||
line-height: 41px;
|
||||
font-size: 0.875rem;
|
||||
line-height: 2.5rem;
|
||||
}
|
||||
|
||||
.microsoft-logo {
|
||||
|
||||
4
debian/control
vendored
4
debian/control
vendored
@@ -34,7 +34,7 @@ Description: Configuration for web serving of Jitsi Meet
|
||||
|
||||
Package: jitsi-meet-prosody
|
||||
Architecture: all
|
||||
Depends: openssl, prosody (>= 0.11.7) | prosody-trunk | prosody-0.12 | prosody-0.11, lua-sec, lua-basexx, lua-luaossl, lua-cjson, lua-inspect
|
||||
Depends: openssl, prosody (>= 0.12.0) | prosody-trunk | prosody-0.12 | prosody-13.0, lua-sec, lua-basexx, lua-luaossl, lua-cjson, lua-inspect
|
||||
Replaces: jitsi-meet-tokens
|
||||
Description: Prosody configuration for Jitsi Meet
|
||||
Jitsi Meet is a WebRTC JavaScript application that uses Jitsi
|
||||
@@ -48,7 +48,7 @@ Description: Prosody configuration for Jitsi Meet
|
||||
|
||||
Package: jitsi-meet-tokens
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, prosody-trunk | prosody-0.11 | prosody-0.12 | prosody (>= 0.11.7), jitsi-meet-prosody
|
||||
Depends: ${misc:Depends}, prosody-trunk | prosody-0.12 | prosody-13.0 | prosody (>= 0.12.0), jitsi-meet-prosody
|
||||
Description: Prosody token authentication plugin for Jitsi Meet
|
||||
|
||||
Package: jitsi-meet-turnserver
|
||||
|
||||
@@ -15,6 +15,7 @@ external_services = {
|
||||
|
||||
cross_domain_bosh = false;
|
||||
consider_bosh_secure = true;
|
||||
consider_websocket_secure = true;
|
||||
-- https_ports = { }; -- Remove this line to prevent listening on port 5284
|
||||
|
||||
-- by default prosody 0.12 sends cors headers, if you want to disable it uncomment the following (the config is available on 0.12.1)
|
||||
@@ -38,6 +39,11 @@ unlimited_jids = {
|
||||
"jvb@auth.jitmeet.example.com"
|
||||
}
|
||||
|
||||
-- https://prosody.im/doc/modules/mod_smacks
|
||||
smacks_max_unacked_stanzas = 5;
|
||||
smacks_hibernation_time = 60;
|
||||
smacks_max_old_sessions = 1;
|
||||
|
||||
VirtualHost "jitmeet.example.com"
|
||||
authentication = "jitsi-anonymous" -- do not delete me
|
||||
-- Properties below are modified by jitsi-meet-tokens package config
|
||||
@@ -58,6 +64,8 @@ VirtualHost "jitmeet.example.com"
|
||||
-- we need bosh
|
||||
modules_enabled = {
|
||||
"bosh";
|
||||
"websocket";
|
||||
"smacks";
|
||||
"ping"; -- Enable mod_ping
|
||||
"speakerstats";
|
||||
"external_services";
|
||||
@@ -127,6 +135,13 @@ VirtualHost "auth.jitmeet.example.com"
|
||||
authentication = "internal_hashed"
|
||||
smacks_hibernation_time = 15;
|
||||
|
||||
VirtualHost "recorder.jitmeet.example.com"
|
||||
modules_enabled = {
|
||||
"smacks";
|
||||
}
|
||||
authentication = "internal_hashed"
|
||||
smacks_max_old_sessions = 2000;
|
||||
|
||||
-- Proxy to jicofo's user JID, so that it doesn't have to register as a component.
|
||||
Component "focus.jitmeet.example.com" "client_proxy"
|
||||
target_address = "focusUser@auth.jitmeet.example.com"
|
||||
|
||||
@@ -150,6 +150,12 @@ server {
|
||||
# alias /usr/share/jitsi-meet/load-test/libs/$1;
|
||||
#}
|
||||
|
||||
location = /_unlock {
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains';
|
||||
add_header "Cache-Control" "no-cache, no-store";
|
||||
}
|
||||
|
||||
location ~ ^/conference-request/v1(\/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:8888/conference-request/v1$1;
|
||||
add_header "Cache-Control" "no-cache, no-store";
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
Component: JitsiMeetJS.app.entryPoints.APP
|
||||
})
|
||||
|
||||
const inIframe = () => {
|
||||
const isEmbedded = () => {
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
@@ -45,7 +45,7 @@
|
||||
};
|
||||
|
||||
const isElectron = navigator.userAgent.includes('Electron');
|
||||
const shouldRegisterWorker = !isElectron && !inIframe() && 'serviceWorker' in navigator;
|
||||
const shouldRegisterWorker = !isElectron && !isEmbedded() && 'serviceWorker' in navigator;
|
||||
|
||||
if (shouldRegisterWorker) {
|
||||
navigator.serviceWorker
|
||||
|
||||
@@ -24,15 +24,11 @@
|
||||
}
|
||||
|
||||
+ (void)activateWithAudioSession:(AVAudioSession *)session {
|
||||
if (!self.rtcAudioSession.useManualAudio) {
|
||||
[self.rtcAudioSession audioSessionDidActivate:session];
|
||||
}
|
||||
[self.rtcAudioSession audioSessionDidActivate:session];
|
||||
}
|
||||
|
||||
+ (void)deactivateWithAudioSession:(AVAudioSession *)session {
|
||||
if (!self.rtcAudioSession.useManualAudio) {
|
||||
[self.rtcAudioSession audioSessionDidDeactivate:session];
|
||||
}
|
||||
[self.rtcAudioSession audioSessionDidDeactivate:session];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1111,7 +1111,7 @@
|
||||
"incomingMessage": "Příchozí zpráva",
|
||||
"language": "Jazyk",
|
||||
"loggedIn": "Přihlášen/a jako {{name}}",
|
||||
"maxStageParticipants": "Maximální počet účastníků, které lze připnout na hlavní pódium (EXPERIMENTÁLNÍ)",
|
||||
"maxStageParticipants": "Maximální počet účastníků, které lze připnout na hlavní pódium",
|
||||
"microphones": "Mikrofony",
|
||||
"moderator": "Moderátor",
|
||||
"moderatorOptions": "Možnosti moderátora",
|
||||
|
||||
@@ -263,6 +263,7 @@
|
||||
"Remove": "Entfernen",
|
||||
"Share": "Teilen",
|
||||
"Submit": "OK",
|
||||
"Understand": "Verstanden",
|
||||
"WaitForHostMsg": "Die Konferenz wurde noch nicht gestartet. Falls Sie die Konferenz leiten, authentifizieren Sie sich bitte. Warten Sie andernfalls, bis die Konferenz gestartet wird.",
|
||||
"WaitForHostNoAuthMsg": "Die Konferenz wurde noch nicht gestartet. Bitte warten Sie, bis die Konferenz gestartet wird.",
|
||||
"WaitingForHostButton": "Auf Moderation warten",
|
||||
@@ -393,6 +394,8 @@
|
||||
"recentlyUsedObjects": "Ihre zuletzt verwendeten Objekte",
|
||||
"recording": "Aufnahme",
|
||||
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Während eines Livestreams nicht möglich",
|
||||
"recordingInProgressDescription": "Diese Konferenz wird aufgezeichnet. Ihr Ton und Video ist deaktiviert, wenn Sie es aktivieren, stimmen Sie der Aufzeichnung zu.",
|
||||
"recordingInProgressTitle": "Aufnahme läuft",
|
||||
"rejoinNow": "Jetzt erneut beitreten",
|
||||
"remoteControlAllowedMessage": "{{user}} hat die Anfrage zur Fernsteuerung angenommen!",
|
||||
"remoteControlDeniedMessage": "{{user}} hat die Anfrage zur Fernsteuerung verweigert!",
|
||||
@@ -749,7 +752,8 @@
|
||||
"dataChannelClosedDescriptionWithAudio": "Die Steuerungsverbindung (Bridge Channel) wurde unterbrochen, daher können Video- und Tonprobleme auftreten.",
|
||||
"dataChannelClosedWithAudio": "Ton- und Videoqualität können beeinträchtigt sein",
|
||||
"disabledIframe": "Die Einbettung ist nur für Demo-Zwecke vorgesehen. Diese Konferenz wird in {{timeout}} Minuten beendet.",
|
||||
"disabledIframeSecondary": "Die Einbettung von {{domain}} ist nur für Demo-Zwecke vorgesehen. Diese Konferenz wird in {{timeout}} Minuten beendet. Bitte nutzen Sie <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi as a Service</a> für produktive Zwecke!",
|
||||
"disabledIframeSecondaryNative": "Die Einbettung von {{domain}} ist nur für Demo-Zwecke vorgesehen. Diese Konferenz wird in {{timeout}} Minuten beendet.",
|
||||
"disabledIframeSecondaryWeb": "Die Einbettung von {{domain}} ist nur für Demo-Zwecke vorgesehen. Diese Konferenz wird in {{timeout}} Minuten beendet. Bitte nutzen Sie <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi as a Service</a> für produktive Zwecke!",
|
||||
"disconnected": "getrennt",
|
||||
"displayNotifications": "Benachrichtigungen anzeigen für",
|
||||
"dontRemindMe": "Nicht erinnern",
|
||||
@@ -877,6 +881,7 @@
|
||||
"waitingLobby": "In der Lobby ({{count}})"
|
||||
},
|
||||
"search": "Suche Anwesende",
|
||||
"searchDescription": "Tippen Sie um die Anwesendenliste zu filtern",
|
||||
"title": "Anwesende"
|
||||
},
|
||||
"passwordDigitsOnly": "Bis zu {{number}} Ziffern",
|
||||
@@ -1104,6 +1109,7 @@
|
||||
"signedIn": "Momentan wird auf Kalendertermine von {{email}} zugegriffen. Klicken Sie auf die folgende Schaltfläche „Trennen“, um den Zugriff auf die Kalendertermine zu stoppen.",
|
||||
"title": "Kalender"
|
||||
},
|
||||
"chatWithPermissions": "Chat mit Freigaben",
|
||||
"desktopShareFramerate": "Framerate für Bildschirmfreigabe",
|
||||
"desktopShareHighFpsWarning": "Eine höhere Framerate könnte sich auf Ihre Datenrate auswirken. Sie müssen die Bildschirmfreigabe neustarten, damit die Einstellung übernommen wird.",
|
||||
"desktopShareWarning": "Sie müssen die Bildschirmfreigabe neustarten, damit die Einstellung übernommen wird.",
|
||||
@@ -1192,6 +1198,7 @@
|
||||
"neutral": "Neutral",
|
||||
"sad": "Traurig",
|
||||
"search": "Suche",
|
||||
"searchDescription": "Tippen Sie um die Anwesendenliste zu filtern",
|
||||
"searchHint": "Suche Anwesende",
|
||||
"seconds": "{{count}} Sek.",
|
||||
"speakerStats": "Sprechstatistik",
|
||||
@@ -1270,7 +1277,7 @@
|
||||
"muteGUMPending": "Verbinde Ihr Mikrofon",
|
||||
"noiseSuppression": "Rauschunterdrückung",
|
||||
"openChat": "Chat öffnen",
|
||||
"participants": "Anwesende",
|
||||
"participants": "Anwesenheitsliste öffnen. {{participantsCount}} anwesend",
|
||||
"pip": "Bild-in-Bild-Modus ein-/ausschalten",
|
||||
"privateMessage": "Private Nachricht senden",
|
||||
"profile": "Profil bearbeiten",
|
||||
@@ -1408,7 +1415,8 @@
|
||||
"ccButtonTooltip": "Untertitel ein-/ausschalten",
|
||||
"expandedLabel": "Transkribieren ist derzeit eingeschaltet",
|
||||
"failed": "Transkribieren fehlgeschlagen",
|
||||
"labelToolTip": "Die Konferenz wird transkribiert",
|
||||
"labelTooltip": "Die Konferenz wird transkribiert",
|
||||
"labelTooltipExtra": "Zusätzlich wird das Transkript später verfügbar sein.",
|
||||
"sourceLanguageDesc": "Aktuell ist die Sprache der Konferenz auf <b>{{sourceLanguage}}</b> eingestellt. <br/> Sie könne dies hier ",
|
||||
"sourceLanguageHere": "ändern",
|
||||
"start": "Anzeige der Untertitel starten",
|
||||
|
||||
@@ -984,7 +984,7 @@
|
||||
"incomingMessage": "Εισερχόμενο μήνυμα",
|
||||
"language": "Γλώσσα",
|
||||
"loggedIn": "Συνδέθηκε ως {{name}}",
|
||||
"maxStageParticipants": "Μέγιστος αριθμός συμμετεχόντων που μπορούν να διατηρηθούν στην κύρια σκηνή (ΠΕΙΡΑΜΑΤΙΚΟ)",
|
||||
"maxStageParticipants": "Μέγιστος αριθμός συμμετεχόντων που μπορούν να διατηρηθούν στην κύρια σκηνή",
|
||||
"microphones": "Μικρόφωνα",
|
||||
"moderator": "Συντονιστής",
|
||||
"moderatorOptions": "Επιλογές συντονιστή",
|
||||
|
||||
@@ -1070,7 +1070,7 @@
|
||||
"incomingMessage": "Envena mesaĝo",
|
||||
"language": "Lingvo",
|
||||
"loggedIn": "Ensalutinta kiels {{name}}",
|
||||
"maxStageParticipants": "Maksimuma nombro da partoprenantoj, kiuj povas esti alpinglitaj al la ĉefa scenejo (EXPERIMENTA)",
|
||||
"maxStageParticipants": "Maksimuma nombro da partoprenantoj, kiuj povas esti alpinglitaj al la ĉefa scenejo",
|
||||
"microphones": "Mikrofonoj",
|
||||
"moderator": "Kunvenestro",
|
||||
"moderatorOptions": "Kunvenestaj agordoj",
|
||||
|
||||
@@ -1026,7 +1026,7 @@
|
||||
"incomingMessage": "پیام ورودی",
|
||||
"language": "زبان",
|
||||
"loggedIn": "واردشده به عنوان {{name}}",
|
||||
"maxStageParticipants": "بیشینه تعداد شرکتکنندگانی که میتوانند به صحنه اصلی سنجاق شوند (<b>آزمایشی</b>)",
|
||||
"maxStageParticipants": "بیشینه تعداد شرکتکنندگانی که میتوانند به صحنه اصلی سنجاق شوند",
|
||||
"microphones": "میکروفونها",
|
||||
"moderator": "مدیر",
|
||||
"moderatorOptions": "گزینههای مدیر",
|
||||
|
||||
@@ -1111,7 +1111,7 @@
|
||||
"incomingMessage": "un message arrive",
|
||||
"language": "Langue",
|
||||
"loggedIn": "Connecté en tant que {{name}}",
|
||||
"maxStageParticipants": "Nombre maximum de participants pouvant être épinglé sur l’affichage principal (EXPÉRIMENTAL)",
|
||||
"maxStageParticipants": "Nombre maximum de participants pouvant être épinglé sur l’affichage principal",
|
||||
"microphones": "Microphones",
|
||||
"moderator": "Modérateur",
|
||||
"moderatorOptions": "Options de modérateur",
|
||||
|
||||
@@ -1077,7 +1077,7 @@
|
||||
"incomingMessage": "un message arrive",
|
||||
"language": "Langue",
|
||||
"loggedIn": "Connecté en tant que {{name}}",
|
||||
"maxStageParticipants": "Nombre maximum de participants pouvant être épinglé sur l’affichage principal (EXPÉRIMENTAL)",
|
||||
"maxStageParticipants": "Nombre maximum de participants pouvant être épinglé sur l’affichage principal",
|
||||
"microphones": "Microphones",
|
||||
"moderator": "Modérateur",
|
||||
"moderatorOptions": "Options de modérateur",
|
||||
|
||||
@@ -1088,7 +1088,7 @@
|
||||
"incomingMessage": "Pesan masuk",
|
||||
"language": "Bahasa",
|
||||
"loggedIn": "Masuk sebagai {{name}}",
|
||||
"maxStageParticipants": "Jumlah maksimum peserta yang dapat ditampilkan di panggung utama (PERCOBAAN)",
|
||||
"maxStageParticipants": "Jumlah maksimum peserta yang dapat ditampilkan di panggung utama",
|
||||
"microphones": "Mikrofon",
|
||||
"moderator": "Moderator",
|
||||
"moderatorOptions": "Opsi moderator",
|
||||
|
||||
@@ -1069,7 +1069,7 @@
|
||||
"incomingMessage": "Móttekin skilaboð",
|
||||
"language": "Tungumál",
|
||||
"loggedIn": "Skráð inn sem {{name}}",
|
||||
"maxStageParticipants": "Hámarksfjöldi þátttakenda sem hægt er að festa á aðalgluggann (Á TILRAUNASTIGI)",
|
||||
"maxStageParticipants": "Hámarksfjöldi þátttakenda sem hægt er að festa á aðalgluggann",
|
||||
"microphones": "Hljóðnemar",
|
||||
"moderator": "Stjórnandi",
|
||||
"moderatorOptions": "Valkostir umsjónarmanns",
|
||||
|
||||
@@ -1110,7 +1110,7 @@
|
||||
"incomingMessage": "수신 메시지",
|
||||
"language": "언어",
|
||||
"loggedIn": "{{name}}으로 로그인",
|
||||
"maxStageParticipants": "메인 스테이지에 고정할 수 있는 최대 참가자 수 (실험적 기능)",
|
||||
"maxStageParticipants": "메인 스테이지에 고정할 수 있는 최대 참가자 수",
|
||||
"microphones": "마이크",
|
||||
"moderator": "진행자",
|
||||
"moderatorOptions": "진행자 옵션",
|
||||
|
||||
@@ -263,6 +263,7 @@
|
||||
"Remove": "Noņemt",
|
||||
"Share": "Kopīgot",
|
||||
"Submit": "Iesniegt",
|
||||
"Understand": "Saprotu",
|
||||
"WaitForHostMsg": "Sapulce vēl nav sākusies, jo vēl nav ieradies neviens moderators. Lūdzu, autorizējieties, lai kļūtu par moderatoru. Pretējā gadījumā, lūdzu, uzgaidiet.",
|
||||
"WaitForHostNoAuthMsg": "Sapulce vēl nav sākusies, jo vēl nav ieradies neviens moderators. Lūdzu, uzgaidiet.",
|
||||
"WaitingForHostButton": "Gaidīt rīkotāju",
|
||||
@@ -393,6 +394,8 @@
|
||||
"recentlyUsedObjects": "Jūsu nesen izmantotie objekti",
|
||||
"recording": "Ieraksts",
|
||||
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Nav iespējams, kamēr ir aktīva tiešraides straume",
|
||||
"recordingInProgressDescription": "Šī sapulce tiek ierakstīta. Jūsu audio un video ir izslēgti. Ja izvēlaties ieslēgt skaņu vai video, jūs piekrītat ierakstīšanai.",
|
||||
"recordingInProgressTitle": "Notiek ierakstīšana",
|
||||
"rejoinNow": "Pieslēgties no jauna",
|
||||
"remoteControlAllowedMessage": "{{user}} apstiprināja jūsu attālās pārvaldības pieprasījumu!",
|
||||
"remoteControlDeniedMessage": "{{user}} noraidīja jūsu attālās pārvaldības pieprasījumu!",
|
||||
@@ -481,7 +484,7 @@
|
||||
"tokenAuthFailedTitle": "Autentifikācijas kļūda",
|
||||
"tokenAuthFailedWithReasons": "Atvainojiet, jums nav atļauts pievienoties šim zvanam. Iespējamie iemesli: {{reason}}",
|
||||
"tokenAuthUnsupported": "Token URL netiek atbalstīts.",
|
||||
"transcribing": "Notiek transkripcija",
|
||||
"transcribing": "Notiek atšifrējuma izveide",
|
||||
"unlockRoom": "Noņemt $t(lockRoomPassword)",
|
||||
"user": "Lietotājs",
|
||||
"userIdentifier": "Lietotājvārds",
|
||||
@@ -492,7 +495,7 @@
|
||||
"verifyParticipantTitle": "Lietotāja verifikācija",
|
||||
"videoLink": "Video saite",
|
||||
"viewUpgradeOptions": "Skatīt jaunināšanas iespējas",
|
||||
"viewUpgradeOptionsContent": "Lai iegūtu neierobežotu piekļuvi augstākās klases funkcijām, piemēram, ierakstīšanai, transkripcijām, RTMP straumēšanai un citām iespējām, jums ir jāpalielina plāns.",
|
||||
"viewUpgradeOptionsContent": "Lai iegūtu neierobežotu piekļuvi augstākās klases funkcijām, piemēram, ierakstīšanai, atšifrējuma izveidei, RTMP straumēšanai un citām iespējām, jums ir jāpalielina plāns.",
|
||||
"viewUpgradeOptionsTitle": "Jūs atklājāt premium funkcionalitāti!",
|
||||
"whiteboardLimitContent": "Diemžēl ir sasniegts vienlaicīgu tāfeles lietotāju ierobežojums.",
|
||||
"whiteboardLimitReference": "Lai iegūtu vairāk informācijas, lūdzu, apmeklējiet",
|
||||
@@ -733,7 +736,9 @@
|
||||
"me": "es",
|
||||
"notify": {
|
||||
"OldElectronAPPTitle": "Drošības ievainojamība!",
|
||||
"allowAction": "Atļaut",
|
||||
"allowAudio": "Atļaut audio",
|
||||
"allowBoth": "Abus",
|
||||
"allowVideo": "Atļaut video",
|
||||
"allowedUnmute": "Varat ieslēgt mikrofona skaņu, ieslēgt kameru vai kopīgot ekrānu.",
|
||||
"audioUnmuteBlockedDescription": "Mikrofona ieslēgšanas darbība ir īslaicīgi bloķēta sistēmas ierobežojumu dēļ.",
|
||||
"audioUnmuteBlockedTitle": "Mikrofona ieslēgšana ir bloķēta!",
|
||||
@@ -825,6 +830,7 @@
|
||||
"suggestRecordingDescription": "Vai vēlaties sākt ierakstīšanu?",
|
||||
"suggestRecordingTitle": "Ierakstīt sanāksmi",
|
||||
"unmute": "Ieslēgt mikrofonu",
|
||||
"unmuteVideo": "Ieslēgt video",
|
||||
"videoMutedRemotelyDescription": "Jūs vienmēr varat to atkal ieslēgt.",
|
||||
"videoMutedRemotelyTitle": "{{participantDisplayName}} izslēdza jūsu video",
|
||||
"videoUnmuteBlockedDescription": "Kameras ieslēgšanas un darbvirsmas koplietošanas darbība ir īslaicīgi bloķēta sistēmas ierobežojumu dēļ.",
|
||||
@@ -1059,7 +1065,7 @@
|
||||
"pending": "Gatavojas ierakstīt sapulci…",
|
||||
"policyError": "Jūs mēģinājāt pārāk ātri sākt ierakstīšanu. Lūdzu, vēlāk mēģiniet vēlreiz!",
|
||||
"recordAudioAndVideo": "Ierakstīt audio un video",
|
||||
"recordTranscription": "Ierakstīt transkripciju",
|
||||
"recordTranscription": "Ierakstīt atšifrējumu",
|
||||
"saveLocalRecording": "Ieraksta faila saglabāšana lokāli (beta)",
|
||||
"serviceDescription": "Jūsu ierakstu saglabās attiecīgais pakalpojums",
|
||||
"serviceDescriptionCloud": "Ierakstīšana mākonī",
|
||||
@@ -1111,7 +1117,7 @@
|
||||
"incomingMessage": "Ienākošā ziņa",
|
||||
"language": "Valoda",
|
||||
"loggedIn": "Ierakstījies kā {{name}}",
|
||||
"maxStageParticipants": "Maksimālais dalībnieku skaits, kurus var piespraust galvenajai skatuvei (EKSPERIMENTĀLS)",
|
||||
"maxStageParticipants": "Maksimālais dalībnieku skaits, kurus var piespraust galvenajai skatuvei",
|
||||
"microphones": "Mikrofoni",
|
||||
"moderator": "Moderators",
|
||||
"moderatorOptions": "Moderatora opcijas",
|
||||
@@ -1183,6 +1189,7 @@
|
||||
"fearful": "Bailīgs",
|
||||
"happy": "Priecīgs",
|
||||
"hours": "{{count}}s",
|
||||
"labelTooltip": "Dalībnieku skaits: {{count}}",
|
||||
"minutes": "{{count}}m",
|
||||
"name": "Vārds",
|
||||
"neutral": "Neitrāls",
|
||||
@@ -1402,9 +1409,10 @@
|
||||
},
|
||||
"transcribing": {
|
||||
"ccButtonTooltip": "Iesl./izsl. subtitrus",
|
||||
"expandedLabel": "Transkripcija ir ieslēgta",
|
||||
"failed": "Transkripcija neizdevās",
|
||||
"labelToolTip": "Notiek sapulces transkripcija",
|
||||
"expandedLabel": "Atšifrējuma izveide ir ieslēgta",
|
||||
"failed": "Atšifrējuma izveide neizdevās",
|
||||
"labelTooltip": "Šajā sapulcē notiek atšifrējuma izveide.",
|
||||
"labelTooltipExtra": "Turklāt vēlāk būs pieejams atšifrējums.",
|
||||
"sourceLanguageDesc": "Pašlaik sapulces valoda ir iestatīta uz <b>{{sourceLanguage}}</b>. <br/> Varat to mainīt no ",
|
||||
"sourceLanguageHere": "šeit",
|
||||
"start": "Iesl. subtitru rādīšanu",
|
||||
|
||||
@@ -997,7 +997,7 @@
|
||||
"incomingMessage": "Ирсэн мессэж",
|
||||
"language": "Хэл",
|
||||
"loggedIn": "{{name}} нэвтэрсэн",
|
||||
"maxStageParticipants": "Үндсэн тайз руу гарах оролцогчийн хамгийн их тоо(Туршилтынх)",
|
||||
"maxStageParticipants": "Үндсэн тайз руу гарах оролцогчийн хамгийн их тоо",
|
||||
"microphones": "Микрофон",
|
||||
"moderator": "Зохицуулагч",
|
||||
"moderatorOptions": "Зохицуулагчийн сонголт",
|
||||
|
||||
@@ -1111,7 +1111,7 @@
|
||||
"incomingMessage": "Innkommende melding",
|
||||
"language": "Språk",
|
||||
"loggedIn": "Logget inn som {{name}}",
|
||||
"maxStageParticipants": "Maksimalt antall deltakere som kan festes til hovedscenen (EKSPERIMENTELL)",
|
||||
"maxStageParticipants": "Maksimalt antall deltakere som kan festes til hovedscenen",
|
||||
"microphones": "Mikrofoner",
|
||||
"moderator": "Moderator",
|
||||
"moderatorOptions": "Moderatoralternativer",
|
||||
|
||||
@@ -1111,7 +1111,7 @@
|
||||
"incomingMessage": "Innkommende melding",
|
||||
"language": "Språk",
|
||||
"loggedIn": "Logget inn som {{name}}",
|
||||
"maxStageParticipants": "Maksimalt antall deltakere som kan festes til hovedscenen (EKSPERIMENTELL)",
|
||||
"maxStageParticipants": "Maksimalt antall deltakere som kan festes til hovedscenen",
|
||||
"microphones": "Mikrofoner",
|
||||
"moderator": "Moderator",
|
||||
"moderatorOptions": "Moderatoralternativer",
|
||||
|
||||
@@ -1111,7 +1111,7 @@
|
||||
"incomingMessage": "Messatge dintrant",
|
||||
"language": "Lenga",
|
||||
"loggedIn": "Session a {{name}}",
|
||||
"maxStageParticipants": "Nombre maximal de participants que se pòt penjar a la scèna principala (EXPERIMENTAL)",
|
||||
"maxStageParticipants": "Nombre maximal de participants que se pòt penjar a la scèna principala",
|
||||
"microphones": "Microfòns",
|
||||
"moderator": "Moderator",
|
||||
"moderatorOptions": "Opcions de moderacion",
|
||||
|
||||
@@ -1097,7 +1097,7 @@
|
||||
"incomingMessage": "Receber uma mensagem",
|
||||
"language": "Idioma",
|
||||
"loggedIn": "Sessão iniciada como {{name}}",
|
||||
"maxStageParticipants": "Número máximo de participantes que podem ser afixados (EXPERIMENTAL)",
|
||||
"maxStageParticipants": "Número máximo de participantes que podem ser afixados",
|
||||
"microphones": "Microfones",
|
||||
"moderator": "Moderador",
|
||||
"moderatorOptions": "Opções de moderador",
|
||||
|
||||
@@ -1067,7 +1067,7 @@
|
||||
"incomingMessage": "Mensagem recebida",
|
||||
"language": "Idioma",
|
||||
"loggedIn": "Conectado como {{name}}",
|
||||
"maxStageParticipants": "Número máximo de participantes que podem ser fixados no palco principal (EXPERIMENTAL)",
|
||||
"maxStageParticipants": "Número máximo de participantes que podem ser fixados no palco principal",
|
||||
"microphones": "Microfones",
|
||||
"moderator": "Moderador",
|
||||
"moderatorOptions": "Opções de moderador",
|
||||
|
||||
@@ -1083,7 +1083,7 @@
|
||||
"incomingMessage": "Входящее сообщение",
|
||||
"language": "Язык",
|
||||
"loggedIn": "Вошел как {{name}}",
|
||||
"maxStageParticipants": "Максимальное количество участников, которых можно закрепить на главной сцене (ЭКСПЕРИМЕНТАЛЬНО)",
|
||||
"maxStageParticipants": "Максимальное количество участников, которых можно закрепить на главной сцене",
|
||||
"microphones": "Микрофоны",
|
||||
"moderator": "Модератор",
|
||||
"moderatorOptions": "Настройки модератора",
|
||||
|
||||
@@ -968,7 +968,7 @@
|
||||
"incomingMessage": "Messàgiu in intrada",
|
||||
"language": "Limba",
|
||||
"loggedIn": "Autenticatzione: {{name}}",
|
||||
"maxStageParticipants": "Nùmeru màssimu de partetzipantes chi podent èssere apicados a s'iscena printzipale (ISPERIMENTALE)",
|
||||
"maxStageParticipants": "Nùmeru màssimu de partetzipantes chi podent èssere apicados a s'iscena printzipale",
|
||||
"microphones": "Micròfonos",
|
||||
"moderator": "Moderadore",
|
||||
"more": "Àteru",
|
||||
|
||||
@@ -1110,7 +1110,7 @@
|
||||
"incomingMessage": "Mesazh ardhës",
|
||||
"language": "Gjuhë",
|
||||
"loggedIn": "I futur si {{name}}",
|
||||
"maxStageParticipants": "Numër maksimum pjesëmarrësish që mund të fiksohen te skena kryesore (EKSPERIMENTALe)",
|
||||
"maxStageParticipants": "Numër maksimum pjesëmarrësish që mund të fiksohen te skena kryesore",
|
||||
"microphones": "Mikrofona",
|
||||
"moderator": "Moderator",
|
||||
"moderatorOptions": "Mundësi moderatori",
|
||||
|
||||
@@ -995,7 +995,7 @@
|
||||
"incomingMessage": "Вхідне повідомлення",
|
||||
"language": "Мова",
|
||||
"loggedIn": "Увійшли як {{name}}",
|
||||
"maxStageParticipants": "Максимальна кількість учасників, яку можна закріпити на головній сцені (ТЕСТУВАННЯ)",
|
||||
"maxStageParticipants": "Максимальна кількість учасників, яку можна закріпити на головній сцені",
|
||||
"microphones": "Мікрофони",
|
||||
"moderator": "Модератор",
|
||||
"moderatorOptions": "Параметри модерації",
|
||||
|
||||
@@ -1081,7 +1081,7 @@
|
||||
"incomingMessage": "Tin nhắn đang gửi",
|
||||
"language": "Ngôn ngữ",
|
||||
"loggedIn": "Đã đăng nhập dưới tên {{name}}",
|
||||
"maxStageParticipants": "Số lượng người tham gia tối đa có thể được ghim vào sân khấu chính (THỬ NGHIỆM)",
|
||||
"maxStageParticipants": "Số lượng người tham gia tối đa có thể được ghim vào sân khấu chính",
|
||||
"microphones": "Micro",
|
||||
"moderator": "Quản trị viên",
|
||||
"moderatorOptions": "Tùy chọn quản trị viên",
|
||||
|
||||
@@ -1049,7 +1049,7 @@
|
||||
"incomingMessage": "新消息",
|
||||
"language": "语言",
|
||||
"loggedIn": "以{{name}}登录",
|
||||
"maxStageParticipants": "可以固定的最大参会者人数(实验性功能)",
|
||||
"maxStageParticipants": "可以固定的最大参会者人数",
|
||||
"microphones": "麦克风",
|
||||
"moderator": "主持人",
|
||||
"moderatorOptions": "主持人选项",
|
||||
|
||||
@@ -1066,7 +1066,7 @@
|
||||
"incomingMessage": "新訊息",
|
||||
"language": "語言",
|
||||
"loggedIn": "以{{name}}登入",
|
||||
"maxStageParticipants": "可被釘選的最大與會者人數(實驗性功能)",
|
||||
"maxStageParticipants": "可被釘選的最大與會者人數",
|
||||
"microphones": "麥克風",
|
||||
"moderator": "主持人",
|
||||
"moderatorOptions": "主持人選項",
|
||||
|
||||
@@ -122,7 +122,9 @@
|
||||
"nickname": {
|
||||
"popover": "Choose a nickname",
|
||||
"title": "Enter a nickname to use chat",
|
||||
"titleWithPolls": "Enter a nickname to use chat and polls"
|
||||
"titleWithCC": "Enter a nickname to use chat and closed captions",
|
||||
"titleWithPolls": "Enter a nickname to use chat and polls",
|
||||
"titleWithPollsAndCC": "Enter a nickname to use chat, polls and closed captions"
|
||||
},
|
||||
"noMessagesMessage": "There are no messages in the meeting yet. Start a conversation here!",
|
||||
"privateNotice": "Private message to {{recipient}}",
|
||||
@@ -131,10 +133,13 @@
|
||||
"systemDisplayName": "System",
|
||||
"tabs": {
|
||||
"chat": "Chat",
|
||||
"closedCaptions": "CC",
|
||||
"polls": "Polls"
|
||||
},
|
||||
"title": "Chat",
|
||||
"titleWithCC": "Chat and CC",
|
||||
"titleWithPolls": "Chat and Polls",
|
||||
"titleWithPollsAndCC": "Chat, Polls and CC",
|
||||
"you": "you"
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
@@ -144,6 +149,10 @@
|
||||
"dontShowAgain": "Don’t show me this again",
|
||||
"installExtensionText": "Install the extension for Google Calendar and Office 365 integration"
|
||||
},
|
||||
"closedCaptionsTab": {
|
||||
"emptyState": "The closed captions content will be available once a moderator starts it",
|
||||
"startClosedCaptionsButton": "Start closed captions"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
"joiningRoom": "Connecting you to your meeting…"
|
||||
},
|
||||
@@ -752,7 +761,8 @@
|
||||
"dataChannelClosedDescriptionWithAudio": "The bridge channel is down and thus disruptions to audio and video may occur.",
|
||||
"dataChannelClosedWithAudio": "Audio and video quality may be impaired",
|
||||
"disabledIframe": "Embedding is only meant for demo purposes, so this call will disconnect in {{timeout}} minutes.",
|
||||
"disabledIframeSecondary": "Embedding {{domain}} is only meant for demo purposes, so this call will disconnect in {{timeout}} minutes. Please use <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi as a Service</a> for production embedding!",
|
||||
"disabledIframeSecondaryNative": "Embedding {{domain}} is only meant for demo purposes, so this call will disconnect in {{timeout}} minutes.",
|
||||
"disabledIframeSecondaryWeb": "Embedding {{domain}} is only meant for demo purposes, so this call will disconnect in {{timeout}} minutes. Please use <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi as a Service</a> for production embedding!",
|
||||
"disconnected": "disconnected",
|
||||
"displayNotifications": "Display notifications for",
|
||||
"dontRemindMe": "Do not remind me",
|
||||
@@ -880,6 +890,7 @@
|
||||
"waitingLobby": "Waiting in lobby ({{count}})"
|
||||
},
|
||||
"search": "Search participants",
|
||||
"searchDescription": "Start typing to filter participants",
|
||||
"title": "Participants"
|
||||
},
|
||||
"passwordDigitsOnly": "Up to {{number}} digits",
|
||||
@@ -1107,6 +1118,7 @@
|
||||
"signedIn": "Currently accessing calendar events for {{email}}. Click the Disconnect button below to stop accessing calendar events.",
|
||||
"title": "Calendar"
|
||||
},
|
||||
"chatWithPermissions": "Chat requires permission",
|
||||
"desktopShareFramerate": "Desktop sharing frame rate",
|
||||
"desktopShareHighFpsWarning": "A higher frame rate for desktop sharing might affect your bandwidth. You need to restart the screen share for the new settings to take effect.",
|
||||
"desktopShareWarning": "You need to restart the screen share for the new settings to take effect.",
|
||||
@@ -1117,7 +1129,7 @@
|
||||
"incomingMessage": "Incoming message",
|
||||
"language": "Language",
|
||||
"loggedIn": "Logged in as {{name}}",
|
||||
"maxStageParticipants": "Maximum number of participants who can be pinned to the main stage (EXPERIMENTAL)",
|
||||
"maxStageParticipants": "Maximum number of participants who can be pinned to the main stage",
|
||||
"microphones": "Microphones",
|
||||
"moderator": "Moderator",
|
||||
"moderatorOptions": "Moderator options",
|
||||
@@ -1136,6 +1148,7 @@
|
||||
"selectMic": "Microphone",
|
||||
"selfView": "Self view",
|
||||
"shortcuts": "Shortcuts",
|
||||
"showSubtitlesOnStage": "Show subtitles on stage",
|
||||
"speakers": "Speakers",
|
||||
"startAudioMuted": "Everyone starts muted",
|
||||
"startReactionsMuted": "Mute reaction sounds for everyone",
|
||||
@@ -1195,6 +1208,7 @@
|
||||
"neutral": "Neutral",
|
||||
"sad": "Sad",
|
||||
"search": "Search",
|
||||
"searchDescription": "Start typing to filter participants",
|
||||
"searchHint": "Search participants",
|
||||
"seconds": "{{count}}s",
|
||||
"speakerStats": "Participants Stats",
|
||||
@@ -1231,6 +1245,7 @@
|
||||
"closeChat": "Close chat",
|
||||
"closeMoreActions": "Close more actions menu",
|
||||
"closeParticipantsPane": "Close participants pane",
|
||||
"closedCaptions": "Closed captions",
|
||||
"collapse": "Collapse",
|
||||
"document": "Toggle shared document",
|
||||
"documentClose": "Close shared document",
|
||||
@@ -1321,6 +1336,7 @@
|
||||
"closeChat": "Close chat",
|
||||
"closeParticipantsPane": "Close participants pane",
|
||||
"closeReactionsMenu": "Close reactions menu",
|
||||
"closedCaptions": "Closed captions",
|
||||
"disableNoiseSuppression": "Disable extra noise suppression (BETA)",
|
||||
"disableReactionSounds": "You can disable reaction sounds for this meeting",
|
||||
"documentClose": "Close shared document",
|
||||
@@ -1413,13 +1429,16 @@
|
||||
"failed": "Transcribing failed",
|
||||
"labelTooltip": "This meeting is being transcribed.",
|
||||
"labelTooltipExtra": "In addition, a transcript will be available later.",
|
||||
"openClosedCaptions": "Open closed captions",
|
||||
"original": "Original",
|
||||
"sourceLanguageDesc": "Currently the meeting language is set to <b>{{sourceLanguage}}</b>. <br/> You can change it from ",
|
||||
"sourceLanguageHere": "here",
|
||||
"start": "Start showing subtitles",
|
||||
"stop": "Stop showing subtitles",
|
||||
"subtitles": "Subtitles",
|
||||
"subtitlesOff": "Off",
|
||||
"tr": "TR"
|
||||
"tr": "TR",
|
||||
"translateTo": "Translate to"
|
||||
},
|
||||
"unpinParticipant": "{{participantName}} - Unpin",
|
||||
"userMedia": {
|
||||
|
||||
991
package-lock.json
generated
991
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -27,7 +27,6 @@
|
||||
"@jitsi/js-utils": "2.2.1",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
"@jitsi/rnnoise-wasm": "0.2.1",
|
||||
"@jitsi/rtcstats": "9.5.1",
|
||||
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
|
||||
"@microsoft/microsoft-graph-client": "3.0.1",
|
||||
"@mui/material": "5.12.1",
|
||||
@@ -68,7 +67,7 @@
|
||||
"js-md5": "0.6.1",
|
||||
"js-sha512": "0.8.0",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1928.0.0+763b2c8f/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1980.0.0+34a32e86/lib-jitsi-meet.tgz",
|
||||
"lodash-es": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -123,7 +122,6 @@
|
||||
"util": "0.12.1",
|
||||
"uuid": "8.3.2",
|
||||
"wasm-check": "2.0.1",
|
||||
"webm-duration-fix": "1.0.4",
|
||||
"windows-iana": "3.1.0",
|
||||
"zxcvbn": "4.4.2"
|
||||
},
|
||||
|
||||
@@ -12,8 +12,8 @@ import JitsiMeetJS, {
|
||||
browser
|
||||
} from '../base/lib-jitsi-meet';
|
||||
import { isAnalyticsEnabled } from '../base/lib-jitsi-meet/functions.any';
|
||||
import { isEmbedded } from '../base/util/embedUtils';
|
||||
import { getJitsiMeetGlobalNS } from '../base/util/helpers';
|
||||
import { inIframe } from '../base/util/iframeUtils';
|
||||
import { loadScript } from '../base/util/loadScript';
|
||||
import { parseURLParams } from '../base/util/parseURLParams';
|
||||
import { parseURIString } from '../base/util/uri';
|
||||
@@ -213,7 +213,7 @@ export function initAnalytics(store: IStore, handlers: Array<Object>): boolean {
|
||||
permanentProperties.externalApi = typeof API_ID === 'number';
|
||||
|
||||
// Report if we are loaded in iframe
|
||||
permanentProperties.inIframe = inIframe();
|
||||
permanentProperties.inIframe = isEmbedded();
|
||||
|
||||
// Report the tenant from the URL.
|
||||
permanentProperties.tenant = tenant || '/';
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
} from '../base/config/actions';
|
||||
import { setLocationURL } from '../base/connection/actions.web';
|
||||
import { loadConfig } from '../base/lib-jitsi-meet/functions.web';
|
||||
import { inIframe } from '../base/util/iframeUtils';
|
||||
import { isEmbedded } from '../base/util/embedUtils';
|
||||
import { parseURIString } from '../base/util/uri';
|
||||
import { isVpaasMeeting } from '../jaas/functions';
|
||||
import { clearNotifications, showNotification } from '../notifications/actions';
|
||||
@@ -102,7 +102,7 @@ export function maybeRedirectToWelcomePage(options: { feedbackSubmitted?: boolea
|
||||
// if close page is enabled redirect to it, without further action
|
||||
if (enableClosePage) {
|
||||
if (isVpaasMeeting(getState())) {
|
||||
const isOpenedInIframe = inIframe();
|
||||
const isOpenedInIframe = isEmbedded();
|
||||
|
||||
if (isOpenedInIframe) {
|
||||
// @ts-ignore
|
||||
|
||||
@@ -12,6 +12,7 @@ import { clientResized, setSafeAreaInsets } from '../../base/responsive-ui/actio
|
||||
import DimensionsDetector from '../../base/responsive-ui/components/DimensionsDetector.native';
|
||||
import { updateSettings } from '../../base/settings/actions';
|
||||
import JitsiThemePaperProvider from '../../base/ui/components/JitsiThemeProvider.native';
|
||||
import { isEmbedded } from '../../base/util/embedUtils.native';
|
||||
import { _getRouteToRender } from '../getRouteToRender.native';
|
||||
import logger from '../logger';
|
||||
|
||||
@@ -87,7 +88,7 @@ export class App extends AbstractApp<IProps> {
|
||||
|
||||
const liteTxt = AppInfo.isLiteSDK ? ' (lite)' : '';
|
||||
|
||||
logger.info(`Loaded SDK ${AppInfo.sdkVersion}${liteTxt}`);
|
||||
logger.info(`Loaded SDK ${AppInfo.sdkVersion}${liteTxt} isEmbedded=${isEmbedded()}`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@ import { SET_ROOM } from '../base/conference/actionTypes';
|
||||
import { CONNECTION_ESTABLISHED, CONNECTION_FAILED } from '../base/connection/actionTypes';
|
||||
import { getURLWithoutParams } from '../base/connection/utils';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import { inIframe } from '../base/util/iframeUtils';
|
||||
import { isEmbedded } from '../base/util/embedUtils';
|
||||
|
||||
import { reloadNow } from './actions';
|
||||
import { _getRouteToRender } from './getRouteToRender';
|
||||
@@ -52,7 +52,7 @@ function _connectionEstablished(store: IStore, next: Function, action: AnyAction
|
||||
// @ts-ignore
|
||||
const { history, location } = window;
|
||||
|
||||
if (inIframe()) {
|
||||
if (isEmbedded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { AnyAction } from 'redux';
|
||||
|
||||
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
import { inIframe } from '../util/iframeUtils';
|
||||
import { isEmbedded } from '../util/embedUtils';
|
||||
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
|
||||
import logger from './logger';
|
||||
@@ -24,7 +24,7 @@ MiddlewareRegistry.register(() => (next: Function) => (action: AnyAction) => {
|
||||
case APP_WILL_MOUNT: {
|
||||
// Disable it inside an iframe until Google fixes the origin trial for 3rd party sources:
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=1504167
|
||||
if (!inIframe() && 'PressureObserver' in globalThis) {
|
||||
if (!isEmbedded() && 'PressureObserver' in globalThis) {
|
||||
pressureObserver = new window.PressureObserver(
|
||||
(records: typeof window.PressureRecord) => {
|
||||
logger.info('Compute pressure state changed:', JSON.stringify(records));
|
||||
|
||||
@@ -72,11 +72,15 @@ export function getInitials(s?: string) {
|
||||
/**
|
||||
* Checks if the passed URL should be loaded with CORS.
|
||||
*
|
||||
* @param {string} url - The URL.
|
||||
* @param {string | Function} url - The URL (on mobile we use a specific Icon component for avatars).
|
||||
* @param {Array<string>} corsURLs - The URL pattern that matches a URL that needs to be handled with CORS.
|
||||
* @returns {void}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isCORSAvatarURL(url: string, corsURLs: Array<string> = []): boolean {
|
||||
export function isCORSAvatarURL(url: string | Function, corsURLs: Array<string> = []): boolean {
|
||||
if (typeof url === 'function') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return corsURLs.some(pattern => url.startsWith(pattern));
|
||||
}
|
||||
|
||||
|
||||
@@ -190,10 +190,10 @@ export interface IConfig {
|
||||
obfuscateRoomName?: boolean;
|
||||
rtcstatsEnabled?: boolean;
|
||||
rtcstatsEndpoint?: string;
|
||||
rtcstatsLogFlushSizeBytes?: number;
|
||||
rtcstatsPollInterval?: number;
|
||||
rtcstatsSendSdp?: boolean;
|
||||
rtcstatsStoreLogs?: boolean;
|
||||
rtcstatsUseLegacy?: boolean;
|
||||
scriptURLs?: Array<string>;
|
||||
watchRTCEnabled?: boolean;
|
||||
whiteListedEvents?: string[];
|
||||
@@ -617,6 +617,7 @@ export interface IConfig {
|
||||
transcription?: {
|
||||
autoCaptionOnTranscribe?: boolean;
|
||||
autoTranscribeOnRecord?: boolean;
|
||||
disableClosedCaptions?: boolean;
|
||||
enabled?: boolean;
|
||||
preferredLanguage?: string;
|
||||
translationLanguages?: Array<string>;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { inIframe } from '../util/iframeUtils';
|
||||
import { isEmbedded } from '../util/embedUtils';
|
||||
|
||||
import extraConfigWhitelist from './extraConfigWhitelist';
|
||||
import inIframeConfigWhitelist from './inIframeConfigWhitelist';
|
||||
import isEmbeddedConfigWhitelist from './isEmbeddedConfigWhitelist';
|
||||
|
||||
/**
|
||||
* The config keys to whitelist, the keys that can be overridden.
|
||||
@@ -249,4 +249,4 @@ export default [
|
||||
'webrtcIceTcpDisable',
|
||||
'webrtcIceUdpDisable',
|
||||
'whiteboard.enabled'
|
||||
].concat(extraConfigWhitelist).concat(inIframe() ? inIframeConfigWhitelist : []);
|
||||
].concat(extraConfigWhitelist).concat(isEmbedded() ? isEmbeddedConfigWhitelist : []);
|
||||
|
||||
@@ -24,7 +24,6 @@ export function _cleanupConfig(config: IConfig) {
|
||||
delete config.analytics?.rtcstatsEndpoint;
|
||||
delete config.analytics?.rtcstatsPollInterval;
|
||||
delete config.analytics?.rtcstatsSendSdp;
|
||||
delete config.analytics?.rtcstatsUseLegacy;
|
||||
delete config.analytics?.obfuscateRoomName;
|
||||
delete config.analytics?.watchRTCEnabled;
|
||||
delete config.watchRTCConfigParams;
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* Additional config whitelist extending the original whitelist in the case where jitsi-meet is loaded in an iframe.
|
||||
*/
|
||||
export default [];
|
||||
@@ -1,5 +0,0 @@
|
||||
/**
|
||||
* Additional interface config whitelist extending the original whitelist in the case where jitsi-meet is loaded in an
|
||||
* iframe.
|
||||
*/
|
||||
export default [];
|
||||
@@ -1,7 +1,7 @@
|
||||
import { inIframe } from '../util/iframeUtils';
|
||||
import { isEmbedded } from '../util/embedUtils';
|
||||
|
||||
import extraInterfaceConfigWhitelistCopy from './extraInterfaceConfigWhitelist';
|
||||
import inIframeInterfaceConfigWhitelist from './inIframeInterfaceConfigWhitelist';
|
||||
import isEmbeddedInterfaceConfigWhitelist from './isEmbeddedInterfaceConfigWhitelist';
|
||||
|
||||
/**
|
||||
* The interface config keys to whitelist, the keys that can be overridden.
|
||||
@@ -54,4 +54,4 @@ export default [
|
||||
'VERTICAL_FILMSTRIP',
|
||||
'VIDEO_LAYOUT_FIT',
|
||||
'VIDEO_QUALITY_LABEL_DISABLED'
|
||||
].concat(extraInterfaceConfigWhitelistCopy).concat(inIframe() ? inIframeInterfaceConfigWhitelist : []);
|
||||
].concat(extraInterfaceConfigWhitelistCopy).concat(isEmbedded() ? isEmbeddedInterfaceConfigWhitelist : []);
|
||||
|
||||
11
react/features/base/config/isEmbeddedConfigWhitelist.ts
Normal file
11
react/features/base/config/isEmbeddedConfigWhitelist.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Additional config whitelist extending the original whitelist applied when Jitsi Meet is embedded
|
||||
* in another app be that with an iframe or a mobile SDK.
|
||||
*/
|
||||
export default [
|
||||
'customToolbarButtons',
|
||||
'defaultLogoUrl',
|
||||
'deploymentUrls',
|
||||
'liveStreaming',
|
||||
'salesforceUrl'
|
||||
];
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Additional interface config whitelist extending the original whitelist applied when Jitsi Meet is embedded
|
||||
* in another app be that with an iframe or a mobile SDK.
|
||||
*/
|
||||
export default [
|
||||
];
|
||||
@@ -5,7 +5,7 @@ import { conferenceLeft, conferenceWillLeave, redirect } from '../conference/act
|
||||
import { getCurrentConference } from '../conference/functions';
|
||||
import { IConfigState } from '../config/reducer';
|
||||
import JitsiMeetJS, { JitsiConnectionEvents } from '../lib-jitsi-meet';
|
||||
import { inIframe } from '../util/iframeUtils';
|
||||
import { isEmbedded } from '../util/embedUtils';
|
||||
import { parseURLParams } from '../util/parseURLParams';
|
||||
import {
|
||||
appendURLParam,
|
||||
@@ -121,7 +121,7 @@ export function constructOptions(state: IReduxState) {
|
||||
const iceServersOverride = params['iceServers.replace'];
|
||||
|
||||
// Allow iceServersOverride only when jitsi-meet is in an iframe.
|
||||
if (inIframe() && iceServersOverride) {
|
||||
if (isEmbedded() && iceServersOverride) {
|
||||
options.iceServersOverride = iceServersOverride;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { jitsiLocalStorage } from '@jitsi/js-utils/jitsi-local-storage';
|
||||
import { safeJsonParse } from '@jitsi/js-utils/json';
|
||||
|
||||
import { browser } from '../lib-jitsi-meet';
|
||||
import { inIframe } from '../util/iframeUtils';
|
||||
import { isEmbedded } from '../util/embedUtils';
|
||||
import { parseURLParams } from '../util/parseURLParams';
|
||||
|
||||
import logger from './logger';
|
||||
@@ -41,7 +41,7 @@ function shouldUseHostPageLocalStorage(urlParams: { 'config.useHostPageLocalStor
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.isWebKitBased() && inIframe()) {
|
||||
if (browser.isWebKitBased() && isEmbedded()) {
|
||||
// WebKit browsers don't persist local storage for third-party iframes.
|
||||
|
||||
return true;
|
||||
|
||||
@@ -45,17 +45,14 @@ export function getJwtName(state: IReduxState) {
|
||||
*
|
||||
* @param {IReduxState} state - The app state.
|
||||
* @param {string} feature - The feature we want to check.
|
||||
* @param {boolean} ifNoToken - Default value if there is no token.
|
||||
* @param {boolean} ifNotInFeatures - Default value if features prop exists but does not have the {@code feature}.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isJwtFeatureEnabled(
|
||||
state: IReduxState,
|
||||
feature: ParticipantFeaturesKey,
|
||||
ifNoToken: boolean,
|
||||
ifNotInFeatures: boolean
|
||||
) {
|
||||
const { jwt } = state['features/base/jwt'];
|
||||
let { features } = getLocalParticipant(state) || {};
|
||||
|
||||
if (typeof features === 'undefined' && isVpaasMeeting(state)) {
|
||||
@@ -64,17 +61,14 @@ export function isJwtFeatureEnabled(
|
||||
}
|
||||
|
||||
return isJwtFeatureEnabledStateless({
|
||||
jwt,
|
||||
localParticipantFeatures: features,
|
||||
feature,
|
||||
ifNoToken,
|
||||
ifNotInFeatures
|
||||
});
|
||||
}
|
||||
|
||||
interface IIsJwtFeatureEnabledStatelessParams {
|
||||
feature: ParticipantFeaturesKey;
|
||||
ifNoToken: boolean;
|
||||
ifNotInFeatures: boolean;
|
||||
jwt?: string;
|
||||
localParticipantFeatures?: IParticipantFeatures;
|
||||
@@ -83,30 +77,18 @@ interface IIsJwtFeatureEnabledStatelessParams {
|
||||
/**
|
||||
* Check if the given JWT feature is enabled.
|
||||
*
|
||||
* @param {string | undefined} jwt - The jwt token.
|
||||
* @param {ILocalParticipant} localParticipantFeatures - The features of the local participant.
|
||||
* @param {string} feature - The feature we want to check.
|
||||
* @param {boolean} ifNoToken - Default value if there is no token.
|
||||
* @param {boolean} ifNotInFeatures - Default value if features is missing
|
||||
* or prop exists but does not have the {@code feature}.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isJwtFeatureEnabledStateless({
|
||||
jwt,
|
||||
localParticipantFeatures: features,
|
||||
feature,
|
||||
ifNoToken,
|
||||
ifNotInFeatures
|
||||
}: IIsJwtFeatureEnabledStatelessParams) {
|
||||
if (!jwt) {
|
||||
return ifNoToken;
|
||||
}
|
||||
|
||||
if (typeof features === 'undefined') {
|
||||
return ifNoToken;
|
||||
}
|
||||
|
||||
if (typeof features[feature] === 'undefined') {
|
||||
if (typeof features?.[feature] === 'undefined') {
|
||||
return ifNotInFeatures;
|
||||
}
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ function _setJWT(store: IStore, next: Function, action: AnyAction) {
|
||||
const { locationURL = { href: '' } as URL } = state['features/base/connection'];
|
||||
const { tenant = '' } = parseURIString(locationURL.href) || {};
|
||||
|
||||
features = context.tenant === tenant ? features : {};
|
||||
features = context.tenant === tenant || tenant === '' ? features : {};
|
||||
}
|
||||
|
||||
_overwriteLocalParticipant(
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { IStore } from '../../app/types';
|
||||
import JitsiMeetJS from '../../base/lib-jitsi-meet';
|
||||
import RTCStats from '../../rtcstats/RTCStats';
|
||||
import { isRTCStatsEnabled } from '../../rtcstats/functions';
|
||||
|
||||
/**
|
||||
* Implements log storage interface from the @jitsi/logger lib.
|
||||
* Implements log storage interface from the @jitsi/logger lib, as it stands
|
||||
* now it only sends logs to the rtcstats server in case it is enabled.
|
||||
*/
|
||||
export default class JitsiMeetLogStorage {
|
||||
counter: number;
|
||||
getState: IStore['getState'];
|
||||
|
||||
/**
|
||||
@@ -15,12 +16,6 @@ export default class JitsiMeetLogStorage {
|
||||
* @param {Function} getState - The Redux store's {@code getState} method.
|
||||
*/
|
||||
constructor(getState: IStore['getState']) {
|
||||
/**
|
||||
* Counts each log entry, increases on every batch log entry stored.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
this.counter = 1;
|
||||
|
||||
/**
|
||||
* The Redux store's {@code getState} method.
|
||||
@@ -31,18 +26,14 @@ export default class JitsiMeetLogStorage {
|
||||
}
|
||||
|
||||
/**
|
||||
* The JitsiMeetLogStorage is ready when the conference has been joined.
|
||||
* A conference is considered joined when the 'conference' field is defined
|
||||
* in the base/conference state.
|
||||
* The JitsiMeetLogStorage is ready we can use the rtcstats trace to send logs
|
||||
* to the rtcstats server.
|
||||
*
|
||||
* @returns {boolean} <tt>true</tt> when this storage is ready or
|
||||
* <tt>false</tt> otherwise.
|
||||
*/
|
||||
isReady() {
|
||||
const { conference, error: conferenceError } = this.getState()['features/base/conference'];
|
||||
const { error: connectionError } = this.getState()['features/base/connection'];
|
||||
|
||||
return Boolean(conference || conferenceError || connectionError);
|
||||
return JitsiMeetJS.rtcstats.isTraceAvailable();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,9 +46,9 @@ export default class JitsiMeetLogStorage {
|
||||
|
||||
const config = this.getState()['features/base/config'];
|
||||
|
||||
// Saving the logs in RTCStats is a new feature and so there is no prior behavior that needs to be maintained.
|
||||
// That said, this is still experimental and needs to be rolled out gradually so we want this to be off by
|
||||
// default.
|
||||
// RTCStats can run without sending app logs to the server.
|
||||
// Be mindful that there exists another LogStorage instance withing lib-jitsi-meet,
|
||||
// that is used to send logs generated there.
|
||||
return config?.analytics?.rtcstatsStoreLogs && isRTCStatsEnabled(this.getState());
|
||||
}
|
||||
|
||||
|
||||
@@ -107,9 +107,6 @@ function _conferenceJoined({ getState }: IStore, next: Function, action: AnyActi
|
||||
const { logCollector } = getState()['features/base/logging'];
|
||||
|
||||
if (logCollector && conference === getCurrentConference(getState())) {
|
||||
// Start the LogCollector's periodic "store logs" task
|
||||
logCollector.start();
|
||||
|
||||
// Make an attempt to flush in case a lot of logs have been cached,
|
||||
// before the collector was started.
|
||||
logCollector.flush();
|
||||
@@ -150,12 +147,21 @@ function _initLogging({ dispatch, getState }: IStore,
|
||||
|
||||
// Create the LogCollector and register it as the global log transport. It
|
||||
// is done early to capture as much logs as possible. Captured logs will be
|
||||
// cached, before the JitsiMeetLogStorage gets ready (statistics module is
|
||||
// initialized).
|
||||
// cached, before the JitsiMeetLogStorage gets ready (RTCStats trace is
|
||||
// available).
|
||||
if (!logCollector && !loggingConfig.disableLogCollector) {
|
||||
const _logCollector = new Logger.LogCollector(new JitsiMeetLogStorage(getState));
|
||||
const { apiLogLevels, analytics: { rtcstatsLogFlushSizeBytes } = {} } = getState()['features/base/config'];
|
||||
|
||||
const { apiLogLevels } = getState()['features/base/config'];
|
||||
// The smaller the flush size the smaller the chance of losing logs, but
|
||||
// the more often the logs will be sent to the server, by default the LogCollector
|
||||
// will set once the logs reach 10KB or 30 seconds have passed since the last flush,
|
||||
// this means if something happens between that interval and the logs don't get flushed
|
||||
// they will be lost, for instance the meeting tab is closed, the browser crashes,
|
||||
// an uncaught exception happens, etc.
|
||||
// If undefined is passed the default values will be used,
|
||||
const _logCollector = new Logger.LogCollector(new JitsiMeetLogStorage(getState), {
|
||||
maxEntryLength: rtcstatsLogFlushSizeBytes
|
||||
});
|
||||
|
||||
if (apiLogLevels && Array.isArray(apiLogLevels) && typeof APP === 'object') {
|
||||
const transport = buildExternalApiLogTransport(apiLogLevels);
|
||||
@@ -165,6 +171,9 @@ function _initLogging({ dispatch, getState }: IStore,
|
||||
}
|
||||
|
||||
Logger.addGlobalTransport(_logCollector);
|
||||
|
||||
_logCollector.start();
|
||||
|
||||
dispatch(setLogCollector(_logCollector));
|
||||
|
||||
// The JitsiMeetInMemoryLogStorage can not be accessed on mobile through
|
||||
|
||||
@@ -17,8 +17,8 @@ const DEFAULT_LOGGING_CONFIG: ILoggingConfig = {
|
||||
loggers: {
|
||||
// The following are too verbose in their logging with the
|
||||
// {@link #defaultLogLevel}:
|
||||
'modules/RTC/TraceablePeerConnection.js': 'info',
|
||||
'modules/xmpp/strophe.util.js': 'log'
|
||||
'modules/RTC/TraceablePeerConnection': 'info',
|
||||
'modules/xmpp/strophe.util': 'log'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -41,10 +41,10 @@ const DEFAULT_STATE = {
|
||||
// Reduce default verbosity on mobile, it kills performance.
|
||||
if (navigator.product === 'ReactNative') {
|
||||
const RN_LOGGERS: { [key: string]: LogLevel; } = {
|
||||
'modules/sdp/SDPUtil.js': 'info',
|
||||
'modules/xmpp/ChatRoom.js': 'warn',
|
||||
'modules/xmpp/JingleSessionPC.js': 'info',
|
||||
'modules/xmpp/strophe.jingle.js': 'info'
|
||||
'modules/sdp/SDPUtil': 'info',
|
||||
'modules/xmpp/ChatRoom': 'warn',
|
||||
'modules/xmpp/JingleSessionPC': 'info',
|
||||
'modules/xmpp/strophe.jingle': 'info'
|
||||
};
|
||||
|
||||
DEFAULT_STATE.config.loggers = {
|
||||
|
||||
@@ -70,6 +70,11 @@ interface IState {
|
||||
* A generic animated slider view to be used for animated menus.
|
||||
*/
|
||||
export default class SlidingView extends PureComponent<IProps, IState> {
|
||||
/**
|
||||
* Initializes hardwareBackPress subscription.
|
||||
*/
|
||||
_hardwareBackPressSubscription: any;
|
||||
|
||||
/**
|
||||
* True if the component is mounted.
|
||||
*/
|
||||
@@ -120,7 +125,7 @@ export default class SlidingView extends PureComponent<IProps, IState> {
|
||||
* @inheritdoc
|
||||
*/
|
||||
override componentDidMount() {
|
||||
BackHandler.addEventListener('hardwareBackPress', this._onHardwareBackPress);
|
||||
this._hardwareBackPressSubscription = BackHandler.addEventListener('hardwareBackPress', this._onHardwareBackPress);
|
||||
|
||||
this._mounted = true;
|
||||
this._setShow(this.props.show);
|
||||
@@ -145,7 +150,7 @@ export default class SlidingView extends PureComponent<IProps, IState> {
|
||||
* @inheritdoc
|
||||
*/
|
||||
override componentWillUnmount() {
|
||||
BackHandler.removeEventListener('hardwareBackPress', this._onHardwareBackPress);
|
||||
this._hardwareBackPressSubscription?.remove();
|
||||
|
||||
this._mounted = false;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
* localFlipX: boolean,
|
||||
* micDeviceId: string,
|
||||
* serverURL: string,
|
||||
* showSubtitlesOnStage: boolean,
|
||||
* startAudioOnly: boolean,
|
||||
* startWithAudioMuted: boolean,
|
||||
* startWithVideoMuted: boolean,
|
||||
|
||||
@@ -29,6 +29,7 @@ const DEFAULT_STATE: ISettingsState = {
|
||||
micDeviceId: undefined,
|
||||
serverURL: undefined,
|
||||
hideShareAudioHelper: false,
|
||||
showSubtitlesOnStage: false,
|
||||
soundsIncomingMessage: true,
|
||||
soundsParticipantJoined: true,
|
||||
soundsParticipantKnocking: true,
|
||||
@@ -67,6 +68,7 @@ export interface ISettingsState {
|
||||
maxStageParticipants?: number;
|
||||
micDeviceId?: string | boolean;
|
||||
serverURL?: string;
|
||||
showSubtitlesOnStage?: boolean;
|
||||
soundsIncomingMessage?: boolean;
|
||||
soundsParticipantJoined?: boolean;
|
||||
soundsParticipantKnocking?: boolean;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
// Mapping between the token used and the color
|
||||
export const colorMap = {
|
||||
// ----- Surfaces -----
|
||||
@@ -119,8 +118,8 @@ export const colorMap = {
|
||||
|
||||
|
||||
export const font = {
|
||||
weightRegular: '400',
|
||||
weightSemiBold: '600'
|
||||
weightRegular: 400,
|
||||
weightSemiBold: 600
|
||||
};
|
||||
|
||||
export const shape = {
|
||||
@@ -130,7 +129,7 @@ export const shape = {
|
||||
};
|
||||
|
||||
export const spacing
|
||||
= [ 0, 4, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128 ];
|
||||
= [ '0rem', '0.25rem', '0.5rem', '1rem', '1.5rem', '2rem', '2.5rem', '3rem', '3.5rem', '4rem', '4.5rem', '5rem', '5.5rem', '6rem', '6.5rem', '7rem', '7.5rem', '8rem' ];
|
||||
|
||||
export const typography = {
|
||||
labelRegular: 'label01',
|
||||
@@ -138,64 +137,64 @@ export const typography = {
|
||||
labelBold: 'labelBold01',
|
||||
|
||||
bodyShortRegularSmall: {
|
||||
fontSize: 10,
|
||||
lineHeight: 16,
|
||||
fontSize: '0.625rem',
|
||||
lineHeight: '1rem',
|
||||
fontWeight: font.weightRegular,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyShortRegular: {
|
||||
fontSize: 14,
|
||||
lineHeight: 20,
|
||||
fontSize: '0.875rem',
|
||||
lineHeight: '1.25rem',
|
||||
fontWeight: font.weightRegular,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyShortBold: {
|
||||
fontSize: 14,
|
||||
lineHeight: 20,
|
||||
fontSize: '0.875rem',
|
||||
lineHeight: '1.25rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyShortRegularLarge: {
|
||||
fontSize: 16,
|
||||
lineHeight: 22,
|
||||
fontSize: '1rem',
|
||||
lineHeight: '1.375rem',
|
||||
fontWeight: font.weightRegular,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyShortBoldLarge: {
|
||||
fontSize: 16,
|
||||
lineHeight: 22,
|
||||
fontSize: '1rem',
|
||||
lineHeight: '1.375rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyLongRegular: {
|
||||
fontSize: 14,
|
||||
lineHeight: 24,
|
||||
fontSize: '0.875rem',
|
||||
lineHeight: '1.5rem',
|
||||
fontWeight: font.weightRegular,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyLongRegularLarge: {
|
||||
fontSize: 16,
|
||||
lineHeight: 26,
|
||||
fontSize: '1rem',
|
||||
lineHeight: '1.625rem',
|
||||
fontWeight: font.weightRegular,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyLongBold: {
|
||||
fontSize: 14,
|
||||
lineHeight: 24,
|
||||
fontSize: '0.875rem',
|
||||
lineHeight: '1.5rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
bodyLongBoldLarge: {
|
||||
fontSize: 16,
|
||||
lineHeight: 26,
|
||||
fontSize: '1rem',
|
||||
lineHeight: '1.625rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
},
|
||||
@@ -205,29 +204,29 @@ export const typography = {
|
||||
heading2: 'heading02',
|
||||
|
||||
heading3: {
|
||||
fontSize: 32,
|
||||
lineHeight: 40,
|
||||
fontSize: '2rem',
|
||||
lineHeight: '2.5rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
heading4: {
|
||||
fontSize: 28,
|
||||
lineHeight: 36,
|
||||
fontSize: '1.75rem',
|
||||
lineHeight: '2.25rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
heading5: {
|
||||
fontSize: 20,
|
||||
lineHeight: 28,
|
||||
fontSize: '1.25rem',
|
||||
lineHeight: '1.75rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
},
|
||||
|
||||
heading6: {
|
||||
fontSize: 16,
|
||||
lineHeight: 26,
|
||||
fontSize: '1rem',
|
||||
lineHeight: '1.625rem',
|
||||
fontWeight: font.weightSemiBold,
|
||||
letterSpacing: 0
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ const ContextMenu = ({
|
||||
|
||||
if (offsetTop + height > offsetHeight + scrollTop && height > offsetTop) {
|
||||
// top offset and + padding + border
|
||||
container.style.maxHeight = `${offsetTop - ((spacing[2] * 2) + 2)}px`;
|
||||
container.style.maxHeight = `calc(${offsetTop}px - (${spacing[2]} * 2 + 2px))`;
|
||||
}
|
||||
|
||||
// get the height after style changes
|
||||
|
||||
29
react/features/base/ui/components/web/HiddenDescription.tsx
Normal file
29
react/features/base/ui/components/web/HiddenDescription.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
|
||||
interface IHiddenDescriptionProps {
|
||||
children: React.ReactNode;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export const HiddenDescription: React.FC<IHiddenDescriptionProps> = ({ id, children }) => {
|
||||
const hiddenStyle: React.CSSProperties = {
|
||||
border: 0,
|
||||
clip: 'rect(0 0 0 0)',
|
||||
clipPath: 'inset(50%)',
|
||||
height: '1px',
|
||||
margin: '-1px',
|
||||
overflow: 'hidden',
|
||||
padding: 0,
|
||||
position: 'absolute',
|
||||
width: '1px',
|
||||
whiteSpace: 'nowrap'
|
||||
};
|
||||
|
||||
return (
|
||||
<span
|
||||
id = { id }
|
||||
style = { hiddenStyle }>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
@@ -7,6 +7,7 @@ import Icon from '../../../icons/components/Icon';
|
||||
import { IconCloseCircle } from '../../../icons/svg';
|
||||
import { withPixelLineHeight } from '../../../styles/functions.web';
|
||||
import { IInputProps } from '../types';
|
||||
import { HiddenDescription } from './HiddenDescription';
|
||||
|
||||
interface IProps extends IInputProps {
|
||||
accessibilityLabel?: string;
|
||||
@@ -14,6 +15,7 @@ interface IProps extends IInputProps {
|
||||
autoFocus?: boolean;
|
||||
bottomLabel?: string;
|
||||
className?: string;
|
||||
hiddenDescription?: string; // Text that will be announced by screen readers but not displayed visually.
|
||||
iconClick?: () => void;
|
||||
|
||||
/**
|
||||
@@ -152,13 +154,14 @@ const useStyles = makeStyles()(theme => {
|
||||
|
||||
const Input = React.forwardRef<any, IProps>(({
|
||||
accessibilityLabel,
|
||||
autoComplete,
|
||||
autoComplete = 'off',
|
||||
autoFocus,
|
||||
bottomLabel,
|
||||
className,
|
||||
clearable = false,
|
||||
disabled,
|
||||
error,
|
||||
hiddenDescription,
|
||||
icon,
|
||||
iconClick,
|
||||
id,
|
||||
@@ -185,11 +188,22 @@ const Input = React.forwardRef<any, IProps>(({
|
||||
const { classes: styles, cx } = useStyles();
|
||||
const isMobile = isMobileBrowser();
|
||||
const showClearIcon = clearable && value !== '' && !disabled;
|
||||
const inputAutoCompleteOff = autoComplete === 'off' ? { 'data-1p-ignore': '' } : {};
|
||||
|
||||
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) =>
|
||||
onChange?.(e.target.value), []);
|
||||
|
||||
const clearInput = useCallback(() => onChange?.(''), []);
|
||||
const hiddenDescriptionId = `${id}-hidden-description`;
|
||||
let ariaDescribedById: string | undefined;
|
||||
|
||||
if (bottomLabel) {
|
||||
ariaDescribedById = `${id}-description`;
|
||||
} else if (hiddenDescription) {
|
||||
ariaDescribedById = hiddenDescriptionId;
|
||||
} else {
|
||||
ariaDescribedById = undefined;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className = { cx(styles.inputContainer, className) }>
|
||||
@@ -207,6 +221,7 @@ const Input = React.forwardRef<any, IProps>(({
|
||||
src = { icon } />}
|
||||
{textarea ? (
|
||||
<TextareaAutosize
|
||||
aria-describedby = { ariaDescribedById }
|
||||
aria-label = { accessibilityLabel }
|
||||
autoComplete = { autoComplete }
|
||||
autoFocus = { autoFocus }
|
||||
@@ -227,7 +242,7 @@ const Input = React.forwardRef<any, IProps>(({
|
||||
value = { value } />
|
||||
) : (
|
||||
<input
|
||||
aria-describedby = { bottomLabel ? `${id}-description` : undefined }
|
||||
aria-describedby = { ariaDescribedById }
|
||||
aria-label = { accessibilityLabel }
|
||||
autoComplete = { autoComplete }
|
||||
autoFocus = { autoFocus }
|
||||
@@ -236,6 +251,7 @@ const Input = React.forwardRef<any, IProps>(({
|
||||
data-testid = { testId }
|
||||
disabled = { disabled }
|
||||
id = { id }
|
||||
{ ...inputAutoCompleteOff }
|
||||
{ ...(mode ? { inputmode: mode } : {}) }
|
||||
{ ...(type === 'number' ? { max: maxValue } : {}) }
|
||||
maxLength = { maxLength }
|
||||
@@ -266,6 +282,7 @@ const Input = React.forwardRef<any, IProps>(({
|
||||
{bottomLabel}
|
||||
</span>
|
||||
)}
|
||||
{!bottomLabel && hiddenDescription && <HiddenDescription id = { hiddenDescriptionId }>{ hiddenDescription }</HiddenDescription>}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -2,6 +2,47 @@ import { DefaultTheme } from 'react-native-paper';
|
||||
|
||||
import { createColorTokens } from './utils';
|
||||
|
||||
// Base font size in pixels (standard is 16px = 1rem)
|
||||
const BASE_FONT_SIZE = 16;
|
||||
|
||||
/**
|
||||
* Converts rem to pixels.
|
||||
*
|
||||
* @param {string} remValue - The value in rem units (e.g. '0.875rem').
|
||||
* @returns {number}
|
||||
*/
|
||||
function remToPixels(remValue: string): number {
|
||||
const numericValue = parseFloat(remValue.replace('rem', ''));
|
||||
|
||||
return Math.round(numericValue * BASE_FONT_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts all rem to pixels in an object.
|
||||
*
|
||||
* @param {Object} obj - The object to convert rem values in.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function convertRemValues(obj: any): any {
|
||||
const converted: { [key: string]: any; } = {};
|
||||
|
||||
if (typeof obj !== 'object' || obj === null) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
Object.entries(obj).forEach(([ key, value ]) => {
|
||||
if (typeof value === 'string' && value.includes('rem')) {
|
||||
converted[key] = remToPixels(value);
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
converted[key] = convertRemValues(value);
|
||||
} else {
|
||||
converted[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
return converted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a React Native Paper theme based on local UI tokens.
|
||||
*
|
||||
@@ -13,10 +54,10 @@ export function createNativeTheme({ font, colorMap, shape, spacing, typography }
|
||||
...DefaultTheme,
|
||||
palette: createColorTokens(colorMap),
|
||||
shape,
|
||||
spacing,
|
||||
spacing: spacing.map(remToPixels),
|
||||
typography: {
|
||||
font,
|
||||
...typography
|
||||
...convertRemValues(typography)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ interface ThemeProps {
|
||||
colorMap: Object;
|
||||
font: Object;
|
||||
shape: Object;
|
||||
spacing: Array<number>;
|
||||
spacing: Array<number | string>;
|
||||
typography: Object;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ export function createColorTokens(colorMap: Object): any {
|
||||
|
||||
return Object.entries(colorMap)
|
||||
.reduce((result, [ token, value ]: [any, string]) => {
|
||||
const color = allTokens[value as keyof typeof allTokens];
|
||||
const color = allTokens[value as keyof typeof allTokens] || value;
|
||||
|
||||
return Object.assign(result, { [token]: color });
|
||||
}, {});
|
||||
|
||||
@@ -5,8 +5,22 @@
|
||||
* @param {string} filename - The filename to give to the downloaded file.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function downloadJSON(json: Object, filename: string) {
|
||||
const data = encodeURIComponent(JSON.stringify(json, null, ' '));
|
||||
export function downloadJSON(json: Object, filename: string): void {
|
||||
const replacer = () => {
|
||||
const seen = new WeakSet();
|
||||
|
||||
return (_: any, value: any) => {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (seen.has(value)) {
|
||||
return '[circular ref]';
|
||||
}
|
||||
seen.add(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
};
|
||||
const data = encodeURIComponent(JSON.stringify(json, replacer(), ' '));
|
||||
|
||||
const elem = document.createElement('a');
|
||||
|
||||
|
||||
32
react/features/base/util/embedUtils.native.ts
Normal file
32
react/features/base/util/embedUtils.native.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { getBundleId } from 'react-native-device-info';
|
||||
|
||||
/**
|
||||
* BUndle ids for the Jitsi Meet apps.
|
||||
*/
|
||||
const JITSI_MEET_APPS = [
|
||||
|
||||
// iOS app.
|
||||
'com.atlassian.JitsiMeet.ios',
|
||||
|
||||
// Android + iOS (testing) app.
|
||||
'org.jitsi.meet',
|
||||
|
||||
// Android debug app.
|
||||
'org.jitsi.meet.debug',
|
||||
|
||||
// 8x8 Work (Android).
|
||||
'org.vom8x8.sipua',
|
||||
|
||||
// 8x8 Work (iOS).
|
||||
'com.yourcompany.Virtual-Office'
|
||||
];
|
||||
|
||||
/**
|
||||
* Checks whether we are loaded in iframe. In the mobile case we treat SDK
|
||||
* consumers as the web treats iframes.
|
||||
*
|
||||
* @returns {boolean} Whether the current app is a Jitsi Meet app.
|
||||
*/
|
||||
export function isEmbedded(): boolean {
|
||||
return !JITSI_MEET_APPS.includes(getBundleId());
|
||||
}
|
||||
@@ -3,11 +3,7 @@
|
||||
*
|
||||
* @returns {boolean} Whether the current page is loaded in an iframe.
|
||||
*/
|
||||
export function inIframe(): boolean {
|
||||
if (navigator.product === 'ReactNative') {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isEmbedded(): boolean {
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
79
react/features/base/util/messageGrouping.ts
Normal file
79
react/features/base/util/messageGrouping.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Interface representing a message that can be grouped.
|
||||
* Used by both chat messages and subtitles.
|
||||
*/
|
||||
export interface IGroupableMessage {
|
||||
|
||||
/**
|
||||
* The ID of the participant who sent the message.
|
||||
*/
|
||||
participantId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface representing a group of messages from the same sender.
|
||||
*
|
||||
* @template T - The type of messages in the group, must extend IGroupableMessage.
|
||||
*/
|
||||
export interface IMessageGroup<T extends IGroupableMessage> {
|
||||
|
||||
/**
|
||||
* Array of messages in this group.
|
||||
*/
|
||||
messages: T[];
|
||||
|
||||
/**
|
||||
* The ID of the participant who sent all messages in this group.
|
||||
*/
|
||||
senderId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Groups an array of messages by sender.
|
||||
*
|
||||
* @template T - The type of messages to group, must extend IGroupableMessage.
|
||||
* @param {T[]} messages - The array of messages to group.
|
||||
* @returns {IMessageGroup<T>[]} - An array of message groups, where each group contains messages from the same sender.
|
||||
* @example
|
||||
* const messages = [
|
||||
* { participantId: "user1", timestamp: 1000 },
|
||||
* { participantId: "user1", timestamp: 2000 },
|
||||
* { participantId: "user2", timestamp: 3000 }
|
||||
* ];
|
||||
* const groups = groupMessagesBySender(messages);
|
||||
* // Returns:
|
||||
* // [
|
||||
* // {
|
||||
* // senderId: "user1",
|
||||
* // messages: [
|
||||
* // { participantId: "user1", timestamp: 1000 },
|
||||
* // { participantId: "user1", timestamp: 2000 }
|
||||
* // ]
|
||||
* // },
|
||||
* // { senderId: "user2", messages: [{ participantId: "user2", timestamp: 3000 }] }
|
||||
* // ]
|
||||
*/
|
||||
export function groupMessagesBySender<T extends IGroupableMessage>(
|
||||
messages: T[]
|
||||
): IMessageGroup<T>[] {
|
||||
if (!messages?.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const groups: IMessageGroup<T>[] = [];
|
||||
let currentGroup: IMessageGroup<T> | null = null;
|
||||
|
||||
for (const message of messages) {
|
||||
if (!currentGroup || currentGroup.senderId !== message.participantId) {
|
||||
currentGroup = {
|
||||
messages: [ message ],
|
||||
senderId: message.participantId
|
||||
};
|
||||
groups.push(currentGroup);
|
||||
} else {
|
||||
currentGroup.messages.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
return groups;
|
||||
}
|
||||
9
react/features/base/util/spot.ts
Normal file
9
react/features/base/util/spot.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
/**
|
||||
* Checks if Jitsi Meet is running on Spot TV.
|
||||
*
|
||||
* @returns {boolean} Whether or not Jitsi Meet is running on Spot TV.
|
||||
*/
|
||||
export function isSpotTV(): boolean {
|
||||
return navigator.userAgent.includes('SpotElectron/');
|
||||
}
|
||||
@@ -98,14 +98,14 @@ export const SEND_REACTION = 'SEND_REACTION';
|
||||
export const SET_PRIVATE_MESSAGE_RECIPIENT = 'SET_PRIVATE_MESSAGE_RECIPIENT';
|
||||
|
||||
/**
|
||||
* The type of action which signals the update a _isPollsTabFocused.
|
||||
* The type of action which signals setting the focused tab.
|
||||
*
|
||||
* {
|
||||
* isPollsTabFocused: boolean,
|
||||
* type: SET_PRIVATE_MESSAGE_RECIPIENT
|
||||
* type: SET_FOCUSED_TAB,
|
||||
* tabId: string
|
||||
* }
|
||||
*/
|
||||
export const SET_IS_POLL_TAB_FOCUSED = 'SET_IS_POLL_TAB_FOCUSED';
|
||||
export const SET_FOCUSED_TAB = 'SET_FOCUSED_TAB';
|
||||
|
||||
/**
|
||||
* The type of action which sets the current recipient for lobby messages.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user