Compare commits

...

21 Commits

Author SHA1 Message Date
Hristo Terezov
8a8707d778 fix(remote-control):Pin the control participant SS 2023-03-17 13:48:23 -05:00
Hristo Terezov
16115a3a16 fix(large-video):Dont elect participants that left 2023-03-17 09:59:27 -05:00
Calin-Teodor
7c17d80ae8 feat(filmstrip): thumnail indicators ui updates 2023-03-17 14:39:22 +02:00
Robert Pintilii
511548060a fix(speaker-stats) Change icon (#13074) 2023-03-17 14:20:14 +02:00
Robert Pintilii
00780929e5 feat(tooltip) Create and move to our component (#13061)
Create Tooltip component
Fix Popover positioning calculations
Add margins to popover
Remove @atlaskit/tooltip
Update all components to use the new Tooltip component

Added tooltip actions and reducers for the following functionality: when a user hovers over an element is sees the tooltip for that element and then hovers another element that has a tooltip, instead of using the delay and animations we just unmount the current tooltip and mount the next one immediately
2023-03-17 12:23:51 +02:00
Robert Pintilii
a89f762a66 fix(conference-timer) Show correct time (#13070)
Show meeting time after returning from breakout room
2023-03-17 12:23:20 +02:00
Saúl Ibarra Corretgé
82a03c36c6 deps(rn) react-native@0.68.6
Final minor update to 0.68: https://github.com/facebook/react-native/releases/tag/v0.68.6
2023-03-17 09:44:28 +01:00
Robert Pintilii
7968578a25 fix(notification) Fix overflow issue (#13068)
When displaying a long URL break it into multiple lines
2023-03-17 10:25:52 +02:00
Duduman Bogdan Vlad
62b6411bb6 feat(webhid) - add webhid feature flag (#13071) 2023-03-17 10:24:29 +02:00
Robert Pintilii
b3bce9e5ae fix(audio-picker) Fix max height (#13069) 2023-03-17 09:54:27 +02:00
Christoph Settgast
ed37bedee2 lang: update German translation (#13065) 2023-03-16 22:22:18 +01:00
Jaya Allamsetty
2182a1e452 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1592.0.0+6afb0a56...v1595.0.0+5155e550
2023-03-16 16:40:45 -04:00
Calinteodor
4eea924c02 feat(mobile/navigation): fixed close button size (#13063) 2023-03-16 17:53:31 +02:00
Saúl Ibarra Corretgé
de3b6d2a9f feat(noise-suppression) add support for Krisp 2023-03-16 14:50:47 +01:00
Horatiu Muresan
2a090d8034 fix(welcome-header) Fix and improve welcome page header (#13056)
- small refactor
2023-03-16 12:50:59 +02:00
Calinteodor
238def34cf feat(conference): dismiss calendar notification (#13050)
* feat(conference): created action that dismisses calendar notification
2023-03-16 12:17:57 +02:00
Robert Pintilii
43c4ec0808 feat(avatar) Update style (#13019) 2023-03-16 10:20:16 +02:00
Duduman Bogdan Vlad
7910554625 feat(thumbnail,filmstrip) - remove tint from owner screenshare participants (#12944) 2023-03-16 08:59:43 +02:00
Jaya Allamsetty
56d2af197e fix(thumbnail) Fix broken video for thumbnail.
Fixes a regression introduced by 466a36dc93
2023-03-15 17:36:52 -04:00
Jaya Allamsetty
466a36dc93 fix(test) Switch to using 'streamingStatus' on the track for checking… (#13055)
* fix(test) Switch to using 'streamingStatus' on the track for checking if video is received

* fix lint error
2023-03-15 11:24:36 -04:00
Calinteodor
1fc5d6e97e feat(notifications): NotificationsContainer native updates (#13047)
feat(notifications): NotificationsContainer native updates
2023-03-14 19:53:55 +02:00
91 changed files with 1167 additions and 1216 deletions

View File

@@ -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.

View File

@@ -5,7 +5,7 @@
position: relative;
right: auto;
margin-bottom: 4px;
max-height: 456px;
max-height: calc(100vh - 100px);
overflow: auto;
width: 300px;

View File

@@ -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 {

View File

@@ -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%;

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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",

View File

@@ -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",

View File

@@ -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
View File

@@ -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",

View File

@@ -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",

View File

@@ -1,6 +1,5 @@
// @flow
import '../base/devices/reducer';
import '../base/tooltip/reducer';
import '../e2ee/reducer';
import '../face-landmarks/reducer';
import '../feedback/reducer';

View File

@@ -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;

View File

@@ -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%'
};

View File

@@ -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;

View File

@@ -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.
*

View File

@@ -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>
);
}

View File

@@ -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`
};
};

View File

@@ -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()(() => {

View File

@@ -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));
}

View File

@@ -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';

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -1,4 +1,3 @@
// @flow
export { default as OverflowMenuItem } from './OverflowMenuItem';
export { default as ToolboxButtonWithIcon } from './ToolboxButtonWithIcon';

View 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';

View 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
};
}

View 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;

View File

@@ -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;

View File

@@ -1,3 +0,0 @@
// @flow
export { default as Tooltip } from './TooltipWrapper';

View File

@@ -1,3 +0,0 @@
// @flow
export * from './components';

View 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;
});

View File

@@ -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';

View File

@@ -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.
*

View File

@@ -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: {

View File

@@ -46,7 +46,6 @@ export interface ITrackOptions {
export interface ITrack {
isReceivingData: boolean;
jitsiTrack: any;
lastMediaEvent?: string;
local: boolean;
mediaType: MediaType;
mirror: boolean;

View File

@@ -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';
/**

View File

@@ -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}.

View 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';

View File

@@ -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
};
}

View File

@@ -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
};
}

View File

@@ -82,6 +82,7 @@ const ConferenceTimer = ({ textStyle }: IProps) => {
const stopTimer = useCallback(() => {
if (interval.current) {
clearInterval(interval.current);
interval.current = undefined;
}
setTimerValue(getLocalizedDurationFormatter(0));

View File

@@ -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';
/**

View File

@@ -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 => {

View File

@@ -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 }

View File

@@ -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>
);
};

View File

@@ -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 = () => {

View File

@@ -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({

View File

@@ -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

View File

@@ -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: {

View File

@@ -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;

View File

@@ -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]
},

View File

@@ -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';

View File

@@ -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';

View File

@@ -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)

View File

@@ -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 } />

View File

@@ -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),

View File

@@ -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
},

View File

@@ -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()(() => {

View File

@@ -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 => {

View File

@@ -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),

View File

@@ -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'

View File

@@ -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 {

View File

@@ -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.
*

View File

@@ -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).

View File

@@ -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.
*

View File

@@ -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,

View File

@@ -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: {

View File

@@ -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.');

View File

@@ -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);

View File

@@ -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%'
}
};

View File

@@ -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)

View File

@@ -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';

View File

@@ -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, {

View File

@@ -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

View File

@@ -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));
}
}

View File

@@ -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';

View File

@@ -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>

View File

@@ -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',

View File

@@ -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');
}

View File

@@ -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);
}

View File

@@ -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';

View File

@@ -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, {

View File

@@ -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

View File

@@ -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 => {

View File

@@ -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'>

View File

@@ -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",