Compare commits

...

77 Commits

Author SHA1 Message Date
paweldomas
4d60a4e3a6 ref(base/session): createSession on APP_WILL_NAVIGATE 2019-05-08 14:48:53 -05:00
paweldomas
160380dac0 ref(base/session): create tracks and connect on SET_ROOM 2019-05-08 14:46:18 -05:00
paweldomas
9dbba7b119 ref(base/session): move endAllSessions to APP_WILL_NAVIGATE 2019-05-08 14:39:18 -05:00
paweldomas
7101f90b6e feat: add base/session 2019-05-06 16:06:56 -05:00
paweldomas
621ee7b447 ref(base/connection/actions.native): JitsiConnection.connect returns void
Do not return anything from JitsiConnection.connect, because it's not
a promise and returns void. Doing so is confusing to the reader.
2019-05-06 16:06:56 -05:00
Leonard Kim
3f4a71c26d fix(welcome-page): remove watermark container to avoid z-index wars
By making the container 100% height and position relative, that
would cause it to overlap any static-positioned  elements below it.
The 100% makes it so that any watermarks intended for the bottom
of the page show up on the bottom of the page. However, it's not
needed because watermark stylings already try to position the
watermarks at the bottom.
2019-05-04 11:03:48 -07:00
Leonard Kim
e7db8d6812 fix(chat): save chat error messages into redux
The proper field name is "messageType",
not "type." Also using "type" would
override the actionType.
2019-05-03 14:06:36 -07:00
Saúl Ibarra Corretgé
7d2ac0244d deps: react-native-webrtc@4064c6f2db4f8b961daaaa8dafc6a896d7cfbc43
New M69 build with Metal crash fixes.
2019-05-03 19:29:30 +02:00
Saúl Ibarra Corretgé
c0efea5168 ios: enable bitcode
Time has come. We need to enable bitcode. It's optional for iOS targets, but
mandatory for the entire project if there is a watchOS target. Since we have a
watchOS target, it's time to enable it.
2019-05-03 19:29:30 +02:00
Saúl Ibarra Corretgé
5ed53dcef5 ios: update Fastlane for watchOS app 2019-05-03 19:29:30 +02:00
Saúl Ibarra Corretgé
746159a1ac ios: set compilation mode to "wholemodule" for release builds 2019-05-03 19:29:30 +02:00
Saúl Ibarra Corretgé
43a8fd2a53 ios: set iOS deployment target correctly everywhere 2019-05-03 19:29:30 +02:00
Saúl Ibarra Corretgé
a26bb2c1a6 watchos: add watchOS app
Co-authored-by: Pawel Domas <pawel.domas@jitsi.org>
2019-05-03 19:29:30 +02:00
paweldomas
e4af5ddbe9 feat(base/connection): throw error and add isInviteURLReady 2019-05-03 19:29:30 +02:00
Дамян Минков
768cff48a4 Notify for new device (#4165)
* Fix detecting preferred audio output.

Fixes detecting when a new output device is found and we have stored user preference of using that device.

* Does not store which is the currently open device on save.

Does not save the currently opened device when saving settings dialog, this will be done once we successfully replace the tracks to use the new devices.

* Saves opened audio device after successfully changing it.

If we do it earlier _updateAudioDeviceId is using localAudio and can store wrong value.

* Adds notification for new non preferred devices.

A notification is shown which gives an option to the user to select and use the newly plugged devices.
Adding custom button and handler for the action to the notifications.

* Changes logic to search and handle all newly added devices from array.

* Moves some utility methods to features/base/devices.
2019-05-03 18:25:33 +01:00
damencho
384f0d4317 Removes hardcoded defaulting to US number from the code. 2019-05-03 16:55:22 +01:00
damencho
0ec4e6a805 Makes numbers clickable on the more numbers page when opened on mobile. 2019-05-03 16:55:22 +01:00
Saúl Ibarra Corretgé
5cc01b074e ios: update Podfile.lock for RN update 2019-05-03 10:27:17 +02:00
damencho
deaf5ba612 Always uses the id for the device extrackted from the track.
When updating the currently used devices always uses the id that is used by the local track instance.
2019-05-02 11:55:46 +01:00
damencho
740c1eb84f Adds new persistent state for devices user selection.
The state about currently opened devices is filtered and not stored, where we only store when user selects a device preferences.
Also allow changing input devices for Firefox when we are not in a conference.
2019-05-02 11:55:46 +01:00
Saúl Ibarra Corretgé
2d45709a6a android: add the ability to make a "libre" build
A libre build will exclude the following:

- Analytics modules
- Google Play services GMS
- Crashlytics
- Firebase
2019-05-02 09:26:20 +02:00
Saúl Ibarra Corretgé
6bbc2927ab analytics: don't initialize handlers if they are not properly configured 2019-05-02 09:26:20 +02:00
Saúl Ibarra Corretgé
08891b17b6 android: expose JitsiMeetActivity.leave() 2019-05-02 09:26:20 +02:00
Saúl Ibarra Corretgé
aab3428347 android: make JitsiMeetActivity.join public 2019-05-02 09:26:20 +02:00
Saúl Ibarra Corretgé
bf7b1c5cfc rn: add support for alpha.jitsi.net 2019-05-01 23:23:24 +02:00
Saúl Ibarra Corretgé
7b347baab6 deps: react-native@0.59.5 2019-05-01 19:16:08 +02:00
Saúl Ibarra Corretgé
f9b3d470e9 cc: fix showing CC button if config option is undefined 2019-04-30 14:50:56 +02:00
Saúl Ibarra Corretgé
7b78fa45f4 invite: don't consider "add people" enabled if there is no search URL
This avoids showing the + button when there is no service configured, ie with
the default Jitsi Meet install.
2019-04-30 14:50:56 +02:00
Saúl Ibarra Corretgé
34dcbd991e rn: wait for animation before hiding SlidingView 2019-04-30 12:45:53 +02:00
Saúl Ibarra Corretgé
70dc22c107 rn: refactor BottomSheet
Avoid using a Modal since those create trouble with the view hierarchy.
2019-04-30 12:45:53 +02:00
damencho
89719520e2 Disposes the tracks in component was unmounted while creating those.
The issue is if you quickly click Devices and then another tab, we may leave open tracks (video light stays on even when you are video muted).
2019-04-29 14:38:17 +00:00
Дамян Минков
ce7bdb35ac Merge pull request #4152 from jitsi/prosody-0.10-update
Updates config if prosody 0.10 is used.
2019-04-29 14:36:55 +00:00
Дамян Минков
bf8c716477 Merge pull request #4150 from jitsi/invitation-update
Update copy invite text.
2019-04-29 14:36:46 +00:00
Дамян Минков
93e8d755d3 Merge pull request #4148 from zbettenbuk/recording-web-css-fix
Safeguard Container style when used cross-platform
2019-04-29 14:36:35 +00:00
damencho
c09eee0985 Disables chat when we are in recorder mode. 2019-04-29 14:36:22 +00:00
damencho
4f6a0d7d3a Updates config if prosody 0.10 is used. 2019-04-29 15:24:55 +01:00
damencho
dd5233d31b Update copy invite text. 2019-04-29 15:06:36 +01:00
Bettenbuk Zoltan
31638133b7 Safeguard Container style when used cross-platform 2019-04-29 13:37:30 +02:00
Bettenbuk Zoltan
b886f8d72d rn: specify chat text field font color 2019-04-26 21:33:11 +02:00
Дамян Минков
a6555c5d24 Singleton follow me (#4144)
* Prints errors in case of wrong initialization.

Not printing can masks some errors in the code.

* Allow only one Follow Me moderator in a meeting.

* Sends Follow Me state with all presences of the moderator.

This fixes an issue where the moderator sends the Follow Me state and then for example mute or unmute video (this will produce a presence without Follow Me state) and the new comers will not reflect current Follow Me state till a change of it comes.

* Changes fixing comments.

* Changes fixing comments.
2019-04-26 18:11:53 +00:00
Hristo Terezov
98c8fb09c4 feat(package.json): Update lib-jitsi-meet. 2019-04-26 07:54:38 -07:00
Leonard Kim
b76b261cab fix(invite): show telephone icon 2019-04-26 07:46:41 -07:00
Bettenbuk Zoltan
0b6c51f666 rn: replace 3rd party chat library with custom implementation 2019-04-26 15:17:36 +02:00
Sylvia van Os
1cb9bbc7a4 Fix wrong filename change 2019-04-26 09:06:43 +00:00
Sylvia van Os
fee9bdb98c Fix NAT documentation 2019-04-26 09:06:43 +00:00
virtuacoplenny
fb82cf4517 fix(modal): bump dep to 8.0.1 to remove scrollbars (#4139) 2019-04-25 11:58:11 -07:00
Saúl Ibarra Corretgé
85388b8d23 ios: handle some corner cases with Firebase Dynamic Links
- handle some weird bug
(https://github.com/firebase/firebase-ios-sdk/issues/233)
- use a common function to extract the URL off a dynamic link
2019-04-25 18:18:09 +02:00
Saúl Ibarra Corretgé
33f133ac25 ios: simplify code for handling CallKit listeners
Replace the Swift array with an Objective-C one, since it's going to store
Objective-C objects and not Swift objects (or Swift objects which inherit from
NSObject, which is equivalent).

This avoids the need for JMCallKitEventListenerWrapper entirely, since an
NSArray can store NSObjectProtocol objects, unlike a Swift array, which prompted
the creation of the wrapper in the first place.
2019-04-25 18:17:55 +02:00
Saúl Ibarra Corretgé
774c5ecd18 rn: ensure the conference terminated event is always sent
Dear reader, I'm not proud at all of what you are about to read, but sometimes
life just gives you lemons, so enjoy some lemonade!

Joining a conference implies first creating the XMPP connection and then joining
the MUC. It's very possible the XMPP connection was made but there was no chance
for the conference to be created.

This patch fixes this case by artificially genrating a conference terminated
event in such case. In order to have all the necessary knowledge for this event
to be sent the connection now keeps track of the conference that runs it.

In addition, there is an even more obscure corner case: it's not impossible to
try to disconnect when there is not even a connection. This was fixed by
creating a fake disconnect event. Alas the location URL is lost at this point,
but it's better than nothing I guess.
2019-04-25 14:04:26 +02:00
Saúl Ibarra Corretgé
ccc5e19e3c rn: fix filling LoadConfigOverlay's background 2019-04-24 17:41:28 +02:00
Saúl Ibarra Corretgé
32a81b0be5 rn: add our benevolent employer to the list of known domains 2019-04-24 17:36:41 +02:00
Saúl Ibarra Corretgé
59db39d4d9 rn: cleanup old code
This legacy code was added about a year ago to ease the migration between
releases:
631f51d627

I consider this not to be needed anymore.
2019-04-24 17:36:41 +02:00
damencho
2219298501 Updates web styling for file recording service sharing option. 2019-04-24 14:54:33 +00:00
Bettenbuk Zoltan
f92d530b0a Fix double file recording sharing switch 2019-04-24 10:35:43 +00:00
Bettenbuk Zoltan
e98c169c2f [RN] Fix iOS keyboard bug on invite search dialog 2019-04-24 11:48:09 +02:00
Saúl Ibarra Corretgé
6bf962817b ios: add a CallKit icon
The SDK will now search for an asset called "CallKitIcon" on the main bundle,
and fallback to a built-in asset it it's not there, allowing SDK users to
customize it by just adding asset with that name.
2019-04-24 10:03:46 +02:00
virtuacoplenny
4c286b8580 chore(deps): bump lib to get fixed rtc.destroy call (#4122) 2019-04-23 15:38:32 -07:00
Дамян Минков
37639a5614 Merge pull request #4121 from jitsi/remove-edge-support
Removes Edge support.
2019-04-23 20:32:17 +00:00
Bettenbuk Zoltan
b7198ba4b3 Add recording file sharing switch 2019-04-23 20:32:10 +00:00
damencho
2180d33e3d Adds alias for external_api.js in all default web config. 2019-04-23 20:31:53 +00:00
damencho
43a0ae578e Removes Edge support. 2019-04-23 17:55:07 +01:00
Bettenbuk Zoltan
154200460d Add some other paths to proxy bypass 2019-04-23 18:00:27 +02:00
Saúl Ibarra Corretgé
9a92dc578c ios: fix resetting CallKit's CXProvider
When CallKit is enabled / disabled, a new CXProvider must be created in order to
not confuse CallKit (it misbehaves otherwise).
2019-04-23 09:55:01 +02:00
paweldomas
eb38300c0d chore: update LJM to 1bfc96a2876d6527bfa27cf46d4f1e9f6e65edbc
Updates LJM in order to stop printing few obsolete error messages.
2019-04-18 12:24:23 -05:00
paweldomas
37b1ccbe61 ios: update react-native-werbtc in order to fix leaking streams 2019-04-18 12:24:23 -05:00
Bettenbuk Zoltan
725f9b1961 [RN] Rename lock room button 2019-04-18 14:18:08 +01:00
Leonard Kim
b172639237 fix(follow-me): remove duplicate default state 2019-04-17 15:58:55 -05:00
virtuacoplenny
c7013f5c4b ref(follow-me): hook into redux (#3991)
Use subscribers to detect state change and emit those
out to other participants. Use middleware to register
the command listener.
2019-04-17 08:05:32 -07:00
Saúl Ibarra Corretgé
aefa836406 Revert "misc: don't show a warning on Safari with VP8"
This reverts commit 9625be1db3.
2019-04-17 15:15:48 +02:00
virtuacoplenny
f6c410610a fix(toolbar): let click through gradient (#4107)
Otherwise it can eat clicks on elements it is above,
like YouTube and Etherpad controls.
2019-04-17 06:15:08 -07:00
Saúl Ibarra Corretgé
603d161788 ios: remove no longer needed code
Ever since we switched to handling track events instead of mute actions this has
been dead code. It was also added in the wrong place, since it's responsibility
of the JS code to solve the ping-pong problem.
2019-04-17 13:24:42 +02:00
Saúl Ibarra Corretgé
c1f8a35156 doc: add links to the sample SDK applications repo 2019-04-17 09:37:28 +02:00
virtuacoplenny
866dc4dbc6 ref(subtitles): remove logic around dialing transcriber (#4011) 2019-04-16 12:27:17 -07:00
damencho
69a12395d2 Removes debug log and adds safety check whether config exists. 2019-04-16 21:16:38 +02:00
virtuacoplenny
17627291e8 ref(css): use var for desktop drag area margin (#4104) 2019-04-16 11:45:25 -07:00
Hristo Terezov
30669c7699 feat(lib-jitsi-meet): Update version. 2019-04-16 17:05:02 +01:00
Hristo Terezov
4abc2db24a fix(device-selection): Default device change. 2019-04-16 17:05:02 +01:00
188 changed files with 4555 additions and 1650 deletions

View File

@@ -33,7 +33,7 @@ You can get our mobile versions from here:
## Building the sources
Node.js >= 8 and npm >= 6 are required.
Node.js >= 10 and npm >= 6 are required.
On Debian/Ubuntu systems, the required packages can be installed with:
```

View File

@@ -1,5 +1,10 @@
# Jitsi Meet SDK for Android
## Sample applications using the SDK
If you want to see how easy integrating the Jitsi Meet SDK into a native application is, take a look at the
[sample applications repository](https://github.com/jitsi/jitsi-meet-sdk-samples).
## Build your own, or use a pre-build SDK artifacts/binaries
Jitsi conveniently provides a pre-build SDK artifacts/binaries in its Maven repository. When you do not require any

View File

@@ -1,6 +1,7 @@
apply plugin: 'com.android.application'
boolean googleServicesEnabled = project.file('google-services.json').exists()
boolean googleServicesEnabled \
= project.file('google-services.json').exists() && !rootProject.ext.libreBuild
// Crashlytics integration is done as part of Firebase now, so it gets
// automagically activated with google-services.json
@@ -36,11 +37,24 @@ android {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-debug.pro'
buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${googleServicesEnabled}"
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-release.pro'
buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${googleServicesEnabled}"
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
}
}
sourceSets {
main {
java {
if (rootProject.ext.libreBuild) {
srcDir "src"
exclude "**/GoogleServicesHelper.java"
}
}
}
}
@@ -58,7 +72,17 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "com.android.support:support-v4:${rootProject.ext.supportLibVersion}"
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
implementation 'com.google.android.gms:play-services-auth:16.0.1'
if (!rootProject.ext.libreBuild) {
implementation 'com.google.android.gms:play-services-auth:16.0.1'
// Firebase
// - Crashlytics
// - Dynamic Links
implementation 'com.google.firebase:firebase-core:16.0.6'
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.8'
implementation 'com.google.firebase:firebase-dynamic-links:16.1.5'
}
implementation project(':sdk')
@@ -73,13 +97,6 @@ dependencies {
exclude group: "com.android.support", module: "annotations"
}
annotationProcessor "com.github.bumptech.glide:compiler:${rootProject.ext.glideVersion}"
// Firebase
// - Crashlytics
// - Dynamic Links
implementation 'com.google.firebase:firebase-core:16.0.6'
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.8'
implementation 'com.google.firebase:firebase-dynamic-links:16.1.5'
}
gradle.projectsEvaluated {

View File

@@ -80,6 +80,7 @@
# Jisti Meet SDK
-keep class org.jitsi.meet.** { *; }
-keep class org.jitsi.meet.sdk.** { *; }
# We added the following when we switched minifyEnabled on. Probably because we

View File

@@ -25,6 +25,7 @@
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:host="alpha.jitsi.net" android:scheme="https" />
<data android:host="beta.meet.jit.si" android:scheme="https" />
<data android:host="meet.jit.si" android:scheme="https" />
</intent-filter>

View File

@@ -0,0 +1,40 @@
package org.jitsi.meet;
import android.net.Uri;
import android.util.Log;
import com.crashlytics.android.Crashlytics;
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks;
import io.fabric.sdk.android.Fabric;
import org.jitsi.meet.sdk.JitsiMeetActivity;
/**
* Helper class to initialize Google related services and functionality.
* This functionality is compiled conditionally and called via reflection, that's why it was
* extracted here.
*
* "Libre builds" (builds with the LIBRE_BUILD flag set) will not include this file.
*/
final class GoogleServicesHelper {
public static void initialize(JitsiMeetActivity activity) {
if (BuildConfig.GOOGLE_SERVICES_ENABLED) {
Log.d(activity.getClass().getSimpleName(), "Initializing Google Services");
Fabric.with(activity, new Crashlytics());
FirebaseDynamicLinks.getInstance().getDynamicLink(activity.getIntent())
.addOnSuccessListener(activity, pendingDynamicLinkData -> {
Uri dynamicLink = null;
if (pendingDynamicLinkData != null) {
dynamicLink = pendingDynamicLinkData.getLink();
}
if (dynamicLink != null) {
activity.join(dynamicLink.toString());
}
});
}
}
}

View File

@@ -29,10 +29,7 @@ import org.jitsi.meet.sdk.JitsiMeet;
import org.jitsi.meet.sdk.JitsiMeetActivity;
import org.jitsi.meet.sdk.JitsiMeetConferenceOptions;
import com.crashlytics.android.Crashlytics;
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks;
import io.fabric.sdk.android.Fabric;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
@@ -57,22 +54,16 @@ public class MainActivity extends JitsiMeetActivity {
@Override
protected boolean extraInitialize() {
Log.d(this.getClass().getSimpleName(), "LIBRE_BUILD="+BuildConfig.LIBRE_BUILD);
// Setup Crashlytics and Firebase Dynamic Links
if (BuildConfig.GOOGLE_SERVICES_ENABLED) {
Fabric.with(this, new Crashlytics());
FirebaseDynamicLinks.getInstance().getDynamicLink(getIntent())
.addOnSuccessListener(this, pendingDynamicLinkData -> {
Uri dynamicLink = null;
if (pendingDynamicLinkData != null) {
dynamicLink = pendingDynamicLinkData.getLink();
}
if (dynamicLink != null) {
join(dynamicLink.toString());
}
});
// Here we are using reflection since it may have been disabled at compile time.
try {
Class<?> cls = Class.forName("org.jitsi.meet.GoogleServicesHelper");
Method m = cls.getMethod("initialize", JitsiMeetActivity.class);
m.invoke(null, this);
} catch (Exception e) {
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
}
// In Debug builds React needs permission to write over other apps in

View File

@@ -167,6 +167,9 @@ ext {
// Glide
excludeAppGlideModule = true
glideVersion = "4.7.1" // keep in sync with react-native-fast-image
// Libre build
libreBuild = (System.env.LIBRE_BUILD ?: "true").toBoolean()
}
// If Android SDK is not installed, accept its license so that it

View File

@@ -10,10 +10,25 @@ android {
}
buildTypes {
debug {}
debug {
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
}
}
sourceSets {
main {
java {
if (rootProject.ext.libreBuild) {
srcDir "src"
exclude "**/AmplitudeModule.java"
}
exclude "test/"
}
}
}
}
@@ -24,19 +39,23 @@ dependencies {
implementation "com.android.support:support-v4:${rootProject.ext.supportLibVersion}"
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
implementation 'com.amplitude:android-sdk:2.14.1'
implementation 'com.dropbox.core:dropbox-core-sdk:3.0.8'
api 'com.facebook.react:react-native:+'
implementation 'com.dropbox.core:dropbox-core-sdk:3.0.8'
if (!rootProject.ext.libreBuild) {
implementation 'com.amplitude:android-sdk:2.14.1'
implementation(project(":react-native-google-signin")) {
exclude group: 'com.google.android.gms'
exclude group: 'com.android.support'
}
}
implementation project(':react-native-background-timer')
implementation project(':react-native-calendar-events')
implementation(project(':react-native-fast-image')) {
exclude group: 'com.android.support'
}
implementation(project(":react-native-google-signin")) {
exclude group: 'com.google.android.gms'
exclude group: 'com.android.support'
}
implementation project(':react-native-immersive')
implementation project(':react-native-keep-awake')
implementation project(':react-native-linear-gradient')

View File

@@ -75,6 +75,7 @@ class AppInfoModule
constants.put(
"version",
packageInfo == null ? "" : packageInfo.versionName);
constants.put("LIBRE_BUILD", BuildConfig.LIBRE_BUILD);
return constants;
}

View File

@@ -73,7 +73,7 @@ public class JitsiMeetActivity extends FragmentActivity
@Override
public void finish() {
getJitsiView().leave();
leave();
super.finish();
}
@@ -87,7 +87,7 @@ public class JitsiMeetActivity extends FragmentActivity
return fragment.getJitsiView();
}
protected void join(@Nullable String url) {
public void join(@Nullable String url) {
JitsiMeetConferenceOptions options
= new JitsiMeetConferenceOptions.Builder()
.setRoom(url)
@@ -95,10 +95,14 @@ public class JitsiMeetActivity extends FragmentActivity
join(options);
}
protected void join(JitsiMeetConferenceOptions options) {
public void join(JitsiMeetConferenceOptions options) {
getJitsiView().join(options);
}
public void leave() {
getJitsiView().leave();
}
private @Nullable JitsiMeetConferenceOptions getConferenceOptions(Intent intent) {
String action = intent.getAction();

View File

@@ -21,6 +21,7 @@ import android.app.Application;
import android.support.annotation.Nullable;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactApplicationContext;
@@ -28,6 +29,7 @@ import com.facebook.react.common.LifecycleState;
import com.facebook.react.devsupport.DevInternalSettings;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -48,7 +50,6 @@ class ReactInstanceManagerHolder {
ReactApplicationContext reactContext) {
List<NativeModule> nativeModules
= new ArrayList<>(Arrays.<NativeModule>asList(
new AmplitudeModule(reactContext),
new AndroidSettingsModule(reactContext),
new AppInfoModule(reactContext),
new AudioModeModule(reactContext),
@@ -64,6 +65,14 @@ class ReactInstanceManagerHolder {
nativeModules.add(new RNConnectionService(reactContext));
}
try {
Class<?> amplitudeModuleClass = Class.forName("AmplitudeModule");
Constructor constructor = amplitudeModuleClass.getConstructor(ReactApplicationContext.class);
nativeModules.add((NativeModule)constructor.newInstance(reactContext));
} catch (Exception e) {
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
}
return nativeModules;
}
@@ -128,31 +137,39 @@ class ReactInstanceManagerHolder {
return;
}
List<ReactPackage> packages
= new ArrayList<>(Arrays.asList(
new com.BV.LinearGradient.LinearGradientPackage(),
new com.calendarevents.CalendarEventsPackage(),
new com.corbt.keepawake.KCKeepAwakePackage(),
new com.dylanvann.fastimage.FastImageViewPackage(),
new com.facebook.react.shell.MainReactPackage(),
new com.oblador.vectoricons.VectorIconsPackage(),
new com.ocetnik.timer.BackgroundTimerPackage(),
new com.oney.WebRTCModule.WebRTCModulePackage(),
new com.rnimmersive.RNImmersivePackage(),
new com.zmxv.RNSound.RNSoundPackage(),
new ReactPackageAdapter() {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return ReactInstanceManagerHolder.createNativeModules(reactContext);
}
}));
try {
Class<?> googlePackageClass = Class.forName("co.apptailor.googlesignin.RNGoogleSigninPackage");
Constructor constructor = googlePackageClass.getConstructor();
packages.add((ReactPackage)constructor.newInstance());
} catch (Exception e) {
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
}
reactInstanceManager
= ReactInstanceManager.builder()
.setApplication(application)
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index.android")
.addPackage(new co.apptailor.googlesignin.RNGoogleSigninPackage())
.addPackage(new com.BV.LinearGradient.LinearGradientPackage())
.addPackage(new com.calendarevents.CalendarEventsPackage())
.addPackage(new com.corbt.keepawake.KCKeepAwakePackage())
.addPackage(new com.dylanvann.fastimage.FastImageViewPackage())
.addPackage(new com.facebook.react.shell.MainReactPackage())
.addPackage(new com.oblador.vectoricons.VectorIconsPackage())
.addPackage(new com.ocetnik.timer.BackgroundTimerPackage())
.addPackage(new com.oney.WebRTCModule.WebRTCModulePackage())
.addPackage(new com.rnimmersive.RNImmersivePackage())
.addPackage(new com.zmxv.RNSound.RNSoundPackage())
.addPackage(new ReactPackageAdapter() {
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
return
ReactInstanceManagerHolder.createNativeModules(
reactContext);
}
})
.addPackages(packages)
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();

View File

@@ -49,6 +49,7 @@ import {
setDesktopSharingEnabled
} from './react/features/base/conference';
import {
checkAndNotifyForNewDevice,
getAvailableDevices,
setAudioOutputDeviceId,
updateDeviceList
@@ -437,8 +438,8 @@ class ConferenceConnector {
hasRead: true,
error: code,
message: msg,
timestamp: Date.now(),
type: 'error'
messageType: 'error',
timestamp: Date.now()
}));
}
break;
@@ -2094,9 +2095,7 @@ export default {
})
.then(() => {
logger.log('switched local video device');
APP.store.dispatch(updateSettings({
cameraDeviceId
}));
this._updateVideoDeviceId();
})
.catch(err => {
APP.UI.showCameraErrorNotification(err);
@@ -2125,12 +2124,11 @@ export default {
return stream;
})
.then(stream => {
this.useAudioStream(stream);
.then(stream => this.useAudioStream(stream))
.then(() => {
logger.log('switched local audio device');
APP.store.dispatch(updateSettings({
micDeviceId
}));
this._updateAudioDeviceId();
})
.catch(err => {
APP.UI.showMicErrorNotification(err);
@@ -2301,18 +2299,9 @@ export default {
// Ugly way to synchronize real device IDs with local
// storage and settings menu. This is a workaround until
// getConstraints() method will be implemented in browsers.
if (this.localAudio) {
dispatch(updateSettings({
micDeviceId: this.localAudio.getDeviceId()
}));
}
this._updateAudioDeviceId();
if (this.localVideo
&& this.localVideo.videoType === 'camera') {
dispatch(updateSettings({
cameraDeviceId: this.localVideo.getDeviceId()
}));
}
this._updateVideoDeviceId();
APP.UI.onAvailableDevicesChanged(devices);
});
@@ -2321,6 +2310,33 @@ export default {
return Promise.resolve();
},
/**
* Updates the settings for the currently used video device, extracting
* the device id from the used track.
* @private
*/
_updateVideoDeviceId() {
if (this.localVideo
&& this.localVideo.videoType === 'camera') {
APP.store.dispatch(updateSettings({
cameraDeviceId: this.localVideo.getDeviceId()
}));
}
},
/**
* Updates the settings for the currently used audio device, extracting
* the device id from the used track.
* @private
*/
_updateAudioDeviceId() {
if (this.localAudio) {
APP.store.dispatch(updateSettings({
micDeviceId: this.localAudio.getDeviceId()
}));
}
},
/**
* Event listener for JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED to
* handle change of available media devices.
@@ -2329,6 +2345,8 @@ export default {
* @returns {Promise}
*/
_onDeviceListChanged(devices) {
const oldDevices = APP.store.getState()['features/base/devices'].availableDevices;
APP.store.dispatch(updateDeviceList(devices));
const newDevices
@@ -2340,6 +2358,10 @@ export default {
const promises = [];
const audioWasMuted = this.isLocalAudioMuted();
const videoWasMuted = this.isLocalVideoMuted();
const requestedInput = {
audio: Boolean(newDevices.audioinput),
video: Boolean(newDevices.videoinput)
};
if (typeof newDevices.audiooutput !== 'undefined') {
const { dispatch } = APP.store;
@@ -2351,6 +2373,37 @@ export default {
promises.push(setAudioOutputPromise);
}
// Handles the use case when the default device is changed (we are always stopping the streams because it's
// 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 && this.localAudio) {
this.localAudio.stopStream();
}
if (requestedInput.video && this.localVideo) {
this.localVideo.stopStream();
}
// Let's handle unknown/non-preferred devices
const newAvailDevices
= APP.store.getState()['features/base/devices'].availableDevices;
if (typeof newDevices.audiooutput === 'undefined') {
APP.store.dispatch(
checkAndNotifyForNewDevice(newAvailDevices.audioOutput, oldDevices.audioOutput));
}
if (!requestedInput.audio) {
APP.store.dispatch(
checkAndNotifyForNewDevice(newAvailDevices.audioInput, oldDevices.audioInput));
}
if (!requestedInput.video) {
APP.store.dispatch(
checkAndNotifyForNewDevice(newAvailDevices.videoInput, oldDevices.videoInput));
}
promises.push(
mediaDeviceHelper.createLocalTracksAfterDeviceListChanged(
createLocalTracksF,
@@ -2369,8 +2422,25 @@ export default {
});
return Promise.all(muteSyncPromises)
.then(() => Promise.all(
this._setLocalAudioVideoStreams(tracks)));
.then(() =>
Promise.all(Object.keys(requestedInput).map(mediaType => {
if (requestedInput[mediaType]) {
const useStream
= mediaType === 'audio'
? this.useAudioStream.bind(this)
: this.useVideoStream.bind(this);
// Use the new stream or null if we failed to obtain it.
return useStream(tracks.find(track => track.getType() === mediaType) || null)
.then(() => {
mediaType === 'audio'
? this._updateAudioDeviceId()
: this._updateVideoDeviceId();
});
}
return Promise.resolve();
})));
})
.then(() => {
// Log and sync known mute state.

View File

@@ -184,7 +184,11 @@ var config = {
// by enabling fileRecordingsServiceEnabled, we show both the integrations
// and the generic recording service (its configuration and storage type
// depends on jibri configuration)
// fileRecordingsServiceEnabled: false
// fileRecordingsServiceEnabled: false,
// Whether to show the possibility to share file recording with other people
// (e.g. meeting participants), based on the actual implementation
// on the backend.
// fileRecordingsServiceSharingEnabled: false,
// Whether to enable live streaming or not.
// liveStreamingEnabled: false,

View File

@@ -5,7 +5,8 @@ import jitsiLocalStorage from './modules/util/JitsiLocalStorage';
import {
connectionEstablished,
connectionFailed
connectionFailed,
connectionWillConnect
} from './react/features/base/connection';
import {
isFatalJitsiConnectionError,
@@ -74,6 +75,7 @@ function checkForAttachParametersAndConnect(id, password, connection) {
function connect(id, password, roomName) {
const connectionConfig = Object.assign({}, config);
const { issuer, jwt } = APP.store.getState()['features/base/jwt'];
const { locationURL } = APP.store.getState()['features/base/connection'];
connectionConfig.bosh += `?room=${roomName}`;
@@ -83,6 +85,8 @@ function connect(id, password, roomName) {
jwt && issuer && issuer !== 'anonymous' ? jwt : undefined,
connectionConfig);
APP.store.dispatch(connectionWillConnect(connection, locationURL));
return new Promise((resolve, reject) => {
connection.addEventListener(
JitsiConnectionEvents.CONNECTION_ESTABLISHED,

View File

@@ -42,7 +42,7 @@
flex: 1;
font-size: 10pt;
line-height: 20px;
margin-top: 30px;
margin-top: $desktopAppDragBarHeight + 5px;
overflow: auto;
padding: 5px;
text-align: left;
@@ -104,7 +104,7 @@
position: absolute;
right: 5px;
text-align: center;
top: 25px;
top: $desktopAppDragBarHeight;
width: 10px;
z-index: 1;
}

View File

@@ -11,7 +11,7 @@
flex: 0;
flex-direction: row;
justify-content: space-between;
margin-top: 32px;
padding-top: 32px;
.recording-title {
display: inline-flex;
@@ -21,6 +21,14 @@
}
}
.recording-header-line {
border-top: 1px solid #5e6d7a;
}
.recording-switch-disabled {
opacity: 0.5;
}
.recording-icon-container {
display: inline-flex;
align-items: center;

View File

@@ -3,6 +3,7 @@
transition: top .3s ease-in;
height: 95px;
width: 100%;
pointer-events: none;
position: absolute;
padding: 25px 140px 0 140px;
text-align: center;

View File

@@ -48,6 +48,7 @@
height: 160px;
width: 100%;
bottom: -160px;
pointer-events: none;
position: absolute;
z-index: $toolbarBackgroundZ;
}

View File

@@ -90,6 +90,7 @@ $defaultWatermarkLink: '../images/watermark.png';
$sidebarWidth: 220px;
$popoverMenuPadding: 13px;
$happySoftwareBackground: transparent;
$desktopAppDragBarHeight: 25px;
/**
* Z-indexes. TODO: Replace this by a function.

View File

@@ -162,10 +162,4 @@ body.welcome-page {
font-size: 32px;
}
}
.welcome-watermark {
position: absolute;
width: 100%;
height: 100%;
}
}

View File

@@ -25,7 +25,7 @@
display: flex;
flex-direction: column-reverse;
height: 100%;
padding: 20px 5px 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

View File

@@ -126,16 +126,30 @@ case "$1" in
fi
PR11_INSTALL_CHECK="$(dpkg-query -f '${Status}' -W 'prosody-0.11' 2>/dev/null | awk '{print $3}' || true)"
echo "PR11_INSTALL_CHECK is $PR11_INSTALL_CHECK"
PR10_INSTALL_CHECK="$(dpkg-query -f '${Status}' -W 'prosody-0.10' 2>/dev/null | awk '{print $3}' || true)"
PR_VER_INSTALLED=$(dpkg-query -f='${Version}\n' --show prosody 2>/dev/null || true)
echo "PR_VER_INSTALLED is $PR_VER_INSTALLED"
if [ "$PR11_INSTALL_CHECK" = "installed" ] \
|| [ "$PR11_INSTALL_CHECK" = "unpacked" ] \
|| dpkg --compare-versions "$PR_VER_INSTALLED" gt "0.11" ; then
sed -i 's/storage = \"null\"/storage = \"memory\"/g' $PROSODY_HOST_CONFIG
if [ -f $PROSODY_HOST_CONFIG ]; then
sed -i 's/storage = \"null\"/storage = \"memory\"/g' $PROSODY_HOST_CONFIG
# trigger a restart
PROSODY_CONFIG_PRESENT="false"
# trigger a restart
PROSODY_CONFIG_PRESENT="false"
fi
fi
if [ "$PR10_INSTALL_CHECK" = "installed" ] \
|| [ "$PR10_INSTALL_CHECK" = "unpacked" ] \
|| dpkg --compare-versions "$PR_VER_INSTALLED" gt "0.10" ; then
# if the version is 0.10.X (>0.10 and <0.11)
if [ -f $PROSODY_HOST_CONFIG ] \
&& dpkg --compare-versions "$PR_VER_INSTALLED" lt "0.11" ; then
sed -i 's/storage = \"null\"/storage = \"none\"/g' $PROSODY_HOST_CONFIG
# trigger a restart
PROSODY_CONFIG_PRESENT="false"
fi
fi
if [ ! -f /var/lib/prosody/$JICOFO_AUTH_DOMAIN.crt ]; then

View File

@@ -132,6 +132,7 @@ case "$1" in
echo "org.jitsi.videobridge.rest.jetty.ResourceHandler.alias./config.js=/etc/jitsi/meet/$JVB_HOSTNAME-config.js" >> $JVB_CONFIG
echo "org.jitsi.videobridge.rest.jetty.ResourceHandler.alias./interface_config.js=/usr/share/jitsi-meet/interface_config.js" >> $JVB_CONFIG
echo "org.jitsi.videobridge.rest.jetty.ResourceHandler.alias./logging_config.js=/usr/share/jitsi-meet/logging_config.js" >> $JVB_CONFIG
echo "org.jitsi.videobridge.rest.jetty.ResourceHandler.alias./external_api.js=/usr/share/jitsi-meet/libs/external_api.min.js" >> $JVB_CONFIG
echo "org.jitsi.videobridge.rest.jetty.RewriteHandler.regex=^/([a-zA-Z0-9]+)$" >> $JVB_CONFIG
echo "org.jitsi.videobridge.rest.jetty.RewriteHandler.replacement=/" >> $JVB_CONFIG
echo "org.jitsi.videobridge.rest.jetty.SSIResourceHandler.paths=/" >> $JVB_CONFIG

View File

@@ -26,6 +26,10 @@ server {
alias /etc/jitsi/meet/jitsi-meet.example.com-config.js;
}
location /external_api.js {
alias /usr/share/jitsi-meet/libs/external_api.min.js;
}
location ~ ^/([a-zA-Z0-9=\?]+)$ {
rewrite ^/(.*)$ / break;
}
@@ -34,11 +38,6 @@ server {
ssi on;
}
# Backward compatibility
location ~ /external_api.* {
root /usr/share/jitsi-meet/libs;
}
# BOSH
location /http-bind {
proxy_pass http://localhost:5280/http-bind;

View File

@@ -36,6 +36,11 @@
Require all granted
</Location>
Alias "/external_api.js" "/usr/share/jitsi-meet/libs/external_api.min.js"
<Location /external_api.js>
Require all granted
</Location>
ProxyPreserveHost on
ProxyPass /http-bind http://localhost:5280/http-bind/
ProxyPassReverse /http-bind http://localhost:5280/http-bind/

View File

@@ -236,19 +236,12 @@ invoke-rc.d nginx restart
```
## Running behind NAT
Jitsi-Videobridge can run behind a NAT, provided that all required ports are routed (forwarded) to the machine that it runs on. By default these ports are (TCP/443 or TCP/4443 and UDP 10000-20000).
Jitsi-Videobridge can run behind a NAT, provided that all required ports are routed (forwarded) to the machine that it runs on. By default these ports are (TCP/443 or TCP/4443 and UDP 10000).
The following extra lines need to be added the file `~/.sip-communicator/sip-communicator.properties` (in the home directory of the user running the videobridge):
```
org.jitsi.videobridge.NAT_HARVESTER_LOCAL_ADDRESS=<Local.IP.Address>
org.jitsi.videobridge.NAT_HARVESTER_PUBLIC_ADDRESS=<Public.IP.Address>
```
So the file should look like this at the end:
```
org.jitsi.impl.neomedia.transform.srtp.SRTPCryptoContext.checkReplay=false
org.jitsi.videobridge.NAT_HARVESTER_LOCAL_ADDRESS=<Local.IP.Address>
org.jitsi.videobridge.NAT_HARVESTER_PUBLIC_ADDRESS=<Public.IP.Address>
org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS=<Local.IP.Address>
org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS=<Public.IP.Address>
```
# Hold your first conference

View File

@@ -1,13 +1,14 @@
# Jitsi Meet apps for Android and iOS
Jitsi Meet can also be built as a standalone app for Android or iOS. It uses the
Jitsi Meet can be built as a standalone app for Android or iOS. It uses the
[React Native] framework.
**If you want to rebuild the SDK yourself look in [Android README] or [iOS README].**
First make sure the [React Native dependencies] are installed.
**NOTE**: This document assumes the app is being built on a macOS system.
**NOTE**: Node 6.X and npm 3.X are recommended for building.
**NOTE**: Node 10.X and npm 6.X are recommended for building.
## iOS
@@ -21,8 +22,6 @@ First make sure the [React Native dependencies] are installed.
npm install -g ios-deploy
```
You may need to add ```--unsafe-perm=true``` if you are running on [Mac OS 10.11 or greater](https://github.com/phonegap/ios-deploy#os-x-1011-el-capitan-or-greater).
- Install main dependencies:
```bash
@@ -68,9 +67,7 @@ First make sure the [React Native dependencies] are installed.
3. Other remarks
It's likely you'll need to change the bundle ID for deploying to a device
because the default bundle ID points to the application signed by Atlassian.
It's likely you'll need to change the bundle ID for deploying to a device.
This can be changed in the "General" tab. Under "Identity" set
"Bundle Identifier" to a different value, and adjust the "Team" in the
"Signing" section to match your own.
@@ -102,6 +99,8 @@ code is being interpreted by Chrome's V8 engine, instead of JSCore which React
Native uses. It's important to keep this in mind due to potential differences in
supported JavaScript features.
[Android README]: https://github.com/jitsi/jitsi-meet/blob/master/android/README.md
[iOS README]: https://github.com/jitsi/jitsi-meet/blob/master/ios/README.md
[Android Studio]: https://developer.android.com/studio/index.html
[debugging]: https://facebook.github.io/react-native/docs/debugging.html
[React Native]: https://facebook.github.io/react-native/

BIN
images/icon-users.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -51,6 +51,7 @@ target 'JitsiMeet' do
:path => '../node_modules/react-native-google-signin'
pod 'RNSound', :path => '../node_modules/react-native-sound'
pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons'
pod 'RNWatch', :path => '../node_modules/react-native-watch-connectivity'
pod 'react-native-calendar-events',
:path => '../node_modules/react-native-calendar-events'
end
@@ -58,7 +59,7 @@ end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
config.build_settings['ENABLE_BITCODE'] = 'YES'
end
end
end

View File

@@ -84,8 +84,8 @@ PODS:
- nanopb/decode (0.3.901)
- nanopb/encode (0.3.901)
- ObjectiveDropboxOfficial (3.9.4)
- React (0.59.4):
- React/Core (= 0.59.4)
- React (0.59.5):
- React/Core (= 0.59.5)
- react-native-background-timer (2.1.1):
- React
- react-native-calendar-events (1.6.4):
@@ -97,52 +97,52 @@ PODS:
- SDWebImage/GIF
- react-native-keep-awake (4.0.0):
- React
- react-native-webrtc (1.69.0):
- react-native-webrtc (1.69.1):
- React
- React/Core (0.59.4):
- yoga (= 0.59.4.React)
- React/CxxBridge (0.59.4):
- React/Core (0.59.5):
- yoga (= 0.59.5.React)
- React/CxxBridge (0.59.5):
- Folly (= 2018.10.22.00)
- React/Core
- React/cxxreact
- React/jsiexecutor
- React/cxxreact (0.59.4):
- React/cxxreact (0.59.5):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React/jsinspector
- React/DevSupport (0.59.4):
- React/DevSupport (0.59.5):
- React/Core
- React/RCTWebSocket
- React/fishhook (0.59.4)
- React/jsi (0.59.4):
- React/fishhook (0.59.5)
- React/jsi (0.59.5):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React/jsiexecutor (0.59.4):
- React/jsiexecutor (0.59.5):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React/cxxreact
- React/jsi
- React/jsinspector (0.59.4)
- React/RCTActionSheet (0.59.4):
- React/jsinspector (0.59.5)
- React/RCTActionSheet (0.59.5):
- React/Core
- React/RCTAnimation (0.59.4):
- React/RCTAnimation (0.59.5):
- React/Core
- React/RCTBlob (0.59.4):
- React/RCTBlob (0.59.5):
- React/Core
- React/RCTImage (0.59.4):
- React/RCTImage (0.59.5):
- React/Core
- React/RCTNetwork
- React/RCTLinkingIOS (0.59.4):
- React/RCTLinkingIOS (0.59.5):
- React/Core
- React/RCTNetwork (0.59.4):
- React/RCTNetwork (0.59.5):
- React/Core
- React/RCTText (0.59.4):
- React/RCTText (0.59.5):
- React/Core
- React/RCTWebSocket (0.59.4):
- React/RCTWebSocket (0.59.5):
- React/Core
- React/fishhook
- React/RCTBlob
@@ -156,11 +156,13 @@ PODS:
- React/Core
- RNVectorIcons (6.0.2):
- React
- RNWatch (0.2.0):
- React
- SDWebImage/Core (4.4.6)
- SDWebImage/GIF (4.4.6):
- FLAnimatedImage (~> 1.0)
- SDWebImage/Core
- yoga (0.59.4.React)
- yoga (0.59.5.React)
DEPENDENCIES:
- Amplitude-iOS (~> 4.0.4)
@@ -191,6 +193,7 @@ DEPENDENCIES:
- RNGoogleSignin (from `../node_modules/react-native-google-signin`)
- RNSound (from `../node_modules/react-native-sound`)
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
- RNWatch (from `../node_modules/react-native-watch-connectivity`)
- yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
@@ -242,6 +245,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-sound"
RNVectorIcons:
:path: "../node_modules/react-native-vector-icons"
RNWatch:
:path: "../node_modules/react-native-watch-connectivity"
yoga:
:path: "../node_modules/react-native/ReactCommon/yoga"
@@ -268,18 +273,19 @@ SPEC CHECKSUMS:
GTMSessionFetcher: 32aeca0aa144acea523e1c8e053089dec2cb98ca
nanopb: 2901f78ea1b7b4015c860c2fdd1ea2fee1a18d48
ObjectiveDropboxOfficial: a5afefc83f6467c42c45f2253f583f2ad1ffc701
React: 5cb71fb1a15b5ce04794ab49e24b48ebe4c94e65
React: 90adac468c7b72bf1fa6c64bf230650f851a8388
react-native-background-timer: 0d34748e53a972507c66963490c775321a88f6f2
react-native-calendar-events: ee9573e355711ac679e071be70789542431f4ce3
react-native-fast-image: 47487b71169aea34868e7b38bf870b6b3f2157c5
react-native-keep-awake: eba3137546b10003361b37c761f6c429b59814ae
react-native-webrtc: a14197fefe96ab462dc098b79c428fc5a7f68216
react-native-webrtc: 90a847d19deb2d7323fef8cc89ca12b8995fbc90
RNGoogleSignin: 361174d9a3090d295b06257162b560d8efc8a6ed
RNSound: e157320f503bdd4f4ee6d8542e948d54f90c3c3a
RNVectorIcons: d819334932bcda3332deb3d2c8ea4d069e0b98f9
RNWatch: 09738b339eceb66e4d80a2371633ca5fb380fa42
SDWebImage: 3f3f0c02f09798048c47a5ed0a13f17b063572d8
yoga: 596e61c9b57751d08a22b07aba310dbd3e65ab75
yoga: 2e571f113e8cbeb0eb752aeebc86c1bfe7a8200c
PODFILE CHECKSUM: 4a11c3d66127a9845d4a5b2c7fad49f58a9c7a89
PODFILE CHECKSUM: 9e6bc935ea7d2974604572cc68938281a88cf35c
COCOAPODS: 1.6.1

View File

@@ -3,6 +3,11 @@
The Jitsi Meet iOS SDK provides the same user experience as the Jitsi Meet app,
in a customizable way which you can embed in your apps.
## Sample applications using the SDK
If you want to see how easy integrating the Jitsi Meet SDK into a native application is, take a look at the
[sample applications repository](https://github.com/jitsi/jitsi-meet-sdk-samples).
## Usage
There are 2 ways to integrate the SDK into your project:

View File

@@ -4,6 +4,7 @@
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:alpha.jitsi.net</string>
<string>applinks:beta.meet.jit.si</string>
<string>applinks:meet.jit.si</string>
</array>

View File

@@ -11,16 +11,45 @@
0B26BE6F1EC5BC3C00EEFB41 /* JitsiMeet.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0B26BE6D1EC5BC3C00EEFB41 /* JitsiMeet.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
0B412F1F1EDEE6E800B1A0A6 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B412F1E1EDEE6E800B1A0A6 /* ViewController.m */; };
0B412F211EDEE95300B1A0A6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0B412F201EDEE95300B1A0A6 /* Main.storyboard */; };
0B5418471F7C5D8C00A2DD86 /* MeetingRowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B5418461F7C5D8C00A2DD86 /* MeetingRowController.swift */; };
0B7001701F7C51CC005944F4 /* InCallController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B70016F1F7C51CC005944F4 /* InCallController.swift */; };
0BD6B4371EF82A6B00D1F4CD /* WebRTC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BD6B4361EF82A6B00D1F4CD /* WebRTC.framework */; };
0BD6B4381EF82A6B00D1F4CD /* WebRTC.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0BD6B4361EF82A6B00D1F4CD /* WebRTC.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
0BEA5C291F7B8F73000D0AB4 /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0BEA5C271F7B8F73000D0AB4 /* Interface.storyboard */; };
0BEA5C2B1F7B8F73000D0AB4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0BEA5C2A1F7B8F73000D0AB4 /* Assets.xcassets */; };
0BEA5C321F7B8F73000D0AB4 /* JitsiMeetCompanion Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 0BEA5C311F7B8F73000D0AB4 /* JitsiMeetCompanion Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
0BEA5C371F7B8F73000D0AB4 /* InterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BEA5C361F7B8F73000D0AB4 /* InterfaceController.swift */; };
0BEA5C391F7B8F73000D0AB4 /* ExtensionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BEA5C381F7B8F73000D0AB4 /* ExtensionDelegate.swift */; };
0BEA5C3B1F7B8F73000D0AB4 /* ComplicationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BEA5C3A1F7B8F73000D0AB4 /* ComplicationController.swift */; };
0BEA5C3D1F7B8F73000D0AB4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0BEA5C3C1F7B8F73000D0AB4 /* Assets.xcassets */; };
0BEA5C411F7B8F73000D0AB4 /* JitsiMeetCompanion.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 0BEA5C251F7B8F73000D0AB4 /* JitsiMeetCompanion.app */; };
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
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 */; };
695AF3ED6F686F9C5EE40F9A /* libPods-jitsi-meet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 489E8EFE2C720D10F5961AEF /* libPods-jitsi-meet.a */; };
DE4C456121DE1E4E00EA0709 /* FIRUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = DE4C455F21DE1E4E00EA0709 /* FIRUtilities.m */; };
E588011722789D43008B0561 /* JitsiMeetContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = E58801132278944E008B0561 /* JitsiMeetContext.swift */; };
E5C97B63227A1EB400199214 /* JitsiMeetCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5C97B62227A1EB400199214 /* JitsiMeetCommands.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
0BEA5C331F7B8F73000D0AB4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 0BEA5C301F7B8F73000D0AB4;
remoteInfo = "JitsiMeetCompanion Extension";
};
0BEA5C3F1F7B8F73000D0AB4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 0BEA5C241F7B8F73000D0AB4;
remoteInfo = JitsiMeetCompanion;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
0B26BE701EC5BC3C00EEFB41 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
@@ -34,6 +63,28 @@
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
0BEA5C471F7B8F73000D0AB4 /* Embed App Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
0BEA5C321F7B8F73000D0AB4 /* JitsiMeetCompanion Extension.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
runOnlyForDeploymentPostprocessing = 0;
};
0BEA5C491F7B8F73000D0AB4 /* Embed Watch Content */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
dstSubfolderSpec = 16;
files = (
0BEA5C411F7B8F73000D0AB4 /* JitsiMeetCompanion.app in Embed Watch Content */,
);
name = "Embed Watch Content";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
@@ -42,8 +93,20 @@
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>"; };
0B412F201EDEE95300B1A0A6 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
0B5418461F7C5D8C00A2DD86 /* MeetingRowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingRowController.swift; sourceTree = "<group>"; };
0B70016F1F7C51CC005944F4 /* InCallController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InCallController.swift; sourceTree = "<group>"; };
0BBD021F212EB69D00CCB19F /* Types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Types.h; sourceTree = "<group>"; };
0BD6B4361EF82A6B00D1F4CD /* WebRTC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebRTC.framework; path = "../../node_modules/react-native-webrtc/ios/WebRTC.framework"; sourceTree = "<group>"; };
0BEA5C251F7B8F73000D0AB4 /* JitsiMeetCompanion.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JitsiMeetCompanion.app; sourceTree = BUILT_PRODUCTS_DIR; };
0BEA5C281F7B8F73000D0AB4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Interface.storyboard; sourceTree = "<group>"; };
0BEA5C2A1F7B8F73000D0AB4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
0BEA5C2C1F7B8F73000D0AB4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0BEA5C311F7B8F73000D0AB4 /* JitsiMeetCompanion Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "JitsiMeetCompanion Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
0BEA5C361F7B8F73000D0AB4 /* InterfaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceController.swift; sourceTree = "<group>"; };
0BEA5C381F7B8F73000D0AB4 /* ExtensionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionDelegate.swift; sourceTree = "<group>"; };
0BEA5C3A1F7B8F73000D0AB4 /* ComplicationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplicationController.swift; sourceTree = "<group>"; };
0BEA5C3C1F7B8F73000D0AB4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
0BEA5C3E1F7B8F73000D0AB4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* jitsi-meet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "jitsi-meet.app"; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
@@ -56,9 +119,18 @@
B3B083EB1D4955FF0069CEE7 /* app.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = app.entitlements; 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>"; };
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>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
0BEA5C2E1F7B8F73000D0AB4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -69,6 +141,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
1F021A8A5B056078665DE530 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -82,6 +161,34 @@
name = Frameworks;
sourceTree = "<group>";
};
0BEA5C261F7B8F73000D0AB4 /* Watch app */ = {
isa = PBXGroup;
children = (
0BEA5C271F7B8F73000D0AB4 /* Interface.storyboard */,
0BEA5C2A1F7B8F73000D0AB4 /* Assets.xcassets */,
0BEA5C2C1F7B8F73000D0AB4 /* Info.plist */,
);
name = "Watch app";
path = watchos/app;
sourceTree = "<group>";
};
0BEA5C351F7B8F73000D0AB4 /* WatchKit extension */ = {
isa = PBXGroup;
children = (
0BEA5C361F7B8F73000D0AB4 /* InterfaceController.swift */,
0BEA5C381F7B8F73000D0AB4 /* ExtensionDelegate.swift */,
0BEA5C3A1F7B8F73000D0AB4 /* ComplicationController.swift */,
0BEA5C3C1F7B8F73000D0AB4 /* Assets.xcassets */,
0BEA5C3E1F7B8F73000D0AB4 /* Info.plist */,
0B70016F1F7C51CC005944F4 /* InCallController.swift */,
0B5418461F7C5D8C00A2DD86 /* MeetingRowController.swift */,
E58801132278944E008B0561 /* JitsiMeetContext.swift */,
E5C97B62227A1EB400199214 /* JitsiMeetCommands.swift */,
);
name = "WatchKit extension";
path = watchos/extension;
sourceTree = "<group>";
};
13B07FAE1A68108700A75B9A /* src */ = {
isa = PBXGroup;
children = (
@@ -118,6 +225,8 @@
83CBBA001A601CBA00E9B192 /* Products */,
13B07FAE1A68108700A75B9A /* src */,
5E96ADD5E49F3B3822EF9A52 /* Pods */,
0BEA5C261F7B8F73000D0AB4 /* Watch app */,
0BEA5C351F7B8F73000D0AB4 /* WatchKit extension */,
);
indentWidth = 2;
sourceTree = "<group>";
@@ -127,6 +236,8 @@
isa = PBXGroup;
children = (
13B07F961A680F5B00A75B9A /* jitsi-meet.app */,
0BEA5C251F7B8F73000D0AB4 /* JitsiMeetCompanion.app */,
0BEA5C311F7B8F73000D0AB4 /* JitsiMeetCompanion Extension.appex */,
);
name = Products;
sourceTree = "<group>";
@@ -134,6 +245,41 @@
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
0BEA5C241F7B8F73000D0AB4 /* JitsiMeetCompanion */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0BEA5C481F7B8F73000D0AB4 /* Build configuration list for PBXNativeTarget "JitsiMeetCompanion" */;
buildPhases = (
0BEA5C231F7B8F73000D0AB4 /* Resources */,
0BEA5C471F7B8F73000D0AB4 /* Embed App Extensions */,
1F021A8A5B056078665DE530 /* Frameworks */,
);
buildRules = (
);
dependencies = (
0BEA5C341F7B8F73000D0AB4 /* PBXTargetDependency */,
);
name = JitsiMeetCompanion;
productName = JitsiMeetCompanion;
productReference = 0BEA5C251F7B8F73000D0AB4 /* JitsiMeetCompanion.app */;
productType = "com.apple.product-type.application.watchapp2";
};
0BEA5C301F7B8F73000D0AB4 /* JitsiMeetCompanion Extension */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0BEA5C461F7B8F73000D0AB4 /* Build configuration list for PBXNativeTarget "JitsiMeetCompanion Extension" */;
buildPhases = (
0BEA5C2D1F7B8F73000D0AB4 /* Sources */,
0BEA5C2E1F7B8F73000D0AB4 /* Frameworks */,
0BEA5C2F1F7B8F73000D0AB4 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "JitsiMeetCompanion Extension";
productName = "JitsiMeetCompanion Extension";
productReference = 0BEA5C311F7B8F73000D0AB4 /* JitsiMeetCompanion Extension.appex */;
productType = "com.apple.product-type.watchkit2-extension";
};
13B07F861A680F5B00A75B9A /* jitsi-meet */ = {
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "jitsi-meet" */;
@@ -150,10 +296,12 @@
DEC2069321CBBD6900072F03 /* Setup Fabric */,
DE11877A21EE09640078D059 /* Setup Google reverse URL handler */,
DE4F6D6E22005C0400DE699E /* Setup Dropbox */,
0BEA5C491F7B8F73000D0AB4 /* Embed Watch Content */,
);
buildRules = (
);
dependencies = (
0BEA5C401F7B8F73000D0AB4 /* PBXTargetDependency */,
);
name = "jitsi-meet";
productName = "Jitsi Meet";
@@ -169,6 +317,16 @@
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = Facebook;
TargetAttributes = {
0BEA5C241F7B8F73000D0AB4 = {
CreatedOnToolsVersion = 9.0;
DevelopmentTeam = FC967L3QRG;
ProvisioningStyle = Automatic;
};
0BEA5C301F7B8F73000D0AB4 = {
CreatedOnToolsVersion = 9.0;
DevelopmentTeam = FC967L3QRG;
ProvisioningStyle = Automatic;
};
13B07F861A680F5B00A75B9A = {
DevelopmentTeam = FC967L3QRG;
ProvisioningStyle = Automatic;
@@ -197,11 +355,30 @@
projectRoot = "";
targets = (
13B07F861A680F5B00A75B9A /* jitsi-meet */,
0BEA5C241F7B8F73000D0AB4 /* JitsiMeetCompanion */,
0BEA5C301F7B8F73000D0AB4 /* JitsiMeetCompanion Extension */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
0BEA5C231F7B8F73000D0AB4 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0BEA5C2B1F7B8F73000D0AB4 /* Assets.xcassets in Resources */,
0BEA5C291F7B8F73000D0AB4 /* Interface.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
0BEA5C2F1F7B8F73000D0AB4 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0BEA5C3D1F7B8F73000D0AB4 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F8E1A680F5B00A75B9A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -354,6 +531,20 @@
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
0BEA5C2D1F7B8F73000D0AB4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0B7001701F7C51CC005944F4 /* InCallController.swift in Sources */,
E5C97B63227A1EB400199214 /* JitsiMeetCommands.swift in Sources */,
0B5418471F7C5D8C00A2DD86 /* MeetingRowController.swift in Sources */,
E588011722789D43008B0561 /* JitsiMeetContext.swift in Sources */,
0BEA5C391F7B8F73000D0AB4 /* ExtensionDelegate.swift in Sources */,
0BEA5C371F7B8F73000D0AB4 /* InterfaceController.swift in Sources */,
0BEA5C3B1F7B8F73000D0AB4 /* ComplicationController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F871A680F5B00A75B9A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -367,7 +558,28 @@
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
0BEA5C341F7B8F73000D0AB4 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 0BEA5C301F7B8F73000D0AB4 /* JitsiMeetCompanion Extension */;
targetProxy = 0BEA5C331F7B8F73000D0AB4 /* PBXContainerItemProxy */;
};
0BEA5C401F7B8F73000D0AB4 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 0BEA5C241F7B8F73000D0AB4 /* JitsiMeetCompanion */;
targetProxy = 0BEA5C3F1F7B8F73000D0AB4 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
0BEA5C271F7B8F73000D0AB4 /* Interface.storyboard */ = {
isa = PBXVariantGroup;
children = (
0BEA5C281F7B8F73000D0AB4 /* Base */,
);
name = Interface.storyboard;
sourceTree = "<group>";
};
13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
@@ -379,6 +591,140 @@
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
0BEA5C421F7B8F73000D0AB4 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = FC967L3QRG;
GCC_C_LANGUAGE_STANDARD = gnu11;
IBSC_MODULE = JitsiMeetCompanion_Extension;
INFOPLIST_FILE = watchos/app/Info.plist;
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet.watchkit;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 4.0;
};
name = Debug;
};
0BEA5C431F7B8F73000D0AB4 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = FC967L3QRG;
GCC_C_LANGUAGE_STANDARD = gnu11;
IBSC_MODULE = JitsiMeetCompanion_Extension;
INFOPLIST_FILE = watchos/app/Info.plist;
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet.watchkit;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 4.0;
};
name = Release;
};
0BEA5C441F7B8F73000D0AB4 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = FC967L3QRG;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = watchos/extension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet.watchkit.extension;
PRODUCT_NAME = "${TARGET_NAME}";
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 4.0;
};
name = Debug;
};
0BEA5C451F7B8F73000D0AB4 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = FC967L3QRG;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = watchos/extension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet.watchkit.extension;
PRODUCT_NAME = "${TARGET_NAME}";
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 4.0;
};
name = Release;
};
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 4670A512A688E2DC34528282 /* Pods-jitsi-meet.debug.xcconfig */;
@@ -391,7 +737,7 @@
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = FC967L3QRG;
ENABLE_BITCODE = NO;
ENABLE_BITCODE = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"../../node_modules/react-native-webrtc/ios",
@@ -427,7 +773,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = FC967L3QRG;
ENABLE_BITCODE = NO;
ENABLE_BITCODE = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"../../node_modules/react-native-webrtc/ios",
@@ -482,7 +828,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_BITCODE = NO;
ENABLE_BITCODE = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
@@ -504,7 +850,7 @@
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
);
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -541,7 +887,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_BITCODE = NO;
ENABLE_BITCODE = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
@@ -556,9 +902,10 @@
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
);
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
VALIDATE_PRODUCT = YES;
};
name = Release;
@@ -566,6 +913,24 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
0BEA5C461F7B8F73000D0AB4 /* Build configuration list for PBXNativeTarget "JitsiMeetCompanion Extension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0BEA5C441F7B8F73000D0AB4 /* Debug */,
0BEA5C451F7B8F73000D0AB4 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0BEA5C481F7B8F73000D0AB4 /* Build configuration list for PBXNativeTarget "JitsiMeetCompanion" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0BEA5C421F7B8F73000D0AB4 /* Debug */,
0BEA5C431F7B8F73000D0AB4 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "jitsi-meet" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View File

@@ -41,7 +41,7 @@
jitsiMeet.conferenceActivityType = JitsiMeetConferenceActivityType;
jitsiMeet.customUrlScheme = @"org.jitsi.meet";
jitsiMeet.universalLinkDomains = @[@"meet.jit.si", @"beta.meet.jit.si"];
jitsiMeet.universalLinkDomains = @[@"meet.jit.si", @"alpha.jitsi.net", @"beta.meet.jit.si"];
jitsiMeet.defaultConferenceOptions = [JitsiMeetConferenceOptions fromBuilder:^(JitsiMeetConferenceOptionsBuilder *builder) {
builder.serverURL = [NSURL URLWithString:@"https://meet.jit.si"];
@@ -67,9 +67,9 @@
= [[FIRDynamicLinks dynamicLinks]
handleUniversalLink:userActivity.webpageURL
completion:^(FIRDynamicLink * _Nullable dynamicLink, NSError * _Nullable error) {
NSURL *dynamicLinkURL = dynamicLink.url;
if (dynamicLinkURL) {
userActivity.webpageURL = dynamicLinkURL;
NSURL *firebaseUrl = [FIRUtilities extractURL:dynamicLink];
if (firebaseUrl != nil) {
userActivity.webpageURL = firebaseUrl;
[[JitsiMeet sharedInstance] application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
@@ -91,19 +91,20 @@
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
// This shows up during a reload in development, skip it.
// https://github.com/firebase/firebase-ios-sdk/issues/233
if ([[url absoluteString] containsString:@"google/link/?dismiss=1&is_weak_match=1"]) {
return NO;
}
NSURL *openUrl = url;
if ([FIRUtilities appContainsRealServiceInfoPlist]) {
// Process Firebase Dynamic Links
FIRDynamicLink *dynamicLink = [[FIRDynamicLinks dynamicLinks] dynamicLinkFromCustomSchemeURL:url];
if (dynamicLink != nil) {
NSURL *dynamicLinkURL = dynamicLink.url;
if (dynamicLinkURL != nil
&& (dynamicLink.matchType == FIRDLMatchTypeUnique
|| dynamicLink.matchType == FIRDLMatchTypeDefault)) {
// Strong match, process it.
openUrl = dynamicLinkURL;
}
NSURL *firebaseUrl = [FIRUtilities extractURL:dynamicLink];
if (firebaseUrl != nil) {
openUrl = firebaseUrl;
}
}

View File

@@ -16,8 +16,12 @@
#import <Foundation/Foundation.h>
@import Firebase;
@interface FIRUtilities : NSObject
+ (BOOL)appContainsRealServiceInfoPlist;
+ (NSURL *_Nullable)extractURL: (FIRDynamicLink* _Nullable)dynamicLink;
@end

View File

@@ -61,4 +61,19 @@ NSString *const kGoogleAppIDPlistKey = @"GOOGLE_APP_ID";
return YES;
}
+ (NSURL *)extractURL: (FIRDynamicLink*)dynamicLink {
NSURL *url = nil;
if (dynamicLink != nil) {
NSURL *dynamicLinkURL = dynamicLink.url;
if (dynamicLinkURL != nil
&& (dynamicLink.matchType == FIRDLMatchTypeUnique
|| dynamicLink.matchType == FIRDLMatchTypeDefault)) {
// Strong match, process it.
url = dynamicLinkURL;
}
}
return url;
}
@end

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "CallKit@1x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "CallKit@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "CallKit@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@@ -0,0 +1,92 @@
{
"images" : [
{
"size" : "24x24",
"idiom" : "watch",
"filename" : "Icon-24@2x.png",
"scale" : "2x",
"role" : "notificationCenter",
"subtype" : "38mm"
},
{
"size" : "27.5x27.5",
"idiom" : "watch",
"filename" : "Icon-27.5@2x.png",
"scale" : "2x",
"role" : "notificationCenter",
"subtype" : "42mm"
},
{
"size" : "29x29",
"idiom" : "watch",
"filename" : "Icon-29@2x.png",
"role" : "companionSettings",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "watch",
"filename" : "Icon-29@3x.png",
"role" : "companionSettings",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "watch",
"filename" : "Icon-40@2x.png",
"scale" : "2x",
"role" : "appLauncher",
"subtype" : "38mm"
},
{
"size" : "44x44",
"idiom" : "watch",
"filename" : "Icon-88@2x.png",
"scale" : "2x",
"role" : "appLauncher",
"subtype" : "40mm"
},
{
"size" : "50x50",
"idiom" : "watch",
"filename" : "Icon-100@2x.png",
"scale" : "2x",
"role" : "appLauncher",
"subtype" : "44mm"
},
{
"size" : "86x86",
"idiom" : "watch",
"filename" : "Icon-86@2x.png",
"scale" : "2x",
"role" : "quickLook",
"subtype" : "38mm"
},
{
"size" : "98x98",
"idiom" : "watch",
"filename" : "Icon-98@2x.png",
"scale" : "2x",
"role" : "quickLook",
"subtype" : "42mm"
},
{
"size" : "108x108",
"idiom" : "watch",
"filename" : "Icon-216@2x.png",
"scale" : "2x",
"role" : "quickLook",
"subtype" : "44mm"
},
{
"size" : "1024x1024",
"idiom" : "watch-marketing",
"filename" : "Icon-1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "hangup@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "mute-off@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "mute-on@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="14490.70" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="AgC-eL-Hgc">
<device id="watch38" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="watchOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="14490.21"/>
</dependencies>
<scenes>
<!--Meetings-->
<scene sceneID="aou-V4-d1y">
<objects>
<controller title="Meetings" id="AgC-eL-Hgc" customClass="InterfaceController" customModule="JitsiMeetCompanion" customModuleProvider="target">
<items>
<table alignment="left" id="gpO-ql-Xsr">
<items>
<tableRow identifier="MeetingRowType" id="GGl-av-xeJ" customClass="MeetingRowController" customModule="JitsiMeetCompanion_Extension">
<group key="rootItem" width="1" height="0.0" alignment="left" layout="vertical" id="5XE-gq-qzG">
<items>
<label alignment="left" text="Label" id="Sij-up-N4p"/>
<label alignment="left" text="Label" id="V5K-sm-jEH">
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="font" style="UICTFontTextStyleFootnote"/>
</label>
</items>
<connections>
<segue destination="9RD-qP-1Z0" kind="push" id="Boa-6E-eZs"/>
</connections>
</group>
<connections>
<outlet property="roomLabel" destination="Sij-up-N4p" id="PdS-SO-ylc"/>
<outlet property="rowGroup" destination="5XE-gq-qzG" id="GZN-2c-2Gz"/>
<outlet property="timeLabel" destination="V5K-sm-jEH" id="fWQ-kx-vE4"/>
</connections>
</tableRow>
</items>
</table>
</items>
<connections>
<outlet property="table" destination="gpO-ql-Xsr" id="aVV-iZ-z3l"/>
</connections>
</controller>
</objects>
<point key="canvasLocation" x="-99" y="117"/>
</scene>
<!--Meetings-->
<scene sceneID="ns4-Kh-qqU">
<objects>
<controller identifier="InCallController" title="Meetings" hidesWhenLoading="NO" id="9RD-qP-1Z0" customClass="InCallController" customModule="JitsiMeetCompanion" customModuleProvider="target">
<items>
<label alignment="center" text="Label" id="vFt-lL-SNY"/>
<timer alignment="center" textAlignment="center" previewedSeconds="0" id="W8S-uZ-MPm">
<color key="textColor" red="0.024725984125768763" green="1" blue="0.24241188365329402" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="font" style="UICTFontTextStyleHeadline"/>
</timer>
<group alignment="center" verticalAlignment="bottom" spacing="10" id="Hfk-a0-uWj">
<items>
<button width="60" height="60" alignment="left" verticalAlignment="bottom" backgroundImage="hangup" id="8jF-SI-UHz">
<connections>
<action selector="hangupClicked" destination="9RD-qP-1Z0" id="cXK-lw-tsd"/>
</connections>
</button>
<button width="60" height="60" alignment="right" verticalAlignment="bottom" backgroundImage="mute-off" id="LmN-FI-aQq">
<connections>
<action selector="muteClicked" destination="9RD-qP-1Z0" id="dJg-kV-cqH"/>
</connections>
</button>
</items>
</group>
</items>
<connections>
<outlet property="mutedButton" destination="LmN-FI-aQq" id="gfi-4T-gdN"/>
<outlet property="roomLabel" destination="vFt-lL-SNY" id="cYB-Tf-Efz"/>
<outlet property="timer" destination="W8S-uZ-MPm" id="r7T-j1-9VJ"/>
</connections>
</controller>
</objects>
<point key="canvasLocation" x="213" y="117"/>
</scene>
</scenes>
</document>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Jitsi Meet</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>19.2.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>WKCompanionAppBundleIdentifier</key>
<string>org.jitsi.meet</string>
<key>WKWatchKitApp</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "jitsi@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,81 @@
/*
* Copyright @ 2018-present 8x8, Inc.
* Copyright @ 2017-2018 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ClockKit
class ComplicationController: NSObject, CLKComplicationDataSource {
// MARK: - Timeline Configuration
func getSupportedTimeTravelDirections(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimeTravelDirections) -> Void) {
handler([])
}
func getPrivacyBehavior(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationPrivacyBehavior) -> Void) {
handler(.showOnLockScreen)
}
// MARK: - Timeline Population
func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void) {
// Call the handler with the current timeline entry
getLocalizableSampleTemplate(for: complication) {template in
guard let template = template else {
handler(nil)
return
}
handler(CLKComplicationTimelineEntry(date: Date(), complicationTemplate: template))
}
}
func getTimelineEntries(for complication: CLKComplication, before date: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
// Call the handler with the timeline entries prior to the given date
handler(nil)
}
func getTimelineEntries(for complication: CLKComplication, after date: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
// Call the handler with the timeline entries after to the given date
handler(nil)
}
// MARK: - Placeholder Templates
func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
// This method will be called once per supported complication, and the results will be cached
let imageProvider = CLKImageProvider(onePieceImage: UIImage(named: "jitsi")!)
if complication.family == .circularSmall {
let small = CLKComplicationTemplateCircularSmallRingImage()
small.imageProvider = imageProvider
small.ringStyle = .closed
small.fillFraction = 0
handler(small)
} else if complication.family == .utilitarianSmall {
let utilitarian = CLKComplicationTemplateUtilitarianSmallSquare()
utilitarian.imageProvider = imageProvider
handler(utilitarian)
} else if complication.family == .modularSmall {
let modular = CLKComplicationTemplateModularSmallRingImage()
modular.imageProvider = imageProvider
modular.ringStyle = .closed
modular.fillFraction = 0
handler(modular)
}
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright @ 2018-present 8x8, Inc.
* Copyright @ 2017-2018 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import WatchConnectivity
import WatchKit
class ExtensionDelegate: NSObject, WCSessionDelegate, WKExtensionDelegate {
var currentContext : JitsiMeetContext = JitsiMeetContext()
static var currentJitsiMeetContext: JitsiMeetContext {
get {
return (WKExtension.shared().delegate as! ExtensionDelegate).currentContext
}
}
func applicationDidFinishLaunching() {
// Start Watch Connectivity
if WCSession.isSupported() {
let session = WCSession.default
session.delegate = self
session.activate()
}
}
func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
// Sent when the system needs to launch the application in the background to process tasks. Tasks arrive in a set, so loop through and process each one.
for task in backgroundTasks {
// Use a switch statement to check the task type
switch task {
case let backgroundTask as WKApplicationRefreshBackgroundTask:
// Be sure to complete the background task once youre done.
backgroundTask.setTaskCompletedWithSnapshot(false)
case let snapshotTask as WKSnapshotRefreshBackgroundTask:
// Snapshot tasks have a unique completion call, make sure to set your expiration date
snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil)
case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask:
// Be sure to complete the connectivity task once youre done.
connectivityTask.setTaskCompletedWithSnapshot(false)
case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
// Be sure to complete the URL session task once youre done.
urlSessionTask.setTaskCompletedWithSnapshot(false)
default:
// make sure to complete unhandled task types
task.setTaskCompletedWithSnapshot(false)
}
}
}
func session(_ session: WCSession, activationDidCompleteWith
activationState: WCSessionActivationState, error: Error?) {
if let error = error {
print("WATCH Session activation failed with error: \(error.localizedDescription)")
return
}
print("WATCH Session activated with state: \(activationState.rawValue)")
}
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
DispatchQueue.main.async {
let newContext = JitsiMeetContext(context: applicationContext)
print("WATCH got new context: \(newContext.description)");
// Update context on the root controller which displays the recent list
let controller = WKExtension.shared().rootInterfaceController as! InterfaceController
controller.updateUI(newContext)
// If the current controller is not the in-call controller and we have a
// conference URL, show the in-call controller
if let currentController = WKExtension.shared().visibleInterfaceController as? InterfaceController {
// Go to the in-call controller only if the conference URL has changed, because the user may have
// clicked the back button
if newContext.conferenceURL != nil
&& self.currentContext.conferenceURL != newContext.conferenceURL {
currentController.pushController(withName: "InCallController", context: newContext)
}
} else if let inCallController = WKExtension.shared().visibleInterfaceController as? InCallController {
if newContext.conferenceURL == nil {
inCallController.popToRootController()
} else {
inCallController.updateUI(newContext)
}
}
self.currentContext = newContext;
}
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright @ 2018-present 8x8, Inc.
* Copyright @ 2017-2018 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import WatchConnectivity
import WatchKit
import Foundation
class InCallController: WKInterfaceController {
@IBOutlet var mutedButton: WKInterfaceButton!
@IBOutlet var roomLabel: WKInterfaceLabel!
@IBOutlet var timer: WKInterfaceTimer!
@IBAction func hangupClicked() {
sendCommand(JitsiMeetCommands.CMD_HANG_UP, message: nil)
}
@IBAction func muteClicked() {
if var micMuted = ExtensionDelegate.currentJitsiMeetContext.micMuted {
micMuted = !micMuted;
sendCommand(
JitsiMeetCommands.CMD_SET_MUTED,
message: [
"muted": micMuted ? "true" : "false"
])
updateMutedButton(withMuted: micMuted)
}
}
func sendCommand(_ command: JitsiMeetCommands, message: [String : Any]?) {
if WCSession.isSupported() {
let session = WCSession.default
var data = [String: Any]()
if let sessionID = ExtensionDelegate.currentJitsiMeetContext.sessionID {
if message != nil {
message!.forEach { data[$0] = $1 }
}
data["command"] = command.rawValue;
data["sessionID"] = sessionID;
session.sendMessage(data, replyHandler: nil, errorHandler: nil)
}
}
}
func updateUI(_ newContext: JitsiMeetContext) {
var conferenceURL = newContext.conferenceURL
if let joinConferenceURL = newContext.joinConferenceURL {
sendCommand(JitsiMeetCommands.CMD_JOIN_CONFERENCE, message: [ "data" : joinConferenceURL ])
conferenceURL = joinConferenceURL
}
let newRoomName = conferenceURL != nil ? conferenceURL!.components(separatedBy: "/").last : ""
roomLabel.setText(newRoomName)
if let newTimestamp = newContext.conferenceTimestamp {
restartTimer(newTimestamp)
}
if let newMuted = newContext.micMuted {
updateMutedButton(withMuted: newMuted)
}
}
func restartTimer(_ conferenceTimestamp: Int64) {
if (conferenceTimestamp != 0) {
let newDate = Date(timeIntervalSince1970: TimeInterval(conferenceTimestamp / 1000))
timer.setDate(newDate)
timer.start();
print("WATCH timer set date to: \(newDate) and start")
} else {
print("WATCH timer stop")
timer.stop();
}
}
func updateMutedButton(withMuted isMuted: Bool) {
if isMuted {
mutedButton.setBackgroundImageNamed("mute-on.png")
} else {
mutedButton.setBackgroundImageNamed("mute-off.png")
}
}
override func awake(withContext context: Any?) {
super.awake(withContext: context)
if let data = context as? JitsiMeetContext {
updateUI(data)
}
}
}

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Jitsi Meet Companion Extension</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>19.2.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CLKComplicationPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).ComplicationController</string>
<key>CLKComplicationSupportedFamilies</key>
<array>
<string>CLKComplicationFamilyModularSmall</string>
<string>CLKComplicationFamilyUtilitarianSmall</string>
<string>CLKComplicationFamilyCircularSmall</string>
</array>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>WKAppBundleIdentifier</key>
<string>org.jitsi.meet.watchkit</string>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.watchkit</string>
</dict>
<key>WKExtensionDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).ExtensionDelegate</string>
</dict>
</plist>

View File

@@ -0,0 +1,80 @@
/*
* Copyright @ 2018-present 8x8, Inc.
* Copyright @ 2017-2018 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import WatchKit
import Foundation
class InterfaceController: WKInterfaceController {
@IBOutlet var table: WKInterfaceTable!
func updateUI(_ newContext:JitsiMeetContext) {
if let recentURLsArray = newContext.recentURLs {
updateRecents(withRecents: recentURLsArray, currentContext: newContext)
}
}
private func updateRecents(withRecents recents: NSArray, currentContext: JitsiMeetContext) {
// Updating the # of rows only if it actually changed prevents from blinking the UI
if (table.numberOfRows != recents.count) {
table.setNumberOfRows(recents.count, withRowType: "MeetingRowType")
}
for (index, entry) in recents.enumerated() {
let entryDict = entry as! NSDictionary
let roomURL = entryDict["conference"] as! NSString
let timestamp = entryDict["date"] as! NSNumber
// Prepare values
let room = roomURL.components(separatedBy: "/").last
let date = Date(timeIntervalSince1970: timestamp.doubleValue / 1000) // timestamp is taken with Date.now() in JS, which uses milliseconds
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone.current
dateFormatter.locale = NSLocale.current
dateFormatter.dateFormat = "HH:mm yyyy-MM-dd"
let strDate = dateFormatter.string(from: date)
// Update row controller
let controller = table.rowController(at: index) as! MeetingRowController
controller.room = room
controller.roomUrl = roomURL as String
controller.roomLabel.setText(room)
controller.timeLabel.setText(strDate)
// Change the background for the active meeting
if (controller.roomUrl == currentContext.conferenceURL) {
controller.rowGroup.setBackgroundColor(UIColor(red: 0.125, green: 0.58, blue: 0.98, alpha: 1))
} else {
controller.rowGroup.setBackgroundColor(UIColor(red: 0.949, green: 0.956, blue: 1, alpha: 0.14))
}
}
}
override func contextForSegue(withIdentifier segueIdentifier: String, in table: WKInterfaceTable, rowIndex: Int) -> Any? {
let controller = table.rowController(at: rowIndex) as! MeetingRowController
let currentContext = ExtensionDelegate.currentJitsiMeetContext
// Copy the current context and add the joinConferenceURL to trigger the command when the in-call screen is displayed
let actionContext = JitsiMeetContext(jmContext: currentContext)
actionContext.joinConferenceURL = controller.roomUrl
print("WATCH contextForSegue: \(actionContext.description)");
return actionContext;
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright @ 2018-present 8x8, Inc.
* Copyright @ 2017-2018 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// This needs to be in sync with features/mobile/watchos/constants.js
enum JitsiMeetCommands : String {
typealias RawValue = String
case CMD_HANG_UP = "hangup";
case CMD_JOIN_CONFERENCE = "joinConference";
case CMD_SET_MUTED = "setMuted";
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright @ 2018-present 8x8, Inc.
* Copyright @ 2017-2018 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Foundation
class JitsiMeetContext {
private var dictionary : [String : Any]
var joinConferenceURL : String? = nil;
init() {
dictionary = [:]
}
init(context: [String : Any]) {
dictionary = context
}
init(jmContext: JitsiMeetContext) {
dictionary = jmContext.dictionary
joinConferenceURL = jmContext.joinConferenceURL
}
var conferenceURL : String? {
get {
return dictionary["conferenceURL"] as? String
}
}
var conferenceTimestamp : Int64? {
get {
return dictionary["conferenceTimestamp"] as? Int64;
}
}
var sessionID : Int64? {
get {
return dictionary["sessionID"] as? Int64;
}
}
var recentURLs : NSArray? {
get {
return dictionary["recentURLs"] as? NSArray
}
}
var micMuted : Bool? {
get {
return (dictionary["micMuted"] as? NSNumber)?.boolValue ?? nil;
}
}
public var description: String {
return "JitsiMeetContext[conferenceURL: \(String(describing: conferenceURL)), conferenceTimestamp: \(String(describing:conferenceTimestamp)), sessionID: \(String(describing:sessionID)), recentURLs: \(String(describing:recentURLs)), joinConferenceURL: \(String(describing:joinConferenceURL)) "
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright @ 2018-present 8x8, Inc.
* Copyright @ 2017-2018 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import WatchKit
class MeetingRowController: NSObject {
@IBOutlet var roomLabel: WKInterfaceLabel!
@IBOutlet var timeLabel: WKInterfaceLabel!
@IBOutlet var rowGroup: WKInterfaceGroup!
var room: String!
var roomUrl: String!
}

View File

@@ -16,6 +16,36 @@ platform :ios do
app_identifier: "com.atlassian.JitsiMeet.ios"
)
# Set the (watch) app identifier
update_app_identifier(
xcodeproj: "app/app.xcodeproj",
plist_path: "watchos/app/Info.plist",
app_identifier: "com.atlassian.JitsiMeet.ios.watchkit"
)
# Set the (watch) extension identifier
update_app_identifier(
xcodeproj: "app/app.xcodeproj",
plist_path: "watchos/extension/Info.plist",
app_identifier: "com.atlassian.JitsiMeet.ios.watchkit.extension"
)
update_info_plist(
xcodeproj: "app/app.xcodeproj",
plist_path: "watchos/app/Info.plist",
block: proc do |plist|
plist["WKCompanionAppBundleIdentifier"] = "com.atlassian.JitsiMeet.ios"
end
)
update_info_plist(
xcodeproj: "app/app.xcodeproj",
plist_path: "watchos/extension/Info.plist",
block: proc do |plist|
plist["NSExtension"]["NSExtensionAttributes"]["WKAppBundleIdentifier"] = "com.atlassian.JitsiMeet.ios.watchkit"
end
)
# Inrement the build number by 1
increment_build_number(
build_number: latest_testflight_build_number + 1,
@@ -25,7 +55,7 @@ platform :ios do
# Actually build the app
build_app(
scheme: "jitsi-meet",
include_bitcode: false,
include_bitcode: true,
include_symbols: true,
export_xcargs: "-allowProvisioningUpdates"
)

View File

@@ -518,7 +518,7 @@
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_BITCODE = NO;
ENABLE_BITCODE = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
@@ -580,7 +580,7 @@
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_BITCODE = NO;
ENABLE_BITCODE = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
@@ -615,7 +615,7 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_BITCODE = NO;
ENABLE_BITCODE = YES;
INFOPLIST_FILE = src/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
@@ -643,7 +643,7 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_BITCODE = NO;
ENABLE_BITCODE = YES;
INFOPLIST_FILE = src/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";

View File

@@ -206,14 +206,20 @@ RCT_EXPORT_METHOD(updateCall:(NSString *)callUUID
// iconTemplateImageData
NSString *iconTemplateImageName = dictionary[@"iconTemplateImageName"];
NSData *iconTemplateImageData;
UIImage *iconTemplateImage;
if (iconTemplateImageName) {
UIImage *iconTemplateImage
= [UIImage imageNamed:iconTemplateImageName
inBundle:[NSBundle bundleForClass:self.class]
compatibleWithTraitCollection:nil];
// First try to load the resource from the main bundle.
iconTemplateImage = [UIImage imageNamed:iconTemplateImageName];
// If that didn't work, use the one built-in.
if (!iconTemplateImage) {
iconTemplateImage = [UIImage imageNamed:iconTemplateImageName
inBundle:[NSBundle bundleForClass:self.class]
compatibleWithTraitCollection:nil];
}
if (iconTemplateImage) {
iconTemplateImageData
= UIImagePNGRepresentation(iconTemplateImage);
iconTemplateImageData = UIImagePNGRepresentation(iconTemplateImage);
}
}

View File

@@ -20,59 +20,35 @@ import Foundation
internal final class JMCallKitEmitter: NSObject, CXProviderDelegate {
private var listeners = Set<JMCallKitEventListenerWrapper>()
private var pendingMuteActions = Set<UUID>()
private let listeners = NSMutableArray()
internal override init() {}
// MARK: - Add/remove listeners
func addListener(_ listener: JMCallKitListener) {
let wrapper = JMCallKitEventListenerWrapper(listener: listener)
listeners.insert(wrapper)
}
func removeListener(_ listener: JMCallKitListener) {
// XXX Constructing a new JMCallKitEventListenerWrapper instance in
// order to remove the specified listener from listeners is (1) a bit
// funny (though may make a statement about performance) and (2) not
// really an option because the specified listener may already be
// executing its dealloc (like RNCallKit).
listeners.forEach {
// 1. JMCallKitEventListenerWrapper weakly references
// JMCallKitListener so it may be nice to clean
// JMCallKitEventListenerWrapperinstances up if they've lost
// their associated JMCallKitListener instances (e.g. for
// example, because whoever did addListener forgot to
// removeListener). Unfortunately, I don't know how to do it
// because JMCallKitEventListenerWrapper is a struct.
//
// 2. XXX JMCallKitEventListenerWrapper implements the weird
// equality by JMCallKitListener hash which (1) I don't
// understand and (2) I don't know how to invoke without
// duplicating.
if ($0.hashValue == listener.hash) {
listeners.remove($0)
}
if (!listeners.contains(listener)) {
listeners.add(listener)
}
}
// MARK: - Add mute action
func addMuteAction(_ actionUUID: UUID) {
pendingMuteActions.insert(actionUUID)
func removeListener(_ listener: JMCallKitListener) {
listeners.remove(listener)
}
// MARK: - CXProviderDelegate
func providerDidReset(_ provider: CXProvider) {
listeners.forEach { $0.listener?.providerDidReset?() }
pendingMuteActions.removeAll()
listeners.forEach {
let listener = $0 as! JMCallKitListener
listener.providerDidReset?()
}
}
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
listeners.forEach {
$0.listener?.performAnswerCall?(UUID: action.callUUID)
let listener = $0 as! JMCallKitListener
listener.performAnswerCall?(UUID: action.callUUID)
}
action.fulfill()
@@ -80,24 +56,17 @@ internal final class JMCallKitEmitter: NSObject, CXProviderDelegate {
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
listeners.forEach {
$0.listener?.performEndCall?(UUID: action.callUUID)
let listener = $0 as! JMCallKitListener
listener.performEndCall?(UUID: action.callUUID)
}
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {
let uuid = pendingMuteActions.remove(action.uuid)
// XXX avoid mute actions ping-pong: if the mute action was caused by
// the JS side (we requested a transaction) don't call the delegate
// method. If it was called by the provder itself (when the user presses
// the mute button in the CallKit view) then call the delegate method.
if (uuid == nil) {
listeners.forEach {
$0.listener?.performSetMutedCall?(UUID: action.callUUID,
isMuted: action.isMuted)
}
listeners.forEach {
let listener = $0 as! JMCallKitListener
listener.performSetMutedCall?(UUID: action.callUUID, isMuted: action.isMuted)
}
action.fulfill()
@@ -105,8 +74,8 @@ internal final class JMCallKitEmitter: NSObject, CXProviderDelegate {
func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
listeners.forEach {
$0.listener?.performStartCall?(UUID: action.callUUID,
isVideo: action.isVideo)
let listener = $0 as! JMCallKitListener
listener.performStartCall?(UUID: action.callUUID, isVideo: action.isVideo)
}
action.fulfill()
@@ -115,35 +84,16 @@ internal final class JMCallKitEmitter: NSObject, CXProviderDelegate {
func provider(_ provider: CXProvider,
didActivate audioSession: AVAudioSession) {
listeners.forEach {
$0.listener?.providerDidActivateAudioSession?(session: audioSession)
let listener = $0 as! JMCallKitListener
listener.providerDidActivateAudioSession?(session: audioSession)
}
}
func provider(_ provider: CXProvider,
didDeactivate audioSession: AVAudioSession) {
listeners.forEach {
$0.listener?.providerDidDeactivateAudioSession?(
session: audioSession)
let listener = $0 as! JMCallKitListener
listener.providerDidDeactivateAudioSession?(session: audioSession)
}
}
}
fileprivate struct JMCallKitEventListenerWrapper: Hashable {
internal weak var listener: JMCallKitListener?
public init(listener: JMCallKitListener) {
self.listener = listener
}
public static func ==(lhs: JMCallKitEventListenerWrapper,
rhs: JMCallKitEventListenerWrapper) -> Bool {
// XXX We're aware that "[t]wo instances with equal hash values are not
// necessarily equal to each other."
return lhs.hashValue == rhs.hashValue
}
func hash(into hasher: inout Hasher) {
hasher.combine(self.listener?.hash)
}
}

View File

@@ -27,7 +27,7 @@ import Foundation
// MARK: - CallKit proxy
private static let provider: CXProvider = {
private static var provider: CXProvider = {
let configuration = CXProviderConfiguration(localizedName: "")
return CXProvider(configuration: configuration)
}()
@@ -52,9 +52,13 @@ import Foundation
/// Defaults to enabled, set to false when you don't want to use CallKit.
@objc public static var enabled: Bool = true {
didSet {
if enabled == false {
provider.invalidate()
if enabled {
guard isProviderConfigured() else { return; }
provider = CXProvider(configuration: providerConfiguration!)
provider.setDelegate(emitter, queue: nil)
} else {
provider.setDelegate(nil, queue: nil)
provider.invalidate()
}
}
}
@@ -156,14 +160,6 @@ import Foundation
completion: @escaping (Error?) -> Swift.Void) {
guard enabled else { return }
// XXX keep track of muted actions to avoid "ping-pong"ing. See
// JMCallKitEmitter for details on the CXSetMutedCallAction handling.
for action in transaction.actions {
if (action as? CXSetMutedCallAction) != nil {
emitter.addMuteAction(action.uuid)
}
}
callController.request(transaction, completion: completion)
}
@@ -191,4 +187,3 @@ import Foundation
return update
}
}

View File

@@ -205,7 +205,7 @@
"liveStreamingDisabledForGuestTooltip": "Guests can't start live streaming.",
"liveStreamingDisabledTooltip": "Start live stream disabled.",
"lockMessage": "Failed to lock the conference.",
"lockRoom": "Lock room",
"lockRoom": "Add meeting password",
"lockTitle": "Lock failed",
"logoutQuestion": "Are you sure you want to logout and stop the conference?",
"logoutTitle": "Logout",
@@ -285,7 +285,7 @@
"tokenAuthFailedTitle": "Authentication failed",
"transcribing": "Transcribing",
"unableToSwitch": "Unable to switch video stream.",
"unlockRoom": "Unlock room",
"unlockRoom": "Remove meeting password",
"userPassword": "user password",
"WaitForHostMsg": "The conference <b>__room__</b> has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
"WaitForHostMsgWOk": "The conference <b>__room__</b> has not yet started. If you are the host then please press Ok to authenticate. Otherwise, please wait for the host to arrive.",
@@ -354,9 +354,10 @@
"dialInTollFree": "Toll Free",
"genericError": "Whoops, something went wrong.",
"inviteLiveStream": "To view the live stream of this meeting, click this link: __url__",
"invitePhone": "To join by phone, dial __number__ and enter this PIN: __conferenceID__#",
"invitePhoneAlternatives": "To view more phone numbers, click this link: __url__",
"inviteURL": "To join the video meeting, click this link: __url__",
"invitePhone": "One tap audio Dial In: __number__,,__conferenceID__#",
"invitePhoneAlternatives": "Looking for a different dial in number? Please see: __url__",
"inviteURL": "You are invited to join a meeting.\n__moreInfo__\nJoin meeting: __url__\n",
"inviteURLMoreInfo": "Meeting ID: __conferenceID__#\n",
"liveStreamURL": "Live stream:",
"moreNumbers": "More numbers",
"noNumbers": "No dial-in numbers.",
@@ -475,7 +476,11 @@
"raisedHand": "__name__ would like to speak.",
"somebody": "Somebody",
"suboptimalExperienceDescription": "Eer... we are afraid your experience with __appName__ isn't going to be that great here. We are looking for ways to improve this but, until then, please try using one of the <a href='static/recommendedBrowsers.html' target='_blank'>fully supported browsers</a>.",
"suboptimalExperienceTitle": "Browser Warning"
"suboptimalExperienceTitle": "Browser Warning",
"newDeviceCameraTitle": "New camera detected",
"newDeviceMicTitle": "New microphone detected",
"newDeviceCameraTitle": "New audio output detected",
"newDeviceAction": "Use"
},
"passwordSetRemotely": "set by another member",
"poweredby": "powered by",
@@ -515,6 +520,7 @@
"expandedOn": "The meeting is currently being recorded.",
"expandedPending": "Recording is being started...",
"failedToStart": "Recording failed to start",
"fileSharingdescription": "Share recording with meeting participants",
"live": "LIVE",
"loggedIn": "Logged in as __userName__",
"off": "Recording stopped",
@@ -610,7 +616,7 @@
"invite": "Invite people",
"kick": "Kick participant",
"localRecording": "Toggle local recording controls",
"lockRoom": "Toggle room lock",
"lockRoom": "Toggle meeting password",
"moreActions": "Toggle more actions menu",
"moreActionsMenu": "More actions menu",
"mute": "Toggle mute audio",

View File

@@ -1,546 +0,0 @@
/* global APP */
/*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const logger = require('jitsi-meet-logger').getLogger(__filename);
import {
getPinnedParticipant,
pinParticipant
} from '../react/features/base/participants';
import { setTileView } from '../react/features/video-layout';
import UIEvents from '../service/UI/UIEvents';
import VideoLayout from './UI/videolayout/VideoLayout';
/**
* The (name of the) command which transports the state (represented by
* {State} for the local state at the time of this writing) of a {FollowMe}
* (instance) between participants.
*/
const _COMMAND = 'follow-me';
/**
* The timeout after which a follow-me command that has been received will be
* ignored if not consumed.
*
* @type {number} in seconds
* @private
*/
const _FOLLOW_ME_RECEIVED_TIMEOUT = 30;
/**
* Represents the set of {FollowMe}-related states (properties and their
* respective values) which are to be followed by a participant. {FollowMe}
* will send {_COMMAND} whenever a property of {State} changes (if the local
* participant is in her right to issue such a command, of course).
*/
class State {
/**
* Initializes a new {State} instance.
*
* @param propertyChangeCallback {Function} which is to be called when a
* property of the new instance has its value changed from an old value
* into a (different) new value. The function is supplied with the name of
* the property, the old value of the property before the change, and the
* new value of the property after the change.
*/
constructor(propertyChangeCallback) {
this._propertyChangeCallback = propertyChangeCallback;
}
/**
*
*/
get filmstripVisible() {
return this._filmstripVisible;
}
/**
*
*/
set filmstripVisible(b) {
const oldValue = this._filmstripVisible;
if (oldValue !== b) {
this._filmstripVisible = b;
this._firePropertyChange('filmstripVisible', oldValue, b);
}
}
/**
*
*/
get nextOnStage() {
return this._nextOnStage;
}
/**
*
*/
set nextOnStage(id) {
const oldValue = this._nextOnStage;
if (oldValue !== id) {
this._nextOnStage = id;
this._firePropertyChange('nextOnStage', oldValue, id);
}
}
/**
*
*/
get sharedDocumentVisible() {
return this._sharedDocumentVisible;
}
/**
*
*/
set sharedDocumentVisible(b) {
const oldValue = this._sharedDocumentVisible;
if (oldValue !== b) {
this._sharedDocumentVisible = b;
this._firePropertyChange('sharedDocumentVisible', oldValue, b);
}
}
/**
* A getter for this object instance to know the state of tile view.
*
* @returns {boolean} True if tile view is enabled.
*/
get tileViewEnabled() {
return this._tileViewEnabled;
}
/**
* A setter for {@link tileViewEnabled}. Fires a property change event for
* other participants to follow.
*
* @param {boolean} b - Whether or not tile view is enabled.
* @returns {void}
*/
set tileViewEnabled(b) {
const oldValue = this._tileViewEnabled;
if (oldValue !== b) {
this._tileViewEnabled = b;
this._firePropertyChange('tileViewEnabled', oldValue, b);
}
}
/**
* Invokes {_propertyChangeCallback} to notify it that {property} had its
* value changed from {oldValue} to {newValue}.
*
* @param property the name of the property which had its value changed
* from {oldValue} to {newValue}
* @param oldValue the value of {property} before the change
* @param newValue the value of {property} after the change
*/
_firePropertyChange(property, oldValue, newValue) {
const propertyChangeCallback = this._propertyChangeCallback;
if (propertyChangeCallback) {
propertyChangeCallback(property, oldValue, newValue);
}
}
}
/**
* Represents the &quot;Follow Me&quot; feature which enables a moderator to
* (partially) control the user experience/interface (e.g. filmstrip
* visibility) of (other) non-moderator particiapnts.
*
* @author Lyubomir Marinov
*/
class FollowMe {
/**
* Initializes a new {FollowMe} instance.
*
* @param conference the {conference} which is to transport
* {FollowMe}-related information between participants
* @param UI the {UI} which is the source (model/state) to be sent to
* remote participants if the local participant is the moderator or the
* destination (model/state) to receive from the remote moderator if the
* local participant is not the moderator
*/
constructor(conference, UI) {
this._conference = conference;
this._UI = UI;
this.nextOnStageTimer = 0;
// The states of the local participant which are to be followed (by the
// remote participants when the local participant is in her right to
// issue such commands).
this._local = new State(this._localPropertyChange.bind(this));
// Listen to "Follow Me" commands. I'm not sure whether a moderator can
// (in lib-jitsi-meet and/or Meet) become a non-moderator. If that's
// possible, then it may be easiest to always listen to commands. The
// listener will validate received commands before acting on them.
conference.commands.addCommandListener(
_COMMAND,
this._onFollowMeCommand.bind(this));
}
/**
* Sets the current state of all follow-me properties, which will fire a
* localPropertyChangeEvent and trigger a send of the follow-me command.
* @private
*/
_setFollowMeInitialState() {
this._filmstripToggled.bind(this, this._UI.isFilmstripVisible());
const pinnedId = VideoLayout.getPinnedId();
this._nextOnStage(pinnedId, Boolean(pinnedId));
// check whether shared document is enabled/initialized
if (this._UI.getSharedDocumentManager()) {
this._sharedDocumentToggled
.bind(this, this._UI.getSharedDocumentManager().isVisible());
}
this._tileViewToggled.bind(
this,
APP.store.getState()['features/video-layout'].tileViewEnabled);
}
/**
* Adds listeners for the UI states of the local participant which are
* to be followed (by the remote participants). A non-moderator (very
* likely) can become a moderator so it may be easiest to always track
* the states of interest.
* @private
*/
_addFollowMeListeners() {
this.filmstripEventHandler = this._filmstripToggled.bind(this);
this._UI.addListener(UIEvents.TOGGLED_FILMSTRIP,
this.filmstripEventHandler);
const self = this;
this.pinnedEndpointEventHandler = function(videoId, isPinned) {
self._nextOnStage(videoId, isPinned);
};
this._UI.addListener(UIEvents.PINNED_ENDPOINT,
this.pinnedEndpointEventHandler);
this.sharedDocEventHandler = this._sharedDocumentToggled.bind(this);
this._UI.addListener(UIEvents.TOGGLED_SHARED_DOCUMENT,
this.sharedDocEventHandler);
this.tileViewEventHandler = this._tileViewToggled.bind(this);
this._UI.addListener(UIEvents.TOGGLED_TILE_VIEW,
this.tileViewEventHandler);
}
/**
* Removes all follow me listeners.
* @private
*/
_removeFollowMeListeners() {
this._UI.removeListener(UIEvents.TOGGLED_FILMSTRIP,
this.filmstripEventHandler);
this._UI.removeListener(UIEvents.TOGGLED_SHARED_DOCUMENT,
this.sharedDocEventHandler);
this._UI.removeListener(UIEvents.PINNED_ENDPOINT,
this.pinnedEndpointEventHandler);
this._UI.removeListener(UIEvents.TOGGLED_TILE_VIEW,
this.tileViewEventHandler);
}
/**
* Enables or disabled the follow me functionality
*
* @param enable {true} to enable the follow me functionality, {false} -
* to disable it
*/
enableFollowMe(enable) {
if (enable) {
this._setFollowMeInitialState();
this._addFollowMeListeners();
} else {
this._removeFollowMeListeners();
}
}
/**
* Notifies this instance that the (visibility of the) filmstrip was
* toggled (in the user interface of the local participant).
*
* @param filmstripVisible {Boolean} {true} if the filmstrip was shown (as a
* result of the toggle) or {false} if the filmstrip was hidden
*/
_filmstripToggled(filmstripVisible) {
this._local.filmstripVisible = filmstripVisible;
}
/**
* Notifies this instance that the (visibility of the) shared document was
* toggled (in the user interface of the local participant).
*
* @param sharedDocumentVisible {Boolean} {true} if the shared document was
* shown (as a result of the toggle) or {false} if it was hidden
*/
_sharedDocumentToggled(sharedDocumentVisible) {
this._local.sharedDocumentVisible = sharedDocumentVisible;
}
/**
* Notifies this instance that the tile view mode has been enabled or
* disabled.
*
* @param {boolean} enabled - True if tile view has been enabled, false
* if has been disabled.
* @returns {void}
*/
_tileViewToggled(enabled) {
this._local.tileViewEnabled = enabled;
}
/**
* Changes the nextOnStage property value.
*
* @param smallVideo the {SmallVideo} that was pinned or unpinned
* @param isPinned indicates if the given {SmallVideo} was pinned or
* unpinned
* @private
*/
_nextOnStage(videoId, isPinned) {
if (!this._conference.isModerator) {
return;
}
let nextOnStage = null;
if (isPinned) {
nextOnStage = videoId;
}
this._local.nextOnStage = nextOnStage;
}
/**
* Sends the follow-me command, when a local property change occurs.
*
* @private
*/
_localPropertyChange() { // eslint-disable-next-line no-unused-vars
// Only a moderator is allowed to send commands.
const conference = this._conference;
if (!conference.isModerator) {
return;
}
const commands = conference.commands;
// XXX The "Follow Me" command represents a snapshot of all states
// which are to be followed so don't forget to removeCommand before
// sendCommand!
commands.removeCommand(_COMMAND);
const local = this._local;
commands.sendCommandOnce(
_COMMAND,
{
attributes: {
filmstripVisible: local.filmstripVisible,
nextOnStage: local.nextOnStage,
sharedDocumentVisible: local.sharedDocumentVisible,
tileViewEnabled: local.tileViewEnabled
}
});
}
/**
* Notifies this instance about a &qout;Follow Me&qout; command (delivered
* by the Command(s) API of {this._conference}).
*
* @param attributes the attributes {Object} carried by the command
* @param id the identifier of the participant who issued the command. A
* notable idiosyncrasy of the Command(s) API to be mindful of here is that
* the command may be issued by the local participant.
*/
_onFollowMeCommand({ attributes }, id) {
// We require to know who issued the command because (1) only a
// moderator is allowed to send commands and (2) a command MUST be
// issued by a defined commander.
if (typeof id === 'undefined') {
return;
}
// The Command(s) API will send us our own commands and we don't want
// to act upon them.
if (this._conference.isLocalId(id)) {
return;
}
if (!this._conference.isParticipantModerator(id)) {
logger.warn('Received follow-me command not from moderator');
return;
}
// Applies the received/remote command to the user experience/interface
// of the local participant.
this._onFilmstripVisible(attributes.filmstripVisible);
this._onNextOnStage(attributes.nextOnStage);
this._onSharedDocumentVisible(attributes.sharedDocumentVisible);
this._onTileViewEnabled(attributes.tileViewEnabled);
}
/**
* Process a filmstrip open / close event received from FOLLOW-ME
* command.
* @param filmstripVisible indicates if the filmstrip has been shown or
* hidden
* @private
*/
_onFilmstripVisible(filmstripVisible) {
if (typeof filmstripVisible !== 'undefined') {
// XXX The Command(s) API doesn't preserve the types (of
// attributes, at least) at the time of this writing so take into
// account that what originated as a Boolean may be a String on
// receipt.
// eslint-disable-next-line eqeqeq, no-param-reassign
filmstripVisible = filmstripVisible == 'true';
// FIXME The UI (module) very likely doesn't (want to) expose its
// eventEmitter as a public field. I'm not sure at the time of this
// writing whether calling UI.toggleFilmstrip() is acceptable (from
// a design standpoint) either.
if (filmstripVisible !== this._UI.isFilmstripVisible()) {
this._UI.eventEmitter.emit(UIEvents.TOGGLE_FILMSTRIP);
}
}
}
/**
* Process the id received from a FOLLOW-ME command.
* @param id the identifier of the next participant to show on stage or
* undefined if we're clearing the stage (we're unpining all pined and we
* rely on dominant speaker events)
* @private
*/
_onNextOnStage(id) {
let clickId = null;
let pin;
// if there is an id which is not pinned we schedule it for pin only the
// first time
if (typeof id !== 'undefined' && !VideoLayout.isPinned(id)) {
clickId = id;
pin = true;
} else if (typeof id === 'undefined' && VideoLayout.getPinnedId()) {
// if there is no id, but we have a pinned one, let's unpin
clickId = VideoLayout.getPinnedId();
pin = false;
}
if (clickId) {
this._pinVideoThumbnailById(clickId, pin);
}
}
/**
* Process a shared document open / close event received from FOLLOW-ME
* command.
* @param sharedDocumentVisible indicates if the shared document has been
* opened or closed
* @private
*/
_onSharedDocumentVisible(sharedDocumentVisible) {
if (typeof sharedDocumentVisible !== 'undefined') {
// XXX The Command(s) API doesn't preserve the types (of
// attributes, at least) at the time of this writing so take into
// account that what originated as a Boolean may be a String on
// receipt.
// eslint-disable-next-line eqeqeq, no-param-reassign
sharedDocumentVisible = sharedDocumentVisible == 'true';
if (sharedDocumentVisible
!== this._UI.getSharedDocumentManager().isVisible()) {
this._UI.getSharedDocumentManager().toggleEtherpad();
}
}
}
/**
* Process a tile view enabled / disabled event received from FOLLOW-ME.
*
* @param {boolean} enabled - Whether or not tile view should be shown.
* @private
* @returns {void}
*/
_onTileViewEnabled(enabled) {
if (typeof enabled === 'undefined') {
return;
}
APP.store.dispatch(setTileView(enabled === 'true'));
}
/**
* Pins / unpins the video thumbnail given by clickId.
*
* @param clickId the identifier of the video thumbnail to pin or unpin
* @param pin {true} to pin, {false} to unpin
* @private
*/
_pinVideoThumbnailById(clickId, pin) {
const self = this;
const smallVideo = VideoLayout.getSmallVideo(clickId);
// If the SmallVideo for the given clickId exists we proceed with the
// pin/unpin.
if (smallVideo) {
this.nextOnStageTimer = 0;
clearTimeout(this.nextOnStageTimout);
if (pin) {
APP.store.dispatch(pinParticipant(clickId));
} else {
const { id } = getPinnedParticipant(APP.store.getState()) || {};
if (id === clickId) {
APP.store.dispatch(pinParticipant(null));
}
}
} else {
// If there's no SmallVideo object for the given id, lets wait and
// see if it's going to be created in the next 30sec.
this.nextOnStageTimout = setTimeout(function() {
if (self.nextOnStageTimer > _FOLLOW_ME_RECEIVED_TIMEOUT) {
self.nextOnStageTimer = 0;
return;
}
// eslint-disable-next-line no-invalid-this
this.nextOnStageTimer++;
self._pinVideoThumbnailById(clickId, pin);
}, 1000);
}
}
}
export default FollowMe;

View File

@@ -32,7 +32,6 @@ import {
const EventEmitter = require('events');
UI.messageHandler = messageHandler;
import FollowMe from '../FollowMe';
const eventEmitter = new EventEmitter();
@@ -41,8 +40,6 @@ UI.eventEmitter = eventEmitter;
let etherpadManager;
let sharedVideoManager;
let followMeHandler;
const JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP = {
microphone: {},
camera: {}
@@ -86,9 +83,6 @@ const UIListeners = new Map([
], [
UIEvents.TOGGLE_FILMSTRIP,
() => UI.toggleFilmstrip()
], [
UIEvents.FOLLOW_ME_ENABLED,
enabled => followMeHandler && followMeHandler.enableFollowMe(enabled)
]
]);
@@ -193,12 +187,6 @@ UI.initConference = function() {
if (displayName) {
UI.changeDisplayName('localVideoContainer', displayName);
}
// FollowMe attempts to copy certain aspects of the moderator's UI into the
// other participants' UI. Consequently, it needs (1) read and write access
// to the UI (depending on the moderator role of the local participant) and
// (2) APP.conference as means of communication between the participants.
followMeHandler = new FollowMe(APP.conference, UI);
};
/**

View File

@@ -5,7 +5,6 @@ import { getToolboxHeight } from '../../../react/features/toolbox';
import VideoLayout from '../videolayout/VideoLayout';
import LargeContainer from '../videolayout/LargeContainer';
import UIEvents from '../../../service/UI/UIEvents';
import Filmstrip from '../videolayout/Filmstrip';
/**
@@ -250,9 +249,6 @@ export default class EtherpadManager {
VideoLayout.showLargeVideoContainer(
ETHERPAD_CONTAINER_TYPE, !isVisible);
this.eventEmitter
.emit(UIEvents.TOGGLED_SHARED_DOCUMENT, !isVisible);
APP.store.dispatch(setDocumentEditingState(!isVisible));
}
}

View File

@@ -25,6 +25,17 @@ function getNewAudioOutputDevice(newDevices) {
d.deviceId === selectedAudioOutputDeviceId)) {
return 'default';
}
const settings = APP.store.getState()['features/base/settings'];
const preferredAudioOutputDeviceId = settings.userSelectedAudioOutputDeviceId;
// if the preferred one is not the selected and is available in the new devices
// we want to use it as it was just added
if (preferredAudioOutputDeviceId
&& preferredAudioOutputDeviceId !== selectedAudioOutputDeviceId
&& availableAudioOutputDevices.find(d => d.deviceId === preferredAudioOutputDeviceId)) {
return preferredAudioOutputDeviceId;
}
}
/**
@@ -39,7 +50,7 @@ function getNewAudioInputDevice(newDevices, localAudio) {
const availableAudioInputDevices = newDevices.filter(
d => d.kind === 'audioinput');
const settings = APP.store.getState()['features/base/settings'];
const selectedAudioInputDeviceId = settings.micDeviceId;
const selectedAudioInputDeviceId = settings.userSelectedMicDeviceId;
const selectedAudioInputDevice = availableAudioInputDevices.find(
d => d.deviceId === selectedAudioInputDeviceId);
@@ -50,7 +61,9 @@ function getNewAudioInputDevice(newDevices, localAudio) {
// If we have new audio device and permission to use it was granted
// (label is not an empty string), then we will try to use the first
// available device.
if (availableAudioInputDevices.length
if (selectedAudioInputDevice && selectedAudioInputDeviceId) {
return selectedAudioInputDeviceId;
} else if (availableAudioInputDevices.length
&& availableAudioInputDevices[0].label !== '') {
return availableAudioInputDevices[0].deviceId;
}
@@ -76,7 +89,7 @@ function getNewVideoInputDevice(newDevices, localVideo) {
const availableVideoInputDevices = newDevices.filter(
d => d.kind === 'videoinput');
const settings = APP.store.getState()['features/base/settings'];
const selectedVideoInputDeviceId = settings.cameraDeviceId;
const selectedVideoInputDeviceId = settings.userSelectedCameraDeviceId;
const selectedVideoInputDevice = availableVideoInputDevices.find(
d => d.deviceId === selectedVideoInputDeviceId);
@@ -87,7 +100,9 @@ function getNewVideoInputDevice(newDevices, localVideo) {
// If we have new video device and permission to use it was granted
// (label is not an empty string), then we will try to use the first
// available device.
if (availableVideoInputDevices.length
if (selectedVideoInputDevice && selectedVideoInputDeviceId) {
return selectedVideoInputDeviceId;
} else if (availableVideoInputDevices.length
&& availableVideoInputDevices[0].label !== '') {
return availableVideoInputDevices[0].deviceId;
}
@@ -121,8 +136,7 @@ export default {
localAudio) {
return {
audioinput: getNewAudioInputDevice(newDevices, localAudio),
videoinput: !isSharingScreen
&& getNewVideoInputDevice(newDevices, localVideo),
videoinput: isSharingScreen ? undefined : getNewVideoInputDevice(newDevices, localVideo),
audiooutput: getNewAudioOutputDevice(newDevices)
};
},
@@ -180,7 +194,7 @@ export default {
/**
*
*/
function createAudioTrack(showError) {
function createAudioTrack(showError = true) {
return (
createLocalTracks({
devices: [ 'audio' ],
@@ -198,7 +212,7 @@ export default {
/**
*
*/
function createVideoTrack(showError) {
function createVideoTrack(showError = true) {
return (
createLocalTracks({
devices: [ 'video' ],

565
package-lock.json generated
View File

@@ -55,23 +55,33 @@
}
},
"@atlaskit/blanket": {
"version": "7.0.12",
"resolved": "https://registry.npmjs.org/@atlaskit/blanket/-/blanket-7.0.12.tgz",
"integrity": "sha512-IWnXU2N42M14kvTU1YhATiK7vGYPZPsk/c2A+b8tNhRJTcfcTxTPMfcmGOvWYPD128el2TSly4uOvn9B9WKc9A==",
"version": "8.0.3",
"resolved": "https://registry.npmjs.org/@atlaskit/blanket/-/blanket-8.0.3.tgz",
"integrity": "sha512-RFV6NsJpgmrmR1nEb5ejFS1V7PlMaK+YN3sYhsnz/61M0NQWIm7y3YGNgwuTvpU5syE5HDrK7fX7aX5IugjXsw==",
"requires": {
"@atlaskit/analytics-next": "^3.1.2",
"@atlaskit/theme": "^7.0.1",
"@atlaskit/analytics-next": "^4.0.3",
"@atlaskit/theme": "^8.1.7",
"@babel/runtime": "^7.0.0"
},
"dependencies": {
"@atlaskit/theme": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@atlaskit/theme/-/theme-7.0.1.tgz",
"integrity": "sha512-wxXDnkUablJketNCrQuNUuazufYEA7kv0Y6Yzv6uvqfuyNpWUQt4H1psz/MW8DbZmCdku9dEYbNVK3nFP5TDGg==",
"@atlaskit/analytics-next": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@atlaskit/analytics-next/-/analytics-next-4.0.5.tgz",
"integrity": "sha512-IqbKUQugMArrHZcCbm3MM9udbYGOzwE2D4vmiE1E/3waMDP+WybUi/5dwGcGY3FcVkW5/x2Mitt357K4ZOL8Dw==",
"requires": {
"@babel/runtime": "^7.0.0",
"prop-types": "^15.5.10"
}
},
"@atlaskit/theme": {
"version": "8.1.7",
"resolved": "https://registry.npmjs.org/@atlaskit/theme/-/theme-8.1.7.tgz",
"integrity": "sha512-G7LUwdUW9dYMC3Fijpopxh+UeVIUjIB44NJB3MaqzneBmPnSP394Ys1m/pQUaCOMaZYXrwT3oct/jjnp7/nHWQ==",
"requires": {
"@babel/runtime": "^7.0.0",
"exenv": "^1.2.2",
"prop-types": "^15.5.10"
}
}
}
},
@@ -551,6 +561,44 @@
"uuid": "^3.1.0"
}
},
"@atlaskit/form": {
"version": "5.2.10",
"resolved": "https://registry.npmjs.org/@atlaskit/form/-/form-5.2.10.tgz",
"integrity": "sha512-nZa3UQfLbrGwDvoj+zv3S1cPkTgheSj3VVraZl6VHqIhxJXPDBg9B/hFb6Hxrmz21l8q9C29alZ/jTD7BJxXEw==",
"requires": {
"@atlaskit/icon": "^16.0.9",
"@atlaskit/theme": "^8.1.7",
"@babel/runtime": "^7.0.0",
"final-form": "^4.10.0",
"final-form-focus": "^1.1.0",
"memoize-one": "^3.0.1",
"react-uid": "^2.2.0",
"shallow-equal": "^1.0.0",
"tiny-invariant": "^0.0.3"
},
"dependencies": {
"@atlaskit/icon": {
"version": "16.0.9",
"resolved": "https://registry.npmjs.org/@atlaskit/icon/-/icon-16.0.9.tgz",
"integrity": "sha512-1gWuWgBsX6XZwX12iAPjoU0B0na92BZuCG0k8vHAIHJnhrgFpMJP7bqqV1IEob39qgbahk/4G9zagLBaNHWxoQ==",
"requires": {
"@atlaskit/theme": "^8.1.7",
"@babel/runtime": "^7.0.0",
"uuid": "^3.1.0"
}
},
"@atlaskit/theme": {
"version": "8.1.7",
"resolved": "https://registry.npmjs.org/@atlaskit/theme/-/theme-8.1.7.tgz",
"integrity": "sha512-G7LUwdUW9dYMC3Fijpopxh+UeVIUjIB44NJB3MaqzneBmPnSP394Ys1m/pQUaCOMaZYXrwT3oct/jjnp7/nHWQ==",
"requires": {
"@babel/runtime": "^7.0.0",
"exenv": "^1.2.2",
"prop-types": "^15.5.10"
}
}
}
},
"@atlaskit/icon": {
"version": "15.0.3",
"resolved": "https://registry.npmjs.org/@atlaskit/icon/-/icon-15.0.3.tgz",
@@ -713,16 +761,18 @@
}
},
"@atlaskit/modal-dialog": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/@atlaskit/modal-dialog/-/modal-dialog-7.1.2.tgz",
"integrity": "sha512-rY8ojmtr0/9MxqQ8Ab9mtgv1VLRuJMNPCCbstjJzv+NLBu5tIh/on+iuzsxBL84E5hgrvg0wf7JHzKyOoQJQsw==",
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/@atlaskit/modal-dialog/-/modal-dialog-8.0.1.tgz",
"integrity": "sha512-Ips7R8wUhBECbYKbRBC2SiQRUKh1ylJKRajMet9WV47V2WKt7AuRZ8YhNT+RWdp+63/Ze4sm748wfdwv9nfV9Q==",
"requires": {
"@atlaskit/analytics-next": "^3.1.2",
"@atlaskit/blanket": "^7.0.12",
"@atlaskit/button": "^10.1.1",
"@atlaskit/icon": "^15.0.2",
"@atlaskit/portal": "^0.0.17",
"@atlaskit/theme": "^7.0.1",
"@atlaskit/analytics-next": "^4.0.0",
"@atlaskit/blanket": "^8.0.0",
"@atlaskit/button": "^10.1.3",
"@atlaskit/form": "^5.1.8",
"@atlaskit/icon": "^16.0.4",
"@atlaskit/portal": "^0.2.0",
"@atlaskit/textfield": "^0.3.0",
"@atlaskit/theme": "^8.0.0",
"@babel/runtime": "^7.0.0",
"exenv": "^1.2.2",
"prop-types": "^15.5.10",
@@ -733,23 +783,68 @@
"tiny-invariant": "^0.0.3"
},
"dependencies": {
"@atlaskit/icon": {
"version": "15.0.3",
"resolved": "https://registry.npmjs.org/@atlaskit/icon/-/icon-15.0.3.tgz",
"integrity": "sha512-UAf7U0/+5giS2uMlOeVMYmhuWD4fQy0eRcp7r8oEDBqZXNH0yIuHrfu1bPgt2SbFotrjxZdPpOX1i1dXEu7y6g==",
"@atlaskit/analytics-next": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@atlaskit/analytics-next/-/analytics-next-4.0.5.tgz",
"integrity": "sha512-IqbKUQugMArrHZcCbm3MM9udbYGOzwE2D4vmiE1E/3waMDP+WybUi/5dwGcGY3FcVkW5/x2Mitt357K4ZOL8Dw==",
"requires": {
"@atlaskit/theme": "^7.0.1",
"@babel/runtime": "^7.0.0",
"prop-types": "^15.5.10"
}
},
"@atlaskit/button": {
"version": "10.1.3",
"resolved": "https://registry.npmjs.org/@atlaskit/button/-/button-10.1.3.tgz",
"integrity": "sha512-FonEQSaGcjUPUY3JMT0UiPNInGnxot/XPDBxwCTyQP9DLF5GPSWlC1N7KmQV4ljiS/DoSCOSetA27cTBPsw/0Q==",
"requires": {
"@atlaskit/analytics-next": "^4.0.0",
"@atlaskit/analytics-next-types": "^3.1.2",
"@atlaskit/spinner": "10.0.0",
"@atlaskit/theme": "^8.0.0",
"@atlaskit/type-helpers": "^2.0.0",
"@babel/runtime": "^7.0.0",
"babel-runtime": "^6.26.0",
"tslib": "^1.8.0"
}
},
"@atlaskit/icon": {
"version": "16.0.9",
"resolved": "https://registry.npmjs.org/@atlaskit/icon/-/icon-16.0.9.tgz",
"integrity": "sha512-1gWuWgBsX6XZwX12iAPjoU0B0na92BZuCG0k8vHAIHJnhrgFpMJP7bqqV1IEob39qgbahk/4G9zagLBaNHWxoQ==",
"requires": {
"@atlaskit/theme": "^8.1.7",
"@babel/runtime": "^7.0.0",
"uuid": "^3.1.0"
}
},
"@atlaskit/theme": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@atlaskit/theme/-/theme-7.0.1.tgz",
"integrity": "sha512-wxXDnkUablJketNCrQuNUuazufYEA7kv0Y6Yzv6uvqfuyNpWUQt4H1psz/MW8DbZmCdku9dEYbNVK3nFP5TDGg==",
"@atlaskit/portal": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@atlaskit/portal/-/portal-0.2.2.tgz",
"integrity": "sha512-RsJG2UAI9e+Nzw7ydhu/pEf0fCwKY69IzV/G2tP/PG2cYgpgc9rvFT0W/lYIoWC8v0Wo9VYYOcTOWWZErLfFKg==",
"requires": {
"@babel/runtime": "^7.0.0",
"exenv": "^1.2.2",
"tiny-invariant": "^0.0.3"
}
},
"@atlaskit/spinner": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/@atlaskit/spinner/-/spinner-10.0.0.tgz",
"integrity": "sha512-zSCde3FyVzLK1LRg6EAEM5unfGO0MkFTjD2EhpHnRvjMCFIhGLa2KFJL6VT/FxvT/RrEDzZwUmIiSK1nXyGIuA==",
"requires": {
"@atlaskit/theme": "^8.0.0",
"@babel/runtime": "^7.0.0",
"babel-runtime": "^6.26.0",
"react-transition-group": "^2.2.1"
}
},
"@atlaskit/theme": {
"version": "8.1.7",
"resolved": "https://registry.npmjs.org/@atlaskit/theme/-/theme-8.1.7.tgz",
"integrity": "sha512-G7LUwdUW9dYMC3Fijpopxh+UeVIUjIB44NJB3MaqzneBmPnSP394Ys1m/pQUaCOMaZYXrwT3oct/jjnp7/nHWQ==",
"requires": {
"@babel/runtime": "^7.0.0",
"exenv": "^1.2.2",
"prop-types": "^15.5.10"
}
}
@@ -927,6 +1022,38 @@
"babel-runtime": "^6.26.0"
}
},
"@atlaskit/textfield": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@atlaskit/textfield/-/textfield-0.3.1.tgz",
"integrity": "sha512-RRjBFrdAt/UkkJqKPqW+Jc1yle9POsEuHAMuzF1mTGjJfIf6ItP2sF3cTTRXZAOWv7Fo8C+IFTO2R/JpNXQrMg==",
"requires": {
"@atlaskit/analytics-next": "^4.0.1",
"@atlaskit/theme": "^8.0.1",
"@babel/runtime": "^7.0.0",
"emotion": "^9.1.1"
},
"dependencies": {
"@atlaskit/analytics-next": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@atlaskit/analytics-next/-/analytics-next-4.0.5.tgz",
"integrity": "sha512-IqbKUQugMArrHZcCbm3MM9udbYGOzwE2D4vmiE1E/3waMDP+WybUi/5dwGcGY3FcVkW5/x2Mitt357K4ZOL8Dw==",
"requires": {
"@babel/runtime": "^7.0.0",
"prop-types": "^15.5.10"
}
},
"@atlaskit/theme": {
"version": "8.1.7",
"resolved": "https://registry.npmjs.org/@atlaskit/theme/-/theme-8.1.7.tgz",
"integrity": "sha512-G7LUwdUW9dYMC3Fijpopxh+UeVIUjIB44NJB3MaqzneBmPnSP394Ys1m/pQUaCOMaZYXrwT3oct/jjnp7/nHWQ==",
"requires": {
"@babel/runtime": "^7.0.0",
"exenv": "^1.2.2",
"prop-types": "^15.5.10"
}
}
}
},
"@atlaskit/theme": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/@atlaskit/theme/-/theme-7.0.2.tgz",
@@ -2058,9 +2185,9 @@
}
},
"@babel/register": {
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/@babel/register/-/register-7.4.0.tgz",
"integrity": "sha512-ekziebXBnS/7V6xk8sBfLSSD6YZuy6P29igBtR6OL/tswKdxOV+Yqq0nzICMguVYtGRZYUCGpfGV8J9Za2iBdw==",
"version": "7.4.4",
"resolved": "https://registry.npmjs.org/@babel/register/-/register-7.4.4.tgz",
"integrity": "sha512-sn51H88GRa00+ZoMqCVgOphmswG4b7mhf9VOB0LUBAieykq2GnRFerlN+JQkO/ntT7wz4jaHNSRPg9IdMPEUkA==",
"requires": {
"core-js": "^3.0.0",
"find-cache-dir": "^2.0.0",
@@ -2240,15 +2367,62 @@
}
}
},
"@expo/react-native-action-sheet": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@expo/react-native-action-sheet/-/react-native-action-sheet-1.1.2.tgz",
"integrity": "sha512-//2EvHVBFVGSAzuJvG0I1UoQVzGJBo2f1CkO+RMnEWdR0FeWYmV7+pCThIroL1czRm/oOtoMxiGS6FgXt6QgVA==",
"@emotion/babel-utils": {
"version": "0.6.10",
"resolved": "https://registry.npmjs.org/@emotion/babel-utils/-/babel-utils-0.6.10.tgz",
"integrity": "sha512-/fnkM/LTEp3jKe++T0KyTszVGWNKPNOUJfjNKLO17BzQ6QPxgbg3whayom1Qr2oLFH3V92tDymU+dT5q676uow==",
"requires": {
"hoist-non-react-statics": "^2.2.2",
"prop-types": "^15.5.10"
"@emotion/hash": "^0.6.6",
"@emotion/memoize": "^0.6.6",
"@emotion/serialize": "^0.9.1",
"convert-source-map": "^1.5.1",
"find-root": "^1.1.0",
"source-map": "^0.7.2"
},
"dependencies": {
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
}
}
},
"@emotion/hash": {
"version": "0.6.6",
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.6.6.tgz",
"integrity": "sha512-ojhgxzUHZ7am3D2jHkMzPpsBAiB005GF5YU4ea+8DNPybMk01JJUM9V9YRlF/GE95tcOm8DxQvWA2jq19bGalQ=="
},
"@emotion/memoize": {
"version": "0.6.6",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.6.6.tgz",
"integrity": "sha512-h4t4jFjtm1YV7UirAFuSuFGyLa+NNxjdkq6DpFLANNQY5rHueFZHVY+8Cu1HYVP6DrheB0kv4m5xPjo7eKT7yQ=="
},
"@emotion/serialize": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.9.1.tgz",
"integrity": "sha512-zTuAFtyPvCctHBEL8KZ5lJuwBanGSutFEncqLn/m9T1a6a93smBStK+bZzcNPgj4QS8Rkw9VTwJGhRIUVO8zsQ==",
"requires": {
"@emotion/hash": "^0.6.6",
"@emotion/memoize": "^0.6.6",
"@emotion/unitless": "^0.6.7",
"@emotion/utils": "^0.8.2"
}
},
"@emotion/stylis": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.7.1.tgz",
"integrity": "sha512-/SLmSIkN13M//53TtNxgxo57mcJk/UJIDFRKwOiLIBEyBHEcipgR6hNMQ/59Sl4VjCJ0Z/3zeAZyvnSLPG/1HQ=="
},
"@emotion/unitless": {
"version": "0.6.7",
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.6.7.tgz",
"integrity": "sha512-Arj1hncvEVqQ2p7Ega08uHLr1JuRYBuO5cIvcA+WWEQ5+VmkOE3ZXzl04NbQxeQpWX78G7u6MqxKuNX3wvYZxg=="
},
"@emotion/utils": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.8.2.tgz",
"integrity": "sha512-rLu3wcBWH4P5q1CGoSSH/i9hrXs7SlbRLkoq9IGuoPYNGQvDJ3pt/wmOM+XgYjIDRMVIdkUWt0RsfzF50JfnCw=="
},
"@jitsi/sdp-interop": {
"version": "0.1.14",
"resolved": "https://registry.npmjs.org/@jitsi/sdp-interop/-/sdp-interop-0.1.14.tgz",
@@ -2275,9 +2449,9 @@
}
},
"@react-native-community/cli": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-1.6.0.tgz",
"integrity": "sha512-OV3N5O/wzjb8OTZDiFerX0gf9/KzLJOvDttU38BqIvn8+OLkH6SIgGrKked9vrKKvH5bFG6jmCmKCW5gP+tOwQ==",
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-1.9.2.tgz",
"integrity": "sha512-wSw3g6HrSUvLZiHiWRcO++JrKdbYNRWycGbGHVCnRLsdDRsj/y152xPlvBa29C8w+1SwiiN8aGsBOO0x9hkrCg==",
"requires": {
"chalk": "^1.1.1",
"commander": "^2.19.0",
@@ -2360,9 +2534,9 @@
}
},
"node-fetch": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz",
"integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA=="
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.5.0.tgz",
"integrity": "sha512-YuZKluhWGJwCcUu4RlZstdAxr8bFfOVHakc1mplwHkk8J+tqM1Y5yraYvIUpeX8aY7+crCwiELJq7Vl0o0LWXw=="
},
"pump": {
"version": "3.0.0",
@@ -2576,8 +2750,7 @@
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"absolute-path": {
"version": "0.0.0",
@@ -3325,14 +3498,63 @@
"util.promisify": "^1.0.0"
}
},
"babel-plugin-check-es2015-constants": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
"integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=",
"babel-plugin-emotion": {
"version": "9.2.11",
"resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-9.2.11.tgz",
"integrity": "sha512-dgCImifnOPPSeXod2znAmgc64NhaaOjGEHROR/M+lmStb3841yK1sgaDYAYMnlvWNz8GnpwIPN0VmNpbWYZ+VQ==",
"requires": {
"babel-runtime": "^6.22.0"
"@babel/helper-module-imports": "^7.0.0",
"@emotion/babel-utils": "^0.6.4",
"@emotion/hash": "^0.6.2",
"@emotion/memoize": "^0.6.1",
"@emotion/stylis": "^0.7.0",
"babel-plugin-macros": "^2.0.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"convert-source-map": "^1.5.0",
"find-root": "^1.1.0",
"mkdirp": "^0.5.1",
"source-map": "^0.5.7",
"touch": "^2.0.1"
}
},
"babel-plugin-macros": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.5.1.tgz",
"integrity": "sha512-xN3KhAxPzsJ6OQTktCanNpIFnnMsCV+t8OloKxIL72D6+SUZYFn9qfklPgef5HyyDtzYZqqb+fs1S12+gQY82Q==",
"requires": {
"@babel/runtime": "^7.4.2",
"cosmiconfig": "^5.2.0",
"resolve": "^1.10.0"
},
"dependencies": {
"@babel/runtime": {
"version": "7.4.3",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.3.tgz",
"integrity": "sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA==",
"requires": {
"regenerator-runtime": "^0.13.2"
}
},
"regenerator-runtime": {
"version": "0.13.2",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz",
"integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA=="
},
"resolve": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.1.tgz",
"integrity": "sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA==",
"requires": {
"path-parse": "^1.0.6"
}
}
}
},
"babel-plugin-syntax-jsx": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
"integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY="
},
"babel-plugin-syntax-trailing-function-commas": {
"version": "7.0.0-beta.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz",
@@ -4572,6 +4794,20 @@
"elliptic": "^6.0.0"
}
},
"create-emotion": {
"version": "9.2.12",
"resolved": "https://registry.npmjs.org/create-emotion/-/create-emotion-9.2.12.tgz",
"integrity": "sha512-P57uOF9NL2y98Xrbl2OuiDQUZ30GVmASsv5fbsjF4Hlraip2kyAvMm+2PoYUvFFw03Fhgtxk3RqZSm2/qHL9hA==",
"requires": {
"@emotion/hash": "^0.6.2",
"@emotion/memoize": "^0.6.1",
"@emotion/stylis": "^0.7.0",
"@emotion/unitless": "^0.6.2",
"csstype": "^2.5.2",
"stylis": "^3.5.0",
"stylis-rule-sheet": "^0.0.10"
}
},
"create-error": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/create-error/-/create-error-0.3.1.tgz",
@@ -4764,6 +5000,11 @@
"source-map": "^0.5.3"
}
},
"csstype": {
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.4.tgz",
"integrity": "sha512-lAJUJP3M6HxFXbqtGRc0iZrdyeN+WzOWeY0q/VnFzI+kqVrYIzC7bWlKqCW7oCIdzoPkvfp82EVvrTlQ8zsWQg=="
},
"current-executing-script": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/current-executing-script/-/current-executing-script-0.1.3.tgz",
@@ -5169,6 +5410,15 @@
"integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
"dev": true
},
"emotion": {
"version": "9.2.12",
"resolved": "https://registry.npmjs.org/emotion/-/emotion-9.2.12.tgz",
"integrity": "sha512-hcx7jppaI8VoXxIWEhxpDW7I+B4kq9RNzQLmsrF6LY8BGKqe2N+gFAQr0EfuFucFlPs2A9HM4+xNj4NeqEWIOQ==",
"requires": {
"babel-plugin-emotion": "^9.2.11",
"create-emotion": "^9.2.12"
}
},
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
@@ -6140,6 +6390,34 @@
}
}
},
"final-form": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/final-form/-/final-form-4.12.0.tgz",
"integrity": "sha512-z1fSzDNmIBlDjRMaluM3WgDbcwCFpPm7mvopplgXGMRS49MXR+1n//lteLwPURdGQNOZhWm3GwiEJanEHCItww==",
"requires": {
"@babel/runtime": "^7.3.1"
},
"dependencies": {
"@babel/runtime": {
"version": "7.4.3",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.3.tgz",
"integrity": "sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA==",
"requires": {
"regenerator-runtime": "^0.13.2"
}
},
"regenerator-runtime": {
"version": "0.13.2",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz",
"integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA=="
}
}
},
"final-form-focus": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/final-form-focus/-/final-form-focus-1.1.2.tgz",
"integrity": "sha512-Gd+Bd2Ll7ijo3/sd6kJ/bwLkhc2bUJPxTON6fIqee/008EJpACWhT+zoWCm9q6NcfMcWRS+Sp5ikRX8iqdXeGQ=="
},
"finalhandler": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz",
@@ -6172,6 +6450,11 @@
"pkg-dir": "^2.0.0"
}
},
"find-root": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
},
"find-up": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
@@ -6252,9 +6535,9 @@
"integrity": "sha512-WQr7DsBZfdmXwqWk7yyk9H2R60iHiUpLMvkov6KivafC9d1SzDTjSBsKMa8skT4laaSxus+F4v7WLO6J0zxPkw=="
},
"focus-lock": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-0.4.2.tgz",
"integrity": "sha512-jqjj49iZEVT/X8yidEMmP8oWmDKJlJy/um7OyYP42CZ0y4icCp6Fm2lTkZVcFVpt4mZ/hPtbs9ikqId7YhUelw=="
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-0.6.3.tgz",
"integrity": "sha512-EU6ePgEauhWrzJEN5RtG1d1ayrWXhEnfzTjnieHj+jG9tNHDEhKTAnCn1TN3gs9h6XWCDH6cpeX1VXY/lzLwZg=="
},
"follow-redirects": {
"version": "1.7.0",
@@ -8588,11 +8871,6 @@
"resolved": "https://registry.npmjs.org/keycode/-/keycode-2.1.9.tgz",
"integrity": "sha1-lkojxU5IiUBbSGGlyfBIDUUUHfo="
},
"keymirror": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/keymirror/-/keymirror-0.1.1.tgz",
"integrity": "sha1-kYiJ6hP40KQufFVyUO7nE63JXDU="
},
"killable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
@@ -8634,8 +8912,8 @@
}
},
"lib-jitsi-meet": {
"version": "github:jitsi/lib-jitsi-meet#86e3badd5c04e1df72435205d28a58c8a64e343a",
"from": "github:jitsi/lib-jitsi-meet#86e3badd5c04e1df72435205d28a58c8a64e343a",
"version": "github:jitsi/lib-jitsi-meet#23503b0efd4b97989af7b10696ec9ae790aec7bb",
"from": "github:jitsi/lib-jitsi-meet#23503b0efd4b97989af7b10696ec9ae790aec7bb",
"requires": {
"@jitsi/sdp-interop": "0.1.14",
"@jitsi/sdp-simulcast": "0.2.1",
@@ -8647,8 +8925,7 @@
"sdp-transform": "2.3.0",
"strophe.js": "1.2.16",
"strophejs-plugin-disco": "0.0.2",
"webrtc-adapter": "github:webrtc/adapter#1eec19782b4058d186341263e7d049cea3e3290a",
"yaeti": "1.0.1"
"webrtc-adapter": "github:webrtc/adapter#1eec19782b4058d186341263e7d049cea3e3290a"
},
"dependencies": {
"js-md5": {
@@ -9300,9 +9577,9 @@
}
},
"node-fetch": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz",
"integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA=="
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.5.0.tgz",
"integrity": "sha512-YuZKluhWGJwCcUu4RlZstdAxr8bFfOVHakc1mplwHkk8J+tqM1Y5yraYvIUpeX8aY7+crCwiELJq7Vl0o0LWXw=="
},
"supports-color": {
"version": "5.5.0",
@@ -11600,10 +11877,11 @@
"integrity": "sha1-0uJZ/clR0diQbAiQIAIQjc6HkuU="
},
"react-clientside-effect": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.0.0.tgz",
"integrity": "sha512-XYOjooNlAEos60o4ha9zDb1R9h3LMJUdXJOjFH6fNUwFxXu2k+Wq4Cd0JWmurgeY0DWTzGvpNJ0cY6eHyfhL1Q==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.0.tgz",
"integrity": "sha512-cVIsGG7SNHsQsCP4+fw7KFUB0HiYiU8hbvL640XaLCbZ31aK8/lj0qOKJ2K+xRjuQz/IM4Q4qclI0aEqTtcXtA==",
"requires": {
"@babel/runtime": "^7.0.0",
"shallowequal": "^1.1.0"
}
},
@@ -11694,23 +11972,38 @@
}
},
"react-focus-lock": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-1.13.2.tgz",
"integrity": "sha512-ev8OHCuqK3fDpnrlJ8udTdUS6MzpFB3XhXyFp7qLrd9B/OkqSDO/n3t5rVMu/BQEz+NcXFuuSk2hYRgJphsNzA==",
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-1.19.1.tgz",
"integrity": "sha512-TPpfiack1/nF4uttySfpxPk4rGZTLXlaZl7ncZg/ELAk24Iq2B1UUaUioID8H8dneUXqznT83JTNDHDj+kwryw==",
"requires": {
"focus-lock": "^0.4.2",
"@babel/runtime": "^7.0.0",
"focus-lock": "^0.6.3",
"prop-types": "^15.6.2",
"react-clientside-effect": "^1.0.0"
"react-clientside-effect": "^1.2.0"
},
"dependencies": {
"prop-types": {
"version": "15.6.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz",
"integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==",
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"requires": {
"loose-envify": "^1.3.1",
"object-assign": "^4.1.1"
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"prop-types": {
"version": "15.7.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.8.1"
}
},
"react-is": {
"version": "16.8.6",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
"integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA=="
}
}
},
@@ -11745,9 +12038,9 @@
}
},
"react-native": {
"version": "0.59.4",
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.59.4.tgz",
"integrity": "sha512-etnXQp9IZgC8Vj5gsxZEDP4xRjJVNIj5/BSE1WcNAONG6tu6+mDBntx1jxHInwh61WYNgoQJuQGsbN5Na59ZDw==",
"version": "0.59.5",
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.59.5.tgz",
"integrity": "sha512-8Q/9cS6IMsGNiFhJgzmncbUeuacXQMe5EJl0c63fW30DvjEjeTVCvhM08eGzSpsNlOvL2XDRa4YOiCrwI7S1TA==",
"requires": {
"@babel/runtime": "^7.0.0",
"@react-native-community/cli": "^1.2.1",
@@ -11848,9 +12141,9 @@
}
},
"node-fetch": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz",
"integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA=="
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.5.0.tgz",
"integrity": "sha512-YuZKluhWGJwCcUu4RlZstdAxr8bFfOVHakc1mplwHkk8J+tqM1Y5yraYvIUpeX8aY7+crCwiELJq7Vl0o0LWXw=="
},
"supports-color": {
"version": "5.5.0",
@@ -11886,37 +12179,11 @@
"jssha": "^2.2.0"
}
},
"react-native-communications": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/react-native-communications/-/react-native-communications-2.2.1.tgz",
"integrity": "sha1-eIO1ayCgAu63kMET+GFuqGksp5U="
},
"react-native-fast-image": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/react-native-fast-image/-/react-native-fast-image-5.1.1.tgz",
"integrity": "sha512-kEzgZxbbXYhy27u5GnhrKitn+XDBFAHSDUJdYC6llMi5cDPjgcqhOAQABj0K+ga5pn+/xPZLmD882rrUGiwVVA=="
},
"react-native-gifted-chat": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/react-native-gifted-chat/-/react-native-gifted-chat-0.6.0.tgz",
"integrity": "sha512-KYI/okKUZmjcJM3I6BP10KG1WNkCKBZhY8N47wk407dr+KqLS4+LR13UKo7j3f++5SrX2Ex+7vYvIQ2pBdzCiA==",
"requires": {
"@expo/react-native-action-sheet": "^1.0.1",
"moment": "^2.19.0",
"react-native-communications": "2.2.1",
"react-native-lightbox": "^0.7.0",
"react-native-parsed-text": "^0.0.20",
"react-native-video": "^3.2.1",
"uuid": "3.3.0"
},
"dependencies": {
"uuid": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.0.tgz",
"integrity": "sha512-ijO9N2xY/YaOqQ5yz5c4sy2ZjWmA6AR6zASb/gdpeKZ8+948CxwfMW9RrKVk5may6ev8c0/Xguu32e2Llelpqw=="
}
}
},
"react-native-google-signin": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/react-native-google-signin/-/react-native-google-signin-1.0.2.tgz",
@@ -11932,28 +12199,11 @@
"resolved": "https://registry.npmjs.org/react-native-keep-awake/-/react-native-keep-awake-4.0.0.tgz",
"integrity": "sha512-0Fotox+eLXQooeibVs3P60yASYUWjtRw9MZNmbuHt5UZQrgUrAKsE4jm7gTr4tPU1m1RkwGzcgUFpcOkh/ec7g=="
},
"react-native-lightbox": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/react-native-lightbox/-/react-native-lightbox-0.7.0.tgz",
"integrity": "sha512-HS3T4WlCd0Gb3us2d6Jse5m6KjNhngnKm35Wapq30WtQa9s+/VMmtuktbGPGaWtswcDyOj6qByeJBw9W80iPCA==",
"requires": {
"prop-types": "^15.5.10"
}
},
"react-native-linear-gradient": {
"version": "2.5.3",
"resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.5.3.tgz",
"integrity": "sha512-XdusrOXXlkI+yQpUW7YLeiq9cZiBwkvQX4XEkHPVrJ9H47gsKmdgBwObkZBzBQUP0dKK/Sg6aVpETEis4w43bQ=="
},
"react-native-parsed-text": {
"version": "0.0.20",
"resolved": "https://registry.npmjs.org/react-native-parsed-text/-/react-native-parsed-text-0.0.20.tgz",
"integrity": "sha512-n77hYu64Tr3oclzIXBXXaiLh1WbMKdA2Y0x6bX/yqwxAM4afcObENY5VrNB+EsTBJBEDqrypA9D1p2cLEIHkuQ==",
"requires": {
"babel-plugin-check-es2015-constants": "6.22.0",
"prop-types": "^15.5.10"
}
},
"react-native-sound": {
"version": "0.10.12",
"resolved": "https://registry.npmjs.org/react-native-sound/-/react-native-sound-0.10.12.tgz",
@@ -12010,18 +12260,14 @@
}
}
},
"react-native-video": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/react-native-video/-/react-native-video-3.2.1.tgz",
"integrity": "sha512-Xansfoo/to80FwhM1HKlf7pCxDZ5RtV+kG3piCVvsNAhPY4GGwiOGUH9y3Y+mFQIDEWcY8I9j16lsFYAbnue3g==",
"requires": {
"keymirror": "0.1.1",
"prop-types": "^15.5.10"
}
"react-native-watch-connectivity": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/react-native-watch-connectivity/-/react-native-watch-connectivity-0.2.0.tgz",
"integrity": "sha512-l3Quzbb+qa4in2U5RSt/lT0/pHrIpEChT1NnqrVAAXNrjkXjVOsxduaaEDdDhTzNJQEm/PcAcoyrFmgvGOohxw=="
},
"react-native-webrtc": {
"version": "github:jitsi/react-native-webrtc#032ee5c90e2c5ff27ab2f952217104772fcbd155",
"from": "github:jitsi/react-native-webrtc#032ee5c90e2c5ff27ab2f952217104772fcbd155",
"version": "github:jitsi/react-native-webrtc#4064c6f2db4f8b961daaaa8dafc6a896d7cfbc43",
"from": "github:jitsi/react-native-webrtc#4064c6f2db4f8b961daaaa8dafc6a896d7cfbc43",
"requires": {
"base64-js": "^1.1.2",
"event-target-shim": "^1.0.5",
@@ -12139,6 +12385,11 @@
"tween-functions": "^1.0.1"
}
},
"react-uid": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/react-uid/-/react-uid-2.2.0.tgz",
"integrity": "sha512-z+g5+hFOQ08hCfrGcJ1PNs+cmvH8Uq2CVzCmPeWBsUi5A4W4NWXR5jouledzy3oSKGMU9HOzf8zFuGi15TXJoQ=="
},
"read-pkg": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
@@ -13608,6 +13859,11 @@
"safe-buffer": "^5.0.1"
}
},
"shallow-equal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.1.0.tgz",
"integrity": "sha512-0SW1nWo1hnabO62SEeHsl8nmTVVEzguVWZCj5gaQrgWAxz/BaCja4OWdJBWLVPDxdtE/WU7c98uUCCXyPHSCvw=="
},
"shallowequal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
@@ -14026,9 +14282,9 @@
}
},
"stacktrace-parser": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.5.tgz",
"integrity": "sha512-fjJ563lEMEXdqUH8fZR84sczWxM+Pi3bViix1n7371mFr8sL7UPewec79+IhHkN4UMmGbXoXj58WIaF7lIciRA==",
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.6.tgz",
"integrity": "sha512-wXhu0Z8YgCGigUtHQq+J7pjXCppk3Um5DwH4qskOKHMlJmKwuuUSm+wDAgU7t4sbVjvuDTNGwOfFKgjMEqSflA==",
"requires": {
"type-fest": "^0.3.0"
}
@@ -14932,6 +15188,24 @@
}
}
},
"touch": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/touch/-/touch-2.0.2.tgz",
"integrity": "sha512-qjNtvsFXTRq7IuMLweVgFxmEuQ6gLbRs2jQxL80TtZ31dEKWYIxRXquij6w6VimyDek5hD3PytljHmEtAs2u0A==",
"requires": {
"nopt": "~1.0.10"
},
"dependencies": {
"nopt": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
"integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
"requires": {
"abbrev": "1"
}
}
}
},
"tough-cookie": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
@@ -15003,9 +15277,9 @@
}
},
"type-fest": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.0.tgz",
"integrity": "sha512-fg3sfdDdJDtdHLUpeGsf/fLyG1aapk6zgFiYG5+MDUPybGrJemH4SLk5tP7hGRe8ntxjg0q5LYW53b6YpJIQ9Q=="
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz",
"integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ=="
},
"type-is": {
"version": "1.6.16",
@@ -16614,11 +16888,6 @@
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
},
"yaeti": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-1.0.1.tgz",
"integrity": "sha1-IX0Eu83LvYbMR45GVapMKMST3r8="
},
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",

View File

@@ -26,7 +26,7 @@
"@atlaskit/inline-dialog": "5.3.0",
"@atlaskit/inline-message": "7.0.10",
"@atlaskit/lozenge": "6.2.4",
"@atlaskit/modal-dialog": "7.1.2",
"@atlaskit/modal-dialog": "8.0.1",
"@atlaskit/multi-select": "11.0.13",
"@atlaskit/spinner": "9.0.13",
"@atlaskit/tabs": "8.0.11",
@@ -51,7 +51,7 @@
"js-utils": "github:jitsi/js-utils#73a67a7a60d52f8e895f50939c8fcbd1f20fe7b5",
"jsrsasign": "8.0.12",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#86e3badd5c04e1df72435205d28a58c8a64e343a",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#23503b0efd4b97989af7b10696ec9ae790aec7bb",
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"lodash": "4.17.11",
"moment": "2.19.4",
@@ -62,12 +62,11 @@
"react-emoji-render": "0.4.6",
"react-i18next": "7.13.0",
"react-linkify": "0.2.2",
"react-native": "0.59.4",
"react-native": "0.59.5",
"react-native-background-timer": "2.1.1",
"react-native-calendar-events": "1.6.4",
"react-native-callstats": "3.58.2",
"react-native-fast-image": "5.1.1",
"react-native-gifted-chat": "0.6.0",
"react-native-google-signin": "1.0.2",
"react-native-immersive": "2.0.0",
"react-native-keep-awake": "4.0.0",
@@ -75,7 +74,8 @@
"react-native-sound": "0.10.12",
"react-native-swipeout": "2.3.6",
"react-native-vector-icons": "6.0.2",
"react-native-webrtc": "github:jitsi/react-native-webrtc#032ee5c90e2c5ff27ab2f952217104772fcbd155",
"react-native-watch-connectivity": "0.2.0",
"react-native-webrtc": "github:jitsi/react-native-webrtc#4064c6f2db4f8b961daaaa8dafc6a896d7cfbc43",
"react-redux": "5.0.7",
"react-transition-group": "2.4.0",
"redux": "4.0.0",

View File

@@ -1,8 +1,6 @@
import AbstractHandler from './AbstractHandler';
import { amplitude } from './amplitude';
const logger = require('jitsi-meet-logger').getLogger(__filename);
/**
* Analytics handler for Amplitude.
*/
@@ -20,10 +18,7 @@ export default class AmplitudeHandler extends AbstractHandler {
const { amplitudeAPPKey, host } = options;
if (!amplitudeAPPKey) {
logger.warn(
'Failed to initialize Amplitude handler, no APP key');
return;
throw new Error('Failed to initialize Amplitude handler, no APP key');
}
this._enabled = true;

View File

@@ -4,8 +4,6 @@ import { getJitsiMeetGlobalNS } from '../../base/util';
import AbstractHandler from './AbstractHandler';
const logger = require('jitsi-meet-logger').getLogger(__filename);
/**
* Analytics handler for Google Analytics.
*/
@@ -24,11 +22,7 @@ class GoogleAnalyticsHandler extends AbstractHandler {
this._userProperties = {};
if (!options.googleAnalyticsTrackingId) {
logger.warn(
'Failed to initialize Google Analytics handler, no tracking ID'
);
return;
throw new Error('Failed to initialize Google Analytics handler, no tracking ID');
}
this._enabled = true;

View File

@@ -13,6 +13,11 @@ class Amplitude {
* be used only for multi-project logging.
*/
constructor(instanceName) {
// It might not have been included in the build.
if (!AmplitudeNative) {
throw new Error('Amplitude analytics is not supported');
}
this._instanceName = instanceName;
}

View File

@@ -2,6 +2,7 @@
import type { Dispatch } from 'redux';
import { appWillNavigate } from '../base/app';
import { setRoom } from '../base/conference';
import {
configWillLoad,
@@ -58,6 +59,9 @@ export function appNavigate(uri: ?string) {
const { contextRoot, host, room } = location;
const locationURL = new URL(location.toString());
// XXX this looks like CONFIG_WILL_LOAD ?
dispatch(appWillNavigate(locationURL, room));
dispatch(configWillLoad(locationURL, room));
let protocol = location.protocol.toLowerCase();
@@ -81,7 +85,7 @@ export function appNavigate(uri: ?string) {
config = restoreConfig(baseURL);
if (!config) {
dispatch(loadConfigError(error, locationURL));
dispatch(loadConfigError(error, locationURL, room));
return;
}
@@ -92,7 +96,7 @@ export function appNavigate(uri: ?string) {
dispatch(setConfig(config));
dispatch(setRoom(room));
} else {
dispatch(loadConfigError(new Error('Config no longer needed!'), locationURL));
dispatch(loadConfigError(new Error('Config no longer needed!'), locationURL, room));
}
};
}

View File

@@ -4,6 +4,7 @@ import React, { Fragment } from 'react';
import { BaseApp } from '../../base/app';
import { toURLString } from '../../base/util';
import '../../follow-me';
import { OverlayContainer } from '../../overlay';
import { appNavigate } from '../actions';

View File

@@ -22,6 +22,7 @@ import '../../mobile/permissions';
import '../../mobile/picture-in-picture';
import '../../mobile/proximity';
import '../../mobile/wake-lock';
import '../../mobile/watchos';
import { AbstractApp } from './AbstractApp';
import type { Props as AbstractAppProps } from './AbstractApp';

View File

@@ -113,6 +113,7 @@ export function cancelWaitForOwner() {
// clients/consumers need an event.
const { authRequired } = getState()['features/base/conference'];
// FIXME remove when external-api ported to base/session
authRequired && dispatch(conferenceLeft(authRequired));
dispatch(appNavigate(undefined));

View File

@@ -9,6 +9,13 @@
*/
export const APP_WILL_MOUNT = 'APP_WILL_MOUNT';
/**
* FIXME.
*
* @type {string}
*/
export const APP_WILL_NAVIGATE = 'APP_WILL_NAVIGATE';
/**
* The type of (redux) action which signals that a specific App will unmount (in
* React terms).

View File

@@ -2,7 +2,7 @@
import type { Dispatch } from 'redux';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
import { APP_WILL_MOUNT, APP_WILL_NAVIGATE, APP_WILL_UNMOUNT } from './actionTypes';
declare var APP;
@@ -33,6 +33,25 @@ export function appWillMount(app: Object) {
};
}
/**
* FIXME.
*
* @param {URL} locationURL - FIXME.
* @param {string} room - FIXME.
* @returns {{
* type: APP_WILL_NAVIGATE,
* locationURL: URL,
* room: ?string
* }}
*/
export function appWillNavigate(locationURL: URL, room: ?string) {
return {
type: APP_WILL_NAVIGATE,
locationURL,
room
};
}
/**
* Signals that a specific App will unmount (in the terms of React).
*

View File

@@ -18,6 +18,8 @@ import { PersistenceRegistry } from '../../storage';
import { appWillMount, appWillUnmount } from '../actions';
const logger = require('jitsi-meet-logger').getLogger(__filename);
declare var APP: Object;
/**
@@ -74,14 +76,20 @@ export default class BaseApp extends Component<*, State> {
* @type {Promise}
*/
this._init = this._initStorage()
.catch(() => { /* BaseApp should always initialize! */ })
.catch(err => {
/* BaseApp should always initialize! */
logger.error(err);
})
.then(() => new Promise(resolve => {
this.setState({
store: this._createStore()
}, resolve);
}))
.then(() => this.state.store.dispatch(appWillMount(this)))
.catch(() => { /* BaseApp should always initialize! */ });
.catch(err => {
/* BaseApp should always initialize! */
logger.error(err);
});
}
/**

View File

@@ -1,12 +1,13 @@
// @flow
import UIEvents from '../../../../service/UI/UIEvents';
import {
createStartMutedConfigurationEvent,
sendAnalytics
} from '../../analytics';
import { getName } from '../../app';
import { endpointMessageReceived } from '../../subtitles';
import { JITSI_CONNECTION_CONFERENCE_KEY } from '../connection';
import { JitsiConferenceEvents } from '../lib-jitsi-meet';
import { setAudioMuted, setVideoMuted } from '../media';
import {
@@ -17,7 +18,6 @@ import {
participantRoleChanged,
participantUpdated
} from '../participants';
import { endpointMessageReceived } from '../../subtitles';
import { getLocalTracks, trackAdded, trackRemoved } from '../tracks';
import { getJitsiMeetGlobalNS } from '../util';
@@ -380,7 +380,10 @@ export function createConference() {
getWiFiStatsMethod: getJitsiMeetGlobalNS().getWiFiStats
});
connection[JITSI_CONNECTION_CONFERENCE_KEY] = conference;
conference[JITSI_CONFERENCE_URL_KEY] = locationURL;
dispatch(_conferenceWillJoin(conference));
_addConferenceListeners(conference, dispatch);
@@ -547,10 +550,6 @@ export function setDesktopSharingEnabled(desktopSharingEnabled: boolean) {
* }}
*/
export function setFollowMe(enabled: boolean) {
if (typeof APP !== 'undefined') {
APP.UI.emitEvent(UIEvents.FOLLOW_ME_ENABLED, enabled);
}
return {
type: SET_FOLLOW_ME,
enabled

View File

@@ -38,17 +38,20 @@ export function configWillLoad(locationURL: URL, room: string) {
* loading of a configuration.
* @param {URL} locationURL - The URL of the location which necessitated the
* loading of a configuration.
* @param {string} room - The name of the conference room.
* @returns {{
* type: LOAD_CONFIG_ERROR,
* error: Error,
* locationURL: URL
* locationURL: URL,
* room: string
* }}
*/
export function loadConfigError(error: Error, locationURL: URL) {
export function loadConfigError(error: Error, locationURL: URL, room: ?string) {
return {
type: LOAD_CONFIG_ERROR,
error,
locationURL
locationURL,
room
};
}

View File

@@ -1,4 +1,4 @@
/* @flow */
// @flow
import _ from 'lodash';

View File

@@ -0,0 +1,21 @@
// @flow
import { NativeModules } from 'react-native';
export * from './functions.any';
/**
* Removes all analytics related options from the given configuration, in case of a libre build.
*
* @param {*} config - The configuration which needs to be cleaned up.
* @returns {void}
*/
export function _cleanupConfig(config: Object) {
if (NativeModules.AppInfo.LIBRE_BUILD) {
config.analytics.scriptURLs = [];
delete config.analytics.amplitudeAPPKey;
delete config.analytics.googleAnalyticsTrackingId;
delete config.callStatsID;
delete config.callStatsSecret;
}
}

View File

@@ -0,0 +1,12 @@
// @flow
export * from './functions.any';
/**
* Removes all analytics related options from the given configuration, in case of a libre build.
*
* @param {*} config - The configuration which needs to be cleaned up.
* @returns {void}
*/
export function _cleanupConfig(config: Object) { // eslint-disable-line no-unused-vars
}

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