Compare commits

..

6 Commits

Author SHA1 Message Date
scott boone
8257e97898 removed a typo (#9244) 2021-05-26 16:04:13 -05:00
Scott Boone
4c5e89beac lowercase to fix tokens with uppercase letters (e.g., slack JWTs) 2021-05-26 16:04:04 -05:00
Jaya Allamsetty
c2ab87900c chore(deps) lib-jitsi-meet@latest
* fix(RTC): Disable simulcast for SS when using H.264. Fixes https://github.com/jitsi/docker-jitsi-meet/issues/1048

9eb4af1e80...f95a455c08
2021-05-25 12:58:38 -04:00
Tudor D. Pop
29103ce6a7 fix(virtual-background) fix track leak in preview 2021-05-25 11:54:36 -05:00
Vlad Piersec
cabeb70506 fix(vpaas): Avoid url blipping on invite dialog 2021-05-25 09:33:40 -05:00
Mihai-Andrei Uscat
e3918754c4 feat(AddPeopleDialog): Add config option to overwrite invite subject app name 2021-05-25 09:33:16 -05:00
848 changed files with 14002 additions and 40488 deletions

View File

@@ -12,7 +12,6 @@ jobs:
with:
node-version: '12.x'
- run: npm install
- name: Check if the git repository is clean
run: exit $( git status --porcelain --untracked-files=no | head -255 | wc -l )
- run: git status -s --untracked-files=no
- run: npm run lint
- run: make

View File

@@ -152,20 +152,3 @@ this model but new features should follow this new layout.
When working on an old feature, adding the necessary changes to migrate to the new
model is encouraged.
### Avoiding bundle bloat
When adding a new feature it's possible that it triggers a build failure due to the increased bundle size. We have safeguards inplace to avoid bundles growing disproportionatelly. While there are legit reasons for increasing the limits, please analyze the bundle first to make sure no unintended dependencies have been included, causing the increase in size.
First, make a production build with bundle-analysis enabled:
```
npx webpack -p --analyze-bundle
```
Then open the interactive bundle analyzer tool:
```
npx webpack-bundle-analyzer build/app-stats.json
```

View File

@@ -3,7 +3,7 @@ CLEANCSS = ./node_modules/.bin/cleancss
DEPLOY_DIR = libs
LIBJITSIMEET_DIR = node_modules/lib-jitsi-meet/
LIBFLAC_DIR = node_modules/libflacjs/dist/min/
OLM_DIR = node_modules/@matrix-org/olm
OLM_DIR = node_modules/olm
RNNOISE_WASM_DIR = node_modules/rnnoise-wasm/dist/
TFLITE_WASM = react/features/stream-effects/virtual-background/vendor/tflite
MEET_MODELS_DIR = react/features/stream-effects/virtual-background/vendor/models/

118
README.md
View File

@@ -1,88 +1,82 @@
# <p align="center">Jitsi Meet</p>
# Jitsi Meet - Secure, Simple and Scalable Video Conferences
Jitsi Meet is a set of Open Source projects which empower users to use and deploy
video conferencing platforms with state-of-the-art video quality and features.
Jitsi Meet is an open-source (Apache) WebRTC JavaScript application that uses [Jitsi Videobridge](https://jitsi.org/videobridge) to provide high quality, [secure](https://jitsi.org/security) and scalable video conferences. Jitsi Meet in action can be seen at [here at the session #482 of the VoIP Users Conference](http://youtu.be/7vFUVClsNh0).
<hr />
The Jitsi Meet client runs in your browser, without installing anything else on your computer. You can try it out at https://meet.jit.si.
<p align="center">
<img src="https://raw.githubusercontent.com/jitsi/jitsi-meet/master/readme-img1.png" width="900" />
</p>
Jitsi Meet allows very efficient collaboration. Users can stream their desktop or only some windows. It also supports shared document editing with Etherpad.
<hr />
**NOTE:** If you are looking for Jitsi as a Service (JaaS) please start [here](https://jaas.8x8.vc).
Amongst others here are the main features Jitsi Meet offers:
## Installation
* Support for all current browsers
* Mobile applications
* Web and native SDKs for integration
* HD audio and video
* Content sharing
* End-to-End Encryption
* Raise hand and reactions
* Chat with private conversations
* Polls
* Virtual backgrounds
On the client side, no installation is necessary. You just point your browser to the URL of your deployment. This section is about installing a Jitsi Meet suite on your server and hosting your own conferencing service.
And many more!
Installing Jitsi Meet is a simple experience. For Debian-based system, following the [quick install](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-quickstart) document, which uses the package system. You can also see a demonstration of the process in [this tutorial video](https://jitsi.org/tutorial).
## Using Jitsi Meet
For other systems, or if you wish to install all components manually, see the [detailed manual installation instructions](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-manual).
Using Jitsi Meet is straightforward, as it's browser based. Head over to [meet.jit.si](https://meet.jit.si) and give it a try. It's anonymous, scalable and free to use. All browsers are supported!
Installation with Docker is also available. Please see the [instruction](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker).
Using mobile? No problem, you can either use your mobile web browser or our fully-featured
mobile apps:
## Download
| Android | Android (F-Droid) | iOS |
|:-:|:-:|:-:|
| [<img src="resources/img/google-play-badge.png" height="50">](https://play.google.com/store/apps/details?id=org.jitsi.meet) | [<img src="resources/img/f-droid-badge.png" height="50">](https://f-droid.org/en/packages/org.jitsi.meet/) | [<img src="resources/img/appstore-badge.png" height="50">](https://itunes.apple.com/us/app/jitsi-meet/id1165103905) |
| Latest stable release | [![release](https://img.shields.io/badge/release-latest-green.svg)](https://github.com/jitsi/jitsi-meet/releases/latest) |
|---|---|
If you are feeling adventurous and want to get an early scoop of the features as they are being
developed you can also sign up for our open beta testing here:
You can download Debian/Ubuntu binaries:
* [stable](https://download.jitsi.org/stable/) ([instructions](https://jitsi.org/downloads/ubuntu-debian-installations-instructions/))
* [testing](https://download.jitsi.org/testing/) ([instructions](https://jitsi.org/downloads/ubuntu-debian-installations-instructions-for-testing/))
* [nightly](https://download.jitsi.org/unstable/) ([instructions](https://jitsi.org/downloads/ubuntu-debian-installations-instructions-nightly/))
You can download source archives (produced by ```make source-package```):
* [source builds](https://download.jitsi.org/jitsi-meet/src/)
### Mobile apps
* [Android](https://play.google.com/store/apps/details?id=org.jitsi.meet)
[<img src="resources/img/google-play-badge.png" height="50">](https://play.google.com/store/apps/details?id=org.jitsi.meet)
* [Android (F-Droid)](https://f-droid.org/en/packages/org.jitsi.meet/)
[<img src="resources/img/f-droid-badge.png" height="50">](https://f-droid.org/en/packages/org.jitsi.meet/)
* [iOS](https://itunes.apple.com/us/app/jitsi-meet/id1165103905)
[<img src="resources/img/appstore-badge.png" height="50">](https://itunes.apple.com/us/app/jitsi-meet/id1165103905)
You can also sign up for our open beta testing here:
* [Android](https://play.google.com/apps/testing/org.jitsi.meet)
* [iOS](https://testflight.apple.com/join/isy6ja7S)
## Running your own instance
## Release notes
If you'd like to run your own Jitsi Meet installation head over to the [handbook](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-start) to get started.
Release notes for Jitsi Meet are maintained on [this repository](https://github.com/jitsi/jitsi-meet-release-notes).
We provide Debian packages and a comprehensive Docker setup to make deployments as simple as possible.
Advanced users also have the possibility of building all the components from source.
## Development
You can check the latest releases [[here](https://jitsi.github.io/handbook/docs/releases).
## Jitsi as a Service
If you like the branding capabilities of running your own instance but you'd like
to avoid dealing with the complexity of monitoring, scaling and updates, JaaS might be
for you.
[8x8 Jitsi as a Service (JaaS)](https://jaas.8x8.vc) is an enterprise-ready video meeting platform that allows developers, organizations and businesses to easily build and deploy video solutions. With Jitsi as a Service we now give you all the power of Jitsi running on our global platform so you can focus on building secure and branded video experiences.
## Documentation
All the Jitsi Meet documentation is available in [the handbook](https://jitsi.github.io/handbook/).
## Security
For a comprehensive description of all Jitsi Meet's security aspects, please check [this link](https://jitsi.org/security).
For a detailed description of Jitsi Meet's End-to-End Encryption (E2EE) implementation,
please check [this link](https://jitsi.org/e2ee-whitepaper/).
For information on reporting security vulnerabilities in Jitsi Meet, see [SECURITY.md](./SECURITY.md).
For web development see [here](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-web), and for mobile see [here](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-mobile).
## Contributing
If you are looking to contribute to Jitsi Meet, first of all, thank you! Please
see our [guidelines for contributing](CONTRIBUTING.md).
<br />
<br />
## Embedding in external applications
<footer>
<p align="center" style="font-size: smaller;">
Built with ❤️ by the Jitsi team at <a href="https://8x8.com" target="_blank">8x8</a> and our community.
</p>
</footer>
Jitsi Meet provides a very flexible way of embedding in external applications by using the [Jitsi Meet API](doc/api.md).
## Security
The security section here was starting to feel a bit too succinct for the complexity of the topic, so we created a post that covers the topic much more broadly here: https://jitsi.org/security
The section on end-to-end encryption in that document is likely going to be one of the key points of interest: https://jitsi.org/security/#e2ee
## Security issues
For information on reporting security vulnerabilities in Jitsi Meet, see [SECURITY.md](./SECURITY.md).
## Acknowledgements
Jitsi Meet started out as a sample conferencing application using Jitsi Videobridge. It was originally developed by ESTOS' developer Philipp Hancke who then contributed it to the community where development continues with joint forces!

View File

@@ -25,5 +25,5 @@ android.enableDexingArtifactTransform.desugaring=false
android.useAndroidX=true
android.enableJetifier=true
appVersion=21.4.0
sdkVersion=3.10.0
appVersion=21.2.0
sdkVersion=3.5.0

View File

@@ -44,7 +44,7 @@ dependencies {
//noinspection GradleDynamicVersion
implementation 'org.webkit:android-jsc:+'
implementation 'com.dropbox.core:dropbox-core-sdk:4.0.1'
implementation 'com.dropbox.core:dropbox-core-sdk:3.0.8'
implementation 'com.jakewharton.timber:timber:4.7.1'
implementation 'com.squareup.duktape:duktape-android:1.3.0'
implementation 'com.google.code.gson:gson:2.8.6'
@@ -56,7 +56,6 @@ dependencies {
exclude group: 'com.android.installreferrer'
}
} else {
implementation project(':react-native-amplitude')
implementation project(':react-native-device-info')
implementation(project(":react-native-google-signin")) {
exclude group: 'com.google.android.gms'
@@ -71,14 +70,11 @@ dependencies {
implementation project(':react-native-default-preference')
implementation project(':react-native-immersive')
implementation project(':react-native-keep-awake')
implementation project(':react-native-performance')
implementation project(':react-native-slider')
implementation project(':react-native-sound')
implementation project(':react-native-splash-screen')
implementation project(':react-native-svg')
implementation project(':react-native-video')
implementation project(':react-native-webrtc')
implementation project(':react-native-webview')
implementation project(':react-native-splash-screen')
testImplementation 'junit:junit:4.12'
}
@@ -157,9 +153,16 @@ android.libraryVariants.all { def variant ->
// Bundle sounds
//
copy {
from("${projectDir}/../../sounds")
include("*.wav")
include("*.mp3")
from("${projectDir}/../../sounds/incomingMessage.wav")
from("${projectDir}/../../sounds/joined.wav")
from("${projectDir}/../../sounds/left.wav")
from("${projectDir}/../../sounds/liveStreamingOn.mp3")
from("${projectDir}/../../sounds/liveStreamingOff.mp3")
from("${projectDir}/../../sounds/outgoingRinging.wav")
from("${projectDir}/../../sounds/outgoingStart.wav")
from("${projectDir}/../../sounds/recordingOn.mp3")
from("${projectDir}/../../sounds/recordingOff.mp3")
from("${projectDir}/../../sounds/rejected.wav")
into("${assetsDir}/sounds")
}

View File

@@ -40,8 +40,7 @@
<service
android:name=".ConnectionService"
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
android:exported="true">
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
<intent-filter>
<action android:name="android.telecom.ConnectionService" />
</intent-filter>

View File

@@ -8,8 +8,6 @@ import android.text.TextUtils;
import com.dropbox.core.DbxException;
import com.dropbox.core.DbxRequestConfig;
import com.dropbox.core.android.Auth;
import com.dropbox.core.oauth.DbxCredential;
import com.dropbox.core.v2.DbxClientV2;
import com.dropbox.core.v2.users.FullAccount;
import com.dropbox.core.v2.users.SpaceAllocation;
@@ -19,6 +17,7 @@ import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.dropbox.core.android.Auth;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.module.annotations.ReactModule;
@@ -67,7 +66,7 @@ class DropboxModule
@ReactMethod
public void authorize(final Promise promise) {
if (isEnabled) {
Auth.startOAuth2PKCE(this.getCurrentActivity(), appKey, DbxRequestConfig.newBuilder(clientId).build());
Auth.startOAuth2Authentication(this.getCurrentActivity(), appKey);
this.promise = promise;
} else {
promise.reject(
@@ -182,23 +181,11 @@ class DropboxModule
@Override
public void onHostResume() {
DbxCredential credential = Auth.getDbxCredential();
if (this.promise != null ) {
if (credential != null) {
WritableMap result = Arguments.createMap();
result.putString("token", credential.getAccessToken());
result.putString("rToken", credential.getRefreshToken());
result.putDouble("expireDate", credential.getExpiresAt());
this.promise.resolve(result);
this.promise = null;
} else {
this.promise.reject("Invalid dropbox credentials");
}
String token = Auth.getOAuth2Token();
if (token != null && this.promise != null) {
this.promise.resolve(token);
this.promise = null;
}
}
}

View File

@@ -116,15 +116,12 @@ public class JitsiMeetActivityDelegate {
= ReactInstanceManagerHolder.getReactInstanceManager();
if (reactInstanceManager != null) {
try {
// Try to avoid a crash because some devices trip on this assert:
// https://github.com/facebook/react-native/blob/df4e67fe75d781d1eb264128cadf079989542755/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java#L512
// Why this happens is a mystery wrapped in an enigma.
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext != null && activity == reactContext.getCurrentActivity()) {
reactInstanceManager.onHostPause(activity);
} catch (AssertionError e) {
// There seems to be a problem in RN when resuming an Activity when
// rotation is involved and the planets align. There doesn't seem to
// be a proper solution, but since the activity is going away anyway,
// we'll YOLO-ignore the exception and hope fo the best.
// Ref: https://github.com/facebook/react-native/search?q=Pausing+an+activity+that+is+not+the+current+activity%2C+this+is+incorrect%21&type=issues
JitsiMeetLogger.e(e, "Error running onHostPause, ignoring");
}
}
}

View File

@@ -40,6 +40,10 @@ public class JitsiMeetConferenceOptions implements Parcelable {
* Room name.
*/
private String room;
/**
* Conference subject.
*/
private String subject;
/**
* JWT token used for authentication.
*/
@@ -50,16 +54,19 @@ public class JitsiMeetConferenceOptions implements Parcelable {
*/
private Bundle colorScheme;
/**
* Config. See: https://github.com/jitsi/jitsi-meet/blob/master/config.js
*/
private Bundle config;
/**
* Feature flags. See: https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/flags/constants.js
*/
private Bundle featureFlags;
/**
* Set to {@code true} to join the conference with audio / video muted or to start in audio
* only mode respectively.
*/
private Boolean audioMuted;
private Boolean audioOnly;
private Boolean videoMuted;
/**
* USer information, to be used when no token is specified.
*/
@@ -73,6 +80,10 @@ public class JitsiMeetConferenceOptions implements Parcelable {
return room;
}
public String getSubject() {
return subject;
}
public String getToken() {
return token;
}
@@ -85,6 +96,18 @@ public class JitsiMeetConferenceOptions implements Parcelable {
return featureFlags;
}
public boolean getAudioMuted() {
return audioMuted;
}
public boolean getAudioOnly() {
return audioOnly;
}
public boolean getVideoMuted() {
return videoMuted;
}
public JitsiMeetUserInfo getUserInfo() {
return userInfo;
}
@@ -95,16 +118,19 @@ public class JitsiMeetConferenceOptions implements Parcelable {
public static class Builder {
private URL serverURL;
private String room;
private String subject;
private String token;
private Bundle colorScheme;
private Bundle config;
private Bundle featureFlags;
private Boolean audioMuted;
private Boolean audioOnly;
private Boolean videoMuted;
private JitsiMeetUserInfo userInfo;
public Builder() {
config = new Bundle();
featureFlags = new Bundle();
}
@@ -136,7 +162,7 @@ public class JitsiMeetConferenceOptions implements Parcelable {
* @return - The {@link Builder} object itself so the method calls can be chained.
*/
public Builder setSubject(String subject) {
setConfigOverride("subject", subject);
this.subject = subject;
return this;
}
@@ -167,11 +193,11 @@ public class JitsiMeetConferenceOptions implements Parcelable {
/**
* Indicates the conference will be joined with the microphone muted.
* @param audioMuted - Muted indication.
* @param muted - Muted indication.
* @return - The {@link Builder} object itself so the method calls can be chained.
*/
public Builder setAudioMuted(boolean audioMuted) {
setConfigOverride("startWithAudioMuted", audioMuted);
public Builder setAudioMuted(boolean muted) {
this.audioMuted = muted;
return this;
}
@@ -183,7 +209,7 @@ public class JitsiMeetConferenceOptions implements Parcelable {
* @return - The {@link Builder} object itself so the method calls can be chained.
*/
public Builder setAudioOnly(boolean audioOnly) {
setConfigOverride("startAudioOnly", audioOnly);
this.audioOnly = audioOnly;
return this;
}
@@ -193,7 +219,7 @@ public class JitsiMeetConferenceOptions implements Parcelable {
* @return - The {@link Builder} object itself so the method calls can be chained.
*/
public Builder setVideoMuted(boolean videoMuted) {
setConfigOverride("startWithVideoMuted", videoMuted);
this.videoMuted = videoMuted;
return this;
}
@@ -235,36 +261,6 @@ public class JitsiMeetConferenceOptions implements Parcelable {
return this;
}
public Builder setConfigOverride(String config, String value) {
this.config.putString(config, value);
return this;
}
public Builder setConfigOverride(String config, int value) {
this.config.putInt(config, value);
return this;
}
public Builder setConfigOverride(String config, boolean value) {
this.config.putBoolean(config, value);
return this;
}
public Builder setConfigOverride(String config, Bundle bundle) {
this.config.putBundle(config, bundle);
return this;
}
public Builder setConfigOverride(String config, String[] list) {
this.config.putStringArray(config, list);
return this;
}
/**
* Builds the immutable {@link JitsiMeetConferenceOptions} object with the configuration
* that this {@link Builder} instance specified.
@@ -275,10 +271,13 @@ public class JitsiMeetConferenceOptions implements Parcelable {
options.serverURL = this.serverURL;
options.room = this.room;
options.subject = this.subject;
options.token = this.token;
options.colorScheme = this.colorScheme;
options.config = this.config;
options.featureFlags = this.featureFlags;
options.audioMuted = this.audioMuted;
options.audioOnly = this.audioOnly;
options.videoMuted = this.videoMuted;
options.userInfo = this.userInfo;
return options;
@@ -291,12 +290,17 @@ public class JitsiMeetConferenceOptions implements Parcelable {
private JitsiMeetConferenceOptions(Parcel in) {
serverURL = (URL) in.readSerializable();
room = in.readString();
subject = in.readString();
token = in.readString();
colorScheme = in.readBundle();
config = in.readBundle();
featureFlags = in.readBundle();
userInfo = new JitsiMeetUserInfo(in.readBundle());
byte tmpAudioMuted = in.readByte();
audioMuted = tmpAudioMuted == 0 ? null : tmpAudioMuted == 1;
byte tmpAudioOnly = in.readByte();
audioOnly = tmpAudioOnly == 0 ? null : tmpAudioOnly == 1;
byte tmpVideoMuted = in.readByte();
videoMuted = tmpVideoMuted == 0 ? null : tmpVideoMuted == 1;
}
Bundle asProps() {
@@ -313,6 +317,21 @@ public class JitsiMeetConferenceOptions implements Parcelable {
props.putBundle("colorScheme", colorScheme);
}
Bundle config = new Bundle();
if (audioMuted != null) {
config.putBoolean("startWithAudioMuted", audioMuted);
}
if (audioOnly != null) {
config.putBoolean("startAudioOnly", audioOnly);
}
if (videoMuted != null) {
config.putBoolean("startWithVideoMuted", videoMuted);
}
if (subject != null) {
config.putString("subject", subject);
}
Bundle urlProps = new Bundle();
// The room is fully qualified
@@ -360,11 +379,14 @@ public class JitsiMeetConferenceOptions implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeSerializable(serverURL);
dest.writeString(room);
dest.writeString(subject);
dest.writeString(token);
dest.writeBundle(colorScheme);
dest.writeBundle(config);
dest.writeBundle(featureFlags);
dest.writeBundle(userInfo != null ? userInfo.asBundle() : new Bundle());
dest.writeByte((byte) (audioMuted == null ? 0 : audioMuted ? 1 : 2));
dest.writeByte((byte) (audioOnly == null ? 0 : audioOnly ? 1 : 2));
dest.writeByte((byte) (videoMuted == null ? 0 : videoMuted ? 1 : 2));
}
@Override

View File

@@ -47,7 +47,7 @@ class LocaleDetector extends ReactContextBaseJavaModule {
public Map<String, Object> getConstants() {
Context context = getReactApplicationContext();
HashMap<String,Object> constants = new HashMap<>();
constants.put("locale", context.getResources().getConfiguration().locale.toLanguageTag());
constants.put("locale", context.getResources().getConfiguration().locale.toString());
return constants;
}
@@ -55,4 +55,4 @@ class LocaleDetector extends ReactContextBaseJavaModule {
public String getName() {
return "LocaleDetector";
}
}
}

View File

@@ -1,11 +0,0 @@
package org.jitsi.meet.sdk;
import java.util.ArrayList;
import java.util.List;
public class NotificationChannels {
static final String ONGOING_CONFERENCE_CHANNEL_ID = "JitsiOngoingConferenceChannel";
static final String ONGOING_CONFERNCE_CHANNEL_NAME = "Ongoing Conference Notifications";
public static List<String> allIds = new ArrayList<String>() {{ add(ONGOING_CONFERENCE_CHANNEL_ID); }};
}

View File

@@ -16,9 +16,6 @@
package org.jitsi.meet.sdk;
import static org.jitsi.meet.sdk.NotificationChannels.ONGOING_CONFERENCE_CHANNEL_ID;
import static org.jitsi.meet.sdk.NotificationChannels.ONGOING_CONFERNCE_CHANNEL_NAME;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -42,6 +39,9 @@ import java.util.Random;
class OngoingNotification {
private static final String TAG = OngoingNotification.class.getSimpleName();
private static final String CHANNEL_ID = "JitsiNotificationChannel";
private static final String CHANNEL_NAME = "Ongoing Conference Notifications";
static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
private static long startingTime = 0;
@@ -60,13 +60,13 @@ class OngoingNotification {
= (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel
= notificationManager.getNotificationChannel(ONGOING_CONFERENCE_CHANNEL_ID);
= notificationManager.getNotificationChannel(CHANNEL_ID);
if (channel != null) {
// The channel was already created, no need to do it again.
return;
}
channel = new NotificationChannel(ONGOING_CONFERENCE_CHANNEL_ID, ONGOING_CONFERNCE_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(false);
channel.enableVibration(false);
channel.setShowBadge(false);
@@ -84,7 +84,7 @@ class OngoingNotification {
Intent notificationIntent = new Intent(context, context.getClass());
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, ONGOING_CONFERENCE_CHANNEL_ID);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
if (startingTime == 0) {
startingTime = System.currentTimeMillis();

View File

@@ -174,7 +174,7 @@ class ReactInstanceManagerHolder {
return;
}
SoLoader.init(activity.getApplication(), /* native exopackage */ false);
SoLoader.init(activity, /* native exopackage */ false);
List<ReactPackage> packages
= new ArrayList<>(Arrays.asList(
@@ -184,15 +184,12 @@ class ReactInstanceManagerHolder {
new com.horcrux.svg.SvgPackage(),
new com.kevinresol.react_native_default_preference.RNDefaultPreferencePackage(),
new com.learnium.RNDeviceInfo.RNDeviceInfo(),
new com.oblador.performance.PerformancePackage(),
new com.ocetnik.timer.BackgroundTimerPackage(),
new com.reactnativecommunity.asyncstorage.AsyncStoragePackage(),
new com.reactnativecommunity.netinfo.NetInfoPackage(),
new com.reactnativecommunity.slider.ReactSliderPackage(),
new com.reactnativecommunity.webview.RNCWebViewPackage(),
new com.rnimmersive.RNImmersivePackage(),
new com.zmxv.RNSound.RNSoundPackage(),
new com.brentvatne.react.ReactVideoPackage(),
new ReactPackageAdapter() {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
@@ -204,16 +201,6 @@ class ReactInstanceManagerHolder {
}
}));
// AmplitudeReactNativePackage
try {
Class<?> amplitudePackageClass = Class.forName("com.amplitude.reactnative.AmplitudeReactNativePackage");
Constructor constructor = amplitudePackageClass.getConstructor();
packages.add((ReactPackage)constructor.newInstance());
} catch (Exception e) {
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
}
// RNGoogleSigninPackage
try {
Class<?> googlePackageClass = Class.forName("co.apptailor.googlesignin.RNGoogleSigninPackage");
Constructor constructor = googlePackageClass.getConstructor();

View File

@@ -1,8 +1,6 @@
rootProject.name = 'jitsi-meet'
include ':app', ':sdk'
include ':react-native-amplitude'
project(':react-native-amplitude').projectDir = new File(rootProject.projectDir, '../node_modules/@amplitude/react-native//android')
include ':react-native-async-storage'
project(':react-native-async-storage').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-async-storage/async-storage/android')
include ':react-native-background-timer'
@@ -21,19 +19,13 @@ include ':react-native-immersive'
project(':react-native-immersive').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-immersive/android')
include ':react-native-keep-awake'
project(':react-native-keep-awake').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keep-awake/android')
include ':react-native-performance'
project(':react-native-performance').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-performance/android')
include ':react-native-slider'
project(':react-native-slider').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/slider/android')
include ':react-native-sound'
project(':react-native-sound').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sound/android')
include ':react-native-splash-screen'
project(':react-native-splash-screen').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-splash-screen/android')
include ':react-native-svg'
project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-svg/android')
include ':react-native-video'
project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android')
include ':react-native-webrtc'
project(':react-native-webrtc').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webrtc/android')
include ':react-native-webview'
project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android')
project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android')

2
app.js
View File

@@ -2,7 +2,7 @@
import 'jquery';
import '@matrix-org/olm';
import 'olm';
import 'focus-visible';

View File

@@ -1,9 +0,0 @@
module.exports = {
presets: [ 'module:metro-react-native-babel-preset' ],
env: {
production: {
plugins: [ 'react-native-paper/babel' ]
}
},
plugins: [ 'optional-require' ]
};

View File

@@ -24,8 +24,6 @@ import {
redirectToStaticPage,
reloadWithStoredParams
} from './react/features/app/actions';
import { showModeratedNotification } from './react/features/av-moderation/actions';
import { shouldShowModeratedNotification } from './react/features/av-moderation/functions';
import {
AVATAR_URL_COMMAND,
EMAIL_COMMAND,
@@ -41,15 +39,12 @@ import {
conferenceWillJoin,
conferenceWillLeave,
dataChannelOpened,
getConferenceOptions,
kickedOut,
lockStateChanged,
onStartMutedPolicyChanged,
p2pStatusChanged,
sendLocalParticipant,
_conferenceWillJoin
sendLocalParticipant
} from './react/features/base/conference';
import { getReplaceParticipant } from './react/features/base/config/functions';
import {
checkAndNotifyForNewDevice,
getAvailableDevices,
@@ -59,7 +54,6 @@ import {
setAudioOutputDeviceId,
updateDeviceList
} from './react/features/base/devices';
import { isIosMobileBrowser } from './react/features/base/environment/utils';
import {
browser,
isFatalJitsiConnectionError,
@@ -116,13 +110,14 @@ import {
trackRemoved
} from './react/features/base/tracks';
import { downloadJSON } from './react/features/base/util/downloadJSON';
import { getConferenceOptions } from './react/features/conference/functions';
import { showDesktopPicker } from './react/features/desktop-picker';
import { appendSuffix } from './react/features/display-name';
import {
maybeOpenFeedbackDialog,
submitFeedback
} from './react/features/feedback';
import { isModerationNotificationDisplayed, showNotification } from './react/features/notifications';
import { showNotification } from './react/features/notifications';
import { mediaPermissionPromptVisibilityChanged, toggleSlowGUMOverlay } from './react/features/overlay';
import { suspendDetected } from './react/features/power-monitor';
import {
@@ -134,9 +129,9 @@ import {
import { disableReceiver, stopReceiver } from './react/features/remote-control';
import { setScreenAudioShareState, isScreenAudioShared } from './react/features/screen-share/';
import { toggleScreenshotCaptureEffect } from './react/features/screenshot-capture';
import { setSharedVideoStatus } from './react/features/shared-video/actions';
import { AudioMixerEffect } from './react/features/stream-effects/audio-mixer/AudioMixerEffect';
import { createPresenterEffect } from './react/features/stream-effects/presenter';
import { createRnnoiseProcessor } from './react/features/stream-effects/rnnoise';
import { endpointMessageReceived } from './react/features/subtitles';
import UIEvents from './service/UI/UIEvents';
@@ -182,7 +177,8 @@ const commands = {
AVATAR_URL: AVATAR_URL_COMMAND,
CUSTOM_ROLE: 'custom-role',
EMAIL: EMAIL_COMMAND,
ETHERPAD: 'etherpad'
ETHERPAD: 'etherpad',
SHARED_VIDEO: 'shared-video'
};
/**
@@ -310,13 +306,10 @@ class ConferenceConnector {
// not enough rights to create conference
case JitsiConferenceErrors.AUTHENTICATION_REQUIRED: {
const replaceParticipant = getReplaceParticipant(APP.store.getState());
// Schedule reconnect to check if someone else created the room.
this.reconnectTimeout = setTimeout(() => {
APP.store.dispatch(conferenceWillJoin(room));
room.join(null, replaceParticipant);
room.join();
}, 5000);
const { password }
@@ -402,10 +395,8 @@ class ConferenceConnector {
*
*/
connect() {
const replaceParticipant = getReplaceParticipant(APP.store.getState());
// the local storage overrides here and in connection.js can be used by jibri
room.join(jitsiLocalStorage.getItem('xmpp_conference_password_override'), replaceParticipant);
room.join(jitsiLocalStorage.getItem('xmpp_conference_password_override'));
}
}
@@ -457,12 +448,27 @@ export default {
isSharingScreen: false,
/**
* The local audio track (if any).
* FIXME tracks from redux store should be the single source of truth
* @type {JitsiLocalTrack|null}
*/
localAudio: null,
/**
* The local presenter video track (if any).
* @type {JitsiLocalTrack|null}
*/
localPresenterVideo: null,
/**
* The local video track (if any).
* FIXME tracks from redux store should be the single source of truth, but
* more refactoring is required around screen sharing ('localVideo' usages).
* @type {JitsiLocalTrack|null}
*/
localVideo: null,
/**
* Returns an object containing a promise which resolves with the created tracks &
* the errors resulting from that process.
@@ -716,7 +722,9 @@ export default {
track.mute();
}
});
logger.log(`Initialized with ${tracks.length} local tracks`);
this._localTracksInitialized = true;
con.addEventListener(JitsiConnectionEvents.CONNECTION_FAILED, _connectionFailedHandler);
APP.connection = connection = con;
@@ -821,13 +829,7 @@ export default {
this._initDeviceList(true);
if (initialOptions.startWithAudioMuted) {
// Always add the audio track to the peer connection and then mute the track on mobile Safari
// because of a known issue where audio playout doesn't happen if the user joins audio and video muted.
if (isIosMobileBrowser()) {
this.muteAudio(true, true);
} else {
localTracks = localTracks.filter(track => track.getType() !== MEDIA_TYPE.AUDIO);
}
localTracks = localTracks.filter(track => track.getType() !== MEDIA_TYPE.AUDIO);
}
return this.startConference(con, localTracks);
@@ -873,24 +875,13 @@ export default {
* dialogs in case of media permissions error.
*/
muteAudio(mute, showUI = true) {
const state = APP.store.getState();
if (!mute
&& isUserInteractionRequiredForUnmute(state)) {
&& isUserInteractionRequiredForUnmute(APP.store.getState())) {
logger.error('Unmuting audio requires user interaction');
return;
}
// check for A/V Moderation when trying to unmute
if (!mute && shouldShowModeratedNotification(MEDIA_TYPE.AUDIO, state)) {
if (!isModerationNotificationDisplayed(MEDIA_TYPE.AUDIO, state)) {
APP.store.dispatch(showModeratedNotification(MEDIA_TYPE.AUDIO));
}
return;
}
// Not ready to modify track's state yet
if (!this._localTracksInitialized) {
// This will only modify base/media.audio.muted which is then synced
@@ -904,9 +895,7 @@ export default {
return;
}
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
if (!localAudio && !mute) {
if (!this.localAudio && !mute) {
const maybeShowErrorDialog = error => {
showUI && APP.store.dispatch(notifyMicError(error));
};
@@ -960,18 +949,17 @@ export default {
const maybeShowErrorDialog = error => {
showUI && APP.store.dispatch(notifyCameraError(error));
};
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
if (mute) {
try {
await localVideo.setEffect(undefined);
await this.localVideo.setEffect(undefined);
} catch (err) {
logger.error('Failed to remove the presenter effect', err);
maybeShowErrorDialog(err);
}
} else {
try {
await localVideo.setEffect(await this._createPresenterStreamEffect());
await this.localVideo.setEffect(await this._createPresenterStreamEffect());
} catch (err) {
logger.error('Failed to apply the presenter effect', err);
maybeShowErrorDialog(err);
@@ -1013,9 +1001,7 @@ export default {
return;
}
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
if (!localVideo && !mute) {
if (!this.localVideo && !mute) {
const maybeShowErrorDialog = error => {
showUI && APP.store.dispatch(notifyCameraError(error));
};
@@ -1101,6 +1087,17 @@ export default {
return room && room.isCallstatsEnabled();
},
/**
* Sends the given feedback through CallStats if enabled.
*
* @param overallFeedback an integer between 1 and 5 indicating the
* user feedback
* @param detailedFeedback detailed feedback from the user. Not yet used
*/
sendFeedback(overallFeedback, detailedFeedback) {
return room.sendFeedback(overallFeedback, detailedFeedback);
},
/**
* Get speaker stats that track total dominant speaker time.
*
@@ -1329,14 +1326,14 @@ export default {
APP.conference.roomName,
this._getConferenceOptions());
// Filter out the tracks that are muted (except on mobile Safari).
const tracks = isIosMobileBrowser() ? localTracks : localTracks.filter(track => !track.isMuted());
APP.store.dispatch(conferenceWillJoin(room));
// Filter out the tracks that are muted.
const tracks = localTracks.filter(track => !track.isMuted());
this._setLocalAudioVideoStreams(tracks);
this._room = room; // FIXME do not use this
APP.store.dispatch(_conferenceWillJoin(room));
sendLocalParticipant(APP.store, room);
this._setupListeners();
@@ -1349,7 +1346,7 @@ export default {
* @private
*/
_setLocalAudioVideoStreams(tracks = []) {
const promises = tracks.map(track => {
return tracks.map(track => {
if (track.isAudioTrack()) {
return this.useAudioStream(track);
} else if (track.isVideoTrack()) {
@@ -1358,24 +1355,16 @@ export default {
return this.useVideoStream(track);
}
logger.error('Ignored not an audio nor a video track: ', track);
logger.error(
'Ignored not an audio nor a video track: ', track);
return Promise.resolve();
});
return Promise.allSettled(promises).then(() => {
this._localTracksInitialized = true;
logger.log(`Initialized with ${tracks.length} local tracks`);
});
},
_getConferenceOptions() {
const options = getConferenceOptions(APP.store.getState());
options.createVADProcessor = createRnnoiseProcessor;
return options;
return getConferenceOptions(APP.store.getState());
},
/**
@@ -1389,20 +1378,29 @@ export default {
return new Promise((resolve, reject) => {
_replaceLocalVideoTrackQueue.enqueue(onFinish => {
const oldTrack = getLocalJitsiVideoTrack(APP.store.getState());
const state = APP.store.getState();
logger.debug(`useVideoStream: Replacing ${oldTrack} with ${newTrack}`);
// When the prejoin page is displayed localVideo is not set
// so just replace the video track from the store with the new one.
if (isPrejoinPageVisible(state)) {
const oldTrack = getLocalJitsiVideoTrack(state);
if (oldTrack === newTrack) {
resolve();
onFinish();
logger.debug(`useVideoStream on the prejoin screen: Replacing ${oldTrack} with ${newTrack}`);
return;
return APP.store.dispatch(replaceLocalTrack(oldTrack, newTrack))
.then(resolve)
.catch(error => {
logger.error(`useVideoStream failed on the prejoin screen: ${error}`);
reject(error);
})
.then(onFinish);
}
logger.debug(`useVideoStream: Replacing ${this.localVideo} with ${newTrack}`);
APP.store.dispatch(
replaceLocalTrack(oldTrack, newTrack, room))
replaceLocalTrack(this.localVideo, newTrack, room))
.then(() => {
this.localVideo = newTrack;
this._setSharingScreen(newTrack);
this.setVideoMuteStatus();
})
@@ -1452,18 +1450,23 @@ export default {
useAudioStream(newTrack) {
return new Promise((resolve, reject) => {
_replaceLocalAudioTrackQueue.enqueue(onFinish => {
const oldTrack = getLocalJitsiAudioTrack(APP.store.getState());
const state = APP.store.getState();
if (oldTrack === newTrack) {
resolve();
onFinish();
// When the prejoin page is displayed localAudio is not set
// so just replace the audio track from the store with the new one.
if (isPrejoinPageVisible(state)) {
const oldTrack = getLocalJitsiAudioTrack(state);
return;
return APP.store.dispatch(replaceLocalTrack(oldTrack, newTrack))
.then(resolve)
.catch(reject)
.then(onFinish);
}
APP.store.dispatch(
replaceLocalTrack(oldTrack, newTrack, room))
replaceLocalTrack(this.localAudio, newTrack, room))
.then(() => {
this.localAudio = newTrack;
this.setAudioMuteStatus(this.isLocalAudioMuted());
})
.then(resolve)
@@ -1503,14 +1506,14 @@ export default {
*
* @param {boolean} didHaveVideo indicates if there was a camera video being
* used, before switching to screen sharing.
* @param {boolean} ignoreDidHaveVideo indicates if the camera video should be
* ignored when switching screen sharing off.
* @param {boolean} wasVideoMuted indicates if the video was muted, before
* switching to screen sharing.
* @return {Promise} resolved after the screen sharing is turned off, or
* rejected with some error (no idea what kind of error, possible GUM error)
* in case it fails.
* @private
*/
async _turnScreenSharingOff(didHaveVideo, ignoreDidHaveVideo) {
async _turnScreenSharingOff(didHaveVideo) {
this._untoggleScreenSharing = null;
this.videoSwitchInProgress = true;
@@ -1538,9 +1541,7 @@ export default {
// If system audio was also shared stop the AudioMixerEffect and dispose of the desktop audio track.
if (this._mixerEffect) {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
await localAudio.setEffect(undefined);
await this.localAudio.setEffect(undefined);
await this._desktopAudioStream.dispose();
this._mixerEffect = undefined;
this._desktopAudioStream = undefined;
@@ -1554,7 +1555,7 @@ export default {
APP.store.dispatch(setScreenAudioShareState(false));
if (didHaveVideo && !ignoreDidHaveVideo) {
if (didHaveVideo) {
promise = promise.then(() => createLocalTracksF({ devices: [ 'video' ] }))
.then(([ stream ]) => {
logger.debug(`_turnScreenSharingOff using ${stream} for useVideoStream`);
@@ -1605,10 +1606,9 @@ export default {
* @param {Array<string>} [options.desktopSharingSources] - Array with the
* sources that have to be displayed in the desktop picker window ('screen',
* 'window', etc.).
* @param {boolean} ignoreDidHaveVideo - if true ignore if video was on when sharing started.
* @return {Promise.<T>}
*/
async toggleScreenSharing(toggle = !this._untoggleScreenSharing, options = {}, ignoreDidHaveVideo) {
async toggleScreenSharing(toggle = !this._untoggleScreenSharing, options = {}) {
logger.debug(`toggleScreenSharing: ${toggle}`);
if (this.videoSwitchInProgress) {
return Promise.reject('Switch in progress.');
@@ -1634,7 +1634,7 @@ export default {
}
return this._untoggleScreenSharing
? this._untoggleScreenSharing(ignoreDidHaveVideo)
? this._untoggleScreenSharing()
: Promise.resolve();
},
@@ -1767,8 +1767,7 @@ export default {
// Create a new presenter track and apply the presenter effect.
if (!this.localPresenterVideo && !mute) {
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
const { height, width } = localVideo.track.getSettings() ?? localVideo.track.getConstraints();
const { height, width } = this.localVideo.track.getSettings() ?? this.localVideo.track.getConstraints();
const isPortrait = height >= width;
const DESKTOP_STREAM_CAP = 720;
@@ -1797,7 +1796,7 @@ export default {
// Apply the constraints on the desktop track.
try {
await localVideo.track.applyConstraints(desktopResizeConstraints);
await this.localVideo.track.applyConstraints(desktopResizeConstraints);
} catch (err) {
logger.error('Failed to apply constraints on the desktop stream for presenter mode', err);
@@ -1805,7 +1804,7 @@ export default {
}
}
const trackHeight = resizeDesktopStream
? localVideo.track.getSettings().height ?? DESKTOP_STREAM_CAP
? this.localVideo.track.getSettings().height ?? DESKTOP_STREAM_CAP
: height;
let effect;
@@ -1820,7 +1819,7 @@ export default {
// Replace the desktop track on the peerconnection.
try {
await localVideo.setEffect(effect);
await this.localVideo.setEffect(effect);
APP.store.dispatch(setVideoMuted(mute, MEDIA_TYPE.PRESENTER));
this.setVideoMuteStatus();
} catch (err) {
@@ -1875,15 +1874,14 @@ export default {
await this.useVideoStream(desktopVideoStream);
}
if (this._desktopAudioStream) {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
if (this._desktopAudioStream) {
// If there is a localAudio stream, mix in the desktop audio stream captured by the screen sharing
// api.
if (localAudio) {
if (this.localAudio) {
this._mixerEffect = new AudioMixerEffect(this._desktopAudioStream);
await localAudio.setEffect(this._mixerEffect);
await this.localAudio.setEffect(this._mixerEffect);
} else {
// If no local stream is present ( i.e. no input audio devices) we use the screen share audio
// stream as we would use a regular stream.
@@ -1987,12 +1985,7 @@ export default {
room.on(
JitsiConferenceEvents.CONFERENCE_UNIQUE_ID_SET,
(...args) => {
// Preserve the sessionId so that the value is accessible even after room
// is disconnected.
room.sessionId = room.getMeetingUniqueId();
APP.store.dispatch(conferenceUniqueIdSet(room, ...args));
});
(...args) => APP.store.dispatch(conferenceUniqueIdSet(room, ...args)));
room.on(
JitsiConferenceEvents.AUTH_STATUS_CHANGED,
@@ -2024,6 +2017,8 @@ export default {
}
logger.log(`USER ${id} LEFT:`, user);
APP.UI.onSharedVideoStop(id);
});
room.on(JitsiConferenceEvents.USER_STATUS_CHANGED, (id, status) => {
@@ -2064,10 +2059,10 @@ export default {
});
room.on(JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED, (id, lvl) => {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
let newLvl = lvl;
if (this.isLocalId(id) && localAudio?.isMuted()) {
if (this.isLocalId(id)
&& this.localAudio && this.localAudio.isMuted()) {
newLvl = 0;
}
@@ -2111,7 +2106,7 @@ export default {
room.on(
JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED,
(dominant, previous) => APP.store.dispatch(dominantSpeakerChanged(dominant, previous, room)));
id => APP.store.dispatch(dominantSpeakerChanged(id, room)));
room.on(
JitsiConferenceEvents.CONFERENCE_CREATED_TIMESTAMP,
@@ -2182,24 +2177,7 @@ export default {
JitsiConferenceEvents.LOCK_STATE_CHANGED,
(...args) => APP.store.dispatch(lockStateChanged(room, ...args)));
room.on(JitsiConferenceEvents.KICKED, (participant, reason, isReplaced) => {
if (isReplaced) {
// this event triggers when the local participant is kicked, `participant`
// is the kicker. In replace participant case, kicker is undefined,
// as the server initiated it. We mark in store the local participant
// as being replaced based on jwt.
const localParticipant = getLocalParticipant(APP.store.getState());
APP.store.dispatch(participantUpdated({
conference: room,
id: localParticipant.id,
isReplaced
}));
// we send readyToClose when kicked participant is replace so that
// embedding app can choose to dispose the iframe API on the handler.
APP.API.notifyReadyToClose();
}
room.on(JitsiConferenceEvents.KICKED, participant => {
APP.store.dispatch(kickedOut(room, participant));
});
@@ -2266,9 +2244,7 @@ export default {
// Remove the tracks from the peerconnection.
for (const track of localTracks) {
// Always add the track on mobile Safari because of a known issue where audio playout doesn't happen
// if the user joins audio and video muted.
if (audioMuted && track.jitsiTrack?.getType() === MEDIA_TYPE.AUDIO && !isIosMobileBrowser()) {
if (audioMuted && track.jitsiTrack?.getType() === MEDIA_TYPE.AUDIO) {
promises.push(this.useAudioStream(null));
}
if (videoMuted && track.jitsiTrack?.getType() === MEDIA_TYPE.VIDEO) {
@@ -2309,7 +2285,6 @@ export default {
APP.UI.addListener(
UIEvents.VIDEO_DEVICE_CHANGED,
cameraDeviceId => {
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
const videoWasMuted = this.isLocalVideoMuted();
sendAnalytics(createDeviceChangedEvent('video', 'input'));
@@ -2317,7 +2292,7 @@ export default {
// If both screenshare and video are in progress, restart the
// presenter mode with the new camera device.
if (this.isSharingScreen && !videoWasMuted) {
const { height } = localVideo.track.getSettings();
const { height } = this.localVideo.track.getSettings();
// dispose the existing presenter track and create a new
// camera track.
@@ -2326,7 +2301,7 @@ export default {
this.localPresenterVideo = null;
return this._createPresenterStreamEffect(height, cameraDeviceId)
.then(effect => localVideo.setEffect(effect))
.then(effect => this.localVideo.setEffect(effect))
.then(() => {
this.setVideoMuteStatus();
logger.log('Switched local video device while screen sharing and the video is unmuted');
@@ -2339,7 +2314,7 @@ export default {
// that can be applied on un-mute.
} else if (this.isSharingScreen && videoWasMuted) {
logger.log('Switched local video device: while screen sharing and the video is muted');
const { height } = localVideo.track.getSettings();
const { height } = this.localVideo.track.getSettings();
this._updateVideoDeviceId();
@@ -2425,15 +2400,13 @@ export default {
return this.useAudioStream(stream);
})
.then(() => {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
if (localAudio && hasDefaultMicChanged) {
if (this.localAudio && hasDefaultMicChanged) {
// workaround for the default device to be shown as selected in the
// settings even when the real device id was passed to gUM because of the
// above mentioned chrome bug.
localAudio._realDeviceId = localAudio.deviceId = 'default';
this.localAudio._realDeviceId = this.localAudio.deviceId = 'default';
}
logger.log(`switched local audio device: ${localAudio?.getDeviceId()}`);
logger.log(`switched local audio device: ${this.localAudio?.getDeviceId()}`);
this._updateAudioDeviceId();
})
@@ -2477,10 +2450,63 @@ export default {
});
APP.UI.addListener(
UIEvents.TOGGLE_SCREENSHARING, ({ enabled, audioOnly, ignoreDidHaveVideo }) => {
this.toggleScreenSharing(enabled, { audioOnly }, ignoreDidHaveVideo);
UIEvents.TOGGLE_SCREENSHARING, audioOnly => {
this.toggleScreenSharing(undefined, { audioOnly });
}
);
/* eslint-disable max-params */
APP.UI.addListener(
UIEvents.UPDATE_SHARED_VIDEO,
(url, state, time, isMuted, volume) => {
/* eslint-enable max-params */
// send start and stop commands once, and remove any updates
// that had left
if (state === 'stop'
|| state === 'start'
|| state === 'playing') {
const localParticipant = getLocalParticipant(APP.store.getState());
room.removeCommand(this.commands.defaults.SHARED_VIDEO);
room.sendCommandOnce(this.commands.defaults.SHARED_VIDEO, {
value: url,
attributes: {
state,
time,
muted: isMuted,
volume,
from: localParticipant.id
}
});
} else {
// in case of paused, in order to allow late users to join
// paused
room.removeCommand(this.commands.defaults.SHARED_VIDEO);
room.sendCommand(this.commands.defaults.SHARED_VIDEO, {
value: url,
attributes: {
state,
time,
muted: isMuted,
volume
}
});
}
APP.store.dispatch(setSharedVideoStatus(state));
});
room.addCommandListener(
this.commands.defaults.SHARED_VIDEO,
({ value, attributes }, id) => {
if (attributes.state === 'stop') {
APP.UI.onSharedVideoStop(id, attributes);
} else if (attributes.state === 'start') {
APP.UI.onSharedVideoStart(id, value, attributes);
} else if (attributes.state === 'playing'
|| attributes.state === 'pause') {
APP.UI.onSharedVideoUpdate(id, value, attributes);
}
});
},
/**
@@ -2499,6 +2525,9 @@ export default {
JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED,
this.deviceChangeListener);
}
this.localVideo = null;
this.localAudio = null;
},
/**
@@ -2561,11 +2590,10 @@ export default {
* @private
*/
_updateVideoDeviceId() {
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
if (localVideo && localVideo.videoType === 'camera') {
if (this.localVideo
&& this.localVideo.videoType === 'camera') {
APP.store.dispatch(updateSettings({
cameraDeviceId: localVideo.getDeviceId()
cameraDeviceId: this.localVideo.getDeviceId()
}));
}
@@ -2583,11 +2611,9 @@ export default {
* @private
*/
_updateAudioDeviceId() {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
if (localAudio) {
if (this.localAudio) {
APP.store.dispatch(updateSettings({
micDeviceId: localAudio.getDeviceId()
micDeviceId: this.localAudio.getDeviceId()
}));
}
},
@@ -2601,8 +2627,6 @@ export default {
*/
_onDeviceListChanged(devices) {
const oldDevices = APP.store.getState()['features/base/devices'].availableDevices;
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
APP.store.dispatch(updateDeviceList(devices));
@@ -2610,8 +2634,8 @@ export default {
= mediaDeviceHelper.getNewMediaDevicesAfterDeviceListChanged(
devices,
this.isSharingScreen,
localVideo,
localAudio);
this.localVideo,
this.localAudio);
const promises = [];
const audioWasMuted = this.isLocalAudioMuted();
const videoWasMuted = this.isLocalVideoMuted();
@@ -2634,12 +2658,12 @@ export default {
// simpler):
// If the default device is changed we need to first stop the local streams and then call GUM. Otherwise GUM
// will return a stream using the old default device.
if (requestedInput.audio && localAudio) {
localAudio.stopStream();
if (requestedInput.audio && this.localAudio) {
this.localAudio.stopStream();
}
if (requestedInput.video && localVideo) {
localVideo.stopStream();
if (requestedInput.video && this.localVideo) {
this.localVideo.stopStream();
}
// Let's handle unknown/non-preferred devices
@@ -2719,16 +2743,15 @@ export default {
= mediaType === 'audio'
? this.useAudioStream.bind(this)
: this.useVideoStream.bind(this);
const track = tracks.find(t => t.getType() === mediaType) || null;
// Use the new stream or null if we failed to obtain it.
return useStream(track)
return useStream(tracks.find(track => track.getType() === mediaType) || null)
.then(() => {
if (track?.isAudioTrack() && hasDefaultMicChanged) {
if (this.localAudio && hasDefaultMicChanged) {
// workaround for the default device to be shown as selected in the
// settings even when the real device id was passed to gUM because of
// the above mentioned chrome bug.
track._realDeviceId = track.deviceId = 'default';
this.localAudio._realDeviceId = this.localAudio.deviceId = 'default';
}
mediaType === 'audio'
? this._updateAudioDeviceId()
@@ -2768,13 +2791,14 @@ export default {
* Determines whether or not the audio button should be enabled.
*/
updateAudioIconEnabled() {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
const audioMediaDevices = APP.store.getState()['features/base/devices'].availableDevices.audioInput;
const audioDeviceCount = audioMediaDevices ? audioMediaDevices.length : 0;
const audioMediaDevices
= APP.store.getState()['features/base/devices'].availableDevices.audioInput;
const audioDeviceCount
= audioMediaDevices ? audioMediaDevices.length : 0;
// The audio functionality is considered available if there are any
// audio devices detected or if the local audio stream already exists.
const available = audioDeviceCount > 0 || Boolean(localAudio);
const available = audioDeviceCount > 0 || Boolean(this.localAudio);
APP.store.dispatch(setAudioAvailable(available));
APP.API.notifyAudioAvailabilityChanged(available);
@@ -2788,14 +2812,13 @@ export default {
= APP.store.getState()['features/base/devices'].availableDevices.videoInput;
const videoDeviceCount
= videoMediaDevices ? videoMediaDevices.length : 0;
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
// The video functionality is considered available if there are any
// video devices detected or if there is local video stream already
// active which could be either screensharing stream or a video track
// created before the permissions were rejected (through browser
// config).
const available = videoDeviceCount > 0 || Boolean(localVideo);
const available = videoDeviceCount > 0 || Boolean(this.localVideo);
APP.store.dispatch(setVideoAvailable(available));
APP.API.notifyVideoAvailabilityChanged(available);
@@ -2813,6 +2836,8 @@ export default {
APP.store.dispatch(destroyLocalTracks());
this._localTracksInitialized = false;
this.localVideo = null;
this.localAudio = null;
// Remove unnecessary event listeners from firing callbacks.
if (this.deviceChangeListener) {
@@ -2835,11 +2860,14 @@ export default {
requestFeedbackPromise = Promise.resolve(true);
}
// All promises are returning Promise.resolve to make Promise.all to
// be resolved when both Promises are finished. Otherwise Promise.all
// will reject on first rejected Promise and we can redirect the page
// before all operations are done.
Promise.all([
requestFeedbackPromise,
this.leaveRoomAndDisconnect()
])
.then(values => {
]).then(values => {
this._room = undefined;
room = undefined;

283
config.js
View File

@@ -27,6 +27,9 @@ var config = {
// Websocket URL
// websocket: 'wss://jitsi-meet.example.com/xmpp-websocket',
// The name of client node advertised in XEP-0115 'c' stanza
clientNode: 'http://jitsi.org/jitsimeet',
// The real JID of focus participant - can be overridden here
// Do not change username - FIXME: Make focus username configurable
// https://github.com/jitsi/jitsi-meet/issues/7376
@@ -41,16 +44,9 @@ var config = {
// issues related to insertable streams.
// disableE2EE: false,
// Enables/disables thumbnail reordering in the filmstrip. It is enabled by default unless explicitly
// disabled by the below option.
// enableThumbnailReordering: true,
// Enables XMPP WebSocket (as opposed to BOSH) for the given amount of users.
// mobileXmppWsThreshold: 10 // enable XMPP WebSockets on mobile for 10% of the users
// P2P test mode disables automatic switching to P2P when there are 2
// participants in the conference.
// p2pTestMode: false,
p2pTestMode: false
// Enables the test specific features consumed by jitsi-meet-torture
// testMode: false
@@ -74,15 +70,6 @@ var config = {
// callStatsThreshold: 5 // enable callstats for 5% of the users.
},
// Disables moderator indicators.
// disableModeratorIndicator: false,
// Disables the reactions feature.
// disableReactions: true,
// Disables polls feature.
// disablePolls: false,
// Disables ICE/UDP by filtering out local and remote UDP candidates in
// signalling.
// webrtcIceUdpDisable: false,
@@ -95,9 +82,6 @@ var config = {
// Media
//
// Enable unified plan implementation support on Chromium based browsers.
// enableUnifiedOnChrome: false,
// Audio
// Disable measuring of audio levels.
@@ -114,10 +98,6 @@ var config = {
// about the call.
// enableSaveLogs: false,
// Enabling this will hide the "Show More" link in the GSM popover that can be
// used to display more statistics about the connection (IP, Port, protocol, etc).
// disableShowMoreStats: true,
// Enabling this will run the lib-jitsi-meet noise detection module which will
// notify the user if there is noise, other than voice, coming from the current
// selected microphone. The purpose it to let the user know that the input could
@@ -154,19 +134,6 @@ var config = {
// Sets the preferred resolution (height) for local video. Defaults to 720.
// resolution: 720,
// Specifies whether the raised hand will hide when someone becomes a dominant speaker or not
// disableRemoveRaisedHandOnFocus: false,
// Specifies whether there will be a search field in speaker stats or not
// disableSpeakerStatsSearch: false,
// Specifies whether participants in speaker stats should be ordered or not, and with what priority
// speakerStatsOrder: [
// 'role', <- Moderators on top
// 'name', <- Alphabetically by name
// 'hasLeft', <- The ones that have left in the bottom
// ] <- the order of the array elements determines priority
// How many participants while in the tile view mode, before the receiving video quality is reduced from HD to SD.
// Use -1 to disable.
// maxFullResolutionParticipants: 2,
@@ -189,10 +156,9 @@ var config = {
// Enable / disable simulcast support.
// disableSimulcast: false,
// Enable / disable layer suspension. If enabled, endpoints whose HD layers are not in use will be suspended
// (no longer sent) until they are requested again. This is enabled by default. This must be enabled for screen
// sharing to work as expected on Chrome. Disabling this might result in low resolution screenshare being sent
// by the client.
// Enable / disable layer suspension. If enabled, endpoints whose HD
// layers are not in use will be suspended (no longer sent) until they
// are requested again.
// enableLayerSuspension: false,
// Every participant after the Nth will start video muted.
@@ -254,18 +220,6 @@ var config = {
// subtitles and buttons can be configured)
// transcribingEnabled: false,
// If true transcriber will use the application language.
// The application language is either explicitly set by participants in their settings or automatically
// detected based on the environment, e.g. if the app is opened in a chrome instance which is using french as its
// default language then transcriptions for that participant will be in french.
// Defaults to true.
// transcribeWithAppLanguage: true,
// Transcriber language. This settings will only work if "transcribeWithAppLanguage" is explicitly set to false.
// Available languages can be found in
// ./src/react/features/transcribing/transcriber-langs.json.
// preferredTranscribeLanguage: 'en-US',
// Enables automatic turning on captions when recording is started
// autoCaptionOnRecord: false,
@@ -274,14 +228,6 @@ var config = {
// Default value for the channel "last N" attribute. -1 for unlimited.
channelLastN: -1,
// Connection indicators
// connectionIndicators: {
// autoHide: true,
// autoHideTimeout: 5000,
// disabled: false,
// inactiveDisabled: false
// },
// Provides a way for the lastN value to be controlled through the UI.
// When startLastN is present, conference starts with a last-n value of startLastN and channelLastN
// value will be used when the quality level is selected using "Manage Video Quality" slider.
@@ -350,7 +296,7 @@ var config = {
// VP9: {
// low: 100000,
// standard: 300000,
// high: 1200000
// high: 1200000
// }
// },
//
@@ -415,11 +361,6 @@ var config = {
// bridge itself is reachable via UDP)
// useTurnUdp: false
// Enable support for encoded transform in supported browsers. This allows
// E2EE to work in Safari if the corresponding flag is enabled in the browser.
// Experimental.
// enableEncodedTransformSupport: false,
// UI
//
@@ -448,9 +389,7 @@ var config = {
// enableClosePage: false,
// Disable hiding of remote thumbnails when in a 1-on-1 conference call.
// Setting this to null, will also disable showing the remote videos
// when the toolbar is shown on mouse movements
// disable1On1Mode: null | false | true,
// disable1On1Mode: false,
// Default language for the user interface.
// defaultLanguage: 'en',
@@ -511,81 +450,13 @@ var config = {
// - 'desktop' controls the "Share your screen" button
// - if `toolbarButtons` is undefined, we fallback to enabling all buttons on the UI
// toolbarButtons: [
// 'camera',
// 'chat',
// 'closedcaptions',
// 'desktop',
// 'download',
// 'embedmeeting',
// 'etherpad',
// 'feedback',
// 'filmstrip',
// 'fullscreen',
// 'hangup',
// 'help',
// 'invite',
// 'livestreaming',
// 'microphone',
// 'mute-everyone',
// 'mute-video-everyone',
// 'participants-pane',
// 'profile',
// 'raisehand',
// 'recording',
// 'security',
// 'select-background',
// 'settings',
// 'shareaudio',
// 'sharedvideo',
// 'shortcuts',
// 'stats',
// 'tileview',
// 'toggle-camera',
// 'videoquality',
// '__end'
// 'microphone', 'camera', 'closedcaptions', 'desktop', 'embedmeeting', 'fullscreen',
// 'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
// 'livestreaming', 'etherpad', 'sharedvideo', 'shareaudio', 'settings', 'raisehand',
// 'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
// 'tileview', 'select-background', 'download', 'help', 'mute-everyone', 'mute-video-everyone', 'security'
// ],
// Toolbar buttons which have their click event exposed through the API on
// `toolbarButtonClicked` event instead of executing the normal click routine.
// buttonsWithNotifyClick: [
// 'camera',
// 'chat',
// 'closedcaptions',
// 'desktop',
// 'download',
// 'embedmeeting',
// 'etherpad',
// 'feedback',
// 'filmstrip',
// 'fullscreen',
// 'hangup',
// 'help',
// 'invite',
// 'livestreaming',
// 'microphone',
// 'mute-everyone',
// 'mute-video-everyone',
// 'participants-pane',
// 'profile',
// 'raisehand',
// 'recording',
// 'security',
// 'select-background',
// 'settings',
// 'shareaudio',
// 'sharedvideo',
// 'shortcuts',
// 'stats',
// 'tileview',
// 'toggle-camera',
// 'videoquality',
// '__end'
// ],
// List of pre meeting screens buttons to hide. The values must be one or more of the 5 allowed buttons:
// 'microphone', 'camera', 'select-background', 'invite', 'settings'
// hiddenPremeetingButtons: [],
// Stats
//
@@ -603,28 +474,6 @@ var config = {
// callStatsID: '',
// callStatsSecret: '',
// The callstats initialize config params as described in the API:
// https://docs.callstats.io/docs/javascript#callstatsinitialize-with-app-secret
// callStatsConfigParams: {
// disableBeforeUnloadHandler: true, // disables callstats.js's window.onbeforeunload parameter.
// applicationVersion: "app_version", // Application version specified by the developer.
// disablePrecalltest: true, // disables the pre-call test, it is enabled by default.
// siteID: "siteID", // The name/ID of the site/campus from where the call/pre-call test is made.
// additionalIDs: { // additionalIDs object, contains application related IDs.
// customerID: "Customer Identifier. Example, walmart.",
// tenantID: "Tenant Identifier. Example, monster.",
// productName: "Product Name. Example, Jitsi.",
// meetingsName: "Meeting Name. Example, Jitsi loves callstats.",
// serverName: "Server/MiddleBox Name. Example, jvb-prod-us-east-mlkncws12.",
// pbxID: "PBX Identifier. Example, walmart.",
// pbxExtensionID: "PBX Extension Identifier. Example, 5625.",
// fqExtensionID: "Fully qualified Extension Identifier. Example, +71 (US) +5625.",
// sessionID: "Session Identifier. Example, session-12-34"
// },
// collectLegacyStats: true, //enables the collection of legacy stats in chrome browser
// collectIP: true //enables the collection localIP address
// },
// Enables sending participants' display names to callstats
// enableDisplayNameInStats: false,
@@ -656,9 +505,6 @@ var config = {
// connection.
enabled: true,
// Enable unified plan implementation support on Chromium for p2p connection.
// enableUnifiedOnChrome: false,
// Sets the ICE transport policy for the p2p connection. At the time
// of this writing the list of possible values are 'all' and 'relay',
// but that is subject to change in the future. The enum is defined in
@@ -695,9 +541,6 @@ var config = {
},
analytics: {
// True if the analytics should be disabled
// disabled: false,
// The Google Analytics Tracking ID:
// googleAnalyticsTrackingId: 'your-tracking-id-UA-123456-1'
@@ -741,42 +584,13 @@ var config = {
// userRegion: "asia"
},
// Array<string> of disabled sounds.
// Possible values:
// - 'ASKED_TO_UNMUTE_SOUND'
// - 'E2EE_OFF_SOUND'
// - 'E2EE_ON_SOUND'
// - 'INCOMING_MSG_SOUND'
// - 'KNOCKING_PARTICIPANT_SOUND'
// - 'LIVE_STREAMING_OFF_SOUND'
// - 'LIVE_STREAMING_ON_SOUND'
// - 'NO_AUDIO_SIGNAL_SOUND'
// - 'NOISY_AUDIO_INPUT_SOUND'
// - 'OUTGOING_CALL_EXPIRED_SOUND'
// - 'OUTGOING_CALL_REJECTED_SOUND'
// - 'OUTGOING_CALL_RINGING_SOUND'
// - 'OUTGOING_CALL_START_SOUND'
// - 'PARTICIPANT_JOINED_SOUND'
// - 'PARTICIPANT_LEFT_SOUND'
// - 'RAISE_HAND_SOUND'
// - 'RECORDING_OFF_SOUND'
// - 'RECORDING_ON_SOUND'
// - 'TALK_WHILE_MUTED_SOUND'
// disabledSounds: [],
// DEPRECATED! Use `disabledSounds` instead.
// Decides whether the start/stop recording audio notifications should play on record.
// disableRecordAudioNotification: false,
// DEPRECATED! Use `disabledSounds` instead.
// Disables the sounds that play when other participants join or leave the
// conference (if set to true, these sounds will not be played).
// disableJoinLeaveSounds: false,
// DEPRECATED! Use `disabledSounds` instead.
// Disables the sounds that play when a chat message is received.
// disableIncomingMessageSound: false,
// Information for the chrome extension banner
// chromeExtensionBanner: {
// // The chrome extension to be installed address
@@ -797,8 +611,8 @@ var config = {
// localRecording: {
// Enables local recording.
// Additionally, 'localrecording' (all lowercase) needs to be added to
// the `toolbarButtons`-array for the Local Recording button to show up
// on the toolbar.
// TOOLBAR_BUTTONS in interface_config.js for the Local Recording
// button to show up on the toolbar.
//
// enabled: true,
//
@@ -875,11 +689,8 @@ var config = {
/**
External API url used to receive branding specific information.
If there is no url set or there are missing fields, the defaults are applied.
The config file should be in JSON.
None of the fields are mandatory and the response must have the shape:
{
// The domain url to apply (will replace the domain in the sharing conference link/embed section)
inviteDomain: 'example-company.org,
// The hex value for the colour used as background
backgroundColor: '#fff',
// The url for the image used as background
@@ -887,11 +698,7 @@ var config = {
// The anchor url used when clicking the logo image
logoClickUrl: 'https://example-company.org',
// The url used for the image used as logo
logoImageUrl: 'https://example.com/logo-img.png',
// Overwrite for pool of background images for avatars
avatarBackgrounds: ['url(https://example.com/avatar-background-1.png)', '#FFF'],
// The lobby/prejoin screen background
premeetingBackground: 'url(https://example.com/premeeting-background.png)'
logoImageUrl: 'https://example.com/logo-img.png'
}
*/
// dynamicBrandingUrl: '',
@@ -907,32 +714,12 @@ var config = {
// If true, tile view will not be enabled automatically when the participants count threshold is reached.
// disableTileView: true,
// Controls the visibility and behavior of the top header conference info labels.
// If a label's id is not in any of the 2 arrays, it will not be visible at all on the header.
// conferenceInfo: {
// // those labels will not be hidden in tandem with the toolbox.
// alwaysVisible: ['recording', 'local-recording'],
// // those labels will be auto-hidden in tandem with the toolbox buttons.
// autoHide: [
// 'subject',
// 'conference-timer',
// 'participants-count',
// 'e2ee',
// 'transcribing',
// 'video-quality',
// 'insecure-room'
// ]
// },
// Hides the conference subject
// hideConferenceSubject: true,
// Hides the conference timer.
// hideConferenceTimer: true,
// Hides the recording label
// hideRecordingLabel: false,
// Hides the participants stats
// hideParticipantsStats: true,
@@ -944,18 +731,6 @@ var config = {
// is not persisting the local storage inside the iframe.
// useHostPageLocalStorage: true,
// etherpad ("shared document") integration.
//
// If set, add a "Open shared document" link to the bottom right menu that
// will open an etherpad document.
// etherpad_base: 'https://your-etherpad-installati.on/p/',
// If etherpad_base is set, and useRoomAsSharedDocumentName is set to true,
// open a pad with the name of the room (lowercased) instead of a pad with a
// random UUID.
// useRoomAsSharedDocumentName: true,
// List of undocumented settings used in jitsi-meet
/**
_immediateReloadThreshold
@@ -968,8 +743,8 @@ var config = {
dialOutCodesUrl
disableRemoteControl
displayJids
etherpad_base
externalConnectUrl
e2eeLabels
firefox_fake_device
googleApiApplicationClientID
iAmRecorder
@@ -1011,11 +786,6 @@ var config = {
websocketKeepAliveUrl
*/
/**
* Default interval (milliseconds) for triggering mouseMoved iframe API event
*/
mouseMoveCallbackInterval: 1000,
/**
Use this array to configure which notifications will be shown to the user
The items correspond to the title or description key of that notification
@@ -1049,19 +819,11 @@ var config = {
// 'lobby.notificationTitle', // shown when lobby is toggled and when join requests are allowed / denied
// 'localRecording.localRecording', // shown when a local recording is started
// 'notify.disconnected', // shown when a participant has left
// 'notify.connectedOneMember', // show when a participant joined
// 'notify.connectedTwoMembers', // show when two participants joined simultaneously
// 'notify.connectedThreePlusMembers', // show when more than 2 participants joined simultaneously
// 'notify.grantedTo', // shown when moderator rights were granted to a participant
// 'notify.invitedOneMember', // shown when 1 participant has been invited
// 'notify.invitedThreePlusMembers', // shown when 3+ participants have been invited
// 'notify.invitedTwoMembers', // shown when 2 participants have been invited
// 'notify.kickParticipant', // shown when a participant is kicked
// 'notify.moderationStartedTitle', // shown when AV moderation is activated
// 'notify.moderationStoppedTitle', // shown when AV moderation is deactivated
// 'notify.moderationInEffectTitle', // shown when user attempts to unmute audio during AV moderation
// 'notify.moderationInEffectVideoTitle', // shown when user attempts to enable video during AV moderation
// 'notify.moderationInEffectCSTitle', // shown when user attempts to share content during AV moderation
// 'notify.mutedRemotelyTitle', // shown when user is muted by a remote party
// 'notify.mutedTitle', // shown when user has been muted upon joining,
// 'notify.newDeviceAudioTitle', // prompts the user to use a newly detected audio device
@@ -1070,7 +832,6 @@ var config = {
// 'notify.passwordSetRemotely', // shown when a password has been set remotely
// 'notify.raisedHand', // shown when a partcipant used raise hand,
// 'notify.startSilentTitle', // shown when user joined with no audio
// 'notify.unmute', // shown to moderator when user raises hand during AV moderation
// 'prejoin.errorDialOut',
// 'prejoin.errorDialOutDisconnected',
// 'prejoin.errorDialOutFailed',
@@ -1084,13 +845,7 @@ var config = {
// 'toolbar.noisyAudioInputTitle', // shown when noise is detected for the current microphone
// 'toolbar.talkWhileMutedPopup', // shown when user tries to speak while muted
// 'transcribing.failedToStart' // shown when transcribing fails to start
// ],
// Prevent the filmstrip from autohiding when screen width is under a certain threshold
// disableFilmstripAutohiding: false,
// Specifies whether the chat emoticons are disabled or not
// disableChatSmileys: false,
// ]
// Allow all above example options to include a trailing comma and
// prevent fear when commenting out the last value.

View File

@@ -11,14 +11,11 @@ import {
connectionFailed
} from './react/features/base/connection/actions';
import { openDialog } from './react/features/base/dialog/actions';
import { setJWT } from './react/features/base/jwt';
import {
isFatalJitsiConnectionError,
JitsiConnectionErrors,
JitsiConnectionEvents
} from './react/features/base/lib-jitsi-meet';
import { getCustomerDetails } from './react/features/jaas/actions.any';
import { isVpaasMeeting, getJaasJWT } from './react/features/jaas/functions';
import { setPrejoinDisplayNameRequired } from './react/features/prejoin/actions';
const logger = Logger.getLogger(__filename);
@@ -85,20 +82,9 @@ function checkForAttachParametersAndConnect(id, password, connection) {
* @returns {Promise<JitsiConnection>} connection if
* everything is ok, else error.
*/
export async function connect(id, password, roomName) {
export function connect(id, password, roomName) {
const connectionConfig = Object.assign({}, config);
const state = APP.store.getState();
let { jwt } = state['features/base/jwt'];
const { iAmRecorder, iAmSipGateway } = state['features/base/config'];
if (!iAmRecorder && !iAmSipGateway && isVpaasMeeting(state)) {
await APP.store.dispatch(getCustomerDetails());
if (!jwt) {
jwt = await getJaasJWT(state);
APP.store.dispatch(setJWT(jwt));
}
}
const { jwt } = APP.store.getState()['features/base/jwt'];
// Use Websocket URL for the web app if configured. Note that there is no 'isWeb' check, because there's assumption
// that this code executes only on web browsers/electron. This needs to be changed when mobile and web are unified.
@@ -106,7 +92,9 @@ export async function connect(id, password, roomName) {
serviceUrl += `?room=${roomName}`;
connectionConfig.serviceUrl = serviceUrl;
// FIXME Remove deprecated 'bosh' option assignment at some point(LJM will be accepting only 'serviceUrl' option
// in future). It's included for the time being for Jitsi Meet and lib-jitsi-meet versions interoperability.
connectionConfig.serviceUrl = connectionConfig.bosh = serviceUrl;
if (connectionConfig.websocketKeepAliveUrl) {
connectionConfig.websocketKeepAliveUrl += `?room=${roomName}`;

View File

@@ -32,18 +32,6 @@
.dropdown-menu div[style*="transform"] {
outline: 1px solid #455166;
}
.dropdown-menu button:not(:active):not(:hover) > span {
color: #B8C7E0;
}
/**
* Override @atlaskit/tab styling when in a modal because the
* tab text color clash with the modal backgrounds.
*/
div[role="tablist"] > div:not([data-selected]):not(:hover),
label > div > span {
color: #B8C7E0 !important;
}
}
/**
@@ -100,18 +88,12 @@
}
.audio-preview > div:nth-child(2),
.video-preview > div:nth-child(2),
.reactions-menu-popup > div:nth-child(2) {
.video-preview > div:nth-child(2) {
margin-bottom: 4px;
outline: none;
padding: 0;
}
.reactions-menu-popup > div:nth-child(2) {
margin-bottom: 6px;
box-shadow: none;
}
/**
* The following selectors keep the chat modal full-size anywhere between 100px
* and 580px for desktop or 680px for mobile.

View File

@@ -9,11 +9,6 @@
max-height: 456px;
overflow: auto;
width: 300px;
&-ul {
margin:0;
padding:0;
list-style-type: none;
}
}
&-header {
@@ -69,13 +64,7 @@
&-speaker {
position: relative;
&-ul {
margin:0;
padding:0;
list-style-type: none;
}
&:hover, &:focus-within, &:focus {
&:hover {
.audio-preview-entry {
background: #36383C;
margin-left: 0;
@@ -92,7 +81,7 @@
}
.audio-preview-entry-text {
max-width: 178px;
max-width: 196px;
}
}
@@ -101,7 +90,7 @@
}
.audio-preview-entry-text {
max-width: 238px;
max-width: 256px;
}
}
@@ -161,9 +150,8 @@
color: #1C2025;
cursor: pointer;
font-weight: 600;
font-size: 0.8rem;
line-height: 24px;
padding: 2px 8px;
padding: 2px 16px;
position: absolute;
right: 16px;
top: 5px;
@@ -174,10 +162,4 @@
right: 16px;
top: 14px;
}
// Override @atlaskit/InlineDialog container which is made with styled components
& > div:nth-child(2) {
outline: none;
padding: 0;
}
}

View File

@@ -219,9 +219,8 @@ abbr {
}
a {
color: #44A5FF;
color: #3572b0;
text-decoration: none;
font-weight: bold;
}
a:focus,
a:hover,

View File

@@ -1,7 +1,7 @@
.avatar {
background-color: #AAA;
border-radius: 50%;
color: rgba(255, 255, 255, 1);
color: rgba(255, 255, 255, 0.6);
font-weight: 100;
object-fit: cover;
@@ -25,6 +25,10 @@
width: 100%;
}
.defaultAvatar {
opacity: 0.6
}
.avatar-badge {
position: relative;

View File

@@ -51,10 +51,8 @@ body {
}
}
.jitsi-icon {
&-default svg {
fill: white;
}
.jitsi-icon svg {
fill: white;
}
.disabled .jitsi-icon svg {

View File

@@ -99,19 +99,18 @@
div {
svg {
cursor: pointer;
fill: white;
fill: white
}
}
}
.chat-header {
height: 70px;
position: relative;
width: 100%;
z-index: 1;
display: flex;
justify-content: space-between;
justify-content: flex-end;
padding: 16px;
align-items: center;
box-sizing: border-box;
@@ -133,7 +132,6 @@
.send-button {
background: #1B67EC;
cursor: pointer;
margin-left: 0.3rem;
@media (hover: hover) and (pointer: fine) {
&:hover {
@@ -190,9 +188,8 @@
display: flex;
align-items: center;
justify-content: center;
height: 38px;
width: 38px;
margin: 2px;
height: 40px;
width: 40px;
border-radius: 3px;
}
@@ -229,11 +226,6 @@
border: 0px none;
box-shadow: none;
}
#usermsg:focus,
#usermsg:active {
border-bottom: 1px solid white;
padding-bottom: 8px;
}
#nickname {
text-align: center;
@@ -242,16 +234,6 @@
margin: auto 0;
padding: 0 16px;
#nickname-title {
margin-bottom: 5px;
display: block;
}
label[for="nickinput"] {
> div > span {
color: #B8C7E0;
}
}
input {
height: 40px;
}
@@ -272,7 +254,7 @@
cursor: pointer;
&.disabled {
color: #AFB6BC;
color: #757575;
background: #11336E;
pointer-events: none;
}
@@ -319,19 +301,6 @@
}
}
.sr-only {
border: 0 !important;
clip: rect(1px, 1px, 1px, 1px) !important;
clip-path: inset(50%) !important;
height: 1px !important;
margin: -1px !important;
overflow: hidden !important;
padding: 0 !important;
position: absolute !important;
width: 1px !important;
white-space: nowrap !important;
}
.chatmessage {
background-color: $chatRemoteMessageBackgroundColor;
border-radius: 0px 6px 6px 6px;
@@ -381,6 +350,10 @@
color: #757575;
}
.smiley {
font-size: 14pt;
}
#smileys {
font-size: 20pt;
margin: auto;
@@ -409,7 +382,7 @@
box-sizing: border-box;
background-color: rgba(0, 0, 0, .6) !important;
height: auto;
display: none;
max-height: 0;
overflow: hidden;
position: absolute;
width: calc(#{$sidebarWidth} - 32px);
@@ -425,7 +398,6 @@
transition: max-height 0.3s;
&.show-smileys {
display: flex;
max-height: 500%;
}
@@ -441,7 +413,7 @@
.smileyContainer {
width: 40px;
height: 40px;
height: 36px;
display: inline-block;
text-align: center;
}
@@ -537,7 +509,7 @@
&-header {
display: flex;
justify-content: space-between;
justify-content: flex-end;
align-items: center;
margin: 16px;
width: calc(100% - 32px);
@@ -574,41 +546,3 @@
background: #36383C;
border-radius: 3px;
}
.chat-tabs-container {
width: 100%;
border-bottom: thin solid #292929;
display: flex;
justify-content: space-around;
}
.chat-tab {
font-size: 1.2em;
padding-bottom: 0.5em;
width: 50%;
text-align: center;
color: #8B8B8B;
cursor: pointer;
}
.chat-tab-focus {
border-bottom-style: solid;
color: #FFF;
}
.chat-tab-title {
margin-right: 8px;
}
.chat-tab-badge {
background-color: #165ecc;
border-radius: 50%;
box-sizing: border-box;
font-weight: 700;
overflow: hidden;
text-align: center;
text-overflow: ellipsis;
vertical-align: middle;
padding: 0 4px;
color: #FFF;
}

View File

@@ -45,10 +45,6 @@
@extend .connection-info__icon;
}
&__mobile {
margin: 15px;
}
.connection-actions {
margin: 10px auto;
text-align: center;

View File

@@ -1,24 +1,30 @@
.con-status {
border-radius: 6px;
color: #fff;
font-size: 12px;
letter-spacing: 0.16px;
line-height: 16px;
position: absolute;
top: 24px;
width: 100%;
z-index: $toolbarZ + 3;
&-container {
border-radius: 3px;
color: #fff;
font-size: 13px;
line-height: 13px;
margin: 0 auto;
width: 320px;
}
&-header {
background-color: rgba(0, 0, 0, 0.7);
background: rgba(28, 32, 37, .5);
align-items: center;
display: flex;
padding: 14px 16px;
justify-content: space-between;
}
&-circle {
border-radius: 50%;
display: inline-block;
padding: 4px;
margin-right: 16px;
margin: 8px;
}
&--good {
@@ -34,7 +40,14 @@
}
&-arrow {
margin-left: auto;
height: 36px;
width: 36px;
border-radius: 3px;
margin-left: 8px;
margin-right: 2px;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.16s ease-out;
&--up {
@@ -55,7 +68,7 @@
}
&-details {
background-color: rgba(0, 0, 0, 0.7);
background: rgba(28, 32, 37, .5);
border-top: 1px solid #5E6D7A;
padding: 16px;
transition: opacity 0.16s ease-out;

View File

@@ -4,28 +4,17 @@
right: 0;
bottom: 0;
z-index: $drawerZ;
border-radius: 16px 16px 0 0;
}
.drawer-portal::after {
content: '';
background-color: $participantsPaneBgColor;
margin-bottom: env(safe-area-inset-bottom, 0);
}
.drawer-menu-container {
height: 100vh;
display: flex;
align-items: flex-end;
}
.drawer-menu {
max-height: calc(80vh - 64px);
max-height: 50vh;
background: #242528;
border-radius: 16px 16px 0 0;
overflow-y: scroll;
margin-bottom: env(safe-area-inset-bottom, 0);
width: 100%;
overflow-y: auto;
&.expanded {
max-height: 80vh;
}
.drawer-toggle {
display: flex;
@@ -53,8 +42,6 @@
font-size: 1.2em;
list-style-type: none;
padding: 0;
height: calc(80vh - 144px - 64px);
overflow-y: auto;
.overflow-menu-item {
box-sizing: border-box;

View File

@@ -5,6 +5,11 @@
.description {
font-size: 13px;
margin: 15px 0;
.read-more {
cursor: pointer;
opacity: .7;
}
}
.control-row {

View File

@@ -1,21 +1,18 @@
.lobby-screen {
font-size: 16px;
font-weight: 400;
line-height: 26px;
#lobby-screen {
.content {
&-content {
align-items: center;
display: flex;
flex-direction: column;
.container {
align-items: center;
display: flex;
flex-direction: column;
.spinner {
margin: 8px;
}
.spinner {
margin: 30px;
}
.joining-message {
color: white;
margin: 24px auto;
text-align: center;
.joining-message {
margin: 10px;
}
}
}
}
@@ -41,23 +38,19 @@
}
}
#notification-participant-list {
#knocking-participant-list {
background-color: $newToolbarBackgroundColor;
border: 1px solid rgba(255, 255, 255, .4);
border-radius: 8px;
display: flex;
flex-direction: column;
left: 0;
margin: 20px;
max-height: 600px;
overflow: hidden;
overflow-y: auto;
position: fixed;
top: 30px;
top: 20;
transition: top 1s ease;
z-index: $toolbarZ + 1;
&:empty {
border: none;
}
&.toolbox-visible {
// Same as toolbox subject position
top: 120px;
@@ -71,7 +64,7 @@
button {
align-self: stretch;
margin-bottom: 8px 0;
margin: 8px 0;
padding: 12px;
transition: .2s transform ease;
@@ -101,6 +94,8 @@
.knocking-participants-container {
list-style-type: none;
max-height: 600px;
overflow-y: scroll;
padding: 0 15px 15px 15px;
}

View File

@@ -125,8 +125,7 @@
cursor: pointer;
}
&.with-click-handler:hover,
&.with-click-handler:focus {
&.with-click-handler:hover {
background-color: #c7ddff;
}
@@ -159,7 +158,7 @@
}
}
.item:hover, .item:focus, .item:focus-within {
.item:hover {
.delete-meeting {
display: block;
}

View File

@@ -29,7 +29,7 @@
margin: 8px 16px 8px 0;
}
@media (max-width: 580px) {
@media (max-width: 375px) {
.participants_pane {
height: 100vh;
height: -webkit-fill-available;
@@ -48,11 +48,4 @@
.participants_pane-content {
width: 100%;
}
}
.jitsi-icon {
&-dominant-speaker {
background-color: #1EC26A;
border-radius: 3px;
}
}
}

View File

@@ -1,448 +0,0 @@
.poll-dialog {
font-size: 1rem;
h1, span, li, strong {
color: #bce;
}
ol {
margin: 0;
}
}
.poll-question-field {
padding: 8px 16px;
padding-bottom: 24px;
border-bottom: 1px solid #525252;
}
.poll-header {
padding: 8px 16px;
}
.poll-answer-container{
padding: 8px;
background: #3D3D3D;
border-radius: 3px;
margin-bottom: 8px;
}
.poll-answer-field-list, .poll-answer-list, .poll-result-list {
list-style-type: none;
padding: 0 16px;
margin: 0;
}
ol.poll-result-list {
margin-bottom: 1.5em;
}
.poll-result-list > li {
margin-bottom: 8px;
}
.poll-answer-field {
flex-direction: column;
align-items: stretch;
margin-bottom: 16;
}
.poll-answer-field:last-child {
margin-bottom: 0;
}
.poll-create-option-row {
display: 'flex';
margin-bottom: 4;
}
// Needeed to override atlaskit default blue color
.poll-create-container .jsYMHu {
background: #292929;
border-color: #808090;
color: white // #808090
}
.poll-add-button {
display: flex;
justify-content: center;
padding: 8px 16px;
}
.poll-remove-option-button {
background: 0 0;
border: none;
color: #8B8B8B;
padding-left: 0;
}
.poll-create-add-option {
border: none;
background-color: #292929;
padding: 3px;
width: 100%;
}
.poll-icon-button, .poll-drag-handle {
.jitsi-icon svg {
fill: #bce;
}
}
.poll-drag-handle {
background-color: transparent;
border: none;
cursor: grab;
padding-left: 8;
display: flex;
}
.poll-dragged {
opacity: 0.5;
* {
cursor: grabbing !important;
}
}
.poll-question {
font-size: 1.2em;
font-weight: 600;
margin-bottom: 0.5em;
}
.poll-answer-voters {
font-size: 1em;
font-weight: lighter;
list-style-type: none;
border: #616161 solid 1px;
border-radius: 3px;
padding: 2px 6px;
margin: 4px 0px 12px;
background-color: #616161;
}
.poll-answer-header {
display: flex;
justify-content: space-between;
}
.poll-answer-vote-name {
flex-shrink: 1;
overflow-wrap: anywhere
}
.poll-answer-vote-count-container{
display: flex;
}
.poll-answer-vote-count {
margin-left: 10px;
white-space: nowrap;
flex: 1;
text-align: right;
}
.poll-answer-short-results{
display: flex;
min-width: 10em;
justify-content: space-between;
align-items: center;
}
.poll-bar-container, .poll-bar {
border-radius: 3px;
height: 6px;
}
.poll-bar-container {
background-color: #616161;
max-width: 160px;
margin-top: 3px;
flex: 1;
}
.poll-bar {
background-color: #246FE5;
}
.poll-message-footer {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 12px;
margin-top: 5px;
}
.poll-notice {
font-weight: 100;
margin-right: 10px;
}
.poll-show-details {
background-color: transparent;
border: none;
&:hover {
text-decoration: underline;
}
}
.poll-result-links {
display: flex;
flex-direction: row;
justify-content: space-between;
}
a.poll-detail-link, a.poll-change-vote-link {
color: #246FE5;
cursor: pointer;
text-decoration: none;
}
.polls-pane-content {
display: flex;
flex-direction: column;
font-weight: 600;
height: 85%;
align-items: stretch;
}
.pane-content{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
.empty-pane-icon {
width: 50%;
padding: 24px;
}
.empty-pane-icon svg {
fill: #3D3D3D;
width: 100%;
height: auto;
}
.empty-pane-message {
text-align: center;
}
.poll-results {
color: white;
}
.poll-answer {
h1, strong ,span {
color: white;
}
}
.poll-results, .poll-answer {
margin-bottom: 16px;
background: #292929;
border-radius: 8px;
padding: 12px 8px;
border-width: thin;
border-style: solid;
border-color: #616161;
}
.poll-create-label {
color: white;
margin-bottom: 4;
display: flex;
}
.expandable-input{
resize: none;
width: 100%;
height: 40px;
box-sizing: border-box;
overflow: hidden;
border: 1px solid #666666;
background-color: #141414;
color: #FFF;
border-radius: 6px;
padding: 10px 16px;
}
.poll-container {
box-sizing: border-box;
flex: 1;
overflow-y: auto;
position: relative;
padding: 16px;
& > * + *:not(.ignore-child) {
margin-top: 16px;
}
&::-webkit-scrollbar {
display: none;
}
}
.poll-create-header {
font-size: 20px;
margin: 20px 16px;
font-weight: 600;
}
.poll-create-container {
padding: 8px 0;
}
.poll-footer {
display: flex;
justify-content: flex-end;
padding: 8px 16px;
height: 40px;
align-items: stretch;
& > *:not(:last-child) {
margin-right: 16px;
}
}
.poll-primary-button {
align-items: center;
background-color: #0056E0;
border: 0;
border-radius: 6px;
display: flex;
font-weight: unset;
justify-content: center;
font-size: 15px;
flex: 1;
&:hover {
background-color: #246FE5;
}
&:active {
background-color: #0045B3;
}
&:focus {
background-color: #0045B3;
border: 3px solid #99BBF3;
}
&:disabled {
background-color: #00225A;
color: #858585;
}
& > *:not(:last-child) {
margin-right: 8px;
}
}
.poll-secondary-button {
align-items: center;
background-color: #3D3D3D;
border: 0;
border-radius: 6px;
display: flex;
font-weight: unset;
justify-content: center;
font-size: 15px;
height: 40px;
width: 100%;
&:hover {
background-color: #525252;
}
&:active {
background-color: #292929;
}
&:focus {
background-color: #292929;
border: 3px solid #858585;
}
&:disabled {
background-color: #141414;
color: #858585;
}
& > *:not(:last-child) {
margin-right: 8px;
}
}
.poll-small-primary-button {
align-items: center;
background-color: #0056E0;
border: 0;
border-radius: 6px;
display: flex;
font-weight: unset;
justify-content: center;
font-size: 15px;
height: 40px;
width: 50%;
&:hover {
background-color: #246FE5;
}
&:active {
background-color: #0045B3;
}
&:focus {
background-color: #0045B3;
border: 3px solid #99BBF3;
}
&:disabled {
background-color: #00225A;
color: #858585;
}
& > *:not(:last-child) {
margin-right: 8px;
}
}
.poll-small-secondary-button {
align-items: center;
background-color: #3D3D3D;
border: 0;
border-radius: 6px;
display: flex;
font-weight: unset;
justify-content: center;
font-size: 15px;
height: 40px;
width: 50%;
&:hover {
background-color: #525252;
}
&:active {
background-color: #292929;
}
&:focus {
background-color: #292929;
border: 3px solid #858585;
}
&:disabled {
background-color: #141414;
color: #858585;
}
& > *:not(:last-child) {
margin-right: 8px;
}
}

138
css/_prejoin.scss Normal file
View File

@@ -0,0 +1,138 @@
.prejoin {
&-input-area {
margin: 0 auto;
text-align: center;
}
&-title {
color: #fff;
font-size: 24px;
line-height: 32px;
margin-bottom: 16px;
}
&-text-btns {
display: flex;
justify-content: space-between;
}
&-input-label {
color: #A4B8D1;
font-size: 13px;
line-height: 20px;
margin-top: 32px 0 8px 0;
text-align: center;
width: 100%;
}
&-checkbox {
border: 0;
height: 16px;
margin-right: 8px;
padding: 0;
width: 16px;
}
&-checkbox-container {
margin-bottom: 14px;
width: 100%;
}
&-error {
color: white;
background-color: rgba(225, 45, 45, 0.6);
border-radius: 3px;
width: 100%;
padding: 2px;
box-sizing: border-box;
margin-top: 4px;
font-size: 13px;
text-align: center;
}
}
@mixin name-placeholder {
color: #fff;
font-weight: 300;
opacity: 0.6;
}
.prejoin-preview {
&-status {
align-items: center;
align-self: stretch;
bottom: 0;
color: #fff;
display: flex;
font-size: 13px;
min-height: 24px;
justify-content: center;
position: absolute;
text-align: center;
width: 100%;
z-index: 1;
&--warning {
background: rgba(241, 173, 51, 0.7)
}
&--ok {
background: rgba(49, 183, 106, 0.7);
}
}
&-icon {
background-position: center;
background-repeat: no-repeat;
display: inline-block;
height: 16px;
margin-right: 8px;
width: 16px;
}
&-error-desc {
margin-right: 4px;
}
.settings-button-container {
width: 49px;
margin: 0 8px;
}
&-dropdown-btns {
width: 320px;
padding: 8px 0;
}
&-dropdown-btn {
align-items: center;
color: #1C2025;
cursor: pointer;
display: flex;
height: 40px;
font-size: 15px;
line-height: 24px;
padding: 0 16px;
&:hover {
background-color: #DAEBFA;
}
}
&-dropdown-icon {
display: inline-block;
margin-right: 16px;
& > svg {
fill: #1C2025;
}
}
&-dropdown-container {
& > div:nth-child(2) {
background: #fff;
padding: 0;
}
}
}

View File

@@ -0,0 +1,274 @@
/**
* Shared style for full screen local track based dialogs/modals.
*/
.premeeting-screen {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.premeeting-screen {
align-items: stretch;
background: radial-gradient(50% 50% at 50% 50%, #2A3A4B 20.83%, #1E2A36 100%);
display: flex;
flex-direction: column;
font-size: 1.3em;
z-index: $toolbarZ + 1;
&-avatar {
background-color: #A4B8D1;
margin-bottom: 24px;
text {
fill: black;
font-size: 26px;
font-weight: 400;
}
}
.action-btn {
border-radius: 3px;
color: #fff;
cursor: pointer;
display: inline-block;
font-size: 15px;
line-height: 24px;
margin-top: 16px;
padding: 7px 16px;
position: relative;
text-align: center;
width: 286px;
&.primary {
background: #0376DA;
border: 1px solid #0376DA;
}
&.secondary {
background: transparent;
border: 1px solid #5E6D7A;
}
&.text {
width: auto;
font-size: 13px;
margin: 0;
padding: 0;
}
&.disabled {
background: #5E6D7A;
border: 1px solid #5E6D7A;
color: #AFB6BC;
cursor: initial;
.icon {
& > svg {
fill: #AFB6BC;
}
}
}
.options {
border-radius: 3px;
align-items: center;
display: flex;
height: 100%;
justify-content: center;
position: absolute;
right: 0;
top: 0;
width: 36px;
&:hover {
background-color: #0262B6;
}
svg {
pointer-events: none;
}
}
}
.content {
align-items: center;
display: flex;
flex: 1;
flex-direction: column;
justify-content: flex-end;
padding-bottom: 24px;
z-index: $toolbarZ + 2;
.title {
color: #fff;
font-size: 24px;
line-height: 32px;
margin-bottom: 16px;
}
.copy-meeting {
align-items: center;
cursor: pointer;
color: #fff;
display: flex;
flex-direction: row;
font-size: 15px;
font-weight: 300;
justify-content: center;
line-height: 24px;
margin-bottom: 16px;
.url {
background: rgba(28, 32, 37, 0.5);
border-radius: 4px;
display: flex;
padding: 8px 10px;
transition: background 0.16s ease-out;
&:hover {
background: #1C2025;
}
&.done {
background: #31B76A;
}
.jitsi-icon {
margin-left: 10px;
}
}
.copy-meeting-text {
width: 266px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&:hover {
align-self: stretch;
}
textarea {
border-width: 0;
height: 0;
opacity: 0;
padding: 0;
width: 0;
}
}
input.field {
background-color: white;
border: none;
outline: none;
border-radius: 3px;
font-size: 15px;
line-height: 24px;
color: #1C2025;
padding: 8px 0;
text-align: center;
width: 320px;
&.error {
box-shadow: 0px 0px 4px 3px rgba(225, 45, 45, 0.4);
}
&.focused {
box-shadow: 0px 0px 4px 3px #0376DA;
}
}
}
.media-btn-container {
display: flex;
justify-content: center;
margin: 24px 0 16px 0;
width: 100%;
&> div {
margin: 0 12px;
}
}
}
#preview {
height: 100%;
position: absolute;
width: 100%;
&.no-video {
background: radial-gradient(50% 50% at 50% 50%, #5B6F80 0%, #365067 100%), #FFFFFF;
text-align: center;
}
.avatar {
background: #A4B8D1;
margin: 0 auto;
}
video {
height: 100%;
object-fit: cover;
position: absolute;
width: 100%;
}
}
@mixin flex-centered() {
align-items: center;
display: flex;
justify-content: center;
}
@mixin icon-container($bg, $fill) {
.toggle-button-icon-container {
background: $bg;
svg {
fill: $fill
}
}
}
.toggle-button {
border-radius: 3px;
cursor: pointer;
color: #fff;
font-size: 13px;
height: 40px;
margin: 0 auto;
transition: background 0.16s ease-out;
width: 320px;
@include flex-centered();
svg {
fill: transparent;
}
&:hover {
background: rgba(255, 255, 255, 0.1);
@include icon-container(#A4B8D1, #1C2025);
}
&-container {
position: relative;
@include flex-centered();
}
&-icon-container {
border-radius: 50%;
left: -22px;
padding: 2px;
position: absolute;
}
&--toggled {
@include icon-container(white, #1C2025);
}
}

View File

@@ -1,196 +0,0 @@
@use 'sass:math';
.reactions-menu {
width: 280px;
background: $menuBG;
box-shadow: 0px 3px 16px rgba(0, 0, 0, 0.6), 0px 0px 4px 1px rgba(0, 0, 0, 0.25);
border-radius: 3px;
padding: 16px;
&.overflow {
width: auto;
padding-bottom: max(env(safe-area-inset-bottom, 0), 16px);
background-color: #141414;
box-shadow: none;
border-radius: 0;
position: relative;
.toolbox-icon {
width: 48px;
height: 48px;
span.emoji {
width: 48px;
height: 48px;
}
}
.reactions-row {
display: flex;
flex-direction: row;
justify-content: space-around;
.toolbox-button {
margin-right: 0;
}
}
}
.toolbox-icon {
width: 40px;
height: 40px;
border-radius: 6px;
span.emoji {
width: 40px;
height: 40px;
font-size: 22px;
display: flex;
align-items: center;
justify-content: center;
transition: font-size ease .1s;
@for $i from 1 through 12 {
&.increase-#{$i}{
font-size: calc(20px + #{$i}px);
}
}
}
}
.reactions-row {
.toolbox-button {
margin-right: 8px;
touch-action: manipulation;
}
.toolbox-button:last-of-type {
margin-right: 0;
}
}
.raise-hand-row {
margin-top: 16px;
.toolbox-button {
width: 100%;
}
.toolbox-icon {
width: 100%;
flex-direction: row;
align-items: center;
span.text {
font-style: normal;
font-weight: 600;
font-size: 14px;
line-height: 24px;
margin-left: 8px;
}
}
}
}
.reactions-animations-container {
position: absolute;
width: 20%;
bottom: 0;
left: 40%;
height: 0;
}
.reactions-menu-popup-container,
.reactions-menu-popup {
display: inline-block;
position: relative;
}
$reactionCount: 20;
@function random($min, $max) {
@return math.random() * ($max - $min) + $min;
}
.reaction-emoji {
position: absolute;
font-size: 24px;
line-height: 32px;
width: 32px;
height: 32px;
top: 0;
left: 20px;
opacity: 0;
z-index: 1;
&.reaction-0 {
animation: flowToRight 5s forwards ease-in-out;
}
@for $i from 1 through $reactionCount {
&.reaction-#{$i} {
animation: animation-#{$i} 5s forwards ease-in-out;
top: #{random(-40, 10)}px;
left: #{random(0, 30)}px;
}
}
}
@keyframes flowToRight {
0% {
transform: translate(0px, 0px) scale(0.6);
opacity: 1;
}
70% {
transform: translate(40px, -70vh) scale(1.5);
opacity: 1;
}
75% {
transform: translate(40px, -70vh) scale(1.5);
opacity: 1;
}
100% {
transform: translate(140px, -50vh) scale(1);
opacity: 0;
}
}
@mixin animation-list {
@for $i from 1 through $reactionCount {
$topX: random(-100, 100);
$topY: random(65, 75);
$bottomX: random(150, 200);
$bottomY: random(40, 50);
@if $topX < 0 {
$bottomX: -$bottomX;
}
@keyframes animation-#{$i} {
0% {
transform: translate(0, 0) scale(0.6);
opacity: 1;
}
70% {
transform: translate(#{$topX}px, -#{$topY}vh) scale(1.5);
opacity: 1;
}
75% {
transform: translate(#{$topX}px, -#{$topY}vh) scale(1.5);
opacity: 1;
}
100% {
transform: translate(#{$bottomX}px, -#{$bottomY}vh) scale(1);
opacity: 0;
}
}
}
}
@include animation-list;

View File

@@ -105,7 +105,6 @@
.helper-link {
cursor: pointer;
font-weight: bold;
display: inline-block;
flex-shrink: 0;
margin-left: auto;

View File

@@ -1,22 +1,31 @@
.subject {
box-sizing: border-box;
color: #fff;
margin-top: -120px;
transition: margin-top .3s ease-in;
margin-top: 20px;
position: absolute;
top: -120px;
transition: top .3s ease-in;
width: 100%;
z-index: $zindex3;
&.visible {
margin-top: 20px;
top: 0px;
}
}
.subject-info-container {
display: flex;
justify-content: center;
max-width: calc(100% - 280px);
margin: 0 auto;
height: 28px;
&--full-width {
max-width: 100%;
}
@media (max-width: 500px) {
flex-wrap: wrap;
max-width: 100%;
}
}
@@ -31,47 +40,21 @@
.subject-text {
background: rgba(0, 0, 0, 0.6);
border-radius: 3px 0px 0px 3px;
box-sizing: border-box;
font-size: 14px;
line-height: 28px;
padding: 0 16px;
height: 28px;
@media (max-width: 700px) {
max-width: 100px;
}
@media (max-width: 300px) {
display: none;
}
&--content {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
line-height: 24px;
padding: 2px 16px;
height: 24px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.subject-timer {
background: rgba(0, 0, 0, 0.8);
border-radius: 0px 3px 3px 0px;
box-sizing: border-box;
display: inline-block;
font-size: 12px;
line-height: 28px;
line-height: 16px;
min-width: 34px;
padding: 0 8px;
height: 28px;
@media (max-width: 300px) {
display: none;
}
}
.details-container {
width: 100%;
display: flex;
justify-content: center;
position: absolute;
top: 0;
height: 48px;
padding: 6px 8px;
}

View File

@@ -54,7 +54,6 @@
margin-bottom: 16px;
position: relative;
z-index: $toolbarZ;
pointer-events: none;
.button-group-center,
.button-group-left,
@@ -104,24 +103,15 @@
flex-direction: column;
margin: 0 auto;
max-width: 100%;
pointer-events: all;
border-radius: 6px;
}
.toolbox-content-wrapper::after {
content: '';
background: $newToolbarBackgroundColor;
padding-bottom: env(safe-area-inset-bottom, 0);
}
.toolbox-content-items {
background: $newToolbarBackgroundColor;
box-shadow: 0px 2px 8px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.15);
border-radius: 6px;
margin: 0 auto;
padding: 6px;
text-align: center;
pointer-events: all;
box-shadow: 0px 2px 8px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.15);
>div {
margin-left: 8px;
@@ -285,10 +275,6 @@
}
}
.profile-button-avatar {
align-items: center;
}
/**
* START of fade in animation for main toolbar
*/
@@ -334,7 +320,7 @@
border-radius: 0;
display: flex;
justify-content: space-evenly;
padding: 8px 0;
padding: 6px 0;
width: 100%;
}

View File

@@ -16,8 +16,8 @@
z-index: $subtitlesZ;
&.lifted {
// Lift subtitle above toolbar+dominant speaker box.
bottom: $newToolbarSize + 36px + 40px;
// Lift subtitle above toolbar+invite box.
bottom: $newToolbarSize + 112px + 40px;
}
span {

View File

@@ -46,7 +46,6 @@ $menuBG:#242528;
$newToolbarFontSize: 24px;
$newToolbarHangupFontSize: 32px;
$newToolbarSize: 48px;
$newToolbarSizeMobile: 60px;
$newToolbarSizeWithPadding: calc(#{$newToolbarSize} + 24px);
$toolbarTitleFontSize: 19px;
$overflowMenuItemColor: #fff;
@@ -116,6 +115,7 @@ $zindex2: 2;
$zindex3: 3;
$toolbarBackgroundZ: 4;
$labelsZ: 5;
$filmstripVideosZ: 6;
$subtitlesZ: 7;
$popoverZ: 8;
$zindex10: 10;
@@ -130,9 +130,6 @@ $dropdownMaskZ: 900;
$dropdownZ: 901;
$centeredVideoLabelZ: 1010;
$overlayZ: 1016;
// Place filmstrip videos over toolbar in order
// to make connection info visible.
$filmstripVideosZ: $toolbarZ + 1;
/**
@@ -264,9 +261,3 @@ $chromeExtensionBannerRightInMeeeting: 10px;
*/
$smallScreen: 700px;
$verySmallScreen: 500px;
/**
* Prejoin / premeeting screen
*/
$prejoinDefaultContentWidth: 336px;

View File

@@ -79,8 +79,4 @@
white-space: nowrap;
}
}
// Override @atlaskit/InlineDialog container which is made with styled components
& > div:nth-child(2) {
padding: 0;
}
}

View File

@@ -240,15 +240,6 @@
object-fit: cover;
}
#sharedVideo video {
width: 100%;
height: 100%;
}
#sharedVideo.disable-pointer {
pointer-events: none;
}
#sharedVideo,
#etherpad,
#localVideoWrapper video,
@@ -428,7 +419,7 @@
right: 0;
z-index: $zindex2;
width: 18px;
height: 18px;
height: 13px;
color: #FFF;
font-size: 10pt;
margin-right: $remoteVideoMenuIconMargin;

View File

@@ -122,11 +122,11 @@ body.welcome-page {
#moderated-meetings {
max-width: calc(100% - 40px);
padding: 16px 0 39px 0;
margin: $welcomePageEnterRoomMargin;
width: $welcomePageEnterRoomWidth;
p {
color: $welcomePageDescriptionColor;
float: left;
text-align: $welcomePageHeaderTextAlign;
a {

View File

@@ -3,7 +3,7 @@
justify-content: space-between;
align-items: center;
padding: 8px 8px 8px 16px;
margin-top: 5px;
margin-top: 8px;
width: calc(100% - 24px);
height: 24px;

View File

@@ -9,10 +9,10 @@ input[type=range]{
}
/**
* Show focus for keyboard accessibility.
* Disable the default focus styles for webkit range inputs (sliders).
*/
input[type=range]:focus {
outline: 1px solid white !important;
outline: none;
}
/**

View File

@@ -16,6 +16,7 @@
padding: 0;
margin: 0;
border: none;
outline: none;
-webkit-appearance: none;

View File

@@ -33,18 +33,18 @@
}
&__videos {
@extend %align-right;
position:relative;
padding: 0;
/* The filmstrip should not be covered by the left toolbar. */
bottom: 0;
width:auto;
overflow: visible !important;
&#remoteVideos {
border: $thumbnailsBorder solid transparent;
transition: bottom 2s;
flex-grow: 1;
display: flex;
flex-direction: row-reverse;
@include minHWAutoFix()
}
@@ -60,25 +60,41 @@
&.hidden {
bottom: calc(-196px - #{$newToolbarSizeWithPadding});
}
.remote-videos-container {
display: flex;
}
}
.remote-videos {
& > div {
transition: opacity 1s;
position: absolute;
}
&.is-not-overflowing > div {
right: 2px;
}
.remote-videos-container {
transition: opacity 1s;
}
&.hide-videos {
.remote-videos {
& > div {
opacity: 0;
pointer-events: none;
}
.remote-videos-container {
opacity: 0;
pointer-events: none;
}
}
#filmstripRemoteVideos {
@include minHWAutoFix();
display: flex;
flex: 1;
width: auto;
justify-content: flex-end;
flex-direction: row;
#filmstripRemoteVideosContainer {
flex-direction: row-reverse;
/**
* Add padding as a hack for Firefox not to show scrollbars when
* unnecessary.
*/
padding: 1px 0;
overflow-y: hidden;
overflow-x: scroll;
}
}
@@ -87,3 +103,25 @@
}
}
/**
* Workarounds for Edge and Firefox not handling scrolling properly with
* flex-direction: row-reverse.
*/
@mixin undoRowReverseVideos() {
.horizontal-filmstrip {
#remoteVideos #filmstripRemoteVideos #filmstripRemoteVideosContainer {
flex-direction: row;
}
}
}
/** Firefox detection hack **/
@-moz-document url-prefix() {
@include undoRowReverseVideos();
}
/** Edge detection hack **/
@supports (-ms-ime-align:auto) {
@include undoRowReverseVideos();
}

View File

@@ -7,14 +7,16 @@
* see.
*/
.active-speaker {
box-shadow: 0px 0px 1px 1.5px black, 0px 0px 1.3px 4px $videoThumbnailSelected;
box-shadow: 0 0 5px 3px $videoThumbnailSelected
}
.remote-videos {
#filmstripRemoteVideos {
align-items: center;
box-sizing: border-box;
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
.filmstrip__videos .videocontainer {
@@ -32,10 +34,6 @@
*/
height: 100% !important;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
transition: margin-bottom .3s ease-in;
}
.filmstrip {
@@ -52,22 +50,6 @@
&.shift-right {
margin-left: $sidebarWidth;
width: calc(100% - #{$sidebarWidth});
.remote-videos {
width: calc(100vw - #{$sidebarWidth});
}
}
}
&.collapse {
#remoteVideos {
height: calc(100% - #{$newToolbarSizeMobile}) !important;
margin-bottom: $newToolbarSizeMobile;
}
.remote-videos {
// !important is needed here as overflow is set via element.style in a FixedSizeGrid.
overflow: hidden auto !important;
}
}
}
@@ -80,49 +62,63 @@
display: block;
}
.remote-videos {
#filmstripRemoteVideos {
box-sizing: border-box;
/**
* Allow vertical scrolling of the thumbnails.
*/
overflow-x: hidden;
overflow-y: auto;
}
/**
* The size of the thumbnails should be set with javascript, based on
* desired column count and window width. The rows are created using flex
* and allowing the thumbnails to wrap.
*/
#filmstripRemoteVideosContainer {
align-content: center;
align-items: center;
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
flex-shrink: 0;
margin-top: auto;
margin-bottom: auto;
justify-content: center;
.videocontainer {
border: 0;
box-sizing: border-box;
display: block;
margin: 2px;
}
video {
object-fit: contain;
}
/**
* The size of the thumbnails should be set with javascript, based on
* desired column count and window width. The rows are created using flex
* and allowing the thumbnails to wrap.
*/
& > div {
align-content: center;
align-items: center;
box-sizing: border-box;
display: flex;
margin-top: auto;
margin-bottom: auto;
justify-content: center;
position: absolute;
.videocontainer {
border: 0;
box-sizing: border-box;
display: block;
margin: 2px;
}
* Max-width corresponding to the ASPECT_RATIO_BREAKPOINT from features/filmstrip/constants.
*/
@media only screen and (max-width: 500px) {
video {
object-fit: contain;
}
/**
* Max-width corresponding to the ASPECT_RATIO_BREAKPOINT from features/filmstrip/constants.
*/
@media only screen and (max-width: 500px) {
video {
object-fit: cover;
}
object-fit: cover;
}
}
}
.has-overflow#filmstripRemoteVideosContainer {
align-content: baseline;
}
.has-overflow .videocontainer {
align-self: baseline;
}
}
.shift-right .remote-videos > div {
.shift-right #filmstripRemoteVideosContainer {
/**
* Max-width corresponding to the ASPECT_RATIO_BREAKPOINT from features/filmstrip/constants,
* from which we subtract the chat size.
@@ -133,7 +129,3 @@
}
}
}
.indicator-icon-container {
display: inline-block;
}

View File

@@ -1,10 +1,8 @@
.vertical-filmstrip .filmstrip {
&.hide-videos {
.remote-videos {
& > div {
opacity: 0;
pointer-events: none;
}
.remote-videos-container {
opacity: 0;
pointer-events: none;
}
}
@@ -28,7 +26,7 @@
flex-direction: column-reverse;
height: 100%;
width: 100%;
padding: ($desktopAppDragBarHeight - 5px) 5px calc(env(safe-area-inset-bottom, 0) + 10px);
padding: ($desktopAppDragBarHeight - 5px) 5px 10px;
/**
* fixed positioning is necessary for remote menus and tooltips to pop
* out of the scrolling filmstrip. AtlasKit dialogs and tooltips use
@@ -41,6 +39,10 @@
right: 0;
z-index: $filmstripVideosZ;
&.reduce-height {
height: calc(100% - #{$newToolbarSizeWithPadding});
}
/**
* Hide videos by making them slight to the right.
*/
@@ -96,10 +98,33 @@
* filmstrip from overlapping the left edge of the screen.
*/
#filmstripLocalVideo,
.remote-videos {
#filmstripRemoteVideos {
padding: 0;
}
#filmstripRemoteVideos {
@include minHWAutoFix();
display: flex;
flex: 1;
flex-direction: column-reverse;
height: auto;
overflow-x: hidden;
overflow-y: scroll;
#filmstripRemoteVideosContainer {
@include minHWAutoFix();
flex-direction: column-reverse;
overflow: visible;
width: calc(100% - 8px); // 8px for margin + border of the thumbnails
.videocontainer {
height: 0px;
width: 100%;
}
}
}
#remoteVideos {
@include minHWAutoFix();
@@ -107,21 +132,56 @@
flex-grow: 1;
}
&.reduce-height {
height: calc(100% - calc(#{$newToolbarSizeWithPadding} + #{$scrollHeight}));
.remote-videos-container {
display: flex;
transition: opacity 1s;
}
.remote-videos {
display: flex;
transition: height .3s ease-in;
& > div {
position: absolute;
transition: opacity 1s;
}
&.is-not-overflowing > div {
bottom: 0px;
.hide-scrollbar#filmstripRemoteVideos {
margin-right: 7px; // Scrollbar size
&::-webkit-scrollbar {
display: none;
}
}
}
/**
* Workarounds for Edge and Firefox not handling scrolling properly with
* flex-direction: column-reverse. The remove videos in filmstrip should
* start scrolling from the bottom of the filmstrip, but in those browsers the
* scrolling won't happen. Per W3C spec, scrolling should happen from the
* bottom. As such, use css hacks to get around the css issue, with the intent
* being to remove the hacks as the spec is supported.
*/
@mixin undoColumnReverseVideos() {
.vertical-filmstrip {
#remoteVideos #filmstripRemoteVideos #filmstripRemoteVideosContainer {
flex-direction: column;
}
}
}
/**
* FF does not include the scroll width when calculating the size of the content. That's why we need to include
* ourselves the width of the scroll so that the remote videos are aligned with the local one.
*/
@mixin filmstripSizeWithoutScroll {
.vertical-filmstrip {
#remoteVideos #filmstripRemoteVideos {
#filmstripRemoteVideosContainer {
width: calc(100% - 15px) // 8 px - margins + border of the thumbnails; 7px - for the scroll
}
}
}
}
/** Firefox detection hack **/
@-moz-document url-prefix() {
@include undoColumnReverseVideos();
@include filmstripSizeWithoutScroll();
}
/** Edge detection hack **/
@supports (-ms-ime-align:auto) {
@include undoColumnReverseVideos();
}

View File

@@ -81,13 +81,9 @@
.local-video-menu-trigger,
.remote-video-menu-trigger {
margin-bottom: 3px;
margin-bottom: 7px;
margin-left: $remoteVideoMenuIconMargin;
}
.self-view-mobile-portrait video {
object-fit: contain;
}
}
/**
@@ -116,11 +112,3 @@
transition-delay: 0.1s;
}
}
/**
* Overrides for self view when in portrait mode on mobile.
* This is done in order to keep the aspect ratio.
*/
.vertical-filmstrip .self-view-mobile-portrait #localVideo_container {
object-fit: contain;
}

View File

@@ -41,8 +41,6 @@ $flagsImagePath: "../images/";
@import 'modals/feedback/feedback';
@import 'modals/invite/info';
@import 'modals/settings/settings';
@import 'modals/screen-share/share-audio';
@import 'modals/screen-share/share-screen-warning';
@import 'modals/speaker_stats/speaker_stats';
@import 'modals/video-quality/video-quality';
@import 'modals/virtual-background/virtual-background';
@@ -79,6 +77,7 @@ $flagsImagePath: "../images/";
@import 'filmstrip/vertical_filmstrip';
@import 'filmstrip/vertical_filmstrip_overrides';
@import 'labels';
@import 'lobby';
@import 'unsupported-browser/main';
@import 'modals/invite/add-people';
@import 'deep-linking/main';
@@ -94,17 +93,16 @@ $flagsImagePath: "../images/";
@import 'meter';
@import 'audio-preview';
@import 'video-preview';
@import 'premeeting/main';
@import 'prejoin';
@import 'prejoin-dialog';
@import 'country-picker';
@import 'modals/invite/invite_more';
@import 'modals/security/security';
@import 'modals/mute/mute-dialog';
@import 'premeeting-screens';
@import 'e2ee';
@import 'responsive';
@import 'connection-status';
@import 'drawer';
@import 'participants-pane';
@import 'reactions-menu';
@import 'plan-limit';
@import 'polls';
/* Modules END */

View File

@@ -103,7 +103,7 @@
font-size: 14px;
a {
color: #6FB1EA;
color: #2684FF;
cursor: pointer;
text-decoration: none;
}
@@ -119,7 +119,7 @@
height: 8px;
.audio-input-preview-level {
background: #75B1FF;
background: #4C9AFF;
border-radius: 5px;
height: 100%;
-webkit-transition: width .1s ease-in-out;
@@ -129,20 +129,3 @@
}
}
}
.device-selection.video-hidden {
display: flex;
flex-direction: column;
width: 100%;
.column-selectors {
width: 100%;
margin-left: 0;
}
.column-video {
order: 1;
width: 100%;
margin-top: 8px;
}
}

View File

@@ -94,9 +94,5 @@
};
}
.star-btn:focus,
.star-btn:active {
outline: 1px solid #B8C7E0;
}
}
}

View File

@@ -30,26 +30,20 @@
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: 5px;
}
.info-password-none,
.info-password-remote {
color: #fff;
opacity: 0.5;
}
.info-password-input {
width: 100%;
background-color: #0E1624;
border-radius: 3px;
border: 2px solid #202B3D;
background-color: transparent;
border: none;
color: inherit;
padding-left: 0;
}
.info-password-input:focus ,
.info-password-input:active {
border: 2px solid #B8C7E0;
}
.info-password-local {
user-select: text;

View File

@@ -130,7 +130,6 @@
display: inline-block;
vertical-align: middle;
cursor: pointer;
height: 24px;
}
}
@@ -142,7 +141,7 @@
& > a {
display: inline-block;
height: 24px;
min-width: 48px;
width: 48px;
border-radius: 3px;
text-align: center;
text-decoration: none;

View File

@@ -1,19 +0,0 @@
.mute-dialog {
.separator-line {
margin: 24px 0 24px -20px;
padding: 0 20px;
width: 100%;
height: 1px;
background: #5E6D7A;
}
.control-row {
display: flex;
justify-content: space-between;
margin-top: 15px;
label {
font-size: 14px;
}
}
}

View File

@@ -1,22 +0,0 @@
.share-audio-dialog {
.share-audio-animation {
width: 100%;
height: 90%;
object-fit: contain;
}
input[type="checkbox"] + svg + span {
color: #9FB0CC;
}
.separator-line {
margin: 24px 0 24px -20px;
padding: 0 20px;
width: 100%;
height: 1px;
background: #5E6D7A;
&:last-child {
display: none;
}
}
}

View File

@@ -1,23 +0,0 @@
.share-screen-warn-dialog {
font-size: 14px;
.separator-line {
margin: 24px 0 24px -20px;
padding: 0 20px;
width: 100%;
height: 1px;
background: #5E6D7A;
&:last-child {
display: none;
}
}
.header {
font-weight: 600;
}
.description {
margin-top: 16px;
}
}

View File

@@ -16,19 +16,12 @@
}
.mock-atlaskit-label {
color: #b8c7e0;
color: #56637A;
font-size: 12px;
font-weight: 600;
line-height: 1.33;
padding: 20px 0px 4px 0px;
}
input[type="checkbox"]:checked + svg {
--checkbox-background-color: #6492e7;
--checkbox-border-color: #6492e7;
}
input[type="checkbox"] + svg + span {
color: #b8c7e0;
}
input[type="checkbox"] + svg + span {
color: #9FB0CC;
@@ -36,12 +29,6 @@
.calendar-tab,
.more-tab,
.box {
display: flex;
justify-content: space-between;
width: 100%;
}
.profile-edit {
display: flex;
width: 100%;
@@ -51,24 +38,18 @@
flex: 1;
}
.settings-sub-pane {
flex: 1;
flex-grow: 1;
}
.settings-sub-pane .right {
flex: 1;
}
.settings-sub-pane .left {
flex: 1;
}
.settings-sub-pane-element {
text-align: left;
flex: 1;
}
.profile-edit-field {
margin-right: 20px;
}
.language-settings {
max-width: 50%;
width: 35%;
}
.calendar-tab {
align-items: center;
flex-direction: column;
@@ -84,14 +65,4 @@
.sign-out-cta {
margin-bottom: 20px;
}
@media only screen and (max-width: $smallScreen) {
.device-selection {
display: flex;
flex-direction: column;
}
.more-tab {
flex-direction: column;
}
}
}

View File

@@ -86,7 +86,6 @@
.video-quality-dialog-label-container.active {
color: $videoQualityActive;
font-weight: bold;
&::before {
background: $videoQualityActive;

View File

@@ -1,109 +1,118 @@
.virtual-background-dialog {
margin-left: -10px;
position: relative;
max-height: 300px;
color: white;
display: inline-grid;
grid-template-columns: auto auto auto auto auto;
column-gap: 9px;
column-gap: 8px;
cursor: pointer;
.desktop-share:hover,
.thumbnail:hover,
.blur:hover,
.slight-blur:hover,
.virtual-background-none:hover {
opacity: 0.5;
.thumbnail:hover, .blur:hover, .slight-blur:hover, .virtual-background-none:hover{
height: 56px;
width: 103px;
opacity: .5;
border: 2px solid #99bbf3;
@media (max-width: 632px) {
height: 60px;
width: 60px;
@media (min-width: 432px) and (max-width: 632px) {
height: 56px;
width: 56px;
}
}
.background-option {
.thumbnail {
margin-top: 8px;
border-radius: 6px;
object-fit: cover;
height: 60px;
width: 107px;
text-align: center;
justify-content: center;
font-weight: bold;
box-sizing: border-box;
display: flex;
align-items: center;
}
.thumbnail {
object-fit: cover;
}
.thumbnail:hover ~ .delete-image-icon {
display: block;
}
.thumbnail-selected {
margin-top: 8px;
border-radius: 6px;
object-fit: cover;
border: 2px solid #246fe5;
height: 60px;
width: 107px;
border: 2px solid #246FE5;
}
.blur {
.blur{
box-shadow: inset 0 0 12px #000000;
background: #7e8287;
padding: 0 10px;
margin-top: 8px;
background: #7E8287;
font-weight: bold;
height: 60px;
width: 107px;
border-radius: 6px;
text-align: center;
vertical-align: middle;
line-height: 60px;
}
.blur-selected {
box-shadow: inset 0 0 12px #000000;
background: #7e8287;
border: 2px solid #246fe5;
padding: 0 10px;
margin-top: 8px;
background: #7E8287;
font-weight: bold;
height: 60px;
width: 107px;
border-radius: 6px;
border: 2px solid #246FE5;
text-align: center;
vertical-align: middle;
line-height: 60px;
}
.slight-blur {
.slight-blur{
box-shadow: inset 0 0 12px #000000;
background: #a4a4a4;
padding: 0 10px;
margin-top: 8px;
background: #A4A4A4;
font-weight: bold;
height: 60px;
width: 107px;
border-radius: 6px;
text-align: center;
vertical-align: middle;
line-height: 60px;
}
.slight-blur-selected {
.slight-blur-selected{
box-shadow: inset 0 0 12px #000000;
background: #a4a4a4;
border: 2px solid #246fe5;
padding: 0 10px;
margin-top: 8px;
background: #A4A4A4;
font-weight: bold;
height: 60px;
width: 107px;
border-radius: 6px;
border: 2px solid #246FE5;
text-align: center;
vertical-align: middle;
line-height: 60px;
}
.virtual-background-none {
margin-top: 8px;
background: #525252;
padding: 0 10px;
font-weight: bold;
height: 60px;
width: 107px;
border-radius: 6px;
text-align: center;
vertical-align: middle;
line-height: 60px;
}
.none-selected {
margin-top: 8px;
background: #525252;
border: 2px solid #246fe5;
padding: 0 10px;
font-weight: bold;
height: 60px;
width: 107px;
border-radius: 6px;
border: 2px solid #246FE5;
text-align: center;
vertical-align: middle;
line-height: 60px;
}
.desktop-share {
background: #525252;
}
.desktop-share-selected {
background: #525252;
border: 2px solid #246fe5;
padding: 0 10px;
}
@media (max-width: 632px) {
@media (min-width: 432px) and (max-width: 632px) {
font-size: 1.5vw;
.desktop-share,
.virtual-background-none,
.thumbnail,
.blur,
.slight-blur {
.virtual-background-none, .thumbnail, .thumbnail-selected, .none-selected, .blur, .blur-selected, .slight-blur, .slight-blur-selected{
height: 60px;
width: 60px;
}
.desktop-share-selected,
.thumbnail-selected,
.none-selected,
.blur-selected,
.slight-blur-selected {
height: 60px;
width: 60px;
}
}
@media (max-width: 360px) {
grid-template-columns: auto auto auto;
}
}
@@ -120,14 +129,13 @@
.file-upload-btn {
display: none;
}
.file-upload-label {
.file-upload-label{
font-size: 14px;
font-weight: 600;
line-height: 20px;
margin-left: -10px;
margin-top: 16px;
margin-bottom: 8px;
color: #669aec;
color: #669AEC;
display: inline-flex;
cursor: pointer;
}
@@ -138,54 +146,28 @@
display: none;
left: 96;
bottom: 51;
@media (max-width: 632px) {
left: 51px;
@media (min-width: 432px) and (max-width: 632px) {
left: 51px
}
}
.delete-image-icon:hover {
display: block;
}
.thumbnail-container {
position: relative;
&:focus-within {
.thumbnail ~ .delete-image-icon {
display: block;
}
}
}
.add-background {
.add-background{
margin-right: 8px;
}
.apply-background-btn {
.apply-background-btn{
margin-top: 16px;
float: right;
}
}
.video-background-preview-entry {
margin-left: -10px;
height: 250px;
width: 570px;
margin-bottom: 8px;
z-index: 2;
@media (max-width: 632px) {
max-width: 336;
}
}
.virtual-background-preview-video {
margin-left: -10;
border-radius: 6px;
height: 100%;
object-fit: cover;
width: 100%;
}
.video-preview-loader {
border-radius: 6px;
background-color: transparent;
.video-background-preview-entry{
height: 250px;
margin-bottom: 8px;
width: 572px;
@@ -194,10 +176,11 @@
@media (min-width: 432px) and (max-width: 632px) {
width: 340px;
}
}
}
.video-preview-loader svg {
position: absolute;
top: 40%;
left: 45%;
}
.video-preview-loader{
position: fixed;
left: 50%;
top: 35%;
transform: translate(-50%,-35%);
}

View File

@@ -1,38 +0,0 @@
.device {
&-status {
align-items: center;
color: #fff;
display: flex;
font-size: 14px;
line-height: 20px;
padding: 6px;
text-align: center;
&-error {
align-items: flex-start;
background-color: #F8AE1A;
border-radius: 6px;
color: #040404;
padding: 12px 16px;
text-align: left;
}
span {
margin-left: 16px;
}
}
&-icon {
background-position: center;
background-repeat: no-repeat;
display: inline-block;
height: 16px;
width: 16px;
&--ok {
svg path {
fill: #189b55;
}
}
}
}

View File

@@ -1,7 +0,0 @@
@import 'connection-status';
@import 'device-status';
@import 'lobby';
@import 'premeeting-screens';
@import 'prejoin';
@import 'prejoin-dialog';
@import 'prejoin-third-party';

View File

@@ -1,40 +0,0 @@
$sidePanelWidth: 300px;
.prejoin-third-party {
flex-direction: column-reverse;
.content {
height: auto;
margin: 0 auto;
width: auto;
.new-toolbox {
width: auto;
}
}
#preview {
background-color: transparent;
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0;
.avatar {
display: none;
}
}
&.splash {
.content {
margin-left: calc((100% - #{$prejoinDefaultContentWidth} + #{$sidePanelWidth}) / 2)
}
}
&.guest {
.content {
margin-bottom: auto;
}
}
}

View File

@@ -1,68 +0,0 @@
.prejoin {
&-input-area {
width: 100%;
}
&-error {
background-color: #E04757;
border-radius: 6px;
box-sizing: border-box;
color: white;
font-size: 12px;
line-height: 16px;
margin-bottom: 16px;
margin-top: -8px;
padding: 4px;
text-align: center;
width: 100%;
}
}
.prejoin-preview {
&-dropdown-btns {
padding: 8px 0;
width: calc(100% - 48px);
}
&-dropdown-btn {
align-items: center;
color: #1C2025;
cursor: pointer;
display: flex;
height: 40px;
font-size: 15px;
line-height: 24px;
padding: 0 16px;
&:hover {
background-color: #DAEBFA;
}
}
&-dropdown-icon {
display: inline-block;
margin-right: 16px;
& > svg {
fill: #1C2025;
}
}
&-dropdown-container {
position: relative;
width: 100%;
/**
* Override default InlineDialog behaviour, since it does not play nicely with relative widths
*/
& > div:nth-child(2) {
background: #fff;
padding: 0;
position: absolute !important;
top: 48px !important;
transform: none !important;
width: 100%;
}
}
}

View File

@@ -1,245 +0,0 @@
.premeeting-screen {
background: #292929;
bottom: 0;
display: flex;
font-size: 1.3em;
left: 0;
position: absolute;
right: 0;
top: 0;
z-index: $toolbarZ + 1;
.action-btn {
border-radius: 6px;
box-sizing: border-box;
color: #fff;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: 600;
line-height: 24px;
margin-bottom: 16px;
padding: 7px 16px;
position: relative;
text-align: center;
width: 100%;
&.primary {
background: #0376DA;
border: 1px solid #0376DA;
}
&.secondary {
background: #3D3D3D;
border: 1px solid transparent;
}
&.text {
width: auto;
font-size: 13px;
margin: 0;
padding: 0;
}
&.disabled {
background: #5E6D7A;
border: 1px solid #5E6D7A;
color: #AFB6BC;
cursor: initial;
.icon {
& > svg {
fill: #AFB6BC;
}
}
}
.options {
border-radius: 3px;
align-items: center;
display: flex;
height: 100%;
justify-content: center;
position: absolute;
right: 0;
top: 0;
width: 36px;
&:hover {
background-color: #0262B6;
}
svg {
pointer-events: none;
}
}
}
.content {
align-items: center;
box-sizing: border-box;
display: flex;
flex-direction: column;
flex-shrink: 0;
height: 100%;
margin: 0 110px;
padding: 24px 0 16px;
position: relative;
width: $prejoinDefaultContentWidth;
z-index: $toolbarZ + 2;
&-controls {
align-items: center;
display: flex;
flex-direction: column;
margin: auto;
width: 100%;
.title {
color: #fff;
font-size: 28px;
font-weight: 600;
letter-spacing: -0.015;
line-height: 36px;
margin-bottom: 32px;
text-align: center;
}
input.field {
background-color: white;
border: none;
outline: none;
border-radius: 6px;
font-size: 14px;
line-height: 20px;
margin-bottom: 16px;
color: #1C2025;
padding: 10px 16px;
text-align: center;
width: 100%;
&.error {
border: 1px solid #E04757;
}
&.focused {
box-shadow: 0px 0px 1px 1.5px black, 0px 0px 1.3px 4px white;
}
}
#new-toolbox {
bottom: 0;
position: relative;
transition: none;
.toolbox-content {
margin-bottom: 4px;
}
.toolbox-content-items {
background: transparent;
border-radius: 0;
box-shadow: none;
display: flex;
justify-content: space-evenly;
padding: 8px 0;
}
.toolbox-content,
.toolbox-content-wrapper,
.toolbox-content-items {
box-sizing: border-box;
width: 100%;
}
}
}
}
@media (max-width: 1000px) {
flex-direction: column-reverse;
.content {
height: auto;
margin: 0 auto;
}
.con-status {
margin: 24px auto;
position: fixed;
top: 0;
width: $prejoinDefaultContentWidth;
}
}
@media (max-width: 400px) {
.content {
padding: 16px;
width: 100%;
&-controls {
input.field {
font-size: 16px;
padding: 14px 16px;
}
}
.title {
display: none;
}
}
.con-status {
margin: 0;
width: 100%;
}
.device-status-error {
border-radius: 0;
margin: 0 -16px;
}
input.field {
font-size: 16px;
padding: 14px 16px;
}
.action-btn {
font-size: 16px;
margin-bottom: 8px;
padding: 11px 16px;
}
}
input::placeholder {
color: #040404;
}
}
#preview {
background: #040404;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
.avatar {
text {
fill: white;
font-size: 26px;
font-weight: 400;
}
}
video {
height: 100%;
object-fit: cover;
width: 100%;
}
}
@mixin flex-centered() {
align-items: center;
display: flex;
justify-content: center;
}

View File

@@ -107,4 +107,4 @@ $selectActiveItemBg: darken($controlBackground, 20%);
/**
* TODO: Replace by themed component.
*/
$videoQualityActive: #57A0ff;
$videoQualityActive: #4C9AFF;

2
debian/control vendored
View File

@@ -33,7 +33,7 @@ Description: Configuration for web serving of Jitsi Meet
Package: jitsi-meet-prosody
Architecture: all
Depends: openssl, prosody (>= 0.11.0) | prosody-trunk | prosody-0.11, lua-sec
Depends: openssl, prosody | prosody-trunk | prosody-0.11, lua-sec
Replaces: jitsi-meet-tokens
Description: Prosody configuration for Jitsi Meet
Jitsi Meet is a WebRTC JavaScript application that uses Jitsi

View File

@@ -125,11 +125,11 @@ case "$1" in
# Check whether prosody config has the internal muc, if not add it,
# as we are migrating configs
if [ -f $PROSODY_HOST_CONFIG ] && ! grep -q "internal.$JICOFO_AUTH_DOMAIN" $PROSODY_HOST_CONFIG; then
echo -e "\nComponent \"internal.$JICOFO_AUTH_DOMAIN\" \"muc\"" >> $PROSODY_HOST_CONFIG
if [ -f $PROSODY_HOST_CONFIG ] && ! grep -q "internal.auth.$JVB_HOSTNAME" $PROSODY_HOST_CONFIG; then
echo -e "\nComponent \"internal.auth.$JVB_HOSTNAME\" \"muc\"" >> $PROSODY_HOST_CONFIG
echo -e " storage = \"memory\"" >> $PROSODY_HOST_CONFIG
echo -e " modules_enabled = { \"ping\"; }" >> $PROSODY_HOST_CONFIG
echo -e " admins = { \"$JICOFO_AUTH_USER@$JICOFO_AUTH_DOMAIN\", \"jvb@$JICOFO_AUTH_DOMAIN\" }" >> $PROSODY_HOST_CONFIG
echo -e " admins = { \"$JICOFO_AUTH_USER@auth.$JVB_HOSTNAME\", \"jvb@auth.$JVB_HOSTNAME\" }" >> $PROSODY_HOST_CONFIG
fi
# Convert the old focus component config to the new one.
@@ -140,7 +140,7 @@ case "$1" in
# Component "focus.jitmeet.example.com" "client_proxy"
# target_address = "focus@auth.jitmeet.example.com"
if grep -q "Component \"focus.$JVB_HOSTNAME\"" $PROSODY_HOST_CONFIG && ! grep "Component \"focus.$JVB_HOSTNAME\" \"client_proxy\"" $PROSODY_HOST_CONFIG ;then
sed -i "s/Component \"focus.$JVB_HOSTNAME\"/Component \"focus.$JVB_HOSTNAME\" \"client_proxy\"\n target_address = \"$JICOFO_AUTH_USER@$JICOFO_AUTH_DOMAIN\"/g" $PROSODY_HOST_CONFIG
sed -i "s/Component \"focus.$JVB_HOSTNAME\"/Component \"focus.$JVB_HOSTNAME\" \"client_proxy\"\n target_address = \"$JICOFO_AUTH_USER@auth.$JVB_HOSTNAME\"/g" $PROSODY_HOST_CONFIG
PROSODY_CONFIG_PRESENT="false"
fi
@@ -151,21 +151,8 @@ case "$1" in
PROSODY_CONFIG_PRESENT="false"
fi
# Updates main muc component
MAIN_MUC_PATTERN="Component \"conference.$JVB_HOSTNAME\" \"muc\""
if ! grep -A 2 -- "${MAIN_MUC_PATTERN}" $PROSODY_HOST_CONFIG | grep -q "restrict_room_creation" ;then
sed -i "s/${MAIN_MUC_PATTERN}/${MAIN_MUC_PATTERN}\n restrict_room_creation = true/g" $PROSODY_HOST_CONFIG
PROSODY_CONFIG_PRESENT="false"
fi
if ! grep -q -- 'unlimited_jids' $PROSODY_HOST_CONFIG ;then
sed -i "1s/^/unlimited_jids = { \"$JICOFO_AUTH_USER@$JICOFO_AUTH_DOMAIN\", \"jvb@$JICOFO_AUTH_DOMAIN\" }\n/" $PROSODY_HOST_CONFIG
sed -i "s/VirtualHost \"$JICOFO_AUTH_DOMAIN\"/VirtualHost \"$JICOFO_AUTH_DOMAIN\"\n modules_enabled = { \"limits_exception\"; }/g" $PROSODY_HOST_CONFIG
PROSODY_CONFIG_PRESENT="false"
fi
# Make sure the focus@auth user's roster includes the proxy component (this is idempotent)
prosodyctl mod_roster_command subscribe focus.$JVB_HOSTNAME $JICOFO_AUTH_USER@$JICOFO_AUTH_DOMAIN
prosodyctl mod_roster_command subscribe focus.$JVB_HOSTNAME $JICOFO_AUTH_USER@auth.$JVB_HOSTNAME
if [ ! -f /var/lib/prosody/$JVB_HOSTNAME.crt ]; then
# prosodyctl takes care for the permissions

View File

@@ -20,11 +20,6 @@ ssl = {
ciphers = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"
}
unlimited_jids = {
"focusUser@auth.jitmeet.example.com",
"jvb@auth.jitmeet.example.com"
}
VirtualHost "jitmeet.example.com"
-- enabled = false -- Remove this line to enable this host
authentication = "anonymous"
@@ -40,7 +35,6 @@ VirtualHost "jitmeet.example.com"
key = "/etc/prosody/certs/jitmeet.example.com.key";
certificate = "/etc/prosody/certs/jitmeet.example.com.crt";
}
av_moderation_component = "avmoderation.jitmeet.example.com"
speakerstats_component = "speakerstats.jitmeet.example.com"
conference_duration_component = "conferenceduration.jitmeet.example.com"
-- we need bosh
@@ -52,7 +46,6 @@ VirtualHost "jitmeet.example.com"
"external_services";
"conference_duration";
"muc_lobby_rooms";
"av_moderation";
}
c2s_require_encryption = false
lobby_muc = "lobby.jitmeet.example.com"
@@ -60,12 +53,10 @@ VirtualHost "jitmeet.example.com"
-- muc_lobby_whitelist = { "recorder.jitmeet.example.com" } -- Here we can whitelist jibri to enter lobby enabled rooms
Component "conference.jitmeet.example.com" "muc"
restrict_room_creation = true
storage = "memory"
modules_enabled = {
"muc_meeting_id";
"muc_domain_mapper";
"polls";
--"token_verification";
}
admins = { "focusUser@auth.jitmeet.example.com" }
@@ -83,9 +74,6 @@ Component "internal.auth.jitmeet.example.com" "muc"
muc_room_default_public_jids = true
VirtualHost "auth.jitmeet.example.com"
modules_enabled = {
"limits_exception";
}
authentication = "internal_hashed"
-- Proxy to jicofo's user JID, so that it doesn't have to register as a component.
@@ -98,9 +86,6 @@ Component "speakerstats.jitmeet.example.com" "speakerstats_component"
Component "conferenceduration.jitmeet.example.com" "conference_duration_component"
muc_component = "conference.jitmeet.example.com"
Component "avmoderation.jitmeet.example.com" "av_moderation_component"
muc_component = "conference.jitmeet.example.com"
Component "lobby.jitmeet.example.com" "muc"
storage = "memory"
restrict_room_creation = true

View File

@@ -35,7 +35,6 @@ server {
ssl_session_tickets off;
add_header Strict-Transport-Security "max-age=63072000" always;
set $prefix "";
ssl_certificate /etc/jitsi/meet/jitsi-meet.example.com.crt;
ssl_certificate_key /etc/jitsi/meet/jitsi-meet.example.com.key;
@@ -77,7 +76,7 @@ server {
# BOSH
location = /http-bind {
proxy_pass http://127.0.0.1:5280/http-bind?prefix=$prefix&$args;
proxy_pass http://localhost:5280/http-bind;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
}
@@ -126,6 +125,13 @@ server {
alias /etc/jitsi/meet/jitsi-meet.example.com-config.js;
}
# Anything that didn't match above, and isn't a real file, assume it's a room name and redirect to /
location ~ ^/([^/?&:'"]+)/(.*)$ {
set $subdomain "$1.";
set $subdir "$1/";
rewrite ^/([^/?&:'"]+)/(.*)$ /$2;
}
# BOSH for subdomains
location ~ ^/([^/?&:'"]+)/http-bind {
set $subdomain "$1.";
@@ -143,11 +149,4 @@ server {
rewrite ^/(.*)$ /xmpp-websocket;
}
# Anything that didn't match above, and isn't a real file, assume it's a room name and redirect to /
location ~ ^/([^/?&:'"]+)/(.*)$ {
set $subdomain "$1.";
set $subdir "$1/";
rewrite ^/([^/?&:'"]+)/(.*)$ /$2;
}
}

0
eslint
View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

View File

@@ -25,16 +25,8 @@
Component: JitsiMeetJS.app.entryPoints.APP
})
const inIframe = () => {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
};
const isElectron = navigator.userAgent.includes('Electron');
const shouldRegisterWorker = !isElectron && !inIframe() && 'serviceWorker' in navigator;
const shouldRegisterWorker = !isElectron && 'serviceWorker' in navigator;
if (shouldRegisterWorker) {
navigator.serviceWorker
@@ -194,10 +186,10 @@
<!--#include virtual="static/settingsToolbarAdditionalContent.html" -->
</head>
<body>
<noscript aria-hidden="true">
<noscript>
<div>JavaScript is disabled. </br>For this site to work you have to enable JavaScript.</div>
</noscript>
<!--#include virtual="body.html" -->
<div id="react" role="main"></div>
<div id="react"></div>
</body>
</html>

View File

@@ -25,11 +25,31 @@ var interfaceConfig = {
BRAND_WATERMARK_LINK: '',
CLOSE_PAGE_GUEST_HINT: false, // A html text to be shown to guests on the close page, false disables it
/**
* Whether the connection indicator icon should hide itself based on
* connection strength. If true, the connection indicator will remain
* displayed while the participant has a weak connection and will hide
* itself after the CONNECTION_INDICATOR_HIDE_TIMEOUT when the connection is
* strong.
*
* @type {boolean}
*/
CONNECTION_INDICATOR_AUTO_HIDE_ENABLED: true,
// Connection indicators (
// CONNECTION_INDICATOR_AUTO_HIDE_ENABLED,
// CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT,
// CONNECTION_INDICATOR_DISABLED) got moved to config.js.
/**
* How long the connection indicator should remain displayed before hiding.
* Used in conjunction with CONNECTION_INDICATOR_AUTOHIDE_ENABLED.
*
* @type {number}
*/
CONNECTION_INDICATOR_AUTO_HIDE_TIMEOUT: 5000,
/**
* If true, hides the connection indicators completely.
*
* @type {boolean}
*/
CONNECTION_INDICATOR_DISABLED: false,
DEFAULT_BACKGROUND: '#474747',
DEFAULT_LOCAL_DISPLAY_NAME: 'me',
@@ -39,8 +59,7 @@ var interfaceConfig = {
DISABLE_DOMINANT_SPEAKER_INDICATOR: false,
// Deprecated. Please use disableModeratorIndicator from config.js
// DISABLE_FOCUS_INDICATOR: false,
DISABLE_FOCUS_INDICATOR: false,
/**
* If true, notifications regarding joining/leaving are no longer displayed.
@@ -155,7 +174,7 @@ var interfaceConfig = {
RECENT_LIST_ENABLED: true,
REMOTE_THUMBNAIL_RATIO: 1, // 1:1
SETTINGS_SECTIONS: [ 'devices', 'language', 'moderator', 'profile', 'calendar', 'sounds' ],
SETTINGS_SECTIONS: [ 'devices', 'language', 'moderator', 'profile', 'calendar' ],
/**
* Specify which sharing features should be displayed. If the value is not set
@@ -166,10 +185,10 @@ var interfaceConfig = {
SHOW_BRAND_WATERMARK: false,
/**
* Decides whether the chrome extension banner should be rendered on the landing page and during the meeting.
* If this is set to false, the banner will not be rendered at all. If set to true, the check for extension(s)
* being already installed is done before rendering.
*/
* Decides whether the chrome extension banner should be rendered on the landing page and during the meeting.
* If this is set to false, the banner will not be rendered at all. If set to true, the check for extension(s)
* being already installed is done before rendering.
*/
SHOW_CHROME_EXTENSION_BANNER: false,
SHOW_DEEP_LINKING_IMAGE: false,
@@ -189,7 +208,13 @@ var interfaceConfig = {
* DEPRECATED!
* This config was moved to config.js as `toolbarButtons`.
*/
// TOOLBAR_BUTTONS: [],
// TOOLBAR_BUTTONS: [
// 'microphone', 'camera', 'closedcaptions', 'desktop', 'embedmeeting', 'fullscreen',
// 'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
// 'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
// 'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
// 'tileview', 'select-background', 'download', 'help', 'mute-everyone', 'mute-video-everyone', 'security'
// ],
TOOLBAR_TIMEOUT: 4000,
@@ -205,8 +230,7 @@ var interfaceConfig = {
// Determines how the video would fit the screen. 'both' would fit the whole
// screen, 'height' would fit the original video height to the height of the
// screen, 'width' would fit the original video width to the width of the
// screen respecting ratio, 'nocrop' would make the video as large as
// possible and preserve aspect ratio without cropping.
// screen respecting ratio.
VIDEO_LAYOUT_FIT: 'both',
/**

View File

@@ -29,7 +29,7 @@ target 'JitsiMeetSDK' do
'CoreModulesHeaders',
'DevSupport',
'RCTWebSocket'
], :modular_headers => true
]
pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules'
pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
@@ -54,15 +54,11 @@ target 'JitsiMeetSDK' do
# React Native plugins
#
pod 'amplitude-react-native', :path => '../node_modules/@amplitude/react-native'
pod 'react-native-background-timer', :path => '../node_modules/react-native-background-timer'
pod 'react-native-calendar-events', :path => '../node_modules/react-native-calendar-events'
pod 'react-native-keep-awake', :path => '../node_modules/react-native-keep-awake'
pod 'react-native-netinfo', :path => '../node_modules/@react-native-community/netinfo'
pod 'react-native-performance', :path => '../node_modules/react-native-performance/ios'
pod 'react-native-slider', :path => '../node_modules/@react-native-community/slider'
pod 'react-native-splash-screen', :path => '../node_modules/react-native-splash-screen'
pod 'react-native-video', :path => '../node_modules/react-native-video/react-native-video.podspec'
pod 'react-native-webview', :path => '../node_modules/react-native-webview'
pod 'react-native-webrtc', :path => '../node_modules/react-native-webrtc'
pod 'RNCAsyncStorage', :path => '../node_modules/@react-native-async-storage/async-storage'
@@ -77,7 +73,7 @@ target 'JitsiMeetSDK' do
#
pod 'CocoaLumberjack', '~>3.5.3'
pod 'ObjectiveDropboxOfficial', '~>6.1.0'
pod 'ObjectiveDropboxOfficial', '~> 3.9.4'
use_native_modules!
end

View File

@@ -1,13 +1,9 @@
PODS:
- Amplitude (8.2.0)
- amplitude-react-native (2.3.3):
- Amplitude (= 8.2.0)
- React-Core
- AppAuth (1.4.0):
- AppAuth/Core (= 1.4.0)
- AppAuth/ExternalUserAgent (= 1.4.0)
- AppAuth/Core (1.4.0)
- AppAuth/ExternalUserAgent (1.4.0)
- AppAuth (1.2.0):
- AppAuth/Core (= 1.2.0)
- AppAuth/ExternalUserAgent (= 1.2.0)
- AppAuth/Core (1.2.0)
- AppAuth/ExternalUserAgent (1.2.0)
- boost-for-react-native (1.63.0)
- CocoaLumberjack (3.5.3):
- CocoaLumberjack/Core (= 3.5.3)
@@ -52,7 +48,7 @@ PODS:
- GoogleUtilities/Environment (~> 6.7)
- GoogleUtilities/Logger (~> 6.7)
- nanopb (~> 1.30906.0)
- FirebaseCrashlytics (4.6.2):
- FirebaseCrashlytics (4.6.1):
- FirebaseCore (~> 6.10)
- FirebaseInstallations (~> 1.6)
- GoogleDataTransport (~> 7.2)
@@ -81,9 +77,9 @@ PODS:
- GoogleUtilities/Network (~> 6.7)
- "GoogleUtilities/NSData+zlib (~> 6.7)"
- nanopb (~> 1.30906.0)
- GoogleDataTransport (7.5.1):
- GoogleDataTransport (7.4.0):
- nanopb (~> 1.30906.0)
- GoogleSignIn (5.0.2):
- GoogleSignIn (5.0.1):
- AppAuth (~> 1.2)
- GTMAppAuth (~> 1.0)
- GTMSessionFetcher/Core (~> 1.1)
@@ -106,17 +102,21 @@ PODS:
- GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (6.7.2):
- GoogleUtilities/Logger
- GTMAppAuth (1.2.2):
- AppAuth/Core (~> 1.4)
- GTMSessionFetcher/Core (~> 1.5)
- GTMSessionFetcher/Core (1.6.1)
- GTMAppAuth (1.0.0):
- AppAuth/Core (~> 1.0)
- GTMSessionFetcher (~> 1.1)
- GTMSessionFetcher (1.2.2):
- GTMSessionFetcher/Full (= 1.2.2)
- GTMSessionFetcher/Core (1.2.2)
- GTMSessionFetcher/Full (1.2.2):
- GTMSessionFetcher/Core (= 1.2.2)
- nanopb (1.30906.0):
- nanopb/decode (= 1.30906.0)
- nanopb/encode (= 1.30906.0)
- nanopb/decode (1.30906.0)
- nanopb/encode (1.30906.0)
- ObjectiveDropboxOfficial (6.1.0)
- PromisesObjC (1.2.12)
- ObjectiveDropboxOfficial (3.9.4)
- PromisesObjC (1.2.10)
- RCTRequired (0.61.5-jitsi.2)
- RCTTypeSafety (0.61.5-jitsi.2):
- FBLazyVector (= 0.61.5-jitsi.2)
@@ -288,18 +288,9 @@ PODS:
- React
- react-native-netinfo (4.1.5):
- React
- react-native-performance (2.0.0):
- React-Core
- react-native-slider (3.0.3):
- React
- react-native-splash-screen (3.2.0):
- React
- react-native-video (5.1.1):
- React-Core
- react-native-video/Video (= 5.1.1)
- react-native-video/Video (5.1.1):
- React-Core
- react-native-webrtc (1.92.1):
- react-native-webrtc (1.89.1):
- React-Core
- react-native-webview (11.0.2):
- React-Core
@@ -357,8 +348,8 @@ PODS:
- React-jsi (= 0.61.5-jitsi.2)
- ReactCommon/jscallinvoker (= 0.61.5-jitsi.2)
- ReactCommon/turbomodule/core (= 0.61.5-jitsi.2)
- RNCAsyncStorage (1.15.5):
- React-Core
- RNCAsyncStorage (1.13.2):
- React
- RNDefaultPreference (1.4.2):
- React
- RNDeviceInfo (8.0.0):
@@ -378,7 +369,6 @@ PODS:
- Yoga (1.14.0)
DEPENDENCIES:
- "amplitude-react-native (from `../node_modules/@amplitude/react-native`)"
- CocoaLumberjack (~> 3.5.3)
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector/`)
@@ -388,7 +378,7 @@ DEPENDENCIES:
- Firebase/DynamicLinks (~> 6.33.0)
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- ObjectiveDropboxOfficial (~> 6.1.0)
- ObjectiveDropboxOfficial (~> 3.9.4)
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired/`)
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety/`)
- React (from `../node_modules/react-native/`)
@@ -404,10 +394,7 @@ DEPENDENCIES:
- react-native-calendar-events (from `../node_modules/react-native-calendar-events`)
- react-native-keep-awake (from `../node_modules/react-native-keep-awake`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-performance (from `../node_modules/react-native-performance/ios`)
- "react-native-slider (from `../node_modules/@react-native-community/slider`)"
- react-native-splash-screen (from `../node_modules/react-native-splash-screen`)
- react-native-video (from `../node_modules/react-native-video/react-native-video.podspec`)
- react-native-webrtc (from `../node_modules/react-native-webrtc`)
- react-native-webview (from `../node_modules/react-native-webview`)
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
@@ -431,7 +418,6 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- Amplitude
- AppAuth
- boost-for-react-native
- CocoaLumberjack
@@ -453,8 +439,6 @@ SPEC REPOS:
- PromisesObjC
EXTERNAL SOURCES:
amplitude-react-native:
:path: "../node_modules/@amplitude/react-native"
DoubleConversion:
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
FBLazyVector:
@@ -491,14 +475,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-keep-awake"
react-native-netinfo:
:path: "../node_modules/@react-native-community/netinfo"
react-native-performance:
:path: "../node_modules/react-native-performance/ios"
react-native-slider:
:path: "../node_modules/@react-native-community/slider"
react-native-splash-screen:
:path: "../node_modules/react-native-splash-screen"
react-native-video:
:path: "../node_modules/react-native-video/react-native-video.podspec"
react-native-webrtc:
:path: "../node_modules/react-native-webrtc"
react-native-webview:
@@ -541,9 +519,7 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/yoga"
SPEC CHECKSUMS:
Amplitude: 263118b9e691e73a1c864b05bb08a3aff3636d16
amplitude-react-native: 833a4bd7f656f826bda1de01a7b8593b58842209
AppAuth: 31bcec809a638d7bd2f86ea8a52bd45f6e81e7c7
AppAuth: bce82c76043657c99d91e7882e8a9e1a93650cd4
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
CocoaLumberjack: 2f44e60eb91c176d471fdba43b9e3eae6a721947
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
@@ -553,20 +529,20 @@ SPEC CHECKSUMS:
FirebaseAnalytics: 5dd088bd2e67bb9d13dbf792d1164ceaf3052193
FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd
FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1
FirebaseCrashlytics: 1a747c9cc084a24dc6d9511c991db1cd078154eb
FirebaseCrashlytics: 5777d3462fb8c3ab9e80a2473bd7d667a2e8411c
FirebaseDynamicLinks: 6eac37d86910382eafb6315d952cc44c9e176094
FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
GoogleAppMeasurement: 966e88df9d19c15715137bb2ddaf52373f111436
GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833
GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213
GoogleDataTransport: b7f406340a291370045a270c599e53c6fa6ec20f
GoogleSignIn: 3a51b9bb8e48b635fd7f4272cee06ca260345b86
GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
GTMAppAuth: ad5c2b70b9a8689e1a04033c9369c4915bfcbe89
GTMSessionFetcher: 36689134877faeb055b27dfa4ccc9ceaa42e029e
GTMAppAuth: 4deac854479704f348309e7b66189e604cf5e01e
GTMSessionFetcher: 61bb0f61a4cb560030f1222021178008a5727a23
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
ObjectiveDropboxOfficial: b4765572e334d6fc6214b43a7595510324bbbbaa
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
ObjectiveDropboxOfficial: a5afefc83f6467c42c45f2253f583f2ad1ffc701
PromisesObjC: b14b1c6b68e306650688599de8a45e49fae81151
RCTRequired: a686731276578c125dff205f08b6ec9cee6ede32
RCTTypeSafety: 88e5500e801c00d16a3d1895e3470d13beed6584
React: 8b2bcf6a93846e47a7a365a54ec6edeb78b37701
@@ -580,11 +556,8 @@ SPEC CHECKSUMS:
react-native-calendar-events: 1442fad71a00388f933cfa25512588fec300fcf8
react-native-keep-awake: eba3137546b10003361b37c761f6c429b59814ae
react-native-netinfo: 8d8db463bcc5db66a8ac5c48a7d86beb3b92f61a
react-native-performance: 8edfa2bbc9a2af4a02f01d342118e413a95145e0
react-native-slider: b733e17fdd31186707146debf1f04b5d94aa1a93
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
react-native-video: 1574074179ecaf6a9dd067116c8f31bf9fec15c8
react-native-webrtc: 77b969fe6bc5b7c93b455f93a13698812fb8bb4e
react-native-webrtc: ccb0c21eb4fb04326648fbdb4a5d49977e2cf274
react-native-webview: b2542d6fd424bcc3e3b2ec5f854f0abb4ec86c87
React-RCTActionSheet: bcbc311dc3b47bc8efb2737ff0940239a45789a9
React-RCTAnimation: 65f61080ce632f6dea23d52e354ffac9948396c6
@@ -596,7 +569,7 @@ SPEC CHECKSUMS:
React-RCTText: 4f1b99f228278d2a5e9008eced8dc9c974c4a270
React-RCTVibration: c1041024893fdfdb8371e7c720c437751b711676
ReactCommon: 18014e1d98dbeb9141e935cfe35fc93bd511ffb6
RNCAsyncStorage: 8324611026e8dc3706f829953aa6e3899f581589
RNCAsyncStorage: bc2f81cc1df90c267ce9ed30bb2dbc93b945a8ee
RNDefaultPreference: 56a405ce61033ac77b95004dccd7ac54c2eb50d1
RNDeviceInfo: 72ded653ce636b3f03571e90bed99309a714944e
RNGoogleSignin: 39336070b35fc4cea6a98cf111e00480317be0ae
@@ -605,6 +578,6 @@ SPEC CHECKSUMS:
RNWatch: a5320c959c75e72845c07985f3e935e58998f1d3
Yoga: 96b469c5e81ff51b917b92e8c3390642d4ded30c
PODFILE CHECKSUM: e830b1b5a46d340e22689b146b55dcf24664c6f1
PODFILE CHECKSUM: d059cebf82da14a53940a16c24c3330752d4b0c8
COCOAPODS: 1.10.1

View File

@@ -23,7 +23,6 @@
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
2681BB562C7A0B42CFBA6719 /* libPods-JitsiMeet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D6152FF9E9F7B0E86F70A21D /* libPods-JitsiMeet.a */; };
4E90F9402632D1AB001102D4 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E90F93F2632D1AB001102D4 /* Atomic.swift */; };
4EB06024260E026600F524C5 /* ReplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4EC49B8625BED71300E76218 /* ReplayKit.framework */; };
4EB06027260E026600F524C5 /* SampleHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB06026260E026600F524C5 /* SampleHandler.swift */; };
@@ -31,6 +30,7 @@
4EB0603C260E09D000F524C5 /* SocketConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB06039260E09D000F524C5 /* SocketConnection.swift */; };
4EB0603D260E09D000F524C5 /* DarwinNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB0603A260E09D000F524C5 /* DarwinNotificationCenter.swift */; };
4EB0603E260E09D000F524C5 /* SampleUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB0603B260E09D000F524C5 /* SampleUploader.swift */; };
55BEDABDA92D47D399A70A5E /* libPods-JitsiMeet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D878B07B3FBD6E305EAA6B27 /* libPods-JitsiMeet.a */; };
DE050389256E904600DEE3A5 /* WebRTC.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE050388256E904600DEE3A5 /* WebRTC.xcframework */; };
DE05038A256E904600DEE3A5 /* WebRTC.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DE050388256E904600DEE3A5 /* WebRTC.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
DE4C456121DE1E4E00EA0709 /* FIRUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = DE4C455F21DE1E4E00EA0709 /* FIRUtilities.m */; };
@@ -113,6 +113,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
09AA3B93E4CC62D84B424690 /* Pods-jitsi-meet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-jitsi-meet.release.xcconfig"; path = "../Pods/Target Support Files/Pods-jitsi-meet/Pods-jitsi-meet.release.xcconfig"; sourceTree = "<group>"; };
0B26BE6D1EC5BC3C00EEFB41 /* JitsiMeet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = JitsiMeet.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0B412F1D1EDEE6E800B1A0A6 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
0B412F1E1EDEE6E800B1A0A6 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
@@ -138,7 +139,7 @@
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
3E0F4ED943C0B12BE77F6B45 /* Pods-JitsiMeet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.release.xcconfig"; path = "Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.release.xcconfig"; sourceTree = "<group>"; };
4670A512A688E2DC34528282 /* Pods-jitsi-meet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-jitsi-meet.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-jitsi-meet/Pods-jitsi-meet.debug.xcconfig"; sourceTree = "<group>"; };
4E90F93F2632D1AB001102D4 /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = "<group>"; };
4EB06023260E026600F524C5 /* JitsiMeetBroadcastExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = JitsiMeetBroadcastExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
4EB06026260E026600F524C5 /* SampleHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleHandler.swift; sourceTree = "<group>"; };
@@ -148,9 +149,11 @@
4EB0603A260E09D000F524C5 /* DarwinNotificationCenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DarwinNotificationCenter.swift; sourceTree = "<group>"; };
4EB0603B260E09D000F524C5 /* SampleUploader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SampleUploader.swift; sourceTree = "<group>"; };
4EC49B8625BED71300E76218 /* ReplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReplayKit.framework; path = System/Library/Frameworks/ReplayKit.framework; sourceTree = SDKROOT; };
756FCE06C08D9B947653C98A /* Pods-JitsiMeet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.debug.xcconfig"; path = "Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.debug.xcconfig"; sourceTree = "<group>"; };
5FEF9D87A4D2A38AD7193308 /* Pods-JitsiMeet-JitsiMeetBroadcastExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet-JitsiMeetBroadcastExtension.release.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeet-JitsiMeetBroadcastExtension/Pods-JitsiMeet-JitsiMeetBroadcastExtension.release.xcconfig"; sourceTree = "<group>"; };
609CB2080B75F75A89923F3D /* Pods-JitsiMeet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.debug.xcconfig"; sourceTree = "<group>"; };
A7B2827E068A0E05260054AC /* Pods-JitsiMeet-JitsiMeetBroadcastExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet-JitsiMeetBroadcastExtension.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeet-JitsiMeetBroadcastExtension/Pods-JitsiMeet-JitsiMeetBroadcastExtension.debug.xcconfig"; sourceTree = "<group>"; };
B3B083EB1D4955FF0069CEE7 /* app.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = app.entitlements; sourceTree = "<group>"; };
D6152FF9E9F7B0E86F70A21D /* libPods-JitsiMeet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-JitsiMeet.a"; sourceTree = BUILT_PRODUCTS_DIR; };
D878B07B3FBD6E305EAA6B27 /* libPods-JitsiMeet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-JitsiMeet.a"; sourceTree = BUILT_PRODUCTS_DIR; };
DE050388256E904600DEE3A5 /* WebRTC.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = WebRTC.xcframework; path = "../../node_modules/react-native-webrtc/apple/WebRTC.xcframework"; sourceTree = "<group>"; };
DE4C455F21DE1E4E00EA0709 /* FIRUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRUtilities.m; sourceTree = "<group>"; };
DE4C456021DE1E4E00EA0709 /* FIRUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FIRUtilities.h; sourceTree = "<group>"; };
@@ -158,6 +161,7 @@
DEFDBBDB25656E3B00344B23 /* WebRTC.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = WebRTC.xcframework; path = "../../node_modules/react-native-webrtc/ios/WebRTC.xcframework"; sourceTree = "<group>"; };
E58801132278944E008B0561 /* JitsiMeetContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JitsiMeetContext.swift; sourceTree = "<group>"; };
E5C97B62227A1EB400199214 /* JitsiMeetCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JitsiMeetCommands.swift; sourceTree = "<group>"; };
FC040BBED70876444D89E91C /* Pods-JitsiMeet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.release.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -174,7 +178,7 @@
files = (
DE050389256E904600DEE3A5 /* WebRTC.xcframework in Frameworks */,
DEA9F289258A6EA800D4CD74 /* JitsiMeetSDK.framework in Frameworks */,
2681BB562C7A0B42CFBA6719 /* libPods-JitsiMeet.a in Frameworks */,
55BEDABDA92D47D399A70A5E /* libPods-JitsiMeet.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -204,8 +208,8 @@
0B26BE6D1EC5BC3C00EEFB41 /* JitsiMeet.framework */,
DEFDBBDB25656E3B00344B23 /* WebRTC.xcframework */,
0BD6B4361EF82A6B00D1F4CD /* WebRTC.framework */,
D878B07B3FBD6E305EAA6B27 /* libPods-JitsiMeet.a */,
4EC49B8625BED71300E76218 /* ReplayKit.framework */,
D6152FF9E9F7B0E86F70A21D /* libPods-JitsiMeet.a */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -274,6 +278,19 @@
sourceTree = "<group>";
tabWidth = 4;
};
5E96ADD5E49F3B3822EF9A52 /* Pods */ = {
isa = PBXGroup;
children = (
4670A512A688E2DC34528282 /* Pods-jitsi-meet.debug.xcconfig */,
09AA3B93E4CC62D84B424690 /* Pods-jitsi-meet.release.xcconfig */,
609CB2080B75F75A89923F3D /* Pods-JitsiMeet.debug.xcconfig */,
FC040BBED70876444D89E91C /* Pods-JitsiMeet.release.xcconfig */,
A7B2827E068A0E05260054AC /* Pods-JitsiMeet-JitsiMeetBroadcastExtension.debug.xcconfig */,
5FEF9D87A4D2A38AD7193308 /* Pods-JitsiMeet-JitsiMeetBroadcastExtension.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
@@ -281,10 +298,10 @@
0B26BE711EC5BC4D00EEFB41 /* Frameworks */,
83CBBA001A601CBA00E9B192 /* Products */,
13B07FAE1A68108700A75B9A /* src */,
5E96ADD5E49F3B3822EF9A52 /* Pods */,
0BEA5C261F7B8F73000D0AB4 /* Watch app */,
0BEA5C351F7B8F73000D0AB4 /* WatchKit extension */,
4EB06025260E026600F524C5 /* JitsiMeetBroadcast Extension */,
CDD71F5E1157E9F283DF92A8 /* Pods */,
);
indentWidth = 2;
sourceTree = "<group>";
@@ -301,16 +318,6 @@
name = Products;
sourceTree = "<group>";
};
CDD71F5E1157E9F283DF92A8 /* Pods */ = {
isa = PBXGroup;
children = (
756FCE06C08D9B947653C98A /* Pods-JitsiMeet.debug.xcconfig */,
3E0F4ED943C0B12BE77F6B45 /* Pods-JitsiMeet.release.xcconfig */,
);
name = Pods;
path = ../Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -353,7 +360,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "JitsiMeet" */;
buildPhases = (
69BC5020DBE393B56BD76636 /* [CP] Check Pods Manifest.lock */,
B6607F42A5CF0C76E98929E2 /* [CP] Check Pods Manifest.lock */,
0BBA83C41EC9F7600075A103 /* Run React packager */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
@@ -516,7 +523,7 @@
shellPath = /bin/sh;
shellScript = "../scripts/run-packager.sh\n";
};
69BC5020DBE393B56BD76636 /* [CP] Check Pods Manifest.lock */ = {
B6607F42A5CF0C76E98929E2 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -818,7 +825,7 @@
};
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 756FCE06C08D9B947653C98A /* Pods-JitsiMeet.debug.xcconfig */;
baseConfigurationReference = 609CB2080B75F75A89923F3D /* Pods-JitsiMeet.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconDebug;
@@ -848,7 +855,7 @@
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3E0F4ED943C0B12BE77F6B45 /* Pods-JitsiMeet.release.xcconfig */;
baseConfigurationReference = FC040BBED70876444D89E91C /* Pods-JitsiMeet.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconRelease;

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>21.4.0</string>
<string>21.2.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>21.4.0</string>
<string>21.2.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>21.4.0</string>
<string>21.2.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>UISupportedInterfaceOrientations</key>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>21.4.0</string>
<string>21.2.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CLKComplicationPrincipalClass</key>

View File

@@ -10,6 +10,8 @@
0B412F181EDEC65D00B1A0A6 /* JitsiMeetView.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B412F161EDEC65D00B1A0A6 /* JitsiMeetView.h */; settings = {ATTRIBUTES = (Public, ); }; };
0B412F191EDEC65D00B1A0A6 /* JitsiMeetView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B412F171EDEC65D00B1A0A6 /* JitsiMeetView.m */; };
0B412F221EDEF6EA00B1A0A6 /* JitsiMeetViewDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B412F1B1EDEC80100B1A0A6 /* JitsiMeetViewDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
0B49424520AD8DBD00BD2DE0 /* outgoingStart.wav in Resources */ = {isa = PBXBuildFile; fileRef = 0B49424320AD8DBD00BD2DE0 /* outgoingStart.wav */; };
0B49424620AD8DBD00BD2DE0 /* outgoingRinging.wav in Resources */ = {isa = PBXBuildFile; fileRef = 0B49424420AD8DBD00BD2DE0 /* outgoingRinging.wav */; };
0B93EF7E1EC9DDCD0030D24D /* RCTBridgeWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B93EF7C1EC9DDCD0030D24D /* RCTBridgeWrapper.h */; };
0B93EF7F1EC9DDCD0030D24D /* RCTBridgeWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B93EF7D1EC9DDCD0030D24D /* RCTBridgeWrapper.m */; };
0BA13D311EE83FF8007BEF7F /* ExternalAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BA13D301EE83FF8007BEF7F /* ExternalAPI.m */; };
@@ -24,8 +26,16 @@
0BD906EA1EC0C00300C8C18E /* JitsiMeet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BD906E81EC0C00300C8C18E /* JitsiMeet.h */; settings = {ATTRIBUTES = (Public, ); }; };
4E51B76425E5345E0038575A /* ScheenshareEventEmiter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E51B76225E5345E0038575A /* ScheenshareEventEmiter.h */; };
4E51B76525E5345E0038575A /* ScheenshareEventEmiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E51B76325E5345E0038575A /* ScheenshareEventEmiter.m */; };
6C31EDC820C06D490089C899 /* recordingOn.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 6C31EDC720C06D490089C899 /* recordingOn.mp3 */; };
6C31EDCA20C06D530089C899 /* recordingOff.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 6C31EDC920C06D530089C899 /* recordingOff.mp3 */; };
6F08DF7D4458EE3CF3F36F6D /* libPods-JitsiMeetSDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E4376CA6886DE68FD7A4294B /* libPods-JitsiMeetSDK.a */; };
75635B0A20751D6D00F29C9F /* joined.wav in Resources */ = {isa = PBXBuildFile; fileRef = 75635B0820751D6D00F29C9F /* joined.wav */; };
75635B0B20751D6D00F29C9F /* left.wav in Resources */ = {isa = PBXBuildFile; fileRef = 75635B0920751D6D00F29C9F /* left.wav */; };
87FE6F3321E52437004A5DC7 /* incomingMessage.wav in Resources */ = {isa = PBXBuildFile; fileRef = 87FE6F3221E52437004A5DC7 /* incomingMessage.wav */; };
A4414AE020B37F1A003546E6 /* rejected.wav in Resources */ = {isa = PBXBuildFile; fileRef = A4414ADF20B37F1A003546E6 /* rejected.wav */; };
A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */ = {isa = PBXBuildFile; fileRef = A4A934E8212F3ADB001E9388 /* Dropbox.m */; };
C30F88D0CB0F4F5593216D24 /* liveStreamingOff.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C30F88D1CB0F4F5593216D24 /* liveStreamingOff.mp3 */; };
C30F88D2CB0F4F5593216D24 /* liveStreamingOn.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C30F88D3CB0F4F5593216D24 /* liveStreamingOn.mp3 */; };
C6245F5D2053091D0040BE68 /* image-resize@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6245F5B2053091D0040BE68 /* image-resize@2x.png */; };
C6245F5E2053091D0040BE68 /* image-resize@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6245F5C2053091D0040BE68 /* image-resize@3x.png */; };
C69EFA0C209A0F660027712B /* JMCallKitEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA09209A0F650027712B /* JMCallKitEmitter.swift */; };
@@ -60,6 +70,8 @@
0B412F161EDEC65D00B1A0A6 /* JitsiMeetView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JitsiMeetView.h; sourceTree = "<group>"; };
0B412F171EDEC65D00B1A0A6 /* JitsiMeetView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JitsiMeetView.m; sourceTree = "<group>"; };
0B412F1B1EDEC80100B1A0A6 /* JitsiMeetViewDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeetViewDelegate.h; sourceTree = "<group>"; };
0B49424320AD8DBD00BD2DE0 /* outgoingStart.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = outgoingStart.wav; path = ../../sounds/outgoingStart.wav; sourceTree = "<group>"; };
0B49424420AD8DBD00BD2DE0 /* outgoingRinging.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = outgoingRinging.wav; path = ../../sounds/outgoingRinging.wav; sourceTree = "<group>"; };
0B93EF7A1EC608550030D24D /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
0B93EF7C1EC9DDCD0030D24D /* RCTBridgeWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBridgeWrapper.h; sourceTree = "<group>"; };
0B93EF7D1EC9DDCD0030D24D /* RCTBridgeWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBridgeWrapper.m; sourceTree = "<group>"; };
@@ -77,11 +89,19 @@
0BD906E91EC0C00300C8C18E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4E51B76225E5345E0038575A /* ScheenshareEventEmiter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScheenshareEventEmiter.h; sourceTree = "<group>"; };
4E51B76325E5345E0038575A /* ScheenshareEventEmiter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ScheenshareEventEmiter.m; sourceTree = "<group>"; };
6C31EDC720C06D490089C899 /* recordingOn.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = recordingOn.mp3; path = ../../sounds/recordingOn.mp3; sourceTree = "<group>"; };
6C31EDC920C06D530089C899 /* recordingOff.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = recordingOff.mp3; path = ../../sounds/recordingOff.mp3; sourceTree = "<group>"; };
75635B0820751D6D00F29C9F /* joined.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = joined.wav; path = ../../sounds/joined.wav; sourceTree = "<group>"; };
75635B0920751D6D00F29C9F /* left.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = left.wav; path = ../../sounds/left.wav; sourceTree = "<group>"; };
87FE6F3221E52437004A5DC7 /* incomingMessage.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = incomingMessage.wav; path = ../../sounds/incomingMessage.wav; sourceTree = "<group>"; };
891FE43DAD30BC8976683100 /* Pods-JitsiMeetSDK.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeetSDK.release.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeetSDK/Pods-JitsiMeetSDK.release.xcconfig"; sourceTree = "<group>"; };
98E09B5C73D9036B4ED252FC /* Pods-JitsiMeet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.debug.xcconfig"; sourceTree = "<group>"; };
9C77CA3CC919B081F1A52982 /* Pods-JitsiMeet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.release.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.release.xcconfig"; sourceTree = "<group>"; };
A4414ADF20B37F1A003546E6 /* rejected.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = rejected.wav; path = ../../sounds/rejected.wav; sourceTree = "<group>"; };
A4A934E8212F3ADB001E9388 /* Dropbox.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Dropbox.m; sourceTree = "<group>"; };
A4A934EB21349A06001E9388 /* Dropbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Dropbox.h; sourceTree = "<group>"; };
C30F88D1CB0F4F5593216D24 /* liveStreamingOff.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = liveStreamingOff.mp3; path = ../../sounds/liveStreamingOff.mp3; sourceTree = "<group>"; };
C30F88D3CB0F4F5593216D24 /* liveStreamingOn.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = liveStreamingOn.mp3; path = ../../sounds/liveStreamingOn.mp3; sourceTree = "<group>"; };
C6245F5B2053091D0040BE68 /* image-resize@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "image-resize@2x.png"; path = "src/picture-in-picture/image-resize@2x.png"; sourceTree = "<group>"; };
C6245F5C2053091D0040BE68 /* image-resize@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "image-resize@3x.png"; path = "src/picture-in-picture/image-resize@3x.png"; sourceTree = "<group>"; };
C69EFA09209A0F650027712B /* JMCallKitEmitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JMCallKitEmitter.swift; sourceTree = "<group>"; };
@@ -135,9 +155,19 @@
0BCA49681EC4BBE500B793EE /* Resources */ = {
isa = PBXGroup;
children = (
87FE6F3221E52437004A5DC7 /* incomingMessage.wav */,
0BC4B8681F8C01E100CE8B21 /* CallKitIcon.png */,
C6245F5B2053091D0040BE68 /* image-resize@2x.png */,
C6245F5C2053091D0040BE68 /* image-resize@3x.png */,
75635B0820751D6D00F29C9F /* joined.wav */,
75635B0920751D6D00F29C9F /* left.wav */,
C30F88D1CB0F4F5593216D24 /* liveStreamingOff.mp3 */,
C30F88D3CB0F4F5593216D24 /* liveStreamingOn.mp3 */,
0B49424420AD8DBD00BD2DE0 /* outgoingRinging.wav */,
0B49424320AD8DBD00BD2DE0 /* outgoingStart.wav */,
6C31EDC920C06D530089C899 /* recordingOff.mp3 */,
6C31EDC720C06D490089C899 /* recordingOn.mp3 */,
A4414ADF20B37F1A003546E6 /* rejected.wav */,
);
name = Resources;
sourceTree = "<group>";
@@ -298,7 +328,6 @@
0BD906E11EC0C00300C8C18E /* Frameworks */,
0BD906E21EC0C00300C8C18E /* Headers */,
0BD906E31EC0C00300C8C18E /* Resources */,
DE17D0D426E0B86300F77E2E /* Copy sounds */,
0BCA49651EC4B77500B793EE /* Package React bundle */,
C7BC10B338C94EEB98048E64 /* [CP] Copy Pods Resources */,
);
@@ -350,8 +379,18 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0BC4B8691F8C03A700CE8B21 /* CallKitIcon.png in Resources */,
87FE6F3321E52437004A5DC7 /* incomingMessage.wav in Resources */,
0B49424520AD8DBD00BD2DE0 /* outgoingStart.wav in Resources */,
C30F88D0CB0F4F5593216D24 /* liveStreamingOff.mp3 in Resources */,
C30F88D2CB0F4F5593216D24 /* liveStreamingOn.mp3 in Resources */,
6C31EDCA20C06D530089C899 /* recordingOff.mp3 in Resources */,
A4414AE020B37F1A003546E6 /* rejected.wav in Resources */,
0B49424620AD8DBD00BD2DE0 /* outgoingRinging.wav in Resources */,
C6245F5D2053091D0040BE68 /* image-resize@2x.png in Resources */,
6C31EDC820C06D490089C899 /* recordingOn.mp3 in Resources */,
0BC4B8691F8C03A700CE8B21 /* CallKitIcon.png in Resources */,
75635B0B20751D6D00F29C9F /* left.wav in Resources */,
75635B0A20751D6D00F29C9F /* joined.wav in Resources */,
C6245F5E2053091D0040BE68 /* image-resize@3x.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -398,12 +437,10 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-JitsiMeetSDK/Pods-JitsiMeetSDK-resources.sh",
"${PODS_ROOT}/Amplitude/Sources/Amplitude/Resources/ComodoRsaDomainValidationCA.der",
"${PODS_ROOT}/GoogleSignIn/Resources/GoogleSignIn.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ComodoRsaDomainValidationCA.der",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
@@ -411,24 +448,6 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-JitsiMeetSDK/Pods-JitsiMeetSDK-resources.sh\"\n";
showEnvVarsInLog = 0;
};
DE17D0D426E0B86300F77E2E /* Copy sounds */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Copy sounds";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "SOUNDS_DIR=\"${PROJECT_DIR}/../../sounds\"\n\ncp $SOUNDS_DIR/* ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */

View File

@@ -125,19 +125,12 @@ RCT_EXPORT_MODULE();
return _workerQueue;
}
- (BOOL)setConfigWithoutLock:(RTCAudioSessionConfiguration *)config
error:(NSError * _Nullable *)outError {
RTCAudioSession *session = [RTCAudioSession sharedInstance];
return [session setConfiguration:config error:outError];
}
- (BOOL)setConfig:(RTCAudioSessionConfiguration *)config
error:(NSError * _Nullable *)outError {
RTCAudioSession *session = [RTCAudioSession sharedInstance];
[session lockForConfiguration];
BOOL success = [self setConfigWithoutLock:config error:outError];
BOOL success = [session setConfiguration:config error:outError];
[session unlockForConfiguration];
return success;
@@ -203,7 +196,7 @@ RCT_EXPORT_METHOD(setAudioDevice:(NSString *)device
break;
}
}
if (port != nil) {
// First remove the override if we are going to select a different device.
if (isSpeakerOn) {
@@ -213,11 +206,11 @@ RCT_EXPORT_METHOD(setAudioDevice:(NSString *)device
// Special case for the earpiece.
if ([port.portType isEqualToString:AVAudioSessionPortBuiltInMic]) {
forceEarpiece = YES;
[self setConfigWithoutLock:earpieceConfig error:nil];
[self setConfig:earpieceConfig error:nil];
} else if (isEarpieceOn) {
// Reset the config.
RTCAudioSessionConfiguration *config = [self configForMode:activeMode];
[self setConfigWithoutLock:config error:nil];
[self setConfig:config error:nil];
}
// Select our preferred input.

View File

@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.10.0</string>
<string>3.5.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>

View File

@@ -59,16 +59,6 @@
#pragma mark - Utility methods
/**
* Once the react native bridge is destroyed you are responsible for reinstantiating it back. Use this method to do so.
*/
- (void)instantiateReactNativeBridge;
/**
* Helper method to destroy the react native bridge, cleaning up resources in the process. Once the react native bridge is destroyed you are responsible for reinstantiating it back using `instantiateReactNativeBridge` method.
*/
- (void)destroyReactNativeBridge;
- (JitsiMeetConferenceOptions *_Nonnull)getInitialConferenceOptions;
- (BOOL)isCrashReportingDisabled;

View File

@@ -28,6 +28,7 @@
#import <RNGoogleSignin/RNGoogleSignin.h>
#import <WebRTC/RTCLogging.h>
@implementation JitsiMeet {
RCTBridgeWrapper *_bridgeWrapper;
NSDictionary *_launchOptions;
@@ -49,7 +50,7 @@
- (instancetype)init {
if (self = [super init]) {
// Initialize the one and only bridge for interfacing with React Native.
// Initialize the on and only bridge for interfacing with React Native.
_bridgeWrapper = [[RCTBridgeWrapper alloc] init];
// Initialize the listener for handling start/stop screensharing notifications.
@@ -118,18 +119,6 @@
#pragma mark - Utility methods
- (void)instantiateReactNativeBridge {
if (_bridgeWrapper != nil) {
return;
};
_bridgeWrapper = [[RCTBridgeWrapper alloc] init];
}
- (void)destroyReactNativeBridge {
_bridgeWrapper = nil;
}
- (JitsiMeetConferenceOptions *)getInitialConferenceOptions {
if (_launchOptions[UIApplicationLaunchOptionsURLKey]) {
NSURL *url = _launchOptions[UIApplicationLaunchOptionsURLKey];

View File

@@ -29,6 +29,10 @@
* Room name.
*/
@property (nonatomic, copy, nullable) NSString *room;
/**
* Conference subject.
*/
@property (nonatomic, copy, nullable) NSString *subject;
/**
* JWT token used for authentication.
*/
@@ -45,7 +49,13 @@
*/
@property (nonatomic, readonly, nonnull) NSDictionary *featureFlags;
@property (nonatomic, readonly, nonnull) NSDictionary *config;
/**
* Set to YES to join the conference with audio / video muted or to start in audio
* only mode respectively.
*/
@property (nonatomic) BOOL audioOnly;
@property (nonatomic) BOOL audioMuted;
@property (nonatomic) BOOL videoMuted;
/**
* Set to YES to enable the welcome page. Typically SDK users won't need this enabled
@@ -61,17 +71,15 @@
- (void)setFeatureFlag:(NSString *_Nonnull)flag withBoolean:(BOOL)value;
- (void)setFeatureFlag:(NSString *_Nonnull)flag withValue:(id _Nonnull)value;
- (void)setConfigOverride:(NSString *_Nonnull)config withBoolean:(BOOL)value;
- (void)setConfigOverride:(NSString *_Nonnull)config withValue:(id _Nonnull)value;
- (void)setConfigOverride:(NSString *_Nonnull)config withDictionary:(NSDictionary * _Nonnull)dictionary;
- (void)setConfigOverride:(NSString *_Nonnull)config withArray:( NSArray * _Nonnull)array;
/**
* CallKit call handle, to be used when implementing incoming calls.
*/
@property (nonatomic, copy, nullable) NSString *callHandle;
- (void)setAudioOnly:(BOOL)audioOnly;
- (void)setAudioMuted:(BOOL)audioMuted;
- (void)setVideoMuted:(BOOL)videoMuted;
- (void)setCallHandle:(NSString *_Nonnull)callHandle;
- (void)setCallUUID:(NSUUID *_Nonnull)callUUID;
- (void)setSubject:(NSString *_Nonnull)subject;
/**
* CallKit call UUID, to be used when implementing incoming calls.
*/
@property (nonatomic, copy, nullable) NSUUID *callUUID;
@end
@@ -80,15 +88,23 @@
@property (nonatomic, copy, nullable, readonly) NSURL *serverURL;
@property (nonatomic, copy, nullable, readonly) NSString *room;
@property (nonatomic, copy, nullable, readonly) NSString *subject;
@property (nonatomic, copy, nullable, readonly) NSString *token;
@property (nonatomic, copy, nullable) NSDictionary *colorScheme;
@property (nonatomic, readonly, nonnull) NSDictionary *featureFlags;
@property (nonatomic, readonly) BOOL audioOnly;
@property (nonatomic, readonly) BOOL audioMuted;
@property (nonatomic, readonly) BOOL videoMuted;
@property (nonatomic, readonly) BOOL welcomePageEnabled;
@property (nonatomic, nullable) JitsiMeetUserInfo *userInfo;
@property (nonatomic, copy, nullable, readonly) NSString *callHandle;
@property (nonatomic, copy, nullable, readonly) NSUUID *callUUID;
+ (instancetype _Nonnull)fromBuilder:(void (^_Nonnull)(JitsiMeetConferenceOptionsBuilder *_Nonnull))initBlock;
- (instancetype _Nonnull)init NS_UNAVAILABLE;

View File

@@ -26,23 +26,35 @@ static NSString *const WelcomePageEnabledFeatureFlag = @"welcomepage.enabled";
@implementation JitsiMeetConferenceOptionsBuilder {
NSNumber *_audioOnly;
NSNumber *_audioMuted;
NSNumber *_videoMuted;
NSMutableDictionary *_featureFlags;
NSMutableDictionary *_config;
}
@dynamic audioOnly;
@dynamic audioMuted;
@dynamic videoMuted;
@dynamic welcomePageEnabled;
- (instancetype)init {
if (self = [super init]) {
_serverURL = nil;
_room = nil;
_subject = nil;
_token = nil;
_colorScheme = nil;
_config = [[NSMutableDictionary alloc] init];
_featureFlags = [[NSMutableDictionary alloc] init];
_audioOnly = nil;
_audioMuted = nil;
_videoMuted = nil;
_userInfo = nil;
_callHandle = nil;
_callUUID = nil;
}
return self;
@@ -56,48 +68,32 @@ static NSString *const WelcomePageEnabledFeatureFlag = @"welcomepage.enabled";
_featureFlags[flag] = value;
}
#pragma mark - Dynamic properties
- (void)setAudioOnly:(BOOL)audioOnly {
[self setConfigOverride:@"startAudioOnly" withBoolean:audioOnly];
_audioOnly = [NSNumber numberWithBool:audioOnly];
}
- (BOOL)audioOnly {
return _audioOnly && [_audioOnly boolValue];
}
- (void)setAudioMuted:(BOOL)audioMuted {
[self setConfigOverride:@"startWithAudioMuted" withBoolean:audioMuted];
_audioMuted = [NSNumber numberWithBool:audioMuted];
}
- (BOOL)audioMuted {
return _audioMuted && [_audioMuted boolValue];
}
- (void)setVideoMuted:(BOOL)videoMuted {
[self setConfigOverride:@"startWithVideoMuted" withBoolean:videoMuted];
_videoMuted = [NSNumber numberWithBool:videoMuted];
}
- (void)setCallHandle:(NSString *_Nonnull)callHandle {
[self setConfigOverride:@"callHandle" withValue:callHandle];
- (BOOL)videoMuted {
return _videoMuted && [_videoMuted boolValue];
}
- (void)setCallUUID:(NSUUID *_Nonnull)callUUID {
[self setConfigOverride:@"callUUID" withValue:[callUUID UUIDString]];
}
- (void)setSubject:(NSString *_Nonnull)subject {
[self setConfigOverride:@"subject" withValue:subject];
}
- (void)setConfigOverride:(NSString *_Nonnull)config withBoolean:(BOOL)value {
[self setConfigOverride:config withValue:[NSNumber numberWithBool:value]];
}
- (void)setConfigOverride:(NSString *_Nonnull)config withDictionary:(NSDictionary*)dictionary {
_config[config] = dictionary;
}
- (void)setConfigOverride:(NSString *_Nonnull)config withArray:( NSArray * _Nonnull)array {
_config[config] = array;
}
- (void)setConfigOverride:(NSString *_Nonnull)config withValue:(id _Nonnull)value {
_config[config] = value;
}
#pragma mark - Dynamic properties
- (void)setWelcomePageEnabled:(BOOL)welcomePageEnabled {
[self setFeatureFlag:WelcomePageEnabledFeatureFlag
withBoolean:welcomePageEnabled];
@@ -109,17 +105,48 @@ static NSString *const WelcomePageEnabledFeatureFlag = @"welcomepage.enabled";
return n != nil ? [n boolValue] : NO;
}
#pragma mark - Private API
- (NSNumber *)getAudioOnly {
return _audioOnly;
}
- (NSNumber *)getAudioMuted {
return _audioMuted;
}
- (NSNumber *)getVideoMuted {
return _videoMuted;
}
@end
@implementation JitsiMeetConferenceOptions {
NSNumber *_audioOnly;
NSNumber *_audioMuted;
NSNumber *_videoMuted;
NSDictionary *_featureFlags;
NSDictionary *_config;
}
@dynamic audioOnly;
@dynamic audioMuted;
@dynamic videoMuted;
@dynamic welcomePageEnabled;
#pragma mark - Dynamic properties
- (BOOL)audioOnly {
return _audioOnly && [_audioOnly boolValue];
}
- (BOOL)audioMuted {
return _audioMuted && [_audioMuted boolValue];
}
- (BOOL)videoMuted {
return _videoMuted && [_videoMuted boolValue];
}
- (BOOL)welcomePageEnabled {
NSNumber *n = _featureFlags[WelcomePageEnabledFeatureFlag];
@@ -132,15 +159,21 @@ static NSString *const WelcomePageEnabledFeatureFlag = @"welcomepage.enabled";
if (self = [super init]) {
_serverURL = builder.serverURL;
_room = builder.room;
_subject = builder.subject;
_token = builder.token;
_colorScheme = builder.colorScheme;
_config = builder.config;
_audioOnly = [builder getAudioOnly];
_audioMuted = [builder getAudioMuted];
_videoMuted = [builder getVideoMuted];
_featureFlags = [NSDictionary dictionaryWithDictionary:builder.featureFlags];
_userInfo = builder.userInfo;
_callHandle = builder.callHandle;
_callUUID = builder.callUUID;
}
return self;
@@ -165,6 +198,26 @@ static NSString *const WelcomePageEnabledFeatureFlag = @"welcomepage.enabled";
props[@"colorScheme"] = self.colorScheme;
}
NSMutableDictionary *config = [[NSMutableDictionary alloc] init];
if (_audioOnly != nil) {
config[@"startAudioOnly"] = @(self.audioOnly);
}
if (_audioMuted != nil) {
config[@"startWithAudioMuted"] = @(self.audioMuted);
}
if (_videoMuted != nil) {
config[@"startWithVideoMuted"] = @(self.videoMuted);
}
if (_subject != nil) {
config[@"subject"] = self.subject;
}
if (_callHandle != nil) {
config[@"callHandle"] = self.callHandle;
}
if (_callUUID != nil) {
config[@"callUUID"] = [self.callUUID UUIDString];
}
NSMutableDictionary *urlProps = [[NSMutableDictionary alloc] init];
// The room is fully qualified.
@@ -188,7 +241,7 @@ static NSString *const WelcomePageEnabledFeatureFlag = @"welcomepage.enabled";
props[@"userInfo"] = [self.userInfo asDict];
}
urlProps[@"config"] = _config;
urlProps[@"config"] = config;
props[@"url"] = urlProps;
return props;

View File

@@ -63,14 +63,11 @@ RCT_EXPORT_METHOD(authorize:(RCTPromiseResolveBlock)resolve
currentReject = reject;
dispatch_async(dispatch_get_main_queue(), ^{
DBScopeRequest *scopeRequest = [[DBScopeRequest alloc] initWithScopeType:DBScopeTypeUser
scopes:@[]
includeGrantedScopes:NO];
[DBClientsManager authorizeFromControllerV2:[UIApplication sharedApplication]
controller:[[self class] topMostController]
loadingStatusDelegate:nil
openURL:^(NSURL *url) { [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; }
scopeRequest:scopeRequest];
[DBClientsManager authorizeFromController:[UIApplication sharedApplication]
controller:[[self class] topMostController]
openURL:^(NSURL *url) {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
}];
});
}
@@ -131,31 +128,25 @@ RCT_EXPORT_METHOD(getSpaceUsage: (NSString *)token
if (currentReject == nil || currentResolve == nil) {
return NO;
}
BOOL canHandle = [DBClientsManager handleRedirectURL:url completion:^(DBOAuthResult *authResult) {
if (authResult) {
if ([authResult isSuccess]) {
NSInteger msTimestamp = authResult.accessToken.tokenExpirationTimestamp * 1000;
NSDictionary *authInfo = @{@"token": authResult.accessToken.accessToken,
@"rToken": authResult.accessToken.refreshToken,
@"expireDate": @(msTimestamp)
};
currentResolve(authInfo);
DBOAuthResult *authResult = [DBClientsManager handleRedirectURL:url];
if (authResult) {
if ([authResult isSuccess]) {
currentResolve(authResult.accessToken.accessToken);
} else {
NSString *msg;
if ([authResult isError]) {
msg = [NSString stringWithFormat:@"%@, error type: %zd",[authResult errorDescription], [authResult errorType]];
} else {
NSString *msg;
if ([authResult isError]) {
msg = [NSString stringWithFormat:@"%@, error type: %zd", [authResult errorDescription], [authResult errorType]];
} else {
msg = @"OAuth canceled!";
}
currentReject(@"authorize", msg, nil);
msg = @"OAuth canceled!";
}
currentResolve = nil;
currentReject = nil;
currentReject(@"authorize", msg, nil);
}
}];
return canHandle;
currentResolve = nil;
currentReject = nil;
return YES;
}
return NO;
}
+ (UIViewController *)topMostController {

View File

@@ -144,6 +144,7 @@ public class PiPViewCoordinator {
/// screen size changes
public func resetBounds(bounds: CGRect) {
currentBounds = bounds
exitPictureInPicture()
}
/// Stop the dragging gesture of the root view

View File

@@ -18,7 +18,6 @@
"fr": "Francés",
"frCA": "Francés (Canadian)",
"he": "Ebrèu",
"hi": "Indi",
"mr":"Marathi",
"hr": "Croat",
"hu": "Ongrés",
@@ -43,9 +42,7 @@
"sk": "Eslovac",
"sl": "Eslovèn",
"sr": "Sèrbe",
"sq": "Albanés",
"sv": "Suedés",
"te": "Telugu",
"th": "Tai",
"tr": "Turc",
"uk": "Ucraïnian",

View File

@@ -18,7 +18,6 @@
"fr": "Frëngjisht",
"frCA": "Frëngjisht (Kebek)",
"he": "Hebraisht",
"hi": "Hindi",
"mr":"Maratisht",
"hr": "Kroatisht",
"hu": "Hungarisht",
@@ -35,17 +34,15 @@
"oc": "Oçitanisht",
"fa": "Persisht",
"pl": "Polonisht",
"pt": "Portugalisht",
"ptBR": "Portugalisht (Brazil)",
"ru": "Rusisht",
"ro": "Rumanisht",
"sc": "Sardenjisht",
"sk": "Sllovakisht",
"sl": "Sllovenisht",
"sr": "Serbisht",
"sq": "Shqip",
"sr": "Serbisht",
"sv": "Suedisht",
"te": "Telugu",
"th": "Tajlandisht",
"tr": "Turqisht",
"uk": "Ukrainisht",

View File

@@ -1,55 +1,34 @@
{
"en": "英文",
"en": "英語",
"af": "南非荷蘭文",
"ar": "阿拉伯文",
"bg": "保加利亞文",
"ca": "卡達隆尼亞文",
"cs": "捷克文",
"da": "丹麥文",
"de": "德文",
"el": "希臘文",
"enGB": "英文 (英國)",
"eo": "世界語",
"es": "西班牙文",
"esUS": "西班牙文 (拉丁美洲)",
"et": "愛沙尼亞文",
"eu": "巴斯克語",
"fi": "芬蘭文",
"fr": "法文",
"frCA": "法文 (加拿大)",
"he": "希伯來語",
"hi": "印地語",
"mr":"馬拉提語",
"hr": "克羅埃西亞文",
"hu": "匈牙利文",
"hy": "亞美尼亞文",
"id": "印尼語",
"it": "義大利文",
"ja": "日語",
"kab": "卡拜爾語",
"ko": "韓文",
"lt": "立陶宛語",
"ml": "馬拉雅拉姆語",
"lv": "拉脫維亞語",
"nl": "荷蘭文",
"oc": "奧西坦文",
"fa": "波斯語",
"pl": "波蘭文",
"pt": "葡萄牙語",
"ptBR": "葡萄牙文 (巴西)",
"ru": "俄文",
"ro": "羅馬尼亞語",
"sc": "薩丁尼亞語",
"sk": "斯洛伐克語",
"sl": "斯洛維尼亞語",
"sr": "塞爾維亞語",
"sq": "阿羅馬尼亞語",
"sv": "瑞典文",
"te": "泰盧固語",
"th": "泰語",
"tr": "土耳其文",
"uk": "烏克蘭語",
"vi": "越南文",
"zhCN": "中文 (中国,简体)",
"zhTW": "中文 (台灣,正體)"
"zhTW": "中文 (台灣,正體)",
"et": "愛沙尼亞文",
"da": "丹麥文"
}

View File

@@ -46,7 +46,7 @@
"sq": "Albanian",
"sv": "Swedish",
"te": "Telugu",
"th": "Thai",
"th": "Thailand",
"tr": "Turkish",
"uk": "Ukrainian",
"vi": "Vietnamese",

View File

@@ -49,11 +49,9 @@
"messagebox": "",
"nickname": {
"popover": "Kies ’n bynaam",
"title": "",
"titleWithPolls": ""
"title": ""
},
"title": "",
"titleWithPolls": ""
"title": ""
},
"connectingOverlay": {
"joiningRoom": ""

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