diff --git a/css/_mixins.scss b/css/_mixins.scss
index 51a4a42f39..11ec2a6e78 100644
--- a/css/_mixins.scss
+++ b/css/_mixins.scss
@@ -206,13 +206,3 @@
bottom: 0;
width: 35%;
}
-
-/**
- * Resizes elements width to fill the whole screen width with some margin
- */
-@mixin adjust-for-max-width($width, $margin) {
- @media (max-width: $width) {
- margin: 0 $margin;
- width: $width - 2 * $margin;
- }
-}
diff --git a/css/_prejoin.scss b/css/_prejoin.scss
deleted file mode 100644
index 86f89afc7c..0000000000
--- a/css/_prejoin.scss
+++ /dev/null
@@ -1,153 +0,0 @@
-.prejoin {
-
- &-input-area {
- margin: 0 auto;
- text-align: center;
-
- &-label {
- display: block;
- margin-bottom: 5px;
- color: #ffffff;
- font-weight: 300;
- font-size: 15px;
- line-height: 24px;
- }
- }
-
- &-title {
- color: #fff;
- font-size: 24px;
- line-height: 32px;
- margin-bottom: 16px;
- }
-
- &-text-btns {
- display: flex;
- justify-content: space-between;
- }
-
- &-input-label {
- color: #A4B8D1;
- font-size: 13px;
- line-height: 20px;
- margin-top: 32px 0 8px 0;
- text-align: center;
- width: 100%;
- }
-
- &-checkbox {
- border: 0;
- height: 16px;
- margin-right: 8px;
- padding: 0;
- width: 16px;
- }
-
- &-checkbox-container {
- margin-bottom: 14px;
- width: 100%;
- }
-
- &-error {
- color: white;
- background-color: rgba(225, 45, 45, 0.6);
- border-radius: 3px;
- width: 100%;
- padding: 2px;
- box-sizing: border-box;
- margin-top: 4px;
- font-size: 13px;
- text-align: center;
- }
-}
-
-@mixin name-placeholder {
- color: #fff;
- font-weight: 300;
- opacity: 0.6;
-}
-
-.prejoin-preview {
- &-status {
- align-items: center;
- align-self: stretch;
- bottom: 0;
- color: #fff;
- display: flex;
- font-size: 13px;
- min-height: 24px;
- justify-content: center;
- position: absolute;
- text-align: center;
- width: 100%;
- z-index: 1;
-
- &--warning {
- background: rgba(241, 173, 51, 1);
- }
- &--ok {
- background: rgba(49, 183, 106, 1);
- }
- }
-
- &-icon {
- background-position: center;
- background-repeat: no-repeat;
- display: inline-block;
- height: 16px;
- margin-right: 8px;
- width: 16px;
- }
-
- &-error-desc {
- margin-right: 4px;
- color: #fff;
- font-weight: bold;
- }
-
- .settings-button-container {
- width: 49px;
- margin: 0 8px;
- }
-
- &-dropdown-btns {
- width: 320px;
- padding: 8px 0;
-
- @include adjust-for-max-width(320px, 8px);
- }
-
- &-dropdown-btn {
- align-items: center;
- color: #1C2025;
- cursor: pointer;
- display: flex;
- height: 40px;
- font-size: 15px;
- line-height: 24px;
- padding: 0 16px;
-
- &:hover {
- background-color: #DAEBFA;
- }
- }
-
- &-dropdown-icon {
- display: inline-block;
- margin-right: 16px;
-
- & > svg {
- fill: #1C2025;
- }
- }
-
- &-dropdown-container {
- margin-top: 16px;
-
- & > div:nth-child(2) {
- background: #fff;
- padding: 0;
- }
- }
-
-}
diff --git a/css/_toolbars.scss b/css/_toolbars.scss
index 99c95a8c92..3ee0f3ce5b 100644
--- a/css/_toolbars.scss
+++ b/css/_toolbars.scss
@@ -334,7 +334,7 @@
border-radius: 0;
display: flex;
justify-content: space-evenly;
- padding: 6px 0;
+ padding: 8px 0;
width: 100%;
}
diff --git a/css/_variables.scss b/css/_variables.scss
index 1b0a6a49bf..f8fae8a970 100644
--- a/css/_variables.scss
+++ b/css/_variables.scss
@@ -264,3 +264,9 @@ $chromeExtensionBannerRightInMeeeting: 10px;
*/
$smallScreen: 700px;
$verySmallScreen: 500px;
+
+/**
+* Prejoin / premeeting screen
+*/
+
+$prejoinDefaultContentWidth: 336px;
\ No newline at end of file
diff --git a/css/main.scss b/css/main.scss
index 8102091832..98e2ebbadc 100644
--- a/css/main.scss
+++ b/css/main.scss
@@ -79,7 +79,6 @@ $flagsImagePath: "../images/";
@import 'filmstrip/vertical_filmstrip';
@import 'filmstrip/vertical_filmstrip_overrides';
@import 'labels';
-@import 'lobby';
@import 'unsupported-browser/main';
@import 'modals/invite/add-people';
@import 'deep-linking/main';
@@ -95,15 +94,12 @@ $flagsImagePath: "../images/";
@import 'meter';
@import 'audio-preview';
@import 'video-preview';
-@import 'prejoin';
-@import 'prejoin-dialog';
+@import 'premeeting/main';
@import 'country-picker';
@import 'modals/invite/invite_more';
@import 'modals/security/security';
-@import 'premeeting-screens';
@import 'e2ee';
@import 'responsive';
-@import 'connection-status';
@import 'drawer';
@import 'participants-pane';
@import 'reactions-menu';
diff --git a/css/_connection-status.scss b/css/premeeting/_connection-status.scss
similarity index 60%
rename from css/_connection-status.scss
rename to css/premeeting/_connection-status.scss
index b0ebacdecd..52ff1d232b 100644
--- a/css/_connection-status.scss
+++ b/css/premeeting/_connection-status.scss
@@ -1,32 +1,24 @@
.con-status {
+ border-radius: 6px;
+ color: #fff;
+ font-size: 12px;
+ letter-spacing: 0.16px;
+ line-height: 16px;
position: absolute;
- top: 24px;
width: 100%;
- z-index: $toolbarZ + 3;
-
- &-container {
- border-radius: 3px;
- color: #fff;
- font-size: 13px;
- line-height: 13px;
- margin: 0 auto;
- width: 320px;
-
- @include adjust-for-max-width(320px, 8px);
- }
&-header {
- background: rgba(28, 32, 37, .5);
+ background-color: rgba(0, 0, 0, 0.7);
align-items: center;
display: flex;
- justify-content: space-between;
+ padding: 8px 12px;
}
&-circle {
border-radius: 50%;
display: inline-block;
padding: 4px;
- margin: 8px;
+ margin-right: 16px;
}
&--good {
@@ -42,14 +34,7 @@
}
&-arrow {
- height: 36px;
- width: 36px;
- border-radius: 3px;
- margin-left: 8px;
- margin-right: 2px;
- display: flex;
- align-items: center;
- justify-content: center;
+ margin-left: auto;
transition: background-color 0.16s ease-out;
&--up {
@@ -70,7 +55,7 @@
}
&-details {
- background: rgba(28, 32, 37, .5);
+ background-color: rgba(0, 0, 0, 0.7);
border-top: 1px solid #5E6D7A;
padding: 16px;
transition: opacity 0.16s ease-out;
diff --git a/css/premeeting/_device-status.scss b/css/premeeting/_device-status.scss
new file mode 100644
index 0000000000..aff964244e
--- /dev/null
+++ b/css/premeeting/_device-status.scss
@@ -0,0 +1,35 @@
+.device {
+ &-status {
+ align-items: center;
+ align-self: stretch;
+ color: #fff;
+ display: flex;
+ font-size: 14px;
+ font-weight: 400;
+ justify-content: center;
+ line-height: 20px;
+ margin-top: 8px;
+ padding: 6px;
+ text-align: center;
+ }
+
+ &-icon {
+ background-position: center;
+ background-repeat: no-repeat;
+ display: inline-block;
+ height: 16px;
+ margin-right: 10px;
+ width: 16px;
+
+ &--warning {
+ svg path {
+ fill: rgba(241, 173, 51, 1);
+ }
+ }
+ &--ok {
+ svg path {
+ fill: #189b55;
+ }
+ }
+ }
+}
diff --git a/css/_lobby.scss b/css/premeeting/_lobby.scss
similarity index 85%
rename from css/_lobby.scss
rename to css/premeeting/_lobby.scss
index f9c93588a0..3264a92cc8 100644
--- a/css/_lobby.scss
+++ b/css/premeeting/_lobby.scss
@@ -1,18 +1,21 @@
-#lobby-screen {
- .content {
+.lobby-screen {
+ font-size: 16px;
+ font-weight: 400;
+ line-height: 26px;
- .container {
- align-items: center;
- display: flex;
- flex-direction: column;
+ &-content {
+ align-items: center;
+ display: flex;
+ flex-direction: column;
- .spinner {
- margin: 30px;
- }
+ .spinner {
+ margin: 8px;
+ }
- .joining-message {
- margin: 10px;
- }
+ .joining-message {
+ color: white;
+ margin: 24px auto;
+ text-align: center;
}
}
}
@@ -68,7 +71,7 @@
button {
align-self: stretch;
- margin: 8px 0;
+ margin-bottom: 8px 0;
padding: 12px;
transition: .2s transform ease;
diff --git a/css/premeeting/_main.scss b/css/premeeting/_main.scss
new file mode 100644
index 0000000000..fbf2b02423
--- /dev/null
+++ b/css/premeeting/_main.scss
@@ -0,0 +1,7 @@
+@import 'connection-status';
+@import 'device-status';
+@import 'lobby';
+@import 'premeeting-screens';
+@import 'prejoin';
+@import 'prejoin-dialog';
+@import 'prejoin-third-party';
diff --git a/css/_prejoin-dialog.scss b/css/premeeting/_prejoin-dialog.scss
similarity index 100%
rename from css/_prejoin-dialog.scss
rename to css/premeeting/_prejoin-dialog.scss
diff --git a/css/premeeting/_prejoin-third-party.scss b/css/premeeting/_prejoin-third-party.scss
new file mode 100644
index 0000000000..efde129ee5
--- /dev/null
+++ b/css/premeeting/_prejoin-third-party.scss
@@ -0,0 +1,39 @@
+$sidePanelWidth: 300px;
+
+.prejoin-third-party {
+ flex-direction: column-reverse;
+
+ .content {
+ height: auto;
+ margin: 0 auto;
+
+ .new-toolbox {
+ width: auto;
+ }
+ }
+
+ #preview {
+ background-color: transparent;
+ bottom: 0;
+ left: 0;
+ position: absolute;
+ right: 0;
+ top: 0;
+
+ .avatar {
+ display: none;
+ }
+ }
+
+ &.splash {
+ .content {
+ margin-left: calc((100% - #{$prejoinDefaultContentWidth} + #{$sidePanelWidth}) / 2)
+ }
+ }
+
+ &.guest {
+ .content {
+ margin-bottom: auto;
+ }
+ }
+}
diff --git a/css/premeeting/_prejoin.scss b/css/premeeting/_prejoin.scss
new file mode 100644
index 0000000000..ba1fd02444
--- /dev/null
+++ b/css/premeeting/_prejoin.scss
@@ -0,0 +1,73 @@
+.prejoin {
+ &-input-area {
+ width: 100%;
+ }
+
+ &-checkbox-container {
+ margin-bottom: 16px;
+ width: 100%;
+ text-align: center;
+ }
+
+ &-error {
+ color: white;
+ background-color: #E04757;
+ border-radius: 6px;
+ padding: 4px;
+ box-sizing: border-box;
+ margin-bottom: 16px;
+ margin-top: -8px;
+ font-size: 12px;
+ text-align: center;
+ width: 100%;
+ }
+}
+
+.prejoin-preview {
+ &-dropdown-btns {
+ padding: 8px 0;
+ width: calc(100% - 48px);
+ }
+
+ &-dropdown-btn {
+ align-items: center;
+ color: #1C2025;
+ cursor: pointer;
+ display: flex;
+ height: 40px;
+ font-size: 15px;
+ line-height: 24px;
+ padding: 0 16px;
+
+ &:hover {
+ background-color: #DAEBFA;
+ }
+ }
+
+ &-dropdown-icon {
+ display: inline-block;
+ margin-right: 16px;
+
+ & > svg {
+ fill: #1C2025;
+ }
+ }
+
+ &-dropdown-container {
+ position: relative;
+ width: 100%;
+
+ /**
+ * Override default InlineDialog behaviour, since it does not play nicely with relative widths
+ */
+ & > div:nth-child(2) {
+ background: #fff;
+ padding: 0;
+ position: absolute !important;
+ top: 48px !important;
+ transform: none !important;
+ width: 100%;
+ }
+ }
+ }
+
\ No newline at end of file
diff --git a/css/_premeeting-screens.scss b/css/premeeting/_premeeting-screens.scss
similarity index 51%
rename from css/_premeeting-screens.scss
rename to css/premeeting/_premeeting-screens.scss
index 9ff9a7f1d5..7efef32a99 100644
--- a/css/_premeeting-screens.scss
+++ b/css/premeeting/_premeeting-screens.scss
@@ -1,47 +1,27 @@
-/**
- * Shared style for full screen local track based dialogs/modals.
- */
.premeeting-screen {
- position: absolute;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- }
-
- .premeeting-screen {
- align-items: stretch;
- background: radial-gradient(50% 50% at 50% 50%, #2A3A4B 20.83%, #1E2A36 100%);
+ background: #292929;
+ bottom: 0;
display: flex;
- flex-direction: column;
font-size: 1.3em;
+ left: 0;
+ position: absolute;
+ right: 0;
+ top: 0;
z-index: $toolbarZ + 1;
- &-avatar {
- background-color: #A4B8D1;
- margin-bottom: 24px;
-
- text {
- fill: black;
- font-size: 26px;
- font-weight: 400;
- }
- }
-
.action-btn {
- border-radius: 3px;
+ border-radius: 6px;
box-sizing: border-box;
color: #fff;
cursor: pointer;
display: inline-block;
- font-size: 15px;
+ font-size: 14px;
line-height: 24px;
+ margin-bottom: 16px;
padding: 7px 16px;
position: relative;
text-align: center;
- width: 320px;
-
- @include adjust-for-max-width(320px, 8px);
+ width: 100%;
&.primary {
background: #0376DA;
@@ -49,8 +29,8 @@
}
&.secondary {
- background: transparent;
- border: 1px solid #5E6D7A;
+ background: #3D3D3D;
+ border: 1px solid transparent;
}
&.text {
@@ -96,130 +76,150 @@
.content {
align-items: center;
+ box-sizing: border-box;
display: flex;
- flex: 1;
flex-direction: column;
- justify-content: flex-end;
- padding-bottom: 24px;
+ flex-shrink: 0;
+ height: 100%;
+ margin: 0 110px;
+ padding: 24px 0 16px;
+ position: relative;
+ width: $prejoinDefaultContentWidth;
z-index: $toolbarZ + 2;
- .title {
- color: #fff;
- font-size: 24px;
- line-height: 32px;
- margin-bottom: 16px;
- }
-
- .copy-meeting {
+ &-controls {
align-items: center;
- cursor: pointer;
- color: #fff;
display: flex;
flex-direction: column;
- font-size: 15px;
- font-weight: 300;
- justify-content: center;
- line-height: 24px;
- margin-bottom: 16px;
+ margin: auto;
+ width: 100%;
- .url {
- background: rgba(28, 32, 37, 0.5);
- border-radius: 4px;
- display: flex;
- padding: 8px 10px;
- transition: background 0.16s ease-out;
-
- &:hover {
- background: #1C2025;
+ .title {
+ color: #fff;
+ font-size: 28px;
+ font-weight: 600;
+ letter-spacing: -0.015;
+ line-height: 36px;
+ margin-bottom: 32px;
+ text-align: center;
+ }
+
+ input.field {
+ background-color: white;
+ border: none;
+ outline: none;
+ border-radius: 6px;
+ font-size: 14px;
+ line-height: 20px;
+ margin-bottom: 16px;
+ color: #1C2025;
+ padding: 10px 16px;
+ text-align: center;
+ width: 100%;
+
+ &.error {
+ border: 1px solid #E04757;
}
-
- &.done {
- background: #31B76A;
- }
-
- .jitsi-icon {
- margin-left: 10px;
+
+ &.focused {
+ box-shadow: 0px 0px 1px 1.5px black, 0px 0px 1.3px 4px white;
}
}
- .copy-button{
- width: 298px;
- }
- .copy-meeting-text {
- width: 266px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
+ #new-toolbox {
+ bottom: 0;
+ margin-bottom: 16px;
+ position: relative;
+ transition: none;
- &:hover {
- align-self: stretch;
- }
-
- textarea {
- border-width: 0;
- height: 0;
- opacity: 0;
- padding: 0;
- width: 0;
- }
- }
-
- input.field {
- background-color: white;
- border: none;
- outline: none;
- border-radius: 3px;
- font-size: 15px;
- line-height: 24px;
- color: #1C2025;
- padding: 8px 0;
- text-align: center;
- width: 320px;
-
- @include adjust-for-max-width(320px, 8px);
-
- &.error {
- box-shadow: 0px 0px 4px 3px rgba(225, 45, 45, 0.4);
- }
-
- &.focused {
- box-shadow: 0px 0px 1px 1.5px black, 0px 0px 1.3px 4px white;
+ .toolbox-content,
+ .toolbox-content-wrapper,
+ .toolbox-content-items {
+ box-sizing: border-box;
+ width: 100%;
+ }
}
}
}
- .media-btn-container {
- display: flex;
- justify-content: center;
- margin: 24px 0 16px 0;
- width: 100%;
-
- &> div {
- margin: 0 12px;
+ @media (max-width: 1000px) {
+ flex-direction: column-reverse;
+
+ .content {
+ height: auto;
+ margin: 0 auto;
}
+
+ .con-status {
+ margin: 24px auto;
+ position: fixed;
+ top: 0;
+ width: $prejoinDefaultContentWidth;
+ }
+ }
+
+ @media (max-width: 400px) {
+ .content {
+ padding: 16px;
+ width: 100%;
+
+ .title {
+ font-size: 20px;
+ line-height: 28px;
+ letter-spacing: -0.012;
+ margin-bottom: 24px;
+ }
+ }
+
+ .con-status {
+ margin: 16px;
+ width: calc(100% - 32px);
+ }
+
+ input.field {
+ font-size: 16px;
+ padding: 14px 16px;
+ }
+
+ .action-btn {
+ font-size: 16px;
+ padding: 11px 16px;
+ }
+
+ .toolbox-content-items {
+ border-radius: 0;
+ display: flex;
+ justify-content: space-evenly;
+ padding: 8px 0;
+ }
+ }
+
+ input::placeholder {
+ color: #040404;
}
}
#preview {
+ background: #040404;
+ display: flex;
+ align-items: center;
+ justify-content: center;
height: 100%;
- position: absolute;
width: 100%;
- &.no-video {
- background: radial-gradient(50% 50% at 50% 50%, #5B6F80 0%, #365067 100%), #FFFFFF;
- text-align: center;
- }
-
.avatar {
- background: #A4B8D1;
- margin: 0 auto;
+ background: #0045B3;
+
+ text {
+ fill: white;
+ font-size: 26px;
+ font-weight: 400;
+ }
}
video {
height: 100%;
object-fit: cover;
- position: absolute;
width: 100%;
}
}
@@ -241,16 +241,14 @@
}
.toggle-button {
- border-radius: 3px;
+ border-radius: 6px;
cursor: pointer;
color: #fff;
font-size: 13px;
height: 40px;
margin: 0 auto;
transition: background 0.16s ease-out;
- width: 320px;
- @include adjust-for-max-width(320px, 8px);
@include flex-centered();
svg {
diff --git a/lang/main-de.json b/lang/main-de.json
index 4935864201..a56763abcb 100644
--- a/lang/main-de.json
+++ b/lang/main-de.json
@@ -209,7 +209,6 @@
"e2eeLabel": "Ende-zu-Ende-Verschlüsselung aktivieren",
"e2eeWarning": "WARNUNG: Nicht alle Personen dieser Konferenz scheinen Ende-zu-Ende-Verschlüsselung zu unterstützen. Wenn Sie diese aktivieren, können die entsprechenden Personen nichts mehr sehen oder hören.",
"enterDisplayName": "Bitte geben Sie hier Ihren Namen ein",
- "enterDisplayNameToJoin" : "Benutzername für Konferenz eingeben" ,
"embedMeeting": "Besprechung einbetten",
"error": "Fehler",
"gracefulShutdown": "Der Dienst steht momentan wegen Wartungsarbeiten nicht zur Verfügung. Bitte versuchen Sie es später noch einmal.",
diff --git a/lang/main-eo.json b/lang/main-eo.json
index c9dff5fbb3..25966fe0c3 100644
--- a/lang/main-eo.json
+++ b/lang/main-eo.json
@@ -179,7 +179,7 @@
"e2eeLabel": "Ŝlosilo",
"e2eeTitle": "Tutvoja ĉifrado",
"e2eeWarning": "
ATENTIGO: Ne ĉiuj partoprenantoj en ĉi tiu kunveno ŝajnas havi subtenon de tutvoja ĉifrado. Se vi ŝaltos ĝin, ili ne povos vidi aŭ aŭdi vin.
",
- "enterDisplayName": "Please enter your name here",
+ "enterDisplayName": "Enter your name here",
"error": "Eraro",
"externalInstallationMsg": "Vi devas instali nian ekranvidadan kromprogramon.",
"externalInstallationTitle": "Kromprogramo bezonata",
diff --git a/lang/main-eu.json b/lang/main-eu.json
index c6183534e5..da0917cde7 100644
--- a/lang/main-eu.json
+++ b/lang/main-eu.json
@@ -203,7 +203,6 @@
"e2eeLabel": "Aktibatu puntutik punturako zifratzea",
"e2eeWarning": "OHARRA: bileraren partaide guztiek ezin dute puntutik punturako zifratzea erabili. Aukera hau aktibatzen baduzu, batzuk ezingo zaituzte ikusi eta entzun.",
"enterDisplayName": "Sartu zure izena hemen",
- "enterDisplayNameToJoin": "Mesedez idatzi zure izena bileran sartzeko",
"embedMeeting": "Kapsulatu bilera",
"error": "Errorea",
"gracefulShutdown": "Zerbitzua ez dago erabilgarri mantentze-lanak direla eta. Saiatu berriro beranduago.",
diff --git a/lang/main-fr.json b/lang/main-fr.json
index ab516c6a5e..5bf72e0f27 100644
--- a/lang/main-fr.json
+++ b/lang/main-fr.json
@@ -213,7 +213,6 @@
"e2eeLabel": "Activer le chiffrement de Bout-en-Bout",
"e2eeWarning": "ATTENTION : Tous les participants de cette réunion ne semblent pas prendre en charge le chiffrement de Bout-en-Bout. Si vous activez le chiffrement, ils ne pourront ni vous voir, ni vous entendre.",
"enterDisplayName": "Merci de saisir votre nom ici",
- "enterDisplayNameToJoin": "Merci de saisir votre nom pour rejoindre",
"embedMeeting": "Intégrer la réunion",
"error": "Erreur",
"gracefulShutdown": "Notre service est actuellement en maintenance. Veuillez réessayer plus tard.",
diff --git a/lang/main-id.json b/lang/main-id.json
index f8428aefd0..9311fa326d 100644
--- a/lang/main-id.json
+++ b/lang/main-id.json
@@ -175,7 +175,7 @@
"dismiss": "Dismiss",
"displayNameRequired": "Hi! What’s your name?",
"done": "Done",
- "enterDisplayName": "Please enter your name here",
+ "enterDisplayName": "Enter your name here",
"error": "Error",
"externalInstallationMsg": "You need to install our desktop sharing extension.",
"externalInstallationTitle": "Extension required",
diff --git a/lang/main-pt.json b/lang/main-pt.json
index da870cb046..1bf43d3bea 100644
--- a/lang/main-pt.json
+++ b/lang/main-pt.json
@@ -197,7 +197,6 @@
"e2eeLabel": "Habilitar encriptação de ponta a ponta",
"e2eeWarning": "AVISO: Nem todos os participantes neste encontro parecem ter apoio para a encriptação de ponta a ponta. Se o permitir, eles não o poderão ver nem ouvir.",
"enterDisplayName": "Digite o seu nome aqui",
- "enterDisplayNameToJoin": "Por favor, digite o seu nome para participar",
"embedMeeting": "Embutir reunião",
"error": "Erro",
"gracefulShutdown": "O nosso serviço está atualmente em manutenção. Por favor, tente novamente mais tarde.",
diff --git a/lang/main-ptBR.json b/lang/main-ptBR.json
index ce12390adf..e309ed099a 100644
--- a/lang/main-ptBR.json
+++ b/lang/main-ptBR.json
@@ -209,7 +209,6 @@
"e2eeLabel": "Enable End-to-End Encryption",
"e2eeWarning": "WARNING: Not all participants in this meeting seem to have support for End-to-End encryption. If you enable it they won't be able to see nor hear you.",
"enterDisplayName": "Digite seu nome aqui",
- "enterDisplayNameToJoin": "Digite seu nome para participar",
"embedMeeting": "Reunião em formato compacto",
"error": "Erro",
"gracefulShutdown": "Nosso serviço está em manutenção. Tente novamente mais tarde.",
diff --git a/lang/main-sq.json b/lang/main-sq.json
index 62a86fae0a..fe23c036be 100644
--- a/lang/main-sq.json
+++ b/lang/main-sq.json
@@ -209,7 +209,6 @@
"e2eeLabel": "Aktivizo Fshehtëzim Skaj-më-Skaj",
"e2eeWarning": "KUJDES: Jo të gjithë pjesëmarrësit në këtë takim duket të kenë mbulim për fshehtëzim Skaj-më-Skaj. Në e aktivizofshi, ata s’do të jenë në gjendje t’ju shohin apo dëgjojnë.",
"enterDisplayName": "Ju lutemi, jepni këtu emrin tuaj",
- "enterDisplayNameToJoin": "Që të merrni pjesë, ju lutemi, jepni emrin tuaj",
"embedMeeting": "Trupëzoni takim",
"error": "Gabim",
"gracefulShutdown": "Shërbimi ynë është aktualisht i ndërprerë, për punë mirëmbajtjeje. Ju lutemi, riprovoni më vonë.",
diff --git a/lang/main-zhTW.json b/lang/main-zhTW.json
index 05bdf48941..677f7b30d2 100644
--- a/lang/main-zhTW.json
+++ b/lang/main-zhTW.json
@@ -209,7 +209,6 @@
"e2eeLabel": "啟用端對端加密",
"e2eeWarning": "警告:看來不是每位此會議的參與者都有啟用端對端加密,如果您啟用了,他們可能無法看/聽到您。",
"enterDisplayName": "請在此輸入您自己的名字",
- "enterDisplayNameToJoin": "請輸入您的名字以加入",
"embedMeeting": "嵌入會議",
"error": "錯誤",
"gracefulShutdown": "我們的服務目前關閉維護中,請稍後再試。",
diff --git a/lang/main.json b/lang/main.json
index 2eb32677c7..e45b91de8c 100644
--- a/lang/main.json
+++ b/lang/main.json
@@ -212,8 +212,7 @@
"e2eeDescription": "End-to-End Encryption is currently EXPERIMENTAL. Please keep in mind that turning on end-to-end encryption will effectively disable server-side provided services such as: phone participation. Also keep in mind that the meeting will only work for people joining from browsers with support for insertable streams.",
"e2eeLabel": "Enable End-to-End Encryption",
"e2eeWarning": "WARNING: Not all participants in this meeting seem to have support for End-to-End encryption. If you enable it they won't be able to see nor hear you.",
- "enterDisplayName": "Please enter your name here",
- "enterDisplayNameToJoin": "Please enter your name to join",
+ "enterDisplayName": "Enter your name here",
"embedMeeting": "Embed meeting",
"error": "Error",
"gracefulShutdown": "Our service is currently down for maintenance. Please try again later.",
@@ -694,7 +693,7 @@
"joinWithoutAudio": "Join without audio",
"initiated": "Call initiated",
"linkCopied": "Link copied to clipboard",
- "lookGood": "It sounds like your microphone is working properly",
+ "lookGood": "Your microphone is working properly",
"or": "or",
"premeeting": "Pre meeting",
"showScreen": "Enable pre meeting screen",
@@ -1121,7 +1120,7 @@
"admitAll": "Admit all",
"knockingParticipantList": "Knocking participant list",
"allow": "Allow",
- "backToKnockModeButton": "No password, ask to join instead",
+ "backToKnockModeButton": "Ask to join",
"dialogTitle": "Lobby mode",
"disableDialogContent": "Lobby mode is currently enabled. This feature ensures that unwanted participants can't join your meeting. Do you want to disable it?",
"disableDialogSubmit": "Disable",
@@ -1131,6 +1130,7 @@
"enableDialogText": "Lobby mode lets you protect your meeting by only allowing people to enter after a formal approval by a moderator.",
"enterPasswordButton": "Enter meeting password",
"enterPasswordTitle": "Enter password to join meeting",
+ "errorMissingPassword": "Please enter the meeting password",
"invalidPassword": "Invalid password",
"joiningMessage": "You'll join the meeting as soon as someone accepts your request",
"joinWithPasswordMessage": "Trying to join with password, please wait...",
diff --git a/react/features/app/components/App.web.js b/react/features/app/components/App.web.js
index f19edb7f9b..b8c03a4585 100644
--- a/react/features/app/components/App.web.js
+++ b/react/features/app/components/App.web.js
@@ -43,9 +43,11 @@ export class App extends AbstractApp {
*/
_renderDialogContainer() {
return (
-
-
-
+
+
+
+
+
);
}
}
diff --git a/react/features/base/conference/middleware.web.js b/react/features/base/conference/middleware.web.js
index c61f657e88..778c01377e 100644
--- a/react/features/base/conference/middleware.web.js
+++ b/react/features/base/conference/middleware.web.js
@@ -1,21 +1,20 @@
// @flow
import { setPrejoinPageVisibility, setSkipPrejoinOnReload } from '../../prejoin';
+import { PREJOIN_SCREEN_STATES } from '../../prejoin/constants';
import { JitsiConferenceErrors } from '../lib-jitsi-meet';
import { MiddlewareRegistry } from '../redux';
import { CONFERENCE_FAILED, CONFERENCE_JOINED } from './actionTypes';
import './middleware.any';
-declare var APP: Object;
-
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
const { enableForcedReload } = getState()['features/base/config'];
switch (action.type) {
case CONFERENCE_JOINED: {
if (enableForcedReload) {
- dispatch(setPrejoinPageVisibility(false));
+ dispatch(setPrejoinPageVisibility(PREJOIN_SCREEN_STATES.HIDDEN));
dispatch(setSkipPrejoinOnReload(false));
}
diff --git a/react/features/base/icons/svg/check-solid.svg b/react/features/base/icons/svg/check-solid.svg
new file mode 100644
index 0000000000..bf948de1bb
--- /dev/null
+++ b/react/features/base/icons/svg/check-solid.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/react/features/base/icons/svg/index.js b/react/features/base/icons/svg/index.js
index fc270d53a6..bb03001d09 100644
--- a/react/features/base/icons/svg/index.js
+++ b/react/features/base/icons/svg/index.js
@@ -26,6 +26,7 @@ export { default as IconChat } from './chat.svg';
export { default as IconChatSend } from './send.svg';
export { default as IconChatUnread } from './chat-unread.svg';
export { default as IconCheck } from './check.svg';
+export { default as IconCheckSolid } from './check-solid.svg';
export { default as IconClose } from './close.svg';
export { default as IconCloseCircle } from './close-circle.svg';
export { default as IconCloseX } from './close-x.svg';
diff --git a/react/features/base/premeeting/components/web/ConnectionStatus.js b/react/features/base/premeeting/components/web/ConnectionStatus.js
index d1bb781a96..468609d33e 100644
--- a/react/features/base/premeeting/components/web/ConnectionStatus.js
+++ b/react/features/base/premeeting/components/web/ConnectionStatus.js
@@ -79,37 +79,35 @@ function ConnectionStatus({ connectionDetails, t, connectionType }: Props) {
return (
-
-
-
-
-
-
{t(connectionText)}
+
+
+ size = { 16 }
+ src = { icon } />
-
- {detailsText}
+
{t(connectionText)}
+
+
+ {detailsText}
);
}
diff --git a/react/features/base/premeeting/components/web/CopyMeetingUrl.js b/react/features/base/premeeting/components/web/CopyMeetingUrl.js
deleted file mode 100644
index a84875e761..0000000000
--- a/react/features/base/premeeting/components/web/CopyMeetingUrl.js
+++ /dev/null
@@ -1,67 +0,0 @@
-// @flow
-
-import React, { Component } from 'react';
-
-import CopyMeetingLinkSection
- from '../../../../invite/components/add-people-dialog/web/CopyMeetingLinkSection';
-import { getCurrentConferenceUrl } from '../../../connection';
-import { translate } from '../../../i18n';
-import { connect } from '../../../redux';
-
-type Props = {
-
- /**
- * The meeting url.
- */
- url: string,
-
- /**
- * Used for translation.
- */
- t: Function,
-
- /**
- * Used to determine if invitation link should be automatically copied
- * after creating a meeting.
- */
- _enableAutomaticUrlCopy: boolean,
-};
-
-
-/**
- * Component used to copy meeting url on prejoin page.
- */
-class CopyMeetingUrl extends Component
{
-
- /**
- * Implements React's {@link Component#render()}.
- *
- * @inheritdoc
- * @returns {ReactElement}
- */
- render() {
- return (
-
-
-
- );
- }
-}
-
-/**
- * Maps (parts of) the redux state to the React {@code Component} props.
- *
- * @param {Object} state - The redux state.
- * @returns {Object}
- */
-function mapStateToProps(state) {
- const { enableAutomaticUrlCopy } = state['features/base/config'];
- const { customizationReady } = state['features/dynamic-branding'];
-
- return {
- url: customizationReady ? getCurrentConferenceUrl(state) : '',
- _enableAutomaticUrlCopy: enableAutomaticUrlCopy || false
- };
-}
-
-export default connect(mapStateToProps)(translate(CopyMeetingUrl));
diff --git a/react/features/base/premeeting/components/web/PreMeetingScreen.js b/react/features/base/premeeting/components/web/PreMeetingScreen.js
index 47a7d2e768..c4ffc2a094 100644
--- a/react/features/base/premeeting/components/web/PreMeetingScreen.js
+++ b/react/features/base/premeeting/components/web/PreMeetingScreen.js
@@ -2,14 +2,10 @@
import React, { PureComponent } from 'react';
-import { AudioSettingsButton, VideoSettingsButton } from '../../../../toolbox/components/web';
-import { VideoBackgroundButton } from '../../../../virtual-background';
-import { checkBlurSupport } from '../../../../virtual-background/functions';
-import { Avatar } from '../../../avatar';
-import { allowUrlSharing } from '../../functions';
+import DeviceStatus from '../../../../prejoin/components/preview/DeviceStatus';
+import { Toolbox } from '../../../../toolbox/components/web';
import ConnectionStatus from './ConnectionStatus';
-import CopyMeetingUrl from './CopyMeetingUrl';
import Preview from './Preview';
type Props = {
@@ -17,12 +13,12 @@ type Props = {
/**
* Children component(s) to be rendered on the screen.
*/
- children: React$Node,
+ children?: React$Node,
/**
- * Footer to be rendered for the page (if any).
+ * Additional CSS class names to set on the icon container.
*/
- footer?: React$Node,
+ className?: string,
/**
* The name of the participant.
@@ -35,25 +31,25 @@ type Props = {
showCopyUrlButton: boolean,
/**
- * Indicates whether the avatar should be shown when video is off
+ * Indicates whether the device status should be shown
*/
- showAvatar: boolean,
-
- /**
- * Indicates whether the label and copy url action should be shown
- */
- showConferenceInfo: boolean,
-
- /**
- * Title of the screen.
- */
- title: string,
+ showDeviceStatus: boolean,
/**
* The 'Skip prejoin' button to be rendered (if any).
*/
skipPrejoinButton?: React$Node,
+ /**
+ * Title of the screen.
+ */
+ title?: string,
+
+ /**
+ * Override for default toolbar buttons
+ */
+ toolbarButtons?: Array,
+
/**
* True if the preview overlay should be muted, false otherwise.
*/
@@ -62,14 +58,11 @@ type Props = {
/**
* The video track to render as preview (if omitted, the default local track will be rendered).
*/
- videoTrack?: Object,
-
- /**
- * Array with the buttons which this Toolbox should display.
- */
- visibleButtons?: Array
+ videoTrack?: Object
}
+const buttons = [ 'microphone', 'camera', 'select-background', 'invite', 'settings' ];
+
/**
* Implements a pre-meeting screen that can be used at various pre-meeting phases, for example
* on the prejoin screen (pre-connection) or lobby (post-connection).
@@ -81,9 +74,8 @@ export default class PreMeetingScreen extends PureComponent {
* @static
*/
static defaultProps = {
- showAvatar: true,
showCopyUrlButton: true,
- showConferenceInfo: true
+ showToolbox: true
};
/**
@@ -93,57 +85,37 @@ export default class PreMeetingScreen extends PureComponent {
*/
render() {
const {
- name,
- showAvatar,
- showConferenceInfo,
- showCopyUrlButton,
+ children,
+ className,
+ showDeviceStatus,
+ skipPrejoinButton,
title,
+ toolbarButtons,
videoMuted,
- videoTrack,
- visibleButtons
+ videoTrack
} = this.props;
- const showSharingButton = allowUrlSharing() && showCopyUrlButton;
+
+ const containerClassName = `premeeting-screen ${className ? className : ''}`;
return (
-
-
+
+
+
+
+
+
+ { title }
+
+ { children }
+
+ { skipPrejoinButton }
+ { showDeviceStatus && }
+
+
+
-
- {showAvatar && videoMuted && (
-
- )}
- {showConferenceInfo && (
- <>
-
- { title }
-
- {showSharingButton ?
: null}
- >
- )}
- { this.props.children }
-
-
-
-
-
- { ((visibleButtons && visibleButtons.includes('select-background'))
- || (visibleButtons && visibleButtons.includes('videobackgroundblur')))
- &&
}
-
-
-
- { this.props.skipPrejoinButton }
- { this.props.footer }
-
);
}
diff --git a/react/features/base/premeeting/components/web/Preview.js b/react/features/base/premeeting/components/web/Preview.js
index 8cf895dc34..cb6013361a 100644
--- a/react/features/base/premeeting/components/web/Preview.js
+++ b/react/features/base/premeeting/components/web/Preview.js
@@ -2,17 +2,30 @@
import React from 'react';
+import { getDisplayName } from '../../../../base/settings';
+import { Avatar } from '../../../avatar';
import { Video } from '../../../media';
+import { getLocalParticipant } from '../../../participants';
import { connect } from '../../../redux';
import { getLocalVideoTrack } from '../../../tracks';
export type Props = {
+ /**
+ * Local participant id
+ */
+ _participantId: string,
+
/**
* Flag controlling whether the video should be flipped or not.
*/
flipVideo: boolean,
+ /**
+ * The name of the user that is about to join.
+ */
+ name: string,
+
/**
* Flag signaling the visibility of camera preview.
*/
@@ -31,20 +44,27 @@ export type Props = {
* @returns {ReactElement}
*/
function Preview(props: Props) {
- const { videoMuted, videoTrack, flipVideo } = props;
+ const { _participantId, flipVideo, name, videoMuted, videoTrack } = props;
const className = flipVideo ? 'flipVideoX' : '';
- if (!videoMuted && videoTrack) {
- return (
-
-
-
- );
- }
-
- return null;
+ return (
+
+ {!videoMuted && videoTrack
+ ? (
+
+ )
+ : (
+
+ )}
+
+ );
}
/**
@@ -55,8 +75,13 @@ function Preview(props: Props) {
* @returns {Props}
*/
function _mapStateToProps(state, ownProps) {
+ const name = getDisplayName(state);
+ const { id: _participantId } = getLocalParticipant(state);
+
return {
+ _participantId,
flipVideo: state['features/base/settings'].localFlipX,
+ name,
videoMuted: ownProps.videoTrack ? ownProps.videoMuted : state['features/base/media'].video.muted,
videoTrack: ownProps.videoTrack || (getLocalVideoTrack(state['features/base/tracks']) || {}).jitsiTrack
};
diff --git a/react/features/base/premeeting/functions.js b/react/features/base/premeeting/functions.js
index 275bca19f5..88f7de2dce 100644
--- a/react/features/base/premeeting/functions.js
+++ b/react/features/base/premeeting/functions.js
@@ -213,14 +213,3 @@ export function getConnectionData(state: Object) {
connectionDetails: []
};
}
-
-/**
- * Returns if url sharing is enabled in interface configuration.
- *
- * @returns {boolean}
- */
-export function allowUrlSharing() {
- return typeof interfaceConfig === 'undefined'
- || typeof interfaceConfig.SHARING_FEATURES === 'undefined'
- || (interfaceConfig.SHARING_FEATURES.length && interfaceConfig.SHARING_FEATURES.indexOf('url') > -1);
-}
diff --git a/react/features/conference/components/native/Conference.js b/react/features/conference/components/native/Conference.js
index 4700c06933..c51ec0d66b 100644
--- a/react/features/conference/components/native/Conference.js
+++ b/react/features/conference/components/native/Conference.js
@@ -22,6 +22,8 @@ import {
import { AddPeopleDialog, CalleeInfoContainer } from '../../../invite';
import { LargeVideo } from '../../../large-video';
import { KnockingParticipantList } from '../../../lobby';
+import { LobbyScreen } from '../../../lobby/components/native';
+import { getIsLobbyVisible } from '../../../lobby/functions';
import { BackButtonRegistry } from '../../../mobile/back-button';
import { ParticipantsPane } from '../../../participants-pane/components/native';
import { Captions } from '../../../subtitles';
@@ -98,6 +100,11 @@ type Props = AbstractProps & {
*/
_toolboxVisible: boolean,
+ /**
+ * Indicates whether the lobby screen should be visible.
+ */
+ _showLobby: boolean,
+
/**
* The redux {@code dispatch} function.
*/
@@ -154,7 +161,11 @@ class Conference extends AbstractConference
{
* @returns {ReactElement}
*/
render() {
- const { _fullscreenEnabled } = this.props;
+ const { _fullscreenEnabled, _showLobby } = this.props;
+
+ if (_showLobby) {
+ return ;
+ }
return (
@@ -427,6 +438,7 @@ function _mapStateToProps(state) {
_largeVideoParticipantId: state['features/large-video'].participantId,
_pictureInPictureEnabled: getFeatureFlag(state, PIP_ENABLED),
_reducedUI: reducedUI,
+ _showLobby: getIsLobbyVisible(state),
_toolboxVisible: isToolboxVisible(state)
};
}
diff --git a/react/features/conference/components/web/Conference.js b/react/features/conference/components/web/Conference.js
index 764d94197d..e12753650b 100644
--- a/react/features/conference/components/web/Conference.js
+++ b/react/features/conference/components/web/Conference.js
@@ -15,9 +15,10 @@ import { Filmstrip } from '../../../filmstrip';
import { CalleeInfoContainer } from '../../../invite';
import { LargeVideo } from '../../../large-video';
import { KnockingParticipantList, LobbyScreen } from '../../../lobby';
+import { getIsLobbyVisible } from '../../../lobby/functions';
import { ParticipantsPane } from '../../../participants-pane/components/web';
import { getParticipantsPaneOpen } from '../../../participants-pane/functions';
-import { Prejoin, isPrejoinPageVisible } from '../../../prejoin';
+import { Prejoin, isPrejoinPageVisible, isPrejoinPageLoading } from '../../../prejoin';
import { fullScreenChanged, showToolbox } from '../../../toolbox/actions.web';
import { Toolbox } from '../../../toolbox/components/web';
import { LAYOUTS, getCurrentLayout } from '../../../video-layout';
@@ -70,11 +71,6 @@ type Props = AbstractProps & {
*/
_backgroundAlpha: number,
- /**
- * Returns true if the 'lobby screen' is visible.
- */
- _isLobbyScreenVisible: boolean,
-
/**
* If participants pane is visible or not.
*/
@@ -96,6 +92,11 @@ type Props = AbstractProps & {
*/
_roomName: string,
+ /**
+ * If lobby page is visible or not.
+ */
+ _showLobby: boolean,
+
/**
* If prejoin page is visible or not.
*/
@@ -207,9 +208,9 @@ class Conference extends AbstractConference {
*/
render() {
const {
- _isLobbyScreenVisible,
_isParticipantsPaneVisible,
_layoutClassName,
+ _showLobby,
_showPrejoin
} = this.props;
@@ -237,7 +238,7 @@ class Conference extends AbstractConference {
- { _showPrejoin || _isLobbyScreenVisible || }
+ { _showPrejoin || _showLobby || }
{ this.renderNotificationsContainer() }
@@ -245,7 +246,7 @@ class Conference extends AbstractConference {
{ _showPrejoin && }
-
+ { _showLobby && }
@@ -373,12 +374,12 @@ function _mapStateToProps(state) {
return {
...abstractMapStateToProps(state),
_backgroundAlpha: backgroundAlpha,
- _isLobbyScreenVisible: state['features/base/dialog']?.component === LobbyScreen,
_isParticipantsPaneVisible: getParticipantsPaneOpen(state),
_layoutClassName: LAYOUT_CLASSNAMES[getCurrentLayout(state)],
_mouseMoveCallbackInterval: mouseMoveCallbackInterval,
_roomName: getConferenceNameForTitle(state),
- _showPrejoin: isPrejoinPageVisible(state)
+ _showLobby: getIsLobbyVisible(state),
+ _showPrejoin: isPrejoinPageVisible(state) || isPrejoinPageLoading(state)
};
}
diff --git a/react/features/invite/components/add-people-dialog/web/InviteButton.js b/react/features/invite/components/add-people-dialog/web/InviteButton.js
new file mode 100644
index 0000000000..3a3ea8f2c2
--- /dev/null
+++ b/react/features/invite/components/add-people-dialog/web/InviteButton.js
@@ -0,0 +1,44 @@
+// @flow
+
+import { createToolbarEvent, sendAnalytics } from '../../../../analytics';
+import { translate } from '../../../../base/i18n';
+import { IconAddPeople } from '../../../../base/icons';
+import { connect } from '../../../../base/redux';
+import { AbstractButton, type AbstractButtonProps } from '../../../../base/toolbox/components';
+import { beginAddPeople } from '../../../actions.any';
+
+/**
+ * The type of the React {@code Component} props of {@link EmbedMeetingButton}.
+ */
+type Props = AbstractButtonProps & {
+
+ /**
+ * The redux {@code dispatch} function.
+ */
+ dispatch: Function
+};
+
+/**
+ * Implementation of a button for opening invite people dialog.
+ */
+class InviteButton extends AbstractButton {
+ accessibilityLabel = 'toolbar.accessibilityLabel.invite';
+ icon = IconAddPeople;
+ label = 'toolbar.invite';
+ tooltip = 'toolbar.invite';
+
+ /**
+ * Handles clicking / pressing the button, and opens the appropriate dialog.
+ *
+ * @protected
+ * @returns {void}
+ */
+ _handleClick() {
+ const { dispatch } = this.props;
+
+ sendAnalytics(createToolbarEvent('invite'));
+ dispatch(beginAddPeople());
+ }
+}
+
+export default translate(connect()(InviteButton));
diff --git a/react/features/invite/components/add-people-dialog/web/index.js b/react/features/invite/components/add-people-dialog/web/index.js
index f2e67e6310..1aedf86dc1 100644
--- a/react/features/invite/components/add-people-dialog/web/index.js
+++ b/react/features/invite/components/add-people-dialog/web/index.js
@@ -1,3 +1,4 @@
// @flow
export { default as AddPeopleDialog } from './AddPeopleDialog';
+export { default as InviteButton } from './InviteButton';
diff --git a/react/features/lobby/actionTypes.js b/react/features/lobby/actionTypes.js
index 8d00a46786..b734263ea1 100644
--- a/react/features/lobby/actionTypes.js
+++ b/react/features/lobby/actionTypes.js
@@ -20,6 +20,11 @@ export const SET_LOBBY_MODE_ENABLED = 'SET_LOBBY_MODE_ENABLED';
*/
export const SET_KNOCKING_STATE = 'SET_KNOCKING_STATE';
+/**
+ * Action type to set the lobby visibility.
+ */
+export const SET_LOBBY_VISIBILITY = 'TOGGLE_LOBBY_VISIBILITY';
+
/**
* Action type to set the password join failed status.
*/
diff --git a/react/features/lobby/actions.any.js b/react/features/lobby/actions.any.js
index 75f6f5b899..1c5b6ff659 100644
--- a/react/features/lobby/actions.any.js
+++ b/react/features/lobby/actions.any.js
@@ -6,6 +6,8 @@ import {
getCurrentConference
} from '../base/conference';
+import { SET_LOBBY_VISIBILITY } from './actionTypes';
+
/**
* Action to toggle lobby mode on or off.
*
@@ -23,3 +25,27 @@ export function toggleLobbyMode(enabled: boolean) {
}
};
}
+
+/**
+ * Action to open the lobby screen.
+ *
+ * @returns {openDialog}
+ */
+export function openLobbyScreen() {
+ return {
+ type: SET_LOBBY_VISIBILITY,
+ visible: true
+ };
+}
+
+/**
+ * Action to hide the lobby screen.
+ *
+ * @returns {hideDialog}
+ */
+export function hideLobbyScreen() {
+ return {
+ type: SET_LOBBY_VISIBILITY,
+ visible: false
+ };
+}
diff --git a/react/features/lobby/actions.web.js b/react/features/lobby/actions.web.js
index 8f0775afa4..48f37a7788 100644
--- a/react/features/lobby/actions.web.js
+++ b/react/features/lobby/actions.web.js
@@ -9,7 +9,6 @@ import {
sendLocalParticipant,
setPassword
} from '../base/conference';
-import { hideDialog, openDialog } from '../base/dialog';
import { getLocalParticipant } from '../base/participants';
export * from './actions.any';
@@ -20,7 +19,6 @@ import {
SET_LOBBY_MODE_ENABLED,
SET_PASSWORD_JOIN_FAILED
} from './actionTypes';
-import { LobbyScreen } from './components';
declare var APP: Object;
@@ -44,15 +42,6 @@ export function cancelKnocking() {
};
}
-/**
- * Action to hide the lobby screen.
- *
- * @returns {hideDialog}
- */
-export function hideLobbyScreen() {
- return hideDialog(LobbyScreen);
-}
-
/**
* Tries to join with a preset password.
*
@@ -83,15 +72,6 @@ export function knockingParticipantLeft(id: string) {
};
}
-/**
- * Action to open the lobby screen.
- *
- * @returns {openDialog}
- */
-export function openLobbyScreen() {
- return openDialog(LobbyScreen, {}, true);
-}
-
/**
* Action to be executed when a participant starts knocking or an already knocking participant gets updated.
*
diff --git a/react/features/lobby/components/AbstractLobbyScreen.js b/react/features/lobby/components/AbstractLobbyScreen.js
index bb8fd1a400..f2ced30c01 100644
--- a/react/features/lobby/components/AbstractLobbyScreen.js
+++ b/react/features/lobby/components/AbstractLobbyScreen.js
@@ -7,6 +7,7 @@ import { getFeatureFlag, INVITE_ENABLED } from '../../base/flags';
import { getLocalParticipant } from '../../base/participants';
import { getFieldValue } from '../../base/react';
import { updateSettings } from '../../base/settings';
+import { isDeviceStatusVisible } from '../../prejoin/functions';
import { cancelKnocking, joinWithPassword, setPasswordJoinFailed, startKnocking } from '../actions';
export const SCREEN_STATES = {
@@ -17,6 +18,11 @@ export const SCREEN_STATES = {
export type Props = {
+ /**
+ * Indicates whether the device status should be visible.
+ */
+ _deviceStatusVisible: boolean,
+
/**
* True if knocking is already happening, so we're waiting for a response.
*/
@@ -380,8 +386,10 @@ export function _mapStateToProps(state: Object): $Shape {
const { knocking, passwordJoinFailed } = state['features/lobby'];
const { iAmSipGateway } = state['features/base/config'];
const showCopyUrlButton = inviteEnabledFlag || !disableInviteFunctions;
+ const deviceStatusVisible = isDeviceStatusVisible(state);
return {
+ _deviceStatusVisible: deviceStatusVisible,
_knocking: knocking,
_meetingName: getConferenceName(state),
_participantEmail: localParticipant?.email,
diff --git a/react/features/lobby/components/native/LobbyScreen.js b/react/features/lobby/components/native/LobbyScreen.js
index b4c5711e28..16bd4d7bdc 100644
--- a/react/features/lobby/components/native/LobbyScreen.js
+++ b/react/features/lobby/components/native/LobbyScreen.js
@@ -27,15 +27,16 @@ class LobbyScreen extends AbstractLobbyScreen {
return (
-
- { t(this._getScreenTitleKey()) }
-
-
- { _meetingName }
-
- { this._renderContent() }
+ onCancel = { this._onCancel }>
+
+
+ { t(this._getScreenTitleKey()) }
+
+
+ { _meetingName }
+
+ { this._renderContent() }
+
);
}
diff --git a/react/features/lobby/components/web/LobbyScreen.js b/react/features/lobby/components/web/LobbyScreen.js
index 7d796f23d9..6fbe1fdcaa 100644
--- a/react/features/lobby/components/web/LobbyScreen.js
+++ b/react/features/lobby/components/web/LobbyScreen.js
@@ -20,11 +20,13 @@ class LobbyScreen extends AbstractLobbyScreen {
* @inheritdoc
*/
render() {
- const { showCopyUrlButton, t } = this.props;
+ const { _deviceStatusVisible, showCopyUrlButton, t } = this.props;
return (
{ this._renderContent() }
@@ -62,7 +64,7 @@ class LobbyScreen extends AbstractLobbyScreen {
*/
_renderJoining() {
return (
-
+
@@ -113,13 +115,19 @@ class LobbyScreen extends AbstractLobbyScreen {
const { _passwordJoinFailed, t } = this.props;
return (
-
+ <>
+
+
+ {_passwordJoinFailed &&
{t('lobby.invalidPassword')}
}
+ >
);
}
@@ -134,11 +142,10 @@ class LobbyScreen extends AbstractLobbyScreen {
return (
<>
- { t('lobby.passwordJoinButton') }
+ { t('prejoin.joinMeeting') }
{
...state,
lobbyEnabled: action.enabled
};
+ case SET_LOBBY_VISIBILITY:
+ return {
+ ...state,
+ lobbyVisible: action.visible
+ };
case SET_PASSWORD:
return {
...state,
diff --git a/react/features/prejoin/actions.js b/react/features/prejoin/actions.js
index 0b271448f0..f470ce22c6 100644
--- a/react/features/prejoin/actions.js
+++ b/react/features/prejoin/actions.js
@@ -33,6 +33,7 @@ import {
SET_PREJOIN_DEVICE_ERRORS,
SET_PREJOIN_PAGE_VISIBILITY
} from './actionTypes';
+import { type PREJOIN_SCREEN_STATE } from './constants';
import {
getFullDialOutNumber,
getDialOutConferenceUrl,
@@ -480,10 +481,10 @@ export function setPrejoinDeviceErrors(value: Object) {
/**
* Action used to set the visibility of the prejoin page.
*
- * @param {boolean} value - The value.
+ * @param {string} value - The value.
* @returns {Object}
*/
-export function setPrejoinPageVisibility(value: boolean) {
+export function setPrejoinPageVisibility(value: PREJOIN_SCREEN_STATE) {
return {
type: SET_PREJOIN_PAGE_VISIBILITY,
value
diff --git a/react/features/prejoin/components/Prejoin.js b/react/features/prejoin/components/Prejoin.js
index b1bc773da0..124642a9b3 100644
--- a/react/features/prejoin/components/Prejoin.js
+++ b/react/features/prejoin/components/Prejoin.js
@@ -4,7 +4,6 @@ import InlineDialog from '@atlaskit/inline-dialog';
import React, { Component } from 'react';
import { getRoomName } from '../../base/conference';
-import { getToolbarButtons } from '../../base/config';
import { translate } from '../../base/i18n';
import { Icon, IconArrowDown, IconArrowUp, IconPhone, IconVolumeOff } from '../../base/icons';
import { isVideoMutedByUser } from '../../base/media';
@@ -12,7 +11,6 @@ import { ActionButton, InputField, PreMeetingScreen, ToggleButton } from '../../
import { connect } from '../../base/redux';
import { getDisplayName, updateSettings } from '../../base/settings';
import { getLocalJitsiVideoTrack } from '../../base/tracks';
-import { isButtonEnabled } from '../../toolbox/functions.web';
import {
joinConference as joinConferenceAction,
joinConferenceWithoutAudio as joinConferenceWithoutAudioAction,
@@ -28,9 +26,6 @@ import {
} from '../functions';
import JoinByPhoneDialog from './dialogs/JoinByPhoneDialog';
-import DeviceStatus from './preview/DeviceStatus';
-
-declare var interfaceConfig: Object;
type Props = {
@@ -84,11 +79,6 @@ type Props = {
*/
setJoinByPhoneDialogVisiblity: Function,
- /**
- * Indicates whether the avatar should be shown when video is off
- */
- showAvatar: boolean,
-
/**
* Flag signaling the visibility of camera preview.
*/
@@ -99,26 +89,11 @@ type Props = {
*/
showErrorOnJoin: boolean,
- /**
- * Flag signaling the visibility of join label, input and buttons
- */
- showJoinActions: boolean,
-
- /**
- * Flag signaling the visibility of the conference URL section.
- */
- showConferenceInfo: boolean,
-
/**
* If 'JoinByPhoneDialog' is visible or not.
*/
showDialog: boolean,
- /**
- * Flag signaling the visibility of the skip prejoin toggle
- */
- showSkipPrejoin: boolean,
-
/**
* Used for translation.
*/
@@ -127,12 +102,7 @@ type Props = {
/**
* The JitsiLocalTrack to display.
*/
- videoTrack: ?Object,
-
- /**
- * Array with the buttons which this Toolbox should display.
- */
- visibleButtons: Array
+ videoTrack: ?Object
};
type State = {
@@ -152,17 +122,6 @@ type State = {
* This component is displayed before joining a meeting.
*/
class Prejoin extends Component {
- /**
- * Default values for {@code Prejoin} component's properties.
- *
- * @static
- */
- static defaultProps = {
- showConferenceInfo: true,
- showJoinActions: true,
- showSkipPrejoin: true
- };
-
/**
* Initializes a new {@code Prejoin} instance.
*
@@ -344,18 +303,15 @@ class Prejoin extends Component {
*/
render() {
const {
+ deviceStatusVisible,
hasJoinByPhoneButton,
joinConference,
joinConferenceWithoutAudio,
name,
- showAvatar,
showCameraPreview,
showDialog,
- showConferenceInfo,
- showJoinActions,
t,
- videoTrack,
- visibleButtons
+ videoTrack
} = this.props;
const { _closeDialog, _onDropdownClose, _onJoinButtonClick, _onJoinKeyPress, _showDialogKeyPress,
@@ -364,89 +320,78 @@ class Prejoin extends Component {
return (
- {showJoinActions && (
-
-
-
- { t('dialog.enterDisplayNameToJoin') }
-
+ videoTrack = { videoTrack }>
+
+
- {showError &&
{t('prejoin.errorMissingName')}
}
+ {showError &&
{t('prejoin.errorMissingName')}
}
-
-
-
-
- { t('prejoin.joinWithoutAudio') }
-
- {hasJoinByPhoneButton &&
-
- { t('prejoin.joinAudioByPhone') }
-
}
- }
- isOpen = { showJoinByPhoneButtons }
- onClose = { _onDropdownClose }>
-
- { t('prejoin.joinMeeting') }
-
-
-
-
+
+
+
+
+ { t('prejoin.joinWithoutAudio') }
+
+ {hasJoinByPhoneButton &&
+
+ { t('prejoin.joinAudioByPhone') }
+
}
+ }
+ isOpen = { showJoinByPhoneButtons }
+ onClose = { _onDropdownClose }>
+
+ { t('prejoin.joinMeeting') }
+
+
- )}
+
{ showDialog && (
{
);
}
- /**
- * Renders the screen footer if any.
- *
- * @returns {React$Element}
- */
- _renderFooter() {
- return this.props.deviceStatusVisible && ;
- }
-
/**
* Renders the 'skip prejoin' button.
*
* @returns {React$Element}
*/
_renderSkipPrejoinButton() {
- const { buttonIsToggled, t, showSkipPrejoin } = this.props;
-
- if (!showSkipPrejoin) {
- return null;
- }
+ const { buttonIsToggled, t } = this.props;
return (
@@ -493,22 +425,11 @@ class Prejoin extends Component
{
* Maps (parts of) the redux state to the React {@code Component} props.
*
* @param {Object} state - The redux state.
- * @param {Object} ownProps - The props passed to the component.
* @returns {Object}
*/
-function mapStateToProps(state, ownProps): Object {
+function mapStateToProps(state): Object {
const name = getDisplayName(state);
const showErrorOnJoin = isDisplayNameRequired(state) && !name;
- const { showJoinActions } = ownProps;
- const isInviteButtonEnabled = isButtonEnabled('invite', state);
-
- // Hide conference info when interfaceConfig is available and the invite button is disabled.
- // In all other cases we want to preserve the behaviour and control the the conference info
- // visibility through showJoinActions.
- const showConferenceInfo
- = typeof isInviteButtonEnabled === 'undefined' || isInviteButtonEnabled === true
- ? showJoinActions
- : false;
return {
buttonIsToggled: isPrejoinSkipped(state),
@@ -519,9 +440,7 @@ function mapStateToProps(state, ownProps): Object {
showErrorOnJoin,
hasJoinByPhoneButton: isJoinByPhoneButtonVisible(state),
showCameraPreview: !isVideoMutedByUser(state),
- showConferenceInfo,
- videoTrack: getLocalJitsiVideoTrack(state),
- visibleButtons: getToolbarButtons(state)
+ videoTrack: getLocalJitsiVideoTrack(state)
};
}
diff --git a/react/features/prejoin/components/PrejoinApp.js b/react/features/prejoin/components/PrejoinApp.js
index 579a771991..afdb945734 100644
--- a/react/features/prejoin/components/PrejoinApp.js
+++ b/react/features/prejoin/components/PrejoinApp.js
@@ -9,27 +9,18 @@ import { getConferenceOptions } from '../../base/conference/functions';
import { setConfig } from '../../base/config';
import { DialogContainer } from '../../base/dialog';
import { createPrejoinTracks } from '../../base/tracks';
+import JitsiThemeProvider from '../../base/ui/components/JitsiThemeProvider';
import { initPrejoin, makePrecallTest } from '../actions';
-import Prejoin from './Prejoin';
+import PrejoinThirdParty from './PrejoinThirdParty';
type Props = {
/**
- * Indicates whether the avatar should be shown when video is off
+ * Indicates the style type that needs to be applied.
*/
- showAvatar: boolean,
-
- /**
- * Flag signaling the visibility of join label, input and buttons
- */
- showJoinActions: boolean,
-
- /**
- * Flag signaling the visibility of the skip prejoin toggle
- */
- showSkipPrejoin: boolean,
-};
+ styleType: string
+}
/**
* Wrapper application for prejoin.
@@ -50,14 +41,12 @@ export default class PrejoinApp extends BaseApp {
this._init.then(async () => {
const { store } = this.state;
const { dispatch } = store;
- const { showAvatar, showJoinActions, showSkipPrejoin } = this.props;
+ const { styleType } = this.props;
super._navigate({
- component: Prejoin,
+ component: PrejoinThirdParty,
props: {
- showAvatar,
- showJoinActions,
- showSkipPrejoin
+ className: styleType
}
});
@@ -88,9 +77,11 @@ export default class PrejoinApp extends BaseApp {
*/
_createMainElement(component, props) {
return (
-
- { super._createMainElement(component, props) }
-
+
+
+ { super._createMainElement(component, props) }
+
+
);
}
@@ -101,9 +92,11 @@ export default class PrejoinApp extends BaseApp {
*/
_renderDialogContainer() {
return (
-
-
-
+
+
+
+
+
);
}
}
diff --git a/react/features/prejoin/components/PrejoinThirdParty.js b/react/features/prejoin/components/PrejoinThirdParty.js
new file mode 100644
index 0000000000..9e64a506ba
--- /dev/null
+++ b/react/features/prejoin/components/PrejoinThirdParty.js
@@ -0,0 +1,87 @@
+// @flow
+
+import React, { Component } from 'react';
+
+import { translate } from '../../base/i18n';
+import { isVideoMutedByUser } from '../../base/media';
+import { PreMeetingScreen } from '../../base/premeeting';
+import { connect } from '../../base/redux';
+import { getLocalJitsiVideoTrack } from '../../base/tracks';
+import { isDeviceStatusVisible } from '../functions';
+
+type Props = {
+
+ /**
+ * Indicates the className that needs to be applied.
+ */
+ className: string,
+
+ /**
+ * Flag signaling if the device status is visible or not.
+ */
+ deviceStatusVisible: boolean,
+
+ /**
+ * Flag signaling the visibility of camera preview.
+ */
+ showCameraPreview: boolean,
+
+ /**
+ * Used for translation.
+ */
+ t: Function,
+
+ /**
+ * The JitsiLocalTrack to display.
+ */
+ videoTrack: ?Object
+};
+
+const buttons = [ 'microphone', 'camera', 'select-background' ];
+
+/**
+ * This component is displayed before joining a meeting.
+ */
+class PrejoinThirdParty extends Component {
+ /**
+ * Implements React's {@link Component#render()}.
+ *
+ * @inheritdoc
+ * @returns {ReactElement}
+ */
+ render() {
+ const {
+ className,
+ deviceStatusVisible,
+ showCameraPreview,
+ videoTrack
+ } = this.props;
+
+ return (
+
+ );
+ }
+}
+
+/**
+ * Maps (parts of) the redux state to the React {@code Component} props.
+ *
+ * @param {Object} state - The redux state.
+ * @param {Object} ownProps - The props passed to the component.
+ * @returns {Object}
+ */
+function mapStateToProps(state): Object {
+ return {
+ deviceStatusVisible: isDeviceStatusVisible(state),
+ showCameraPreview: !isVideoMutedByUser(state),
+ videoTrack: getLocalJitsiVideoTrack(state)
+ };
+}
+
+export default connect(mapStateToProps)(translate(PrejoinThirdParty));
diff --git a/react/features/prejoin/components/preview/DeviceStatus.js b/react/features/prejoin/components/preview/DeviceStatus.js
index 12f5a0c951..522db73b49 100644
--- a/react/features/prejoin/components/preview/DeviceStatus.js
+++ b/react/features/prejoin/components/preview/DeviceStatus.js
@@ -3,7 +3,7 @@
import React from 'react';
import { translate } from '../../../base/i18n';
-import { Icon, IconCheck, IconExclamation } from '../../../base/icons';
+import { Icon, IconCheckSolid, IconExclamation } from '../../../base/icons';
import { connect } from '../../../base/redux';
import {
getDeviceStatusType,
@@ -38,11 +38,11 @@ export type Props = {
const iconMap = {
warning: {
src: IconExclamation,
- className: 'prejoin-preview-status--warning'
+ className: 'device-icon--warning'
},
ok: {
- src: IconCheck,
- className: 'prejoin-preview-status--ok'
+ src: IconCheckSolid,
+ className: 'device-icon--ok'
}
};
@@ -57,15 +57,14 @@ function DeviceStatus({ deviceStatusType, deviceStatusText, rawError, t }: Props
return (
{t(deviceStatusText)}
diff --git a/react/features/prejoin/constants.js b/react/features/prejoin/constants.js
new file mode 100644
index 0000000000..4200dbdece
--- /dev/null
+++ b/react/features/prejoin/constants.js
@@ -0,0 +1,19 @@
+// @flow
+
+export type PREJOIN_SCREEN_STATE = "hidden" | "loading" | true;
+
+
+type PREJOIN_SCREEN_STATE_TYPE = {
+ HIDDEN: PREJOIN_SCREEN_STATE,
+ LOADING: PREJOIN_SCREEN_STATE,
+ VISIBLE: PREJOIN_SCREEN_STATE
+ }
+
+/**
+ * Enum of possible prejoin screen states.
+ */
+export const PREJOIN_SCREEN_STATES: PREJOIN_SCREEN_STATE_TYPE = {
+ HIDDEN: 'hidden',
+ LOADING: 'loading',
+ VISIBLE: true // backwards compatibility with old boolean implementation
+};
diff --git a/react/features/prejoin/functions.js b/react/features/prejoin/functions.js
index 511429e4ce..f6da9dbd35 100644
--- a/react/features/prejoin/functions.js
+++ b/react/features/prejoin/functions.js
@@ -4,6 +4,8 @@ import { getRoomName } from '../base/conference';
import { getDialOutStatusUrl, getDialOutUrl } from '../base/config/functions';
import { isAudioMuted, isVideoMutedByUser } from '../base/media';
+import { PREJOIN_SCREEN_STATES } from './constants';
+
/**
* Selector for the visibility of the 'join by phone' button.
*
@@ -160,7 +162,17 @@ export function isPrejoinPageEnabled(state: Object): boolean {
* @returns {boolean}
*/
export function isPrejoinPageVisible(state: Object): boolean {
- return isPrejoinPageEnabled(state) && state['features/prejoin']?.showPrejoin;
+ return isPrejoinPageEnabled(state) && state['features/prejoin']?.showPrejoin === PREJOIN_SCREEN_STATES.VISIBLE;
+}
+
+/**
+ * Returns true if the prejoin page is loading.
+ *
+ * @param {Object} state - The state of the app.
+ * @returns {boolean}
+ */
+export function isPrejoinPageLoading(state: Object): boolean {
+ return isPrejoinPageEnabled(state) && state['features/prejoin']?.showPrejoin === PREJOIN_SCREEN_STATES.LOADING;
}
/**
diff --git a/react/features/prejoin/middleware.js b/react/features/prejoin/middleware.js
index 0feadb4ebf..f6dbc66217 100644
--- a/react/features/prejoin/middleware.js
+++ b/react/features/prejoin/middleware.js
@@ -1,5 +1,6 @@
// @flow
+import { CONFERENCE_JOINED } from '../base/conference';
import { updateConfig } from '../base/config';
import { SET_AUDIO_MUTED, SET_VIDEO_MUTED } from '../base/media';
import { MiddlewareRegistry } from '../base/redux';
@@ -17,6 +18,7 @@ import {
setDeviceStatusWarning,
setPrejoinPageVisibility
} from './actions';
+import { PREJOIN_SCREEN_STATES } from './constants';
import { isPrejoinPageVisible } from './functions';
declare var APP: Object;
@@ -56,7 +58,8 @@ MiddlewareRegistry.register(store => next => async action => {
const jitsiTracks = localTracks.map(t => t.jitsiTrack);
- dispatch(setPrejoinPageVisibility(false));
+ dispatch(setPrejoinPageVisibility(PREJOIN_SCREEN_STATES.LOADING));
+
APP.conference.prejoinStart(jitsiTracks);
break;
@@ -103,8 +106,23 @@ MiddlewareRegistry.register(store => next => async action => {
}
break;
}
-
+ case CONFERENCE_JOINED:
+ return _conferenceJoined(store, next, action);
}
return next(action);
});
+
+/**
+ * Handles cleanup of prejoin state when a conference is joined.
+ *
+ * @param {Object} store - The Redux store.
+ * @param {Function} next - The Redux next function.
+ * @param {Object} action - The Redux action.
+ * @returns {Object}
+ */
+function _conferenceJoined({ dispatch }, next, action) {
+ dispatch(setPrejoinPageVisibility(PREJOIN_SCREEN_STATES.HIDDEN));
+
+ return next(action);
+}
diff --git a/react/features/settings/actions.js b/react/features/settings/actions.js
index c793cf25b5..cf0c9e3d84 100644
--- a/react/features/settings/actions.js
+++ b/react/features/settings/actions.js
@@ -5,6 +5,7 @@ import { openDialog } from '../base/dialog';
import { i18next } from '../base/i18n';
import { updateSettings } from '../base/settings';
import { setPrejoinPageVisibility } from '../prejoin/actions';
+import { PREJOIN_SCREEN_STATES } from '../prejoin/constants';
import { setScreenshareFramerate } from '../screen-share/actions';
import {
@@ -84,7 +85,7 @@ export function submitMoreTab(newState: Object): Function {
// The 'showPrejoin' flag starts as 'true' on every new session.
// This prevents displaying the prejoin page when the user re-enables it.
if (showPrejoinPage && getState()['features/prejoin']?.showPrejoin) {
- dispatch(setPrejoinPageVisibility(false));
+ dispatch(setPrejoinPageVisibility(PREJOIN_SCREEN_STATES.HIDDEN));
}
dispatch(updateSettings({
userSelectedSkipPrejoin: !showPrejoinPage
diff --git a/react/features/toolbox/components/web/Toolbox.js b/react/features/toolbox/components/web/Toolbox.js
index 36b1602ac0..bb1f692175 100644
--- a/react/features/toolbox/components/web/Toolbox.js
+++ b/react/features/toolbox/components/web/Toolbox.js
@@ -28,6 +28,7 @@ import { DominantSpeakerName } from '../../../display-name';
import { EmbedMeetingButton } from '../../../embed-meeting';
import { SharedDocumentButton } from '../../../etherpad';
import { FeedbackButton } from '../../../feedback';
+import { InviteButton } from '../../../invite/components/add-people-dialog';
import { isVpaasMeeting } from '../../../jaas/functions';
import { KeyboardShortcutsButton } from '../../../keyboard-shortcuts';
import { LocalRecordingButton } from '../../../local-recording';
@@ -66,7 +67,6 @@ import { VideoQualityDialog, VideoQualityButton } from '../../../video-quality/c
import { VideoBackgroundButton } from '../../../virtual-background';
import { toggleBackgroundEffect } from '../../../virtual-background/actions';
import { VIRTUAL_BACKGROUND_TYPE } from '../../../virtual-background/constants';
-import { checkBlurSupport } from '../../../virtual-background/functions';
import {
setFullScreen,
setOverflowMenuVisible,
@@ -207,11 +207,6 @@ type Props = {
*/
_visible: boolean,
- /**
- * Array with the buttons which this Toolbox should display.
- */
- _visibleButtons: Array
,
-
/**
* Returns the selected virtual source object.
*/
@@ -230,7 +225,12 @@ type Props = {
/**
* Invoked to obtain translated strings.
*/
- t: Function
+ t: Function,
+
+ /**
+ * Explicitly passed array with the buttons which this Toolbox should display.
+ */
+ toolbarButtons: Array,
};
declare var APP: Object;
@@ -399,9 +399,9 @@ class Toolbox extends Component {
* @returns {ReactElement}
*/
render() {
- const { _chatOpen, _visible, _visibleButtons } = this.props;
+ const { _chatOpen, _visible, _toolbarButtons } = this.props;
const rootClassNames = `new-toolbox ${_visible ? 'visible' : ''} ${
- _visibleButtons.length ? '' : 'no-buttons'} ${_chatOpen ? 'shift-right' : ''}`;
+ _toolbarButtons.length ? '' : 'no-buttons'} ${_chatOpen ? 'shift-right' : ''}`;
return (
{
const participants = {
key: 'participants-pane',
- alias: 'invite',
Content: ParticipantsPaneButton,
handleClick: this._onToolbarToggleParticipantsPane,
group: 2
};
+ const invite = {
+ key: 'invite',
+ Content: InviteButton,
+ group: 2
+ };
+
const tileview = {
key: 'tileview',
Content: TileViewButton,
@@ -691,7 +696,7 @@ class Toolbox extends Component
{
group: 3
};
- const virtualBackground = !_screenSharing && checkBlurSupport() && {
+ const virtualBackground = !_screenSharing && {
key: 'select-background',
Content: VideoBackgroundButton,
group: 3
@@ -747,6 +752,7 @@ class Toolbox extends Component {
chat,
raisehand,
participants,
+ invite,
tileview,
toggleCamera,
videoQuality,
@@ -1238,10 +1244,11 @@ class Toolbox extends Component {
* props.
*
* @param {Object} state - The redux store/state.
+ * @param {Object} ownProps - The props explicitly passed.
* @private
* @returns {{}}
*/
-function _mapStateToProps(state) {
+function _mapStateToProps(state, ownProps) {
const { conference } = state['features/base/conference'];
let desktopSharingEnabled = JitsiMeetJS.isDesktopSharingEnabled();
const {
@@ -1268,6 +1275,15 @@ function _mapStateToProps(state) {
}
}
+ let { toolbarButtons } = ownProps;
+ const stateToolbarButtons = getToolbarButtons(state);
+
+ if (toolbarButtons) {
+ toolbarButtons = toolbarButtons.filter(name => isToolbarButtonEnabled(name, stateToolbarButtons));
+ } else {
+ toolbarButtons = stateToolbarButtons;
+ }
+
return {
_chatOpen: state['features/chat'].isOpen,
_clientWidth: clientWidth,
@@ -1289,9 +1305,8 @@ function _mapStateToProps(state) {
_participantsPaneOpen: getParticipantsPaneOpen(state),
_raisedHand: localParticipant?.raisedHand,
_screenSharing: isScreenVideoShared(state),
- _toolbarButtons: getToolbarButtons(state),
+ _toolbarButtons: toolbarButtons,
_visible: isToolboxVisible(state),
- _visibleButtons: getToolbarButtons(state),
_reactionsEnabled: enableReactions
};
}
diff --git a/react/features/virtual-background/components/VideoBackgroundButton.js b/react/features/virtual-background/components/VideoBackgroundButton.js
index 3afb24917f..42d474ca28 100644
--- a/react/features/virtual-background/components/VideoBackgroundButton.js
+++ b/react/features/virtual-background/components/VideoBackgroundButton.js
@@ -6,6 +6,7 @@ import { IconVirtualBackground } from '../../base/icons';
import { connect } from '../../base/redux';
import { AbstractButton } from '../../base/toolbox/components';
import type { AbstractButtonProps } from '../../base/toolbox/components';
+import { checkBlurSupport } from '../functions';
import { VirtualBackgroundDialog } from './index';
@@ -72,7 +73,8 @@ class VideoBackgroundButton extends AbstractButton {
function _mapStateToProps(state): Object {
return {
- _isBackgroundEnabled: Boolean(state['features/virtual-background'].backgroundEffectEnabled)
+ _isBackgroundEnabled: Boolean(state['features/virtual-background'].backgroundEffectEnabled),
+ visible: checkBlurSupport()
};
}
diff --git a/static/prejoin.html b/static/prejoin.html
index 8ce110a529..e0156b2bee 100644
--- a/static/prejoin.html
+++ b/static/prejoin.html
@@ -13,16 +13,12 @@
const url = new URL(window.location.href);
const params = new URLSearchParams(url.search);
- const showAvatar = params.get('showAvatar') === 'true';
- const showJoinActions = params.get('showJoinActions') === 'true';
- const showSkipPrejoin = params.get('showSkipPrejoin') === 'true';
+ const styleType = params.get('styleType');
JitsiMeetJS.app.renderEntryPoint({
Component: JitsiMeetJS.app.entryPoints.PREJOIN,
props: {
- showAvatar,
- showJoinActions,
- showSkipPrejoin
+ styleType
}
})
})