mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-01-11 09:10:20 +00:00
Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
101bd637b0 | ||
|
|
078503b1b3 | ||
|
|
8c4e9f823d | ||
|
|
fe1f858ef9 | ||
|
|
dd7b953a92 | ||
|
|
1f2aaa8dc0 | ||
|
|
80bf228a65 | ||
|
|
62e0f09f98 | ||
|
|
6654feacee |
@@ -1,14 +1,20 @@
|
||||
# Follow Our Updated Guide to See How You Can Contribute
|
||||
|
||||
Hello there! 👋
|
||||
**Hello there! 👋**
|
||||
|
||||
We're thrilled that you're eager to contribute to Jitsi Meet! ❤️
|
||||
We're thrilled that you're eager to contribute to **Jitsi Meet! ❤️**
|
||||
|
||||
Your interest in improving our platform means a lot to us. To ensure your contributions align seamlessly with our goals and processes, we've recently updated our guide. This guide will provide you with clear instructions on how to get involved effectively.
|
||||
|
||||
Ready to get started? Head over to our [Jitsi Meet Handbook](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-contributing/) and let's make Jitsi Meet even better together!
|
||||
### 📖 Get Started
|
||||
|
||||
Ready to get started? Head over to our [Jitsi Meet Handbook](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-contributing/) and let's make **Jitsi Meet** even better together!
|
||||
|
||||
### 💬 Join the Discussion
|
||||
|
||||
Have questions or need help? Join our community discussions on the [Jitsi Forum](https://community.jitsi.org/) where contributors and maintainers can assist you.
|
||||
|
||||
### ❗️Additional Note
|
||||
Before sending us your code, double-check that it meets our coding standards. You can do this by running a command: `npm run lint`. If there are any issues, don't worry! You can fix them by running: `npm run lint-fix`. Once your code passes these checks, feel free to submit your pull request.
|
||||
|
||||
Happy coding!
|
||||
**Happy coding!**
|
||||
|
||||
@@ -42,6 +42,7 @@ android {
|
||||
debug {
|
||||
buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${googleServicesEnabled}"
|
||||
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
|
||||
applicationIdSuffix ".debug"
|
||||
}
|
||||
release {
|
||||
// Uncomment the following line for singing a test release build.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user