Compare commits

...

81 Commits

Author SHA1 Message Date
Jaya Allamsetty
e35338b73d chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1631.0.0+f0dd4039...v1632.0.0+e4966db9
2023-05-09 15:31:28 -04:00
Gabriel Borlea
a112d38943 feat(prejoin) add unsafe room name warning 2023-05-09 20:04:58 +02:00
Horatiu Muresan
b705c63a65 fix(local-recording) Enable local rec for non-moderators (#13334) 2023-05-09 17:52:20 +03:00
Saúl Ibarra Corretgé
b4c8f7d097 feat(external-api) optional sandbox
Add optional "sandbox" option to the external API which will be applied
to the iframe.
2023-05-09 15:18:28 +02:00
Robert Pintilii
74bac9806f fix(virtual-background) Use correct video device (#13329)
In the case when the user selects a new video device then goes to Virtual Background without saving first, use the newly selected device for the virtual background preview instead of the saved one
2023-05-09 15:39:51 +03:00
Robert Pintilii
65248d7d29 chore(deps) Upgrade TS (#13331)
Upgrade typescript related packages
Fix new errors and warnings
2023-05-09 15:39:31 +03:00
Robert Pintilii
dc037bc8dd ref(TS) Convert some native components to TS (#13307) 2023-05-09 12:10:46 +03:00
Robert Pintilii
a22db037c7 ref(TS) Improve TS (#13282)
Remove unnecessary @ts-ignores
Use @ts-expect-error instead of @ts-ignore for external dependencies
2023-05-09 11:05:11 +03:00
Horatiu Muresan
44cc0f7e9a fix(toolbar-buttons) Hide rec and livestream buttons for non-moderators (#13328) 2023-05-08 19:17:01 +03:00
Calinteodor
eafb337cd1 feat(video-menu): native track volume control updates (#13305)
* feat(video-menu/native): added volume slider control for remote participants
2023-05-08 16:33:45 +03:00
damencho
9b3be66287 feat: Updates unsupported desktop to tsx.
Easier to apply branding.
2023-05-05 12:44:33 -05:00
Jaya Allamsetty
1a10a00f74 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1629.0.0+1714bf07...v1631.0.0+f0dd4039
2023-05-05 11:05:50 -04:00
George Politis
a196bc27b8 Update RTCStats.ts
Addresses an issue where the client is sending malformed stats messages to the server.

Introduced in 78ce68160a .
2023-05-05 11:30:04 +02:00
damencho
ac8e4d9828 fix: Fixes notifying vnodes to destroy rooms.
It may happen we receive the disconnect iq after the main room is already destroyed. We now send disconnect on destroy to all vnodes or when receiving disconnect iq per vnode.
2023-05-04 15:10:02 -05:00
damencho
a6ade336b7 fix: Fix measure messages.
This just counts messages and should not block processing messages. Breaks visitor messages coming from s2s and no session params are available.
2023-05-04 15:09:52 -05:00
Hristo Terezov
350443ad34 fix(large-video): Attempt to fix jumping.
When the toolbox is hidden and due to a ReactFocusLock instance the
focus is returned to the toolbox the whole page scrolls to the toolbox
which is positioned outside of the viewport in the bottom.
Then when the animation for displaying the toolbox is started the
scenario looks like the large video is jumping.
Now we don't return the focus from ReactFocusLock to elements which are
not part of the viewport.
2023-05-03 17:31:54 -05:00
Jaya Allamsetty
4c37ef7a2c ref(conference) Simplify track creation. (#13209)
* ref(conference) Simplify track creation.
If gUM fails, we do not have to retry gUM with mic only and camera only constraints. gUM has come a long way and this is not needed anymore.

* ref(conference) Filter tracks that are added to conference.

* squash: Address review comments

* fix(prejoin): Display the exact gUM error in prejoin.

* squash: Address review comments
2023-05-03 18:16:48 -04:00
damencho
3eedc2a49d fix: Restore old config for promoted visitors.
In case a visitor is promoted to main room and want to join an empty breakout room we want to send conference iq to jicofo.
2023-05-03 11:04:40 -05:00
FIKRAT HUSEYNKHANOV
aaeb1a90e5 feat: add toggleWhiteboard to Jitsi API (#13292)
* add toggleWhiteboard to Jitsi API

* eslint recommendations applied

* Prevent to send whiteboard status change notifications for mobile

* Fix code style errors (eslint)

* Requested changes (by mihhu) have been made.

---------

Co-authored-by: Fikret Huseynkhanov <fikret.huseynkhanov@simbrella.com>
2023-05-03 09:52:44 -05:00
Saúl Ibarra Corretgé
ed89f9af20 feat(android) add support for Hearing Aid devices 2023-05-03 09:09:10 +02:00
Saúl Ibarra Corretgé
863ad0b0e6 fix(ios) bump WebRTC version to fix crash
Fix a crash in Metal rendering: 0c9cc42025
2023-05-02 23:12:56 +02:00
Дамян Минков
e2d701a8cc feat: Audio output settings in visitor mode. (#13315)
* feat: Audio output settings in visitor mode.

* squash: Fix lint errors.
2023-05-02 16:06:19 -05:00
damencho
2710273069 feat: Sets meeting id using the connect method. 2023-05-02 12:40:08 -05:00
damencho
07af18e284 fix: Handles disconnect coming from jicofo to destroy visitor rooms.
Drops destroy room for no main participants from vnode. In case of breakout rooms we can end up with nobody in the main room for some time, till they are back from the breakout rooms.
2023-05-02 12:40:08 -05:00
damencho
519e37f567 fix: Drops console warn for logger. 2023-05-02 12:40:08 -05:00
damencho
7cf61eb776 fix: Disables p2p for visitors as it doesn't make sense.
The usecase is breakout rooms when main room is empty, but then one of the participants come back.
2023-05-02 12:40:08 -05:00
Jaya Allamsetty
f81446909c chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1626.0.0+a41aa571...v1629.0.0+1714bf07
2023-05-02 10:01:10 -04:00
damencho
b4115593c0 fix: Fix xmldom version to be used. 2023-05-02 08:29:10 -05:00
Hristo Terezov
f8bd8b616e feat(reactions): New button for web. 2023-05-02 08:20:35 -05:00
Hristo Terezov
be55ccd6f4 fix(main-Toolbox): Display the correct buttons.
If some of the buttons from the main toolbar are disabled we were
displaying buttons from the overflow menu in their place.
2023-05-02 08:20:35 -05:00
Horatiu Muresan
e7db18bd80 fix(dial-in) Place PIN on a new line (#13309) 2023-05-02 16:02:51 +03:00
Robert Pintilii
dff41e0fcb fix(chat) Fix horizontal scroll (#13308) 2023-05-02 15:53:30 +03:00
damencho
43be4324af fix: Fix room locking without visitors. 2023-05-02 06:25:37 -05:00
Saúl Ibarra Corretgé
c33baf4c96 fix(ios) avoid rejecting builds in progress in TestFlight 2023-05-02 10:21:30 +02:00
Saúl Ibarra Corretgé
f95a356025 feat(android) bump minimum API level to 24
Some of our dependencies (most notably WebRTC) have dropped it and we
can no longer claim to support API level 23).
2023-05-02 10:19:19 +02:00
Robert Pintilii
1ba7765898 ref(TS) Convert some native components to TS (#13281)
Remove some @ts-ignores
2023-05-02 11:09:38 +03:00
Robert Pintilii
0346fca434 fix(checkbox) Fix misalign when label has multiple lines (#13304) 2023-05-02 10:23:04 +03:00
Robert Pintilii
d267b2499d fix(chat) Fix name overflows chat bubble (#13303)
Revert color change of scroll corner
2023-05-02 10:22:49 +03:00
Дамян Минков
e3e5f1fbfa feat(visitors): Handles locked rooms for visitors. (#13296)
* feat(visitors): Handles locked rooms for visitors.

* squash: Handle locked room password on promotion.

* squash: quotes.

* squash: Renames main_domain to local_domain.

* squash: Renames fmuc_main_domain to main_domain.

Adds required config to point to the main virtual host of the main prosody. There are cases when the first visitor tries to join and there are not main participants as they are in the queue waiting for the vnode connect message and we cannot get dynamically the main domain.

* squash: Fix check for main_domain config.
2023-05-01 17:16:16 -05:00
robertpin
4697192b43 fix(keyboard-a11y) Remove space from click trigger 2023-05-01 16:50:23 +02:00
damencho
38a293f8f6 fix(chat): Fixes long display name that overflow the message bubble. 2023-04-28 13:31:14 -05:00
damencho
13e8f992b5 fix(chat): White square when both scrolls are visible. 2023-04-28 13:31:14 -05:00
damencho
c384d0d3a9 Revert "fix(chat) Make the name fit the chat bubble"
This reverts commit e56c7070c2.
2023-04-28 13:31:14 -05:00
Дамян Минков
2b71fa512b feat: Adds conference duration to the amplitude stat. (#13294) 2023-04-28 11:09:13 -05:00
damencho
d381ceb040 feat: Shows html in notification warning. 2023-04-27 12:42:28 -05:00
damencho
e18c428f52 fix: Hide virtual background for unsupported browsers from vide preview. 2023-04-27 12:42:12 -05:00
Gabriel Borlea
9fc32dc59b fix: multiselect for invite people (#13287)
* fix: multiselect duplicates

* set multiselect height to 200px
2023-04-27 10:14:16 -05:00
robertpin
6f45622ef1 fix(dialog) Fix close animation moves whole body 2023-04-27 10:06:17 -05:00
robertpin
e56c7070c2 fix(chat) Make the name fit the chat bubble 2023-04-27 09:40:27 -05:00
damencho
0aef7a36aa fix: Fixes unresolved function. 2023-04-27 09:25:07 -05:00
damencho
c030cf941e feat: Implements amplitude events for messages count. 2023-04-27 09:24:59 -05:00
Robert Pintilii
f6760e4ac7 fix(chat) Focus input on chat open (#13285) 2023-04-27 17:23:47 +03:00
Robert Pintilii
9060c77307 ref(TS) Convert some native components to TS (#13266) 2023-04-27 08:44:20 +03:00
Дамян Минков
a1d018eef4 feat: Disables sending localstats in visitor mode. (#13279) 2023-04-27 07:38:57 +02:00
Jaya Allamsetty
3f724d8fb7 fix(visitors) Do not add tracks in redux to conference. 2023-04-26 16:51:19 -04:00
Jaya Allamsetty
49d69a5a02 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1623.0.0+c520877a...v1624.0.0+e3a8472f
2023-04-26 13:04:01 -04:00
damencho
6db9e42876 fix: Allows jicofo entering rooms without requiring a password.
The case where the main room is locked and everyone leaves it to a breakout room and then coming back allows jicofo entering without a password.
2023-04-26 09:04:55 -05:00
Jaya Allamsetty
ad3e8f9f53 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1620.0.0+7f0012f7...v1623.0.0+c520877a
2023-04-26 09:26:34 -04:00
Mihaela Dumitru
9f39caa247 feat(external-api) support assumed bandwidth bps config and command (#13164) 2023-04-26 15:32:53 +03:00
Avram Tudor
1402a63324 ref(keyboard-shortcuts) refactor keyboard shortcuts to use redux (#13260)
* ref(keyboard-shortcuts) refactor keyboard shortcuts to use redux

fix unsynced default value between config flag and local storage

* code review

* fix build
2023-04-26 11:21:42 +03:00
robertpin
a9863e65c3 fix(dial-in) Make text selectable on Dial In page 2023-04-25 19:41:27 -05:00
Robert Pintilii
646c58f7d1 ref(TS) Convert some native components to TS (#13264) 2023-04-25 13:50:52 +03:00
Дамян Минков
a78ea7ca9c fix: Updates the option for disabling iframe to show a warning. (#13263)
* fix: Updates the option for disabling iframe to show a warning.

It will give a timeout of 5 mins for the conference, before navigating away from it.

* squash: Fix lint error.

* squash: Fix mobile build.
2023-04-24 14:59:25 -05:00
Robert Pintilii
8b8565bf60 ref(TS) Convert some native components to TS (#13259) 2023-04-24 20:14:02 +03:00
Saúl Ibarra Corretgé
b9e30f3c1b ref(android) remove unused code
This basically reverts
e61ccc956f
since we are no longer interested in using Detox.

In addition, the WebRTC initialization code was only placed in the RAN
instance manager holder's App initialization path, which is now gone, so
add it to the Activity initialization path.
2023-04-24 14:08:50 +02:00
Robert Pintilii
96b6edccf8 ref(TS) Remove flow comments in TS files (#13258) 2023-04-24 14:49:56 +03:00
Robert Pintilii
2af9dc88e6 ref|(TS) Convert some native components to TS (#13239) 2023-04-24 14:09:50 +03:00
Robert Pintilii
eda25ca3c9 fix(toolbar) Remove focus on hide (#13256) 2023-04-24 14:07:42 +03:00
Amga
c99da17973 fix(lang) update Mongolian translation 2023-04-24 11:58:07 +02:00
Saúl Ibarra Corretgé
9e147d7842 fix(android) fix JitsiMeetActivity.onDestroy not leaving the room
When we refactored the external API to use broadcast actions leave() was
changes to use the hangup broadcast action.

This mechanism does not seem to work while onDestroy is getting
executed, however.

There is another way to accomplish the same, for the particular case of
hangup: to pass empty props to the running RN application. This was the
previous behavior too.

This PR introduces a new abort() method on JitsiMeetView, which does
exactly that, passes empty props to RN. This allows cleanup to happen
and the meeting properly ends when the activity is swipped from the
recents list.

Fixes: https://github.com/jitsi/jitsi-meet/issues/13175
2023-04-24 10:14:06 +02:00
Jaya Allamsetty
d7afaf871f fix(visitor): Do not add media tracks in visitor mode.
When gUM resolves after the user has joined as a visitor, skip adding the local tracks to the conference.
2023-04-21 15:25:21 -04:00
Calin-Teodor
c4f6d37aa1 feat(conference): fixed raisedhandcountlabel and filmstrip conflict 2023-04-21 15:58:51 +03:00
Calinteodor
a5663872d9 feat(invite/native): add people functionality fixes (#13240)
feat(invite/native): add people functionality fixes
2023-04-21 14:13:25 +03:00
Robert Pintilii
007283aab3 chore(deps) Cleanup (#13246)
Remove @atlaskit and styled-components
Upgrade @emotion and @mui packages
Move @types packages to devDeps
2023-04-21 10:11:56 +03:00
Saúl Ibarra Corretgé
3b612376f2 chore(deps,giphy) update @giphy/react-components (#13243)
Also update the patches to match the new package versions.
2023-04-21 09:31:50 +03:00
Amga
1a312e2140 lang: update translation for mongolian language (#13237) 2023-04-20 22:46:15 -05:00
Saúl Ibarra Corretgé
6f5d0400b8 fix(deps) override xmldom dependency from strophe.js
lib-jitsi-meet does not bundle xmldom anyway, and we are providing it
here. strophe seems to be stuck in a slightly old version which creates
spurious security warnings.
2023-04-20 19:13:43 +02:00
Gabriel Borlea
aec86cecc0 ref(invite): add people form (#13207) 2023-04-20 14:00:42 +03:00
Robert Pintilii
bf1dde7cd1 ref(TS) Convert some files to TS (#13223) 2023-04-20 12:06:45 +03:00
Calin-Teodor
91e9005f08 feat(base/config): commented out mobile codecs override 2023-04-20 11:49:26 +03:00
Дамян Минков
57f9ea2865 feat: Adds an option to disable iframeAPI. (#13235)
* feat: Adds an option to disable iframeAPI.

* squash: Use utility.
2023-04-19 16:56:32 -05:00
606 changed files with 7543 additions and 7566 deletions

3
.npmrc
View File

@@ -1,6 +1,3 @@
package-lock=true
; FIXME Set legacy-peer-deps=false when we upgrade RN.
legacy-peer-deps=true
; Omit optional dependencies
omit=optional

View File

@@ -7,7 +7,6 @@
android:extractNativeLibs="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:name=".MainApplication"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/AppTheme">
<meta-data

View File

@@ -1,47 +0,0 @@
/*
* Copyright @ 2022-present 8x8, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet;
import android.app.Application;
import android.util.Log;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import org.jitsi.meet.sdk.JitsiReactNativeHost;
/**
* Application class for Jitsi Meet. The only reason why this exists is for Detox
* to believe our app is a "greenfield" app. SDK users need not use this.
*/
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new JitsiReactNativeHost(this);
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
// Initialize RN
Log.d(this.getClass().getCanonicalName(), "app onCreate");
getReactNativeHost().getReactInstanceManager();
}
}

View File

@@ -19,7 +19,7 @@ buildscript {
ext {
buildToolsVersion = "31.0.0"
compileSdkVersion = 32
minSdkVersion = 23
minSdkVersion = 24
targetSdkVersion = 32
supportLibVersion = "28.0.0"

View File

@@ -45,6 +45,12 @@ class AudioDeviceHandlerGeneric implements
*/
private AudioModeModule module;
/**
* Constant defining a Hearing Aid. Only available on API level >= 28.
* The value of: AudioDeviceInfo.TYPE_HEARING_AID
*/
private static final int TYPE_HEARING_AID = 23;
/**
* Constant defining a USB headset. Only available on API level >= 26.
* The value of: AudioDeviceInfo.TYPE_USB_HEADSET
@@ -85,6 +91,7 @@ class AudioDeviceHandlerGeneric implements
break;
case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
case AudioDeviceInfo.TYPE_WIRED_HEADSET:
case TYPE_HEARING_AID:
case TYPE_USB_HEADSET:
devices.add(AudioModeModule.DEVICE_HEADPHONES);
break;

View File

@@ -16,6 +16,7 @@
package org.jitsi.meet.sdk;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -177,8 +178,11 @@ public class JitsiMeetActivity extends AppCompatActivity
}
protected void leave() {
Intent hangupBroadcastIntent = BroadcastIntentHelper.buildHangUpIntent();
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(hangupBroadcastIntent);
if (this.jitsiView != null) {
this.jitsiView.abort();
} else {
JitsiMeetLogger.w("Cannot leave, view is null");
}
}
private @Nullable
@@ -295,6 +299,7 @@ public class JitsiMeetActivity extends AppCompatActivity
JitsiMeetActivityDelegate.requestPermissions(this, permissions, requestCode, listener);
}
@SuppressLint("MissingSuperCall")
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
JitsiMeetActivityDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults);

View File

@@ -157,6 +157,14 @@ public class JitsiMeetView extends FrameLayout {
setProps(options != null ? options.asProps() : new Bundle());
}
/**
* Internal method which aborts running RN by passing empty props.
* This is only meant to be used from the enclosing Activity's onDestroy.
*/
public void abort() {
setProps(new Bundle());
}
/**
* Creates the {@code ReactRootView} for the given app name with the given
* props. Once created it's set as the view of this {@code FrameLayout}.

View File

@@ -1,41 +0,0 @@
package org.jitsi.meet.sdk;
import android.app.Application;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import java.util.List;
/**
* This is the minimal implementation of ReactNativeHost that will make things like the
* Detox testing framework believe we are a "greenfield" app.
*
* Generally speaking, apps using the SDK (other than the Jitsi Meet app itself) should not
* need to use this because the
*/
public class JitsiReactNativeHost extends ReactNativeHost {
public JitsiReactNativeHost(Application application) {
super(application);
}
@Override
public boolean getUseDeveloperSupport() {
// Unused since we override `createReactInstanceManager`.
return false;
}
@Override
protected List<ReactPackage> getPackages() {
// Unused since we override `createReactInstanceManager`.
return null;
}
@Override
protected ReactInstanceManager createReactInstanceManager() {
ReactInstanceManagerHolder.initReactInstanceManager(this.getApplication());
return ReactInstanceManagerHolder.getReactInstanceManager();
}
}

View File

@@ -17,7 +17,6 @@
package org.jitsi.meet.sdk;
import android.app.Activity;
import android.app.Application;
import android.util.Log;
import androidx.annotation.Nullable;
@@ -227,11 +226,9 @@ class ReactInstanceManagerHolder {
* time. All {@code ReactRootView} instances will be tied to the one and
* only {@code ReactInstanceManager}.
*
* This method is only meant to be called when integrating with {@code JitsiReactNativeHost}.
*
* @param app {@code Application} current running Application.
* @param activity {@code Activity} current running Activity.
*/
static void initReactInstanceManager(Application app) {
static void initReactInstanceManager(Activity activity) {
if (reactInstanceManager != null) {
return;
}
@@ -244,34 +241,7 @@ class ReactInstanceManagerHolder {
options.videoDecoderFactory = new H264AndSoftwareVideoDecoderFactory(eglContext);
options.videoEncoderFactory = new H264AndSoftwareVideoEncoderFactory(eglContext);
Log.d(TAG, "initializing RN with Application");
reactInstanceManager
= ReactInstanceManager.builder()
.setApplication(app)
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index.android")
.setJavaScriptExecutorFactory(getReactNativeJSFactory())
.addPackages(getReactNativePackages())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE)
.build();
}
/**
* Internal method to initialize the React Native instance manager. We
* create a single instance in order to load the JavaScript bundle a single
* time. All {@code ReactRootView} instances will be tied to the one and
* only {@code ReactInstanceManager}.
*
* @param activity {@code Activity} current running Activity.
*/
static void initReactInstanceManager(Activity activity) {
if (reactInstanceManager != null) {
return;
}
Log.d(ReactInstanceManagerHolder.class.getCanonicalName(), "initializing RN with Activity");
Log.d(TAG, "initializing RN with Activity");
reactInstanceManager
= ReactInstanceManager.builder()

2
app.js
View File

@@ -18,7 +18,6 @@ import './react/features/base/jitsi-local-storage/setup';
import conference from './conference';
import API from './modules/API';
import UI from './modules/UI/UI';
import keyboardshortcut from './modules/keyboardshortcut/keyboardshortcut';
import translation from './modules/translation/translation';
// Initialize Olm as early as possible.
@@ -38,7 +37,6 @@ window.APP = {
'index.loaded': window.indexLoadedTime
},
keyboardshortcut,
translation,
UI
};

View File

@@ -140,6 +140,7 @@ import { downloadJSON } from './react/features/base/util/downloadJSON';
import { showDesktopPicker } from './react/features/desktop-picker/actions';
import { appendSuffix } from './react/features/display-name/functions';
import { maybeOpenFeedbackDialog, submitFeedback } from './react/features/feedback/actions';
import { initKeyboardShortcuts } from './react/features/keyboard-shortcuts/actions';
import { maybeSetLobbyChatMessageListener } from './react/features/lobby/actions.any';
import { setNoiseSuppressionEnabled } from './react/features/noise-suppression/actions';
import { hideNotification, showNotification, showWarningNotification } from './react/features/notifications/actions';
@@ -162,6 +163,7 @@ import { endpointMessageReceived } from './react/features/subtitles/actions.any'
import { handleToggleVideoMuted } from './react/features/toolbox/actions.any';
import { muteLocal } from './react/features/video-menu/actions.any';
import { setIAmVisitor } from './react/features/visitors/actions';
import { iAmVisitor } from './react/features/visitors/functions';
import UIEvents from './service/UI/UIEvents';
const logger = Logger.getLogger(__filename);
@@ -557,7 +559,7 @@ export default {
);
}
let tryCreateLocalTracks;
let tryCreateLocalTracks = Promise.resolve([]);
// On Electron there is no permission prompt for granting permissions. That's why we don't need to
// spend much time displaying the overlay screen. If GUM is not resolved within 15 seconds it will
@@ -598,76 +600,65 @@ export default {
return [];
});
} else if (!requestedAudio && !requestedVideo) {
// Resolve with no tracks
tryCreateLocalTracks = Promise.resolve([]);
} else {
} else if (requestedAudio || requestedVideo) {
tryCreateLocalTracks = createLocalTracksF({
devices: initialDevices,
timeout,
firePermissionPromptIsShownEvent: true
})
.catch(err => {
if (requestedAudio && requestedVideo) {
// Try audio only...
errors.audioAndVideoError = err;
if (err.name === JitsiTrackErrors.TIMEOUT && !browser.isElectron()) {
// In this case we expect that the permission prompt is still visible. There is no point of
// executing GUM with different source. Also at the time of writing the following
// inconsistency have been noticed in some browsers - if the permissions prompt is visible
// and another GUM is executed the prompt does not change its content but if the user
// clicks allow the user action isassociated with the latest GUM call.
errors.audioOnlyError = err;
errors.videoOnlyError = err;
return [];
}
return createLocalTracksF(audioOptions);
} else if (requestedAudio && !requestedVideo) {
errors.audioOnlyError = err;
return [];
} else if (requestedVideo && !requestedAudio) {
errors.videoOnlyError = err;
return [];
}
logger.error('Should never happen');
})
.catch(err => {
// Log this just in case...
if (!requestedAudio) {
logger.error('The impossible just happened', err);
}
errors.audioOnlyError = err;
// Try video only...
return requestedVideo
? createLocalTracksF({
devices: [ MEDIA_TYPE.VIDEO ],
firePermissionPromptIsShownEvent: true
})
: [];
})
.catch(err => {
// Log this just in case...
if (!requestedVideo) {
logger.error('The impossible just happened', err);
}
errors.videoOnlyError = err;
.catch(async error => {
if (error.name === JitsiTrackErrors.TIMEOUT && !browser.isElectron()) {
errors.audioAndVideoError = error;
return [];
}
// Retry with separate gUM calls.
const gUMPromises = [];
const tracks = [];
if (requestedAudio) {
gUMPromises.push(createLocalTracksF(audioOptions));
}
if (requestedVideo) {
gUMPromises.push(createLocalTracksF({
devices: [ MEDIA_TYPE.VIDEO ],
timeout,
firePermissionPromptIsShownEvent: true
}));
}
const results = await Promise.allSettled(gUMPromises);
let errorMsg;
results.forEach((result, idx) => {
if (result.status === 'fulfilled') {
tracks.push(result.value[0]);
} else {
errorMsg = result.reason;
const isAudio = idx === 0;
logger.error(`${isAudio ? 'Audio' : 'Video'} track creation failed with error ${errorMsg}`);
if (isAudio) {
errors.audioOnlyError = errorMsg;
} else {
errors.videoOnlyError = errorMsg;
}
}
});
if (errors.audioOnlyError && errors.videoOnlyError) {
errors.audioAndVideoError = errorMsg;
}
return tracks;
});
}
// Hide the permissions prompt/overlay as soon as the tracks are
// created. Don't wait for the connection to be made, since in some
// cases, when auth is required, for instance, that won't happen until
// the user inputs their credentials, but the dialog would be
// overshadowed by the overlay.
// Hide the permissions prompt/overlay as soon as the tracks are created. Don't wait for the connection to
// be established, as in some cases like when auth is required, connection won't be established until the user
// inputs their credentials, but the dialog would be overshadowed by the overlay.
tryCreateLocalTracks.then(tracks => {
APP.store.dispatch(mediaPermissionPromptVisibilityChanged(false));
@@ -804,46 +795,55 @@ export default {
* @returns {Promise}
*/
async init({ roomName }) {
const state = APP.store.getState();
const initialOptions = {
startAudioOnly: config.startAudioOnly,
startScreenSharing: config.startScreenSharing,
startWithAudioMuted: getStartWithAudioMuted(APP.store.getState())
|| isUserInteractionRequiredForUnmute(APP.store.getState()),
startWithVideoMuted: getStartWithVideoMuted(APP.store.getState())
|| isUserInteractionRequiredForUnmute(APP.store.getState())
startWithAudioMuted: getStartWithAudioMuted(state) || isUserInteractionRequiredForUnmute(state),
startWithVideoMuted: getStartWithVideoMuted(state) || isUserInteractionRequiredForUnmute(state)
};
this.roomName = roomName;
try {
// Initialize the device list first. This way, when creating tracks
// based on preferred devices, loose label matching can be done in
// cases where the exact ID match is no longer available, such as
// when the camera device has switched USB ports.
// when in startSilent mode we want to start with audio muted
// Initialize the device list first. This way, when creating tracks based on preferred devices, loose label
// matching can be done in cases where the exact ID match is no longer available, such as -
// 1. When the camera device has switched USB ports.
// 2. When in startSilent mode we want to start with audio muted
await this._initDeviceList();
} catch (error) {
logger.warn('initial device list initialization failed', error);
}
const handleStartAudioMuted = (options, tracks) => {
if (options.startWithAudioMuted) {
// Filter out the local tracks based on various config options, i.e., when user joins muted or is muted by
// focus. However, audio track will always be created even though it is not added to the conference since we
// want audio related features (noisy mic, talk while muted, etc.) to work even if the mic is muted.
const handleInitialTracks = (options, tracks) => {
let localTracks = tracks;
// No local tracks are added when user joins as a visitor.
if (iAmVisitor(state)) {
return [];
}
if (options.startWithAudioMuted || room?.isStartAudioMuted()) {
// Always add the track on Safari because of a known issue where audio playout doesn't happen
// if the user joins audio and video muted, i.e., if there is no local media capture.
if (browser.isWebKitBased()) {
this.muteAudio(true, true);
} else {
return tracks.filter(track => track.getType() !== MEDIA_TYPE.AUDIO);
localTracks = localTracks.filter(track => track.getType() !== MEDIA_TYPE.AUDIO);
}
}
if (room?.isStartVideoMuted()) {
localTracks = localTracks.filter(track => track.getType() !== MEDIA_TYPE.VIDEO);
}
return tracks;
return localTracks;
};
if (isPrejoinPageVisible(APP.store.getState())) {
if (isPrejoinPageVisible(state)) {
_connectionPromise = connect(roomName).then(c => {
// we want to initialize it early, in case of errors to be able
// to gather logs
// We want to initialize it early, in case of errors to be able to gather logs.
APP.connection = c;
return c;
@@ -856,43 +856,28 @@ export default {
APP.store.dispatch(makePrecallTest(this._getConferenceOptions()));
const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(initialOptions);
const tracks = await tryCreateLocalTracks;
const localTracks = await tryCreateLocalTracks;
// Initialize device list a second time to ensure device labels
// get populated in case of an initial gUM acceptance; otherwise
// they may remain as empty strings.
// Initialize device list a second time to ensure device labels get populated in case of an initial gUM
// acceptance; otherwise they may remain as empty strings.
this._initDeviceList(true);
if (isPrejoinPageVisible(APP.store.getState())) {
return APP.store.dispatch(initPrejoin(tracks, errors));
if (isPrejoinPageVisible(state)) {
return APP.store.dispatch(initPrejoin(localTracks, errors));
}
logger.debug('Prejoin screen no longer displayed at the time when tracks were created');
this._displayErrorsForCreateInitialLocalTracks(errors);
let localTracks = handleStartAudioMuted(initialOptions, tracks);
// in case where gum is slow and resolves after the startAudio/VideoMuted coming from jicofo, we can be
// join unmuted even though jicofo had instruct us to mute, so let's respect that before passing the tracks
if (!browser.isWebKitBased()) {
if (room?.isStartAudioMuted()) {
localTracks = localTracks.filter(track => track.getType() !== MEDIA_TYPE.AUDIO);
}
}
if (room?.isStartVideoMuted()) {
localTracks = localTracks.filter(track => track.getType() !== MEDIA_TYPE.VIDEO);
}
return this._setLocalAudioVideoStreams(localTracks);
return this._setLocalAudioVideoStreams(handleInitialTracks(initialOptions, localTracks));
}
const [ tracks, con ] = await this.createInitialLocalTracksAndConnect(roomName, initialOptions);
this._initDeviceList(true);
return this.startConference(con, handleStartAudioMuted(initialOptions, tracks));
return this.startConference(con, handleInitialTracks(initialOptions, tracks));
},
/**
@@ -1065,7 +1050,7 @@ export default {
*/
muteVideo(mute, showUI = true) {
if (this.videoSwitchInProgress) {
console.warn('muteVideo - unable to perform operations while video switch is in progress');
logger.warn('muteVideo - unable to perform operations while video switch is in progress');
return;
}
@@ -2301,10 +2286,7 @@ export default {
APP.UI.initConference();
if (!config.disableShortcuts) {
APP.keyboardshortcut.init();
}
dispatch(initKeyboardShortcuts());
dispatch(conferenceJoined(room));
const jwt = APP.store.getState()['features/base/jwt'];

View File

@@ -1406,6 +1406,7 @@ var config = {
disableAGC
disableAP
disableHPF
disableLocalStats
disableNS
enableTalkWhileMuted
forceJVB121Ratio

View File

@@ -108,6 +108,10 @@
#largeVideoContainer {
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
margin: 0 !important;
}
#largeVideoWrapper {

View File

@@ -60,7 +60,6 @@ $flagsImagePath: "../images/";
@import 'filmstrip/vertical_filmstrip';
@import 'filmstrip/vertical_filmstrip_overrides';
@import 'unsupported-browser/main';
@import 'modals/invite/add-people';
@import 'deep-linking/main';
@import 'transcription-subtitles';
@import '_meetings_list.scss';

View File

@@ -12,24 +12,6 @@
}
}
/**
* Styling inline dialog errors.
*/
.inline-dialog-error {
margin-top: 16px;
&-text {
color: $dialogErrorText;
margin-bottom: 8px;
text-align: center;
}
&-button {
display: block;
margin: 16px auto 0 auto;
}
}
/**
* Styling shared video dialog errors.
*/

View File

@@ -41,10 +41,3 @@
}
}
}
/**
* Styles errors in the MultiSelectAutocomplete.
*/
.autocomplete-error {
min-width: 260px;
}

View File

@@ -57,6 +57,10 @@
line-height: 24px;
border-collapse: collapse;
* {
user-select: text;
}
thead {
text-align: left;
}

View File

@@ -1,57 +1,4 @@
.invite-more {
&-container {
margin-bottom: 8px;
transition: margin-bottom 0.3s;
&.elevated {
margin-bottom: 36px;
}
}
&-content {
display: flex;
flex-direction: column;
align-items: center;
padding: 16px;
background: rgba(0, 0, 0, 0.7);
border-radius: 8px;
color: #fff;
font-size: 14px;
line-height: 24px;
font-weight: 600;
}
&-header {
max-width: 100%;
margin-bottom: 16px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
&-button {
display: flex;
max-width: 100%;
height: 40px;
box-sizing: border-box;
padding: 8px 16px;
background: #0376DA;
border-radius: 3px;
cursor: pointer;
@media (hover: hover) and (pointer: fine) {
&:hover {
background: #278ADF;
}
}
&-text {
margin-left: 8px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
&-dialog {
color: #fff;
font-size: 15px;
@@ -65,59 +12,6 @@
background: #5E6D7A;
}
&.email-container {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 8px 8px 16px;
margin-top: 24px;
width: calc(100% - 26px);
height: 22px;
background: #2A3A4B;
border: 1px solid #5E6D7A;
border-radius: 3px;
cursor: pointer;
&.active {
border-radius: 3px 3px 0 0;
}
}
&.invite-buttons {
width: 100%;
text-align: right;
margin-top: 8px;
& > a {
display: inline-block;
height: 24px;
min-width: 48px;
border-radius: 3px;
text-align: center;
text-decoration: none;
cursor: pointer;
}
&-cancel {
margin-right: 16px;
padding: 7px 15px;
background: #2A3A4B;
border: 1px solid #5E6D7A;
}
&-add {
padding: 8px 16px;
background: #0376DA;
}
&.disabled {
& > a {
pointer-events: none;
}
}
}
&.stream {
display: flex;
justify-content: space-between;
@@ -158,14 +52,3 @@
}
}
}
.mobile-browser {
.invite-more-content {
font-size: 16px;
}
.invite-more-button {
height: 48px;
padding: 12px 16px;
}
}

View File

@@ -84,8 +84,12 @@ Component "conference.jitmeet.example.com" "muc"
"polls";
--"token_verification";
"muc_rate_limit";
"muc_password_whitelist";
}
admins = { "focusUser@auth.jitmeet.example.com" }
muc_password_whitelist = {
"focusUser@auth.jitmeet.example.com"
}
muc_room_locking = false
muc_room_default_public_jids = true

6
globals.d.ts vendored
View File

@@ -10,12 +10,6 @@ declare global {
API: any;
conference: any;
debugLogs: any;
keyboardshortcut: {
registerShortcut: Function;
unregisterShortcut: Function;
openDialog: Function;
enable: Function;
}
};
const interfaceConfig: any;

View File

@@ -134,7 +134,7 @@ PODS:
- AppAuth/Core (~> 1.6)
- GTMSessionFetcher/Core (< 3.0, >= 1.5)
- GTMSessionFetcher/Core (2.3.0)
- JitsiWebRTC (111.0.1)
- JitsiWebRTC (111.0.2)
- libwebp (1.2.4):
- libwebp/demux (= 1.2.4)
- libwebp/mux (= 1.2.4)
@@ -725,7 +725,7 @@ SPEC CHECKSUMS:
GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749
GTMAppAuth: 0ff230db599948a9ad7470ca667337803b3fc4dd
GTMSessionFetcher: 3a63d75eecd6aa32c2fc79f578064e1214dfdec2
JitsiWebRTC: 9619c1f71cc16eeca76df68aa2d213c6d63274a8
JitsiWebRTC: 80f62908fcf2a1160e0d14b584323fb6e6be630b
libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
ObjectiveDropboxOfficial: fe206ce8c0bc49976c249d472db7fdbc53ebbd53

View File

@@ -98,7 +98,6 @@ platform :ios do
demo_account_required: false,
distribute_external: true,
groups: ENV["JITSI_BETA_TESTING_GROUPS"],
reject_build_waiting_for_review: true,
uses_non_exempt_encryption: false
)

File diff suppressed because it is too large Load Diff

View File

@@ -675,6 +675,7 @@
"connectedTwoMembers": "{{first}} and {{second}} joined the meeting",
"dataChannelClosed": "Video quality impaired",
"dataChannelClosedDescription": "The bridge channel has been disconnected and thus video quality is limited to its lowest setting.",
"disabledIframe": "Embedding is only meant for demo purposes, so this call will disconnect in {{timeout}} minutes.",
"disconnected": "disconnected",
"displayNotifications": "Display notifications for",
"dontRemindMe": "Do not remind me",
@@ -869,9 +870,11 @@
"lookGood": "Your microphone is working properly",
"or": "or",
"premeeting": "Pre meeting",
"proceedAnyway": "Proceed anyway",
"screenSharingError": "Screen sharing error:",
"showScreen": "Enable pre meeting screen",
"startWithPhone": "Start with phone audio",
"unsafeRoomConsent": "I understand the risks, I want to join the meeting",
"videoOnlyError": "Video error:",
"videoTrackError": "Could not create video track.",
"viewAllNumbers": "view all numbers"
@@ -973,8 +976,14 @@
"security": {
"about": "You can add a $t(lockRoomPassword) to your meeting. Participants will need to provide the $t(lockRoomPassword) before they are allowed to join the meeting.",
"aboutReadOnly": "Moderator participants can add a $t(lockRoomPassword) to the meeting. Participants will need to provide the $t(lockRoomPassword) before they are allowed to join the meeting.",
"insecureRoomNameWarning": "The room name is unsafe. Unwanted participants may join your conference. Consider securing your meeting using the security button.",
"title": "Security Options"
"insecureRoomNameWarningNative": "The room name is unsafe. Unwanted participants may join your meeting. {{recommendAction}} Learn more about securing you meeting ",
"insecureRoomNameWarningWeb": "The room name is unsafe. Unwanted participants may join your meeting. {{recommendAction}} Learn more about securing you meeting <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">here</a>.",
"title": "Security Options",
"unsafeRoomActions": {
"meeting": "Consider securing your meeting using the security button.",
"prejoin": "Consider using a more unique meeting name.",
"welcome": "Consider using a more unique meeting name, or pick one of the suggestions."
}
},
"settings": {
"audio": "Audio",
@@ -1149,6 +1158,7 @@
"privateMessage": "Send private message",
"profile": "Edit your profile",
"raiseHand": "Raise your hand",
"reactions": "Reactions",
"reactionsMenu": "Reactions menu",
"recording": "Toggle recording",
"remoteMute": "Mute participant",
@@ -1246,6 +1256,7 @@
"reactionLike": "Send thumbs up reaction",
"reactionSilence": "Send silence reaction",
"reactionSurprised": "Send surprised reaction",
"reactions": "Reactions",
"security": "Security options",
"selectBackground": "Select background",
"shareRoom": "Invite someone",

View File

@@ -113,9 +113,15 @@ import { isAudioMuteButtonDisabled } from '../../react/features/toolbox/function
import { setTileView, toggleTileView } from '../../react/features/video-layout/actions.any';
import { muteAllParticipants } from '../../react/features/video-menu/actions';
import { setVideoQuality } from '../../react/features/video-quality/actions';
import { toggleWhiteboard } from '../../react/features/whiteboard/actions.any';
import { WhiteboardStatus } from '../../react/features/whiteboard/types';
import { getJitsiMeetTransport } from '../transport';
import { API_ID, ENDPOINT_TEXT_MESSAGE_NAME } from './constants';
import {
API_ID,
ASSUMED_BANDWIDTH_BPS,
ENDPOINT_TEXT_MESSAGE_NAME
} from './constants';
const logger = Logger.getLogger(__filename);
@@ -310,6 +316,23 @@ function initCommands() {
APP.store.dispatch(sendTones(tones, duration, pause));
},
'set-assumed-bandwidth-bps': value => {
logger.debug('Set assumed bandwidth bps command received', value);
if (typeof value !== 'number' || isNaN(value)) {
logger.error('Assumed bandwidth bps must be a number.');
return;
}
const { conference } = APP.store.getState()['features/base/conference'];
if (conference) {
conference.setAssumedBandwidthBps(value < ASSUMED_BANDWIDTH_BPS
? ASSUMED_BANDWIDTH_BPS
: value);
}
},
'set-follow-me': value => {
logger.debug('Set follow me command received');
@@ -812,6 +835,9 @@ function initCommands() {
} else {
logger.error(' End Conference not supported');
}
},
'toggle-whiteboard': () => {
APP.store.dispatch(toggleWhiteboard());
}
};
transport.on('event', ({ data, name }) => {
@@ -1993,6 +2019,20 @@ class API {
});
}
/**
* Notify external application (if API is enabled) if whiteboard state is
* changed.
*
* @param {WhiteboardStatus} status - The new whiteboard status.
* @returns {void}
*/
notifyWhiteboardStatusChanged(status: WhiteboardStatus) {
this._sendEvent({
name: 'whiteboard-status-changed',
status
});
}
/**
* Disposes the allocated resources.
*

View File

@@ -15,3 +15,10 @@ export const API_ID = parseURLParams(window.location).jitsi_meet_external_api_id
* The payload name for the datachannel/endpoint text message event.
*/
export const ENDPOINT_TEXT_MESSAGE_NAME = 'endpoint-text-message';
/**
* The min value that can be set for the assumed bandwidth.
* Setting it to this value means not assuming any bandwidth,
* but rather allowing the estimations to take place.
*/
export const ASSUMED_BANDWIDTH_BPS = -1;

View File

@@ -59,6 +59,7 @@ const commands = {
sendEndpointTextMessage: 'send-endpoint-text-message',
sendParticipantToRoom: 'send-participant-to-room',
sendTones: 'send-tones',
setAssumedBandwidthBps: 'set-assumed-bandwidth-bps',
setFollowMe: 'set-follow-me',
setLargeVideoParticipant: 'set-large-video-participant',
setMediaEncryptionKey: 'set-media-encryption-key',
@@ -89,7 +90,8 @@ const commands = {
toggleSubtitles: 'toggle-subtitles',
toggleTileView: 'toggle-tile-view',
toggleVirtualBackgroundDialog: 'toggle-virtual-background',
toggleVideo: 'toggle-video'
toggleVideo: 'toggle-video',
toggleWhiteboard: 'toggle-whiteboard'
};
/**
@@ -153,7 +155,8 @@ const events = {
'subject-change': 'subjectChange',
'suspend-detected': 'suspendDetected',
'tile-view-changed': 'tileViewChanged',
'toolbar-button-clicked': 'toolbarButtonClicked'
'toolbar-button-clicked': 'toolbarButtonClicked',
'whiteboard-status-changed': 'whiteboardStatusChanged'
};
/**
@@ -313,6 +316,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
* @param {string} [options.e2eeKey] - The key used for End-to-End encryption.
* THIS IS EXPERIMENTAL.
* @param {string} [options.release] - The key used for specifying release if enabled on the backend.
* @param {string} [options.sandbox] - Sandbox directive for the created iframe, if desired.
*/
constructor(domain, ...args) {
super();
@@ -330,7 +334,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
devices,
userInfo,
e2eeKey,
release
release,
sandbox = ''
} = parseArguments(args);
const localStorageContent = jitsiLocalStorage.getItem('jitsiLocalStorage');
@@ -348,7 +353,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
},
release
});
this._createIFrame(height, width, onload);
this._createIFrame(height, width, onload, sandbox);
this._transport = new Transport({
backend: new PostMessageTransportBackend({
postisOptions: {
@@ -381,11 +386,12 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
* parseSizeParam for format details.
* @param {Function} onload - The function that will listen
* for onload event.
* @param {string} sandbox - Sandbox directive for the created iframe, if desired.
* @returns {void}
*
* @private
*/
_createIFrame(height, width, onload) {
_createIFrame(height, width, onload, sandbox) {
const frameName = `jitsiConferenceFrame${id}`;
this._frame = document.createElement('iframe');
@@ -396,6 +402,10 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
this._frame.setAttribute('allowFullScreen', 'true');
this._frame.style.border = 0;
if (sandbox) {
this._frame.sandbox = sandbox;
}
if (onload) {
// waits for iframe resources to load
// and fires event when it is done

View File

@@ -11,11 +11,11 @@ import { setColorAlpha } from '../../react/features/base/util/helpers';
import { setDocumentUrl } from '../../react/features/etherpad/actions';
import { setFilmstripVisible } from '../../react/features/filmstrip/actions.any';
import {
joinLeaveNotificationsDisabled,
setNotificationsEnabled,
showNotification
} from '../../react/features/notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../../react/features/notifications/constants';
import { joinLeaveNotificationsDisabled } from '../../react/features/notifications/functions';
import {
dockToolbox,
setToolboxEnabled,

View File

@@ -1,261 +0,0 @@
/* global APP */
import { jitsiLocalStorage } from '@jitsi/js-utils';
import Logger from '@jitsi/logger';
import {
ACTION_SHORTCUT_PRESSED as PRESSED,
ACTION_SHORTCUT_RELEASED as RELEASED,
createShortcutEvent
} from '../../react/features/analytics/AnalyticsEvents';
import { sendAnalytics } from '../../react/features/analytics/functions';
import { clickOnVideo } from '../../react/features/filmstrip/actions';
import { openSettingsDialog } from '../../react/features/settings/actions';
import { SETTINGS_TABS } from '../../react/features/settings/constants';
const logger = Logger.getLogger(__filename);
/**
* Map of shortcuts. When a shortcut is registered it enters the mapping.
* @type {Map}
*/
const _shortcuts = new Map();
/**
* Map of registered keyboard keys and translation keys describing the
* action performed by the key.
* @type {Map}
*/
const _shortcutsHelp = new Map();
/**
* The key used to save in local storage if keyboard shortcuts are enabled.
*/
const _enableShortcutsKey = 'enableShortcuts';
/**
* Prefer keyboard handling of these elements over global shortcuts.
* If a button is triggered using the Spacebar it should not trigger PTT.
* If an input element is focused and M is pressed it should not mute audio.
*/
const _elementsBlacklist = [
'input',
'textarea',
'button',
'[role=button]',
'[role=menuitem]',
'[role=radio]',
'[role=tab]',
'[role=option]',
'[role=switch]',
'[role=range]',
'[role=log]'
];
/**
* An element selector for elements that have their own keyboard handling.
*/
const _focusedElementsSelector = `:focus:is(${_elementsBlacklist.join(',')})`;
/**
* Maps keycode to character, id of popover for given function and function.
*/
const KeyboardShortcut = {
init() {
this._initGlobalShortcuts();
window.onkeyup = e => {
if (!this.getEnabled()) {
return;
}
const key = this._getKeyboardKey(e).toUpperCase();
const num = parseInt(key, 10);
if (!document.querySelector(_focusedElementsSelector)) {
if (_shortcuts.has(key)) {
_shortcuts.get(key).function(e);
} else if (!isNaN(num) && num >= 0 && num <= 9) {
APP.store.dispatch(clickOnVideo(num));
}
}
};
window.onkeydown = e => {
if (!this.getEnabled()) {
return;
}
const focusedElement = document.querySelector(_focusedElementsSelector);
if (!focusedElement) {
if (this._getKeyboardKey(e).toUpperCase() === ' ') {
if (APP.conference.isLocalAudioMuted()) {
sendAnalytics(createShortcutEvent(
'push.to.talk',
PRESSED));
logger.log('Talk shortcut pressed');
APP.conference.muteAudio(false);
}
}
} else if (this._getKeyboardKey(e).toUpperCase() === 'ESCAPE') {
// Allow to remove focus from selected elements using ESC key.
if (focusedElement && focusedElement.blur) {
focusedElement.blur();
}
}
};
},
/**
* Enables/Disables the keyboard shortcuts.
* @param {boolean} value - the new value.
*/
enable(value) {
jitsiLocalStorage.setItem(_enableShortcutsKey, value);
},
getEnabled() {
// Should be enabled if not explicitly set to false
// eslint-disable-next-line no-unneeded-ternary
return jitsiLocalStorage.getItem(_enableShortcutsKey) === 'false' ? false : true;
},
getShortcutsDescriptions() {
return _shortcutsHelp;
},
/**
* Opens the {@SettingsDialog} dialog on the Shortcuts page.
*
* @returns {void}
*/
openDialog() {
APP.store.dispatch(openSettingsDialog(SETTINGS_TABS.SHORTCUTS, false));
},
/**
* Registers a new shortcut.
*
* @param shortcutChar the shortcut character triggering the action
* @param shortcutAttr the "shortcut" html element attribute mapping an
* element to this shortcut and used to show the shortcut character on the
* element tooltip
* @param exec the function to be executed when the shortcut is pressed
* @param helpDescription the description of the shortcut that would appear
* in the help menu
* @param altKey whether or not the alt key must be pressed.
*/
registerShortcut(// eslint-disable-line max-params
shortcutChar,
shortcutAttr,
exec,
helpDescription,
altKey = false) {
_shortcuts.set(altKey ? `:${shortcutChar}` : shortcutChar, {
character: shortcutChar,
function: exec,
shortcutAttr,
altKey
});
if (helpDescription) {
this._addShortcutToHelp(altKey ? `:${shortcutChar}` : shortcutChar, helpDescription);
}
},
/**
* Unregisters a shortcut.
*
* @param shortcutChar unregisters the given shortcut, which means it will
* no longer be usable
* @param altKey whether or not shortcut is combo with alt key
*/
unregisterShortcut(shortcutChar, altKey = false) {
_shortcuts.delete(altKey ? `:${shortcutChar}` : shortcutChar);
_shortcutsHelp.delete(shortcutChar);
},
/**
* @param e a KeyboardEvent
* @returns {string} e.key or something close if not supported
*/
_getKeyboardKey(e) {
// If alt is pressed a different char can be returned so this takes
// the char from the code. It also prefixes with a colon to differentiate
// alt combo from simple keypress.
if (e.altKey) {
const key = e.code.replace('Key', '');
return `:${key}`;
}
// If e.key is a string, then it is assumed it already plainly states
// the key pressed. This may not be true in all cases, such as with Edge
// and "?", when the browser cannot properly map a key press event to a
// keyboard key. To be safe, when a key is "Unidentified" it must be
// further analyzed by jitsi to a key using e.which.
if (typeof e.key === 'string' && e.key !== 'Unidentified') {
return e.key;
}
if (e.type === 'keypress'
&& ((e.which >= 32 && e.which <= 126)
|| (e.which >= 160 && e.which <= 255))) {
return String.fromCharCode(e.which);
}
// try to fallback (0-9A-Za-z and QWERTY keyboard)
switch (e.which) {
case 27:
return 'Escape';
case 191:
return e.shiftKey ? '?' : '/';
}
if (e.shiftKey || e.type === 'keypress') {
return String.fromCharCode(e.which);
}
return String.fromCharCode(e.which).toLowerCase();
},
/**
* Adds the given shortcut to the help dialog.
*
* @param shortcutChar the shortcut character
* @param shortcutDescriptionKey the description of the shortcut
* @private
*/
_addShortcutToHelp(shortcutChar, shortcutDescriptionKey) {
_shortcutsHelp.set(shortcutChar, shortcutDescriptionKey);
},
/**
* Initialise global shortcuts.
* Global shortcuts are shortcuts for features that don't have a button or
* link associated with the action. In other words they represent actions
* triggered _only_ with a shortcut.
*/
_initGlobalShortcuts() {
this.registerShortcut('?', null, () => {
sendAnalytics(createShortcutEvent('help'));
this.openDialog();
}, 'keyboardShortcuts.toggleShortcuts');
// register SPACE shortcut in two steps to insure visibility of help
// message
this.registerShortcut(' ', null, () => {
sendAnalytics(createShortcutEvent('push.to.talk', RELEASED));
logger.log('Talk shortcut released');
APP.conference.muteAudio(true);
});
this._addShortcutToHelp('SPACE', 'keyboardShortcuts.pushToTalk');
/**
* FIXME: Currently focus keys are directly implemented below in
* onkeyup. They should be moved to the SmallVideo instead.
*/
this._addShortcutToHelp('0', 'keyboardShortcuts.focusLocal');
this._addShortcutToHelp('1-9', 'keyboardShortcuts.focusRemote');
}
};
export default KeyboardShortcut;

3662
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,14 +16,10 @@
"readmeFilename": "README.md",
"dependencies": {
"@amplitude/react-native": "2.7.0",
"@atlaskit/inline-dialog": "13.0.9",
"@atlaskit/inline-message": "11.0.8",
"@atlaskit/multi-select": "15.0.5",
"@atlaskit/theme": "11.0.2",
"@emotion/react": "11.10.0",
"@emotion/styled": "11.10.0",
"@emotion/react": "11.10.6",
"@emotion/styled": "11.10.6",
"@giphy/js-fetch-api": "4.7.1",
"@giphy/react-components": "5.6.0",
"@giphy/react-components": "6.8.1",
"@giphy/react-native-sdk": "1.7.0",
"@hapi/bourne": "2.0.0",
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.12/jitsi-excalidraw-0.0.12.tgz",
@@ -33,8 +29,8 @@
"@jitsi/rtcstats": "9.5.1",
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
"@microsoft/microsoft-graph-client": "3.0.1",
"@mui/material": "5.10.2",
"@mui/styles": "5.10.2",
"@mui/material": "5.12.1",
"@mui/styles": "5.12.0",
"@react-native-async-storage/async-storage": "1.17.3",
"@react-native-community/clipboard": "1.5.1",
"@react-native-community/netinfo": "7.1.7",
@@ -48,10 +44,6 @@
"@svgr/webpack": "6.3.1",
"@tensorflow/tfjs-backend-wasm": "3.13.0",
"@tensorflow/tfjs-core": "3.13.0",
"@types/amplitude-js": "8.16.2",
"@types/audioworklet": "0.0.29",
"@types/w3c-image-capture": "1.0.6",
"@types/w3c-web-hid": "1.0.3",
"@vladmandic/human": "2.6.5",
"@vladmandic/human-models": "2.5.9",
"@xmldom/xmldom": "0.8.7",
@@ -73,7 +65,7 @@
"js-md5": "0.6.1",
"js-sha512": "0.8.0",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1620.0.0+7f0012f7/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1632.0.0+e4966db9/lib-jitsi-meet.tgz",
"lodash": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",
@@ -84,7 +76,7 @@
"react": "17.0.2",
"react-dom": "17.0.2",
"react-emoji-render": "1.2.4",
"react-focus-lock": "2.5.1",
"react-focus-lock": "2.9.4",
"react-i18next": "10.11.4",
"react-linkify": "1.0.0-alpha",
"react-native": "0.68.6",
@@ -123,7 +115,6 @@
"redux-thunk": "2.4.1",
"resemblejs": "4.0.0",
"seamless-scroll-polyfill": "2.1.8",
"styled-components": "3.4.9",
"tss-react": "4.4.4",
"util": "0.12.1",
"uuid": "8.3.2",
@@ -140,20 +131,27 @@
"@babel/preset-flow": "7.16.0",
"@babel/preset-react": "7.16.0",
"@jitsi/eslint-config": "4.1.5",
"@types/amplitude-js": "8.16.2",
"@types/audioworklet": "0.0.29",
"@types/js-md5": "0.4.3",
"@types/lodash": "4.14.182",
"@types/punycode": "2.1.0",
"@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-native-keep-awake": "2.0.3",
"@types/react-native-video": "5.0.14",
"@types/react-redux": "7.1.24",
"@types/react-window": "1.8.5",
"@types/resemblejs": "^4.1.0",
"@types/unorm": "1.3.28",
"@types/uuid": "8.3.4",
"@types/w3c-image-capture": "1.0.6",
"@types/w3c-web-hid": "1.0.3",
"@types/zxcvbn": "4.4.1",
"@typescript-eslint/eslint-plugin": "5.30.5",
"@typescript-eslint/parser": "5.30.4",
"@typescript-eslint/eslint-plugin": "5.59.5",
"@typescript-eslint/parser": "5.59.5",
"babel-loader": "8.2.3",
"babel-plugin-optional-require": "0.3.1",
"circular-dependency-plugin": "5.2.0",
@@ -173,14 +171,19 @@
"sass": "1.26.8",
"style-loader": "3.3.1",
"traverse": "0.6.6",
"ts-loader": "9.4.1",
"typescript": "4.7.4",
"ts-loader": "9.4.2",
"typescript": "5.0.4",
"unorm": "1.6.0",
"webpack": "5.76.0",
"webpack-bundle-analyzer": "4.4.2",
"webpack-cli": "4.9.0",
"webpack-dev-server": "4.7.3"
},
"overrides": {
"strophe.js@1.5.0": {
"@xmldom/xmldom": "0.8.7"
}
},
"engines": {
"node": ">=14.0.0",
"npm": ">=7.0.0"
@@ -197,6 +200,8 @@
"lint-fix": "eslint --ext .js,.ts,.tsx --max-warnings 0 --fix .",
"postinstall": "patch-package --error-on-fail && jetify",
"validate": "npm ls",
"tsc-test:web": "tsc --project tsconfig.web.json --listFilesOnly | grep -v node_modules | grep native",
"tsc-test:native": "tsc --project tsconfig.native.json --listFilesOnly | grep -v node_modules | grep web",
"start": "make dev"
},
"resolutions": {

View File

@@ -1,14 +1,14 @@
diff --git a/node_modules/@giphy/js-analytics/dist/send-pingback.js b/node_modules/@giphy/js-analytics/dist/send-pingback.js
index 001345a..f303443 100644
index 989f0ff..149e77c 100644
--- a/node_modules/@giphy/js-analytics/dist/send-pingback.js
+++ b/node_modules/@giphy/js-analytics/dist/send-pingback.js
@@ -10,6 +10,9 @@ var global_1 = __importDefault(require("./global"));
var environment = (global_1.default === null || global_1.default === void 0 ? void 0 : global_1.default.GIPHY_PINGBACK_URL) || 'https://pingback.giphy.com';
var pingBackUrl = environment + "/v2/pingback?apikey=l0HlIwPWyBBUDAUgM";
var pingBackUrl = "".concat(environment, "/v2/pingback?apikey=l0HlIwPWyBBUDAUgM");
var sendPingback = function (events) {
+ // Disabled.
+ return Promise.resolve();
+
var headers = js_util_1.getGiphySDKRequestHeaders();
var headers = (0, js_util_1.getGiphySDKRequestHeaders)();
/* istanbul ignore next */
headers === null || headers === void 0 ? void 0 : headers.set('Content-Type', 'application/json');

View File

@@ -1,12 +0,0 @@
diff --git a/node_modules/@giphy/js-brand/dist/typography.js b/node_modules/@giphy/js-brand/dist/typography.js
index af796bc..585fa00 100644
--- a/node_modules/@giphy/js-brand/dist/typography.js
+++ b/node_modules/@giphy/js-brand/dist/typography.js
@@ -7,7 +7,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.css = exports.fontSize = exports.fontFamily = void 0;
var emotion_1 = require("emotion");
// eslint-disable-next-line
-emotion_1.injectGlobal(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n@font-face {\n font-family: 'interface';\n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Rg.woff2') format('woff2'),\n url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Rg.woff') format('woff');\n}\n\n@font-face {\n font-family: 'interface';\n font-style: normal;\n font-weight: bold;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Bd.woff2') format('woff2'),\n url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Bd.woff') format('woff');\n}\n@font-face {\n font-family: 'interface';\n font-style: normal;\n font-weight: 900;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_XBd.woff') format('woff');\n}\n@font-face {\n font-family: 'nexablack'; \n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/nexa_black-webfont.woff2') format('woff2'),\n url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/nexa_black-webfont.woff') format('woff');\n}\n@font-face {\n font-family: 'SSStandard'; \n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/ss-standard.woff') format('woff');\n}\n@font-face {\n font-family: 'SSSocial'; \n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/ss-social.woff') format('woff');\n}\n"], ["\n@font-face {\n font-family: 'interface';\n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Rg.woff2') format('woff2'),\n url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Rg.woff') format('woff');\n}\n\n@font-face {\n font-family: 'interface';\n font-style: normal;\n font-weight: bold;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Bd.woff2') format('woff2'),\n url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Bd.woff') format('woff');\n}\n@font-face {\n font-family: 'interface';\n font-style: normal;\n font-weight: 900;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_XBd.woff') format('woff');\n}\n@font-face {\n font-family: 'nexablack'; \n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/nexa_black-webfont.woff2') format('woff2'),\n url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/nexa_black-webfont.woff') format('woff');\n}\n@font-face {\n font-family: 'SSStandard'; \n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/ss-standard.woff') format('woff');\n}\n@font-face {\n font-family: 'SSSocial'; \n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/ss-social.woff') format('woff');\n}\n"])));
exports.fontFamily = {
title: "'nexablack', sans-serif",
body: 'interface, Helvetica Neue, helvetica, sans-serif;',

View File

@@ -0,0 +1,13 @@
diff --git a/node_modules/@giphy/js-brand/dist/typography.js b/node_modules/@giphy/js-brand/dist/typography.js
index 75ad96b..815cb8b 100644
--- a/node_modules/@giphy/js-brand/dist/typography.js
+++ b/node_modules/@giphy/js-brand/dist/typography.js
@@ -6,7 +6,7 @@ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cook
Object.defineProperty(exports, "__esModule", { value: true });
exports.css = exports.fontSize = exports.fontFamily = exports.addFonts = void 0;
var emotion_1 = require("emotion");
-var addFonts = function () { return (0, emotion_1.injectGlobal)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n@font-face {\n font-family: 'interface';\n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Rg.woff2') format('woff2'),\n url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Rg.woff') format('woff');\n}\n\n@font-face {\n font-family: 'interface';\n font-style: normal;\n font-weight: bold;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Bd.woff2') format('woff2'),\n url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Bd.woff') format('woff');\n}\n@font-face {\n font-family: 'interface';\n font-style: normal;\n font-weight: 900;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_XBd.woff') format('woff');\n}\n@font-face {\n font-family: 'nexablack'; \n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/nexa_black-webfont.woff2') format('woff2'),\n url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/nexa_black-webfont.woff') format('woff');\n}\n@font-face {\n font-family: 'SSStandard'; \n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/ss-standard.woff') format('woff');\n}\n@font-face {\n font-family: 'SSSocial'; \n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/ss-social.woff') format('woff');\n}\n"], ["\n@font-face {\n font-family: 'interface';\n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Rg.woff2') format('woff2'),\n url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Rg.woff') format('woff');\n}\n\n@font-face {\n font-family: 'interface';\n font-style: normal;\n font-weight: bold;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Bd.woff2') format('woff2'),\n url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_Bd.woff') format('woff');\n}\n@font-face {\n font-family: 'interface';\n font-style: normal;\n font-weight: 900;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/InterFace_W_XBd.woff') format('woff');\n}\n@font-face {\n font-family: 'nexablack'; \n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/nexa_black-webfont.woff2') format('woff2'),\n url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/nexa_black-webfont.woff') format('woff');\n}\n@font-face {\n font-family: 'SSStandard'; \n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/ss-standard.woff') format('woff');\n}\n@font-face {\n font-family: 'SSSocial'; \n font-style: normal;\n font-weight: normal;\n src: url('https://s3.amazonaws.com/giphyscripts/react-giphy-brand/fonts/ss-social.woff') format('woff');\n}\n"]))); };
+var addFonts = function () { };
exports.addFonts = addFonts;
try {
// in an env where process.env exists,

View File

@@ -1,5 +1,3 @@
// @flow
/**
* The type of (redux) action which signals that local media duration has changed.
*

View File

@@ -1,4 +1,3 @@
/* eslint-disable lines-around-comment */
import { setRoom } from '../base/conference/actions';
import {
configWillLoad,
@@ -13,6 +12,7 @@ import {
import { connect, disconnect, setLocationURL } from '../base/connection/actions';
import { loadConfig } from '../base/lib-jitsi-meet/functions.native';
import { createDesiredLocalTracks } from '../base/tracks/actions';
import isInsecureRoomName from '../base/util/isInsecureRoomName';
import { parseURLParams } from '../base/util/parseURLParams';
import {
appendURLParam,
@@ -20,14 +20,11 @@ import {
parseURIString,
toURLString
} from '../base/util/uri';
// @ts-ignore
import { isPrejoinPageEnabled } from '../mobile/navigation/functions';
import {
goBackToRoot,
navigateRoot
// @ts-ignore
} from '../mobile/navigation/rootNavigationContainerRef';
// @ts-ignore
import { screen } from '../mobile/navigation/routes';
import { clearNotifications } from '../notifications/actions';
@@ -55,7 +52,7 @@ export function appNavigate(uri?: string, options: IReloadNowOptions = {}) {
// If the specified location (URI) does not identify a host, use the app's
// default.
if (!location || !location.host) {
if (!location?.host) {
const defaultLocation = parseURIString(getDefaultURL(getState));
if (location) {
@@ -140,10 +137,14 @@ export function appNavigate(uri?: string, options: IReloadNowOptions = {}) {
dispatch(setRoom(room));
if (room) {
if (isInsecureRoomName(room)) {
navigateRoot(screen.unsafeRoomWarning);
return;
}
dispatch(createDesiredLocalTracks());
dispatch(clearNotifications());
// @ts-ignore
const { hidePrejoin } = options;
if (!hidePrejoin && isPrejoinPageEnabled(getState())) {

View File

@@ -49,7 +49,7 @@ export function appNavigate(uri?: string) {
// If the specified location (URI) does not identify a host, use the app's
// default.
if (!location || !location.host) {
if (!location?.host) {
const defaultLocation = parseURIString(getDefaultURL(getState));
if (location) {

View File

@@ -1,4 +1,3 @@
import { AtlasKitThemeProvider } from '@atlaskit/theme';
import React from 'react';
import GlobalStyles from '../../base/ui/components/GlobalStyles.web';
@@ -46,11 +45,9 @@ export class App extends AbstractApp {
_createMainElement(component: React.ComponentType, props: any) {
return (
<JitsiThemeProvider>
<AtlasKitThemeProvider mode = 'dark'>
<GlobalStyles />
<ChromeExtensionBanner />
{ super._createMainElement(component, props) }
</AtlasKitThemeProvider>
<GlobalStyles />
<ChromeExtensionBanner />
{ super._createMainElement(component, props) }
</JitsiThemeProvider>
);
}
@@ -63,9 +60,7 @@ export class App extends AbstractApp {
_renderDialogContainer() {
return (
<JitsiThemeProvider>
<AtlasKitThemeProvider mode = 'dark'>
<DialogContainer />
</AtlasKitThemeProvider>
<DialogContainer />
</JitsiThemeProvider>
);
}

View File

@@ -5,8 +5,6 @@ import { IStateful } from '../base/app/types';
import { isRoomValid } from '../base/conference/functions';
import { isSupportedBrowser } from '../base/environment/environment';
import { toState } from '../base/redux/functions';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import Conference from '../conference/components/web/Conference';
import { getDeepLinkingPage } from '../deep-linking/functions';
import UnsupportedDesktopBrowser from '../unsupported-browser/components/UnsupportedDesktopBrowser';

View File

@@ -5,6 +5,7 @@ import '../base/media/middleware';
import '../dynamic-branding/middleware';
import '../e2ee/middleware';
import '../external-api/middleware';
import '../keyboard-shortcuts/middleware';
import '../no-audio-signal/middleware';
import '../notifications/middleware';
import '../noise-detection/middleware';

View File

@@ -1,5 +1,3 @@
// @flow
import '../analytics/reducer';
import '../authentication/reducer';
import '../av-moderation/reducer';

View File

@@ -1,5 +1,3 @@
// @flow
import '../mobile/audio-mode/reducer';
import '../mobile/background/reducer';
import '../mobile/call-integration/reducer';

View File

@@ -1,8 +1,10 @@
import '../base/devices/reducer';
import '../base/premeeting/reducer';
import '../base/tooltip/reducer';
import '../e2ee/reducer';
import '../face-landmarks/reducer';
import '../feedback/reducer';
import '../keyboard-shortcuts/reducer';
import '../no-audio-signal/reducer';
import '../noise-detection/reducer';
import '../participants-pane/reducer';

View File

@@ -20,6 +20,7 @@ import { ILoggingState } from '../base/logging/reducer';
import { IMediaState } from '../base/media/reducer';
import { INetInfoState } from '../base/net-info/reducer';
import { IParticipantsState } from '../base/participants/reducer';
import { IPreMeetingState } from '../base/premeeting/types';
import { IResponsiveUIState } from '../base/responsive-ui/reducer';
import { ISettingsState } from '../base/settings/reducer';
import { ISoundsState } from '../base/sounds/reducer';
@@ -43,6 +44,7 @@ import { IGifsState } from '../gifs/reducer';
import { IGoogleApiState } from '../google-api/reducer';
import { IInviteState } from '../invite/reducer';
import { IJaaSState } from '../jaas/reducer';
import { IKeyboardShortcutsState } from '../keyboard-shortcuts/types';
import { ILargeVideoState } from '../large-video/reducer';
import { ILobbyState } from '../lobby/reducer';
import { IMobileAudioModeState } from '../mobile/audio-mode/reducer';
@@ -109,6 +111,7 @@ export interface IReduxState {
'features/base/net-info': INetInfoState;
'features/base/no-src-data': INoSrcDataState;
'features/base/participants': IParticipantsState;
'features/base/premeeting': IPreMeetingState;
'features/base/responsive-ui': IResponsiveUIState;
'features/base/settings': ISettingsState;
'features/base/sounds': ISoundsState;
@@ -133,6 +136,7 @@ export interface IReduxState {
'features/google-api': IGoogleApiState;
'features/invite': IInviteState;
'features/jaas': IJaaSState;
'features/keyboard-shortcuts': IKeyboardShortcutsState;
'features/large-video': ILargeVideoState;
'features/lobby': ILobbyState;
'features/mobile/audio-mode': IMobileAudioModeState;

View File

@@ -27,13 +27,13 @@ export function cancelLogin() {
// a reaction to CONNECTION_FAILED). Since the
// app/user is going to navigate to WelcomePage, the SDK
// clients/consumers need an event.
const { error, passwordRequired }
const { error = { recoverable: undefined }, passwordRequired }
= getState()['features/base/connection'];
passwordRequired
&& dispatch(
connectionFailed(
passwordRequired, // @ts-ignore
passwordRequired,
set(error, 'recoverable', false) as any));
};
}

View File

@@ -1,4 +1,2 @@
export { default as LoginDialog } from './native/LoginDialog';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
export { default as WaitForOwnerDialog } from './native/WaitForOwnerDialog';

View File

@@ -24,7 +24,7 @@ import {
openLoginDialog,
openWaitForOwnerDialog,
stopWaitForOwner,
waitForOwner } from './actions.native'; // @ts-ignore
waitForOwner } from './actions.native';
import { LoginDialog, WaitForOwnerDialog } from './components';
/**

View File

@@ -1,5 +1,3 @@
// @flow
/**
* The type of (redux) action which sets the audio-only flag for the current
* conference.

View File

@@ -3,6 +3,7 @@ import { sendAnalytics } from '../../analytics/functions';
import { appNavigate } from '../../app/actions';
import { IReduxState, IStore } from '../../app/types';
import { endpointMessageReceived } from '../../subtitles/actions.any';
import { iAmVisitor } from '../../visitors/functions';
import { getReplaceParticipant } from '../config/functions';
import { disconnect } from '../connection/actions';
import { JITSI_CONNECTION_CONFERENCE_KEY } from '../connection/constants';
@@ -450,11 +451,12 @@ export function conferenceUniqueIdSet(conference: IJitsiConference) {
*/
export function _conferenceWillJoin(conference: IJitsiConference) {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState();
const localTracks
= getLocalTracks(getState()['features/base/tracks'])
= getLocalTracks(state['features/base/tracks'])
.map(t => t.jitsiTrack);
if (localTracks.length) {
if (localTracks.length && !iAmVisitor(state)) {
_addLocalTracksToConference(conference, localTracks);
}
@@ -806,7 +808,7 @@ export function setStartReactionsMuted(muted: boolean, updateBackend = false) {
export function setPassword(
conference: IJitsiConference | undefined,
method: Function | undefined,
password: string) {
password?: string) {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
if (!conference) {
return;

View File

@@ -159,7 +159,6 @@ export function forEachConference(
// Does the value of the base/conference's property look like a
// JitsiConference?
if (v && typeof v === 'object') {
// $FlowFixMe
const url: URL = v[JITSI_CONFERENCE_URL_KEY];
// XXX The Web version of Jitsi Meet does not utilize
@@ -293,7 +292,7 @@ export function getVisitorOptions(stateful: IStateful, params: Array<string>) {
const config = toState(stateful)['features/base/config'];
if (!config || !config.hosts) {
if (!config?.hosts) {
logger.warn('Wrong configuration, missing hosts.');
return;
@@ -301,7 +300,8 @@ export function getVisitorOptions(stateful: IStateful, params: Array<string>) {
if (!vnode) {
// this is redirecting back to main, lets restore config
// no point of updating disableFocus, we can skip the initial iq to jicofo
// not updating disableFocus, as if the room capacity is full the promotion to the main room will fail
// and the visitor will be redirected back to a vnode from jicofo
if (config.oldConfig && username) {
return {
hosts: {
@@ -309,7 +309,9 @@ export function getVisitorOptions(stateful: IStateful, params: Array<string>) {
muc: config.oldConfig.hosts.muc
},
focusUserJid: focusJid,
disableLocalStats: false,
bosh: config.oldConfig.bosh && appendURLParam(config.oldConfig.bosh, 'customusername', username),
p2p: config.oldConfig.p2p,
websocket: config.oldConfig.websocket
&& appendURLParam(config.oldConfig.websocket, 'customusername', username),
oldConfig: undefined // clears it up
@@ -326,6 +328,7 @@ export function getVisitorOptions(stateful: IStateful, params: Array<string>) {
},
focusUserJid: config.focusUserJid,
bosh: config.bosh,
p2p: config.p2p,
websocket: config.websocket
};
@@ -339,7 +342,12 @@ export function getVisitorOptions(stateful: IStateful, params: Array<string>) {
},
focusUserJid: focusJid,
disableFocus: true, // This flag disables sending the initial conference request
disableLocalStats: true,
bosh: config.bosh && appendURLParam(config.bosh, 'vnode', vnode),
p2p: {
...config.p2p,
enabled: false
},
websocket: config.websocket && appendURLParam(config.websocket, 'vnode', vnode)
};
}

View File

@@ -1,6 +1,5 @@
// @flow
import { AnyAction } from 'redux';
import { readyToClose } from '../../../features/mobile/external-api/actions';
import {
ACTION_PINNED,
ACTION_UNPINNED,
@@ -9,11 +8,14 @@ import {
} from '../../analytics/AnalyticsEvents';
import { sendAnalytics } from '../../analytics/functions';
import { reloadNow } from '../../app/actions';
import { IReduxState, IStore } from '../../app/types';
import { removeLobbyChatParticipant } from '../../chat/actions.any';
import { openDisplayNamePrompt } from '../../display-name/actions';
import { readyToClose } from '../../mobile/external-api/actions';
import { showErrorNotification, showWarningNotification } from '../../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants';
import { setIAmVisitor } from '../../visitors/actions';
import { iAmVisitor } from '../../visitors/functions';
import { overwriteConfig } from '../config/actions';
import { CONNECTION_ESTABLISHED, CONNECTION_FAILED } from '../connection/actionTypes';
import { connect, connectionDisconnected, disconnect } from '../connection/actions';
@@ -62,12 +64,10 @@ import {
} from './functions';
import logger from './logger';
declare var APP: Object;
/**
* Handler for before unload event.
*/
let beforeUnloadHandler;
let beforeUnloadHandler: Function | undefined;
/**
* Implements the middleware of the feature base/conference.
@@ -129,7 +129,7 @@ MiddlewareRegistry.register(store => next => action => {
* @private
* @returns {Object} The value returned by {@code next(action)}.
*/
function _conferenceFailed({ dispatch, getState }, next, action) {
function _conferenceFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
const { conference, error } = action;
if (error.name === JitsiConferenceErrors.REDIRECTED) {
@@ -191,7 +191,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) {
const newConfig = restoreConferenceOptions(getState);
if (newConfig) {
dispatch(overwriteConfig(newConfig))
dispatch(overwriteConfig(newConfig)) // @ts-ignore
.then(dispatch(conferenceWillLeave(conference)))
.then(conference.leave())
.then(dispatch(disconnect()))
@@ -217,7 +217,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) {
const [ vnode ] = error.params;
dispatch(overwriteConfig(newConfig))
dispatch(overwriteConfig(newConfig)) // @ts-ignore
.then(dispatch(conferenceWillLeave(conference)))
.then(conference.leave())
.then(dispatch(disconnect()))
@@ -234,7 +234,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) {
if (typeof APP === 'undefined') {
!error.recoverable
&& conference
&& conference.leave(CONFERENCE_LEAVE_REASONS.UNRECOVERABLE_ERROR).catch(reason => {
&& conference.leave(CONFERENCE_LEAVE_REASONS.UNRECOVERABLE_ERROR).catch((reason: Error) => {
// Even though we don't care too much about the failure, it may be
// good to know that it happen, so log it (on the info level).
logger.info('JitsiConference.leave() rejected with:', reason);
@@ -267,7 +267,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) {
* @private
* @returns {Object} The value returned by {@code next(action)}.
*/
function _conferenceJoined({ dispatch, getState }, next, action) {
function _conferenceJoined({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
const result = next(action);
const { conference } = action;
const { pendingSubjectChange } = getState()['features/base/conference'];
@@ -288,6 +288,14 @@ function _conferenceJoined({ dispatch, getState }, next, action) {
beforeUnloadHandler = () => {
dispatch(conferenceWillLeave(conference));
};
if (!iAmVisitor(getState())) {
// if a visitor is promoted back to main room and want to join an empty breakout room
// we need to send iq to jicofo, so it can join/create the breakout room
dispatch(overwriteConfig({ disableFocus: false }));
}
// @ts-ignore
window.addEventListener(disableBeforeUnloadHandlers ? 'unload' : 'beforeunload', beforeUnloadHandler);
if (requireDisplayName
@@ -313,7 +321,7 @@ function _conferenceJoined({ dispatch, getState }, next, action) {
* @private
* @returns {Object} The value returned by {@code next(action)}.
*/
function _connectionEstablished({ dispatch }, next, action) {
function _connectionEstablished({ dispatch }: IStore, next: Function, action: AnyAction) {
const result = next(action);
// FIXME: Workaround for the web version. Currently, the creation of the
@@ -330,7 +338,7 @@ function _connectionEstablished({ dispatch }, next, action) {
* @param {Object} state - The redux state.
* @returns {void}
*/
function _logJwtErrors(message, state) {
function _logJwtErrors(message: string, state: IReduxState) {
const { jwt } = state['features/base/jwt'];
if (!jwt) {
@@ -357,7 +365,7 @@ function _logJwtErrors(message, state) {
* @private
* @returns {Object} The value returned by {@code next(action)}.
*/
function _connectionFailed({ dispatch, getState }, next, action) {
function _connectionFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
_logJwtErrors(action.error.message, getState());
const result = next(action);
@@ -417,7 +425,7 @@ function _connectionFailed({ dispatch, getState }, next, action) {
* @private
* @returns {Object} The value returned by {@code next(action)}.
*/
function _conferenceSubjectChanged({ dispatch, getState }, next, action) {
function _conferenceSubjectChanged({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
const result = next(action);
const { subject } = getState()['features/base/conference'];
@@ -442,7 +450,7 @@ function _conferenceSubjectChanged({ dispatch, getState }, next, action) {
* @param {Object} store - The redux store.
* @returns {void}
*/
function _conferenceWillLeave({ getState }: { getState: Function }) {
function _conferenceWillLeave({ getState }: IStore) {
_removeUnloadHandler(getState);
}
@@ -460,7 +468,7 @@ function _conferenceWillLeave({ getState }: { getState: Function }) {
* @private
* @returns {Object} The value returned by {@code next(action)}.
*/
function _pinParticipant({ getState }, next, action) {
function _pinParticipant({ getState }: IStore, next: Function, action: AnyAction) {
const state = getState();
const { conference } = state['features/base/conference'];
@@ -473,7 +481,7 @@ function _pinParticipant({ getState }, next, action) {
const pinnedParticipant = getPinnedParticipant(state);
const actionName = id ? ACTION_PINNED : ACTION_UNPINNED;
const local
= (participantById && participantById.local)
= participantById?.local
|| (!id && pinnedParticipant && pinnedParticipant.local);
let participantIdForEvent;
@@ -481,7 +489,7 @@ function _pinParticipant({ getState }, next, action) {
participantIdForEvent = local;
} else {
participantIdForEvent
= actionName === ACTION_PINNED ? id : pinnedParticipant && pinnedParticipant.id;
= actionName === ACTION_PINNED ? id : pinnedParticipant?.id;
}
sendAnalytics(createPinnedEvent(
@@ -501,10 +509,11 @@ function _pinParticipant({ getState }, next, action) {
* @param {Function} getState - The redux getState function.
* @returns {void}
*/
function _removeUnloadHandler(getState) {
function _removeUnloadHandler(getState: IStore['getState']) {
if (typeof beforeUnloadHandler !== 'undefined') {
const { disableBeforeUnloadHandlers = false } = getState()['features/base/config'];
// @ts-ignore
window.removeEventListener(disableBeforeUnloadHandlers ? 'unload' : 'beforeunload', beforeUnloadHandler);
beforeUnloadHandler = undefined;
}
@@ -522,7 +531,7 @@ function _removeUnloadHandler(getState) {
* @private
* @returns {Object} The value returned by {@code next(action)}.
*/
function _sendTones({ getState }, next, action) {
function _sendTones({ getState }: IStore, next: Function, action: AnyAction) {
const state = getState();
const { conference } = state['features/base/conference'];
@@ -549,15 +558,15 @@ function _sendTones({ getState }, next, action) {
* @private
* @returns {Object} The value returned by {@code next(action)}.
*/
function _setRoom({ dispatch, getState }, next, action) {
function _setRoom({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
const state = getState();
const { localSubject, subject } = state['features/base/config'];
const { room } = action;
if (room) {
// Set the stored subject.
dispatch(setLocalSubject(localSubject));
dispatch(setSubject(subject));
dispatch(setLocalSubject(localSubject ?? ''));
dispatch(setSubject(subject ?? ''));
}
return next(action);
@@ -572,15 +581,20 @@ function _setRoom({ dispatch, getState }, next, action) {
* @private
* @returns {Promise}
*/
function _syncConferenceLocalTracksWithState({ getState }, action) {
const conference = getCurrentConference(getState);
function _syncConferenceLocalTracksWithState({ getState }: IStore, action: AnyAction) {
const state = getState();
const conference = getCurrentConference(state);
let promise;
if (conference) {
const track = action.track.jitsiTrack;
if (action.type === TRACK_ADDED) {
promise = _addLocalTracksToConference(conference, [ track ]);
// If gUM is slow and tracks are created after the user has already joined the conference, avoid
// adding the tracks to the conference if the user is a visitor.
if (!iAmVisitor(state)) {
promise = _addLocalTracksToConference(conference, [ track ]);
}
} else {
promise = _removeLocalTracksFromConference(conference, [ track ]);
}
@@ -603,7 +617,7 @@ function _syncConferenceLocalTracksWithState({ getState }, action) {
* @private
* @returns {Object} The value returned by {@code next(action)}.
*/
function _trackAddedOrRemoved(store, next, action) {
function _trackAddedOrRemoved(store: IStore, next: Function, action: AnyAction) {
const track = action.track;
// TODO All track swapping should happen here instead of conference.js.
@@ -628,7 +642,7 @@ function _trackAddedOrRemoved(store, next, action) {
* @private
* @returns {Object} The value returned by {@code next(action)}.
*/
function _updateLocalParticipantInConference({ dispatch, getState }, next, action) {
function _updateLocalParticipantInConference({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
const { conference } = getState()['features/base/conference'];
const { participant } = action;
const result = next(action);

View File

@@ -1,4 +1,3 @@
import {
setPrejoinPageVisibility,
setSkipPrejoinOnReload

View File

@@ -46,6 +46,7 @@ export interface IJitsiConference {
authenticateAndUpgradeRole: Function;
avModerationApprove: Function;
avModerationReject: Function;
callUUID?: string;
createVideoSIPGWSession: Function;
dial: Function;
disableAVModeration: Function;
@@ -60,6 +61,7 @@ export interface IJitsiConference {
getMetadataHandler: Function;
getName: Function;
getParticipantById: Function;
getParticipantCount: Function;
getParticipants: Function;
getRole: Function;
getSpeakerStats: () => ISpeakerStats;
@@ -101,7 +103,9 @@ export interface IJitsiConference {
sendMessage: Function;
sendPrivateTextMessage: Function;
sendTextMessage: Function;
sendTones: Function;
sessionId: string;
setAssumedBandwidthBps: (value: number) => void;
setDesktopSharingFrameRate: Function;
setDisplayName: Function;
setLocalParticipantProperty: Function;

View File

@@ -1,4 +1,4 @@
// @ts-ignore
// @ts-expect-error
import { jitsiLocalStorage } from '@jitsi/js-utils';
import { IStore } from '../../app/types';

View File

@@ -18,6 +18,7 @@ type ToolbarButtons = 'camera' |
'participants-pane' |
'profile' |
'raisehand' |
'reactions' |
'recording' |
'security' |
'select-background' |
@@ -169,6 +170,7 @@ export interface IConfig {
}>;
callDisplayName?: string;
callFlowsEnabled?: boolean;
callHandle?: string;
callStatsConfigParams?: {
additionalIDs?: {
customerID?: string;
@@ -190,6 +192,7 @@ export interface IConfig {
};
callStatsID?: string;
callStatsSecret?: string;
callUUID?: string;
channelLastN?: number;
chromeExtensionBanner?: {
chromeExtensionsInfo?: Array<{ id: string; path: string; }>;
@@ -253,6 +256,7 @@ export interface IConfig {
disableDeepLinking?: boolean;
disableFilmstripAutohiding?: boolean;
disableFocus?: boolean;
disableIframeAPI?: boolean;
disableIncomingMessageSound?: boolean;
disableInitialGUM?: boolean;
disableInviteFunctions?: boolean;
@@ -404,6 +408,7 @@ export interface IConfig {
legalUrls?: {
helpCentre: string;
privacy: string;
security: string;
terms: string;
};
liveStreaming?: {

View File

@@ -64,7 +64,7 @@ export const THIRD_PARTY_PREJOIN_BUTTONS = [ 'microphone', 'camera', 'select-bac
/**
* The toolbar buttons to show when in visitors mode.
*/
export const VISITORS_MODE_BUTTONS = [ 'chat', 'hangup', 'raisehand', 'tileview' ];
export const VISITORS_MODE_BUTTONS = [ 'chat', 'hangup', 'raisehand', 'settings', 'tileview' ];
/**
* The set of feature flags.

View File

@@ -1,12 +1,13 @@
// @ts-ignore
// @ts-expect-error
import Bourne from '@hapi/bourne';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
// @ts-expect-error
import { jitsiLocalStorage } from '@jitsi/js-utils';
import _ from 'lodash';
import { IReduxState } from '../../app/types';
import { browser } from '../lib-jitsi-meet';
import { IMediaState } from '../media/reducer';
import { parseURLParams } from '../util/parseURLParams';
import { IConfig } from './configType';
@@ -65,7 +66,7 @@ export function getMeetingRegion(state: IReduxState) {
* @param {Object} _state - The global state.
* @returns {boolean}
*/
export function getMultipleVideoSendingSupportFeatureFlag(_state: IReduxState) {
export function getMultipleVideoSendingSupportFeatureFlag(_state: IReduxState | IMediaState) {
return browser.supportsUnifiedPlan();
}

View File

@@ -46,15 +46,17 @@ const INITIAL_RN_STATE: IConfig = {
analytics: {},
// FIXME: Mobile codecs should probably be configurable separately, rather
// than requiring this override here...
// FIXME: than requiring this override here...
// TODO: Remove comments later, after next release, so that the fix is applied
p2p: {
disabledCodec: 'vp9',
preferredCodec: 'vp8'
// disabledCodec: 'vp9',
// preferredCodec: 'vp8'
},
videoQuality: {
disabledCodec: 'vp9',
preferredCodec: 'vp8'
// disabledCodec: 'vp9',
// preferredCodec: 'vp8'
}
};
@@ -82,6 +84,7 @@ export interface IConfigState extends IConfig {
domain: string;
muc: string;
};
p2p?: object;
websocket?: string;
};
}

View File

@@ -1,5 +1,3 @@
// @flow
/**
* The type of (redux) action which signals that a connection disconnected.
*

View File

@@ -72,7 +72,7 @@ export type ConnectionFailedError = {
* connection: JitsiConnection
* }}
*/
export function connectionDisconnected(connection: Object) {
export function connectionDisconnected(connection?: Object) {
return {
type: CONNECTION_DISCONNECTED,
connection

View File

@@ -36,7 +36,7 @@ type Props = {
/**
* Function to render a bottom sheet footer element, if necessary.
*/
renderFooter?: Function;
renderFooter?: () => React.ReactNode;
/**
* Function to render a bottom sheet header element, if necessary.
@@ -109,9 +109,7 @@ class BottomSheet extends PureComponent<Props> {
} = this.props;
return (
<SlidingView // @ts-ignore
accessibilityRole = 'menu'
accessibilityViewIsModal = { true }
<SlidingView
onHide = { this._onCancel }
position = 'bottom'
show = { Boolean(showSlidingView) }>

View File

@@ -19,7 +19,7 @@ interface IProps extends AbstractProps, WithTranslation {
/**
* The i18n key of the text label for the cancel button.
*/
cancelLabel: string;
cancelLabel?: string;
/**
* The React {@code Component} children.
@@ -29,7 +29,7 @@ interface IProps extends AbstractProps, WithTranslation {
/**
* The i18n key of the text label for the confirm button.
*/
confirmLabel: string;
confirmLabel?: string;
/**
* Dialog description key for translations.

View File

@@ -18,7 +18,7 @@ interface IProps extends AbstractProps, WithTranslation {
/**
* The dialog descriptionKey.
*/
descriptionKey: string;
descriptionKey?: string;
/**
* An optional initial value to initiate the field with.

View File

@@ -1,4 +1,4 @@
// @ts-ignore
// @ts-expect-error
import { randomInt } from '@jitsi/js-utils/random';
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
@@ -11,7 +11,6 @@ import { isFatalJitsiConnectionError } from '../../../lib-jitsi-meet/functions.n
import { hideDialog } from '../../actions';
import logger from '../../logger';
// @ts-ignore
import ConfirmDialog from './ConfirmDialog';
@@ -39,9 +38,7 @@ interface IPageReloadDialogState {
* Shows a warning message and counts down towards the re-load.
*/
class PageReloadDialog extends Component<IPageReloadDialogProps, IPageReloadDialogState> {
// @ts-ignore
_interval: IntervalID;
_interval?: number;
_timeoutSeconds: number;
/**
@@ -105,7 +102,7 @@ class PageReloadDialog extends Component<IPageReloadDialogProps, IPageReloadDial
_onCancel() {
const { dispatch } = this.props;
clearInterval(this._interval);
clearInterval(this._interval ?? 0);
dispatch(appNavigate(undefined));
return true;
@@ -145,7 +142,7 @@ class PageReloadDialog extends Component<IPageReloadDialogProps, IPageReloadDial
_onReloadNow() {
const { dispatch } = this.props;
clearInterval(this._interval);
clearInterval(this._interval ?? 0);
dispatch(reloadNow());
return true;
@@ -200,8 +197,6 @@ function mapStateToProps(state: IReduxState) {
const { fatalError } = state['features/overlay'];
const fatalConnectionError
// @ts-ignore
= connectionError && isFatalJitsiConnectionError(connectionError);
const fatalConfigError = fatalError === configError;

View File

@@ -30,12 +30,12 @@ export type DialogProps = {
/**
* The handler for onCancel event.
*/
onCancel: Function;
onCancel?: Function;
/**
* The handler for the event when submitting the dialog.
*/
onSubmit: Function;
onSubmit?: Function;
/**
* Additional style to be applied on the dialog.

View File

@@ -1,5 +1,3 @@
// @flow
/**
* Flag indicating if add-people functionality should be enabled.
* Default: enabled (true).

View File

@@ -1,5 +1,3 @@
// @flow
/**
* The type of (redux) action which signals that i18next has been initialized.
*/

View File

@@ -90,7 +90,7 @@ interface IProps extends IIconProps {
/**
* Style object to be applied.
*/
style?: StyleType;
style?: StyleType | StyleType[];
/**
* TabIndex for the Icon.

View File

@@ -1,5 +1,3 @@
// @flow
import { getLogger } from '../logging/functions';
export default getLogger('features/base/jitsi-local-storage');

View File

@@ -1,6 +1,7 @@
// @flow
// @ts-expect-error
import Bourne from '@hapi/bourne';
// eslint-disable-next-line lines-around-comment
// @ts-expect-error
import { jitsiLocalStorage } from '@jitsi/js-utils/jitsi-local-storage';
import { browser } from '../lib-jitsi-meet';
@@ -9,9 +10,6 @@ import { parseURLParams } from '../util/parseURLParams';
import logger from './logger';
declare var APP: Object;
declare var config: Object;
/**
* Handles changes of the fake local storage.
@@ -29,7 +27,7 @@ function onFakeLocalStorageChanged() {
* @returns {boolean} - True if the local storage of the host page needs to be used instead jitsi-meet's local storage
* and false otherwise.
*/
function shouldUseHostPageLocalStorage(urlParams) {
function shouldUseHostPageLocalStorage(urlParams: { 'config.useHostPageLocalStorage'?: boolean; }) {
// NOTE: normally the url params and the config will be merged into the redux store. But we want to setup the local
// storage as soon as possible, the store is not created yet and the merging of the URL params and the config
// haven't been executed yet. That's why we need to manually parse the URL params and also access the config through
@@ -58,6 +56,7 @@ function shouldUseHostPageLocalStorage(urlParams) {
* @returns {void}
*/
function setupJitsiLocalStorage() {
// @ts-ignore
const urlParams = parseURLParams(window.location);
if (shouldUseHostPageLocalStorage(urlParams)) {

View File

@@ -1,4 +1,4 @@
// @ts-ignore
// @ts-expect-error
import jwtDecode from 'jwt-decode';
import { IReduxState } from '../../app/types';

View File

@@ -1,4 +1,4 @@
// @ts-ignore
// @ts-expect-error
import jwtDecode from 'jwt-decode';
import { AnyAction } from 'redux';

View File

@@ -1,5 +1,3 @@
// @flow
/**
* The type of (redux) action to add known domains to the list of domains known
* to the feature base/known-domains.

View File

@@ -29,7 +29,7 @@ interface IState {
* A react {@code Component} that implements an expanded label as tooltip-like
* component to explain the meaning of the {@code Label}.
*/
export default class ExpandedLabel<P extends IProps> extends Component<P, IState> {
export default abstract class ExpandedLabel<P extends IProps> extends Component<P, IState> {
/**
* Instantiates a new {@code ExpandedLabel} instance.
*
@@ -85,7 +85,7 @@ export default class ExpandedLabel<P extends IProps> extends Component<P, IState
*
* @returns {string}
*/
_getLabel: () => string;
abstract _getLabel(): string;
/**
* Defines the color of the expanded label. This function returns a default

View File

@@ -1,5 +1,3 @@
// @flow
/**
* The type of (redux) action which sets the last-n for the conference.
*

View File

@@ -2,5 +2,6 @@
// of) the project jitsi-meet.
//
// @ts-ignore
import JitsiMeetJS from 'lib-jitsi-meet';
export { JitsiMeetJS as default };

View File

@@ -1,5 +0,0 @@
// @flow
declare var JitsiMeetJS: Object;
export default JitsiMeetJS;

View File

@@ -0,0 +1,3 @@
declare let JitsiMeetJS: any;
export default JitsiMeetJS;

View File

@@ -1,10 +1,9 @@
// @ts-ignore
// @ts-expect-error
import { jitsiLocalStorage } from '@jitsi/js-utils';
import { IStore } from '../../app/types';
import { isOnline } from '../net-info/selectors';
// @ts-ignore
import JitsiMeetJS from './_';
import {
LIB_DID_DISPOSE,

View File

@@ -1,4 +1,5 @@
import { IStateful } from '../app/types';
import { ConnectionFailedError } from '../connection/actions.any';
import { toState } from '../redux/functions';
// @ts-ignore
@@ -91,7 +92,7 @@ export function isFatalJitsiConferenceError(error: Error | string) {
* indicates a fatal {@code JitsiConnection} error, {@code true}; otherwise,
* {@code false}.
*/
export function isFatalJitsiConnectionError(error: Error | string) {
export function isFatalJitsiConnectionError(error: Error | string | ConnectionFailedError) {
if (typeof error !== 'string') {
error = error.name; // eslint-disable-line no-param-reassign
}

View File

@@ -1,4 +1,4 @@
// @ts-ignore
// @ts-expect-error
import Bourne from '@hapi/bourne';
import { NativeModules } from 'react-native';

View File

@@ -1,6 +1,5 @@
// Re-export JitsiMeetJS from the library lib-jitsi-meet to (the other features
// of) the project jitsi-meet.
// @ts-ignore
import JitsiMeetJS from './_';
export { JitsiMeetJS as default };

View File

@@ -6,7 +6,6 @@ import { SET_NETWORK_INFO } from '../net-info/actionTypes';
import { PARTICIPANT_LEFT } from '../participants/actionTypes';
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
// @ts-ignore
import JitsiMeetJS from './_';
import { LIB_WILL_INIT } from './actionTypes';
import { disposeLib, initLib } from './actions';

View File

@@ -90,7 +90,7 @@ export default class JitsiMeetLogStorage {
storeLogsCallstats(logEntries: Array<string | any>) {
const conference = getCurrentConference(this.getState());
if (!conference || !conference.isCallstatsEnabled()) {
if (!conference?.isCallstatsEnabled()) {
// Discard the logs if CallStats is not enabled.
return;
}

View File

@@ -1,6 +1,6 @@
import { NativeModules } from 'react-native';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
// @ts-expect-error
import { format } from 'util';
// Some code adapted from https://github.com/houserater/react-native-lumberjack

View File

@@ -1,4 +1,4 @@
// @ts-ignore
// @ts-expect-error
import Logger, { getLogger as _getLogger } from '@jitsi/logger';
import _ from 'lodash';

View File

@@ -1,4 +1,4 @@
// @ts-ignore
// @ts-expect-error
import Logger from '@jitsi/logger';
import { IStore } from '../../app/types';

View File

@@ -157,7 +157,7 @@ export function setVideoAvailable(available: boolean) {
* @returns {Function}
*/
export function setVideoMuted(
muted: boolean,
muted: boolean | number,
authority: number = VIDEO_MUTISM_AUTHORITY.USER,
ensureTrack = false) {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {

View File

@@ -1,5 +1,2 @@
// @ts-ignore
export { default as Audio } from './native/Audio';
// @ts-ignore
export { default as Video } from './native/Video';

View File

@@ -7,7 +7,6 @@ import { IReduxState, IStore } from '../../../../app/types';
import { ASPECT_RATIO_WIDE } from '../../../responsive-ui/constants';
import { storeVideoTransform } from '../../actions';
// @ts-ignore
import styles from './styles';
@@ -125,12 +124,12 @@ class VideoTransform extends Component<IProps, IState> {
/**
* The gesture handler object.
*/
gestureHandlers: Object;
gestureHandlers: any;
/**
* The initial distance of the fingers on pinch start.
*/
initialDistance: number;
initialDistance?: number;
/**
* The initial position of the finger on touch start.
@@ -234,8 +233,6 @@ class VideoTransform extends Component<IProps, IState> {
videoTransformedViewContainerStyles,
style
] }
// @ts-ignore
{ ...this.gestureHandlers.panHandlers }>
<SafeAreaView
edges = { [ 'bottom', 'left' ] }
@@ -489,7 +486,7 @@ class VideoTransform extends Component<IProps, IState> {
* @param {?Object | number} value - The value of the gesture, if any.
* @returns {void}
*/
_onGesture(type: string, value: any) {
_onGesture(type: string, value?: any) {
let transform;
switch (type) {
@@ -600,7 +597,7 @@ class VideoTransform extends Component<IProps, IState> {
this._onGesture('scale', scale);
}
} else if (gestureState.numberActiveTouches === 1
&& isNaN(this.initialDistance)
&& isNaN(this.initialDistance ?? 0)
&& this._didMove(gestureState)) {
// this is a move event
const position = this._getTouchPosition(evt);
@@ -623,11 +620,9 @@ class VideoTransform extends Component<IProps, IState> {
*/
_onPanResponderRelease() {
if (this.lastTap && Date.now() - this.lastTap < TAP_TIMEOUT_MS) {
// @ts-ignore
this._onGesture('press');
}
// @ts-ignore
delete this.initialDistance;
this.initialPosition = {
x: 0,

View File

@@ -185,7 +185,7 @@ class AudioTrack extends Component<IProps> {
* @returns {void}
*/
_attachTrack(track?: ITrack) {
if (!track || !track.jitsiTrack) {
if (!track?.jitsiTrack) {
return;
}

View File

@@ -321,7 +321,7 @@ class Video extends Component<IProps> {
* @returns {void}
*/
_attachTrack(videoTrack?: Partial<ITrack>) {
if (!videoTrack || !videoTrack.jitsiTrack) {
if (!videoTrack?.jitsiTrack) {
return;
}

View File

@@ -1,4 +1,4 @@
// @flow
import { AnyAction } from 'redux';
import {
createStartAudioOnlyEvent,
@@ -7,6 +7,7 @@ import {
createTrackMutedEvent
} from '../../analytics/AnalyticsEvents';
import { sendAnalytics } from '../../analytics/functions';
import { IStore } from '../../app/types';
import { APP_STATE_CHANGED } from '../../mobile/background/actionTypes';
import { showWarningNotification } from '../../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants';
@@ -23,6 +24,7 @@ import { getPropertyValue } from '../settings/functions.any';
import { TRACK_ADDED } from '../tracks/actionTypes';
import { destroyLocalTracks } from '../tracks/actions.any';
import { isLocalTrackMuted, isLocalVideoTrackDesktop, setTrackMuted } from '../tracks/functions.any';
import { ITrack } from '../tracks/types';
import {
SET_AUDIO_MUTED,
@@ -155,7 +157,7 @@ MiddlewareRegistry.register(store => next => action => {
* @private
* @returns {Object} The value returned by {@code next(action)}.
*/
function _appStateChanged({ dispatch, getState }, next, action) {
function _appStateChanged({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
if (navigator.product === 'ReactNative') {
const { appState } = action;
const mute = appState !== 'active' && !isLocalVideoTrackDesktop(getState());
@@ -180,7 +182,7 @@ function _appStateChanged({ dispatch, getState }, next, action) {
* @private
* @returns {Object} The value returned by {@code next(action)}.
*/
function _setAudioOnly({ dispatch, getState }, next, action) {
function _setAudioOnly({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
const { audioOnly } = action;
const state = getState();
@@ -209,7 +211,7 @@ function _setAudioOnly({ dispatch, getState }, next, action) {
* @returns {Object} The new state that is the result of the reduction of the
* specified {@code action}.
*/
function _setRoom({ dispatch, getState }, next, action) {
function _setRoom({ dispatch, getState }: IStore, next: Function, action: AnyAction) {
// Figure out the desires/intents i.e. the state of base/media. There are
// multiple desires/intents ordered by precedence such as server-side
// config, config overrides in the user-supplied URL, user's own app
@@ -222,7 +224,7 @@ function _setRoom({ dispatch, getState }, next, action) {
const videoMuted = roomIsValid ? getStartWithVideoMuted(state) : _VIDEO_INITIAL_MEDIA_STATE.muted;
sendAnalytics(
createStartMutedConfigurationEvent('local', audioMuted, videoMuted));
createStartMutedConfigurationEvent('local', audioMuted, Boolean(videoMuted)));
logger.log(
`Start muted: ${audioMuted ? 'audio, ' : ''}${
videoMuted ? 'video' : ''}`);
@@ -295,7 +297,7 @@ function _setRoom({ dispatch, getState }, next, action) {
* @private
* @returns {void}
*/
function _syncTrackMutedState({ getState }, track) {
function _syncTrackMutedState({ getState }: IStore, track: ITrack) {
const state = getState()['features/base/media'];
const mediaType = track.mediaType;
const muted = Boolean(state[mediaType].muted);

View File

@@ -1 +1 @@
import './middleware.any.js';
import './middleware.any';

View File

@@ -1,4 +1,4 @@
import './middleware.any.js';
import './middleware.any';
import { IStore } from '../../app/types';
import { showNotification } from '../../notifications/actions';

View File

@@ -1,5 +1,5 @@
import { useHeaderHeight } from '@react-navigation/elements';
import React, { ReactElement, useCallback, useEffect, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import {
Keyboard,
KeyboardAvoidingView,
@@ -8,44 +8,44 @@ import {
} from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { StyleType } from '../../styles';
import { StyleType } from '../../styles/functions.any';
type Props = {
interface IProps {
/**
* Adds bottom padding.
*/
addBottomPadding?: boolean,
addBottomPadding?: boolean;
/**
* The children component(s) of the Modal, to be rendered.
*/
children: ReactElement,
children: React.ReactNode;
/**
* Additional style to be appended to the KeyboardAvoidingView content container.
*/
contentContainerStyle?: StyleType,
contentContainerStyle?: StyleType;
/**
* Disable forced keyboard dismiss?
*/
disableForcedKeyboardDismiss?: boolean,
disableForcedKeyboardDismiss?: boolean;
/**
* Is a text input rendered at the bottom of the screen?
*/
hasBottomTextInput: boolean,
hasBottomTextInput: boolean;
/**
* Is the screen rendering a tab navigator?
*/
hasTabNavigator: boolean,
hasTabNavigator: boolean;
/**
* Additional style to be appended to the KeyboardAvoidingView.
*/
style?: StyleType
style?: StyleType;
}
const JitsiKeyboardAvoidingView = (
@@ -57,7 +57,7 @@ const JitsiKeyboardAvoidingView = (
hasTabNavigator,
hasBottomTextInput,
style
}: Props) => {
}: IProps) => {
const headerHeight = useHeaderHeight();
const insets = useSafeAreaInsets();
const [ bottomPadding, setBottomPadding ] = useState(insets.bottom);
@@ -77,11 +77,11 @@ const JitsiKeyboardAvoidingView = (
const iosVerticalOffset
= headerHeight + noNotchDevicePadding + tabNavigatorPadding;
const androidVerticalOffset = hasBottomTextInput
? headerHeight + StatusBar.currentHeight : headerHeight;
? headerHeight + Number(StatusBar.currentHeight) : headerHeight;
// Tells the view what to do with taps
const shouldSetResponse = useCallback(() => !disableForcedKeyboardDismiss);
const onRelease = useCallback(() => Keyboard.dismiss());
const shouldSetResponse = useCallback(() => !disableForcedKeyboardDismiss, []);
const onRelease = useCallback(() => Keyboard.dismiss(), []);
return (
<KeyboardAvoidingView

View File

@@ -1,59 +1,58 @@
import React from 'react';
import { View } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { Edge, SafeAreaView } from 'react-native-safe-area-context';
import { StyleType } from '../../styles';
import { StyleType } from '../../styles/functions.any';
import JitsiKeyboardAvoidingView from './JitsiKeyboardAvoidingView';
import styles from './styles';
type Props = {
interface IProps {
/**
* Adds bottom padding.
*/
addBottomPadding: boolean,
/**
* Additional style to be appended to the KeyboardAvoidingView content container.
*/
contentContainerStyle?: StyleType,
addBottomPadding?: boolean;
/**
* The children component(s) of the Modal, to be rendered.
*/
children: React.ReactNode,
children: React.ReactNode;
/**
* Additional style to be appended to the KeyboardAvoidingView content container.
*/
contentContainerStyle?: StyleType;
/**
* Disabled forced keyboard dismiss?
*/
disableForcedKeyboardDismiss?: boolean,
disableForcedKeyboardDismiss?: boolean;
/**
* Optional function that renders a footer component, if needed.
*/
footerComponent?: Function,
footerComponent?: Function;
/**
* Is a text input rendered at the bottom of the screen?
*/
hasBottomTextInput?: boolean,
hasBottomTextInput?: boolean;
/**
* Is the screen rendering a tab navigator?
*/
hasTabNavigator?: boolean,
hasTabNavigator?: boolean;
/**
* Insets for the SafeAreaView.
*/
safeAreaInsets?: Array,
safeAreaInsets?: Edge[];
/**
* Additional style to be appended to the KeyboardAvoidingView containing the content of the modal.
*/
style?: StyleType
style?: StyleType;
}
const JitsiScreen = ({
@@ -66,7 +65,7 @@ const JitsiScreen = ({
hasBottomTextInput = false,
safeAreaInsets = [ 'left', 'right' ],
style
}: Props) => {
}: IProps) => {
const renderContent = () => (
<JitsiKeyboardAvoidingView
addBottomPadding = { addBottomPadding }
@@ -80,7 +79,7 @@ const JitsiScreen = ({
style = { styles.safeArea }>
{ children }
</SafeAreaView>
{ footerComponent && footerComponent() }
{ footerComponent?.() }
</JitsiKeyboardAvoidingView>
);

View File

@@ -1,5 +1,4 @@
// @flow
import { IStateful } from '../../app/types';
import { toState } from '../../redux/functions';
/**
@@ -11,7 +10,7 @@ import { toState } from '../../redux/functions';
* features/base/config.
* @returns {number}.
*/
export function getClientWidth(stateful: Object) {
export function getClientWidth(stateful: IStateful) {
const state = toState(stateful)['features/base/responsive-ui'];
return state.clientWidth;
@@ -26,7 +25,7 @@ export function getClientWidth(stateful: Object) {
* features/base/config.
* @returns {number}.
*/
export function getClientHeight(stateful: Object) {
export function getClientHeight(stateful: IStateful) {
const state = toState(stateful)['features/base/responsive-ui'];
return state.clientHeight;

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