Compare commits

..

39 Commits

Author SHA1 Message Date
Saúl Ibarra Corretgé
38068b33e5 fix(notifications) remove dead code 2023-02-14 10:11:08 +01:00
Robert Pintilii
22ded30b61 feat(audio-menu) Redesign audio picker menu (#12899)
Convert some files to TS
Remove unnecessary files
Implement redesign
Add noise suppression to picker menu
Fix Popover placement on browser resize
2023-02-13 16:01:08 +02:00
Robert Pintilii
533deea5fd ref(password-required) Update component to use new Dialog (#12900)
Convert component to TS
2023-02-13 15:47:42 +02:00
Saúl Ibarra Corretgé
46c6d1057d fix(ios) avoid getting duplicated SDK events
UIView has 2 designated initializers: initWithFrame and initWithCoder,
which means either of them is going to be called, whatever the
constructor.

THus overriding init will cause creating new (and unnecessary)
observers.

Ref: https://community.jitsi.org/t/duplicate-delegate-calls/121051/6
Fixes: https://github.com/jitsi/jitsi-meet/issues/12892
2023-02-13 14:20:44 +01:00
Titus Moldovan
45aa53b1a6 chore(rn) updates react-native-gesture-handler 2023-02-13 15:11:31 +02:00
damencho
7d65123495 fix: Drop unused dependency. 2023-02-13 06:48:53 +01:00
Maria Mironova
e1ac000cd1 fix(chat) keep avatar width inside flex container (#12891)
Co-authored-by: Maria Mironova <maria@example.com>
2023-02-10 14:31:11 +02:00
Saúl Ibarra Corretgé
f98036efa1 fixup! 2023-02-09 16:38:03 +01:00
Saúl Ibarra Corretgé
23aeafcc93 fixup! 2023-02-09 16:38:03 +01:00
Saúl Ibarra Corretgé
0ffe2c2c87 fixup! 2023-02-09 16:38:03 +01:00
Saúl Ibarra Corretgé
dec58afe46 feat(icons) add new moderator icon 2023-02-09 16:38:03 +01:00
Mihaela Dumitru
2aa770e532 feat(config) add flag to disable lobby password & group lobby config flags (#12793) 2023-02-09 14:46:25 +02:00
Gabriel Borlea
1a113ba733 feat: add custom buttons for participant menu and toolbar via config (#12832)
* add custom remote menu button

* add config for custom buttons

* whitelist custom buttons flag

* add toolbox custom button

* fix notify toolbox buttons

* whitelist toolbar custom buttons

* rename and fix notify

* rename participant remote menu

* revert some flag wrong changes

* fix some formatings

* add undefined type to custom buttons toolbox

* code review

* code review 2

* fix linting issue
2023-02-09 13:12:00 +02:00
dependabot[bot]
3a5833829c chore(deps): bump @sideway/formula from 3.0.0 to 3.0.1
Bumps [@sideway/formula](https://github.com/sideway/formula) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/sideway/formula/releases)
- [Commits](https://github.com/sideway/formula/compare/v3.0.0...v3.0.1)

---
updated-dependencies:
- dependency-name: "@sideway/formula"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-09 10:36:48 +01:00
Priyanshu Sharma
e6d1f039d2 fix(participant-count) Fix mobile style (#12880) 2023-02-09 10:10:16 +02:00
Horatiu Muresan
fef78152e1 fix(remote-control) Add some missing key codes for numpad (#12879) 2023-02-07 17:00:59 +02:00
Mihaela Dumitru
84221c5c13 feat(dialout) check appId for permission to call outbound destination (#12871) 2023-02-07 16:18:27 +02:00
Calinteodor
3e59359563 feat(base/icon): removed burger icon (#12876)
* feat(base/icons): removed unused icon
2023-02-07 13:02:15 +02:00
Calin-Teodor
e69db9b878 feat(participants-pane): removed unused action 2023-02-07 12:40:35 +02:00
Robert Pintilii
ae7e441e21 fix(context-menu) Minor style fixes (#12874) 2023-02-07 12:05:46 +02:00
Robert Pintilii
6b8afbcceb fix(filmstrip) Minor style fixes (#12870) 2023-02-07 10:10:28 +02:00
José Luís Andrade
d712a565f8 lang: Update Portuguese translation (#12647)
* Update Portuguese translation

* Small fix in the translation

* Add new update

* feat(audioOnly) translation

* chore(welcome-page) translation

* translate "noMicPermission"
2023-02-03 11:41:11 -06:00
Saúl Ibarra Corretgé
36bfbeb81d fix(etherpad) avoid using deprecated property 2023-02-03 15:52:26 +01:00
Saúl Ibarra Corretgé
e7b16b0daf fix(etherpad) fix CORS issues
Avoid modifying the iframe. We don't really need to bubble up mouse
events anymore since the Etherpad frame won't overlap with the toolbar
or filmstrip, so when the user moves over those areas it will just show
up.
2023-02-03 15:52:26 +01:00
Saúl Ibarra Corretgé
92a891e7d3 chore(rn,deps) react-native-webrtc@latest
Brings back Metal rendering and other SDP negotiation improvements.
2023-02-03 13:34:10 +01:00
Robert Pintilii
09e4696c60 feat(title-bar) Update design (#12851)
Convert some files to TS
Move some styles from SCSS to JSS
Update design
2023-02-03 13:31:00 +02:00
Robert Pintilii
a594aac078 fix(toolbar) Fix styles (#12863) 2023-02-03 13:30:38 +02:00
Saúl Ibarra Corretgé
9409e64066 fix(deps) remove nunused dependencies 2023-02-03 11:57:22 +02:00
Robert Pintilii
12318db4c7 fix(local-rec) Handle no mic permission (#12862) 2023-02-03 11:34:07 +02:00
Shawn
749c26b74c fix(toolbox): consistent color of hangup buttons 2023-02-02 15:55:17 +01:00
Robert10B
babe62eb6d fix(lang) updated Dutch translation 2023-02-02 13:50:25 +01:00
Robert Pintilii
fbc0a502e7 ref(TS) Improve TS (#12656) 2023-02-02 13:12:31 +02:00
Shawn
ab262ec8b1 fix(toolbox): do not show hangup menu for non-moderators 2023-02-02 10:50:15 +01:00
Maciej Zakrzewski
cced41665d fix(local-recording) after IFrame sandboxing
Fix local recording saving not working after IFrame sanbox introduciton. The allow-downloads flag was missing.
2023-02-02 10:45:48 +01:00
Mihaela Dumitru
f95e167779 feat(giphy) add sample resource for giphy-proxy 2023-02-02 10:30:40 +01:00
damencho
bf1b7cc856 fix: Fixes follow-me on the side that is screen sharing. 2023-02-01 07:12:15 -06:00
damencho
091e3f69dc fix: Fixes follow-me when there is a screenshare. 2023-01-31 08:40:56 -06:00
Horatiu Muresan
42868c9ec2 fix(context-menu) Fit the overflow menu on small heights (#12848) 2023-01-31 15:19:01 +02:00
Robert Pintilii
0d5dae7ab9 feat(prejoin) Update design (#12844) 2023-01-30 13:34:56 +02:00
167 changed files with 1818 additions and 1890 deletions

View File

@@ -76,7 +76,6 @@ dependencies {
implementation project(':react-native-get-random-values')
implementation project(':react-native-immersive')
implementation project(':react-native-keep-awake')
implementation project(':react-native-masked-view_masked-view')
implementation project(':react-native-orientation-locker')
implementation project(':react-native-pager-view')
implementation project(':react-native-performance')

View File

@@ -119,7 +119,6 @@ class ReactInstanceManagerHolder {
new com.oblador.performance.PerformancePackage(),
new com.reactnativecommunity.slider.ReactSliderPackage(),
new com.brentvatne.react.ReactVideoPackage(),
new org.reactnative.maskedview.RNCMaskedViewPackage(),
new com.reactnativecommunity.webview.RNCWebViewPackage(),
new com.kevinresol.react_native_default_preference.RNDefaultPreferencePackage(),
new com.learnium.RNDeviceInfo.RNDeviceInfo(),

View File

@@ -31,8 +31,6 @@ include ':react-native-immersive'
project(':react-native-immersive').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-immersive/android')
include ':react-native-keep-awake'
project(':react-native-keep-awake').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keep-awake/android')
include ':react-native-masked-view_masked-view'
project(':react-native-masked-view_masked-view').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-masked-view/masked-view/android')
include ':react-native-orientation-locker'
project(':react-native-orientation-locker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-orientation-locker/android')
include ':react-native-pager-view'

View File

@@ -542,12 +542,15 @@ var config = {
// Disables responsive tiles.
// disableResponsiveTiles: false,
// Hides lobby button
// DEPRECATED. Please use `securityUi?.hideLobbyButton` instead.
// Hides lobby button.
// hideLobbyButton: false,
// DEPRECATED. Please use `lobby?.autoKnock` instead.
// If Lobby is enabled starts knocking automatically.
// autoKnockLobby: false,
// DEPRECATED. Please use `lobby?.enableChat` instead.
// Enable lobby chat.
// enableLobbyChat: true,
@@ -572,6 +575,22 @@ var config = {
// customUrl: ''
// },
// Configs for the lobby screen.
// lobby {
// // If Lobby is enabled, it starts knocking automatically. Replaces `autoKnockLobby`.
// autoKnock: false,
// // Enables the lobby chat. Replaces `enableLobbyChat`.
// enableChat: true,
// },
// Configs for the security related UI elements.
// securityUi: {
// // Hides the lobby button. Replaces `hideLobbyButton`.
// hideLobbyButton: false,
// // Hides the possibility to set and enter a lobby password.
// disableLobbyPassword: false,
// },
// Disable app shortcuts that are registered upon joining a conference
// disableShortcuts: false,
@@ -799,6 +818,14 @@ var config = {
// 'microphone', 'camera', 'select-background', 'invite', 'settings'
// hiddenPremeetingButtons: [],
// An array with custom option buttons for the participant context menu
// type: Array<{ icon: string; id: string; text: string; }>
// customParticipantMenuButtons: [],
// An array with custom option buttons for the toolbar
// type: Array<{ icon: string; id: string; text: string; }>
// customToolbarButtons: [],
// Stats
//
@@ -1335,6 +1362,7 @@ var config = {
deploymentInfo
dialOutAuthUrl
dialOutCodesUrl
dialOutRegionUrl
disableRemoteControl
displayJids
externalConnectUrl

View File

@@ -2,13 +2,13 @@
display: inline-block;
&-content {
background: $menuBG;
border-radius: 3px;
font-size: 14px;
line-height: 24px;
position: relative;
right: auto;
margin-bottom: 8px;
max-height: 456px;
overflow: auto;
width: 300px;
&-ul {
margin:0;
padding:0;
@@ -16,90 +16,37 @@
}
}
&-header {
color: #fff;
align-items: center;
display: flex;
margin-top: 8px;
padding: 8px 16px;
&-icon {
display: inline-block;
svg {
fill: #fff;
}
}
&--bordered {
border-bottom: 1px solid #4C4D50;
}
&-text {
margin-left: 12px;
}
&-header:hover {
background-color: initial;
cursor: initial;
}
&-entry {
align-items: center;
color: #fff;
cursor: pointer;
display: flex;
padding: 8px 0;
margin-left: 48px;
&-entry-text {
display: inline-block;
text-overflow: ellipsis;
max-width: 213px;
overflow: hidden;
white-space: nowrap;
&--selected {
background: #131519;
cursor: initial;
margin-left: 0;
padding-left: 18px;
}
&-text {
color: #fff;
display: inline-block;
line-height: 24px;
text-overflow: ellipsis;
max-width: 213px;
overflow: hidden;
white-space: nowrap;
&.left-margin {
margin-left: 36px;
}
}
&-speaker {
position: relative;
&-ul {
margin:0;
padding:0;
list-style-type: none;
}
&:hover, &:focus-within, &:focus {
.audio-preview-entry {
background: #36383C;
margin-left: 0;
padding-left: 48px;
&--selected {
padding-left: 18px;
background: $newToolbarBackgroundColor;
}
}
.audio-preview-test-button {
display: inline-block;
}
.audio-preview-entry-text {
max-width: 178px;
margin-right: 0;
}
}
&:last-child {
padding-bottom: 8px;
}
.audio-preview-entry-text {
max-width: 238px;
}
@@ -108,19 +55,6 @@
&-microphone {
position: relative;
&:hover {
.audio-preview-entry {
background: #36383C;
margin-left: 0;
padding-left: 48px;
&--selected {
background: $newToolbarBackgroundColor;
padding-left: 18px;
}
}
}
&--nometer {
.audio-preview-entry-text {
max-width: 238px;
@@ -140,42 +74,21 @@
display: inline-block;
width: 14px;
& svg {
fill: #1C2025;
}
&--check {
background: #31B76A;
margin-right: 16px;
}
&--exclamation {
margin-left: 6px;
& svg {
fill: #E54B4B;
}
}
}
&-hr {
border-top: 1px solid #4C4D50;
border-bottom: 0;
}
&-test-button {
display: none;
background: #FFF;
border: 1px solid #D1DBE8;
border-radius: 3px;
color: #1C2025;
cursor: pointer;
font-weight: 600;
font-size: 0.8rem;
line-height: 24px;
padding: 2px 8px;
padding: 4px 10px;
position: absolute;
right: 16px;
top: 5px;
top: 6px;
}
&-meter-mic {
@@ -184,9 +97,7 @@
top: 14px;
}
// Override @atlaskit/InlineDialog container which is made with styled components
& > div:nth-child(2) {
outline: none;
padding: 0;
&-checkbox-container {
padding: 10px 16px;
}
}

View File

@@ -3,28 +3,28 @@
display: inline-block;
& > svg {
fill: #4E5E6C;
fill: #525252;
width: 38px;
}
}
&.metr--disabled {
& > svg {
fill: #4E5E6C;
fill: #525252;
}
}
}
.metr-l-0 {
rect:first-child {
fill: #31B76A;
fill: #1EC26A;
}
}
@for $i from 1 through 7 {
.metr-l-#{$i} {
rect:nth-child(-n+#{$i+1}) {
fill: #31B76A;
fill: #1EC26A;
}
}
}

View File

@@ -5,15 +5,15 @@
.popupmenu__contents {
.popupmenu__volume-slider {
&::-webkit-slider-runnable-track {
background-color: $popupSliderColor;
background-color: #246FE5;
}
&::-moz-range-track {
background-color: $popupSliderColor;
background-color: #246FE5;
}
&::-ms-fill-lower {
background-color: $popupSliderColor;
background-color: #246FE5;
}
}
}

View File

@@ -30,24 +30,24 @@
right: -4px;
top: -3px;
&:hover {
&:hover {
background: #F2F3F4;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
&> svg {
fill: #000;
& > svg {
fill: #040404;
}
&.settings-button-small-icon--disabled {
background: #36383C;
&> svg {
fill: #929292;
}
fill: #929292;
}
}
}
&> svg {
& > svg {
fill: #fff;
}

View File

@@ -12,7 +12,6 @@
&#autoHide.with-always-on {
overflow: hidden;
animation: hideSubject forwards .6s ease-out;
margin-left: 4px;
& > .subject-info-container {
justify-content: flex-start;
@@ -43,43 +42,6 @@
height: 28px;
}
.subject-text {
background: rgba(0, 0, 0, 0.6);
border-radius: 3px 0px 0px 3px;
box-sizing: border-box;
font-size: 14px;
line-height: 28px;
padding: 0 16px;
height: 28px;
max-width: 324px;
@media (max-width: 300px) {
display: none;
}
&--content {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.subject-timer {
background: rgba(0, 0, 0, 0.8);
border-radius: 0px 3px 3px 0px;
box-sizing: border-box;
font-size: 12px;
line-height: 28px;
min-width: 34px;
padding: 0 8px;
height: 28px;
font-variant-numeric: tabular-nums;
@media (max-width: 300px) {
display: none;
}
}
.details-container {
width: 100%;
display: flex;

View File

@@ -120,12 +120,16 @@
margin: 8px 0;
}
.hangup-button {
background-color: $hangupColor;
div.hangup-button {
background-color: #CB2233;
@media (hover: hover) and (pointer: fine) {
&:hover {
background-color: $hangupHoverColor;
background-color: #E04757;
}
&:active {
background-color: #A21B29;
}
}
@@ -134,12 +138,16 @@
}
}
.hangup-menu-button {
background-color: $hangupMenuButtonColor;
div.hangup-menu-button {
background-color: #CB2233;
@media (hover: hover) and (pointer: fine) {
&:hover {
background-color: $hangupMenuButtonHoverColor;
background-color: #E04757;
}
&:active {
background-color: #A21B29;
}
}

View File

@@ -4,10 +4,6 @@
* Style variables
*/
$baseFontFamily: -apple-system, BlinkMacSystemFont, 'open_sanslight', 'Helvetica Neue', Helvetica, Arial, sans-serif;
$hangupColor:#DD3849;
$hangupHoverColor: #F25363;
$hangupMenuButtonColor:#0056E0;;
$hangupMenuButtonHoverColor: #246FE5;
/**
* Size variables.

View File

@@ -41,11 +41,11 @@
&-dropdown-btns {
padding: 8px 0;
}
&-dropdown-container {
position: relative;
width: 100%;
/**
* Override default InlineDialog behaviour, since it does not play nicely with relative widths
*/
@@ -56,5 +56,12 @@
width: 100%;
}
}
}
}
.prejoin-input {
margin-bottom: 16px;
& input {
text-align: center;
}
}

View File

@@ -1,14 +1,4 @@
.premeeting-screen {
background: #292929;
bottom: 0;
display: flex;
font-size: 1.3em;
left: 0;
position: absolute;
right: 0;
top: 0;
z-index: $toolbarZ + 2;
.premeeting-screen {
.action-btn {
border-radius: 6px;
box-sizing: border-box;
@@ -75,139 +65,44 @@
}
}
.content {
align-items: center;
box-sizing: border-box;
display: flex;
flex-direction: column;
flex-shrink: 0;
height: 100%;
margin: 0 30px;
padding: 24px 0 16px;
#new-toolbox {
bottom: 0;
position: relative;
width: $prejoinDefaultContentWidth;
z-index: $toolbarZ + 2;
transition: none;
&-controls {
align-items: center;
.toolbox-content {
margin-bottom: 4px;
}
.toolbox-content-items {
@include ltr;
background: transparent;
box-shadow: none;
display: flex;
flex-direction: column;
margin: auto;
justify-content: space-between;
padding: 8px 0;
}
.toolbox-content,
.toolbox-content-wrapper,
.toolbox-content-items {
box-sizing: border-box;
width: 100%;
.title {
color: #fff;
font-size: 28px;
font-weight: 600;
letter-spacing: -0.015;
line-height: 36px;
margin-bottom: 16px;
text-align: center;
}
input.field {
background-color: white;
border: none;
outline: none;
border-radius: 6px;
font-size: 14px;
line-height: 20px;
margin-bottom: 16px;
color: #1C2025;
padding: 10px 16px;
text-align: center;
width: 100%;
&.error {
border: 1px solid #E04757;
}
&.focused {
box-shadow: 0px 0px 1px 1.5px black, 0px 0px 1.3px 4px white;
}
}
#new-toolbox {
bottom: 0;
position: relative;
transition: none;
.toolbox-content {
margin-bottom: 4px;
}
.toolbox-content-items {
@include ltr;
background: transparent;
box-shadow: none;
display: flex;
justify-content: space-evenly;
padding: 8px 0;
}
.toolbox-content,
.toolbox-content-wrapper,
.toolbox-content-items {
box-sizing: border-box;
width: 100%;
}
}
}
}
@media (max-width: 720px) {
flex-direction: column-reverse;
.content {
height: auto;
margin: 0 auto;
}
}
// mobile phone landscape
@media (max-height: 420px) {
div.content {
padding: 16px 16px 0 16px;
}
}
@media (max-width: 400px) {
.content {
padding: 16px;
width: 100%;
&-controls {
input.field {
font-size: 16px;
padding: 14px 16px;
}
}
.title {
display: none;
}
}
.device-status-error {
border-radius: 0;
margin: 0 -16px;
}
input.field {
font-size: 16px;
padding: 14px 16px;
}
.action-btn {
font-size: 16px;
margin-bottom: 8px;
padding: 11px 16px;
}
}
input::placeholder {
color: #040404;
}
}
#preview {

View File

@@ -65,7 +65,6 @@ $errorColor: #c61600;
// Popover colors
$popoverFontColor: #ffffff !important;
$popupSliderColor: #0376da;
// Toolbar
$toolbarBackground: rgba(0, 0, 0, 0.5);

View File

@@ -389,7 +389,7 @@ PODS:
- react-native-video/Video (6.0.0-alpha.1):
- PromisesSwift
- React-Core
- react-native-webrtc (106.0.4):
- react-native-webrtc (106.0.5):
- JitsiWebRTC (~> 106.0.0)
- React-Core
- react-native-webview (11.15.1):
@@ -465,13 +465,11 @@ PODS:
- React-Core
- RNCClipboard (1.5.1):
- React-Core
- RNCMaskedView (0.2.6):
- React-Core
- RNDefaultPreference (1.4.4):
- React-Core
- RNDeviceInfo (8.4.8):
- React-Core
- RNGestureHandler (2.8.0):
- RNGestureHandler (2.9.0):
- React-Core
- RNGoogleSignin (7.0.4):
- GoogleSignIn (~> 6.0.0)
@@ -547,7 +545,6 @@ DEPENDENCIES:
- RNCalendarEvents (from `../node_modules/react-native-calendar-events`)
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "RNCClipboard (from `../node_modules/@react-native-community/clipboard`)"
- "RNCMaskedView (from `../node_modules/@react-native-masked-view/masked-view`)"
- RNDefaultPreference (from `../node_modules/react-native-default-preference`)
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
@@ -682,8 +679,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-async-storage/async-storage"
RNCClipboard:
:path: "../node_modules/@react-native-community/clipboard"
RNCMaskedView:
:path: "../node_modules/@react-native-masked-view/masked-view"
RNDefaultPreference:
:path: "../node_modules/react-native-default-preference"
RNDeviceInfo:
@@ -759,7 +754,7 @@ SPEC CHECKSUMS:
react-native-slider: 6e9b86e76cce4b9e35b3403193a6432ed07e0c81
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
react-native-video: bb6f12a7198db53b261fefb5d609dc77417acc8b
react-native-webrtc: 4522d420ead45fff83c4ecc7e5a706797857a185
react-native-webrtc: ef315d8adb68e78298b22100377d12ef168efdb5
react-native-webview: ea4899a1056c782afa96dd082179a66cbebf5504
React-perflogger: 0458a87ea9a7342079e7a31b0d32b3734fb8415f
React-RCTActionSheet: 22538001ea2926dea001111dd2846c13a0730bc9
@@ -776,10 +771,9 @@ SPEC CHECKSUMS:
RNCalendarEvents: 7e65eb4a94f53c1744d1e275f7fafcfaa619f7a3
RNCAsyncStorage: 005c0e2f09575360f142d0d1f1f15e4ec575b1af
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
RNCMaskedView: c298b644a10c0c142055b3ae24d83879ecb13ccd
RNDefaultPreference: 08bdb06cfa9188d5da97d4642dac745218d7fb31
RNDeviceInfo: 0400a6d0c94186d1120c3cbd97b23abc022187a9
RNGestureHandler: 62232ba8f562f7dea5ba1b3383494eb5bf97a4d3
RNGestureHandler: 071d7a9ad81e8b83fe7663b303d132406a7d8f39
RNGoogleSignin: c4381751eefd73c552b923ba347a9bfc6f18771c
RNScreens: 40a2cb40a02a609938137a1e0acfbf8fc9eebf19
RNSound: 27e8268bdb0a1f191f219a33267f7e0445e8d62f

View File

@@ -40,19 +40,10 @@ static NSString *const PiPEnabledFeatureFlag = @"pip.enabled";
#pragma mark Initializers
- (instancetype)init {
self = [super init];
if (self) {
[self initWithXXX];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
if (self) {
[self initWithXXX];
[self doInitialize];
}
return self;
@@ -61,7 +52,7 @@ static NSString *const PiPEnabledFeatureFlag = @"pip.enabled";
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self initWithXXX];
[self doInitialize];
}
return self;
@@ -71,9 +62,9 @@ static NSString *const PiPEnabledFeatureFlag = @"pip.enabled";
* Internal initialization:
*
* - sets the background color
* - initializes the external API scope
* - registers necessary observers
*/
- (void)initWithXXX {
- (void)doInitialize {
// Set a background color which is in accord with the JavaScript and Android
// parts of the application and causes less perceived visual flicker than
// the default background color.

View File

@@ -882,6 +882,7 @@
"document": "Gedeeld document in- of uitschakelen",
"download": "Download onze apps",
"embedMeeting": "Vergadering embedden",
"endConference": "Vergadering voor iedereen beëindigen",
"feedback": "Feedback achterlaten",
"fullScreen": "Volledig scherm in- of uitschakelen",
"grantModerator": "Moderatorrechten verlenen",
@@ -889,6 +890,7 @@
"help": "Hulp",
"invite": "Personen uitnodigen",
"kick": "Deelnemer verwijderen",
"leaveConference": "Vergadering verlaten",
"lobbyButton": "Lobby-modus in- of uitschakelen",
"localRecording": "Besturingselementen voor lokale opname in- of uitschakelen",
"lockRoom": "Wachtwoord voor vergadering in- of uitschakelen",
@@ -938,6 +940,7 @@
"download": "Download onze apps",
"e2ee": "Eind-tot-eind-versleuteling",
"embedMeeting": "Vergadering embedden",
"endConference": "Vergadering voor iedereen beëindigen",
"enterFullScreen": "Volledig scherm weergeven",
"enterTileView": "Tegelweergave openen",
"exitFullScreen": "Volledig scherm sluiten",
@@ -948,6 +951,7 @@
"invite": "Personen uitnodigen",
"joinBreakoutRoom": "Deelnemen aan aparte vergaderruimte",
"leaveBreakoutRoom": "Aparte vergaderruimte verlaten",
"leaveConference": "Vergadering verlaten",
"lobbyButtonDisable": "Schakel lobby-modus uit",
"lobbyButtonEnable": "Schakel lobby-modus in",
"login": "Aanmelden",

View File

@@ -89,7 +89,7 @@
"chat": {
"enter": "Entrar na sala",
"error": "Erro: a sua mensagem não foi enviada. Motivo: {{error}}",
"fieldPlaceHolder": "Escreva aqui a sua mensagem",
"fieldPlaceHolder": "Aa",
"lobbyChatMessageTo": "Mensagem de chat na sala de espera para {{recipient}}",
"message": "Mensagem",
"messageAccessibleTitle": "{{user}} disse:",
@@ -147,6 +147,7 @@
"bridgeCount": "Servidores: ",
"codecs": "Codecs (A/V): ",
"connectedTo": "Ligado a:",
"e2eeVerified": "E2EE verificada:",
"framerate": "Taxa de frames:",
"less": "Mostrar menos",
"localaddress": "Endereço local:",
@@ -266,7 +267,7 @@
"e2eeWarning": "AVISO: Nem todos os participantes neste encontro parecem ter apoio para a encriptação de ponta a ponta. Se o permitir, eles não o poderão ver nem ouvir.",
"e2eeWillDisableDueToMaxModeDescription": "AVISO: A encriptação de ponta a ponta será automaticamente desativada se mais participantes aderirem à conferência.",
"embedMeeting": "Embutir reunião",
"enterDisplayName": "Digite o seu nome aqui",
"enterDisplayName": "Digite o seu nome",
"error": "Erro",
"gracefulShutdown": "O nosso serviço está atualmente em manutenção. Por favor, tente novamente mais tarde.",
"grantModeratorDialog": "Tem a certeza que quer conceder direitos de moderador a {{participantName}}?",
@@ -408,6 +409,10 @@
"user": "Utilizador",
"userIdentifier": "Identificador do utilizador",
"userPassword": "Palavra-passe do utilizador",
"verifyParticipantConfirm": "Coincidem",
"verifyParticipantDismiss": "Não coincidem",
"verifyParticipantQuestion": "EXPERIMENTAL: Perguntar ao participante {{participantName}} se vêem o mesmo conteúdo, na mesma ordem.",
"verifyParticipantTitle": "Verificação pelo utilizador",
"videoLink": "Link do vídeo",
"viewUpgradeOptions": "Ver opções de actualização",
"viewUpgradeOptionsContent": "Para obter acesso ilimitado a funcionalidades premium como gravação, transcrições, RTMP Streaming & mais, terá de actualizar o seu plano.",
@@ -437,9 +442,6 @@
"noResults": "Não foram encontrados resultados :(",
"search": "Procurar no GIPHY"
},
"helpView": {
"title": "Centro de ajuda"
},
"incomingCall": {
"answer": "Responder",
"audioCallTitle": "Chamada recebida",
@@ -563,7 +565,6 @@
"lobby": {
"admit": "Aceitar",
"admitAll": "Aceitar todos",
"allow": "Permitir",
"backToKnockModeButton": "Peça para aderir",
"chat": "Chat",
"dialogTitle": "Modo sala de espera",
@@ -649,6 +650,8 @@
"connectedOneMember": "{{name}} entrou na reunião",
"connectedThreePlusMembers": "{{name}} e muitos outros entraram na reunião",
"connectedTwoMembers": "{{first}} e {{second}} entraram na reunião",
"dataChannelClosed": "Deficiência na qualidade do vídeo",
"dataChannelClosedDescription": "O canal de ponte foi desconectado e, portanto, a qualidade do vídeo está limitada à sua configuração mais baixa.",
"disconnected": "desconectado",
"displayNotifications": "Mostrar notificações para",
"focus": "Foco da conferência",
@@ -709,6 +712,8 @@
"reactionSoundsForAll": "Desativar sons para todos",
"screenShareNoAudio": "A caixa de compartilhar áudio não foi marcada no ecrã de seleção da janela.",
"screenShareNoAudioTitle": "Não foi possível partilhar o áudio do sistema!",
"screenSharingAudioOnlyDescription": "Note por favor que ao partilhar o seu ecrã está a afectar o modo \"Melhor desempenho\" e irá utilizar mais largura de banda.",
"screenSharingAudioOnlyTitle": "Modo \"Melhor desempenho\"",
"selfViewTitle": "Pode sempre reexibir a autovisualização a partir das definições",
"somebody": "Alguém",
"startSilentDescription": "Volte à reunião para habilitar o áudio",
@@ -858,9 +863,6 @@
"rejected": "Rejeitado",
"ringing": "Tocando..."
},
"privacyView": {
"title": "Privacidade"
},
"profile": {
"avatar": "avatar",
"setDisplayNameLabel": "Definir seu nome de exibição",
@@ -914,6 +916,7 @@
"localRecordingVideoWarning": "Para gravar o seu vídeo deve tê-lo ligado quando iniciar a gravação",
"localRecordingWarning": "Certifique-se de selecionar o separador actual a fim de utilizar o vídeo e áudio corretos. A gravação está actualmente limitada a 1 GB, o que é cerca de 100 minutos.",
"loggedIn": "Conectado como {{userName}}",
"noMicPermission": "Não foi possível criar a faixa de microfone. Por favor, conceda permissão para utilizar o microfone.",
"noStreams": "Não foi detetado nenhum sinal áudio ou vídeo.",
"off": "Gravação parada",
"offBy": "{{name}} parou a gravação",
@@ -964,7 +967,7 @@
"incomingMessage": "Receber uma mensagem",
"language": "Idioma",
"loggedIn": "Sessão iniciada como {{name}}",
"maxStageParticipants": "Número máximo de participantes que podem ser afixados",
"maxStageParticipants": "Número máximo de participantes que podem ser afixados (EXPERIMENTAL)",
"microphones": "Microfones",
"moderator": "Moderador",
"more": "Mais",
@@ -983,7 +986,7 @@
"sounds": "Sons",
"speakers": "Participantes",
"startAudioMuted": "Todos começam com microfone desligado",
"startReactionsMuted": "Sons de reação silenciados para todos",
"startReactionsMuted": "Todos começam com os sons de reação desativados",
"startVideoMuted": "Todos começam com câmara desligada",
"talkWhileMuted": "Falar com o microfone desligado",
"title": "Definições"
@@ -1003,6 +1006,7 @@
"displayName": "Nome de exibição",
"displayNamePlaceholderText": "Ex: João Dias",
"email": "Email",
"emailPlaceholderText": "email@example.com",
"goTo": "Ir para",
"header": "Configurações",
"help": "Ajuda",
@@ -1291,6 +1295,7 @@
"show": "Mostrar no palco",
"showSelfView": "Mostrar autovisualização",
"unpinFromStage": "Desafixar",
"verify": "Verificar participante",
"videoMuted": "Câmara desativada",
"videomute": "Participante parou a câmara"
},
@@ -1358,6 +1363,7 @@
"recentList": "Recente",
"recentListDelete": "Remover",
"recentListEmpty": "A sua lista recente está atualmente vazia. Converse com a sua equipa e encontrará aqui todas as suas reuniões recentes.",
"recentMeetings": "As suas reuniões recentes",
"reducedUIText": "Bem-vindo ao {{app}}!",
"roomNameAllowedChars": "Nome da reunião não deve conter qualquer um destes caracteres: ?. &, :, ', \", %, #.",
"roomname": "Digite o nome da sala",
@@ -1366,6 +1372,7 @@
"settings": "Definições",
"startMeeting": "Iniciar reunião",
"terms": "Termos",
"title": "Videoconferências mais seguras, flexíveis e totalmente gratuitas"
"title": "Videoconferências mais seguras, flexíveis e totalmente gratuitas",
"upcomingMeetings": "As suas próximas reuniões"
}
}

View File

@@ -916,6 +916,7 @@
"localRecordingVideoWarning": "To record your video you must have it on when starting the recording",
"localRecordingWarning": "Make sure you select the current tab in order to use the right video and audio. The recording is currently limited to 1GB, which is around 100 minutes.",
"loggedIn": "Logged in as {{userName}}",
"noMicPermission": "Microphone track could not be created. Please grant permission to use the microphone.",
"noStreams": "No audio or video stream detected.",
"off": "Recording stopped",
"offBy": "{{name}} stopped the recording",

View File

@@ -1941,6 +1941,21 @@ class API {
});
}
/**
* Notify external application ( if API is enabled) that a participant menu button was clicked.
*
* @param {string} key - The key of the participant menu button.
* @param {string} participantId - The ID of the participant for with the participant menu button was clicked.
* @returns {void}
*/
notifyParticipantMenuButtonClicked(key, participantId) {
this._sendEvent({
name: 'participant-menu-button-clicked',
key,
participantId
});
}
/**
* Disposes the allocated resources.
*

View File

@@ -140,6 +140,7 @@ const events = {
'raise-hand-updated': 'raiseHandUpdated',
'recording-link-available': 'recordingLinkAvailable',
'recording-status-changed': 'recordingStatusChanged',
'participant-menu-button-clicked': 'participantMenuButtonClick',
'video-ready-to-close': 'readyToClose',
'video-conference-joined': 'videoConferenceJoined',
'video-conference-left': 'videoConferenceLeft',
@@ -391,7 +392,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
this._frame.name = frameName;
this._frame.id = frameName;
this._setSize(height, width);
this._frame.sandbox = 'allow-scripts allow-same-origin allow-popups allow-forms';
this._frame.sandbox = 'allow-scripts allow-same-origin allow-popups allow-forms allow-downloads';
this._frame.setAttribute('allowFullScreen', 'true');
this._frame.style.border = 0;

View File

@@ -8,39 +8,6 @@ import Filmstrip from '../videolayout/Filmstrip';
import LargeContainer from '../videolayout/LargeContainer';
import VideoLayout from '../videolayout/VideoLayout';
/**
*
*/
function bubbleIframeMouseMove(iframe) {
const existingOnMouseMove = iframe.contentWindow.onmousemove;
iframe.contentWindow.onmousemove = function(e) {
if (existingOnMouseMove) {
existingOnMouseMove(e);
}
const evt = document.createEvent('MouseEvents');
const boundingClientRect = iframe.getBoundingClientRect();
evt.initMouseEvent(
'mousemove',
true, // bubbles
false, // not cancelable
window,
e.detail,
e.screenX,
e.screenY,
e.clientX + boundingClientRect.left,
e.clientY + boundingClientRect.top,
e.ctrlKey,
e.altKey,
e.shiftKey,
e.metaKey,
e.button,
null // no related element
);
iframe.dispatchEvent(evt);
};
}
/**
* Default Etherpad frame width.
@@ -68,7 +35,7 @@ class Etherpad extends LargeContainer {
iframe.id = 'etherpadIFrame';
iframe.src = url;
iframe.frameBorder = 0;
iframe.style.border = 0;
iframe.scrolling = 'no';
iframe.width = DEFAULT_WIDTH;
iframe.height = DEFAULT_HEIGHT;
@@ -76,26 +43,6 @@ class Etherpad extends LargeContainer {
this.container.appendChild(iframe);
iframe.onload = function() {
// eslint-disable-next-line no-self-assign
document.domain = document.domain;
bubbleIframeMouseMove(iframe);
setTimeout(() => {
const doc = iframe.contentDocument;
// the iframes inside of the etherpad are
// not yet loaded when the etherpad iframe is loaded
const outer = doc.getElementsByName('ace_outer')[0];
bubbleIframeMouseMove(outer);
const inner = doc.getElementsByName('ace_inner')[0];
bubbleIframeMouseMove(inner);
}, 2000);
};
this.iframe = iframe;
}

89
package-lock.json generated
View File

@@ -41,7 +41,6 @@
"@react-native-community/netinfo": "7.1.7",
"@react-native-community/slider": "4.1.12",
"@react-native-google-signin/google-signin": "7.0.4",
"@react-native-masked-view/masked-view": "0.2.6",
"@react-navigation/bottom-tabs": "6.5.3",
"@react-navigation/elements": "1.3.13",
"@react-navigation/material-top-tabs": "6.5.2",
@@ -92,11 +91,10 @@
"react-native-background-timer": "2.4.1",
"react-native-calendar-events": "2.2.0",
"react-native-callstats": "3.73.7",
"react-native-collapsible": "1.6.0",
"react-native-default-preference": "1.4.4",
"react-native-device-info": "8.4.8",
"react-native-dialog": "https://github.com/jitsi/react-native-dialog/releases/download/v9.2.2-jitsi.1/react-native-dialog-9.2.2.tgz",
"react-native-gesture-handler": "2.8.0",
"react-native-gesture-handler": "2.9.0",
"react-native-get-random-values": "1.7.2",
"react-native-immersive": "2.0.0",
"react-native-keep-awake": "4.0.0",
@@ -114,7 +112,7 @@
"react-native-url-polyfill": "1.3.0",
"react-native-video": "https://git@github.com/react-native-video/react-native-video#7c48ae7c8544b2b537fb60194e9620b9fcceae52",
"react-native-watch-connectivity": "1.0.11",
"react-native-webrtc": "106.0.4",
"react-native-webrtc": "106.0.5",
"react-native-webview": "11.15.1",
"react-native-youtube-iframe": "2.2.1",
"react-redux": "7.1.0",
@@ -147,6 +145,7 @@
"@types/js-md5": "0.4.3",
"@types/lodash": "4.14.182",
"@types/react": "17.0.14",
"@types/react-dom": "17.0.14",
"@types/react-linkify": "1.0.1",
"@types/react-native": "0.68.9",
"@types/react-redux": "7.1.24",
@@ -5441,15 +5440,6 @@
"react-native": "*"
}
},
"node_modules/@react-native-masked-view/masked-view": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/@react-native-masked-view/masked-view/-/masked-view-0.2.6.tgz",
"integrity": "sha512-303CxmetUmgiX9NSUxatZkNh9qTYYdiM8xkGf9I3Uj20U3eGY3M78ljeNQ4UVCJA+FNGS5nC1dtS9GjIqvB4dg==",
"peerDependencies": {
"react": "16 || 17",
"react-native": ">=0.57"
}
},
"node_modules/@react-native/assets": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@react-native/assets/-/assets-1.0.0.tgz",
@@ -5664,9 +5654,9 @@
}
},
"node_modules/@sideway/formula": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz",
"integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg=="
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz",
"integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg=="
},
"node_modules/@sideway/pinpoint": {
"version": "2.0.0",
@@ -6532,6 +6522,15 @@
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-dom": {
"version": "17.0.14",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.14.tgz",
"integrity": "sha512-H03xwEP1oXmSfl3iobtmQ/2dHF5aBHr8aUMwyGZya6OW45G+xtdzmq6HkncefiBt5JU8DVyaWl/nWZbjZCnzAQ==",
"dev": true,
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/react-is": {
"version": "17.0.3",
"resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz",
@@ -16268,15 +16267,6 @@
"nullthrows": "^1.1.1"
}
},
"node_modules/react-native-collapsible": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/react-native-collapsible/-/react-native-collapsible-1.6.0.tgz",
"integrity": "sha512-beZjdgbT9Y/Pg591Xy5XkKG20HffJiVad4n9bfcUF/f783A+tvOVXnqvbS58Lkaym93mi4jcDPMuW9Vc1t6rqg==",
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-default-preference": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/react-native-default-preference/-/react-native-default-preference-1.4.4.tgz",
@@ -16303,9 +16293,9 @@
}
},
"node_modules/react-native-gesture-handler": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.8.0.tgz",
"integrity": "sha512-poOSfz/w0IyD6Qwq7aaIRRfEaVTl1ecQFoyiIbpOpfNTjm2B1niY2FLrdVQIOtIOe+K9nH55Qal04nr4jGkHdQ==",
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.9.0.tgz",
"integrity": "sha512-a0BcH3Qb1tgVqUutc6d3VuWQkI1AM3+fJx8dkxzZs9t06qA27QgURYFoklpabuWpsUTzuKRpxleykp25E8m7tg==",
"dependencies": {
"@egjs/hammerjs": "^2.0.17",
"hoist-non-react-statics": "^3.3.0",
@@ -16555,9 +16545,9 @@
}
},
"node_modules/react-native-webrtc": {
"version": "106.0.4",
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-106.0.4.tgz",
"integrity": "sha512-mIdXstKkua5fRqPaCCxQuZmO7amVFnCUYibXP+cXLMSKIsHwilpvbMQRby0jcBftTGN6rjGyIr+CXffFrtztQg==",
"version": "106.0.5",
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-106.0.5.tgz",
"integrity": "sha512-EINzYpTZh6zXb2lcGH13Ieli1ur3M1FaT8R8WMqfUZEW8/y0WV6yBeQQVz55OA4LtWnBUX0RZyaYQ4aZN4e1Sw==",
"hasInstallScript": true,
"dependencies": {
"adm-zip": "0.5.9",
@@ -24440,11 +24430,6 @@
"resolved": "https://registry.npmjs.org/@react-native-google-signin/google-signin/-/google-signin-7.0.4.tgz",
"integrity": "sha512-N5uVDlTp/mgpa5gFr6VIr8pldt68jlmHOlqcTSnSwBuZXusXMiK53DCIOWuYk4OJ1rlb8Esa9J4FJwUB0psU9Q=="
},
"@react-native-masked-view/masked-view": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/@react-native-masked-view/masked-view/-/masked-view-0.2.6.tgz",
"integrity": "sha512-303CxmetUmgiX9NSUxatZkNh9qTYYdiM8xkGf9I3Uj20U3eGY3M78ljeNQ4UVCJA+FNGS5nC1dtS9GjIqvB4dg=="
},
"@react-native/assets": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@react-native/assets/-/assets-1.0.0.tgz",
@@ -24614,9 +24599,9 @@
}
},
"@sideway/formula": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz",
"integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg=="
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz",
"integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg=="
},
"@sideway/pinpoint": {
"version": "2.0.0",
@@ -25267,6 +25252,15 @@
"csstype": "^3.0.2"
}
},
"@types/react-dom": {
"version": "17.0.14",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.14.tgz",
"integrity": "sha512-H03xwEP1oXmSfl3iobtmQ/2dHF5aBHr8aUMwyGZya6OW45G+xtdzmq6HkncefiBt5JU8DVyaWl/nWZbjZCnzAQ==",
"dev": true,
"requires": {
"@types/react": "*"
}
},
"@types/react-is": {
"version": "17.0.3",
"resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz",
@@ -32710,11 +32704,6 @@
"nullthrows": "^1.1.1"
}
},
"react-native-collapsible": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/react-native-collapsible/-/react-native-collapsible-1.6.0.tgz",
"integrity": "sha512-beZjdgbT9Y/Pg591Xy5XkKG20HffJiVad4n9bfcUF/f783A+tvOVXnqvbS58Lkaym93mi4jcDPMuW9Vc1t6rqg=="
},
"react-native-default-preference": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/react-native-default-preference/-/react-native-default-preference-1.4.4.tgz",
@@ -32730,9 +32719,9 @@
"integrity": "sha512-MKbuBbovO8eGiAM9i6o0nrdBXivhRpzPQ+aVBXGJEPMH7RrCSNUKaCoEpkjfGHlTxjZimi6WjDCjjzCRSHlV1A=="
},
"react-native-gesture-handler": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.8.0.tgz",
"integrity": "sha512-poOSfz/w0IyD6Qwq7aaIRRfEaVTl1ecQFoyiIbpOpfNTjm2B1niY2FLrdVQIOtIOe+K9nH55Qal04nr4jGkHdQ==",
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.9.0.tgz",
"integrity": "sha512-a0BcH3Qb1tgVqUutc6d3VuWQkI1AM3+fJx8dkxzZs9t06qA27QgURYFoklpabuWpsUTzuKRpxleykp25E8m7tg==",
"requires": {
"@egjs/hammerjs": "^2.0.17",
"hoist-non-react-statics": "^3.3.0",
@@ -32906,9 +32895,9 @@
}
},
"react-native-webrtc": {
"version": "106.0.4",
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-106.0.4.tgz",
"integrity": "sha512-mIdXstKkua5fRqPaCCxQuZmO7amVFnCUYibXP+cXLMSKIsHwilpvbMQRby0jcBftTGN6rjGyIr+CXffFrtztQg==",
"version": "106.0.5",
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-106.0.5.tgz",
"integrity": "sha512-EINzYpTZh6zXb2lcGH13Ieli1ur3M1FaT8R8WMqfUZEW8/y0WV6yBeQQVz55OA4LtWnBUX0RZyaYQ4aZN4e1Sw==",
"requires": {
"adm-zip": "0.5.9",
"base64-js": "1.5.1",

View File

@@ -46,7 +46,6 @@
"@react-native-community/netinfo": "7.1.7",
"@react-native-community/slider": "4.1.12",
"@react-native-google-signin/google-signin": "7.0.4",
"@react-native-masked-view/masked-view": "0.2.6",
"@react-navigation/bottom-tabs": "6.5.3",
"@react-navigation/elements": "1.3.13",
"@react-navigation/material-top-tabs": "6.5.2",
@@ -97,11 +96,10 @@
"react-native-background-timer": "2.4.1",
"react-native-calendar-events": "2.2.0",
"react-native-callstats": "3.73.7",
"react-native-collapsible": "1.6.0",
"react-native-default-preference": "1.4.4",
"react-native-device-info": "8.4.8",
"react-native-dialog": "https://github.com/jitsi/react-native-dialog/releases/download/v9.2.2-jitsi.1/react-native-dialog-9.2.2.tgz",
"react-native-gesture-handler": "2.8.0",
"react-native-gesture-handler": "2.9.0",
"react-native-get-random-values": "1.7.2",
"react-native-immersive": "2.0.0",
"react-native-keep-awake": "4.0.0",
@@ -119,7 +117,7 @@
"react-native-url-polyfill": "1.3.0",
"react-native-video": "https://git@github.com/react-native-video/react-native-video#7c48ae7c8544b2b537fb60194e9620b9fcceae52",
"react-native-watch-connectivity": "1.0.11",
"react-native-webrtc": "106.0.4",
"react-native-webrtc": "106.0.5",
"react-native-webview": "11.15.1",
"react-native-youtube-iframe": "2.2.1",
"react-redux": "7.1.0",
@@ -152,6 +150,7 @@
"@types/js-md5": "0.4.3",
"@types/lodash": "4.14.182",
"@types/react": "17.0.14",
"@types/react-dom": "17.0.14",
"@types/react-linkify": "1.0.1",
"@types/react-native": "0.68.9",
"@types/react-redux": "7.1.24",

View File

@@ -90,6 +90,7 @@ export interface IReduxState {
'features/background': IBackgroundState;
'features/base/app': IAppState;
'features/base/audio-only': IAudioOnlyState;
'features/base/color-scheme': any;
'features/base/conference': IConferenceState;
'features/base/config': IConfigState;
'features/base/connection': IConnectionState;

View File

@@ -24,9 +24,8 @@ import {
openWaitForOwnerDialog,
stopWaitForOwner
} from './actions.web';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { LoginDialog, WaitForOwnerDialog } from './components';
import LoginDialog from './components/web/LoginDialog';
import WaitForOwnerDialog from './components/web/WaitForOwnerDialog';
/**
* Middleware that captures connection or conference failed errors and controls

View File

@@ -1,7 +1,5 @@
// @flow
import { toState } from '../redux';
import { StyleType } from '../styles';
import { toState } from '../redux/functions';
import { StyleType } from '../styles/functions.any';
import defaultScheme from './defaultScheme';
@@ -90,7 +88,7 @@ class ColorSchemeRegistry {
stateful: Object | Function,
componentName: string,
style: StyleType): StyleType {
let schemedStyle;
let schemedStyle: any;
if (Array.isArray(style)) {
// The style is an array of styles, we apply the same transformation
@@ -116,7 +114,7 @@ class ColorSchemeRegistry {
// The value is another style object, we apply the same
// transformation recursively.
schemedStyle[styleName]
= this._applyColorScheme(
= this._applyColorScheme( // @ts-ignore
stateful, componentName, styleValue);
} else if (typeof styleValue === 'function') {
// The value is a function, which indicates that it's a
@@ -149,11 +147,14 @@ class ColorSchemeRegistry {
stateful: Object | Function,
componentName: string,
colorDefinition: string): string {
// @ts-ignore
const colorScheme = toState(stateful)['features/base/color-scheme'] || {};
return {
...defaultScheme._defaultTheme,
...colorScheme._defaultTheme,
// @ts-ignore
...defaultScheme[componentName],
...colorScheme[componentName]
}[colorDefinition];

View File

@@ -1,4 +1,5 @@
import { ColorPalette, getRGBAFormat } from '../styles';
import { ColorPalette } from '../styles/components/styles/ColorPalette';
import { getRGBAFormat } from '../styles/functions.any';
/**
* The default color scheme of the application.

View File

@@ -1,5 +1,3 @@
// @flow
/**
* A special function to be used in the {@code createColorSchemedStyle} call,
* that denotes that the color is a dynamic color.

View File

@@ -206,6 +206,8 @@ export interface IConfig {
};
};
corsAvatarURLs?: Array<string>;
customParticipantMenuButtons?: Array<{ icon: string; id: string; text: string; }>;
customToolbarButtons?: Array<{ icon: string; id: string; text: string; }>;
deeplinking?: IDeeplinkingConfig;
defaultLanguage?: string;
defaultLocalDisplayName?: string;
@@ -394,6 +396,10 @@ export interface IConfig {
validatorRegExpString?: string;
};
liveStreamingEnabled?: boolean;
lobby?: {
autoKnock?: boolean;
enableChat?: boolean;
};
localRecording?: {
disable?: boolean;
disableSelfRecording?: boolean;
@@ -464,6 +470,10 @@ export interface IConfig {
enabled?: boolean;
mode?: 'always' | 'recording';
};
securityUi?: {
disableLobbyPassword?: boolean;
hideLobbyButton?: boolean;
};
serviceUrl?: string;
sipInviteUrl?: string;
speakerStats?: {

View File

@@ -185,6 +185,7 @@ export default [
'inviteAppName',
'liveStreaming',
'liveStreamingEnabled',
'lobby',
'localRecording',
'localSubject',
'logging',
@@ -209,6 +210,7 @@ export default [
'resolution',
'salesforceUrl',
'screenshotCapture',
'securityUi',
'speakerStats',
'startAudioMuted',
'startAudioOnly',

View File

@@ -316,3 +316,13 @@ export function getDialOutStatusUrl(state: IReduxState) {
export function getDialOutUrl(state: IReduxState) {
return state['features/base/config'].guestDialOutUrl;
}
/**
* Selector to return the security UI config.
*
* @param {IReduxState} state - State object.
* @returns {Object}
*/
export function getSecurityUiConfig(state: IReduxState) {
return state['features/base/config']?.securityUi || {};
}

View File

@@ -32,9 +32,16 @@ export function getReplaceParticipant(state: IReduxState): string | undefined {
* @returns {Array<string>} - The list of enabled toolbar buttons.
*/
export function getToolbarButtons(state: IReduxState): Array<string> {
const { toolbarButtons } = state['features/base/config'];
const { toolbarButtons, customToolbarButtons } = state['features/base/config'];
const customButtons = customToolbarButtons?.map(({ id }) => id);
return Array.isArray(toolbarButtons) ? toolbarButtons : TOOLBAR_BUTTONS;
const buttons = Array.isArray(toolbarButtons) ? toolbarButtons : TOOLBAR_BUTTONS;
if (customButtons) {
buttons.push(...customButtons);
}
return buttons;
}
/**
@@ -101,3 +108,30 @@ export function _setDeeplinkingDefaults(deeplinking: IDeeplinkingConfig) {
android.dynamicLink.isi = android.dynamicLink.isi || '1165103905';
}
}
/**
* Returns the list of buttons that have that notify the api when clicked.
*
* @param {Object} state - The redux state.
* @returns {Array} - The list of buttons.
*/
export function getButtonsWithNotifyClick(state: IReduxState): Array<{ key: string; preventExecution: boolean; }> {
const { buttonsWithNotifyClick, customToolbarButtons } = state['features/base/config'];
const customButtons = customToolbarButtons?.map(({ id }) => {
return {
key: id,
preventExecution: false
};
});
const buttons = Array.isArray(buttonsWithNotifyClick)
? buttonsWithNotifyClick as Array<{ key: string; preventExecution: boolean; }>
: [];
if (customButtons) {
buttons.push(...customButtons);
}
return buttons;
}

View File

@@ -535,6 +535,30 @@ function _translateLegacyConfig(oldValue: IConfig) {
};
}
if (oldValue.autoKnockLobby !== undefined
&& newValue.lobby?.autoKnock === undefined) {
newValue.lobby = {
...newValue.lobby || {},
autoKnock: oldValue.autoKnockLobby
};
}
if (oldValue.enableLobbyChat !== undefined
&& newValue.lobby?.enableChat === undefined) {
newValue.lobby = {
...newValue.lobby || {},
enableChat: oldValue.enableLobbyChat
};
}
if (oldValue.hideLobbyButton !== undefined
&& newValue.securityUi?.hideLobbyButton === undefined) {
newValue.securityUi = {
...newValue.securityUi || {},
hideLobbyButton: oldValue.hideLobbyButton
};
}
_setDeeplinkingDefaults(newValue.deeplinking as IDeeplinkingConfig);
return newValue;

View File

@@ -2,9 +2,7 @@ import { ComponentType } from 'react';
import { IReduxState } from '../../app/types';
import { IStateful } from '../app/types';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { ColorSchemeRegistry } from '../color-scheme';
import ColorSchemeRegistry from '../color-scheme/ColorSchemeRegistry';
import { toState } from '../redux/functions';
/**
@@ -28,7 +26,7 @@ export function isAnyDialogOpen(stateful: IStateful) {
* {@code Dialog} to be checked.
* @returns {boolean}
*/
export function isDialogOpen(stateful: IStateful, component: ComponentType) {
export function isDialogOpen(stateful: IStateful, component: ComponentType<any>) {
return toState(stateful)['features/base/dialog'].component === component;
}

View File

@@ -21,6 +21,7 @@ import StartRecordingDialog from '../../recording/components/Recording/web/Start
import StopRecordingDialog from '../../recording/components/Recording/web/StopRecordingDialog';
// @ts-ignore
import RemoteControlAuthorizationDialog from '../../remote-control/components/RemoteControlAuthorizationDialog';
import PasswordRequiredPrompt from '../../room-lock/components/PasswordRequiredPrompt.web';
import SalesforceLinkDialog from '../../salesforce/components/web/SalesforceLinkDialog';
import ShareAudioDialog from '../../screen-share/components/web/ShareAudioDialog';
import ShareScreenWarningDialog from '../../screen-share/components/web/ShareScreenWarningDialog';
@@ -50,7 +51,7 @@ const NEW_DIALOG_LIST = [ KeyboardShortcutsDialog, ChatPrivacyDialog, DisplayNam
SharedVideoDialog, SpeakerStats, LanguageSelectorDialog, MuteEveryoneDialog, MuteEveryonesVideoDialog,
GrantModeratorDialog, KickRemoteParticipantDialog, MuteRemoteParticipantsVideoDialog, VideoQualityDialog,
VirtualBackgroundDialog, LoginDialog, WaitForOwnerDialog, DesktopPicker, RemoteControlAuthorizationDialog,
LogoutDialog, SalesforceLinkDialog, ParticipantVerificationDialog ];
LogoutDialog, SalesforceLinkDialog, ParticipantVerificationDialog, PasswordRequiredPrompt ];
// This function is necessary while the transition from @atlaskit dialog to our component is ongoing.
const isNewDialog = (component: any) => NEW_DIALOG_LIST.some(comp => comp === component);

View File

@@ -2,9 +2,7 @@ import React, { useCallback } from 'react';
// @ts-ignore
import { Container } from '../../react/base';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { styleTypeToObject } from '../../styles';
import { styleTypeToObject } from '../../styles/functions';
interface IProps {
@@ -141,6 +139,8 @@ export default function Icon(props: IProps) {
color: styleColor,
fontSize: styleSize,
...restStyle
// @ts-ignore
} = styleTypeToObject(style ?? {});
const calculatedColor = color ?? styleColor ?? DEFAULT_COLOR;
const calculatedSize = size ?? styleSize ?? DEFAULT_SIZE;

View File

@@ -1,5 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M1.5 6.75C1.5 6.33579 1.83579 6 2.25 6H21.75C22.1642 6 22.5 6.33579 22.5 6.75C22.5 7.16421 22.1642 7.5 21.75 7.5H2.25C1.83579 7.5 1.5 7.16421 1.5 6.75Z" />
<path d="M1.5 17.25C1.5 16.8358 1.83579 16.5 2.25 16.5H21.75C22.1642 16.5 22.5 16.8358 22.5 17.25C22.5 17.6642 22.1642 18 21.75 18H2.25C1.83579 18 1.5 17.6642 1.5 17.25Z" />
<path d="M2.25 11.25C1.83579 11.25 1.5 11.5858 1.5 12C1.5 12.4142 1.83579 12.75 2.25 12.75H21.75C22.1642 12.75 22.5 12.4142 22.5 12C22.5 11.5858 22.1642 11.25 21.75 11.25H2.25Z" />
</svg>

Before

Width:  |  Height:  |  Size: 623 B

View File

@@ -1,6 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.1602 8.24439C13.3281 8.16225 14.25 7.18879 14.25 6C14.25 4.75736 13.2426 3.75 12 3.75C10.7574 3.75 9.75 4.75736 9.75 6C9.75 7.18151 10.6607 8.15032 11.8184 8.24278C11.5197 8.21896 11.2375 8.13687 10.9831 8.00775C9.85816 9.83693 8.19346 10.3318 6.74461 10.3424C6.66364 9.17333 5.68961 8.25 4.5 8.25C3.25736 8.25 2.25 9.25736 2.25 10.5C2.25 11.7426 3.25736 12.75 4.5 12.75C5.32135 12.75 6.03995 12.31 6.43279 11.6527C6.39557 11.715 6.35542 11.7754 6.31253 11.8336C6.67901 11.8506 7.06503 11.8447 7.4618 11.805C8.64456 11.6868 9.95784 11.2623 11.0918 10.2228C11.4736 9.87283 11.8205 9.46641 12.1289 9.0006C12.4727 9.47803 12.8468 9.89069 13.2474 10.2432C14.3929 11.2513 15.6592 11.6829 16.8118 11.8042C17.1152 11.8362 17.4101 11.8467 17.6932 11.8412C17.6739 11.8152 17.6551 11.7887 17.6369 11.7619C18.0415 12.3582 18.725 12.75 19.5 12.75C20.7426 12.75 21.75 11.7426 21.75 10.5C21.75 9.25736 20.7426 8.25 19.5 8.25C18.3129 8.25 17.3405 9.16938 17.256 10.335C15.9245 10.2658 14.3912 9.7053 13.1957 7.90649C12.8918 8.09752 12.5389 8.21778 12.1602 8.24439ZM12 6.75C12.4142 6.75 12.75 6.41421 12.75 6C12.75 5.58579 12.4142 5.25 12 5.25C11.5858 5.25 11.25 5.58579 11.25 6C11.25 6.41421 11.5858 6.75 12 6.75ZM20.25 10.5C20.25 10.9142 19.9142 11.25 19.5 11.25C19.0858 11.25 18.75 10.9142 18.75 10.5C18.75 10.0858 19.0858 9.75 19.5 9.75C19.9142 9.75 20.25 10.0858 20.25 10.5ZM4.5 11.25C4.91421 11.25 5.25 10.9142 5.25 10.5C5.25 10.0858 4.91421 9.75 4.5 9.75C4.08579 9.75 3.75 10.0858 3.75 10.5C3.75 10.9142 4.08579 11.25 4.5 11.25Z" />
<path d="M17.9485 12.1296C18.3135 12.4773 18.7952 12.7036 19.3289 12.7437L19.2591 12.9706C19.1623 13.2853 18.8715 13.5 18.5423 13.5C18.0377 13.5 17.677 13.0117 17.8254 12.5294L17.9485 12.1296Z" />
<path d="M12.75 18.0001C13.1642 18.0001 13.5 18.3359 13.5 18.7501C13.5 19.1643 13.1642 19.5001 12.75 19.5001H7.85792C7.19941 19.5001 6.61791 19.0706 6.42425 18.4412L4.6712 12.7437C5.20487 12.7036 5.6866 12.4773 6.05164 12.1296L7.85792 18.0001H12.75Z" />
<path d="M11.25 18.0002C10.8358 18.0002 10.5 18.336 10.5 18.7502C10.5 19.1644 10.8358 19.5002 11.25 19.5002H16.1421C16.8006 19.5002 17.3821 19.0707 17.5757 18.4413L19.3289 12.7437C18.7952 12.7036 18.3135 12.4773 17.9485 12.1296L16.1421 18.0002H11.25Z" />
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -20,7 +20,6 @@ export { default as IconCode } from './code.svg';
export { default as IconConnection } from './connection.svg';
export { default as IconConnectionInactive } from './ninja.svg';
export { default as IconCopy } from './copy.svg';
export { default as IconCrown } from './host.svg';
export { default as IconDeviceHeadphone } from './headset.svg';
export { default as IconDotsHorizontal } from './dots-horizontal.svg';
export { default as IconDownload } from './download.svg';
@@ -47,11 +46,11 @@ export { default as IconHelp } from './help.svg';
export { default as IconHighlight } from './highlight.svg';
export { default as IconImage } from './image.svg';
export { default as IconInfoCircle } from './info-circle.svg';
export { default as IconBurger } from './burger.svg';
export { default as IconMessage } from './message.svg';
export { default as IconMeter } from './meter.svg';
export { default as IconMic } from './mic.svg';
export { default as IconMicSlash } from './mic-slash.svg';
export { default as IconModerator } from './moderator.svg';
export { default as IconNoiseSuppressionOff } from './noise-suppression-off.svg';
export { default as IconNoiseSuppressionOn } from './noise-suppression-on.svg';
export { default as IconArrowRight } from './arrow-right.svg';

View File

@@ -1,10 +1,10 @@
<svg width="38" height="12" viewBox="0 0 38 12" fill="#5E6D7A" xmlns="http://www.w3.org/2000/svg">
<rect width="3" height="12" rx="1"/>
<rect x="5" width="3" height="12" rx="1" />
<rect x="10" width="3" height="12" rx="1" />
<rect x="15" width="3" height="12" rx="1" />
<rect x="20" width="3" height="12" rx="1" />
<rect x="25" width="3" height="12" rx="1" />
<rect x="30" width="3" height="12" rx="1" />
<rect x="35" width="3" height="12" rx="1" />
<svg width="38" height="12" viewBox="0 0 38 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="3" height="12" rx="1" />
<rect x="5" width="3" height="12" rx="1" />
<rect x="10" width="3" height="12" rx="1" />
<rect x="15" width="3" height="12" rx="1" />
<rect x="20" width="3" height="12" rx="1" />
<rect x="25" width="3" height="12" rx="1" />
<rect x="30" width="3" height="12" rx="1" />
<rect x="35" width="3" height="12" rx="1" />
</svg>

Before

Width:  |  Height:  |  Size: 457 B

After

Width:  |  Height:  |  Size: 487 B

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill-rule="evenodd" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.5 3H19.5C20.3284 3 21 3.67157 21 4.5V19.5C21 20.3284 20.3284 21 19.5 21H4.5C3.67157 21 3 20.3284 3 19.5V4.5C3 3.67157 3.67157 3 4.5 3ZM1.5 4.5C1.5 2.84315 2.84315 1.5 4.5 1.5H19.5C21.1569 1.5 22.5 2.84315 22.5 4.5V19.5C22.5 21.1569 21.1569 22.5 19.5 22.5H4.5C2.84315 22.5 1.5 21.1569 1.5 19.5V4.5ZM8.71837 7H6.30005V17.9091H8.19636V10.3984H8.29756L11.3125 17.8771H12.7294L15.7443 10.4144H15.8455V17.9091H17.7418V7H15.3235L12.0849 14.9048H11.957L8.71837 7Z"/>
</svg>

After

Width:  |  Height:  |  Size: 622 B

View File

@@ -50,10 +50,10 @@ const useStyles = makeStyles()(theme => {
...withPixelLineHeight(theme.typography.labelRegular),
alignItems: 'center',
background: theme.palette.ui04,
borderRadius: Number(theme.shape.borderRadius) / 2,
borderRadius: '4px',
color: theme.palette.text01,
display: 'flex',
margin: '0 0 4px 4px',
margin: '0 2px',
padding: '6px',
height: 28,
boxSizing: 'border-box'

View File

@@ -4,8 +4,6 @@ import { IStore } from '../../app/types';
import { showNotification } from '../../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants';
import LocalRecordingManager from '../../recording/components/Recording/LocalRecordingManager.web';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import StopRecordingDialog from '../../recording/components/Recording/web/StopRecordingDialog';
import { openDialog } from '../dialog/actions';
import MiddlewareRegistry from '../redux/MiddlewareRegistry';

View File

@@ -1,6 +1,7 @@
// @flow
import NetInfo from '@react-native-community/netinfo';
import type { NetInfoState, NetInfoSubscription } from '@react-native-community/netinfo';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import EventEmitter from 'events';
import { ONLINE_STATE_CHANGED_EVENT } from './events';
@@ -25,7 +26,10 @@ export default class NetworkInfoService extends EventEmitter {
*/
static _convertNetInfoState(netInfoState: NetInfoState): NetworkInfo {
return {
// @ts-ignore
isOnline: netInfoState.isInternetReachable,
// @ts-ignore
details: netInfoState.details,
networkType: netInfoState.type
};
@@ -47,6 +51,7 @@ export default class NetworkInfoService extends EventEmitter {
*/
start() {
this._subscription = NetInfo.addEventListener(netInfoState => {
// @ts-ignore
this.emit(ONLINE_STATE_CHANGED_EVENT, NetworkInfoService._convertNetInfoState(netInfoState));
});
}
@@ -59,6 +64,8 @@ export default class NetworkInfoService extends EventEmitter {
stop() {
if (this._subscription) {
this._subscription();
// @ts-ignore
this._subscription = undefined;
}
}

View File

@@ -6,6 +6,8 @@ import { ONLINE_STATE_CHANGED_EVENT } from './events';
* The network info service implementation for web (Chrome, Firefox and Safari).
*/
export default class NetworkInfoService extends EventEmitter {
_onlineStateListener: any;
_offlineStateListener: any;
/**
* Creates new instance...
@@ -23,7 +25,7 @@ export default class NetworkInfoService extends EventEmitter {
* @private
* @returns {void}
*/
_handleOnlineStatusChange(isOnline) {
_handleOnlineStatusChange(isOnline: boolean) {
this.emit(ONLINE_STATE_CHANGED_EVENT, { isOnline });
}
@@ -33,6 +35,7 @@ export default class NetworkInfoService extends EventEmitter {
* @returns {boolean}
*/
static isSupported() {
// @ts-ignore
return window.addEventListener && typeof navigator.onLine !== 'undefined';
}

View File

@@ -1,7 +1,6 @@
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app/actionTypes';
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
// @ts-ignore
import NetworkInfoService from './NetworkInfoService';
import { _storeNetworkInfoCleanup, setNetworkInfo } from './actions';
import { STORE_NAME } from './constants';
@@ -25,9 +24,12 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
const networkInfoService = new NetworkInfoService();
const stop = () => {
networkInfoService.stop();
// @ts-ignore
networkInfoService.removeAllListeners();
};
// @ts-ignore
networkInfoService.addListener(
ONLINE_STATE_CHANGED_EVENT,
({ isOnline, networkType, details }: NetworkInfo) => {

View File

@@ -19,8 +19,6 @@ import {
PARTICIPANT_ROLE,
WHITEBOARD_PARTICIPANT_ICON
} from './constants';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { preloadImage } from './preloadImage';
import { FakeParticipant, IJitsiParticipant, IParticipant, ISourceInfo } from './types';

View File

@@ -1,6 +1,3 @@
// @flow
import { Image } from 'react-native';
import { isIconUrl } from './functions';
@@ -9,14 +6,16 @@ import { isIconUrl } from './functions';
* Tries to preload an image.
*
* @param {string | Object} src - Source of the avatar.
* @param {boolean} _isUsingCORS - Used on web.
* @returns {Promise}
*/
export function preloadImage(src: string | Object): Promise<Object> {
export function preloadImage(src: string | Object, _isUsingCORS: boolean): Promise<any> {
if (isIconUrl(src)) {
return Promise.resolve(src);
}
return new Promise((resolve, reject) => {
// @ts-ignore
Image.prefetch(src).then(
() => resolve({
src,

View File

@@ -1,6 +1,4 @@
// @flow
import { isIconUrl } from './functions';
/**
@@ -14,9 +12,9 @@ import { isIconUrl } from './functions';
*/
export function preloadImage(
src: string | Object,
useCORS: ?boolean = false,
tryOnce: ?boolean = false
): Promise<Object> {
useCORS = false,
tryOnce = false
): Promise<{ isUsingCORS?: boolean; src: string | Object; }> {
if (isIconUrl(src)) {
return Promise.resolve({ src });
}
@@ -41,8 +39,9 @@ export function preloadImage(
}
};
// $FlowExpectedError
image.referrerPolicy = 'no-referrer';
// @ts-ignore
image.src = src;
});
}

View File

@@ -1,9 +1,9 @@
import React, { Component, ReactNode } from 'react';
import { IReduxState } from '../../../app/types';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { DialogPortal, Drawer, JitsiPortal } from '../../../toolbox/components/web';
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';

View File

@@ -7,6 +7,7 @@ import { translate } from '../../../i18n/functions';
import Icon from '../../../icons/components/Icon';
import { IconArrowDown, IconWifi1Bar, IconWifi2Bars, IconWifi3Bars } from '../../../icons/svg';
import { connect } from '../../../redux/functions';
import { withPixelLineHeight } from '../../../styles/functions.web';
import { PREJOIN_DEFAULT_CONTENT_WIDTH } from '../../../ui/components/variables';
import { CONNECTION_TYPE } from '../../constants';
import { getConnectionData } from '../../functions';
@@ -27,11 +28,8 @@ interface IProps extends WithTranslation {
const useStyles = makeStyles()(theme => {
return {
connectionStatus: {
borderRadius: '6px',
color: '#fff',
fontSize: '12px',
letterSpacing: '0.16px',
lineHeight: '16px',
...withPixelLineHeight(theme.typography.bodyShortRegular),
position: 'absolute',
width: '100%',
@@ -56,14 +54,15 @@ const useStyles = makeStyles()(theme => {
backgroundColor: 'rgba(0, 0, 0, 0.7)',
alignItems: 'center',
display: 'flex',
padding: '14px 16px'
padding: '12px 16px',
borderRadius: theme.shape.borderRadius
},
'& .con-status-circle': {
borderRadius: '50%',
display: 'inline-block',
padding: theme.spacing(1),
marginRight: theme.spacing(3)
marginRight: theme.spacing(2)
},
'& .con-status--good': {

View File

@@ -1,18 +1,18 @@
/* eslint-disable lines-around-comment */
import clsx from 'clsx';
import React, { ReactNode } from 'react';
import { connect } from 'react-redux';
import { makeStyles } from 'tss-react/mui';
import { IReduxState } from '../../../../app/types';
import DeviceStatus from '../../../../prejoin/components/web/preview/DeviceStatus';
// @ts-ignore
import { Toolbox } from '../../../../toolbox/components/web';
import Toolbox from '../../../../toolbox/components/web/Toolbox';
import { getConferenceName } from '../../../conference/functions';
import { PREMEETING_BUTTONS, THIRD_PARTY_PREJOIN_BUTTONS } from '../../../config/constants';
import { getToolbarButtons, isToolbarButtonEnabled } from '../../../config/functions.web';
import { connect } from '../../../redux/functions';
import { withPixelLineHeight } from '../../../styles/functions.web';
import ConnectionStatus from './ConnectionStatus';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import Preview from './Preview';
@@ -51,7 +51,7 @@ interface IProps {
/**
* Indicates whether the copy url button should be shown.
*/
showCopyUrlButton: boolean;
showCopyUrlButton?: boolean;
/**
* Indicates whether the device status should be shown.
@@ -86,7 +86,64 @@ interface IProps {
const useStyles = makeStyles()(theme => {
return {
subtitle: {
container: {
height: '100%',
position: 'absolute',
inset: '0 0 0 0',
display: 'flex',
backgroundColor: theme.palette.ui01,
zIndex: 252,
'@media (max-width: 720px)': {
flexDirection: 'column-reverse'
}
},
content: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
flexShrink: 0,
boxSizing: 'border-box',
margin: '0 48px',
padding: '24px 0 16px',
position: 'relative',
width: '300px',
height: '100%',
zIndex: 252,
'@media (max-width: 720px)': {
height: 'auto',
margin: '0 auto'
},
// mobile phone landscape
'@media (max-width: 420px)': {
padding: '16px 16px 0 16px',
width: '100%'
},
'@media (max-width: 400px)': {
padding: '16px'
}
},
contentControls: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
margin: 'auto',
width: '100%'
},
title: {
...withPixelLineHeight(theme.typography.heading4),
color: `${theme.palette.text01}!important`,
marginBottom: theme.spacing(3),
textAlign: 'center',
'@media (max-width: 400px)': {
display: 'none'
}
},
roomName: {
...withPixelLineHeight(theme.typography.heading5),
color: theme.palette.text01,
marginBottom: theme.spacing(4),
@@ -112,7 +169,6 @@ const PreMeetingScreen = ({
videoTrack
}: IProps) => {
const { classes } = useStyles();
const containerClassName = `premeeting-screen ${className ? className : ''}`;
const style = _premeetingBackground ? {
background: _premeetingBackground,
backgroundPosition: 'center',
@@ -120,17 +176,17 @@ const PreMeetingScreen = ({
} : {};
return (
<div className = { containerClassName }>
<div className = { clsx('premeeting-screen', classes.container, className) }>
<div style = { style }>
<div className = 'content'>
<div className = { classes.content }>
<ConnectionStatus />
<div className = 'content-controls'>
<h1 className = 'title'>
<div className = { classes.contentControls }>
<h1 className = { classes.title }>
{title}
</h1>
{_roomName && (
<span className = { classes.subtitle }>
<span className = { classes.roomName }>
{_roomName}
</span>
)}
@@ -175,7 +231,7 @@ function mapStateToProps(state: IReduxState, ownProps: Partial<IProps>) {
? premeetingButtons
: premeetingButtons.filter(b => isToolbarButtonEnabled(b, toolbarButtons)),
_premeetingBackground: premeetingBackground,
_roomName: hideConferenceSubject ? undefined : getConferenceName(state)
_roomName: (hideConferenceSubject ? undefined : getConferenceName(state)) ?? ''
};
}

View File

@@ -1,8 +1,6 @@
/* @flow */
import React, { Component, ReactNode } from 'react';
import React, { Component } from 'react';
import { getFixedPlatformStyle } from '../../styles';
import { getFixedPlatformStyle } from '../../styles/functions';
/**
* {@code AbstractContainer} Component's property types.
@@ -12,22 +10,22 @@ export type Props = {
/**
* An optional accessibility label to apply to the container root.
*/
accessibilityLabel?: string,
accessibilityLabel?: string;
/**
* Whether or not this element is an accessibility element.
*/
accessible?: boolean,
accessible?: boolean;
/**
* React Elements to display within the component.
*/
children: React$Node,
children: ReactNode;
/**
* Class names of the component (for web).
*/
className?: string,
className?: string;
/**
* The event handler/listener to be invoked when this
@@ -36,13 +34,13 @@ export type Props = {
* undefined, {@code touchFeedback} is considered defined as
* {@code true}.
*/
onClick?: ?Function,
onClick?: Function;
/**
* The style (as in stylesheet) to be applied to this
* {@code AbstractContainer}.
*/
style?: Array<?string> | Object,
style?: Array<string | undefined> | Object;
/**
* If this instance is to provide visual feedback when touched, then
@@ -50,19 +48,19 @@ export type Props = {
* undefined and {@link onClick} is defined, {@code touchFeedback} is
* considered defined as {@code true}.
*/
touchFeedback?: ?Function,
touchFeedback?: Function;
/**
* Color to display when clicked.
*/
underlayColor?: string,
underlayColor?: string;
/**
* If this {@code AbstractContainer} is to be visible, then {@code true}
* or {@code false} if this instance is to be hidden or not rendered at
* all.
*/
visible?: ?boolean
visible?: boolean;
};
/**
@@ -71,7 +69,7 @@ export type Props = {
*
* @augments Component
*/
export default class AbstractContainer<P: Props> extends Component<P> {
export default class AbstractContainer<P extends Props> extends Component<P> {
/**
* Renders this {@code AbstractContainer} as a React {@code Component} of a
* specific type.
@@ -84,12 +82,12 @@ export default class AbstractContainer<P: Props> extends Component<P> {
* @protected
* @returns {ReactElement}
*/
_render(type, props?: P) {
_render(type: string, props?: P) {
const {
children,
style,
/* eslint-disable no-unused-vars */
/* eslint-disable @typescript-eslint/no-unused-vars */
// The following properties are defined for the benefit of
// AbstractContainer and its extenders so they are to not be
@@ -97,14 +95,14 @@ export default class AbstractContainer<P: Props> extends Component<P> {
touchFeedback,
visible,
/* eslint-enable no-unused-vars */
/* eslint-enable @typescript-eslint/no-unused-vars */
...filteredProps
} = props || this.props;
// @ts-ignore
const _style = getFixedPlatformStyle(style);
// $FlowFixMe
return React.createElement(type, {
style: _style,
...filteredProps

View File

@@ -1,14 +1,11 @@
/* @flow */
import AbstractContainer from '../AbstractContainer';
import type { Props } from '../AbstractContainer';
import AbstractContainer, { Props } from '../AbstractContainer';
/**
* Represents a container of React/Web {@link Component} children with a style.
*
* @augments AbstractContainer
*/
export default class Container<P: Props> extends AbstractContainer<P> {
export default class Container<P extends Props> extends AbstractContainer<P> {
/**
* Implements React's {@link Component#render()}.
*

View File

@@ -52,7 +52,7 @@ const DEFAULT_STATE: ISettingsState = {
};
export interface ISettingsState {
audioOutputDeviceId?: string | boolean;
audioOutputDeviceId?: string;
audioSettingsVisible?: boolean;
avatarURL?: string;
cameraDeviceId?: string | boolean;
@@ -108,6 +108,7 @@ Object.keys(DEFAULT_STATE).forEach(key => {
// we want to filter these props, to not be stored as they represent
// what is currently opened/used as devices
// @ts-ignore
filterSubtree.audioOutputDeviceId = false;
filterSubtree.cameraDeviceId = false;
filterSubtree.micDeviceId = false;

View File

@@ -1,9 +1,11 @@
/* @flow */
import Platform from '../react/Platform';
import { ColorPalette } from './components';
import { ColorPalette } from './components/styles/ColorPalette';
declare type StyleSheet = {
[key: string]: string;
};
declare type StyleSheet = Object;
export type StyleType = StyleSheet | Array<StyleSheet>;
/**
@@ -44,7 +46,7 @@ const _WELL_KNOWN_NUMBER_PROPERTIES = [ 'height', 'width' ];
* @param {Styletype} st - The complex style type.
* @returns {Object}
*/
export function styleTypeToObject(st: StyleType): Object {
export function styleTypeToObject(st: StyleType): { [key: string]: string | number; } {
if (!st) {
return {};
}
@@ -103,12 +105,15 @@ export function combineStyles(a: StyleType, b: StyleType): StyleType {
*/
export function createStyleSheet(
styles: StyleSheet, overrides: StyleSheet = {}): StyleSheet {
const combinedStyles = {};
const combinedStyles: any = {};
for (const k of Object.keys(styles)) {
combinedStyles[k]
= _shimStyles({
// @ts-ignore
...styles[k],
// @ts-ignore
...overrides[k]
});
}
@@ -126,9 +131,12 @@ export function createStyleSheet(
* @public
* @returns {StyleSheet}
*/
export function fixAndroidViewClipping<T: StyleSheet>(styles: T): T {
export function fixAndroidViewClipping<T extends StyleSheet>(styles: T): T {
if (Platform.OS === 'android') {
// @ts-ignore
styles.borderColor = ColorPalette.appBackground;
// @ts-ignore
styles.borderWidth = 1;
}
@@ -220,7 +228,7 @@ function _getColorLuminance(c: number): number {
* b: number
* }}
*/
function _getRGBObjectFormat(color: string): {r: number, g: number, b: number} {
function _getRGBObjectFormat(color: string): { b: number; g: number; r: number; } {
let match = color.match(HEX_LONG_COLOR_FORMAT);
if (match) {
@@ -265,7 +273,7 @@ function _getRGBObjectFormat(color: string): {r: number, g: number, b: number} {
* @private
* @returns {StyleSheet}
*/
function _shimStyles<T: StyleSheet>(styles: T): T {
function _shimStyles<T extends StyleSheet>(styles: T): T {
// Certain style properties may not be numbers on Web but must be numbers on
// React Native. For example, height and width may be expressed in percent
// on Web but React Native will not understand them and we will get errors
@@ -281,6 +289,7 @@ function _shimStyles<T: StyleSheet>(styles: T): T {
if (Number.isNaN(numberV)) {
delete styles[k];
} else {
// @ts-ignore
styles[k] = numberV;
}
}

View File

@@ -1,6 +1,4 @@
// @flow
import { type StyleType } from './functions.any';
import { StyleType } from './functions.any';
export * from './functions.any';

View File

@@ -1,7 +1,5 @@
// @ts-ignore
import { StyleType } from './functions.any';
// @ts-ignore
export * from './functions.any';
/**

View File

@@ -159,7 +159,7 @@ export function createLocalTracksA(options: ITrackOptions = {}) {
throw new Error(`Local track for ${device} already exists`);
}
const gumProcess
const gumProcess: any
= createLocalTracksF(
{
cameraDeviceId: options.cameraDeviceId,
@@ -169,7 +169,7 @@ export function createLocalTracksA(options: ITrackOptions = {}) {
micDeviceId: options.micDeviceId
},
store)
.then(
.then( // @ts-ignore
(localTracks: any[]) => {
// Because GUM is called for 1 device (which is actually
// a media type 'audio', 'video', 'screen', etc.) we

View File

@@ -6,7 +6,6 @@ import { shouldShowModeratedNotification } from '../../av-moderation/functions';
import { setNoiseSuppressionEnabled } from '../../noise-suppression/actions';
import { showNotification } from '../../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants';
// @ts-ignore
import { stopReceiver } from '../../remote-control/actions';
import { setScreenAudioShareState, setScreenshareAudioTrack } from '../../screen-share/actions';
import { isAudioOnlySharing, isScreenVideoShared } from '../../screen-share/functions';

View File

@@ -9,7 +9,6 @@ import {
getUserSelectedMicDeviceId
} from '../settings/functions.web';
// @ts-ignore
import loadEffects from './loadEffects';
import logger from './logger';
import { ITrackOptions } from './types';

View File

@@ -1,11 +1,9 @@
// @flow
/**
* Loads the enabled stream effects.
*
* @param {Object} store - The Redux store.
* @param {Object} _store - The Redux store.
* @returns {Promsie} - A Promise which resolves with an array of the loaded effects.
*/
export default function loadEffects(store: Object): Promise<Array<any>> { // eslint-disable-line no-unused-vars
export default function loadEffects(_store: Object): Promise<Array<any>> {
return Promise.resolve([]);
}

View File

@@ -1,5 +1,6 @@
// @flow
import { IStore } from '../../app/types';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { createVirtualBackgroundEffect } from '../../stream-effects/virtual-background';
import logger from './logger';
@@ -10,13 +11,13 @@ import logger from './logger';
* @param {Object} store - The Redux store.
* @returns {Promsie} - A Promise which resolves when all effects are created.
*/
export default function loadEffects(store: Object): Promise<any> {
export default function loadEffects(store: IStore): Promise<any> {
const state = store.getState();
const virtualBackground = state['features/virtual-background'];
const backgroundPromise = virtualBackground.backgroundEffectEnabled
? createVirtualBackgroundEffect(virtualBackground)
.catch(error => {
.catch((error: Error) => {
logger.error('Failed to obtain the background effect instance with error: ', error);
return Promise.resolve();

View File

@@ -48,7 +48,6 @@ export const colors = {
// after we replace them in the components.
primary10: '#17A0DB',
primary11: '#1081B2',
primary12: '#B8C7E0',
surface00: '#111111',
surface12: '#AAAAAA',
surface13: '#495258',
@@ -199,7 +198,6 @@ export const colorMap = {
border01: 'surface08',
border02: 'surface06',
border03: 'surface04',
border04: 'primary12',
border05: 'surface07',
borderError: 'error06',
warning03: 'warning07',

View File

@@ -2,9 +2,8 @@ import React, { ReactNode, useEffect, useLayoutEffect, useRef, useState } from '
import { useSelector } from 'react-redux';
import { makeStyles } from 'tss-react/mui';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { Drawer, JitsiPortal } from '../../../../toolbox/components/web';
import Drawer from '../../../../toolbox/components/web/Drawer';
import JitsiPortal from '../../../../toolbox/components/web/JitsiPortal';
import { showOverflowDrawer } from '../../../../toolbox/functions.web';
import participantsPaneTheme from '../../../components/themes/participantsPaneTheme.json';
import { withPixelLineHeight } from '../../../styles/functions.web';
@@ -35,6 +34,8 @@ const getComputedOuterHeight = (element: HTMLElement) => {
interface IProps {
[key: `aria-${string}`]: string;
/**
* Accessibility label for menu container.
*/
@@ -60,6 +61,11 @@ interface IProps {
*/
hidden?: boolean;
/**
* Optional id.
*/
id?: string;
/**
* Whether or not the menu is already in a drawer.
*/
@@ -99,6 +105,11 @@ interface IProps {
* Callback for the mouse leaving the component.
*/
onMouseLeave?: (e?: React.MouseEvent) => void;
/**
* Tab index for the menu.
*/
tabIndex?: number;
}
const MAX_HEIGHT = 400;
@@ -109,7 +120,7 @@ const useStyles = makeStyles()(theme => {
backgroundColor: theme.palette.ui01,
border: `1px solid ${theme.palette.ui04}`,
borderRadius: `${Number(theme.shape.borderRadius)}px`,
boxShadow: '0px 4px 25px 4px rgba(20, 20, 20, 0.6)',
boxShadow: '0px 1px 2px rgba(41, 41, 41, 0.25)',
color: theme.palette.text01,
...withPixelLineHeight(theme.typography.bodyShortRegular),
marginTop: `${(participantsPaneTheme.panePadding * 2) + theme.typography.bodyShortRegular.fontSize}px`,
@@ -147,6 +158,7 @@ const ContextMenu = ({
className,
entity,
hidden,
id,
inDrawer,
isDrawerOpen,
offsetTarget,
@@ -154,7 +166,8 @@ const ContextMenu = ({
onKeyDown,
onDrawerClose,
onMouseEnter,
onMouseLeave
onMouseLeave,
tabIndex
}: IProps) => {
const [ isHidden, setIsHidden ] = useState(true);
const containerRef = useRef<HTMLDivElement | null>(null);
@@ -202,7 +215,7 @@ const ContextMenu = ({
return _overflowDrawer
? <JitsiPortal>
<Drawer
isOpen = { isDrawerOpen && _overflowDrawer }
isOpen = { Boolean(isDrawerOpen && _overflowDrawer) }
onClose = { onDrawerClose }>
<div
className = { styles.drawer }
@@ -218,11 +231,14 @@ const ContextMenu = ({
isHidden && styles.contextMenuHidden,
className
) }
id = { id }
onClick = { onClick }
onKeyDown = { onKeyDown }
onMouseEnter = { onMouseEnter }
onMouseLeave = { onMouseLeave }
ref = { containerRef }>
ref = { containerRef }
role = 'menu'
tabIndex = { tabIndex }>
{children}
</div>;
};

View File

@@ -13,6 +13,11 @@ export interface IProps {
*/
accessibilityLabel: string;
/**
* Component children.
*/
children?: ReactNode;
/**
* CSS class name used for custom styles.
*/
@@ -54,6 +59,11 @@ export interface IProps {
*/
onKeyPress?: (e?: React.KeyboardEvent) => void;
/**
* Whether the item is marked as selected.
*/
selected?: boolean;
/**
* TestId of the element, if any.
*/
@@ -62,7 +72,7 @@ export interface IProps {
/**
* Action text.
*/
text: string;
text?: string;
/**
* Class name for the text.
@@ -90,9 +100,19 @@ const useStyles = makeStyles()(theme => {
'&:active': {
backgroundColor: theme.palette.ui03
},
'&:focus': {
boxShadow: `inset 0 0 0 2px ${theme.palette.action01Hover}`
}
},
selected: {
borderLeft: `3px solid ${theme.palette.action01Hover}`,
paddingLeft: '13px',
backgroundColor: theme.palette.ui02
},
contextMenuItemDisabled: {
pointerEvents: 'none'
},
@@ -120,6 +140,7 @@ const useStyles = makeStyles()(theme => {
const ContextMenuItem = ({
accessibilityLabel,
children,
className,
customIcon,
disabled,
@@ -128,6 +149,7 @@ const ContextMenuItem = ({
onClick,
onKeyDown,
onKeyPress,
selected,
testId,
text,
textClassName }: IProps) => {
@@ -141,6 +163,7 @@ const ContextMenuItem = ({
className = { cx(styles.contextMenuItem,
_overflowDrawer && styles.contextMenuItemDrawer,
disabled && styles.contextMenuItemDisabled,
selected && styles.selected,
className
) }
data-testid = { testId }
@@ -148,13 +171,15 @@ const ContextMenuItem = ({
key = { text }
onClick = { disabled ? undefined : onClick }
onKeyDown = { disabled ? undefined : onKeyDown }
onKeyPress = { disabled ? undefined : onKeyPress }>
onKeyPress = { disabled ? undefined : onKeyPress }
role = 'menuitem'>
{customIcon ? customIcon
: icon && <Icon
className = { styles.contextMenuItemIcon }
size = { 20 }
src = { icon } />}
<span className = { cx(textClassName) }>{text}</span>
{text && <span className = { cx(styles.text, textClassName) }>{text}</span>}
{children}
</div>
);
};

View File

@@ -25,7 +25,7 @@ const useStyles = makeStyles()(theme => {
},
'& + &:not(:empty)': {
borderTop: `1px solid ${theme.palette.ui04}`
borderTop: `1px solid ${theme.palette.ui03}`
},
'&:first-of-type': {

View File

@@ -3,9 +3,7 @@ import React, { Component, ComponentType } from 'react';
import { IReduxState } from '../../../../app/types';
import { IReactionEmojiProps } from '../../../../reactions/constants';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { JitsiPortal } from '../../../../toolbox/components/web';
import JitsiPortal from '../../../../toolbox/components/web/JitsiPortal';
import { showOverflowDrawer } from '../../../../toolbox/functions.web';
import { connect } from '../../../redux/functions';

View File

@@ -10,6 +10,7 @@ import { IInputProps } from '../types';
interface IProps extends IInputProps {
accessibilityLabel?: string;
autoComplete?: string;
autoFocus?: boolean;
bottomLabel?: string;
className?: string;
@@ -131,6 +132,7 @@ const useStyles = makeStyles()(theme => {
const Input = React.forwardRef<any, IProps>(({
accessibilityLabel,
autoComplete,
autoFocus,
bottomLabel,
className,
@@ -175,6 +177,7 @@ const Input = React.forwardRef<any, IProps>(({
{textarea ? (
<TextareaAutosize
aria-label = { accessibilityLabel }
autoComplete = { autoComplete }
autoFocus = { autoFocus }
className = { cx(styles.input, isMobile && 'is-mobile',
error && 'error', clearable && styles.clearableInput, icon && 'icon-input') }
@@ -194,6 +197,7 @@ const Input = React.forwardRef<any, IProps>(({
) : (
<input
aria-label = { accessibilityLabel }
autoComplete = { autoComplete }
autoFocus = { autoFocus }
className = { cx(styles.input, isMobile && 'is-mobile',
error && 'error', clearable && styles.clearableInput, icon && 'icon-input') }

View File

@@ -228,7 +228,11 @@ export const commonStyles = (theme: Theme) => {
'@media (hover: hover) and (pointer: fine)': {
'&:hover': {
background: theme.palette.ui04
backgroundColor: theme.palette.ui04
},
'&:active': {
backgroundColor: theme.palette.ui03
}
},
[theme.breakpoints.down(320)]: {
@@ -237,7 +241,7 @@ export const commonStyles = (theme: Theme) => {
},
'&.toggled': {
background: theme.palette.ui03
backgroundColor: theme.palette.ui03
},
'&.disabled': {
@@ -268,10 +272,10 @@ export const commonStyles = (theme: Theme) => {
boxShadow: '0px 2px 8px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.15)',
'& > div': {
marginLeft: 8,
marginRight: theme.spacing(2),
'&:first-child': {
marginLeft: 0
'&:last-of-type': {
marginRight: 0
}
}
}

View File

@@ -45,6 +45,7 @@ const useStyles = makeStyles()(theme => {
avatar: {
margin: `${theme.spacing(1)} ${theme.spacing(2)} ${theme.spacing(3)} 0`,
position: 'sticky',
flexShrink: 0,
top: 0
}
};

View File

@@ -1,4 +1,3 @@
/* eslint-disable lines-around-comment */
import { AnyAction } from 'redux';
import { IReduxState, IStore } from '../app/types';
@@ -30,12 +29,14 @@ import { pushReactions } from '../reactions/actions.any';
import { ENDPOINT_REACTION_NAME } from '../reactions/constants';
import { getReactionMessageFromBuffer, isReactionsEnabled } from '../reactions/functions.any';
import { endpointMessageReceived } from '../subtitles/actions.any';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { showToolbox } from '../toolbox/actions';
import { ADD_MESSAGE, CLOSE_CHAT, OPEN_CHAT, SEND_MESSAGE, SET_IS_POLL_TAB_FOCUSED } from './actionTypes';
import { addMessage, clearMessages, closeChat } from './actions.any';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { ChatPrivacyDialog } from './components';
import {
@@ -47,7 +48,6 @@ import {
} from './constants';
import { getUnreadCount } from './functions';
import { INCOMING_MSG_SOUND_FILE } from './sounds';
/* eslint-enable lines-around-comment */
/**
* Timeout for when to show the privacy notice after a private message was received.

View File

@@ -1,7 +1,6 @@
// @flow
import { PureComponent } from 'react';
import React, { PureComponent } from 'react';
import { IReduxState } from '../../app/types';
import isInsecureRoomName from '../../base/util/isInsecureRoomName';
type Props = {
@@ -14,11 +13,11 @@ type Props = {
/**
* Function to be used to translate i18n labels.
*/
t: Function
}
t: Function;
};
/**
* Abstrsact class for the {@Code InsecureRoomNameLabel} component.
* Abstract class for the {@Code InsecureRoomNameLabel} component.
*/
export default class AbstractInsecureRoomNameLabel extends PureComponent<Props> {
/**
@@ -39,7 +38,9 @@ export default class AbstractInsecureRoomNameLabel extends PureComponent<Props>
*
* @returns {ReactElement}
*/
_render: () => Object;
_render() {
return <></>;
}
}
/**
@@ -48,14 +49,14 @@ export default class AbstractInsecureRoomNameLabel extends PureComponent<Props>
* @param {Object} state - The Redux state.
* @returns {Props}
*/
export function _mapStateToProps(state: Object): $Shape<Props> {
export function _mapStateToProps(state: IReduxState) {
const { locked, room } = state['features/base/conference'];
const { lobbyEnabled } = state['features/lobby'];
const { enableInsecureRoomNameWarning = false } = state['features/base/config'];
return {
_visible: enableInsecureRoomNameWarning
_visible: Boolean(enableInsecureRoomNameWarning
&& room && isInsecureRoomName(room)
&& !(lobbyEnabled || Boolean(locked))
&& !(lobbyEnabled || Boolean(locked)))
};
}

View File

@@ -1,180 +0,0 @@
// @flow
import { Component } from 'react';
import { renderConferenceTimer } from '../';
import { getConferenceTimestamp } from '../../base/conference/functions';
import { getLocalizedDurationFormatter } from '../../base/i18n';
import { connect } from '../../base/redux';
/**
* The type of the React {@code Component} props of {@link ConferenceTimer}.
*/
type Props = {
/**
* The UTC timestamp representing the time when first participant joined.
*/
_startTimestamp: ?number,
/**
* Style to be applied to the rendered text.
*/
textStyle: ?Object,
/**
* The redux {@code dispatch} function.
*/
dispatch: Function
};
/**
* The type of the React {@code Component} state of {@link ConferenceTimer}.
*/
type State = {
/**
* Value of current conference time.
*/
timerValue: string
};
/**
* ConferenceTimer react component.
*
* @class ConferenceTimer
* @augments Component
*/
class ConferenceTimer extends Component<Props, State> {
/**
* Handle for setInterval timer.
*/
_interval;
/**
* Initializes a new {@code ConferenceTimer} instance.
*
* @param {Props} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props: Props) {
super(props);
this.state = {
timerValue: getLocalizedDurationFormatter(0)
};
}
/**
* Starts the conference timer when component will be
* mounted.
*
* @inheritdoc
*/
componentDidMount() {
this._startTimer();
}
/**
* Stops the conference timer when component will be
* unmounted.
*
* @inheritdoc
*/
componentWillUnmount() {
this._stopTimer();
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const { timerValue } = this.state;
const { _startTimestamp, textStyle } = this.props;
if (!_startTimestamp) {
return null;
}
return renderConferenceTimer(timerValue, textStyle);
}
/**
* Sets the current state values that will be used to render the timer.
*
* @param {number} refValueUTC - The initial UTC timestamp value.
* @param {number} currentValueUTC - The current UTC timestamp value.
*
* @returns {void}
*/
_setStateFromUTC(refValueUTC, currentValueUTC) {
if (!refValueUTC || !currentValueUTC) {
return;
}
if (currentValueUTC < refValueUTC) {
return;
}
const timerMsValue = currentValueUTC - refValueUTC;
const localizedTime = getLocalizedDurationFormatter(timerMsValue);
this.setState({
timerValue: localizedTime
});
}
/**
* Start conference timer.
*
* @returns {void}
*/
_startTimer() {
if (!this._interval) {
this._setStateFromUTC(this.props._startTimestamp, new Date().getTime());
this._interval = setInterval(() => {
this._setStateFromUTC(this.props._startTimestamp, new Date().getTime());
}, 1000);
}
}
/**
* Stop conference timer.
*
* @returns {void}
*/
_stopTimer() {
if (this._interval) {
clearInterval(this._interval);
}
this.setState({
timerValue: getLocalizedDurationFormatter(0)
});
}
}
/**
* Maps (parts of) the Redux state to the associated
* {@code ConferenceTimer}'s props.
*
* @param {Object} state - The Redux state.
* @private
* @returns {{
* _startTimestamp: number
* }}
*/
export function _mapStateToProps(state: Object) {
return {
_startTimestamp: getConferenceTimestamp(state)
};
}
export default connect(_mapStateToProps)(ConferenceTimer);

View File

@@ -0,0 +1,106 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useSelector } from 'react-redux';
// @ts-ignore
import { ConferenceTimerDisplay } from '..';
import { getConferenceTimestamp } from '../../base/conference/functions';
import { getLocalizedDurationFormatter } from '../../base/i18n/dateUtil';
/**
* The type of the React {@code Component} props of {@link ConferenceTimer}.
*/
interface IProps {
/**
* Style to be applied to the rendered text.
*/
textStyle?: Object;
}
export interface IDisplayProps {
/**
* Style to be applied to text (native only).
*/
textStyle: Object;
/**
* String to display as time.
*/
timerValue: string;
}
const ConferenceTimer = ({ textStyle }: IProps) => {
const startTimestamp = useSelector(getConferenceTimestamp);
const [ timerValue, setTimerValue ] = useState(getLocalizedDurationFormatter(0));
const interval = useRef<number>();
/**
* Sets the current state values that will be used to render the timer.
*
* @param {number} refValueUTC - The initial UTC timestamp value.
* @param {number} currentValueUTC - The current UTC timestamp value.
*
* @returns {void}
*/
const setStateFromUTC = useCallback((refValueUTC, currentValueUTC) => {
if (!refValueUTC || !currentValueUTC) {
return;
}
if (currentValueUTC < refValueUTC) {
return;
}
const timerMsValue = currentValueUTC - refValueUTC;
const localizedTime = getLocalizedDurationFormatter(timerMsValue);
setTimerValue(localizedTime);
}, []);
/**
* Start conference timer.
*
* @returns {void}
*/
const startTimer = useCallback(() => {
if (!interval.current && startTimestamp) {
setStateFromUTC(startTimestamp, new Date().getTime());
interval.current = window.setInterval(() => {
setStateFromUTC(startTimestamp, new Date().getTime());
}, 1000);
}
}, [ startTimestamp, interval ]);
/**
* Stop conference timer.
*
* @returns {void}
*/
const stopTimer = useCallback(() => {
if (interval.current) {
clearInterval(interval.current);
}
setTimerValue(getLocalizedDurationFormatter(0));
}, [ interval ]);
useEffect(() => {
startTimer();
return () => stopTimer();
}, [ startTimestamp ]);
if (!startTimestamp) {
return null;
}
return (<ConferenceTimerDisplay
textStyle = { textStyle }
timerValue = { timerValue } />);
};
export default ConferenceTimer;

View File

@@ -1,5 +1,5 @@
export const CONFERENCE_INFO = {
alwaysVisible: [ 'recording', 'raised-hands-count' ],
alwaysVisible: [ 'raised-hands-count', 'recording' ],
autoHide: [
'highlight-moment',
'subject',

View File

@@ -1,17 +1,16 @@
// @flow
import React from 'react';
import { Text } from 'react-native';
import { IDisplayProps } from '../ConferenceTimer';
/**
* Returns native element to be rendered.
*
* @param {string} timerValue - String to display as time.
* @param {Object} textStyle - Style to be applied to the text.
* @param {Object} props - Component props.
*
* @returns {ReactElement}
*/
export default function renderConferenceTimer(timerValue: string, textStyle: Object) {
export default function ConferenceTimerDisplay({ timerValue, textStyle }: IDisplayProps) {
return (
<Text
numberOfLines = { 1 }

View File

@@ -1,5 +1,5 @@
// @flow
export { default as Conference } from './Conference';
export { default as renderConferenceTimer } from './ConferenceTimerDisplay';
export { default as ConferenceTimerDisplay } from './ConferenceTimerDisplay';
export { default as InsecureRoomNameLabel } from './InsecureRoomNameLabel';

View File

@@ -6,12 +6,12 @@ import React, { Component } from 'react';
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
import { connect } from '../../../base/redux';
import { E2EELabel } from '../../../e2ee';
import { RecordingLabel } from '../../../recording';
import E2EELabel from '../../../e2ee/components/E2EELabel';
import HighlightButton from '../../../recording/components/Recording/web/HighlightButton';
import RecordingLabel from '../../../recording/components/web/RecordingLabel';
import { isToolboxVisible } from '../../../toolbox/functions.web';
import { TranscribingLabel } from '../../../transcribing';
import { VideoQualityLabel } from '../../../video-quality';
import TranscribingLabel from '../../../transcribing/components/TranscribingLabel.web';
import VideoQualityLabel from '../../../video-quality/components/VideoQualityLabel.web';
import ConferenceTimer from '../ConferenceTimer';
import { getConferenceInfo } from '../functions';

View File

@@ -1,19 +0,0 @@
// @flow
/* eslint-disable no-unused-vars */
import React from 'react';
/**
* Returns web element to be rendered.
*
* @param {string} timerValue - String to display as time.
* @param {Object} textStyle - Unused on web.
*
* @returns {ReactElement}
*/
export default function renderConferenceTimer(timerValue: string, textStyle: Object) {
return (
<span className = 'subject-timer'>{ timerValue }</span>
);
}

View File

@@ -0,0 +1,37 @@
import React from 'react';
import { makeStyles } from 'tss-react/mui';
import { withPixelLineHeight } from '../../../base/styles/functions.web';
import { IDisplayProps } from '../ConferenceTimer';
const useStyles = makeStyles()(theme => {
return {
timer: {
...withPixelLineHeight(theme.typography.labelRegular),
color: theme.palette.text01,
padding: '6px 8px',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
boxSizing: 'border-box',
height: '28px',
borderRadius: `0 ${theme.shape.borderRadius}px ${theme.shape.borderRadius}px 0`,
marginRight: '2px',
'@media (max-width: 300px)': {
display: 'none'
}
}
};
});
/**
* Returns web element to be rendered.
*
* @returns {ReactElement}
*/
export default function ConferenceTimerDisplay({ timerValue, textStyle: _textStyle }: IDisplayProps) {
const { classes } = useStyles();
return (
<span className = { classes.timer }>{ timerValue }</span>
);
}

View File

@@ -1,13 +1,11 @@
// @flow
import Tooltip from '@atlaskit/tooltip';
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../base/i18n';
import { translate } from '../../../base/i18n/functions';
import { IconExclamationTriangle } from '../../../base/icons/svg';
import { Label } from '../../../base/label';
import Label from '../../../base/label/components/web/Label';
import { COLORS } from '../../../base/label/constants';
import { connect } from '../../../base/redux';
import AbstractInsecureRoomNameLabel, { _mapStateToProps } from '../AbstractInsecureRoomNameLabel';
/**

View File

@@ -15,8 +15,7 @@ const useStyles = makeStyles()(theme => {
return {
label: {
backgroundColor: theme.palette.warning02,
color: theme.palette.uiBackground,
marginRight: theme.spacing(1)
color: theme.palette.uiBackground
}
};
});

View File

@@ -1,50 +0,0 @@
/* @flow */
import React from 'react';
import { getConferenceName } from '../../../base/conference/functions';
import { connect } from '../../../base/redux';
import { Tooltip } from '../../../base/tooltip';
type Props = {
/**
* The conference display name.
*/
_subject: string
}
/**
* Label for the conference name.
*
* @param {Props} props - The props of the component.
* @returns {ReactElement}
*/
const SubjectText = ({ _subject }: Props) => (
<div className = 'subject-text'>
<Tooltip
content = { _subject }
position = 'bottom'>
<div className = 'subject-text--content'>{ _subject }</div>
</Tooltip>
</div>
);
/**
* Maps (parts of) the Redux state to the associated
* {@code Subject}'s props.
*
* @param {Object} state - The Redux state.
* @private
* @returns {{
* _subject: string,
* }}
*/
function _mapStateToProps(state) {
return {
_subject: getConferenceName(state)
};
}
export default connect(_mapStateToProps)(SubjectText);

View File

@@ -0,0 +1,57 @@
import clsx from 'clsx';
import React from 'react';
import { useSelector } from 'react-redux';
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';
const useStyles = makeStyles()(theme => {
return {
container: {
...withPixelLineHeight(theme.typography.bodyLongRegular),
color: theme.palette.text01,
padding: '2px 16px',
backgroundColor: 'rgba(0, 0, 0, 0.6)',
maxWidth: '324px',
boxSizing: 'border-box',
height: '28px',
borderRadius: `${theme.shape.borderRadius}px 0 0 ${theme.shape.borderRadius}px`,
marginLeft: '2px',
'@media (max-width: 300px)': {
display: 'none'
}
},
content: {
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}
};
});
/**
* Label for the conference name.
*
* @returns {ReactElement}
*/
const SubjectText = () => {
const subject = useSelector(getConferenceName);
const { classes } = useStyles();
return (
<div className = { classes.container }>
<Tooltip
content = { subject }
position = 'bottom'>
<div className = { clsx('subject-text--content', classes.content) }>{subject}</div>
</Tooltip>
</div>
);
};
export default SubjectText;

View File

@@ -1,7 +1,7 @@
// @flow
export { default as Conference } from './Conference';
export { default as renderConferenceTimer } from './ConferenceTimerDisplay';
export { default as ConferenceTimerDisplay } from './ConferenceTimerDisplay';
export { default as InsecureRoomNameLabel } from './InsecureRoomNameLabel';
export { default as ConferenceInfo } from './ConferenceInfo';
export { default as SubjectText } from './SubjectText';

View File

@@ -147,7 +147,7 @@ const styles = (theme: Theme) => {
},
icon: {
padding: '6px',
padding: '4px',
borderRadius: '4px',
'&.status-high': {

View File

@@ -103,7 +103,7 @@ export const ConnectionIndicatorIcon = ({
<span className = { emptyIconWrapperClassName }>
<Icon
className = { clsx(classes.icon, colorClass) }
size = { 12 }
size = { 16 }
src = { IconConnection } />
</span>
);

View File

@@ -1,32 +1,28 @@
// @flow
import { WithTranslation } from 'react-i18next';
import { IReduxState } from '../../app/types';
export type Props = {
export interface IProps extends WithTranslation {
/**
* Custom e2ee labels.
*/
_e2eeLabels?: Object;
_e2eeLabels?: any;
/**
* True if the label needs to be rendered, false otherwise.
*/
_showLabel: boolean,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
_showLabel?: boolean;
}
/**
* Maps (parts of) the redux state to the associated props of this {@code Component}.
*
* @param {Object} state - The redux state.
* @private
* @returns {Props}
* @returns {IProps}
*/
export function _mapStateToProps(state: Object) {
export function _mapStateToProps(state: IReduxState) {
const { e2ee = {} } = state['features/base/config'];
return {

View File

@@ -1,47 +0,0 @@
// @flow
import React, { Component } from 'react';
import { translate } from '../../base/i18n';
import { IconE2EE } 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 { type Props, _mapStateToProps } from './AbstractE2EELabel';
/**
* React {@code Component} for displaying a label when everyone has E2EE enabled in a conference.
*
* @augments Component
*/
class E2EELabel extends Component<Props> {
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
if (!this.props._showLabel) {
return null;
}
const { _e2eeLabels, t } = this.props;
const content = _e2eeLabels?.labelToolTip || t('e2ee.labelToolTip');
return (
<Tooltip
content = { content }
position = { 'bottom' }>
<Label
color = { COLORS.green }
icon = { IconE2EE } />
</Tooltip>
);
}
}
export default translate(connect(_mapStateToProps)(E2EELabel));

View File

@@ -0,0 +1,32 @@
import React from 'react';
import { connect } from 'react-redux';
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 { IProps, _mapStateToProps } from './AbstractE2EELabel';
const E2EELabel = ({ _e2eeLabels, _showLabel, t }: IProps) => {
if (!_showLabel) {
return null;
}
const content = _e2eeLabels?.labelToolTip || t('e2ee.labelToolTip');
return (
<Tooltip
content = { content }
position = { 'bottom' }>
<Label
color = { COLORS.green }
icon = { IconE2EE } />
</Tooltip>
);
};
export default translate(connect(_mapStateToProps)(E2EELabel));

View File

@@ -1,22 +0,0 @@
// @flow
import React, { Component } from 'react';
import { IconCrown } from '../../../base/icons';
import { BaseIndicator } from '../../../base/react';
/**
* Thumbnail badge showing that the participant is a conference moderator.
*/
export default class ModeratorIndicator extends Component<{}> {
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
*/
render() {
return (
<BaseIndicator icon = { IconCrown } />
);
}
}

View File

@@ -0,0 +1,17 @@
/* eslint-disable lines-around-comment */
import React from 'react';
// @ts-ignore
import { IconModerator } from '../../../base/icons';
// @ts-ignore
import { BaseIndicator } from '../../../base/react';
/**
* Thumbnail badge showing that the participant is a conference moderator.
*
* @returns {JSX.Element}
*/
const ModeratorIndicator = (): JSX.Element => <BaseIndicator icon = { IconModerator } />;
export default ModeratorIndicator;

View File

@@ -1,4 +1,3 @@
/* eslint-disable lines-around-comment */
import { withStyles } from '@mui/styles';
import clsx from 'clsx';
import _ from 'lodash';
@@ -48,9 +47,7 @@ import {
// @ts-ignore
import AudioTracksContainer from './AudioTracksContainer';
import Thumbnail from './Thumbnail';
// @ts-ignore
import ThumbnailWrapper from './ThumbnailWrapper';
// @ts-ignore
import { styles } from './styles';
/**
@@ -307,6 +304,7 @@ class Filmstrip extends PureComponent <IProps, IState> {
'keyboardShortcuts.toggleFilmstrip'
);
document.addEventListener('mouseup', this._onDragMouseUp);
// @ts-ignore
document.addEventListener('mousemove', this._throttledResize);
}
@@ -319,6 +317,7 @@ class Filmstrip extends PureComponent <IProps, IState> {
componentWillUnmount() {
APP.keyboardshortcut.unregisterShortcut('F');
document.removeEventListener('mouseup', this._onDragMouseUp);
// @ts-ignore
document.removeEventListener('mousemove', this._throttledResize);
}
@@ -694,6 +693,7 @@ class Filmstrip extends PureComponent <IProps, IState> {
initialScrollLeft = { 0 }
initialScrollTop = { 0 }
itemData = {{ filmstripType }}
// @ts-ignore
itemKey = { this._gridItemKey }
onItemsRendered = { this._onGridItemsRendered }
@@ -853,6 +853,7 @@ class Filmstrip extends PureComponent <IProps, IState> {
{ ...actions }>
<Icon
aria-label = { t('toolbar.accessibilityLabel.toggleFilmstrip') }
size = { 24 }
src = { icon } />
</button>
</div>

View File

@@ -1,8 +1,10 @@
/* @flow */
/* eslint-disable lines-around-comment */
import React from 'react';
import { IconCrown } from '../../../base/icons';
// @ts-ignore
import { IconModerator } from '../../../base/icons';
// @ts-ignore
import { BaseIndicator } from '../../../base/react';
/**
@@ -13,17 +15,17 @@ type Props = {
/**
* From which side of the indicator the tooltip should appear from.
*/
tooltipPosition: string
tooltipPosition: string;
};
/**
* React {@code Component} for showing a moderator icon with a tooltip.
*
* @returns {Component}
* @returns {JSX.Element}
*/
const ModeratorIndicator = ({ tooltipPosition }: Props) => (
const ModeratorIndicator = ({ tooltipPosition }: Props): JSX.Element => (
<BaseIndicator
icon = { IconCrown }
icon = { IconModerator }
iconSize = { 16 }
tooltipKey = 'videothumbnail.moderator'
tooltipPosition = { tooltipPosition } />

View File

@@ -66,6 +66,7 @@ import ThumbnailBottomIndicators from './ThumbnailBottomIndicators';
import ThumbnailTopIndicators from './ThumbnailTopIndicators';
// @ts-ignore
import VirtualScreenshareParticipant from './VirtualScreenshareParticipant';
/* eslint-enable lines-around-comment */
/**
* The type of the React {@code Component} state of {@link Thumbnail}.
@@ -336,7 +337,7 @@ const defaultStyles = (theme: Theme) => {
activeSpeaker: {
'& .active-speaker-indicator': {
boxShadow: `inset 0px 0px 0px 4px ${theme.palette.link01Active} !important`
boxShadow: `inset 0px 0px 0px 3px ${theme.palette.action01Hover} !important`
}
},
@@ -1218,6 +1219,7 @@ function _mapStateToProps(state: IReduxState, ownProps: any): Object {
const { local, remote }
= tileType === THUMBNAIL_TYPE.VERTICAL
? verticalViewDimensions : horizontalViewDimensions;
// @ts-ignore
const { width, height } = (isLocal ? local : remote) ?? {};

View File

@@ -1,13 +1,14 @@
/* @flow */
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { shouldComponentUpdate } from 'react-window';
import { getLocalParticipant } from '../../../base/participants';
import { connect } from '../../../base/redux';
import { IReduxState } from '../../../app/types';
import { getLocalParticipant } from '../../../base/participants/functions';
import { getHideSelfView } from '../../../base/settings/functions.any';
import { LAYOUTS, getCurrentLayout } from '../../../video-layout';
import { LAYOUTS } from '../../../video-layout/constants';
import { getCurrentLayout } from '../../../video-layout/functions.web';
import { FILMSTRIP_TYPE, TILE_ASPECT_RATIO, TILE_HORIZONTAL_MARGIN } from '../../constants';
import { getActiveParticipantsIds, showGridInVerticalView } from '../../functions';
import { getActiveParticipantsIds, showGridInVerticalView } from '../../functions.web';
import Thumbnail from './Thumbnail';
@@ -19,53 +20,53 @@ type Props = {
/**
* Whether or not to hide the self view.
*/
_disableSelfView: boolean,
_disableSelfView?: boolean;
/**
* The type of filmstrip this thumbnail is displayed in.
*/
_filmstripType: string,
_filmstripType?: string;
/**
* The horizontal offset in px for the thumbnail. Used to center the thumbnails in the last row in tile view.
*/
_horizontalOffset: number,
/**
* The ID of the participant associated with the Thumbnail.
*/
_participantID: ?string,
_horizontalOffset?: number;
/**
* Whether or not the thumbnail is a local screen share.
*/
_isLocalScreenShare: boolean,
_isLocalScreenShare?: boolean;
/**
* The ID of the participant associated with the Thumbnail.
*/
_participantID?: string;
/**
* The width of the thumbnail. Used for expanding the width of the thumbnails on last row in case
* there is empty space.
*/
_thumbnailWidth: number,
_thumbnailWidth?: number;
/**
* The index of the column in tile view.
*/
columnIndex?: number,
columnIndex?: number;
/**
* The index of the ThumbnailWrapper in stage view.
*/
index?: number,
index?: number;
/**
* The index of the row in tile view.
*/
rowIndex?: number,
rowIndex?: number;
/**
* The styles coming from react-window.
*/
style: Object
style: Object;
};
/**
@@ -73,6 +74,7 @@ type Props = {
* to the Thumbnail Component's props.
*/
class ThumbnailWrapper extends Component<Props> {
shouldComponentUpdate: (p: any, s: any) => boolean;
/**
* Creates new ThumbnailWrapper instance.
@@ -85,8 +87,6 @@ class ThumbnailWrapper extends Component<Props> {
this.shouldComponentUpdate = shouldComponentUpdate.bind(this);
}
shouldComponentUpdate: Props => boolean;
/**
* Implements React's {@link Component#render()}.
*
@@ -148,7 +148,8 @@ class ThumbnailWrapper extends Component<Props> {
* @private
* @returns {Props}
*/
function _mapStateToProps(state, ownProps) {
function _mapStateToProps(state: IReduxState, ownProps: { columnIndex: number;
data: { filmstripType: string; }; index?: number; rowIndex: number; }) {
const _currentLayout = getCurrentLayout(state);
const { remoteParticipants: remote } = state['features/filmstrip'];
const activeParticipants = getActiveParticipantsIds(state);
@@ -159,23 +160,23 @@ function _mapStateToProps(state, ownProps) {
const sortedActiveParticipants = activeParticipants.sort();
const remoteParticipants = stageFilmstrip ? sortedActiveParticipants : remote;
const remoteParticipantsLength = remoteParticipants.length;
const localId = getLocalParticipant(state).id;
const localId = getLocalParticipant(state)?.id;
if (_currentLayout === LAYOUTS.TILE_VIEW || _verticalViewGrid || stageFilmstrip) {
const { columnIndex, rowIndex } = ownProps;
const { tileViewDimensions, stageFilmstripDimensions, verticalViewDimensions } = state['features/filmstrip'];
const { gridView } = verticalViewDimensions;
let gridDimensions = tileViewDimensions.gridDimensions,
thumbnailSize = tileViewDimensions.thumbnailSize;
let gridDimensions = tileViewDimensions?.gridDimensions,
thumbnailSize = tileViewDimensions?.thumbnailSize;
if (stageFilmstrip) {
gridDimensions = stageFilmstripDimensions.gridDimensions;
thumbnailSize = stageFilmstripDimensions.thumbnailSize;
} else if (_verticalViewGrid) {
gridDimensions = gridView.gridDimensions;
thumbnailSize = gridView.thumbnailSize;
gridDimensions = gridView?.gridDimensions;
thumbnailSize = gridView?.thumbnailSize;
}
const { columns, rows } = gridDimensions;
const { columns = 1, rows = 1 } = gridDimensions ?? {};
const index = (rowIndex * columns) + columnIndex;
let horizontalOffset, thumbnailWidth;
const { iAmRecorder, disableTileEnlargement } = state['features/base/config'];
@@ -202,7 +203,7 @@ function _mapStateToProps(state, ownProps) {
const partialLastRowParticipantsNumber = participantsLength % columns;
if (partialLastRowParticipantsNumber > 0) {
const { width, height } = thumbnailSize;
const { width = 1, height = 1 } = thumbnailSize ?? {};
const availableWidth = columns * (width + TILE_HORIZONTAL_MARGIN);
let widthDifference = 0;
let widthToUse = width;

View File

@@ -1,3 +1,4 @@
import { Theme } from '@mui/material';
const BACKGROUND_COLOR = 'rgba(51, 51, 51, .5)';
@@ -7,19 +8,19 @@ const BACKGROUND_COLOR = 'rgba(51, 51, 51, .5)';
* @param {Object} theme - The current theme.
* @returns {Object}
*/
export const styles = theme => {
export const styles = (theme: Theme) => {
return {
toggleFilmstripContainer: {
display: 'flex',
flexWrap: 'nowrap',
flexWrap: 'nowrap' as const,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: BACKGROUND_COLOR,
width: '32px',
height: '24px',
position: 'absolute',
position: 'absolute' as const,
borderRadius: '4px',
top: 'calc(-24px - 3px)',
top: 'calc(-24px - 2px)',
left: 'calc(50% - 16px)',
opacity: 0,
transition: 'opacity .3s',
@@ -33,7 +34,7 @@ export const styles = theme => {
toggleFilmstripButton: {
fontSize: '14px',
lineHeight: 1.2,
textAlign: 'center',
textAlign: 'center' as const,
background: 'transparent',
height: 'auto',
width: '100%',
@@ -50,7 +51,7 @@ export const styles = theme => {
toggleVerticalFilmstripContainer: {
transform: 'rotate(-90deg)',
left: 'calc(-24px - 3px - 4px)',
left: 'calc(-24px - 2px - 4px)',
top: 'calc(50% - 12px)'
},
@@ -61,7 +62,7 @@ export const styles = theme => {
},
toggleTopPanelContainerHidden: {
visibility: 'hidden'
visibility: 'hidden' as const
},
filmstrip: {
@@ -83,7 +84,7 @@ export const styles = theme => {
},
'& .dragHandleContainer': {
visibility: 'visible'
visibility: 'visible' as const
}
},
@@ -112,8 +113,8 @@ export const styles = theme => {
resizableFilmstripContainer: {
display: 'flex',
position: 'relative',
flexDirection: 'row',
position: 'relative' as const,
flexDirection: 'row' as const,
alignItems: 'center',
height: '100%',
width: '100%',
@@ -133,12 +134,12 @@ export const styles = theme => {
height: '100%',
width: '9px',
backgroundColor: 'transparent',
position: 'relative',
position: 'relative' as const,
cursor: 'col-resize',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
visibility: 'hidden',
visibility: 'hidden' as const,
'&:hover': {
'& .dragHandle': {

Some files were not shown because too many files have changed in this diff Show More