mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-09-14 09:08:40 +00:00
Compare commits
21 Commits
7074
...
fix-remote
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a8707d778 | ||
|
|
16115a3a16 | ||
|
|
7c17d80ae8 | ||
|
|
511548060a | ||
|
|
00780929e5 | ||
|
|
a89f762a66 | ||
|
|
82a03c36c6 | ||
|
|
7968578a25 | ||
|
|
62b6411bb6 | ||
|
|
b3bce9e5ae | ||
|
|
ed37bedee2 | ||
|
|
2182a1e452 | ||
|
|
4eea924c02 | ||
|
|
de3b6d2a9f | ||
|
|
2a090d8034 | ||
|
|
238def34cf | ||
|
|
43c4ec0808 | ||
|
|
7910554625 | ||
|
|
56d2af197e | ||
|
|
466a36dc93 | ||
|
|
1fc5d6e97e |
19
config.js
19
config.js
@@ -197,6 +197,22 @@ var config = {
|
||||
// enableOpusDtx: false,
|
||||
// },
|
||||
|
||||
// Noise suppression configuration. By default rnnoise is used. Optionally Krisp
|
||||
// can be used by enabling it below, but the Krisp JS SDK files must be supplied in your
|
||||
// installation. Specifically, these files are needed:
|
||||
// - https://meet.example.com/libs/krisp/krisp.mjs
|
||||
// - https://meet.example.com/libs/krisp/models/model_8.kw
|
||||
// - https://meet.example.com/libs/krisp/models/model_16.kw
|
||||
// - https://meet.example.com/libs/krisp/models/model_32.kw
|
||||
// NOTE: Krisp JS SDK v1.0.9 was tested.
|
||||
// noiseSuppression: {
|
||||
// krisp: {
|
||||
// enabled: false,
|
||||
// logProcessStats: false,
|
||||
// debugLogs: false,
|
||||
// },
|
||||
// },
|
||||
|
||||
// Video
|
||||
|
||||
// Sets the preferred resolution (height) for local video. Defaults to 720.
|
||||
@@ -574,6 +590,9 @@ var config = {
|
||||
// Require users to always specify a display name.
|
||||
// requireDisplayName: true,
|
||||
|
||||
// Enables webhid functionality for Audio.
|
||||
// enableWebHIDFeature: false,
|
||||
|
||||
// DEPRECATED! Use 'welcomePage.disabled' instead.
|
||||
// Whether to use a welcome page or not. In case it's false a random room
|
||||
// will be joined when no room is specified.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
position: relative;
|
||||
right: auto;
|
||||
margin-bottom: 4px;
|
||||
max-height: 456px;
|
||||
max-height: calc(100vh - 100px);
|
||||
overflow: auto;
|
||||
width: 300px;
|
||||
|
||||
|
||||
@@ -1,49 +1,27 @@
|
||||
/**
|
||||
* Mousemove padding styles are used to add invisible elements to the popover
|
||||
* to allow mouse movement from the popover trigger to the popover itself
|
||||
* without triggering a mouseleave event.
|
||||
*/
|
||||
%vertical-popover-padding {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 20px;
|
||||
padding: 20px 0;
|
||||
top: -20px;
|
||||
}
|
||||
|
||||
%horizontal-popover-padding {
|
||||
height: 25px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
padding: 0 35px;
|
||||
left: -35px;
|
||||
}
|
||||
|
||||
.popover-mousemove-padding-left {
|
||||
@extend %vertical-popover-padding;
|
||||
left: -35px;
|
||||
}
|
||||
|
||||
.popover-mousemove-padding-right {
|
||||
@extend %vertical-popover-padding;
|
||||
right: -35px;
|
||||
}
|
||||
|
||||
.popover-mousemove-padding-bottom {
|
||||
@extend %horizontal-popover-padding;
|
||||
bottom: -40px;
|
||||
}
|
||||
|
||||
.popover-mousemove-padding-top {
|
||||
@extend %horizontal-popover-padding;
|
||||
top: -40px;
|
||||
}
|
||||
|
||||
.popover {
|
||||
margin: -16px -24px;
|
||||
z-index: $popoverZ;
|
||||
|
||||
.popover-content {
|
||||
margin: 16px 24px;
|
||||
position: relative;
|
||||
|
||||
&.top {
|
||||
bottom: 8px;
|
||||
}
|
||||
|
||||
&.bottom {
|
||||
top: 8px;
|
||||
}
|
||||
|
||||
&.left {
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
&.right {
|
||||
left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.excalidraw .popover {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
width: 280px;
|
||||
background: $menuBG;
|
||||
box-shadow: 0px 3px 16px rgba(0, 0, 0, 0.6), 0px 0px 4px 1px rgba(0, 0, 0, 0.25);
|
||||
border-radius: 3px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
|
||||
&.with-gif {
|
||||
@@ -104,10 +104,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.reactions-menu-container {
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.reactions-animations-container {
|
||||
position: absolute;
|
||||
width: 20%;
|
||||
|
||||
@@ -3,30 +3,33 @@
|
||||
display: block;
|
||||
|
||||
#enter_room {
|
||||
position: relative;
|
||||
height: 42px;
|
||||
|
||||
.welcome-page-button {
|
||||
font-size: 16px;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 68px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: #002637;
|
||||
|
||||
.insecure-room-name-warning {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#enter_room {
|
||||
.enter-room-input-container {
|
||||
padding-right: 0;
|
||||
width: 100%;
|
||||
|
||||
.join-meeting-container {
|
||||
padding: 0;
|
||||
flex-direction: column;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.warning-without-link,
|
||||
.warning-with-link {
|
||||
top: 120px;
|
||||
.enter-room-input-container {
|
||||
padding-right: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,20 +34,20 @@
|
||||
background: #F2F3F4;
|
||||
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
|
||||
|
||||
& > svg {
|
||||
& svg {
|
||||
fill: #040404;
|
||||
}
|
||||
|
||||
&.settings-button-small-icon--disabled {
|
||||
background: #36383C;
|
||||
|
||||
&> svg {
|
||||
& svg {
|
||||
fill: #929292;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& > svg {
|
||||
& svg {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
background-color: #36383c;
|
||||
cursor: default;
|
||||
|
||||
&> svg {
|
||||
& svg {
|
||||
fill: #929292;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ $welcomePageHeaderBackground: linear-gradient(0deg, rgba(0, 0, 0, 0.2), rgba(0,
|
||||
$welcomePageHeaderBackgroundPosition: center;
|
||||
$welcomePageHeaderBackgroundRepeat: none;
|
||||
$welcomePageHeaderBackgroundSize: cover;
|
||||
$welcomePageHeaderPaddingBottom: 0px;
|
||||
$welcomePageHeaderPaddingBottom: 15px;
|
||||
$welcomePageHeaderTitleMaxWidth: initial;
|
||||
$welcomePageHeaderTextAlign: center;
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ body.welcome-page {
|
||||
background-size: $welcomePageHeaderBackgroundSize;
|
||||
padding-bottom: $welcomePageHeaderPaddingBottom;
|
||||
background-color: #131519;
|
||||
height: 400px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
@@ -62,26 +61,58 @@ body.welcome-page {
|
||||
|
||||
}
|
||||
|
||||
.insecure-room-name-warning {
|
||||
align-items: center;
|
||||
color: $defaultWarningColor;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-top: 15px;
|
||||
max-width: 480px;
|
||||
width: $welcomePageEnterRoomWidth;
|
||||
|
||||
.jitsi-icon {
|
||||
margin-right: 15px;
|
||||
|
||||
svg {
|
||||
fill: $defaultWarningColor;
|
||||
|
||||
& > *:first-child {
|
||||
fill: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color: #253858;
|
||||
}
|
||||
|
||||
#enter_room {
|
||||
display: $welcomePageEnterRoomDisplay;
|
||||
align-items: center;
|
||||
max-width: 480px;
|
||||
width: $welcomePageEnterRoomWidth;
|
||||
z-index: $zindex2;
|
||||
background-color: #fff;
|
||||
padding: $welcomePageEnterRoomPadding;
|
||||
border-radius: 4px;
|
||||
margin: $welcomePageEnterRoomMargin;
|
||||
height: fit-content;
|
||||
|
||||
.enter-room-input-container {
|
||||
.join-meeting-container {
|
||||
margin: $welcomePageEnterRoomMargin;
|
||||
padding: $welcomePageEnterRoomPadding;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
color: #253858;
|
||||
}
|
||||
|
||||
.enter-room-input-container {
|
||||
flex-grow: 1;
|
||||
height: fit-content;
|
||||
padding-right: 4px;
|
||||
position: relative;
|
||||
|
||||
.enter-room-input {
|
||||
border-radius: 4px;
|
||||
border: 0;
|
||||
background: #fff;
|
||||
display: inline-block;
|
||||
@@ -94,44 +125,13 @@ body.welcome-page {
|
||||
outline: auto 2px #005fcc;
|
||||
}
|
||||
}
|
||||
|
||||
.insecure-room-name-warning {
|
||||
align-items: center;
|
||||
color: $defaultWarningColor;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-top: 15px;
|
||||
|
||||
.jitsi-icon {
|
||||
margin-right: 15px;
|
||||
|
||||
svg {
|
||||
fill: $defaultWarningColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color: #253858;
|
||||
}
|
||||
}
|
||||
|
||||
.warning-without-link {
|
||||
position: absolute;
|
||||
top: 44px;
|
||||
left: -10px;
|
||||
}
|
||||
|
||||
.warning-with-link {
|
||||
position: absolute;
|
||||
top: 84px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#moderated-meetings {
|
||||
max-width: calc(100% - 40px);
|
||||
padding: 16px 0 39px 0;
|
||||
padding: 16px 0 0;
|
||||
width: $welcomePageEnterRoomWidth;
|
||||
text-align: center;
|
||||
|
||||
|
||||
430
ios/Podfile.lock
430
ios/Podfile.lock
@@ -13,14 +13,14 @@ PODS:
|
||||
- CocoaLumberjack/Core (= 3.7.2)
|
||||
- CocoaLumberjack/Core (3.7.2)
|
||||
- DoubleConversion (1.1.6)
|
||||
- FBLazyVector (0.68.5)
|
||||
- FBReactNativeSpec (0.68.5):
|
||||
- FBLazyVector (0.68.6)
|
||||
- FBReactNativeSpec (0.68.6):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTRequired (= 0.68.5)
|
||||
- RCTTypeSafety (= 0.68.5)
|
||||
- React-Core (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- RCTRequired (= 0.68.6)
|
||||
- RCTTypeSafety (= 0.68.6)
|
||||
- React-Core (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- ReactCommon/turbomodule/core (= 0.68.6)
|
||||
- Firebase/Analytics (8.15.0):
|
||||
- Firebase/Core
|
||||
- Firebase/Core (8.15.0):
|
||||
@@ -163,201 +163,201 @@ PODS:
|
||||
- DoubleConversion
|
||||
- fmt (~> 6.2.1)
|
||||
- glog
|
||||
- RCTRequired (0.68.5)
|
||||
- RCTTypeSafety (0.68.5):
|
||||
- FBLazyVector (= 0.68.5)
|
||||
- RCTRequired (0.68.6)
|
||||
- RCTTypeSafety (0.68.6):
|
||||
- FBLazyVector (= 0.68.6)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTRequired (= 0.68.5)
|
||||
- React-Core (= 0.68.5)
|
||||
- React (0.68.5):
|
||||
- React-Core (= 0.68.5)
|
||||
- React-Core/DevSupport (= 0.68.5)
|
||||
- React-Core/RCTWebSocket (= 0.68.5)
|
||||
- React-RCTActionSheet (= 0.68.5)
|
||||
- React-RCTAnimation (= 0.68.5)
|
||||
- React-RCTBlob (= 0.68.5)
|
||||
- React-RCTImage (= 0.68.5)
|
||||
- React-RCTLinking (= 0.68.5)
|
||||
- React-RCTNetwork (= 0.68.5)
|
||||
- React-RCTSettings (= 0.68.5)
|
||||
- React-RCTText (= 0.68.5)
|
||||
- React-RCTVibration (= 0.68.5)
|
||||
- React-callinvoker (0.68.5)
|
||||
- React-Codegen (0.68.5):
|
||||
- FBReactNativeSpec (= 0.68.5)
|
||||
- RCTRequired (= 0.68.6)
|
||||
- React-Core (= 0.68.6)
|
||||
- React (0.68.6):
|
||||
- React-Core (= 0.68.6)
|
||||
- React-Core/DevSupport (= 0.68.6)
|
||||
- React-Core/RCTWebSocket (= 0.68.6)
|
||||
- React-RCTActionSheet (= 0.68.6)
|
||||
- React-RCTAnimation (= 0.68.6)
|
||||
- React-RCTBlob (= 0.68.6)
|
||||
- React-RCTImage (= 0.68.6)
|
||||
- React-RCTLinking (= 0.68.6)
|
||||
- React-RCTNetwork (= 0.68.6)
|
||||
- React-RCTSettings (= 0.68.6)
|
||||
- React-RCTText (= 0.68.6)
|
||||
- React-RCTVibration (= 0.68.6)
|
||||
- React-callinvoker (0.68.6)
|
||||
- React-Codegen (0.68.6):
|
||||
- FBReactNativeSpec (= 0.68.6)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTRequired (= 0.68.5)
|
||||
- RCTTypeSafety (= 0.68.5)
|
||||
- React-Core (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-Core (0.68.5):
|
||||
- RCTRequired (= 0.68.6)
|
||||
- RCTTypeSafety (= 0.68.6)
|
||||
- React-Core (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsiexecutor (= 0.68.6)
|
||||
- ReactCommon/turbomodule/core (= 0.68.6)
|
||||
- React-Core (0.68.6):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-Core/Default (= 0.68.6)
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsiexecutor (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- Yoga
|
||||
- React-Core/CoreModulesHeaders (0.68.5):
|
||||
- React-Core/CoreModulesHeaders (0.68.6):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsiexecutor (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- Yoga
|
||||
- React-Core/Default (0.68.5):
|
||||
- React-Core/Default (0.68.6):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsiexecutor (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- Yoga
|
||||
- React-Core/DevSupport (0.68.5):
|
||||
- React-Core/DevSupport (0.68.6):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default (= 0.68.5)
|
||||
- React-Core/RCTWebSocket (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-jsinspector (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-Core/Default (= 0.68.6)
|
||||
- React-Core/RCTWebSocket (= 0.68.6)
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsiexecutor (= 0.68.6)
|
||||
- React-jsinspector (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- Yoga
|
||||
- React-Core/RCTActionSheetHeaders (0.68.5):
|
||||
- React-Core/RCTActionSheetHeaders (0.68.6):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsiexecutor (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- Yoga
|
||||
- React-Core/RCTAnimationHeaders (0.68.5):
|
||||
- React-Core/RCTAnimationHeaders (0.68.6):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsiexecutor (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- Yoga
|
||||
- React-Core/RCTBlobHeaders (0.68.5):
|
||||
- React-Core/RCTBlobHeaders (0.68.6):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsiexecutor (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- Yoga
|
||||
- React-Core/RCTImageHeaders (0.68.5):
|
||||
- React-Core/RCTImageHeaders (0.68.6):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsiexecutor (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- Yoga
|
||||
- React-Core/RCTLinkingHeaders (0.68.5):
|
||||
- React-Core/RCTLinkingHeaders (0.68.6):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsiexecutor (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- Yoga
|
||||
- React-Core/RCTNetworkHeaders (0.68.5):
|
||||
- React-Core/RCTNetworkHeaders (0.68.6):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsiexecutor (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- Yoga
|
||||
- React-Core/RCTSettingsHeaders (0.68.5):
|
||||
- React-Core/RCTSettingsHeaders (0.68.6):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsiexecutor (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- Yoga
|
||||
- React-Core/RCTTextHeaders (0.68.5):
|
||||
- React-Core/RCTTextHeaders (0.68.6):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsiexecutor (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- Yoga
|
||||
- React-Core/RCTVibrationHeaders (0.68.5):
|
||||
- React-Core/RCTVibrationHeaders (0.68.6):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsiexecutor (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- Yoga
|
||||
- React-Core/RCTWebSocket (0.68.5):
|
||||
- React-Core/RCTWebSocket (0.68.6):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-Core/Default (= 0.68.6)
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsiexecutor (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- Yoga
|
||||
- React-CoreModules (0.68.5):
|
||||
- React-CoreModules (0.68.6):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.68.5)
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/CoreModulesHeaders (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-RCTImage (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-cxxreact (0.68.5):
|
||||
- RCTTypeSafety (= 0.68.6)
|
||||
- React-Codegen (= 0.68.6)
|
||||
- React-Core/CoreModulesHeaders (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-RCTImage (= 0.68.6)
|
||||
- ReactCommon/turbomodule/core (= 0.68.6)
|
||||
- React-cxxreact (0.68.6):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-callinvoker (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsinspector (= 0.68.5)
|
||||
- React-logger (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-runtimeexecutor (= 0.68.5)
|
||||
- React-jsi (0.68.5):
|
||||
- React-callinvoker (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-jsinspector (= 0.68.6)
|
||||
- React-logger (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- React-runtimeexecutor (= 0.68.6)
|
||||
- React-jsi (0.68.6):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-jsi/Default (= 0.68.5)
|
||||
- React-jsi/Default (0.68.5):
|
||||
- React-jsi/Default (= 0.68.6)
|
||||
- React-jsi/Default (0.68.6):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-jsiexecutor (0.68.5):
|
||||
- React-jsiexecutor (0.68.6):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-jsinspector (0.68.5)
|
||||
- React-logger (0.68.5):
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- React-jsinspector (0.68.6)
|
||||
- React-logger (0.68.6):
|
||||
- glog
|
||||
- react-native-background-timer (2.4.1):
|
||||
- React-Core
|
||||
@@ -394,71 +394,71 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-webview (11.15.1):
|
||||
- React-Core
|
||||
- React-perflogger (0.68.5)
|
||||
- React-RCTActionSheet (0.68.5):
|
||||
- React-Core/RCTActionSheetHeaders (= 0.68.5)
|
||||
- React-RCTAnimation (0.68.5):
|
||||
- React-perflogger (0.68.6)
|
||||
- React-RCTActionSheet (0.68.6):
|
||||
- React-Core/RCTActionSheetHeaders (= 0.68.6)
|
||||
- React-RCTAnimation (0.68.6):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.68.5)
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/RCTAnimationHeaders (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-RCTBlob (0.68.5):
|
||||
- RCTTypeSafety (= 0.68.6)
|
||||
- React-Codegen (= 0.68.6)
|
||||
- React-Core/RCTAnimationHeaders (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- ReactCommon/turbomodule/core (= 0.68.6)
|
||||
- React-RCTBlob (0.68.6):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/RCTBlobHeaders (= 0.68.5)
|
||||
- React-Core/RCTWebSocket (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-RCTNetwork (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-RCTImage (0.68.5):
|
||||
- React-Codegen (= 0.68.6)
|
||||
- React-Core/RCTBlobHeaders (= 0.68.6)
|
||||
- React-Core/RCTWebSocket (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-RCTNetwork (= 0.68.6)
|
||||
- ReactCommon/turbomodule/core (= 0.68.6)
|
||||
- React-RCTImage (0.68.6):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.68.5)
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/RCTImageHeaders (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-RCTNetwork (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-RCTLinking (0.68.5):
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/RCTLinkingHeaders (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-RCTNetwork (0.68.5):
|
||||
- RCTTypeSafety (= 0.68.6)
|
||||
- React-Codegen (= 0.68.6)
|
||||
- React-Core/RCTImageHeaders (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-RCTNetwork (= 0.68.6)
|
||||
- ReactCommon/turbomodule/core (= 0.68.6)
|
||||
- React-RCTLinking (0.68.6):
|
||||
- React-Codegen (= 0.68.6)
|
||||
- React-Core/RCTLinkingHeaders (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- ReactCommon/turbomodule/core (= 0.68.6)
|
||||
- React-RCTNetwork (0.68.6):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.68.5)
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/RCTNetworkHeaders (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-RCTSettings (0.68.5):
|
||||
- RCTTypeSafety (= 0.68.6)
|
||||
- React-Codegen (= 0.68.6)
|
||||
- React-Core/RCTNetworkHeaders (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- ReactCommon/turbomodule/core (= 0.68.6)
|
||||
- React-RCTSettings (0.68.6):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.68.5)
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/RCTSettingsHeaders (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-RCTText (0.68.5):
|
||||
- React-Core/RCTTextHeaders (= 0.68.5)
|
||||
- React-RCTVibration (0.68.5):
|
||||
- RCTTypeSafety (= 0.68.6)
|
||||
- React-Codegen (= 0.68.6)
|
||||
- React-Core/RCTSettingsHeaders (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- ReactCommon/turbomodule/core (= 0.68.6)
|
||||
- React-RCTText (0.68.6):
|
||||
- React-Core/RCTTextHeaders (= 0.68.6)
|
||||
- React-RCTVibration (0.68.6):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/RCTVibrationHeaders (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-runtimeexecutor (0.68.5):
|
||||
- React-jsi (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (0.68.5):
|
||||
- React-Codegen (= 0.68.6)
|
||||
- React-Core/RCTVibrationHeaders (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- ReactCommon/turbomodule/core (= 0.68.6)
|
||||
- React-runtimeexecutor (0.68.6):
|
||||
- React-jsi (= 0.68.6)
|
||||
- ReactCommon/turbomodule/core (0.68.6):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-callinvoker (= 0.68.5)
|
||||
- React-Core (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-logger (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-callinvoker (= 0.68.6)
|
||||
- React-Core (= 0.68.6)
|
||||
- React-cxxreact (= 0.68.6)
|
||||
- React-jsi (= 0.68.6)
|
||||
- React-logger (= 0.68.6)
|
||||
- React-perflogger (= 0.68.6)
|
||||
- RNCalendarEvents (2.2.0):
|
||||
- React
|
||||
- RNCAsyncStorage (1.17.3):
|
||||
@@ -705,8 +705,8 @@ SPEC CHECKSUMS:
|
||||
boost: a7c83b31436843459a1961bfd74b96033dc77234
|
||||
CocoaLumberjack: b7e05132ff94f6ae4dfa9d5bce9141893a21d9da
|
||||
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
|
||||
FBLazyVector: 2b47ff52037bd9ae07cc9b051c9975797814b736
|
||||
FBReactNativeSpec: 0e0d384ef17a33b385f13f0c7f97702c7cd17858
|
||||
FBLazyVector: 74b042924fe14da854ac4e87cefc417f583b22b1
|
||||
FBReactNativeSpec: cc0037b9914b9b1d92a15f179bc3e2e2c7cc0c6f
|
||||
Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d
|
||||
FirebaseAnalytics: 7761cbadb00a717d8d0939363eb46041526474fa
|
||||
FirebaseCore: 5743c5785c074a794d35f2fff7ecc254a91e08b1
|
||||
@@ -731,18 +731,18 @@ SPEC CHECKSUMS:
|
||||
PromisesObjC: ab77feca74fa2823e7af4249b8326368e61014cb
|
||||
PromisesSwift: 99fddfe4a0ec88a56486644c0da106694c92a604
|
||||
RCT-Folly: 4d8508a426467c48885f1151029bc15fa5d7b3b8
|
||||
RCTRequired: 0f06b6068f530932d10e1a01a5352fad4eaacb74
|
||||
RCTTypeSafety: b0ee81f10ef1b7d977605a2b266823dabd565e65
|
||||
React: 3becd12bd51ea8a43bdde7e09d0f40fba7820e03
|
||||
React-callinvoker: 11abfff50e6bf7a55b3a90b4dc2187f71f224593
|
||||
React-Codegen: f8946ce0768fb8e92e092e30944489c4b2955b2d
|
||||
React-Core: 203cdb6ee2657b198d97d41031c249161060e6ca
|
||||
React-CoreModules: 6eb0c06a4a223fde2cb6a8d0f44f58b67e808942
|
||||
React-cxxreact: afb0c6c07d19adbd850747fedeac20c6832d40b9
|
||||
React-jsi: 14d37a6db2af2c1a49f6f5c2e4ee667c364ae45c
|
||||
React-jsiexecutor: 45c0496ca8cef6b02d9fa0274c25cf458fe91a56
|
||||
React-jsinspector: eb202e43b3879aba9a14f3f65788aec85d4e1ea9
|
||||
React-logger: 98f663b292a60967ebbc6d803ae96c1381183b6d
|
||||
RCTRequired: 92cbd71369a2de6add25fd2403ac39838f1b694f
|
||||
RCTTypeSafety: 494e8af41d7410ed0b877210859ee3984f37e6b4
|
||||
React: 59989499c0e8926a90d34a9ae0bdb2d1b5b53406
|
||||
React-callinvoker: 8187db1c71cf2c1c66e8f7328a0cf77a2b255d94
|
||||
React-Codegen: e806dc2f10ddae645d855cb58acf73ce41eb8ea5
|
||||
React-Core: fc7339b493e368ae079850a4721bdf716cf3dba2
|
||||
React-CoreModules: 2f54f6bbf2764044379332089fcbdaf79197021e
|
||||
React-cxxreact: ee119270006794976e1ab271f0111a5a88b16bcf
|
||||
React-jsi: ec691b2a475d13b1fd39f697145a526eeeb6661c
|
||||
React-jsiexecutor: b4ce4afc5dd9c8fdd2ac59049ccf420f288ecef7
|
||||
React-jsinspector: e396d5e56af08fce39f50571726b68a40f1e302d
|
||||
React-logger: cec52b3f8fb0be0d47b2cb75dec69de60f2de3b6
|
||||
react-native-background-timer: 17ea5e06803401a379ebf1f20505b793ac44d0fe
|
||||
react-native-get-random-values: 30b3f74ca34e30e2e480de48e4add2706a40ac8f
|
||||
react-native-keep-awake: afad8a51dfef9fe9655a6344771be32c8596d774
|
||||
@@ -756,18 +756,18 @@ SPEC CHECKSUMS:
|
||||
react-native-video: bb6f12a7198db53b261fefb5d609dc77417acc8b
|
||||
react-native-webrtc: 0df36747802476e758af6b6dceccdeaed8c826c2
|
||||
react-native-webview: ea4899a1056c782afa96dd082179a66cbebf5504
|
||||
React-perflogger: 0458a87ea9a7342079e7a31b0d32b3734fb8415f
|
||||
React-RCTActionSheet: 22538001ea2926dea001111dd2846c13a0730bc9
|
||||
React-RCTAnimation: 732ce66878d4aa151d56a0d142b1105aa12fd313
|
||||
React-RCTBlob: 9cb9e3e9a41d27be34aaf89b0e0f52c7ca415d57
|
||||
React-RCTImage: 6bd16627eb9c4bb79903c4cdec7c551266ee1a5b
|
||||
React-RCTLinking: e9edfc8919c8fa9a3f3c7b34362811f58a2ebba4
|
||||
React-RCTNetwork: 880eccd21bbe2660a0b63da5ccba75c46eceeaa6
|
||||
React-RCTSettings: 8c85d8188c97d6c6bd470af6631a6c4555b79bb3
|
||||
React-RCTText: bbd275ee287730c5acbab1aadc0db39c25c5c64e
|
||||
React-RCTVibration: 9819a3bf6230e4b2a99877c21268b0b2416157a1
|
||||
React-runtimeexecutor: b1f1995089b90696dbc2a7ffe0059a80db5c8eb1
|
||||
ReactCommon: 149e2c0acab9bac61378da0db5b2880a1b5ff59b
|
||||
React-perflogger: 46620fc6d1c3157b60ed28434e08f7fd7f3f3353
|
||||
React-RCTActionSheet: b1f7e72a0ba760ec684df335c61f730b5179f5ff
|
||||
React-RCTAnimation: d73b62d42867ab608dfb10e100d8b91106275b18
|
||||
React-RCTBlob: b5f59693721d50967c35598158e6ca01b474c7de
|
||||
React-RCTImage: 37cf34d0c2fbef2e0278d42a7c5e8ea06a9fed6b
|
||||
React-RCTLinking: a11dced20019cf1c2ec7fd120f18b08f2851f79e
|
||||
React-RCTNetwork: ba097188e5eac42e070029e7cedd9b978940833a
|
||||
React-RCTSettings: 147073708a1c1bde521cf3af045a675682772726
|
||||
React-RCTText: 23f76ebfb2717d181476432e5ecf1c6c4a104c5e
|
||||
React-RCTVibration: be5f18ffc644f96f904e0e673ab639ca5d673ee8
|
||||
React-runtimeexecutor: d5498cfb7059bf8397b6416db4777843f3f4c1e7
|
||||
ReactCommon: 1974dab5108c79b40199f12a4833d2499b9f6303
|
||||
RNCalendarEvents: 7e65eb4a94f53c1744d1e275f7fafcfaa619f7a3
|
||||
RNCAsyncStorage: 005c0e2f09575360f142d0d1f1f15e4ec575b1af
|
||||
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
|
||||
@@ -779,7 +779,7 @@ SPEC CHECKSUMS:
|
||||
RNSound: 27e8268bdb0a1f191f219a33267f7e0445e8d62f
|
||||
RNSVG: f3b60aeeaa81960e2e0536c3a9eef50b667ef3a9
|
||||
RNWatch: dae6c858a2051dbdcfb00b9a86cf4d90400263b4
|
||||
Yoga: c4d61225a466f250c35c1ee78d2d0b3d41fe661c
|
||||
Yoga: 7929b92b1828675c1bebeb114dae8cb8fa7ef6a3
|
||||
|
||||
PODFILE CHECKSUM: e671cdcdb80fab67e305861c36bfae8ed5a5b0ef
|
||||
|
||||
|
||||
@@ -675,6 +675,7 @@
|
||||
"dataChannelClosedDescription": "Die Steuerungsverbindung (Bridge Channel) wurde unterbrochen, daher ist die Videoqulität auf die schlechteste Stufe limitiert.",
|
||||
"disconnected": "getrennt",
|
||||
"displayNotifications": "Benachrichtigungen anzeigen für",
|
||||
"dontRemindMe": "Nicht erinnern",
|
||||
"focus": "Konferenzleitung",
|
||||
"focusFail": "{{component}} ist im Moment nicht verfügbar – wiederholen in {{ms}} Sekunden",
|
||||
"gifsMenu": "GIPHY",
|
||||
@@ -683,6 +684,7 @@
|
||||
"invitedOneMember": "{{name}} wurde eingeladen",
|
||||
"invitedThreePlusMembers": "{{name}} und {{count}} andere wurden eingeladen",
|
||||
"invitedTwoMembers": "{{first}} und {{second}} wurden eingeladen",
|
||||
"joinMeeting": "Beitreten",
|
||||
"kickParticipant": "{{kicked}} wurde von {{kicker}} ausgewiesen",
|
||||
"leftOneMember": "{{name}} hat die Konferenz verlassen",
|
||||
"leftThreePlusMembers": "{{name}} und Weitere haben die Konferenz verlassen",
|
||||
@@ -1097,11 +1099,20 @@
|
||||
"cc": "Untertitel ein-/ausschalten",
|
||||
"chat": "Chatfenster öffnen / schließen",
|
||||
"clap": "Klatschen",
|
||||
"closeChat": "Chat schließen",
|
||||
"closeMoreActions": "„Weitere Einstellungen“ schließen",
|
||||
"closeParticipantsPane": "Anwesendenliste schließen",
|
||||
"collapse": "Einklappen",
|
||||
"document": "Geteiltes Dokument schließen",
|
||||
"documentClose": "Geteiltes Dokument schließen",
|
||||
"documentOpen": "Geteiltes Dokument öffnen",
|
||||
"download": "Unsere Apps herunterladen",
|
||||
"embedMeeting": "Konferenz einbetten",
|
||||
"endConference": "Konferenz für alle beenden",
|
||||
"enterFullScreen": "Vollbildmodus einschalten",
|
||||
"enterTileView": "Kachelansicht einschalten",
|
||||
"exitFullScreen": "Vollbildansicht ausschalten",
|
||||
"exitTileView": "Kachelansicht ausschalten",
|
||||
"expand": "Ausklappen",
|
||||
"feedback": "Feedback hinterlassen",
|
||||
"fullScreen": "Vollbildmodus ein-/ausschalten",
|
||||
@@ -1110,6 +1121,7 @@
|
||||
"hangup": "Konferenz verlassen",
|
||||
"heading": "Toolbar",
|
||||
"help": "Hilfe",
|
||||
"hideWhiteboard": "Whiteboard ausblenden",
|
||||
"invite": "Person einladen",
|
||||
"kick": "Person entfernen",
|
||||
"laugh": "Lachen",
|
||||
@@ -1119,6 +1131,7 @@
|
||||
"lobbyButton": "Lobbymodus ein-/ausschalten",
|
||||
"localRecording": "Lokale Aufzeichnungssteuerelemente ein-/ausschalten",
|
||||
"lockRoom": "Konferenzpasswort ein-/ausschalten",
|
||||
"lowerHand": "Hand senken",
|
||||
"moreActions": "Menü „Weitere Einstellungen“ ein-/ausschalten",
|
||||
"moreActionsMenu": "Menü „Weitere Einstellungen“",
|
||||
"moreOptions": "Menü „Weitere Optionen“",
|
||||
@@ -1128,6 +1141,7 @@
|
||||
"muteEveryoneElsesVideoStream": "Alle anderen Kameras ausschalten",
|
||||
"muteEveryonesVideoStream": "Alle Kameras ausschalten",
|
||||
"noiseSuppression": "Rauschunterdrückung",
|
||||
"openChat": "Chat öffnen",
|
||||
"participants": "Anwesende",
|
||||
"pip": "Bild-in-Bild-Modus ein-/ausschalten",
|
||||
"privateMessage": "Private Nachricht senden",
|
||||
@@ -1146,15 +1160,19 @@
|
||||
"sharedvideo": "Videofreigabe ein-/ausschalten",
|
||||
"shortcuts": "Tastenkombinationen ein-/ausblenden",
|
||||
"show": "Im Vordergrund anzeigen",
|
||||
"showWhiteboard": "Whiteboard anzeigen",
|
||||
"silence": "Stille",
|
||||
"speakerStats": "Sprechstatistik ein-/ausblenden",
|
||||
"stopScreenSharing": "Bildschirmfreigabe beenden",
|
||||
"stopSharedVideo": "Videofreigabe beenden",
|
||||
"surprised": "Überrascht",
|
||||
"tileView": "Kachelansicht ein-/ausschalten",
|
||||
"toggleCamera": "Kamera wechseln",
|
||||
"toggleFilmstrip": "Miniaturansichten ein-/ausschalten",
|
||||
"unmute": "Stummschaltung aufheben",
|
||||
"videoblur": "Unscharfer Hintergrund ein-/ausschalten",
|
||||
"videomute": "„Video stummschalten“ ein-/ausschalten",
|
||||
"whiteboard": "Whiteboard ein-/ausschalten"
|
||||
"videounmute": "Kamera einschalten"
|
||||
},
|
||||
"addPeople": "Personen zur Konferenz hinzufügen",
|
||||
"audioOnlyOff": "Modus „Nur Audio“ deaktivieren",
|
||||
@@ -1167,6 +1185,7 @@
|
||||
"chat": "Chat öffnen / schließen",
|
||||
"clap": "Klatschen",
|
||||
"closeChat": "Chat schließen",
|
||||
"closeParticipantsPane": "Anwesenheitsliste schließen",
|
||||
"closeReactionsMenu": "Interaktionsmenü schließen",
|
||||
"disableNoiseSuppression": "Rauschunterdrückung deaktivieren",
|
||||
"disableReactionSounds": "Sie können die Interaktionstöne für diese Konferenz deaktivieren",
|
||||
@@ -1200,7 +1219,7 @@
|
||||
"lowerYourHand": "Hand senken",
|
||||
"moreActions": "Weitere Einstellungen",
|
||||
"moreOptions": "Weitere Optionen",
|
||||
"mute": "Mikrofon aktivieren / deaktivieren",
|
||||
"mute": "Stummschalten",
|
||||
"muteEveryone": "Alle stummschalten",
|
||||
"muteEveryonesVideo": "Alle Kameras ausschalten",
|
||||
"noAudioSignalDesc": "Wenn Sie das Gerät nicht absichtlich über die Systemeinstellungen oder die Hardware stumm geschaltet haben, sollten Sie einen Wechsel des Geräts in Erwägung ziehen.",
|
||||
@@ -1244,8 +1263,10 @@
|
||||
"talkWhileMutedPopup": "Versuchen Sie zu sprechen? Ihr Mikrofon ist stummgeschaltet.",
|
||||
"tileViewToggle": "Kachelansicht ein-/ausschalten",
|
||||
"toggleCamera": "Kamera wechseln",
|
||||
"unmute": "Stummschaltung aufheben",
|
||||
"videoSettings": "Kameraeinstellungen",
|
||||
"videomute": "Kamera starten / stoppen"
|
||||
"videomute": "Kamera stoppen",
|
||||
"videounmute": "Kamera einschalten"
|
||||
},
|
||||
"transcribing": {
|
||||
"ccButtonTooltip": "Untertitel ein-/ausschalten",
|
||||
|
||||
@@ -675,6 +675,7 @@
|
||||
"dataChannelClosedDescription": "The bridge channel has been disconnected and thus video quality is limited to its lowest setting.",
|
||||
"disconnected": "disconnected",
|
||||
"displayNotifications": "Display notifications for",
|
||||
"dontRemindMe": "Do not remind me",
|
||||
"focus": "Conference focus",
|
||||
"focusFail": "{{component}} not available - retry in {{ms}} sec",
|
||||
"gifsMenu": "GIPHY",
|
||||
|
||||
@@ -6,9 +6,8 @@ import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { browser } from '../../../react/features/base/lib-jitsi-meet';
|
||||
import { isTestModeEnabled } from '../../../react/features/base/testing';
|
||||
import { FILMSTRIP_BREAKPOINT } from '../../../react/features/filmstrip';
|
||||
import { LargeVideoBackground, ORIENTATION, updateLastLargeVideoMediaEvent } from '../../../react/features/large-video';
|
||||
import { LargeVideoBackground, ORIENTATION } from '../../../react/features/large-video';
|
||||
import { setLargeVideoDimensions } from '../../../react/features/large-video/actions.any';
|
||||
import { LAYOUTS, getCurrentLayout } from '../../../react/features/video-layout';
|
||||
/* eslint-enable no-unused-vars */
|
||||
@@ -22,15 +21,6 @@ export const VIDEO_CONTAINER_TYPE = 'camera';
|
||||
|
||||
const FADE_DURATION_MS = 300;
|
||||
|
||||
/**
|
||||
* List of container events that we are going to process, will be added as listener to the
|
||||
* container for every event in the list. The latest event will be stored in redux.
|
||||
*/
|
||||
const containerEvents = [
|
||||
'abort', 'canplay', 'canplaythrough', 'emptied', 'ended', 'error', 'loadeddata', 'loadedmetadata', 'loadstart',
|
||||
'pause', 'play', 'playing', 'ratechange', 'stalled', 'suspend', 'waiting'
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns an array of the video dimensions, so that it keeps it's aspect
|
||||
* ratio and fits available area with it's larger dimension. This method
|
||||
@@ -266,14 +256,6 @@ export class VideoContainer extends LargeContainer {
|
||||
this._resizeListeners = new Set();
|
||||
|
||||
this.$video[0].onresize = this._onResize.bind(this);
|
||||
|
||||
if (isTestModeEnabled(APP.store.getState())) {
|
||||
const cb = name => APP.store.dispatch(updateLastLargeVideoMediaEvent(name));
|
||||
|
||||
containerEvents.forEach(event => {
|
||||
this.$video[0].addEventListener(event, cb.bind(this, event));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
80
package-lock.json
generated
80
package-lock.json
generated
@@ -15,7 +15,6 @@
|
||||
"@atlaskit/inline-message": "11.0.8",
|
||||
"@atlaskit/multi-select": "15.0.5",
|
||||
"@atlaskit/theme": "11.0.2",
|
||||
"@atlaskit/tooltip": "17.1.2",
|
||||
"@emotion/react": "11.10.0",
|
||||
"@emotion/styled": "11.10.0",
|
||||
"@giphy/js-fetch-api": "4.7.1",
|
||||
@@ -69,7 +68,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/v1592.0.0+6afb0a56/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1595.0.0+5155e550/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -83,7 +82,7 @@
|
||||
"react-focus-lock": "2.5.1",
|
||||
"react-i18next": "10.11.4",
|
||||
"react-linkify": "1.0.0-alpha",
|
||||
"react-native": "0.68.5",
|
||||
"react-native": "0.68.6",
|
||||
"react-native-background-timer": "2.4.1",
|
||||
"react-native-calendar-events": "2.2.0",
|
||||
"react-native-callstats": "3.73.7",
|
||||
@@ -599,18 +598,6 @@
|
||||
"styled-components": "^3.2.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@atlaskit/motion": {
|
||||
"version": "0.4.8",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/motion/-/motion-0.4.8.tgz",
|
||||
"integrity": "sha512-+5hABjUNUgl66zNya+EmNXLrbJQ7EgXA+fNQih7qzu7MkIuzJjT5vEtpXrzckLKBu1v1HsbMQW90Wnd8MJugdw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"@emotion/core": "^10.0.9"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@atlaskit/multi-select": {
|
||||
"version": "15.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/multi-select/-/multi-select-15.0.5.tgz",
|
||||
@@ -789,25 +776,6 @@
|
||||
"@babel/types": "^7.15.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@atlaskit/tooltip": {
|
||||
"version": "17.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/tooltip/-/tooltip-17.1.2.tgz",
|
||||
"integrity": "sha512-0N63l18ZuyL2pjNXwY3pwnNos3HjOsFhSmnj2TLASC+RLz/6/Nk1k9gXuydfMjU2ntsr7xrVY5U7ING0mxAzQQ==",
|
||||
"dependencies": {
|
||||
"@atlaskit/analytics-next": "^8.1.0",
|
||||
"@atlaskit/motion": "^0.4.0",
|
||||
"@atlaskit/popper": "^5.0.0",
|
||||
"@atlaskit/portal": "^4.0.0",
|
||||
"@atlaskit/theme": "^11.0.0",
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"@emotion/core": "^10.0.9",
|
||||
"bind-event-listener": "^1.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0",
|
||||
"react-dom": "^16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
|
||||
@@ -13386,8 +13354,8 @@
|
||||
},
|
||||
"node_modules/lib-jitsi-meet": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1592.0.0+6afb0a56/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-mfBTIA0GySRlXScROQqbRAlSDW84cv6Cdiw/JgMclr9bGILvmYK+lQbLvkobzQ04m4GAHSNUV4IZ0psqck2qJg==",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1595.0.0+5155e550/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-GVv19QbTPAPKrKiAE/MltjwhNjAZECNUDll5PnbAW5ToO1T914owFRWOtAW9+FHEaanxfyEwjYqzlqnU2VFgmg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
@@ -16012,9 +15980,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-native": {
|
||||
"version": "0.68.5",
|
||||
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.68.5.tgz",
|
||||
"integrity": "sha512-t3kiQ/gumFV+0r/NRSIGtYxanjY4da0utFqHgkMcRPJVwXFWC0Fr8YiOeRGYO1dp8EfrSsOjtfWic/inqVYlbQ==",
|
||||
"version": "0.68.6",
|
||||
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.68.6.tgz",
|
||||
"integrity": "sha512-evLsY9SEd842qvWU/1UeKa9PUGj2R5aPuTXBZj0AfzZlVQwS0bLLG9+j+bmXPlPXfYE8MpzfMLUK4EqmKBZSxg==",
|
||||
"dependencies": {
|
||||
"@jest/create-cache-key-function": "^27.0.1",
|
||||
"@react-native-community/cli": "^7.0.3",
|
||||
@@ -20705,15 +20673,6 @@
|
||||
"react-scrolllock": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"@atlaskit/motion": {
|
||||
"version": "0.4.8",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/motion/-/motion-0.4.8.tgz",
|
||||
"integrity": "sha512-+5hABjUNUgl66zNya+EmNXLrbJQ7EgXA+fNQih7qzu7MkIuzJjT5vEtpXrzckLKBu1v1HsbMQW90Wnd8MJugdw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"@emotion/core": "^10.0.9"
|
||||
}
|
||||
},
|
||||
"@atlaskit/multi-select": {
|
||||
"version": "15.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/multi-select/-/multi-select-15.0.5.tgz",
|
||||
@@ -20857,21 +20816,6 @@
|
||||
"@babel/types": "^7.15.0"
|
||||
}
|
||||
},
|
||||
"@atlaskit/tooltip": {
|
||||
"version": "17.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/tooltip/-/tooltip-17.1.2.tgz",
|
||||
"integrity": "sha512-0N63l18ZuyL2pjNXwY3pwnNos3HjOsFhSmnj2TLASC+RLz/6/Nk1k9gXuydfMjU2ntsr7xrVY5U7ING0mxAzQQ==",
|
||||
"requires": {
|
||||
"@atlaskit/analytics-next": "^8.1.0",
|
||||
"@atlaskit/motion": "^0.4.0",
|
||||
"@atlaskit/popper": "^5.0.0",
|
||||
"@atlaskit/portal": "^4.0.0",
|
||||
"@atlaskit/theme": "^11.0.0",
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"@emotion/core": "^10.0.9",
|
||||
"bind-event-listener": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"@babel/code-frame": {
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
|
||||
@@ -30235,8 +30179,8 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1592.0.0+6afb0a56/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-mfBTIA0GySRlXScROQqbRAlSDW84cv6Cdiw/JgMclr9bGILvmYK+lQbLvkobzQ04m4GAHSNUV4IZ0psqck2qJg==",
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1595.0.0+5155e550/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-GVv19QbTPAPKrKiAE/MltjwhNjAZECNUDll5PnbAW5ToO1T914owFRWOtAW9+FHEaanxfyEwjYqzlqnU2VFgmg==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
@@ -32255,9 +32199,9 @@
|
||||
}
|
||||
},
|
||||
"react-native": {
|
||||
"version": "0.68.5",
|
||||
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.68.5.tgz",
|
||||
"integrity": "sha512-t3kiQ/gumFV+0r/NRSIGtYxanjY4da0utFqHgkMcRPJVwXFWC0Fr8YiOeRGYO1dp8EfrSsOjtfWic/inqVYlbQ==",
|
||||
"version": "0.68.6",
|
||||
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.68.6.tgz",
|
||||
"integrity": "sha512-evLsY9SEd842qvWU/1UeKa9PUGj2R5aPuTXBZj0AfzZlVQwS0bLLG9+j+bmXPlPXfYE8MpzfMLUK4EqmKBZSxg==",
|
||||
"requires": {
|
||||
"@jest/create-cache-key-function": "^27.0.1",
|
||||
"@react-native-community/cli": "^7.0.3",
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
"@atlaskit/inline-message": "11.0.8",
|
||||
"@atlaskit/multi-select": "15.0.5",
|
||||
"@atlaskit/theme": "11.0.2",
|
||||
"@atlaskit/tooltip": "17.1.2",
|
||||
"@emotion/react": "11.10.0",
|
||||
"@emotion/styled": "11.10.0",
|
||||
"@giphy/js-fetch-api": "4.7.1",
|
||||
@@ -74,7 +73,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/v1592.0.0+6afb0a56/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1595.0.0+5155e550/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -88,7 +87,7 @@
|
||||
"react-focus-lock": "2.5.1",
|
||||
"react-i18next": "10.11.4",
|
||||
"react-linkify": "1.0.0-alpha",
|
||||
"react-native": "0.68.5",
|
||||
"react-native": "0.68.6",
|
||||
"react-native-background-timer": "2.4.1",
|
||||
"react-native-calendar-events": "2.2.0",
|
||||
"react-native-callstats": "3.73.7",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// @flow
|
||||
|
||||
import '../base/devices/reducer';
|
||||
import '../base/tooltip/reducer';
|
||||
import '../e2ee/reducer';
|
||||
import '../face-landmarks/reducer';
|
||||
import '../feedback/reducer';
|
||||
|
||||
@@ -24,6 +24,7 @@ import { IResponsiveUIState } from '../base/responsive-ui/reducer';
|
||||
import { ISettingsState } from '../base/settings/reducer';
|
||||
import { ISoundsState } from '../base/sounds/reducer';
|
||||
import { ITestingState } from '../base/testing/reducer';
|
||||
import { ITooltipState } from '../base/tooltip/reducer';
|
||||
import { INoSrcDataState, ITracksState } from '../base/tracks/reducer';
|
||||
import { IUserInteractionState } from '../base/user-interaction/reducer';
|
||||
import { IBreakoutRoomsState } from '../breakout-rooms/reducer';
|
||||
@@ -111,6 +112,7 @@ export interface IReduxState {
|
||||
'features/base/responsive-ui': IResponsiveUIState;
|
||||
'features/base/settings': ISettingsState;
|
||||
'features/base/sounds': ISoundsState;
|
||||
'features/base/tooltip': ITooltipState;
|
||||
'features/base/tracks': ITracksState;
|
||||
'features/base/user-interaction': IUserInteractionState;
|
||||
'features/breakout-rooms': IBreakoutRoomsState;
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { Theme } from '@mui/material';
|
||||
import { withStyles } from '@mui/styles';
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
|
||||
import Icon from '../../../icons/components/Icon';
|
||||
import { IconUser } from '../../../icons/svg';
|
||||
import { withPixelLineHeight } from '../../../styles/functions.web';
|
||||
import AbstractStatelessAvatar, { type IProps as AbstractProps } from '../AbstractStatelessAvatar';
|
||||
import { PRESENCE_AVAILABLE_COLOR, PRESENCE_AWAY_COLOR, PRESENCE_BUSY_COLOR, PRESENCE_IDLE_COLOR } from '../styles';
|
||||
|
||||
@@ -47,17 +50,21 @@ interface IProps extends AbstractProps {
|
||||
/**
|
||||
* Creates the styles for the component.
|
||||
*
|
||||
* @param {Theme} theme - The MUI theme.
|
||||
* @returns {Object}
|
||||
*/
|
||||
const styles = () => {
|
||||
const styles = (theme: Theme) => {
|
||||
return {
|
||||
avatar: {
|
||||
backgroundColor: '#AAA',
|
||||
borderRadius: '50%',
|
||||
color: 'rgba(255, 255, 255, 1)',
|
||||
fontWeight: '100',
|
||||
fontWeight: '600',
|
||||
color: theme.palette?.text01 || '#fff',
|
||||
...withPixelLineHeight(theme.typography?.heading1 ?? {}),
|
||||
fontSize: 'inherit',
|
||||
objectFit: 'cover' as const,
|
||||
textAlign: 'center' as const,
|
||||
overflow: 'hidden',
|
||||
|
||||
'&.avatar-small': {
|
||||
height: '28px !important',
|
||||
@@ -79,6 +86,14 @@ const styles = () => {
|
||||
}
|
||||
},
|
||||
|
||||
initialsContainer: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
|
||||
badge: {
|
||||
position: 'relative' as const,
|
||||
|
||||
@@ -173,35 +188,23 @@ class StatelessAvatar extends AbstractStatelessAvatar<IProps> {
|
||||
data-testid = { this.props.testId }
|
||||
id = { this.props.id }
|
||||
style = { this._getAvatarStyle(this.props.color) }>
|
||||
<svg
|
||||
className = 'avatar-svg'
|
||||
viewBox = '0 0 100 100'
|
||||
xmlns = 'http://www.w3.org/2000/svg'
|
||||
xmlnsXlink = 'http://www.w3.org/1999/xlink'>
|
||||
<text
|
||||
dominantBaseline = 'central'
|
||||
fill = 'rgba(255,255,255,1)'
|
||||
fontSize = '40pt'
|
||||
textAnchor = 'middle'
|
||||
x = '50'
|
||||
y = '50'>
|
||||
{ initials }
|
||||
</text>
|
||||
</svg>
|
||||
<div className = { this.props.classes.initialsContainer }>
|
||||
{initials}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// default avatar
|
||||
return (
|
||||
<div className = { this._getBadgeClassName() }>
|
||||
<img
|
||||
alt = 'avatar'
|
||||
className = { this._getAvatarClassName('defaultAvatar') }
|
||||
data-testid = { this.props.testId }
|
||||
id = { this.props.id }
|
||||
src = { this.props.defaultAvatar || 'images/avatar.png' }
|
||||
style = { this._getAvatarStyle() } />
|
||||
<div
|
||||
className = { clsx(this._getAvatarClassName('defaultAvatar'), this._getBadgeClassName()) }
|
||||
data-testid = { this.props.testId }
|
||||
id = { this.props.id }
|
||||
style = { this._getAvatarStyle() }>
|
||||
<Icon
|
||||
size = { '50%' }
|
||||
src = { IconUser } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -217,7 +220,7 @@ class StatelessAvatar extends AbstractStatelessAvatar<IProps> {
|
||||
|
||||
return {
|
||||
background: color || undefined,
|
||||
fontSize: size ? size * 0.5 : '180%',
|
||||
fontSize: size ? size * 0.4 : '180%',
|
||||
height: size || '100%',
|
||||
width: size || '100%'
|
||||
};
|
||||
|
||||
@@ -117,6 +117,14 @@ export interface IDeeplinkingConfig {
|
||||
ios?: IDeeplinkingMobileConfig;
|
||||
}
|
||||
|
||||
export interface INoiseSuppressionConfig {
|
||||
krisp?: {
|
||||
debugLogs?: boolean;
|
||||
enabled?: boolean;
|
||||
logProcessStats?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IConfig {
|
||||
_desktopSharingSourceDevice?: string;
|
||||
analytics?: {
|
||||
@@ -316,6 +324,7 @@ export interface IConfig {
|
||||
enableSaveLogs?: boolean;
|
||||
enableTcc?: boolean;
|
||||
enableUnifiedOnChrome?: boolean;
|
||||
enableWebHIDFeature?: boolean;
|
||||
enableWelcomePage?: boolean;
|
||||
etherpad_base?: string;
|
||||
faceLandmarks?: {
|
||||
@@ -416,6 +425,7 @@ export interface IConfig {
|
||||
microsoftApiApplicationClientID?: string;
|
||||
moderatedRoomServiceUrl?: string;
|
||||
mouseMoveCallbackInterval?: number;
|
||||
noiseSuppression?: INoiseSuppressionConfig;
|
||||
noticeMessage?: string;
|
||||
notificationTimeouts?: {
|
||||
long?: number;
|
||||
|
||||
@@ -44,6 +44,16 @@ export function getToolbarButtons(state: IReduxState): Array<string> {
|
||||
return buttons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuration value of web-hid feature.
|
||||
*
|
||||
* @param {Object} state - The state of the app.
|
||||
* @returns {boolean} True if web-hid feature should be enabled, otherwise false.
|
||||
*/
|
||||
export function getWebHIDFeatureConfig(state: IReduxState): boolean {
|
||||
return state['features/base/config'].enableWebHIDFeature || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified button is enabled.
|
||||
*
|
||||
|
||||
@@ -5,7 +5,6 @@ import { IReduxState } from '../../../app/types';
|
||||
import DialogPortal from '../../../toolbox/components/web/DialogPortal';
|
||||
import Drawer from '../../../toolbox/components/web/Drawer';
|
||||
import JitsiPortal from '../../../toolbox/components/web/JitsiPortal';
|
||||
import { isMobileBrowser } from '../../environment/utils';
|
||||
import { connect } from '../../redux/functions';
|
||||
import { getContextMenuStyle } from '../functions.web';
|
||||
|
||||
@@ -14,6 +13,11 @@ import { getContextMenuStyle } from '../functions.web';
|
||||
*/
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
* Whether the child element can be clicked on.
|
||||
*/
|
||||
allowClick?: boolean;
|
||||
|
||||
/**
|
||||
* A child React Element to use as the trigger for showing the dialog.
|
||||
*/
|
||||
@@ -245,7 +249,8 @@ class Popover extends Component<IProps, IState> {
|
||||
<DialogPortal
|
||||
getRef = { this._setContextMenuRef }
|
||||
setSize = { this._setContextMenuStyle }
|
||||
style = { this.state.contextMenuStyle }>
|
||||
style = { this.state.contextMenuStyle }
|
||||
targetSelector = '.popover-content'>
|
||||
<ReactFocusLock
|
||||
lockProps = {{
|
||||
role: 'dialog',
|
||||
@@ -345,9 +350,11 @@ class Popover extends Component<IProps, IState> {
|
||||
* @returns {void}
|
||||
*/
|
||||
_onClick(event: React.MouseEvent) {
|
||||
const { trigger, visible } = this.props;
|
||||
const { allowClick, trigger, visible } = this.props;
|
||||
|
||||
event.stopPropagation();
|
||||
if (!allowClick) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
if (trigger === 'click') {
|
||||
if (visible) {
|
||||
this._onHideDialog();
|
||||
@@ -417,20 +424,15 @@ class Popover extends Component<IProps, IState> {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderContent() {
|
||||
const { content } = this.props;
|
||||
const { content, position } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className = 'popover'
|
||||
onKeyDown = { this._onEscKey }>
|
||||
{ content }
|
||||
{!isMobileBrowser() && (
|
||||
<>
|
||||
<div className = 'popover-mousemove-padding-top' />
|
||||
<div className = 'popover-mousemove-padding-right' />
|
||||
<div className = 'popover-mousemove-padding-left' />
|
||||
<div className = 'popover-mousemove-padding-bottom' />
|
||||
</>)}
|
||||
<div className = { `popover-content ${position.split('-')[0]}` }>
|
||||
{ content }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,43 +1,40 @@
|
||||
const LEFT_RIGHT_OFFSET = 25;
|
||||
const TOP_BOTTOM_OFFSET = 20;
|
||||
|
||||
const getLeftAlignedStyle = (bounds: DOMRect) => {
|
||||
return {
|
||||
position: 'fixed',
|
||||
right: `${window.innerWidth - bounds.x + LEFT_RIGHT_OFFSET}px`
|
||||
right: `${window.innerWidth - bounds.x}px`
|
||||
};
|
||||
};
|
||||
|
||||
const getRightAlignedStyle = (bounds: DOMRect) => {
|
||||
return {
|
||||
position: 'fixed',
|
||||
left: `${bounds.x + bounds.width + LEFT_RIGHT_OFFSET}px`
|
||||
left: `${bounds.x + bounds.width}px`
|
||||
};
|
||||
};
|
||||
|
||||
const getTopAlignedStyle = (bounds: DOMRect) => {
|
||||
return {
|
||||
position: 'fixed',
|
||||
bottom: `${window.innerHeight - bounds.y + TOP_BOTTOM_OFFSET}px`
|
||||
bottom: `${window.innerHeight - bounds.y}px`
|
||||
};
|
||||
};
|
||||
|
||||
const getBottomAlignedStyle = (bounds: DOMRect) => {
|
||||
return {
|
||||
position: 'fixed',
|
||||
top: `${bounds.y + bounds.height + TOP_BOTTOM_OFFSET}px`
|
||||
top: `${bounds.y + bounds.height}px`
|
||||
};
|
||||
};
|
||||
|
||||
const getLeftRightStartAlign = (bounds: DOMRect, size: DOMRectReadOnly) => {
|
||||
return {
|
||||
top: `${Math.min(bounds.y + 15, window.innerHeight - size.height - 20)}px`
|
||||
top: `${Math.min(bounds.y, window.innerHeight - size.height - 20)}px`
|
||||
};
|
||||
};
|
||||
|
||||
const getLeftRightMidAlign = (bounds: DOMRect, size: DOMRectReadOnly) => {
|
||||
return {
|
||||
bottom: `${window.innerHeight - bounds.y - bounds.height - (size.height / 2)}px`
|
||||
bottom: `${window.innerHeight - bounds.y - (bounds.height / 2) - (size.height / 2)}px`
|
||||
};
|
||||
};
|
||||
|
||||
@@ -49,19 +46,19 @@ const getLeftRightEndAlign = (bounds: DOMRect, size: DOMRectReadOnly) => {
|
||||
|
||||
const getTopBotStartAlign = (bounds: DOMRect) => {
|
||||
return {
|
||||
right: `${window.innerWidth - bounds.x + 10}px`
|
||||
right: `${window.innerWidth - bounds.x - 6}px`
|
||||
};
|
||||
};
|
||||
|
||||
const getTopBotMidAlign = (bounds: DOMRect, size: DOMRectReadOnly) => {
|
||||
return {
|
||||
right: `${window.innerWidth - bounds.x - (size.width / 2)}px`
|
||||
right: `${window.innerWidth - bounds.x - (bounds.width / 2) - (size.width / 2)}px`
|
||||
};
|
||||
};
|
||||
|
||||
const getTopBotEndAlign = (bounds: DOMRect) => {
|
||||
return {
|
||||
left: `${bounds.x + bounds.width + 10}px`
|
||||
left: `${bounds.x + bounds.width - 6}px`
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -4,9 +4,7 @@ import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import { translate } from '../../../i18n/functions';
|
||||
import Icon from '../../../icons/components/Icon';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../tooltip';
|
||||
import Tooltip from '../../../tooltip/components/Tooltip';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link BaseIndicator}.
|
||||
@@ -58,7 +56,7 @@ interface IProps extends WithTranslation {
|
||||
* From which side of the indicator the tooltip should appear from,
|
||||
* defaulting to "top".
|
||||
*/
|
||||
tooltipPosition: string;
|
||||
tooltipPosition: 'top' | 'bottom' | 'left' | 'right';
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()(() => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { IReduxState, IStore } from '../../app/types';
|
||||
import { isTrackStreamingStatusActive } from '../../connection-indicator/functions';
|
||||
import { MEDIA_TYPE, VIDEO_TYPE } from '../media/constants';
|
||||
import { getParticipantById, isScreenShareParticipant } from '../participants/functions';
|
||||
import { getTrackByMediaTypeAndParticipant, getVideoTrackByParticipant } from '../tracks/functions';
|
||||
@@ -46,10 +47,8 @@ export function isLargeVideoReceived({ getState }: IStore): boolean {
|
||||
const largeVideoParticipantId = state['features/large-video'].participantId ?? '';
|
||||
const largeVideoParticipant = getParticipantById(state, largeVideoParticipantId ?? '');
|
||||
const videoTrack = getVideoTrackByParticipant(state, largeVideoParticipant);
|
||||
const lastMediaEvent = state['features/large-video']?.lastMediaEvent;
|
||||
|
||||
return Boolean(videoTrack && !videoTrack.muted
|
||||
&& (lastMediaEvent === 'playing' || lastMediaEvent === 'canplaythrough'));
|
||||
return Boolean(videoTrack && !videoTrack.muted && isTrackStreamingStatusActive(videoTrack));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,8 +62,6 @@ export function isRemoteVideoReceived({ getState }: IStore, id: string): boolean
|
||||
const state = getState();
|
||||
const participant = getParticipantById(state, id);
|
||||
const videoTrack = getVideoTrackByParticipant(state, participant);
|
||||
const lastMediaEvent = videoTrack?.lastMediaEvent;
|
||||
|
||||
return Boolean(videoTrack && !videoTrack.muted
|
||||
&& (lastMediaEvent === 'playing' || lastMediaEvent === 'canplaythrough'));
|
||||
return Boolean(videoTrack && !videoTrack.muted && isTrackStreamingStatusActive(videoTrack));
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
import { Icon } from '../../icons';
|
||||
import { Tooltip } from '../../tooltip';
|
||||
import Tooltip from '../../tooltip/components/Tooltip';
|
||||
import ContextMenuItem from '../../ui/components/web/ContextMenuItem';
|
||||
|
||||
import AbstractToolboxItem from './AbstractToolboxItem';
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { Icon } from '../../../icons';
|
||||
import { Tooltip } from '../../../tooltip';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link OverflowMenuItem}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* A succinct description of what the item does. Used by accessibility tools
|
||||
* and torture tests.
|
||||
*/
|
||||
accessibilityLabel: string,
|
||||
|
||||
/**
|
||||
* Whether menu item is disabled or not.
|
||||
*/
|
||||
disabled: boolean,
|
||||
|
||||
/**
|
||||
* A React Element to display at the end of {@code OverflowMenuItem}.
|
||||
*/
|
||||
elementAfter?: React$Node,
|
||||
|
||||
/**
|
||||
* The icon class to use for displaying an icon before the link text.
|
||||
*/
|
||||
icon: Object,
|
||||
|
||||
/**
|
||||
* Id of the icon to be rendered.
|
||||
*/
|
||||
iconId?: string,
|
||||
|
||||
/**
|
||||
* The callback to invoke when {@code OverflowMenuItem} is clicked.
|
||||
*/
|
||||
onClick: Function,
|
||||
|
||||
/**
|
||||
* The text to display in the {@code OverflowMenuItem}.
|
||||
*/
|
||||
text: string,
|
||||
|
||||
/**
|
||||
* The text to display in the tooltip.
|
||||
*/
|
||||
tooltip?: string,
|
||||
|
||||
/**
|
||||
* From which direction the tooltip should appear, relative to the button.
|
||||
*/
|
||||
tooltipPosition: string
|
||||
};
|
||||
|
||||
/**
|
||||
* A React {@code Component} for displaying a link to interact with other
|
||||
* features of the application.
|
||||
*
|
||||
* @augments Component
|
||||
*/
|
||||
class OverflowMenuItem extends Component<Props> {
|
||||
/**
|
||||
* Default values for {@code OverflowMenuItem} component's properties.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static defaultProps = {
|
||||
tooltipPosition: 'left',
|
||||
disabled: false
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes a new {@code OverflowMenuItem} instance.
|
||||
*
|
||||
* @param {*} props - The read-only properties with which the new instance
|
||||
* is to be initialized.
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
// Bind event handler so it is only bound once for every instance.
|
||||
this._onKeyPress = this._onKeyPress.bind(this);
|
||||
}
|
||||
|
||||
_onKeyPress: (Object) => void;
|
||||
|
||||
/**
|
||||
* KeyPress handler for accessibility.
|
||||
*
|
||||
* @param {Object} e - The key event to handle.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_onKeyPress(e) {
|
||||
if (!this.props.disabled && this.props.onClick && (e.key === ' ' || e.key === 'Enter')) {
|
||||
e.preventDefault();
|
||||
this.props.onClick();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { accessibilityLabel, disabled, elementAfter, icon, iconId, onClick } = this.props;
|
||||
|
||||
let className = 'overflow-menu-item';
|
||||
|
||||
className += this.props.disabled ? ' disabled' : '';
|
||||
|
||||
return (
|
||||
<li
|
||||
aria-disabled = { disabled }
|
||||
aria-label = { accessibilityLabel }
|
||||
className = { className }
|
||||
onClick = { disabled ? null : onClick }
|
||||
onKeyPress = { this._onKeyPress }
|
||||
role = 'button'
|
||||
tabIndex = { 0 }>
|
||||
<span className = 'overflow-menu-item-icon'>
|
||||
<Icon
|
||||
id = { iconId }
|
||||
src = { icon } />
|
||||
</span>
|
||||
{ this._renderText() }
|
||||
{
|
||||
elementAfter || null
|
||||
}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the text label to display in the {@code OverflowMenuItem}.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderText() {
|
||||
const textElement = (
|
||||
<span className = 'overflow-menu-item-text'>
|
||||
{ this.props.text }
|
||||
</span>
|
||||
);
|
||||
|
||||
if (this.props.tooltip) {
|
||||
return (
|
||||
<Tooltip
|
||||
content = { this.props.tooltip }
|
||||
position = { this.props.tooltipPosition }>
|
||||
{ textElement }
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
return textElement;
|
||||
}
|
||||
}
|
||||
|
||||
export default OverflowMenuItem;
|
||||
@@ -4,7 +4,7 @@ import React from 'react';
|
||||
|
||||
import { NOTIFY_CLICK_MODE } from '../../../../toolbox/constants';
|
||||
import { Icon } from '../../../icons';
|
||||
import { Tooltip } from '../../../tooltip';
|
||||
import Tooltip from '../../../tooltip/components/Tooltip';
|
||||
|
||||
type Props = {
|
||||
|
||||
@@ -107,12 +107,13 @@ export default function ToolboxButtonWithIcon(props: Props) {
|
||||
} = props;
|
||||
|
||||
const iconProps = {};
|
||||
let className = '';
|
||||
|
||||
if (iconDisabled) {
|
||||
iconProps.className
|
||||
className
|
||||
= 'settings-button-small-icon settings-button-small-icon--disabled';
|
||||
} else {
|
||||
iconProps.className = 'settings-button-small-icon';
|
||||
className = 'settings-button-small-icon';
|
||||
iconProps.onClick = () => {
|
||||
if (typeof APP !== 'undefined' && notifyMode) {
|
||||
APP.API.notifyToolbarButtonClicked(
|
||||
@@ -141,6 +142,7 @@ export default function ToolboxButtonWithIcon(props: Props) {
|
||||
|
||||
<div>
|
||||
<Tooltip
|
||||
containerClassName = { className }
|
||||
content = { iconTooltip }
|
||||
position = 'top'>
|
||||
<Icon
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
import { Icon } from '../../../icons';
|
||||
import { Tooltip } from '../../../tooltip';
|
||||
import AbstractToolboxItem from '../AbstractToolboxItem';
|
||||
import type { Props } from '../AbstractToolboxItem';
|
||||
|
||||
/**
|
||||
* Web implementation of {@code AbstractToolboxItem}.
|
||||
*/
|
||||
export default class ToolboxItem extends AbstractToolboxItem<Props> {
|
||||
/**
|
||||
* Initializes a new {@code ToolboxItem} instance.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this._onKeyPress = this._onKeyPress.bind(this);
|
||||
}
|
||||
|
||||
_onKeyPress: (Object) => void;
|
||||
|
||||
/**
|
||||
* Handles 'Enter' and Space key on the button to trigger onClick for accessibility.
|
||||
*
|
||||
* @param {Object} event - The key event.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onKeyPress(event) {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault();
|
||||
this.props.onClick();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles rendering of the actual item. If the label is being shown, which
|
||||
* is controlled with the `showLabel` prop, the item is rendered for its
|
||||
* display in an overflow menu, otherwise it will only have an icon, which
|
||||
* can be displayed on any toolbar.
|
||||
*
|
||||
* @protected
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderItem() {
|
||||
const {
|
||||
disabled,
|
||||
elementAfter,
|
||||
onClick,
|
||||
showLabel,
|
||||
tooltipPosition,
|
||||
toggled
|
||||
} = this.props;
|
||||
const className = showLabel ? 'overflow-menu-item' : 'toolbox-button';
|
||||
const props = {
|
||||
'aria-pressed': toggled,
|
||||
'aria-disabled': disabled,
|
||||
'aria-label': this.accessibilityLabel,
|
||||
className: className + (disabled ? ' disabled' : ''),
|
||||
onClick: disabled ? undefined : onClick,
|
||||
onKeyPress: this._onKeyPress,
|
||||
tabIndex: 0,
|
||||
role: 'button'
|
||||
};
|
||||
|
||||
const elementType = showLabel ? 'li' : 'div';
|
||||
const useTooltip = this.tooltip && this.tooltip.length > 0;
|
||||
let children = (
|
||||
<Fragment>
|
||||
{ this._renderIcon() }
|
||||
{ showLabel && <span>
|
||||
{ this.label }
|
||||
</span> }
|
||||
{ elementAfter }
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
if (useTooltip) {
|
||||
children = (
|
||||
<Tooltip
|
||||
content = { this.tooltip }
|
||||
position = { tooltipPosition }>
|
||||
{ children }
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
return React.createElement(elementType, props, children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to render the item's icon.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderIcon() {
|
||||
const { customClass, disabled, icon, showLabel, toggled } = this.props;
|
||||
const iconComponent = <Icon src = { icon } />;
|
||||
const elementType = showLabel ? 'span' : 'div';
|
||||
const className = `${showLabel ? 'overflow-menu-item-icon' : 'toolbox-icon'} ${
|
||||
toggled ? 'toggled' : ''} ${disabled ? 'disabled' : ''} ${customClass ?? ''}`;
|
||||
|
||||
return React.createElement(elementType, { className }, iconComponent);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// @flow
|
||||
|
||||
export { default as OverflowMenuItem } from './OverflowMenuItem';
|
||||
export { default as ToolboxButtonWithIcon } from './ToolboxButtonWithIcon';
|
||||
|
||||
19
react/features/base/tooltip/actionTypes.tsx
Normal file
19
react/features/base/tooltip/actionTypes.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* The type of the action which signals a tooltip is being displayed.
|
||||
*
|
||||
* {
|
||||
* type: SHOW_TOOLTIP,
|
||||
* content: string
|
||||
* }.
|
||||
*/
|
||||
export const SHOW_TOOLTIP = 'SHOW_TOOLTIP';
|
||||
|
||||
/**
|
||||
* The type of the action which signals a tooltip should be hidden.
|
||||
*
|
||||
* {
|
||||
* type: SHOW_TOOLTIP,
|
||||
* content: string
|
||||
* }.
|
||||
*/
|
||||
export const HIDE_TOOLTIP = 'HIDE_TOOLTIP';
|
||||
29
react/features/base/tooltip/actions.tsx
Normal file
29
react/features/base/tooltip/actions.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import { HIDE_TOOLTIP, SHOW_TOOLTIP } from './actionTypes';
|
||||
|
||||
/**
|
||||
* Set tooltip state to visible.
|
||||
*
|
||||
* @param {string} content - The content of the tooltip.
|
||||
* Used as unique identifier for tooltip.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function showTooltip(content: string) {
|
||||
return {
|
||||
type: SHOW_TOOLTIP,
|
||||
content
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set tooltip state to hidden.
|
||||
*
|
||||
* @param {string} content - The content of the tooltip.
|
||||
* Used as unique identifier for tooltip.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function hideTooltip(content: string) {
|
||||
return {
|
||||
type: HIDE_TOOLTIP,
|
||||
content
|
||||
};
|
||||
}
|
||||
150
react/features/base/tooltip/components/Tooltip.tsx
Normal file
150
react/features/base/tooltip/components/Tooltip.tsx
Normal file
@@ -0,0 +1,150 @@
|
||||
import React, { ReactElement, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { keyframes } from 'tss-react';
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { isMobileBrowser } from '../../environment/utils';
|
||||
import Popover from '../../popover/components/Popover.web';
|
||||
import { withPixelLineHeight } from '../../styles/functions.web';
|
||||
import { hideTooltip, showTooltip } from '../actions';
|
||||
|
||||
const TOOLTIP_DELAY = 300;
|
||||
const ANIMATION_DURATION = 0.2;
|
||||
|
||||
interface IProps {
|
||||
children: ReactElement;
|
||||
containerClassName?: string;
|
||||
content: string;
|
||||
position?: 'top' | 'bottom' | 'left' | 'right';
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
container: {
|
||||
backgroundColor: theme.palette.uiBackground,
|
||||
borderRadius: '3px',
|
||||
padding: theme.spacing(2),
|
||||
...withPixelLineHeight(theme.typography.labelRegular),
|
||||
color: theme.palette.text01,
|
||||
position: 'relative',
|
||||
|
||||
'&.mounting-animation': {
|
||||
animation: `${keyframes`
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
`} ${ANIMATION_DURATION}s forwards ease-in`
|
||||
},
|
||||
|
||||
'&.unmounting': {
|
||||
animation: `${keyframes`
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
`} ${ANIMATION_DURATION}s forwards ease-out`
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const Tooltip = ({ containerClassName, content, children, position = 'top' }: IProps) => {
|
||||
const dispatch = useDispatch();
|
||||
const [ visible, setVisible ] = useState(false);
|
||||
const [ isUnmounting, setIsUnmounting ] = useState(false);
|
||||
const { classes, cx } = useStyles();
|
||||
const timeoutID = useRef({
|
||||
open: 0,
|
||||
close: 0
|
||||
});
|
||||
const {
|
||||
content: storeContent,
|
||||
previousContent,
|
||||
visible: isVisible
|
||||
} = useSelector((state: IReduxState) => state['features/base/tooltip']);
|
||||
|
||||
if (isMobileBrowser()) {
|
||||
return children;
|
||||
}
|
||||
|
||||
const contentComponent = (
|
||||
<div
|
||||
className = { cx(classes.container, previousContent === '' && 'mounting-animation',
|
||||
isUnmounting && 'unmounting') }>
|
||||
{content}
|
||||
</div>
|
||||
);
|
||||
|
||||
const openPopover = () => {
|
||||
setVisible(true);
|
||||
dispatch(showTooltip(content));
|
||||
};
|
||||
|
||||
const closePopover = () => {
|
||||
setVisible(false);
|
||||
dispatch(hideTooltip(content));
|
||||
setIsUnmounting(false);
|
||||
};
|
||||
|
||||
const onPopoverOpen = useCallback(() => {
|
||||
clearTimeout(timeoutID.current.close);
|
||||
timeoutID.current.close = 0;
|
||||
if (!visible) {
|
||||
if (isVisible) {
|
||||
openPopover();
|
||||
} else {
|
||||
timeoutID.current.open = window.setTimeout(() => {
|
||||
openPopover();
|
||||
}, TOOLTIP_DELAY);
|
||||
}
|
||||
}
|
||||
}, [ visible, isVisible ]);
|
||||
|
||||
const onPopoverClose = useCallback(() => {
|
||||
clearTimeout(timeoutID.current.open);
|
||||
if (visible) {
|
||||
timeoutID.current.close = window.setTimeout(() => {
|
||||
setIsUnmounting(true);
|
||||
}, TOOLTIP_DELAY);
|
||||
}
|
||||
}, [ visible ]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isUnmounting) {
|
||||
setTimeout(() => {
|
||||
if (timeoutID.current.close !== 0) {
|
||||
closePopover();
|
||||
}
|
||||
}, (ANIMATION_DURATION * 1000) + 10);
|
||||
}
|
||||
}, [ isUnmounting ]);
|
||||
|
||||
useEffect(() => {
|
||||
if (storeContent !== content) {
|
||||
closePopover();
|
||||
clearTimeout(timeoutID.current.close);
|
||||
timeoutID.current.close = 0;
|
||||
}
|
||||
}, [ storeContent ]);
|
||||
|
||||
return (
|
||||
<Popover
|
||||
allowClick = { true }
|
||||
className = { containerClassName }
|
||||
content = { contentComponent }
|
||||
onPopoverClose = { onPopoverClose }
|
||||
onPopoverOpen = { onPopoverOpen }
|
||||
position = { position }
|
||||
visible = { visible }>
|
||||
{children}
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tooltip;
|
||||
@@ -1,50 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import Tooltip from '@atlaskit/tooltip';
|
||||
import React from 'react';
|
||||
|
||||
import { isMobileBrowser } from '../../environment/utils';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Children of the component.
|
||||
*/
|
||||
children: React$Node,
|
||||
|
||||
/**
|
||||
* The text to be displayed in the tooltip.
|
||||
*/
|
||||
content?: string | null,
|
||||
|
||||
/**
|
||||
* The position of the tooltip relative to the element it contains.
|
||||
*/
|
||||
position?: string
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper of AtlasKit Tooltip that doesn't render the actual tooltip in mobile browsers.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
function TooltipWrapper({
|
||||
children,
|
||||
content,
|
||||
position
|
||||
}: Props) {
|
||||
if (isMobileBrowser()) {
|
||||
return children;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content = { content }
|
||||
position = { position }>
|
||||
{children}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
export default TooltipWrapper;
|
||||
@@ -1,3 +0,0 @@
|
||||
// @flow
|
||||
|
||||
export { default as Tooltip } from './TooltipWrapper';
|
||||
@@ -1,3 +0,0 @@
|
||||
// @flow
|
||||
|
||||
export * from './components';
|
||||
50
react/features/base/tooltip/reducer.ts
Normal file
50
react/features/base/tooltip/reducer.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
|
||||
import { HIDE_TOOLTIP, SHOW_TOOLTIP } from './actionTypes';
|
||||
|
||||
export interface ITooltipState {
|
||||
content: string;
|
||||
previousContent: string;
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
content: '',
|
||||
previousContent: '',
|
||||
visible: false
|
||||
};
|
||||
|
||||
/**
|
||||
* Reduces redux actions which mark the tooltip as displayed or hidden.
|
||||
*
|
||||
* @param {IDialogState} state - The current redux state.
|
||||
* @param {Action} action - The redux action to reduce.
|
||||
* @param {string} action.type - The type of the redux action to reduce..
|
||||
* @returns {State} The next redux state that is the result of reducing the
|
||||
* specified action.
|
||||
*/
|
||||
ReducerRegistry.register<ITooltipState>('features/base/tooltip', (state = DEFAULT_STATE, action): ITooltipState => {
|
||||
switch (action.type) {
|
||||
case SHOW_TOOLTIP:
|
||||
return {
|
||||
content: action.content,
|
||||
previousContent: state.content,
|
||||
visible: true
|
||||
};
|
||||
case HIDE_TOOLTIP: {
|
||||
// The tooltip can be marked as hidden only if the hide action
|
||||
// is dispatched by the tooltip that is displayed.
|
||||
if (action.content === state.content) {
|
||||
return {
|
||||
content: '',
|
||||
previousContent: '',
|
||||
visible: false
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
});
|
||||
@@ -126,14 +126,3 @@ export const TRACK_UPDATED = 'TRACK_UPDATED';
|
||||
* }
|
||||
*/
|
||||
export const TRACK_WILL_CREATE = 'TRACK_WILL_CREATE';
|
||||
|
||||
/**
|
||||
* Action to update the redux store with the current media event name of the video track.
|
||||
*
|
||||
* @returns {{
|
||||
* type: TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT,
|
||||
* track: Track,
|
||||
* name: string
|
||||
* }}
|
||||
*/
|
||||
export const TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT = 'TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT';
|
||||
|
||||
@@ -31,7 +31,6 @@ import {
|
||||
TRACK_REMOVED,
|
||||
TRACK_STOPPED,
|
||||
TRACK_UPDATED,
|
||||
TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT,
|
||||
TRACK_WILL_CREATE
|
||||
} from './actionTypes';
|
||||
import {
|
||||
@@ -826,29 +825,6 @@ export function setNoSrcDataNotificationUid(uid?: string) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the last media event received for a video track.
|
||||
*
|
||||
* @param {JitsiRemoteTrack} track - JitsiTrack instance.
|
||||
* @param {string} name - The current media event name for the video.
|
||||
* @returns {{
|
||||
* type: TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT,
|
||||
* track: Track,
|
||||
* name: string
|
||||
* }}
|
||||
*/
|
||||
export function updateLastTrackVideoMediaEvent(track: any, name: string): {
|
||||
name: string;
|
||||
track: any;
|
||||
type: 'TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT';
|
||||
} {
|
||||
return {
|
||||
type: TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT,
|
||||
track,
|
||||
name
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the facingMode constraint on the video stream.
|
||||
*
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
TRACK_OWNER_CHANGED,
|
||||
TRACK_REMOVED,
|
||||
TRACK_UPDATED,
|
||||
TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT,
|
||||
TRACK_WILL_CREATE
|
||||
} from './actionTypes';
|
||||
import { ITrack } from './types';
|
||||
@@ -73,20 +72,7 @@ function track(state: ITrack, action: any) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT: {
|
||||
const t = action.track;
|
||||
|
||||
if (state.jitsiTrack === t) {
|
||||
if (state.lastMediaEvent !== action.name) {
|
||||
|
||||
return {
|
||||
...state,
|
||||
lastMediaEvent: action.name
|
||||
};
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TRACK_NO_DATA_FROM_SOURCE: {
|
||||
const t = action.track;
|
||||
|
||||
@@ -117,7 +103,6 @@ ReducerRegistry.register<ITracksState>('features/base/tracks', (state = [], acti
|
||||
case PARTICIPANT_ID_CHANGED:
|
||||
case TRACK_NO_DATA_FROM_SOURCE:
|
||||
case TRACK_OWNER_CHANGED:
|
||||
case TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT:
|
||||
case TRACK_UPDATED:
|
||||
return state.map((t: ITrack) => track(t, action));
|
||||
case TRACK_ADDED: {
|
||||
|
||||
@@ -46,7 +46,6 @@ export interface ITrackOptions {
|
||||
export interface ITrack {
|
||||
isReceivingData: boolean;
|
||||
jitsiTrack: any;
|
||||
lastMediaEvent?: string;
|
||||
local: boolean;
|
||||
mediaType: MediaType;
|
||||
mirror: boolean;
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
import { translate } from '../../base/i18n';
|
||||
import { Icon, IconPlus } from '../../base/icons';
|
||||
import { connect } from '../../base/redux';
|
||||
import { Tooltip } from '../../base/tooltip';
|
||||
import Tooltip from '../../base/tooltip/components/Tooltip';
|
||||
import { updateCalendarEvent } from '../actions';
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@ import React, { Component } from 'react';
|
||||
|
||||
import { translate } from '../../base/i18n';
|
||||
import { Icon, IconPlus } from '../../base/icons';
|
||||
import { Tooltip } from '../../base/tooltip';
|
||||
import Tooltip from '../../base/tooltip/components/Tooltip';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link JoinButton}.
|
||||
|
||||
8
react/features/conference/actionTypes.ts
Normal file
8
react/features/conference/actionTypes.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* The type of (redux) action which dismisses calendar notification.
|
||||
*
|
||||
* {
|
||||
* type: DISMISS_CALENDAR_NOTIFICATION
|
||||
* }
|
||||
*/
|
||||
export const DISMISS_CALENDAR_NOTIFICATION = 'DISMISS_CALENDAR_NOTIFICATION';
|
||||
@@ -5,6 +5,9 @@ import { openDialog } from '../base/dialog/actions';
|
||||
import { AlertDialog } from '../base/dialog/components/native';
|
||||
import { getParticipantDisplayName } from '../base/participants/functions';
|
||||
|
||||
import { DISMISS_CALENDAR_NOTIFICATION } from './actionTypes';
|
||||
|
||||
|
||||
/**
|
||||
* Notify that we've been kicked out of the conference.
|
||||
*
|
||||
@@ -32,3 +35,14 @@ export function notifyKickedOut(participant: any, submit?: Function) {
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismisses calendar notification about next or ongoing event.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function dismissCalendarNotification() {
|
||||
return {
|
||||
type: DISMISS_CALENDAR_NOTIFICATION
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ import { getParticipantDisplayName } from '../base/participants/functions';
|
||||
import { showNotification } from '../notifications/actions';
|
||||
import { NOTIFICATION_TIMEOUT_TYPE, NOTIFICATION_TYPE } from '../notifications/constants';
|
||||
|
||||
import { DISMISS_CALENDAR_NOTIFICATION } from './actionTypes';
|
||||
|
||||
/**
|
||||
* Notify that we've been kicked out of the conference.
|
||||
*
|
||||
@@ -32,3 +34,14 @@ export function notifyKickedOut(participant: any, _?: Function) {
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismisses calendar notification about next or ongoing event.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function dismissCalendarNotification() {
|
||||
return {
|
||||
type: DISMISS_CALENDAR_NOTIFICATION
|
||||
};
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ const ConferenceTimer = ({ textStyle }: IProps) => {
|
||||
const stopTimer = useCallback(() => {
|
||||
if (interval.current) {
|
||||
clearInterval(interval.current);
|
||||
interval.current = undefined;
|
||||
}
|
||||
|
||||
setTimerValue(getLocalizedDurationFormatter(0));
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import Tooltip from '@atlaskit/tooltip';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
@@ -6,6 +5,7 @@ import { translate } from '../../../base/i18n/functions';
|
||||
import { IconExclamationTriangle } from '../../../base/icons/svg';
|
||||
import Label from '../../../base/label/components/web/Label';
|
||||
import { COLORS } from '../../../base/label/constants';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import AbstractInsecureRoomNameLabel, { _mapStateToProps } from '../AbstractInsecureRoomNameLabel';
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,9 +6,7 @@ import { makeStyles } from 'tss-react/mui';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { IconRaiseHand } from '../../../base/icons/svg';
|
||||
import Label from '../../../base/label/components/web/Label';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import { open as openParticipantsPane } from '../../../participants-pane/actions.web';
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { openDialog } from '../../../base/dialog/actions';
|
||||
import { IconConnection } from '../../../base/icons/svg';
|
||||
import { IconUsers } from '../../../base/icons/svg';
|
||||
import Label from '../../../base/label/components/web/Label';
|
||||
import { COLORS } from '../../../base/label/constants';
|
||||
import { getParticipantCount } from '../../../base/participants/functions';
|
||||
@@ -33,7 +33,7 @@ function SpeakerStatsLabel() {
|
||||
return (
|
||||
<Label
|
||||
color = { COLORS.white }
|
||||
icon = { IconConnection }
|
||||
icon = { IconUsers }
|
||||
iconColor = '#fff'
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick = { onClick }
|
||||
|
||||
@@ -5,9 +5,7 @@ import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import { getConferenceName } from '../../../base/conference/functions';
|
||||
import { withPixelLineHeight } from '../../../base/styles/functions.web';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
@@ -44,13 +42,13 @@ const SubjectText = () => {
|
||||
const { classes } = useStyles();
|
||||
|
||||
return (
|
||||
<div className = { classes.container }>
|
||||
<Tooltip
|
||||
content = { subject }
|
||||
position = 'bottom'>
|
||||
<Tooltip
|
||||
content = { subject }
|
||||
position = 'bottom'>
|
||||
<div className = { classes.container }>
|
||||
<div className = { clsx('subject-text--content', classes.content) }>{subject}</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -5,9 +5,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { IconArrowDown } from '../../../base/icons/svg/index';
|
||||
import Label from '../../../base/label/components/web/Label';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import { setTopPanelVisible } from '../../../filmstrip/actions.web';
|
||||
|
||||
const ToggleTopPanelLabel = () => {
|
||||
|
||||
@@ -36,10 +36,12 @@ import {
|
||||
import { showSalesforceNotification } from '../salesforce/actions';
|
||||
import { setToolboxEnabled } from '../toolbox/actions.any';
|
||||
|
||||
import { DISMISS_CALENDAR_NOTIFICATION } from './actionTypes';
|
||||
// @ts-ignore
|
||||
import { notifyKickedOut } from './actions';
|
||||
import { dismissCalendarNotification, notifyKickedOut } from './actions';
|
||||
|
||||
let intervalId: any;
|
||||
|
||||
let intervalID: any;
|
||||
|
||||
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
@@ -72,10 +74,11 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
break;
|
||||
}
|
||||
|
||||
case DISMISS_CALENDAR_NOTIFICATION:
|
||||
case CONFERENCE_LEFT:
|
||||
case CONFERENCE_FAILED: {
|
||||
clearInterval(intervalId);
|
||||
intervalId = null;
|
||||
clearInterval(intervalID);
|
||||
intervalID = null;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -146,8 +149,8 @@ function _conferenceJoined({ dispatch, getState }: IStore) {
|
||||
getState
|
||||
});
|
||||
|
||||
if (!intervalId) {
|
||||
intervalId = setInterval(() =>
|
||||
if (!intervalID) {
|
||||
intervalID = setInterval(() =>
|
||||
_maybeDisplayCalendarNotification({
|
||||
dispatch,
|
||||
getState
|
||||
@@ -232,20 +235,20 @@ function _calendarNotification({ dispatch, getState }: IStore, eventToShow: any)
|
||||
return;
|
||||
}
|
||||
|
||||
const customActionNameKey = [ 'notify.joinMeeting' ];
|
||||
const customActionType = [ BUTTON_TYPES.PRIMARY ];
|
||||
const customActionNameKey = [ 'notify.joinMeeting', 'notify.dontRemindMe' ];
|
||||
const customActionType = [ BUTTON_TYPES.PRIMARY, BUTTON_TYPES.DESTRUCTIVE ];
|
||||
const customActionHandler = [ () => batch(() => {
|
||||
dispatch(hideNotification(CALENDAR_NOTIFICATION_ID));
|
||||
if (eventToShow?.url && (eventToShow.url !== currentConferenceURL)) {
|
||||
dispatch(appNavigate(eventToShow.url));
|
||||
}
|
||||
}) ];
|
||||
}), () => dispatch(dismissCalendarNotification()) ];
|
||||
const description
|
||||
= getLocalizedDateFormatter(eventToShow.startDate).fromNow();
|
||||
const icon = NOTIFICATION_ICON.WARNING;
|
||||
const title = (eventToShow.startDate < now) && (eventToShow.endDate > now)
|
||||
? i18n.t('calendarSync.ongoingMeeting')
|
||||
: i18n.t('calendarSync.nextMeeting');
|
||||
? `${i18n.t('calendarSync.ongoingMeeting')}: ${eventToShow.title}`
|
||||
: `${i18n.t('calendarSync.nextMeeting')}: ${eventToShow.title}`;
|
||||
const uid = CALENDAR_NOTIFICATION_ID;
|
||||
|
||||
dispatch(showNotification({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable lines-around-comment */
|
||||
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import { StyleProp, View, ViewStyle } from 'react-native';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { IconConnection } from '../../../base/icons/svg';
|
||||
@@ -164,10 +164,11 @@ class ConnectionIndicator extends AbstractConnectionIndicator<IProps, IState> {
|
||||
|
||||
return (
|
||||
<View
|
||||
style = {{
|
||||
...indicatorStyles.indicatorContainer,
|
||||
backgroundColor: indicatorColor
|
||||
}}>
|
||||
style = { [
|
||||
indicatorStyles.indicatorContainer as StyleProp<ViewStyle>,
|
||||
{ backgroundColor: indicatorColor }
|
||||
] }>
|
||||
{/* @ts-ignore */}
|
||||
<BaseIndicator
|
||||
icon = { IconConnection }
|
||||
// @ts-ignore
|
||||
|
||||
@@ -230,12 +230,9 @@ const styles = (theme: Theme) => {
|
||||
},
|
||||
contextMenu: {
|
||||
position: 'relative' as const,
|
||||
marginTop: 0,
|
||||
margin: 0,
|
||||
right: 'auto',
|
||||
padding: `${theme.spacing(2)} ${theme.spacing(1)}`,
|
||||
marginLeft: theme.spacing(1),
|
||||
marginRight: theme.spacing(1),
|
||||
marginBottom: theme.spacing(1)
|
||||
padding: `${theme.spacing(2)} ${theme.spacing(1)}`
|
||||
},
|
||||
download: {},
|
||||
mobile: {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IStore } from '../app/types';
|
||||
import { IStateful } from '../base/app/types';
|
||||
import { getWebHIDFeatureConfig } from '../base/config/functions.web';
|
||||
import {
|
||||
addPendingDeviceRequest,
|
||||
getAvailableDevices,
|
||||
@@ -46,7 +47,7 @@ export function getAudioDeviceSelectionDialogProps(stateful: IStateful, isDispla
|
||||
const inputDeviceChangeSupported = JitsiMeetJS.mediaDevices.isDeviceChangeAvailable('input');
|
||||
const speakerChangeSupported = JitsiMeetJS.mediaDevices.isDeviceChangeAvailable('output');
|
||||
const userSelectedMic = getUserSelectedMicDeviceId(state);
|
||||
const deviceHidSupported = isDeviceHidSupported();
|
||||
const deviceHidSupported = isDeviceHidSupported() && getWebHIDFeatureConfig(state);
|
||||
const noiseSuppressionEnabled = isNoiseSuppressionEnabled(state);
|
||||
const hideNoiseSuppression = isPrejoinPageVisible(state) || isDisplayedOnWelcomePage;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ export default {
|
||||
displayNameBackdrop: {
|
||||
alignSelf: 'center',
|
||||
backgroundColor: BaseTheme.palette.ui16,
|
||||
borderRadius: 4,
|
||||
borderRadius: BaseTheme.shape.borderRadius,
|
||||
paddingHorizontal: BaseTheme.spacing[3],
|
||||
paddingVertical: BaseTheme.spacing[1]
|
||||
},
|
||||
|
||||
@@ -10,9 +10,7 @@ import {
|
||||
} from '../../../base/participants/functions';
|
||||
import { updateSettings } from '../../../base/settings/actions';
|
||||
import { withPixelLineHeight } from '../../../base/styles/functions.web';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import { getIndicatorsTooltipPosition } from '../../../filmstrip/functions.web';
|
||||
import { appendSuffix } from '../../functions';
|
||||
|
||||
|
||||
@@ -5,9 +5,7 @@ import { translate } from '../../base/i18n/functions';
|
||||
import { IconE2EE } from '../../base/icons/svg';
|
||||
import Label from '../../base/label/components/web/Label';
|
||||
import { COLORS } from '../../base/label/constants';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../base/tooltip';
|
||||
import Tooltip from '../../base/tooltip/components/Tooltip';
|
||||
|
||||
import { IProps, _mapStateToProps } from './AbstractE2EELabel';
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import { Platform } from '../../../base/react';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
|
||||
import { getHideSelfView } from '../../../base/settings/functions.any';
|
||||
import { areThereNotifications } from '../../../notifications/functions';
|
||||
import { isToolboxVisible } from '../../../toolbox/functions';
|
||||
import { setVisibleRemoteParticipants } from '../../actions';
|
||||
import {
|
||||
@@ -53,8 +52,6 @@ type Props = {
|
||||
|
||||
_localParticipantId: string,
|
||||
|
||||
_notificationsAvailable: boolean,
|
||||
|
||||
/**
|
||||
* The participants in the conference.
|
||||
*/
|
||||
@@ -252,7 +249,6 @@ class Filmstrip extends PureComponent<Props> {
|
||||
_disableSelfView,
|
||||
_toolboxVisible,
|
||||
_localParticipantId,
|
||||
_notificationsAvailable,
|
||||
_participants,
|
||||
_visible
|
||||
} = this.props;
|
||||
@@ -261,7 +257,7 @@ class Filmstrip extends PureComponent<Props> {
|
||||
return null;
|
||||
}
|
||||
|
||||
const bottomEdge = Platform.OS === 'ios' && !_toolboxVisible && !_notificationsAvailable;
|
||||
const bottomEdge = Platform.OS === 'ios' && !_toolboxVisible;
|
||||
const isNarrowAspectRatio = _aspectRatio === ASPECT_RATIO_NARROW;
|
||||
const filmstripStyle = isNarrowAspectRatio ? styles.filmstripNarrow : styles.filmstripWide;
|
||||
const { height, width } = this._getDimensions();
|
||||
@@ -335,7 +331,6 @@ function _mapStateToProps(state) {
|
||||
_clientWidth: responsiveUI.clientWidth,
|
||||
_disableSelfView: disableSelfView,
|
||||
_localParticipantId: getLocalParticipant(state)?.id,
|
||||
_notificationsAvailable: areThereNotifications(state),
|
||||
_participants: showRemoteVideos ? remoteParticipants : NO_REMOTE_VIDEOS,
|
||||
_toolboxVisible: isToolboxVisible(state),
|
||||
_visible: enabled && isFilmstripVisible(state)
|
||||
|
||||
@@ -7,12 +7,21 @@ import { IconRaiseHand } from '../../../base/icons';
|
||||
import { BaseIndicator } from '../../../base/react';
|
||||
import { connect } from '../../../base/redux';
|
||||
import AbstractRaisedHandIndicator, {
|
||||
type Props,
|
||||
type Props as AbstractProps,
|
||||
_mapStateToProps
|
||||
} from '../AbstractRaisedHandIndicator';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
type Props = AbstractProps & {
|
||||
|
||||
/**
|
||||
* Whether or not tile view layout has been enabled as the user preference.
|
||||
*/
|
||||
isTileViewEnabled: boolean
|
||||
};
|
||||
|
||||
/**
|
||||
* Thumbnail badge showing that the participant would like to speak.
|
||||
*
|
||||
@@ -25,8 +34,13 @@ class RaisedHandIndicator extends AbstractRaisedHandIndicator<Props> {
|
||||
* @returns {React$Element<*>}
|
||||
*/
|
||||
_renderIndicator() {
|
||||
const { isTileViewEnabled } = this.props;
|
||||
const raisedHandIndicatorStyles = isTileViewEnabled
|
||||
? styles.raisedHandIndicatorTileView
|
||||
: styles.raisedHandIndicator;
|
||||
|
||||
return (
|
||||
<View style = { styles.raisedHandIndicator }>
|
||||
<View style = { raisedHandIndicatorStyles }>
|
||||
<BaseIndicator
|
||||
icon = { IconRaiseHand }
|
||||
iconStyle = { styles.raisedHandIcon } />
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
showSharedVideoMenu
|
||||
} from '../../../participants-pane/actions.native';
|
||||
import { toggleToolboxVisible } from '../../../toolbox/actions.native';
|
||||
import { shouldDisplayTileView } from '../../../video-layout';
|
||||
import { SQUARE_TILE_ASPECT_RATIO } from '../../constants';
|
||||
|
||||
import AudioMutedIndicator from './AudioMutedIndicator';
|
||||
@@ -65,6 +66,11 @@ type Props = {
|
||||
*/
|
||||
_isScreenShare: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not tile view layout has been enabled as the user preference.
|
||||
*/
|
||||
_isTileViewEnabled: boolean,
|
||||
|
||||
/**
|
||||
* Indicates whether the thumbnail is for a virtual screenshare participant.
|
||||
*/
|
||||
@@ -205,6 +211,7 @@ class Thumbnail extends PureComponent<Props> {
|
||||
const {
|
||||
_audioMuted: audioMuted,
|
||||
_fakeParticipant,
|
||||
_isTileViewEnabled,
|
||||
_isScreenShare: isScreenShare,
|
||||
_isVirtualScreenshare,
|
||||
_renderModeratorIndicator: renderModeratorIndicator,
|
||||
@@ -218,12 +225,13 @@ class Thumbnail extends PureComponent<Props> {
|
||||
if (!_fakeParticipant || _isVirtualScreenshare) {
|
||||
indicators.push(<View
|
||||
key = 'top-left-indicators'
|
||||
style = { [
|
||||
styles.thumbnailTopIndicatorContainer,
|
||||
styles.thumbnailTopLeftIndicatorContainer
|
||||
] }>
|
||||
style = { styles.thumbnailTopLeftIndicatorContainer }>
|
||||
{ !_isVirtualScreenshare && <ConnectionIndicator participantId = { participantId } /> }
|
||||
{ !_isVirtualScreenshare && <RaisedHandIndicator participantId = { participantId } /> }
|
||||
{
|
||||
!_isVirtualScreenshare && <RaisedHandIndicator
|
||||
isTileView = { _isTileViewEnabled }
|
||||
participantId = { participantId } />
|
||||
}
|
||||
{ tileView && isScreenShare && (
|
||||
<View style = { styles.indicatorContainer }>
|
||||
<ScreenShareIndicator />
|
||||
@@ -416,6 +424,7 @@ function _mapStateToProps(state, ownProps) {
|
||||
_fakeParticipant: participant?.fakeParticipant,
|
||||
_gifSrc: mode === 'chat' ? null : gifSrc,
|
||||
_isScreenShare: isScreenShare,
|
||||
_isTileViewEnabled: shouldDisplayTileView(state),
|
||||
_isVirtualScreenshare: isScreenShareParticipant(participant),
|
||||
_local: participant?.local,
|
||||
_localVideoOwner: Boolean(ownerId === localParticipantId),
|
||||
|
||||
@@ -14,10 +14,14 @@ const indicatorContainer = {
|
||||
height: 24,
|
||||
justifyContent: 'center',
|
||||
margin: 2,
|
||||
minWidth: 16,
|
||||
padding: 2
|
||||
};
|
||||
|
||||
const raisedHandIndicator = {
|
||||
...indicatorContainer,
|
||||
backgroundColor: BaseTheme.palette.warning02
|
||||
};
|
||||
|
||||
/**
|
||||
* The styles of the feature filmstrip.
|
||||
*/
|
||||
@@ -107,7 +111,7 @@ export default {
|
||||
thumbnail: {
|
||||
alignItems: 'stretch',
|
||||
backgroundColor: BaseTheme.palette.ui02,
|
||||
borderColor: '#424242',
|
||||
borderColor: BaseTheme.palette.border03,
|
||||
borderRadius: BaseTheme.shape.borderRadius,
|
||||
borderStyle: 'solid',
|
||||
borderWidth: 1,
|
||||
@@ -131,10 +135,10 @@ export default {
|
||||
*/
|
||||
thumbnailIndicatorContainer: {
|
||||
...indicatorContainer,
|
||||
bottom: BaseTheme.spacing[1],
|
||||
bottom: 3,
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
left: BaseTheme.spacing[1],
|
||||
left: 3,
|
||||
position: 'absolute',
|
||||
maxWidth: '95%',
|
||||
overflow: 'hidden',
|
||||
@@ -146,20 +150,22 @@ export default {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
|
||||
thumbnailTopIndicatorContainer: {
|
||||
flexDirection: 'row',
|
||||
padding: BaseTheme.spacing[1],
|
||||
position: 'absolute',
|
||||
top: BaseTheme.spacing[0]
|
||||
},
|
||||
|
||||
thumbnailTopLeftIndicatorContainer: {
|
||||
left: BaseTheme.spacing[0]
|
||||
...indicatorContainer,
|
||||
backgroundColor: 'unset',
|
||||
flexDirection: 'row',
|
||||
position: 'absolute',
|
||||
top: BaseTheme.spacing[1]
|
||||
},
|
||||
|
||||
raisedHandIndicator: {
|
||||
...indicatorContainer,
|
||||
backgroundColor: BaseTheme.palette.warning02
|
||||
...raisedHandIndicator,
|
||||
left: 14
|
||||
},
|
||||
|
||||
raisedHandIndicatorTileView: {
|
||||
...raisedHandIndicator,
|
||||
left: 2
|
||||
},
|
||||
|
||||
raisedHandIcon: {
|
||||
@@ -172,7 +178,7 @@ export default {
|
||||
},
|
||||
|
||||
thumbnailDominantSpeaker: {
|
||||
borderWidth: 4,
|
||||
borderWidth: 2,
|
||||
borderColor: BaseTheme.palette.action01Hover
|
||||
},
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ interface IProps {
|
||||
/**
|
||||
* From which side of the indicator the tooltip should appear from.
|
||||
*/
|
||||
tooltipPosition: string;
|
||||
tooltipPosition: 'top' | 'bottom' | 'left' | 'right';
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()(() => {
|
||||
|
||||
@@ -27,7 +27,7 @@ interface IProps {
|
||||
/**
|
||||
* From which side of the indicator the tooltip should appear from.
|
||||
*/
|
||||
tooltipPosition: string;
|
||||
tooltipPosition: 'top' | 'bottom' | 'left' | 'right';
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
|
||||
@@ -22,6 +22,7 @@ import { pinParticipant } from '../../../base/participants/actions';
|
||||
import {
|
||||
getLocalParticipant,
|
||||
getParticipantByIdOrUndefined,
|
||||
getScreenshareParticipantIds,
|
||||
hasRaisedHand,
|
||||
isLocalScreenshareParticipant,
|
||||
isScreenShareParticipant,
|
||||
@@ -29,10 +30,8 @@ import {
|
||||
} from '../../../base/participants/functions';
|
||||
import { IParticipant } from '../../../base/participants/types';
|
||||
import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
|
||||
import { isTestModeEnabled } from '../../../base/testing/functions';
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import { trackStreamingStatusChanged, updateLastTrackVideoMediaEvent } from '../../../base/tracks/actions';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import { trackStreamingStatusChanged } from '../../../base/tracks/actions';
|
||||
import {
|
||||
getLocalAudioTrack,
|
||||
getTrackByMediaTypeAndParticipant,
|
||||
@@ -51,8 +50,7 @@ import {
|
||||
DISPLAY_VIDEO,
|
||||
FILMSTRIP_TYPE,
|
||||
SHOW_TOOLBAR_CONTEXT_MENU_AFTER,
|
||||
THUMBNAIL_TYPE,
|
||||
VIDEO_TEST_EVENTS
|
||||
THUMBNAIL_TYPE
|
||||
} from '../../constants';
|
||||
import {
|
||||
computeDisplayModeFromInput,
|
||||
@@ -169,11 +167,6 @@ export interface IProps extends WithTranslation {
|
||||
*/
|
||||
_isScreenSharing: boolean;
|
||||
|
||||
/**
|
||||
* Indicates whether testing mode is enabled.
|
||||
*/
|
||||
_isTestModeEnabled: boolean;
|
||||
|
||||
/**
|
||||
* Indicates whether the video associated with the thumbnail is playable.
|
||||
*/
|
||||
@@ -452,7 +445,6 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
trailing: false
|
||||
});
|
||||
this._onMouseLeave = this._onMouseLeave.bind(this);
|
||||
this._onTestingEvent = this._onTestingEvent.bind(this);
|
||||
this._onTouchStart = this._onTouchStart.bind(this);
|
||||
this._onTouchEnd = this._onTouchEnd.bind(this);
|
||||
this._onTouchMove = this._onTouchMove.bind(this);
|
||||
@@ -657,6 +649,17 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size the avatar should have.
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
_getAvatarSize() {
|
||||
const { _height, _width } = this.props;
|
||||
|
||||
return Math.min(_height / 2, _width - 30, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object with the styles for thumbnail.
|
||||
*
|
||||
@@ -694,7 +697,7 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
video: {}
|
||||
};
|
||||
|
||||
const avatarSize = Math.min(_height / 2, _width - 30, 200);
|
||||
const avatarSize = this._getAvatarSize();
|
||||
let { left } = style || {};
|
||||
|
||||
if (typeof left === 'number' && horizontalOffset) {
|
||||
@@ -930,7 +933,8 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
style = { styles }>
|
||||
<Avatar
|
||||
className = 'userAvatar'
|
||||
participantId = { id } />
|
||||
participantId = { id }
|
||||
size = { this._getAvatarSize() } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1009,36 +1013,10 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
/**
|
||||
* Canplay event listener.
|
||||
*
|
||||
* @param {SyntheticEvent} event - The event.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onCanPlay(event: any) {
|
||||
_onCanPlay() {
|
||||
this.setState({ canPlayEventReceived: true });
|
||||
|
||||
const {
|
||||
_isTestModeEnabled,
|
||||
_videoTrack
|
||||
} = this.props;
|
||||
|
||||
if (_videoTrack && _isTestModeEnabled) {
|
||||
this._onTestingEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler for testing events.
|
||||
*
|
||||
* @param {SyntheticEvent} event - The event.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onTestingEvent(event: any) {
|
||||
const {
|
||||
_videoTrack,
|
||||
dispatch
|
||||
} = this.props;
|
||||
const jitsiVideoTrack = _videoTrack?.jitsiTrack;
|
||||
|
||||
dispatch(updateLastTrackVideoMediaEvent(jitsiVideoTrack, event.type));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1055,7 +1033,6 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
_isMobile,
|
||||
_isMobilePortrait,
|
||||
_isScreenSharing,
|
||||
_isTestModeEnabled,
|
||||
_localFlipX,
|
||||
_participant,
|
||||
_shouldDisplayTintBackground,
|
||||
@@ -1084,11 +1061,6 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
containerClassName = `${containerClassName} self-view-mobile-portrait`;
|
||||
}
|
||||
} else {
|
||||
if (_videoTrack && _isTestModeEnabled) {
|
||||
VIDEO_TEST_EVENTS.forEach(attribute => {
|
||||
videoEventListeners[attribute] = this._onTestingEvent;
|
||||
});
|
||||
}
|
||||
videoEventListeners.onCanPlay = this._onCanPlay;
|
||||
}
|
||||
|
||||
@@ -1204,12 +1176,10 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
_isTestModeEnabled,
|
||||
_isVirtualScreenshareParticipant,
|
||||
_participant,
|
||||
_shouldDisplayTintBackground
|
||||
} = this.props;
|
||||
const videoEventListeners: any = {};
|
||||
|
||||
if (!_participant) {
|
||||
return null;
|
||||
@@ -1232,13 +1202,6 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
const { isHovered } = this.state;
|
||||
const { _videoTrack, _isMobile, classes, _thumbnailType } = this.props;
|
||||
|
||||
if (_isTestModeEnabled) {
|
||||
VIDEO_TEST_EVENTS.forEach(attribute => {
|
||||
videoEventListeners[attribute] = this._onTestingEvent;
|
||||
});
|
||||
videoEventListeners.onCanPlay = this._onCanPlay;
|
||||
}
|
||||
|
||||
return (
|
||||
<VirtualScreenshareParticipant
|
||||
classes = { classes }
|
||||
@@ -1386,9 +1349,14 @@ function _mapStateToProps(state: IReduxState, ownProps: any): Object {
|
||||
const participantId = isLocal ? getLocalParticipant(state)?.id : participantID;
|
||||
const isActiveParticipant = activeParticipants.find((pId: string) => pId === participantId);
|
||||
const participantCurrentlyOnLargeVideo = state['features/large-video']?.participantId === id;
|
||||
const screenshareParticipantIds = getScreenshareParticipantIds(state);
|
||||
|
||||
const shouldDisplayTintBackground
|
||||
= _currentLayout !== LAYOUTS.TILE_VIEW && filmstripType === FILMSTRIP_TYPE.MAIN
|
||||
&& (isActiveParticipant || participantCurrentlyOnLargeVideo);
|
||||
&& (isActiveParticipant || participantCurrentlyOnLargeVideo)
|
||||
|
||||
// skip showing tint for owner participants that are screensharing.
|
||||
&& !screenshareParticipantIds.includes(id);
|
||||
|
||||
return {
|
||||
_audioTrack,
|
||||
@@ -1404,7 +1372,6 @@ function _mapStateToProps(state: IReduxState, ownProps: any): Object {
|
||||
_isMobile,
|
||||
_isMobilePortrait,
|
||||
_isScreenSharing: _videoTrack?.videoType === 'desktop',
|
||||
_isTestModeEnabled: isTestModeEnabled(state),
|
||||
_isVideoPlayable: id && isVideoPlayable(state, id),
|
||||
_isVirtualScreenshareParticipant,
|
||||
_localFlipX: Boolean(localFlipX),
|
||||
|
||||
@@ -63,30 +63,6 @@ export const DEFAULT_MAX_COLUMNS = 5;
|
||||
*/
|
||||
export const ABSOLUTE_MAX_COLUMNS = 7;
|
||||
|
||||
/**
|
||||
* An array of attributes of the video element that will be used for adding a listener for every event in the list.
|
||||
* The latest event will be stored in redux. This is currently used by torture only.
|
||||
*/
|
||||
export const VIDEO_TEST_EVENTS = [
|
||||
'onAbort',
|
||||
'onCanPlay',
|
||||
'onCanPlayThrough',
|
||||
'onEmptied',
|
||||
'onEnded',
|
||||
'onError',
|
||||
'onLoadedData',
|
||||
'onLoadedMetadata',
|
||||
'onLoadStart',
|
||||
'onPause',
|
||||
'onPlay',
|
||||
'onPlaying',
|
||||
'onRateChange',
|
||||
'onStalled',
|
||||
'onSuspend',
|
||||
'onWaiting'
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Display mode constant used when video is being displayed on the small video.
|
||||
*
|
||||
@@ -246,7 +222,9 @@ export const STATS_POPOVER_POSITION = {
|
||||
/**
|
||||
* The tooltip position for the indicators on the thumbnail.
|
||||
*/
|
||||
export const INDICATORS_TOOLTIP_POSITION = {
|
||||
export const INDICATORS_TOOLTIP_POSITION: {
|
||||
[x: string]: 'right' | 'left' | 'top';
|
||||
} = {
|
||||
[THUMBNAIL_TYPE.TILE]: 'right',
|
||||
[THUMBNAIL_TYPE.VERTICAL]: 'left',
|
||||
[THUMBNAIL_TYPE.HORIZONTAL]: 'top'
|
||||
|
||||
@@ -11,9 +11,7 @@ import {
|
||||
IconOffice365,
|
||||
IconYahoo
|
||||
} from '../../../../base/icons/svg';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../../base/tooltip';
|
||||
import Tooltip from '../../../../base/tooltip/components/Tooltip';
|
||||
import { copyText } from '../../../../base/util/copyText.web';
|
||||
|
||||
interface IProps {
|
||||
|
||||
@@ -31,17 +31,6 @@ export const SET_LARGE_VIDEO_DIMENSIONS = 'SET_LARGE_VIDEO_DIMENSIONS';
|
||||
export const UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION
|
||||
= 'UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION';
|
||||
|
||||
/**
|
||||
* Action to update the redux store with the current media event name of large video.
|
||||
*
|
||||
* @returns {{
|
||||
* type: UPDATE_LAST_LARGE_VIDEO_MEDIA_EVENT,
|
||||
* name: string
|
||||
* }}
|
||||
*/
|
||||
export const UPDATE_LAST_LARGE_VIDEO_MEDIA_EVENT
|
||||
= 'UPDATE_LAST_LARGE_VIDEO_MEDIA_EVENT';
|
||||
|
||||
/**
|
||||
* Action to set the redux store of the current show me what I'm sharing flag value.
|
||||
*
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { IReduxState, IStore } from '../app/types';
|
||||
import { getSsrcRewritingFeatureFlag } from '../base/config/functions.any';
|
||||
import { IStateful } from '../base/app/types';
|
||||
import { MEDIA_TYPE } from '../base/media/constants';
|
||||
import {
|
||||
getDominantSpeakerParticipant,
|
||||
getLocalParticipant,
|
||||
getLocalScreenShareParticipant,
|
||||
getParticipantById,
|
||||
getPinnedParticipant,
|
||||
getRemoteParticipants,
|
||||
getVirtualScreenshareParticipantByOwnerId
|
||||
} from '../base/participants/functions';
|
||||
import { ITrack } from '../base/tracks/types';
|
||||
import { toState } from '../base/redux/functions';
|
||||
import { isStageFilmstripAvailable } from '../filmstrip/functions';
|
||||
import { getAutoPinSetting } from '../video-layout/functions';
|
||||
|
||||
@@ -104,17 +105,24 @@ export function setLargeVideoDimensions(height: number, width: number) {
|
||||
/**
|
||||
* Returns the most recent existing remote video track.
|
||||
*
|
||||
* @param {Track[]} tracks - All current tracks.
|
||||
* @param {Function|Object} stateful - The redux store or {@code getState} function.
|
||||
* @private
|
||||
* @returns {(Track|undefined)}
|
||||
*/
|
||||
function _electLastVisibleRemoteVideo(tracks: ITrack[]) {
|
||||
function _electLastVisibleRemoteParticipant(stateful: IStateful) {
|
||||
const state = toState(stateful);
|
||||
const tracks = state['features/base/tracks'];
|
||||
|
||||
// First we try to get most recent remote video track.
|
||||
for (let i = tracks.length - 1; i >= 0; --i) {
|
||||
const track = tracks[i];
|
||||
|
||||
if (!track.local && track.mediaType === MEDIA_TYPE.VIDEO) {
|
||||
return track;
|
||||
if (!track.local && track.mediaType === MEDIA_TYPE.VIDEO && track.participantId) {
|
||||
const participant = getParticipantById(state, track.participantId);
|
||||
|
||||
if (participant) {
|
||||
return participant;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,14 +179,10 @@ function _electParticipantInLargeVideo(state: IReduxState) {
|
||||
participant = undefined;
|
||||
|
||||
// Next, pick the most recent participant with video.
|
||||
// (Skip this if rewriting, tracks may be detached from any owner.)
|
||||
if (!getSsrcRewritingFeatureFlag(state)) {
|
||||
const tracks = state['features/base/tracks'];
|
||||
const videoTrack = _electLastVisibleRemoteVideo(tracks);
|
||||
const lastVisibleRemoteParticipant = _electLastVisibleRemoteParticipant(state);
|
||||
|
||||
if (videoTrack) {
|
||||
return videoTrack.participantId;
|
||||
}
|
||||
if (lastVisibleRemoteParticipant) {
|
||||
return lastVisibleRemoteParticipant.id;
|
||||
}
|
||||
|
||||
// Last, select the participant that joined last (other than poltergist or other bot type participants).
|
||||
|
||||
@@ -4,7 +4,7 @@ import { IStore } from '../app/types';
|
||||
import { MEDIA_TYPE } from '../base/media/constants';
|
||||
import { getTrackByMediaTypeAndParticipant } from '../base/tracks/functions.web';
|
||||
|
||||
import { SET_SEE_WHAT_IS_BEING_SHARED, UPDATE_LAST_LARGE_VIDEO_MEDIA_EVENT } from './actionTypes';
|
||||
import { SET_SEE_WHAT_IS_BEING_SHARED } from './actionTypes';
|
||||
|
||||
export * from './actions.any';
|
||||
|
||||
@@ -84,22 +84,6 @@ export function resizeLargeVideo(width: number, height: number) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the last media event received for the large video.
|
||||
*
|
||||
* @param {string} name - The current media event name for the video.
|
||||
* @returns {{
|
||||
* type: UPDATE_LAST_LARGE_VIDEO_MEDIA_EVENT,
|
||||
* name: string
|
||||
* }}
|
||||
*/
|
||||
export function updateLastLargeVideoMediaEvent(name: String) {
|
||||
return {
|
||||
type: UPDATE_LAST_LARGE_VIDEO_MEDIA_EVENT,
|
||||
name
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the value used to display what is being shared.
|
||||
*
|
||||
|
||||
@@ -5,13 +5,11 @@ import {
|
||||
SELECT_LARGE_VIDEO_PARTICIPANT,
|
||||
SET_LARGE_VIDEO_DIMENSIONS,
|
||||
SET_SEE_WHAT_IS_BEING_SHARED,
|
||||
UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION,
|
||||
UPDATE_LAST_LARGE_VIDEO_MEDIA_EVENT
|
||||
UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION
|
||||
} from './actionTypes';
|
||||
|
||||
export interface ILargeVideoState {
|
||||
height?: number;
|
||||
lastMediaEvent?: string;
|
||||
participantId?: string;
|
||||
resolution?: number;
|
||||
seeWhatIsBeingShared?: boolean;
|
||||
@@ -54,12 +52,6 @@ ReducerRegistry.register<ILargeVideoState>('features/large-video', (state = {},
|
||||
resolution: action.resolution
|
||||
};
|
||||
|
||||
case UPDATE_LAST_LARGE_VIDEO_MEDIA_EVENT:
|
||||
return {
|
||||
...state,
|
||||
lastMediaEvent: action.name
|
||||
};
|
||||
|
||||
case SET_SEE_WHAT_IS_BEING_SHARED:
|
||||
return {
|
||||
...state,
|
||||
|
||||
@@ -9,6 +9,14 @@ const unreadCounterDescription = {
|
||||
color: BaseTheme.palette.text03
|
||||
};
|
||||
|
||||
const HEADER_ACTION_BUTTON_SIZE = 16;
|
||||
|
||||
const headerNavigationButtonLabel = {
|
||||
color: BaseTheme.palette.link01,
|
||||
fontSize: HEADER_ACTION_BUTTON_SIZE,
|
||||
lineHeight: BaseTheme.spacing[3]
|
||||
};
|
||||
|
||||
/**
|
||||
* Styles of the navigation feature.
|
||||
*/
|
||||
@@ -39,12 +47,12 @@ export const navigationStyles = {
|
||||
},
|
||||
|
||||
headerNavigationButtonLabel: {
|
||||
color: BaseTheme.palette.link01
|
||||
...headerNavigationButtonLabel
|
||||
},
|
||||
|
||||
headerNavigationButtonLabelBold: {
|
||||
...BaseTheme.typography.bodyShortRegularLarge,
|
||||
color: BaseTheme.palette.link01
|
||||
...headerNavigationButtonLabel,
|
||||
...BaseTheme.typography.bodyShortRegularLarge
|
||||
},
|
||||
|
||||
unreadCounterContainer: {
|
||||
|
||||
@@ -50,6 +50,7 @@ export function setNoiseSuppressionEnabled(enabled: boolean): any {
|
||||
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
|
||||
const { noiseSuppression: nsOptions } = state['features/base/config'];
|
||||
const localAudio = getLocalJitsiAudioTrack(state);
|
||||
const noiseSuppressionEnabled = isNoiseSuppressionEnabled(state);
|
||||
|
||||
@@ -61,7 +62,7 @@ export function setNoiseSuppressionEnabled(enabled: boolean): any {
|
||||
return;
|
||||
}
|
||||
|
||||
await localAudio.setEffect(new NoiseSuppressionEffect());
|
||||
await localAudio.setEffect(new NoiseSuppressionEffect(nsOptions));
|
||||
dispatch(setNoiseSuppressionEnabledState(true));
|
||||
logger.info('Noise suppression enabled.');
|
||||
|
||||
|
||||
@@ -1,32 +1,39 @@
|
||||
// @flow
|
||||
/* eslint-disable lines-around-comment */
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { Platform } from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { Edge, SafeAreaView } from 'react-native-safe-area-context';
|
||||
|
||||
import { connect } from '../../../base/redux';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { connect } from '../../../base/redux/functions';
|
||||
import { hideNotification } from '../../actions';
|
||||
import { areThereNotifications } from '../../functions';
|
||||
import NotificationsTransition from '../NotificationsTransition';
|
||||
|
||||
import Notification from './Notification';
|
||||
// @ts-ignore
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
type Props = {
|
||||
interface IProps extends WithTranslation {
|
||||
|
||||
/**
|
||||
* The notifications to be displayed, with the first index being the
|
||||
* notification at the top and the rest shown below it in order.
|
||||
*/
|
||||
_notifications: Array<Object>,
|
||||
_notifications: Array<Object>;
|
||||
|
||||
/**
|
||||
* Invoked to update the redux store in order to remove notifications.
|
||||
*/
|
||||
dispatch: Function,
|
||||
dispatch: Function;
|
||||
|
||||
toolboxVisible: boolean
|
||||
};
|
||||
/**
|
||||
* Checks toolbox visibility.
|
||||
*/
|
||||
toolboxVisible: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a React {@link Component} which displays notifications and handles
|
||||
@@ -35,19 +42,19 @@ type Props = {
|
||||
*
|
||||
* @augments {Component}
|
||||
*/
|
||||
class NotificationsContainer extends Component<Props> {
|
||||
class NotificationsContainer extends Component<IProps> {
|
||||
|
||||
/**
|
||||
* A timeout id returned by setTimeout.
|
||||
*/
|
||||
_notificationDismissTimeout: ?TimeoutID;
|
||||
_notificationDismissTimeout: any;
|
||||
|
||||
/**
|
||||
* Initializes a new {@code NotificationsContainer} instance.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
/**
|
||||
@@ -70,6 +77,7 @@ class NotificationsContainer extends Component<Props> {
|
||||
*/
|
||||
componentDidMount() {
|
||||
// Set the initial dismiss timeout (if any)
|
||||
// @ts-ignore
|
||||
this._manageDismissTimeout();
|
||||
}
|
||||
|
||||
@@ -78,37 +86,36 @@ class NotificationsContainer extends Component<Props> {
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
componentDidUpdate(prevProps: IProps) {
|
||||
this._manageDismissTimeout(prevProps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets/clears the dismiss timeout for the top notification.
|
||||
*
|
||||
* @param {P} [prevProps] - The previous properties (if called from
|
||||
* @param {IProps} [prevProps] - The previous properties (if called from
|
||||
* {@code componentDidUpdate}).
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
_manageDismissTimeout(prevProps: ?Props) {
|
||||
_manageDismissTimeout(prevProps: IProps) {
|
||||
const { _notifications } = this.props;
|
||||
|
||||
if (_notifications.length) {
|
||||
const notification = _notifications[0];
|
||||
const previousNotification
|
||||
= prevProps && prevProps._notifications.length
|
||||
? prevProps._notifications[0]
|
||||
: undefined;
|
||||
const previousNotification = prevProps?._notifications.length
|
||||
? prevProps._notifications[0] : undefined;
|
||||
|
||||
if (notification !== previousNotification) {
|
||||
this._clearNotificationDismissTimeout();
|
||||
|
||||
if (notification && notification.timeout) {
|
||||
const {
|
||||
timeout,
|
||||
uid
|
||||
} = notification;
|
||||
// @ts-ignore
|
||||
if (notification?.timeout) {
|
||||
|
||||
// @ts-ignore
|
||||
const { timeout, uid } = notification;
|
||||
|
||||
// @ts-ignore
|
||||
this._notificationDismissTimeout = setTimeout(() => {
|
||||
// Perform a no-op if a timeout is not specified.
|
||||
this._onDismissed(uid);
|
||||
@@ -142,21 +149,20 @@ class NotificationsContainer extends Component<Props> {
|
||||
this._notificationDismissTimeout = null;
|
||||
}
|
||||
|
||||
_onDismissed: number => void;
|
||||
|
||||
/**
|
||||
* Emits an action to remove the notification from the redux store so it
|
||||
* stops displaying.
|
||||
*
|
||||
* @param {number} uid - The id of the notification to be removed.
|
||||
* @param {Object} uid - The id of the notification to be removed.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onDismissed(uid) {
|
||||
_onDismissed(uid: any) {
|
||||
const { _notifications } = this.props;
|
||||
|
||||
// Clear the timeout only if it's the top notification that's being
|
||||
// dismissed (the timeout is set only for the top one).
|
||||
// @ts-ignore
|
||||
if (!_notifications.length || _notifications[0].uid === uid) {
|
||||
this._clearNotificationDismissTimeout();
|
||||
}
|
||||
@@ -171,20 +177,23 @@ class NotificationsContainer extends Component<Props> {
|
||||
*/
|
||||
render() {
|
||||
const { _notifications, toolboxVisible } = this.props;
|
||||
const bottomEdge = Platform.OS === 'ios' && !toolboxVisible;
|
||||
const notificationsContainerStyle
|
||||
= toolboxVisible ? styles.withToolbox : styles.withoutToolbox;
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
edges = { [ bottomEdge && 'bottom', 'left', 'right' ].filter(Boolean) }>
|
||||
edges = { [ Platform.OS === 'ios' && 'bottom', 'left', 'right' ].filter(Boolean) as Edge[] }
|
||||
style = { notificationsContainerStyle as any }>
|
||||
<NotificationsTransition>
|
||||
{
|
||||
_notifications.map((notification, index) => {
|
||||
_notifications.map(notification => {
|
||||
// @ts-ignore
|
||||
const { props, uid } = notification;
|
||||
|
||||
return (
|
||||
<Notification
|
||||
{ ...props }
|
||||
key = { index }
|
||||
key = { uid }
|
||||
onDismissed = { this._onDismissed }
|
||||
uid = { uid } />
|
||||
);
|
||||
@@ -194,8 +203,6 @@ class NotificationsContainer extends Component<Props> {
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
_onDismissed: number => void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,7 +213,7 @@ class NotificationsContainer extends Component<Props> {
|
||||
* @private
|
||||
* @returns {Props}
|
||||
*/
|
||||
export function mapStateToProps(state: Object) {
|
||||
export function mapStateToProps(state: IReduxState) {
|
||||
const { notifications } = state['features/notifications'];
|
||||
const _visible = areThereNotifications(state);
|
||||
|
||||
@@ -105,5 +105,16 @@ export default {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
marginLeft: BaseTheme.spacing[1]
|
||||
},
|
||||
|
||||
withToolbox: {
|
||||
bottom: 64,
|
||||
position: 'absolute',
|
||||
width: '100%'
|
||||
},
|
||||
|
||||
withoutToolbox: {
|
||||
position: 'absolute',
|
||||
width: '100%'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -104,7 +104,8 @@ const useStyles = makeStyles()((theme: Theme) => {
|
||||
display: 'flex',
|
||||
alignItems: 'flex-start',
|
||||
padding: '8px 0',
|
||||
flex: 1
|
||||
flex: 1,
|
||||
maxWidth: '100%'
|
||||
},
|
||||
|
||||
textContainer: {
|
||||
@@ -113,7 +114,11 @@ const useStyles = makeStyles()((theme: Theme) => {
|
||||
justifyContent: 'space-between',
|
||||
color: theme.palette.text04,
|
||||
flex: 1,
|
||||
margin: '0 8px'
|
||||
margin: '0 8px',
|
||||
|
||||
// maxWidth: 100% minus the icon on left (20px) minus the close icon on the right (20px) minus the margins
|
||||
maxWidth: 'calc(100% - 40px - 16px)',
|
||||
maxHeight: '150px'
|
||||
},
|
||||
|
||||
title: {
|
||||
@@ -122,6 +127,8 @@ const useStyles = makeStyles()((theme: Theme) => {
|
||||
|
||||
description: {
|
||||
...withPixelLineHeight(theme.typography.bodyShortRegular),
|
||||
overflow: 'auto',
|
||||
overflowWrap: 'break-word',
|
||||
|
||||
'&:not(:empty)': {
|
||||
marginTop: theme.spacing(1)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import AbstractToolbarButton from '../../../toolbox/components/AbstractToolbarButton';
|
||||
import type { Props as AbstractToolbarButtonProps } from '../../../toolbox/components/AbstractToolbarButton';
|
||||
|
||||
|
||||
@@ -10,9 +10,7 @@ import { IconHighlight } from '../../../../base/icons/svg';
|
||||
import { MEET_FEATURES } from '../../../../base/jwt/constants';
|
||||
import Label from '../../../../base/label/components/web/Label';
|
||||
import { connect } from '../../../../base/redux/functions';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../../base/tooltip';
|
||||
import Tooltip from '../../../../base/tooltip/components/Tooltip';
|
||||
import BaseTheme from '../../../../base/ui/components/BaseTheme.web';
|
||||
import { maybeShowPremiumFeatureDialog } from '../../../../jaas/actions';
|
||||
import AbstractHighlightButton, {
|
||||
|
||||
@@ -7,9 +7,7 @@ import { IconRecord, IconSites } from '../../../base/icons/svg';
|
||||
import Label from '../../../base/label/components/web/Label';
|
||||
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
|
||||
import { connect } from '../../../base/redux/functions';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import AbstractRecordingLabel, {
|
||||
_mapStateToProps
|
||||
|
||||
|
||||
@@ -207,14 +207,14 @@ export function processPermissionRequestReply(participantId: string, event: any)
|
||||
// the remote control permissions has been granted
|
||||
// pin the controlled participant
|
||||
const pinnedParticipant = getPinnedParticipant(state);
|
||||
const virtualScreenshareParticipantId = getVirtualScreenshareParticipantByOwnerId(state, participantId);
|
||||
const virtualScreenshareParticipant = getVirtualScreenshareParticipantByOwnerId(state, participantId);
|
||||
const pinnedId = pinnedParticipant?.id;
|
||||
|
||||
// @ts-ignore
|
||||
if (virtualScreenshareParticipantId && pinnedId !== virtualScreenshareParticipantId) {
|
||||
if (virtualScreenshareParticipant?.id && pinnedId !== virtualScreenshareParticipant?.id) {
|
||||
// @ts-ignore
|
||||
dispatch(pinParticipant(virtualScreenshareParticipantId));
|
||||
} else if (!virtualScreenshareParticipantId && pinnedId !== participantId) {
|
||||
dispatch(pinParticipant(virtualScreenshareParticipant?.id));
|
||||
} else if (!virtualScreenshareParticipant?.id && pinnedId !== participantId) {
|
||||
dispatch(pinParticipant(participantId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,7 @@ import {
|
||||
IconEmotionsSad,
|
||||
IconEmotionsSurprised
|
||||
} from '../../../base/icons/svg';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import Dialog from '../../../base/ui/components/web/Dialog';
|
||||
import { escapeRegexp } from '../../../base/util/helpers';
|
||||
import { initSearch, resetSearchCriteria, toggleFaceExpressions } from '../../actions.any';
|
||||
|
||||
@@ -79,13 +79,13 @@ const SpeakerStatsItem = (props: Props) => {
|
||||
<StatelessAvatar
|
||||
className = 'userAvatar'
|
||||
color = { BaseTheme.palette.ui04 }
|
||||
initials = { getInitials(props.displayName) } />
|
||||
initials = { getInitials(props.displayName) }
|
||||
size = { 32 } />
|
||||
) : (
|
||||
<Avatar
|
||||
|
||||
// @ts-ignore
|
||||
className = 'userAvatar'
|
||||
participantId = { props.participantId } />
|
||||
participantId = { props.participantId }
|
||||
size = { 32 } />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -23,9 +23,7 @@ const useStyles = makeStyles()(theme => {
|
||||
color: theme.palette.text03
|
||||
},
|
||||
'& .avatar': {
|
||||
width: '32px',
|
||||
marginRight: theme.spacing(3),
|
||||
height: theme.spacing(5)
|
||||
marginRight: theme.spacing(3)
|
||||
},
|
||||
'& .time': {
|
||||
padding: '2px 4px',
|
||||
|
||||
@@ -1,18 +1,30 @@
|
||||
import { INoiseSuppressionConfig } from '../../base/config/configType';
|
||||
import { getBaseUrl } from '../../base/util/helpers';
|
||||
|
||||
import logger from './logger';
|
||||
|
||||
interface IKrispState {
|
||||
filterNode?: AudioWorkletNode;
|
||||
filterNodeReady: boolean;
|
||||
sdk: any;
|
||||
sdkInitialized: boolean;
|
||||
}
|
||||
|
||||
const krispState: IKrispState = {
|
||||
filterNode: undefined,
|
||||
filterNodeReady: false,
|
||||
sdk: undefined,
|
||||
sdkInitialized: false
|
||||
};
|
||||
|
||||
let audioContext: AudioContext;
|
||||
|
||||
/**
|
||||
* Class Implementing the effect interface expected by a JitsiLocalTrack.
|
||||
* Effect applies rnnoise denoising on a audio JitsiLocalTrack.
|
||||
*/
|
||||
export class NoiseSuppressionEffect {
|
||||
|
||||
/**
|
||||
* Web audio context.
|
||||
*/
|
||||
private _audioContext: AudioContext;
|
||||
|
||||
/**
|
||||
* Source that will be attached to the track affected by the effect.
|
||||
*/
|
||||
@@ -26,7 +38,7 @@ export class NoiseSuppressionEffect {
|
||||
/**
|
||||
* `AudioWorkletProcessor` associated node.
|
||||
*/
|
||||
private _noiseSuppressorNode: AudioWorkletNode;
|
||||
private _noiseSuppressorNode?: AudioWorkletNode;
|
||||
|
||||
/**
|
||||
* Audio track extracted from the original MediaStream to which the effect is applied.
|
||||
@@ -38,6 +50,24 @@ export class NoiseSuppressionEffect {
|
||||
*/
|
||||
private _outputMediaTrack: MediaStreamTrack;
|
||||
|
||||
/**
|
||||
* Configured options for noise suppression.
|
||||
*/
|
||||
private _options?: INoiseSuppressionConfig;
|
||||
|
||||
/**
|
||||
* Instantiates a noise suppressor audio effect which will use either rnnoise or krisp.
|
||||
*
|
||||
* @param {INoiseSuppressionConfig} options - Configured options.
|
||||
*/
|
||||
constructor(options?: INoiseSuppressionConfig) {
|
||||
this._options = options;
|
||||
|
||||
const useKrisp = options?.krisp?.enabled;
|
||||
|
||||
logger.info(`NoiseSuppressionEffect created with ${useKrisp ? 'Krisp' : 'RNNoise'}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Effect interface called by source JitsiLocalTrack.
|
||||
* Applies effect that uses a {@code NoiseSuppressor} service initialized with {@code RnnoiseProcessor}
|
||||
@@ -48,23 +78,39 @@ export class NoiseSuppressionEffect {
|
||||
*/
|
||||
startEffect(audioStream: MediaStream): MediaStream {
|
||||
this._originalMediaTrack = audioStream.getAudioTracks()[0];
|
||||
this._audioContext = new AudioContext();
|
||||
this._audioSource = this._audioContext.createMediaStreamSource(audioStream);
|
||||
this._audioDestination = this._audioContext.createMediaStreamDestination();
|
||||
|
||||
if (!audioContext) {
|
||||
audioContext = new AudioContext();
|
||||
}
|
||||
|
||||
this._audioSource = audioContext.createMediaStreamSource(audioStream);
|
||||
this._audioDestination = audioContext.createMediaStreamDestination();
|
||||
this._outputMediaTrack = this._audioDestination.stream.getAudioTracks()[0];
|
||||
|
||||
const baseUrl = `${getBaseUrl()}libs/`;
|
||||
const workletUrl = `${baseUrl}noise-suppressor-worklet.min.js`;
|
||||
let init;
|
||||
|
||||
if (this._options?.krisp?.enabled) {
|
||||
init = _initializeKrisp(this._options).then(filterNode => {
|
||||
this._noiseSuppressorNode = filterNode;
|
||||
|
||||
if (krispState.filterNodeReady) {
|
||||
// @ts-ignore
|
||||
krispState.filterNode?.enable();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
init = _initializeKRnnoise().then(filterNode => {
|
||||
this._noiseSuppressorNode = filterNode;
|
||||
});
|
||||
}
|
||||
|
||||
// Connect the audio processing graph MediaStream -> AudioWorkletNode -> MediaStreamAudioDestinationNode
|
||||
this._audioContext.audioWorklet.addModule(workletUrl)
|
||||
.then(() => {
|
||||
// After the resolution of module loading, an AudioWorkletNode can be constructed.
|
||||
this._noiseSuppressorNode = new AudioWorkletNode(this._audioContext, 'NoiseSuppressorWorklet');
|
||||
this._audioSource.connect(this._noiseSuppressorNode).connect(this._audioDestination);
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('Error while adding audio worklet module: ', error);
|
||||
|
||||
init.then(() => {
|
||||
if (this._noiseSuppressorNode) {
|
||||
this._audioSource.connect(this._noiseSuppressorNode);
|
||||
this._noiseSuppressorNode.connect(this._audioDestination);
|
||||
}
|
||||
});
|
||||
|
||||
// Sync the effect track muted state with the original track state.
|
||||
@@ -97,13 +143,103 @@ export class NoiseSuppressionEffect {
|
||||
// Sync original track muted state with effect state before removing the effect.
|
||||
this._originalMediaTrack.enabled = this._outputMediaTrack.enabled;
|
||||
|
||||
// Technically after this process the Audio Worklet along with it's resources should be garbage collected,
|
||||
// however on chrome there seems to be a problem as described here:
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=1298955
|
||||
this._noiseSuppressorNode?.port?.close();
|
||||
if (this._options?.krisp?.enabled) {
|
||||
// When using Krisp we'll just disable the filter which we'll keep reusing.
|
||||
|
||||
// @ts-ignore
|
||||
this._noiseSuppressorNode?.disable();
|
||||
} else {
|
||||
// Technically after this process the Audio Worklet along with it's resources should be garbage collected,
|
||||
// however on chrome there seems to be a problem as described here:
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=1298955
|
||||
this._noiseSuppressorNode?.port?.close();
|
||||
}
|
||||
|
||||
this._audioDestination?.disconnect();
|
||||
this._noiseSuppressorNode?.disconnect();
|
||||
this._audioSource?.disconnect();
|
||||
this._audioContext?.close();
|
||||
|
||||
audioContext.suspend();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the Krisp SDK and creates the filter node.
|
||||
*
|
||||
* @param {INoiseSuppressionConfig} options - Krisp options.
|
||||
*
|
||||
* @returns {Promise<AudioWorkletNode | undefined>}
|
||||
*/
|
||||
async function _initializeKrisp(options: INoiseSuppressionConfig): Promise<AudioWorkletNode | undefined> {
|
||||
await audioContext.resume();
|
||||
|
||||
if (!krispState.sdk) {
|
||||
const baseUrl = `${getBaseUrl()}libs/krisp`;
|
||||
const { default: KrispSDK } = await import(/* webpackIgnore: true */ `${baseUrl}/krispsdk.mjs`);
|
||||
|
||||
krispState.sdk = new KrispSDK({
|
||||
params: {
|
||||
models: {
|
||||
model8: `${baseUrl}/models/model_8.kw`,
|
||||
model16: `${baseUrl}/models/model_16.kw`,
|
||||
model32: `${baseUrl}/models/model_32.kw`
|
||||
},
|
||||
logProcessStats: options?.krisp?.logProcessStats,
|
||||
debugLogs: options?.krisp?.debugLogs
|
||||
},
|
||||
callbacks: {}
|
||||
});
|
||||
}
|
||||
|
||||
if (!krispState.sdkInitialized) {
|
||||
// @ts-ignore
|
||||
await krispState.sdk?.init();
|
||||
|
||||
krispState.sdkInitialized = true;
|
||||
}
|
||||
|
||||
if (!krispState.filterNode) {
|
||||
try {
|
||||
// @ts-ignore
|
||||
krispState.filterNode = await krispState.sdk?.createNoiseFilter(audioContext, () => {
|
||||
logger.info('Krisp audio filter ready');
|
||||
|
||||
// Enable audio filtering.
|
||||
// @ts-ignore
|
||||
krispState.filterNode?.enable();
|
||||
krispState.filterNodeReady = true;
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error('Failed to create Krisp noise filter', e);
|
||||
|
||||
krispState.filterNode = undefined;
|
||||
krispState.filterNodeReady = false;
|
||||
}
|
||||
}
|
||||
|
||||
return krispState.filterNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the RNNoise audio worklet and creates the filter node.
|
||||
*
|
||||
* @returns {Promise<AudioWorkletNode | undefined>}
|
||||
*/
|
||||
async function _initializeKRnnoise(): Promise<AudioWorkletNode | undefined> {
|
||||
await audioContext.resume();
|
||||
|
||||
const baseUrl = `${getBaseUrl()}libs/`;
|
||||
const workletUrl = `${baseUrl}noise-suppressor-worklet.min.js`;
|
||||
|
||||
try {
|
||||
await audioContext.audioWorklet.addModule(workletUrl);
|
||||
} catch (e) {
|
||||
logger.error('Error while adding audio worklet module: ', e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// After the resolution of module loading, an AudioWorkletNode can be constructed.
|
||||
|
||||
return new AudioWorkletNode(audioContext, 'NoiseSuppressorWorklet');
|
||||
}
|
||||
|
||||
@@ -31,6 +31,12 @@ type Props = {
|
||||
* Custom style to apply to the container div.
|
||||
*/
|
||||
style?: any;
|
||||
|
||||
/**
|
||||
* The selector for the element we consider the content container.
|
||||
* This is used to determine the correct size of the portal content.
|
||||
*/
|
||||
targetSelector?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -39,7 +45,7 @@ type Props = {
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
function DialogPortal({ children, className, style, getRef, setSize }: Props) {
|
||||
function DialogPortal({ children, className, style, getRef, setSize, targetSelector }: Props) {
|
||||
const clientWidth = useSelector((state: IReduxState) => state['features/base/responsive-ui'].clientWidth);
|
||||
const [ portalTarget ] = useState(() => {
|
||||
const portalDiv = document.createElement('div');
|
||||
@@ -87,13 +93,15 @@ function DialogPortal({ children, className, style, getRef, setSize }: Props) {
|
||||
}
|
||||
});
|
||||
|
||||
const target = targetSelector ? portalTarget.querySelector(targetSelector) : portalTarget;
|
||||
|
||||
if (document.body) {
|
||||
document.body.appendChild(portalTarget);
|
||||
observer.observe(portalTarget);
|
||||
observer.observe(target ?? portalTarget);
|
||||
}
|
||||
|
||||
return () => {
|
||||
observer.unobserve(portalTarget);
|
||||
observer.unobserve(target ?? portalTarget);
|
||||
if (document.body) {
|
||||
document.body.removeChild(portalTarget);
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@ import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../base/i18n/functions';
|
||||
import Label from '../../base/label/components/web/Label';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../base/tooltip';
|
||||
import Tooltip from '../../base/tooltip/components/Tooltip';
|
||||
|
||||
import { Props, _mapStateToProps } from './AbstractTranscribingLabel';
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { IconPerformance } from '../../base/icons';
|
||||
import { Label } from '../../base/label';
|
||||
import { COLORS } from '../../base/label/constants';
|
||||
import { connect } from '../../base/redux';
|
||||
import { Tooltip } from '../../base/tooltip';
|
||||
import Tooltip from '../../base/tooltip/components/Tooltip';
|
||||
import { shouldDisplayTileView } from '../../video-layout';
|
||||
|
||||
import AbstractVideoQualityLabel, {
|
||||
|
||||
@@ -14,8 +14,7 @@ import { translate } from '../../base/i18n/functions';
|
||||
import Icon from '../../base/icons/components/Icon';
|
||||
import { IconCloseLarge } from '../../base/icons/svg';
|
||||
import { withPixelLineHeight } from '../../base/styles/functions.web';
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../base/tooltip';
|
||||
import Tooltip from '../../base/tooltip/components/Tooltip';
|
||||
import Spinner from '../../base/ui/components/web/Spinner';
|
||||
import { BACKGROUNDS_LIMIT, IMAGES, type Image, VIRTUAL_BACKGROUND_TYPE } from '../constants';
|
||||
import { toDataURL } from '../functions';
|
||||
@@ -430,7 +429,7 @@ function VirtualBackgrounds({
|
||||
</Tooltip>
|
||||
{_images.map(image => (
|
||||
<Tooltip
|
||||
content = { image.tooltip && t(`virtualBackground.${image.tooltip}`) }
|
||||
content = { (image.tooltip && t(`virtualBackground.${image.tooltip}`)) ?? '' }
|
||||
key = { image.id }
|
||||
position = { 'top' }>
|
||||
<img
|
||||
|
||||
@@ -6,9 +6,7 @@ import { makeStyles } from 'tss-react/mui';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { IconUsers } from '../../../base/icons/svg';
|
||||
import Label from '../../../base/label/components/web/Label';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import { getVisitorsShortText, iAmVisitor } from '../../functions';
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
|
||||
@@ -210,40 +210,37 @@ class WelcomePage extends AbstractWelcomePage {
|
||||
{ t('welcomepage.headerSubtitle')}
|
||||
</span>
|
||||
<div id = 'enter_room'>
|
||||
<div className = 'enter-room-input-container'>
|
||||
<form onSubmit = { this._onFormSubmit }>
|
||||
<input
|
||||
aria-disabled = 'false'
|
||||
aria-label = 'Meeting name input'
|
||||
autoFocus = { true }
|
||||
className = 'enter-room-input'
|
||||
id = 'enter_room_field'
|
||||
onChange = { this._onRoomChange }
|
||||
pattern = { ROOM_NAME_VALIDATE_PATTERN_STR }
|
||||
placeholder = { this.state.roomPlaceholder }
|
||||
ref = { this._setRoomInputRef }
|
||||
title = { t('welcomepage.roomNameAllowedChars') }
|
||||
type = 'text'
|
||||
value = { this.state.room } />
|
||||
<div
|
||||
className = { _moderatedRoomServiceUrl
|
||||
? 'warning-with-link'
|
||||
: 'warning-without-link' }>
|
||||
{ this._renderInsecureRoomNameWarning() }
|
||||
</div>
|
||||
</form>
|
||||
<div className = 'join-meeting-container'>
|
||||
<div className = 'enter-room-input-container'>
|
||||
<form onSubmit = { this._onFormSubmit }>
|
||||
<input
|
||||
aria-disabled = 'false'
|
||||
aria-label = 'Meeting name input'
|
||||
autoFocus = { true }
|
||||
className = 'enter-room-input'
|
||||
id = 'enter_room_field'
|
||||
onChange = { this._onRoomChange }
|
||||
pattern = { ROOM_NAME_VALIDATE_PATTERN_STR }
|
||||
placeholder = { this.state.roomPlaceholder }
|
||||
ref = { this._setRoomInputRef }
|
||||
title = { t('welcomepage.roomNameAllowedChars') }
|
||||
type = 'text'
|
||||
value = { this.state.room } />
|
||||
</form>
|
||||
</div>
|
||||
<button
|
||||
aria-disabled = 'false'
|
||||
aria-label = 'Start meeting'
|
||||
className = 'welcome-page-button'
|
||||
id = 'enter_room_button'
|
||||
onClick = { this._onFormSubmit }
|
||||
tabIndex = '0'
|
||||
type = 'button'>
|
||||
{ t('welcomepage.startMeeting') }
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
aria-disabled = 'false'
|
||||
aria-label = 'Start meeting'
|
||||
className = 'welcome-page-button'
|
||||
id = 'enter_room_button'
|
||||
onClick = { this._onFormSubmit }
|
||||
tabIndex = '0'
|
||||
type = 'button'>
|
||||
{ t('welcomepage.startMeeting') }
|
||||
</button>
|
||||
</div>
|
||||
{ this._renderInsecureRoomNameWarning() }
|
||||
|
||||
{ _moderatedRoomServiceUrl && (
|
||||
<div id = 'moderated-meetings'>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"node_modules",
|
||||
"react/features/analytics/handlers/GoogleAnalyticsHandler.ts",
|
||||
"react/features/base/components/participants-pane-list",
|
||||
"react/features/base/tooltip",
|
||||
"react/features/connection-stats",
|
||||
"react/features/desktop-picker",
|
||||
"react/features/e2ee",
|
||||
|
||||
Reference in New Issue
Block a user