Compare commits

..

3 Commits

Author SHA1 Message Date
Saúl Ibarra Corretgé
d27a94b3b5 android: raise SDK version 2019-07-03 13:29:21 +02:00
Saúl Ibarra Corretgé
e1710eaa38 android: fix deadlock in uncaught exception handler
The app is about to crash at that stage so it was a moot point to try to leave
the conference anyway.

Stopping ConnectionServers is still a good idea though, since a crash may leave
the device in a bad state otherwise.
2019-07-03 13:29:21 +02:00
Saúl Ibarra Corretgé
f4467206d7 android: fix synchronized access to listeners set
Fixes this issue:

~~~
    java.util.ConcurrentModificationException
        at java.util.HashMap$HashIterator.nextNode(HashMap.java:1441)
        at java.util.HashMap$KeyIterator.next(HashMap.java:1465)
        at org.jitsi.meet.sdk.OngoingConferenceTracker.updateListeners(OngoingConferenceTracker.java:89)
        at org.jitsi.meet.sdk.OngoingConferenceTracker.onExternalAPIEvent(OngoingConferenceTracker.java:74)
        at org.jitsi.meet.sdk.ExternalAPIModule.sendEvent(ExternalAPIModule.java:71)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
        at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:158)
        at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:29)
        at android.os.Looper.loop(Looper.java:214)
        at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:232)
        at java.lang.Thread.run(Thread.java:764)
~~~
2019-07-03 13:29:21 +02:00
493 changed files with 17901 additions and 30797 deletions

View File

@@ -2,27 +2,22 @@
; We fork some components by platform
.*/*[.]android.js
; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/
; Ignore unexpected extra "@providesModule"
.*/node_modules/.*/node_modules/fbjs/.*
node_modules/react-native/Libraries/react-native/React.js
; Ignore duplicate module providers
; For RN Apps installed via npm, "Libraries" folder is inside
; "node_modules/react-native" but in the source repo it is in the root
node_modules/react-native/Libraries/react-native/React.js
.*/Libraries/react-native/React.js
; Ignore polyfills
node_modules/react-native/Libraries/polyfills/.*
.*/Libraries/polyfills/.*
; These should not be required directly
; require from fbjs/lib instead: require('fbjs/lib/warning')
node_modules/warning/.*
; Flow doesn't support platforms
.*/Libraries/Utilities/HMRLoadingView.js
[untyped]
.*/node_modules/@react-native-community/cli/.*/.*
; Ignore metro
.*/node_modules/metro/.*
; Ignore packages in node_modules which we (i.e. the jitsi-meet project) have
; seen to cause errors and we have chosen not to fix.
@@ -45,18 +40,6 @@ emoji=true
esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable
; We (i.e. the jitsi-meet project) are using the haste module system on Web as
; well, not only on React Native. Unfortunately, Flow does not support .web.js
; by default. Override Flow's defaults to include .web.js as well. Technically,
; we have .native.js as well so the choice of .web.js may lead to errors.
; Practically though, it is a potential future problem that we do not have at
; the time of this writing.
module.file_ext=.web.js
; Flow's defaults:
module.file_ext=.js
module.file_ext=.json
module.file_ext=.ios.js
module.system=haste
module.system.haste.use_name_reducers=true
# get basename
@@ -69,11 +52,8 @@ module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
module.system.haste.paths.blacklist=.*/__tests__/.*
module.system.haste.paths.blacklist=.*/__mocks__/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/Libraries/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/RNTester/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/IntegrationTests/.*
module.system.haste.paths.blacklist=<PROJECT_ROOT>/node_modules/react-native/Libraries/react-native/react-native-implementation.js
module.system.haste.paths.blacklist=<PROJECT_ROOT>/node_modules/react-native/Libraries/Animated/src/polyfills/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/Libraries/.*
munge_underscores=true
@@ -84,32 +64,22 @@ suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
[lints]
sketchy-null-number=warn
sketchy-null-mixed=warn
sketchy-number=warn
untyped-type-import=warn
nonstrict-import=warn
deprecated-type=warn
unsafe-getters-setters=warn
inexact-spread=warn
unnecessary-invariant=warn
signature-verification-failure=warn
deprecated-utility=error
[strict]
deprecated-type
nonstrict-import
sketchy-null
unclear-type
unsafe-getters-setters
untyped-import
untyped-type-import
; We (i.e. the jitsi-meet project) are using the haste module system on Web as
; well, not only on React Native. Unfortunately, Flow does not support .web.js
; by default. Override Flow's defaults to include .web.js as well. Technically,
; we have .native.js as well so the choice of .web.js may lead to errors.
; Practically though, it is a potential future problem that we do not have at
; the time of this writing.
module.file_ext=.web.js
; Flow's defaults:
module.file_ext=.js
module.file_ext=.jsx
module.file_ext=.json
[version]
^0.98.0
^0.92.0

View File

@@ -2,5 +2,3 @@ osx_image: xcode10.2
language: objective-c
script:
- "./ios/travis-ci/build-ipa.sh"
after_script:
- sleep 10

View File

@@ -45,8 +45,6 @@ deploy-appbundle:
$(OUTPUT_DIR)/analytics-ga.js \
$(BUILD_DIR)/analytics-ga.min.js \
$(BUILD_DIR)/analytics-ga.min.map \
$(BUILD_DIR)/video-blur-effect.min.js \
$(BUILD_DIR)/video-blur-effect.min.map \
$(DEPLOY_DIR)
deploy-lib-jitsi-meet:

View File

@@ -207,6 +207,24 @@ public class MainActivity extends FragmentActivity implements JitsiMeetActivityI
</details>
Starting with SDK version 1.22, a Glide module must be provided by the host app.
This makes it possible to use the Glide image processing library from both the
SDK and the host app itself.
You can use the code in `JitsiGlideModule.java` and adjust the package name.
When building, add the following code in your `app/build.gradle` file, adjusting
the Glide version to match the one in https://github.com/jitsi/jitsi-meet/blob/master/android/build.gradle
```
// Glide
implementation("com.github.bumptech.glide:glide:${glideVersion}") {
exclude group: "com.android.support", module: "glide"
}
implementation("com.github.bumptech.glide:annotations:${glideVersion}") {
exclude group: "com.android.support", module: "annotations"
}
```
### JitsiMeetActivity
This class encapsulates a high level API in the form of an Android `FragmentActivity`

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>app</name>
<comment>Project app created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>

View File

@@ -1,2 +0,0 @@
connection.project.dir=..
eclipse.preferences.version=1

View File

@@ -70,8 +70,8 @@ repositories {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation "com.android.support:support-v4:${rootProject.ext.supportLibVersion}"
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
if (!rootProject.ext.libreBuild) {
implementation 'com.google.android.gms:play-services-auth:16.0.1'
@@ -88,6 +88,15 @@ dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.1'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'
// Glide
implementation("com.github.bumptech.glide:glide:${rootProject.ext.glideVersion}") {
exclude group: "com.android.support", module: "glide"
}
implementation("com.github.bumptech.glide:annotations:${rootProject.ext.glideVersion}") {
exclude group: "com.android.support", module: "annotations"
}
annotationProcessor "com.github.bumptech.glide:compiler:${rootProject.ext.glideVersion}"
}
gradle.projectsEvaluated {

View File

@@ -9,6 +9,13 @@
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# React Native
# Keep our interfaces so they can be used by other ProGuard rules.
@@ -53,9 +60,19 @@
-keep class sun.misc.Unsafe { *; }
-dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-keep class okio.** { *; }
-dontwarn okio.**
# FastImage + Glide
-keep public class com.dylanvann.fastimage.* {*;}
-keep public class com.dylanvann.fastimage.** {*;}
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
# WebRTC
-keep class org.webrtc.** { *; }

View File

@@ -0,0 +1,16 @@
package org.jitsi.meet;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.AppGlideModule;
/**
* An AppGlideModule needs to be present for image loading events to work in
* react-native-fast-image. However, if this is defined by the SDK it will cause trouble with
* apps which are using Glide themselves.
*
* In order to avoid the problem, define a Jitsi Glide module here, so applications already using
* it are not in trouble.
*/
@GlideModule
public final class JitsiGlideModule extends AppGlideModule {
}

View File

@@ -21,13 +21,14 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.KeyEvent;
import androidx.annotation.Nullable;
import org.jitsi.meet.sdk.JitsiMeet;
import org.jitsi.meet.sdk.JitsiMeetActivity;
import org.jitsi.meet.sdk.JitsiMeetConferenceOptions;
import org.jitsi.meet.sdk.JitsiMeetUserInfo;
import java.lang.reflect.Method;
import java.net.MalformedURLException;

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#66A8DD</color>
</resources>

View File

@@ -25,10 +25,9 @@ allprojects {
repositories {
google()
jcenter()
// React Native (JS, Obj-C sources, Android binaries) is installed from npm.
// React Native (JS, Obj-C sources, Android binaries) is installed from
// npm.
maven { url "$rootDir/../node_modules/react-native/android" }
// Android JSC is installed from npm.
maven { url("$rootDir/../node_modules/jsc-android/dist") }
}
// Make sure we use the react-native version in node_modules and not the one
@@ -75,13 +74,6 @@ allprojects {
def versionQualifierNumber = (int)(((new Date().getTime()/1000) - 1546297200) / 10)
afterEvaluate { project ->
if (project.plugins.hasPlugin('android') || project.plugins.hasPlugin('android-library')) {
project.android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
}
}
if (project.name.startsWith('react-native-')) {
def npmManifest = project.file('../package.json')
def json = new JsonSlurper().parseText(npmManifest.text)
@@ -91,6 +83,17 @@ allprojects {
project.version = "${json.version}-jitsi-${versionQualifierNumber}"
project.android {
compileSdkVersion rootProject.ext.compileSdkVersion
if (rootProject.ext.has('buildToolsVersion')) {
buildToolsVersion rootProject.ext.buildToolsVersion
}
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
}
}
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.source
@@ -161,6 +164,10 @@ ext {
mavenUser = System.env.MVN_USER ?: ""
mavenPassword = System.env.MVN_PASSWORD ?: ""
// Glide
excludeAppGlideModule = true
glideVersion = "4.7.1" // keep in sync with react-native-fast-image
// Libre build
libreBuild = (System.env.LIBRE_BUILD ?: "false").toBoolean()
}

View File

@@ -17,8 +17,5 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.useAndroidX=true
android.enableJetifier=true
appVersion=19.3.0
sdkVersion=2.2.2
appVersion=19.2.0
sdkVersion=2.2.1

View File

@@ -8,14 +8,13 @@ THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOUR
export RCT_METRO_PORT="${RCT_METRO_PORT:=8081}"
echo "export RCT_METRO_PORT=${RCT_METRO_PORT}" > "${THIS_DIR}/../../node_modules/react-native/scripts/.packager.env"
adb reverse tcp:8081 tcp:8081
if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then
if ! curl -s "http://localhost:${RCT_METRO_PORT}/status" | grep -q "packager-status:running" ; then
echo "Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly"
exit 2
fi
else
adb reverse tcp:8081 tcp:8081
CMD="${THIS_DIR}/../../node_modules/react-native/scripts/launchPackager.command"
if [[ `uname` == "Darwin" ]]; then
open -g "${CMD}" || echo "Can't start packager automatically"

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>sdk</name>
<comment>Project sdk created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>

View File

@@ -1,2 +0,0 @@
connection.project.dir=..
eclipse.preferences.version=1

View File

@@ -36,12 +36,10 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.fragment:fragment:1.0.0'
implementation "com.android.support:support-v4:${rootProject.ext.supportLibVersion}"
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
api 'com.facebook.react:react-native:+'
implementation 'org.webkit:android-jsc:+'
implementation 'com.dropbox.core:dropbox-core-sdk:3.0.8'
@@ -49,14 +47,16 @@ dependencies {
implementation 'com.amplitude:android-sdk:2.14.1'
implementation(project(":react-native-google-signin")) {
exclude group: 'com.google.android.gms'
exclude group: 'androidx'
exclude group: 'com.android.support'
}
}
implementation project(':react-native-background-timer')
implementation project(':react-native-calendar-events')
implementation project(':react-native-community-async-storage')
implementation project(':react-native-community_netinfo')
implementation(project(':react-native-fast-image')) {
exclude group: 'com.android.support'
}
implementation project(':react-native-immersive')
implementation project(':react-native-keep-awake')
implementation project(':react-native-linear-gradient')
@@ -152,8 +152,6 @@ android.libraryVariants.all { def variant ->
from("${projectDir}/../../sounds/incomingMessage.wav")
from("${projectDir}/../../sounds/joined.wav")
from("${projectDir}/../../sounds/left.wav")
from("${projectDir}/../../sounds/liveStreamingOn.mp3")
from("${projectDir}/../../sounds/liveStreamingOff.mp3")
from("${projectDir}/../../sounds/outgoingRinging.wav")
from("${projectDir}/../../sounds/outgoingStart.wav")
from("${projectDir}/../../sounds/recordingOn.mp3")

View File

@@ -25,8 +25,8 @@ import android.content.pm.PackageManager;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.Log;
import androidx.annotation.RequiresApi;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
@@ -256,11 +256,6 @@ class AudioModeModule extends ReactContextBaseJavaModule
private static final String DEVICE_HEADPHONES = "HEADPHONES";
private static final String DEVICE_SPEAKER = "SPEAKER";
/**
* Device change event.
*/
private static final String DEVICE_CHANGE_EVENT = "org.jitsi.meet:features/audio-mode#devices-update";
/**
* List of currently available audio devices.
*/
@@ -308,7 +303,7 @@ class AudioModeModule extends ReactContextBaseJavaModule
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Do an initial detection on Android >= M.
onAudioDeviceChange();
runInAudioThread(onAudioDeviceChangeRunner);
} else {
// On Android < M, detect if we have an earpiece.
PackageManager pm = reactContext.getPackageManager();
@@ -332,7 +327,6 @@ class AudioModeModule extends ReactContextBaseJavaModule
public Map<String, Object> getConstants() {
Map<String, Object> constants = new HashMap<>();
constants.put("DEVICE_CHANGE_EVENT", DEVICE_CHANGE_EVENT);
constants.put("AUDIO_CALL", AUDIO_CALL);
constants.put("DEFAULT", DEFAULT);
constants.put("VIDEO_CALL", VIDEO_CALL);
@@ -341,26 +335,31 @@ class AudioModeModule extends ReactContextBaseJavaModule
}
/**
* Notifies JS land that the devices list has changed.
* Gets the list of available audio device categories, i.e. 'bluetooth',
* 'earpiece ', 'speaker', 'headphones'.
*
* @param promise a {@link Promise} which will be resolved with an object
* containing a 'devices' key with a list of devices, plus a
* 'selected' key with the selected one.
*/
private void notifyDevicesChanged() {
@ReactMethod
public void getAudioDevices(final Promise promise) {
runInAudioThread(new Runnable() {
@Override
public void run() {
WritableArray data = Arguments.createArray();
final boolean hasHeadphones = availableDevices.contains(DEVICE_HEADPHONES);
WritableMap map = Arguments.createMap();
map.putString("selected", selectedDevice);
WritableArray devices = Arguments.createArray();
for (String device : availableDevices) {
if (hasHeadphones && device.equals(DEVICE_EARPIECE)) {
// Skip earpiece when headphones are plugged in.
if (mode == VIDEO_CALL && device.equals(DEVICE_EARPIECE)) {
// Skip earpiece when in video call mode.
continue;
}
WritableMap deviceInfo = Arguments.createMap();
deviceInfo.putString("type", device);
deviceInfo.putBoolean("selected", device.equals(selectedDevice));
data.pushMap(deviceInfo);
devices.pushString(device);
}
ReactInstanceManagerHolder.emitEvent(DEVICE_CHANGE_EVENT, data);
Log.i(TAG, "Updating audio device list");
map.putArray("devices", devices);
promise.resolve(map);
}
});
}
@@ -585,7 +584,7 @@ class AudioModeModule extends ReactContextBaseJavaModule
return;
}
runInAudioThread(new Runnable() {
Runnable r = new Runnable() {
@Override
public void run() {
boolean success;
@@ -608,7 +607,8 @@ class AudioModeModule extends ReactContextBaseJavaModule
"Failed to set audio mode to " + mode);
}
}
});
};
runInAudioThread(r);
}
/**
@@ -690,7 +690,6 @@ class AudioModeModule extends ReactContextBaseJavaModule
selectedDevice = null;
userSelectedDevice = null;
notifyDevicesChanged();
return true;
}
@@ -709,6 +708,7 @@ class AudioModeModule extends ReactContextBaseJavaModule
}
boolean bluetoothAvailable = availableDevices.contains(DEVICE_BLUETOOTH);
boolean earpieceAvailable = availableDevices.contains(DEVICE_EARPIECE);
boolean headsetAvailable = availableDevices.contains(DEVICE_HEADPHONES);
// Pick the desired device based on what's available and the mode.
@@ -717,6 +717,8 @@ class AudioModeModule extends ReactContextBaseJavaModule
audioDevice = DEVICE_BLUETOOTH;
} else if (headsetAvailable) {
audioDevice = DEVICE_HEADPHONES;
} else if (mode == AUDIO_CALL && earpieceAvailable) {
audioDevice = DEVICE_EARPIECE;
} else {
audioDevice = DEVICE_SPEAKER;
}
@@ -742,7 +744,6 @@ class AudioModeModule extends ReactContextBaseJavaModule
setAudioRoutePreO(audioDevice);
}
notifyDevicesChanged();
return true;
}
}

View File

@@ -20,9 +20,9 @@ package org.jitsi.meet.sdk;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.react.ReactRootView;
import com.facebook.react.bridge.ReadableMap;
@@ -111,7 +111,8 @@ public abstract class BaseReactView<ListenerT>
setBackgroundColor(BACKGROUND_COLOR);
ReactInstanceManagerHolder.initReactInstanceManager((Activity)context);
ReactInstanceManagerHolder.initReactInstanceManager(
((Activity) context).getApplication());
// Hook this BaseReactView into ExternalAPI.
externalAPIScope = UUID.randomUUID().toString();

View File

@@ -5,6 +5,7 @@ import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.telecom.CallAudioState;
import android.telecom.Connection;
import android.telecom.ConnectionRequest;
@@ -14,7 +15,6 @@ import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import android.util.Log;
import androidx.annotation.RequiresApi;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReadableMap;

View File

@@ -20,9 +20,9 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import com.facebook.react.modules.core.PermissionListener;

View File

@@ -25,7 +25,6 @@ import android.os.Build;
import com.calendarevents.CalendarEventsPackage;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.core.PermissionListener;
/**
@@ -118,13 +117,7 @@ public class JitsiMeetActivityDelegate {
= ReactInstanceManagerHolder.getReactInstanceManager();
if (reactInstanceManager != null) {
// Try to avoid a crash because some devices trip on this assert:
// https://github.com/facebook/react-native/blob/df4e67fe75d781d1eb264128cadf079989542755/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java#L512
// Why this happens is a mystery wrapped in an enigma.
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (activity == reactContext.getCurrentActivity()) {
reactInstanceManager.onHostPause(activity);
}
reactInstanceManager.onHostPause(activity);
}
}

View File

@@ -1,6 +1,6 @@
package org.jitsi.meet.sdk;
import androidx.core.app.ActivityCompat;
import android.support.v4.app.ActivityCompat;
import com.facebook.react.modules.core.PermissionAwareActivity;

View File

@@ -341,7 +341,7 @@ public class JitsiMeetConferenceOptions implements Parcelable {
dest.writeString(token);
dest.writeBundle(colorScheme);
dest.writeBundle(featureFlags);
dest.writeBundle(userInfo != null ? userInfo.asBundle() : new Bundle());
dest.writeBundle(userInfo.asBundle());
dest.writeByte((byte) (audioMuted == null ? 0 : audioMuted ? 1 : 2));
dest.writeByte((byte) (audioOnly == null ? 0 : audioOnly ? 1 : 2));
dest.writeByte((byte) (videoMuted == null ? 0 : videoMuted ? 1 : 2));

View File

@@ -19,10 +19,9 @@ package org.jitsi.meet.sdk;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

View File

@@ -21,7 +21,6 @@ import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
@@ -48,12 +47,7 @@ public class JitsiMeetOngoingConferenceService extends Service
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
intent.setAction(Actions.START);
ComponentName componentName;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
componentName = context.startForegroundService(intent);
} else {
componentName = context.startService(intent);
}
ComponentName componentName = context.startService(intent);
if (componentName == null) {
Log.w(TAG, "Ongoing conference service not started");
}
@@ -88,13 +82,8 @@ public class JitsiMeetOngoingConferenceService extends Service
final String action = intent.getAction();
if (action.equals(Actions.START)) {
Notification notification = OngoingNotification.buildOngoingConferenceNotification();
if (notification == null) {
stopSelf();
Log.w(TAG, "Couldn't start service, notification is null");
} else {
startForeground(OngoingNotification.NOTIFICATION_ID, notification);
Log.i(TAG, "Service started");
}
startForeground(OngoingNotification.NOTIFICATION_ID, notification);
Log.i(TAG, "Service started");
} else if (action.equals(Actions.HANGUP)) {
Log.i(TAG, "Hangup requested");
// Abort all ongoing calls

View File

@@ -19,9 +19,9 @@ package org.jitsi.meet.sdk;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ReadableMap;

View File

@@ -23,7 +23,7 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import androidx.core.app.NotificationCompat;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import java.util.Random;

View File

@@ -5,13 +5,13 @@ import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.telecom.DisconnectCause;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import android.util.Log;
import androidx.annotation.RequiresApi;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;

View File

@@ -18,7 +18,8 @@
package org.jitsi.meet.sdk;
import android.app.Activity;
import androidx.annotation.Nullable;
import android.app.Application;
import android.support.annotation.Nullable;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactPackage;
@@ -27,19 +28,7 @@ import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.devsupport.DevInternalSettings;
import com.facebook.react.jscexecutor.JSCExecutorFactory;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.soloader.SoLoader;
import com.oney.WebRTCModule.RTCVideoViewManager;
import com.oney.WebRTCModule.WebRTCModule;
import org.webrtc.SoftwareVideoDecoderFactory;
import org.webrtc.SoftwareVideoEncoderFactory;
import org.webrtc.VideoDecoderFactory;
import org.webrtc.VideoEncoderFactory;
import org.webrtc.audio.AudioDeviceModule;
import org.webrtc.audio.JavaAudioDeviceModule;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
@@ -58,7 +47,8 @@ class ReactInstanceManagerHolder {
*/
private static ReactInstanceManager reactInstanceManager;
private static List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
private static List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> nativeModules
= new ArrayList<>(Arrays.<NativeModule>asList(
new AndroidSettingsModule(reactContext),
@@ -76,21 +66,6 @@ class ReactInstanceManagerHolder {
nativeModules.add(new RNConnectionService(reactContext));
}
// Initialize the WebRTC module by hand, since we want to override some
// initialization options.
WebRTCModule.Options options = new WebRTCModule.Options();
AudioDeviceModule adm = JavaAudioDeviceModule.builder(reactContext)
.createAudioDeviceModule();
VideoDecoderFactory videoDecoderFactory = new SoftwareVideoDecoderFactory();
VideoEncoderFactory videoEncoderFactory = new SoftwareVideoEncoderFactory();
options.setAudioDeviceModule(adm);
options.setVideoDecoderFactory(videoDecoderFactory);
options.setVideoEncoderFactory(videoEncoderFactory);
nativeModules.add(new WebRTCModule(reactContext, options));
try {
Class<?> amplitudeModuleClass = Class.forName("org.jitsi.meet.sdk.AmplitudeModule");
Constructor constructor = amplitudeModuleClass.getConstructor(ReactApplicationContext.class);
@@ -102,13 +77,6 @@ class ReactInstanceManagerHolder {
return nativeModules;
}
private static List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(
// WebRTC, see createNativeModules for details.
new RTCVideoViewManager()
);
}
/**
* Helper function to send an event to JavaScript.
*
@@ -175,25 +143,24 @@ class ReactInstanceManagerHolder {
* time. All {@code ReactRootView} instances will be tied to the one and
* only {@code ReactInstanceManager}.
*
* @param activity {@code Activity} current running Activity.
* @param application {@code Application} instance which is running.
*/
static void initReactInstanceManager(Activity activity) {
static void initReactInstanceManager(Application application) {
if (reactInstanceManager != null) {
return;
}
SoLoader.init(activity, /* native exopackage */ false);
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.reactnativecommunity.asyncstorage.AsyncStoragePackage(),
new com.reactnativecommunity.netinfo.NetInfoPackage(),
new com.reactnativecommunity.webview.RNCWebViewPackage(),
new com.rnimmersive.RNImmersivePackage(),
new com.zmxv.RNSound.RNSoundPackage(),
@@ -202,10 +169,6 @@ class ReactInstanceManagerHolder {
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return ReactInstanceManagerHolder.createNativeModules(reactContext);
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return ReactInstanceManagerHolder.createViewManagers(reactContext);
}
}));
try {
@@ -216,17 +179,11 @@ class ReactInstanceManagerHolder {
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
}
// Keep on using JSC, the jury is out on Hermes.
JSCExecutorFactory jsFactory
= new JSCExecutorFactory("", "");
reactInstanceManager
= ReactInstanceManager.builder()
.setApplication(activity.getApplication())
.setCurrentActivity(activity)
.setApplication(application)
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index.android")
.setJavaScriptExecutorFactory(jsFactory)
.addPackages(packages)
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)

View File

@@ -144,7 +144,8 @@ class WiFiStatsModule
JSONObject result = new JSONObject();
result.put("rssi", rssi)
.put("signal", signalLevel)
.put("timestamp", System.currentTimeMillis());
.put("timestamp",
String.valueOf(System.currentTimeMillis()));
JSONArray addresses = new JSONArray();

View File

@@ -16,7 +16,7 @@
package org.jitsi.meet.sdk.incoming_call;
import androidx.annotation.NonNull;
import android.support.annotation.NonNull;
public class IncomingCallInfo {
/**

View File

@@ -18,7 +18,7 @@ package org.jitsi.meet.sdk.incoming_call;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import android.support.annotation.NonNull;
import com.facebook.react.bridge.ReadableMap;

View File

@@ -7,8 +7,8 @@ include ':react-native-calendar-events'
project(':react-native-calendar-events').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-calendar-events/android')
include ':react-native-community-async-storage'
project(':react-native-community-async-storage').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/async-storage/android')
include ':react-native-community_netinfo'
project(':react-native-community_netinfo').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/netinfo/android')
include ':react-native-fast-image'
project(':react-native-fast-image').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fast-image/android')
include ':react-native-google-signin'
project(':react-native-google-signin').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-google-signin/android')
include ':react-native-immersive'

View File

@@ -23,8 +23,7 @@ import {
sendAnalytics
} from './react/features/analytics';
import {
maybeRedirectToWelcomePage,
redirectToStaticPage,
redirectWithStoredParams,
reloadWithStoredParams
} from './react/features/app';
@@ -44,7 +43,6 @@ import {
conferenceWillJoin,
conferenceWillLeave,
dataChannelOpened,
kickedOut,
lockStateChanged,
onStartMutedPolicyChanged,
p2pStatusChanged,
@@ -98,12 +96,15 @@ import {
createLocalTracksF,
destroyLocalTracks,
isLocalTrackMuted,
isUserInteractionRequiredForUnmute,
replaceLocalTrack,
trackAdded,
trackRemoved
} from './react/features/base/tracks';
import { getJitsiMeetGlobalNS } from './react/features/base/util';
import {
getLocationContextRoot,
getJitsiMeetGlobalNS
} from './react/features/base/util';
import { notifyKickedOut } from './react/features/conference';
import { addMessage } from './react/features/chat';
import { showDesktopPicker } from './react/features/desktop-picker';
import { appendSuffix } from './react/features/display-name';
@@ -111,8 +112,10 @@ import {
maybeOpenFeedbackDialog,
submitFeedback
} from './react/features/feedback';
import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay';
import { suspendDetected } from './react/features/power-monitor';
import {
mediaPermissionPromptVisibilityChanged,
suspendDetected
} from './react/features/overlay';
import { setSharedVideoStatus } from './react/features/shared-video';
import { isButtonEnabled } from './react/features/toolbox';
import { endpointMessageReceived } from './react/features/subtitles';
@@ -208,6 +211,77 @@ function muteLocalVideo(muted) {
APP.store.dispatch(setVideoMuted(muted));
}
/**
* Check if the welcome page is enabled and redirects to it.
* If requested show a thank you dialog before that.
* If we have a close page enabled, redirect to it without
* showing any other dialog.
*
* @param {object} options used to decide which particular close page to show
* or if close page is disabled, whether we should show the thankyou dialog
* @param {boolean} options.showThankYou - whether we should
* show thank you dialog
* @param {boolean} options.feedbackSubmitted - whether feedback was submitted
*/
function maybeRedirectToWelcomePage(options) {
// if close page is enabled redirect to it, without further action
if (config.enableClosePage) {
const { isGuest } = APP.store.getState()['features/base/jwt'];
// save whether current user is guest or not, before navigating
// to close page
window.sessionStorage.setItem('guest', isGuest);
redirectToStaticPage(`static/${
options.feedbackSubmitted ? 'close.html' : 'close2.html'}`);
return;
}
// else: show thankYou dialog only if there is no feedback
if (options.showThankYou) {
APP.store.dispatch(showNotification({
titleArguments: { appName: interfaceConfig.APP_NAME },
titleKey: 'dialog.thankYou'
}));
}
// if Welcome page is enabled redirect to welcome page after 3 sec, if
// there is a thank you message to be shown, 0.5s otherwise.
if (config.enableWelcomePage) {
setTimeout(
() => {
APP.store.dispatch(redirectWithStoredParams('/'));
},
options.showThankYou ? 3000 : 500);
}
}
/**
* Assigns a specific pathname to window.location.pathname taking into account
* the context root of the Web app.
*
* @param {string} pathname - The pathname to assign to
* window.location.pathname. If the specified pathname is relative, the context
* root of the Web app will be prepended to the specified pathname before
* assigning it to window.location.pathname.
* @return {void}
*/
function redirectToStaticPage(pathname) {
const windowLocation = window.location;
let newPathname = pathname;
if (!newPathname.startsWith('/')) {
// A pathname equal to ./ specifies the current directory. It will be
// fine but pointless to include it because contextRoot is the current
// directory.
newPathname.startsWith('./')
&& (newPathname = newPathname.substring(2));
newPathname = getLocationContextRoot(windowLocation) + newPathname;
}
windowLocation.pathname = newPathname;
}
/**
* A queue for the async replaceLocalTrack action so that multiple audio
* replacements cannot happen simultaneously. This solves the issue where
@@ -273,7 +347,7 @@ class ConferenceConnector {
case JitsiConferenceErrors.NOT_ALLOWED_ERROR: {
// let's show some auth not allowed page
APP.store.dispatch(redirectToStaticPage('static/authError.html'));
redirectToStaticPage('static/authError.html');
break;
}
@@ -555,7 +629,8 @@ export default {
// Resolve with no tracks
tryCreateLocalTracks = Promise.resolve([]);
} else {
tryCreateLocalTracks = createLocalTracksF({ devices: initialDevices }, true)
tryCreateLocalTracks = createLocalTracksF(
{ devices: initialDevices }, true)
.catch(err => {
if (requestedAudio && requestedVideo) {
@@ -659,11 +734,8 @@ export default {
options.roomName, {
startAudioOnly: config.startAudioOnly,
startScreenSharing: config.startScreenSharing,
startWithAudioMuted: config.startWithAudioMuted
|| config.startSilent
|| isUserInteractionRequiredForUnmute(APP.store.getState()),
startWithAudioMuted: config.startWithAudioMuted || config.startSilent,
startWithVideoMuted: config.startWithVideoMuted
|| isUserInteractionRequiredForUnmute(APP.store.getState())
}))
.then(([ tracks, con ]) => {
tracks.forEach(track => {
@@ -764,13 +836,6 @@ export default {
* dialogs in case of media permissions error.
*/
muteAudio(mute, showUI = true) {
if (!mute
&& isUserInteractionRequiredForUnmute(APP.store.getState())) {
logger.error('Unmuting audio requires user interaction');
return;
}
// Not ready to modify track's state yet
if (!this._localTracksInitialized) {
// This will only modify base/media.audio.muted which is then synced
@@ -834,13 +899,6 @@ export default {
* dialogs in case of media permissions error.
*/
muteVideo(mute, showUI = true) {
if (!mute
&& isUserInteractionRequiredForUnmute(APP.store.getState())) {
logger.error('Unmuting video requires user interaction');
return;
}
// If not ready to modify track's state yet adjust the base/media
if (!this._localTracksInitialized) {
// This will only modify base/media.video.muted which is then synced
@@ -960,15 +1018,17 @@ export default {
* Returns the connection times stored in the library.
*/
getConnectionTimes() {
return room.getConnectionTimes();
return this._room.getConnectionTimes();
},
// used by torture currently
isJoined() {
return room && room.isJoined();
return this._room
&& this._room.isJoined();
},
getConnectionState() {
return room && room.getConnectionState();
return this._room
&& this._room.getConnectionState();
},
/**
@@ -977,7 +1037,8 @@ export default {
* P2P connection
*/
getP2PConnectionState() {
return room && room.getP2PConnectionState();
return this._room
&& this._room.getP2PConnectionState();
},
/**
@@ -986,7 +1047,7 @@ export default {
*/
_startP2P() {
try {
room && room.startP2PSession();
this._room && this._room.startP2PSession();
} catch (error) {
logger.error('Start P2P failed', error);
throw error;
@@ -999,7 +1060,7 @@ export default {
*/
_stopP2P() {
try {
room && room.stopP2PSession();
this._room && this._room.stopP2PSession();
} catch (error) {
logger.error('Stop P2P failed', error);
throw error;
@@ -1014,7 +1075,7 @@ export default {
* false otherwise.
*/
isConnectionInterrupted() {
return room.isConnectionInterrupted();
return this._room.isConnectionInterrupted();
},
/**
@@ -1075,7 +1136,7 @@ export default {
},
getMyUserId() {
return room && room.myUserId();
return this._room && this._room.myUserId();
},
/**
@@ -1098,7 +1159,7 @@ export default {
* least one track.
*/
getNumberOfParticipantsWithTracks() {
return room.getParticipants()
return this._room.getParticipants()
.filter(p => p.getTracks().length > 0)
.length;
},
@@ -1236,34 +1297,17 @@ export default {
const options = config;
const nick = APP.store.getState()['features/base/settings'].displayName;
const { locationURL } = APP.store.getState()['features/base/connection'];
if (nick) {
options.displayName = nick;
}
options.applicationName = interfaceConfig.APP_NAME;
options.getWiFiStatsMethod = this._getWiFiStatsMethod;
options.confID = `${locationURL.host}${locationURL.pathname}`;
options.getWiFiStatsMethod = getJitsiMeetGlobalNS().getWiFiStats;
return options;
},
/**
* Returns the result of getWiFiStats from the global NS or does nothing
* (returns empty result).
* Fixes a concurrency problem where we need to pass a function when creating
* JitsiConference, but that method is added to the context later.
*
* @returns {Promise}
* @private
*/
_getWiFiStatsMethod() {
const gloabalNS = getJitsiMeetGlobalNS();
return gloabalNS.getWiFiStats ? gloabalNS.getWiFiStats() : Promise.resolve('{}');
},
/**
* Start using provided video stream.
* Stops previous video stream.
@@ -1279,7 +1323,7 @@ export default {
this.localVideo = newStream;
this._setSharingScreen(newStream);
if (newStream) {
APP.UI.addLocalVideoStream(newStream);
APP.UI.addLocalStream(newStream);
}
this.setVideoMuteStatus(this.isLocalVideoMuted());
})
@@ -1330,6 +1374,9 @@ export default {
replaceLocalTrack(this.localAudio, newStream, room))
.then(() => {
this.localAudio = newStream;
if (newStream) {
APP.UI.addLocalStream(newStream);
}
this.setAudioMuteStatus(this.isLocalAudioMuted());
})
.then(resolve)
@@ -1345,7 +1392,8 @@ export default {
* @returns {boolean}
*/
isAudioOnly() {
return Boolean(APP.store.getState()['features/base/audio-only'].enabled);
return Boolean(
APP.store.getState()['features/base/conference'].audioOnly);
},
videoSwitchInProgress: false,
@@ -1709,7 +1757,14 @@ export default {
return;
}
const displayName = user.getDisplayName();
logger.log(`USER ${id} connnected:`, user);
APP.API.notifyUserJoined(id, {
displayName,
formattedDisplayName: appendSuffix(
displayName || interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME)
});
APP.UI.addUser(user);
// check the roles for the new user and reflect them
@@ -1725,7 +1780,12 @@ export default {
}
logger.log(`USER ${id} LEFT:`, user);
APP.API.notifyUserLeft(id);
APP.UI.messageHandler.participantNotification(
user.getDisplayName(),
'notify.somebody',
'disconnected',
'notify.disconnected');
APP.UI.onSharedVideoStop(id);
});
@@ -1794,12 +1854,15 @@ export default {
APP.UI.setAudioLevel(id, newLvl);
});
room.on(JitsiConferenceEvents.TRACK_MUTE_CHANGED, (track, participantThatMutedUs) => {
room.on(JitsiConferenceEvents.TRACK_MUTE_CHANGED, (_, participantThatMutedUs) => {
if (participantThatMutedUs) {
APP.store.dispatch(participantMutedUs(participantThatMutedUs));
}
});
room.on(JitsiConferenceEvents.TALK_WHILE_MUTED, () => {
APP.UI.showToolbar(6000);
});
room.on(JitsiConferenceEvents.SUBJECT_CHANGED,
subject => APP.store.dispatch(conferenceSubjectChanged(subject)));
@@ -1899,7 +1962,7 @@ export default {
room.on(JitsiConferenceEvents.KICKED, participant => {
APP.UI.hideStats();
APP.store.dispatch(kickedOut(room, participant));
APP.store.dispatch(notifyKickedOut(participant));
// FIXME close
});
@@ -1910,6 +1973,33 @@ export default {
room.on(JitsiConferenceEvents.SUSPEND_DETECTED, () => {
APP.store.dispatch(suspendDetected());
// After wake up, we will be in a state where conference is left
// there will be dialog shown to user.
// We do not want video/audio as we show an overlay and after it
// user need to rejoin or close, while waking up we can detect
// camera wakeup as a problem with device.
// We also do not care about device change, which happens
// on resume after suspending PC.
if (this.deviceChangeListener) {
JitsiMeetJS.mediaDevices.removeEventListener(
JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED,
this.deviceChangeListener);
}
// stop local video
if (this.localVideo) {
this.localVideo.dispose();
this.localVideo = null;
}
// stop local audio
if (this.localAudio) {
this.localAudio.dispose();
this.localAudio = null;
}
APP.API.notifySuspendDetected();
});
APP.UI.addListener(UIEvents.AUDIO_MUTED, muted => {
@@ -2165,27 +2255,6 @@ export default {
});
},
/**
* Cleanups local conference on suspend.
*/
onSuspendDetected() {
// After wake up, we will be in a state where conference is left
// there will be dialog shown to user.
// We do not want video/audio as we show an overlay and after it
// user need to rejoin or close, while waking up we can detect
// camera wakeup as a problem with device.
// We also do not care about device change, which happens
// on resume after suspending PC.
if (this.deviceChangeListener) {
JitsiMeetJS.mediaDevices.removeEventListener(
JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED,
this.deviceChangeListener);
}
this.localVideo = null;
this.localAudio = null;
},
/**
* Callback invoked when the conference has been successfully joined.
* Initializes the UI and various other features.
@@ -2200,7 +2269,7 @@ export default {
if (config.requireDisplayName
&& !APP.conference.getLocalDisplayName()
&& !room.isHidden()) {
&& !this._room.isHidden()) {
APP.UI.promptDisplayName();
}
@@ -2532,7 +2601,7 @@ export default {
room = undefined;
APP.API.notifyReadyToClose();
APP.store.dispatch(maybeRedirectToWelcomePage(values[0]));
maybeRedirectToWelcomePage(values[0]);
});
},
@@ -2544,11 +2613,7 @@ export default {
leaveRoomAndDisconnect() {
APP.store.dispatch(conferenceWillLeave(room));
if (room.isJoined()) {
return room.leave().then(disconnect, disconnect);
}
return disconnect();
return room.leave().then(disconnect, disconnect);
},
/**
@@ -2730,18 +2795,6 @@ export default {
*/
convertVideoToDesktop: true,
/**
* Callback invoked when the connection has been closed
* automatically. Triggers cleanup of screensharing if active.
*
* @returns {void}
*/
onConnectionClosed: () => {
if (this._untoggleScreenSharing) {
this._untoggleScreenSharing();
}
},
/**
* Callback invoked to pass messages from the local client back
* out to the external client.

View File

@@ -418,10 +418,6 @@ var config = {
// use only.
// _desktopSharingSourceDevice: 'sample-id-or-label'
// If true, any checks to handoff to another application will be prevented
// and instead the app will continue to display in the current browser.
// disableDeepLinking: false
// A property to disable the right click context menu for localVideo
// the menu has option to flip the locally seen video for local presentations
// disableLocalVideoFlip: false

View File

@@ -1,31 +0,0 @@
.avatar {
align-items: center;
background-color: #AAA;
display: flex;
border-radius: 50%;
color: rgba(255, 255, 255, 0.6);
font-weight: 100;
justify-content: center;
object-fit: cover;
}
.avatar-foreign {
align-items: center;
bottom: 0;
display: flex;
font-size: 40pt;
justify-content: center;
left: 0;
position: absolute;
right: 0;
top: 0;
}
.avatar-svg {
height: 100%;
width: 100%;
}
.defaultAvatar {
opacity: 0.6
}

View File

@@ -1,12 +1,12 @@
@font-face {
font-family: 'jitsi';
src: url('../fonts/jitsi.eot?icrce1');
src: url('../fonts/jitsi.eot?icrce1#iefix') format('embedded-opentype'),
url('../fonts/jitsi.ttf?icrce1') format('truetype'),
url('../fonts/jitsi.woff?icrce1') format('woff'),
url('../fonts/jitsi.svg?icrce1#jitsi') format('svg');
font-weight: normal;
font-style: normal;
font-family: 'jitsi';
src: url('../fonts/jitsi.eot?3vw865');
src: url('../fonts/jitsi.eot?3vw865#iefix') format('embedded-opentype'),
url('../fonts/jitsi.ttf?3vw865') format('truetype'),
url('../fonts/jitsi.woff?3vw865') format('woff'),
url('../fonts/jitsi.svg?3vw865#jitsi') format('svg');
font-weight: normal;
font-style: normal;
}
[class^="icon-"], [class*=" icon-"] {
@@ -25,12 +25,92 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-send:before {
content: "\e911";
.icon-enlarge:before {
content: "\e90a";
}
.icon-blur-background:before {
content: "\e90f";
color: #a4b8d1;
.icon-signal_cellular_0:before {
content: "\e901";
}
.icon-signal_cellular_1:before {
content: "\e902";
}
.icon-signal_cellular_2:before {
content: "\e907";
}
.icon-phone:before {
content: "\e0cd";
}
.icon-radio_button_unchecked:before {
content: "\e836";
}
.icon-radio_button_checked:before {
content: "\e837";
}
.icon-search:before {
content: "\e8b6";
}
.icon-chat-unread:before {
content: "\e0b7";
}
.icon-closed_caption:before {
content: "\e930";
}
.icon-tiles-many:before {
content: "\e92e";
}
.icon-close:before {
content: "\e5cd";
}
.icon-open_in_new:before {
content: "\e89e";
}
.icon-restore:before {
content: "\e8b3";
}
.icon-navigate_next:before {
content: "\e409";
}
.icon-menu:before {
content: "\e5d2";
}
.icon-arrow_back:before {
content: "\e5c4";
}
.icon-public:before {
content: "\e80b";
}
.icon-event_note:before {
content: "\e616";
}
.icon-bluetooth:before {
content: "\e1aa";
}
.icon-headset:before {
content: "\e310";
}
.icon-phone-talk:before {
content: "\e61d";
}
.icon-thumb-menu:before {
content: "\e5d4";
}
.icon-ninja:before {
content: "\e909";
}
.icon-invite:before {
content: "\e145";
}
.icon-add:before {
content: "\e146";
}
.icon-play:before {
content: "\f04b";
}
.icon-stop:before {
content: "\f04d";
}
.icon-dominant-speaker:before {
content: "\f0a1";
}
.icon-speaker:before {
content: "\e92d";
@@ -140,90 +220,3 @@
.icon-visibility-off:before {
content: "\e924";
}
.icon-enlarge:before {
content: "\e90a";
}
.icon-signal_cellular_0:before {
content: "\e901";
}
.icon-signal_cellular_1:before {
content: "\e902";
}
.icon-signal_cellular_2:before {
content: "\e907";
}
.icon-phone:before {
content: "\e0cd";
}
.icon-radio_button_unchecked:before {
content: "\e836";
}
.icon-radio_button_checked:before {
content: "\e837";
}
.icon-search:before {
content: "\e8b6";
}
.icon-chat-unread:before {
content: "\e0b7";
}
.icon-closed_caption:before {
content: "\e930";
}
.icon-tiles-many:before {
content: "\e92e";
}
.icon-close:before {
content: "\e5cd";
}
.icon-open_in_new:before {
content: "\e89e";
}
.icon-restore:before {
content: "\e8b3";
}
.icon-navigate_next:before {
content: "\e409";
}
.icon-menu:before {
content: "\e5d2";
}
.icon-arrow_back:before {
content: "\e5c4";
}
.icon-public:before {
content: "\e80b";
}
.icon-event_note:before {
content: "\e616";
}
.icon-bluetooth:before {
content: "\e1aa";
}
.icon-headset:before {
content: "\e310";
}
.icon-phone-talk:before {
content: "\e61d";
}
.icon-thumb-menu:before {
content: "\e5d4";
}
.icon-ninja:before {
content: "\e909";
}
.icon-invite:before {
content: "\e145";
}
.icon-add:before {
content: "\e146";
}
.icon-play:before {
content: "\f04b";
}
.icon-stop:before {
content: "\f04d";
}
.icon-dominant-speaker:before {
content: "\f0a1";
}

View File

@@ -493,6 +493,7 @@
}
#dominantSpeakerAvatarContainer,
#dominantSpeakerAvatar,
.dynamic-shadow {
width: 200px;
height: 200px;
@@ -502,9 +503,14 @@
top: 50px;
margin: auto;
position: relative;
border-radius: 100px;
overflow: hidden;
visibility: inherit;
}
#dominantSpeakerAvatar {
background-color: #000000;
object-fit: cover;
}
.dynamic-shadow {
border-radius: 50%;
@@ -518,6 +524,7 @@
.avatar-container {
@include maxSize(60px);
@include absoluteAligning();
border-radius: 50%;
display: flex;
justify-content: center;
height: 50%;

View File

@@ -86,6 +86,5 @@ $flagsImagePath: "../images/";
@import 'navigate_section_list';
@import 'third-party-branding/google';
@import 'third-party-branding/microsoft';
@import 'avatar';
/* Modules END */

7
debian/rules vendored
View File

@@ -17,15 +17,8 @@ override_dh_install: $(LANGUAGES)
dh_install -X/config.js -X/package.json
$(LANGUAGES):
LOCALE=$$(echo $@ | cut -c1-2) ; \
if [ -f $(COUNTRIES_DIR)/$@.json ] ; \
then \
dh_install -pjitsi-meet-web $(COUNTRIES_DIR)/$@.json usr/share/jitsi-meet/lang/; \
mv debian/jitsi-meet-web/usr/share/jitsi-meet/lang/$@.json debian/jitsi-meet-web/usr/share/jitsi-meet/lang/countries-$@.json; \
else \
if [ -f $(COUNTRIES_DIR)/$$LOCALE.json ] ; \
then \
dh_install -pjitsi-meet-web $(COUNTRIES_DIR)/$$LOCALE.json usr/share/jitsi-meet/lang/; \
mv debian/jitsi-meet-web/usr/share/jitsi-meet/lang/$$LOCALE.json debian/jitsi-meet-web/usr/share/jitsi-meet/lang/countries-$@.json; \
fi; \
fi;

View File

@@ -322,13 +322,6 @@ changes. The listener will receive an object with the following structure:
}
```
* **dominantSpeakerChanged** - receives event notifications about change in the dominant speaker. The listener will receive object with the following structure:
```javascript
{
id: string //participantId of the new dominant speaker
}
```
* **tileViewChanged** - event notifications about tile view layout mode being entered or exited. The listener will receive object with the following structure:
```javascript
{
@@ -379,13 +372,6 @@ changes. The listener will receive an object with the following structure:
email: string // the new email
}
```
* **feedbackSubmitted** - event notifications about conference feedback submission
```javascript
{
error: string // The error which occurred during submission, if any.
}
```
* **filmstripDisplayChanged** - event notifications about the visibility of the filmstrip being updated.
```javascript
{
@@ -401,19 +387,6 @@ changes. The listener will receive an object with the following structure:
}
```
* **participantKickedOut** - event notifications about a participants being removed from the room. The listener will receive an object with the following structure:
```javascript
{
kicked: {
id: string, // the id of the participant removed from the room
local: boolean // whether or not the participant is the local particiapnt
},
kicker: {
id: string // the id of the participant who kicked out the other participant
}
}
```
* **participantLeft** - event notifications about participants that leave the room. The listener will receive an object with the following structure:
```javascript
{

View File

@@ -1,5 +1,5 @@
// flow-typed signature: 4e6a5da3290fe9ea49e6bcdced64f358
// flow-typed version: c6154227d1/flow-bin_v0.x.x/flow_>=v0.25.x <=v0.103.x
// flow-typed signature: 6a5610678d4b01e13bbfbbc62bdaf583
// flow-typed version: 3817bc6980/flow-bin_v0.x.x/flow_>=v0.25.x
declare module "flow-bin" {
declare module.exports: string;

View File

@@ -1,5 +1,5 @@
// flow-typed signature: 538d762382091f2239d2d55cab1b574d
// flow-typed version: c6154227d1/jquery_v3.x.x/flow_>=v0.28.x <=v0.103.x
// flow-typed signature: f26fda66e3a551aef37d3b0f53058e6a
// flow-typed version: 44ad941b7a/jquery_v3.x.x/flow_>=v0.28.x
/* eslint-disable max-len, no-unused-vars, flowtype/no-weak-types */

View File

@@ -1,5 +1,5 @@
// flow-typed signature: 96e97db746b98786dbff6de500b4b862
// flow-typed version: 5fe02f287a/lodash_v4.x.x/flow_>=v0.63.x <=v0.103.x
// flow-typed signature: a9b75804169260d49cda34b56dcfabe1
// flow-typed version: e9dac1347c/lodash_v4.x.x/flow_>=v0.63.x
declare module "lodash" {
declare type Path = $ReadOnlyArray<string | number> | string | number;
@@ -149,11 +149,6 @@ declare module "lodash" {
separator?: RegExp | string
};
declare type Cancelable = {
cancel: () => void,
flush: () => mixed
};
declare type DebounceOptions = {
leading?: boolean,
maxWait?: number,
@@ -270,14 +265,14 @@ declare module "lodash" {
): -1;
// alias of _.head
first<T>(array: ?$ReadOnlyArray<T>): T;
flatten<T, X>(array?: ?$ReadOnlyArray<$ReadOnlyArray<T> | X>): Array<T | X>;
flatten<T, X>(array?: ?Array<Array<T> | X>): Array<T | X>;
flattenDeep<T>(array?: ?(any[])): Array<T>;
flattenDepth(array?: ?(any[]), depth?: ?number): any[];
fromPairs<A, B>(pairs?: ?Array<[A, B]>): { [key: A]: B };
head<T>(array: ?$ReadOnlyArray<T>): T;
indexOf<T>(array: $ReadOnlyArray<T>, value: T, fromIndex?: number): number;
indexOf<T>(array: Array<T>, value: T, fromIndex?: number): number;
indexOf<T>(array: void | null, value?: ?T, fromIndex?: ?number): -1;
initial<T>(array: ?$ReadOnlyArray<T>): Array<T>;
initial<T>(array: ?Array<T>): Array<T>;
intersection<T>(...arrays?: Array<$ReadOnlyArray<T>>): Array<T>;
//Workaround until (...parameter: T, parameter2: U) works
intersectionBy<T>(
@@ -325,10 +320,10 @@ declare module "lodash" {
a4?: ?$ReadOnlyArray<T>,
comparator?: ?Comparator<T>
): Array<T>;
join<T>(array: $ReadOnlyArray<T>, separator?: ?string): string;
join<T>(array: Array<T>, separator?: ?string): string;
join<T>(array: void | null, separator?: ?string): "";
last<T>(array: ?$ReadOnlyArray<T>): T;
lastIndexOf<T>(array: $ReadOnlyArray<T>, value?: ?T, fromIndex?: ?number): number;
lastIndexOf<T>(array: Array<T>, value?: ?T, fromIndex?: ?number): number;
lastIndexOf<T>(array: void | null, value?: ?T, fromIndex?: ?number): -1;
nth<T>(array: T[], n?: ?number): T;
nth(array: void | null, n?: ?number): void;
@@ -362,10 +357,10 @@ declare module "lodash" {
start?: ?number,
end?: ?number
): Array<T>;
sortedIndex<T>(array: $ReadOnlyArray<T>, value: T): number;
sortedIndex<T>(array: Array<T>, value: T): number;
sortedIndex<T>(array: void | null, value: ?T): 0;
sortedIndexBy<T>(
array: $ReadOnlyArray<T>,
array: Array<T>,
value?: ?T,
iteratee?: ?ValueOnlyIteratee<T>
): number;
@@ -374,12 +369,12 @@ declare module "lodash" {
value?: ?T,
iteratee?: ?ValueOnlyIteratee<T>
): 0;
sortedIndexOf<T>(array: $ReadOnlyArray<T>, value: T): number;
sortedIndexOf<T>(array: Array<T>, value: T): number;
sortedIndexOf<T>(array: void | null, value?: ?T): -1;
sortedLastIndex<T>(array: $ReadOnlyArray<T>, value: T): number;
sortedLastIndex<T>(array: Array<T>, value: T): number;
sortedLastIndex<T>(array: void | null, value?: ?T): 0;
sortedLastIndexBy<T>(
array: $ReadOnlyArray<T>,
array: Array<T>,
value: T,
iteratee?: ValueOnlyIteratee<T>
): number;
@@ -388,16 +383,16 @@ declare module "lodash" {
value?: ?T,
iteratee?: ?ValueOnlyIteratee<T>
): 0;
sortedLastIndexOf<T>(array: $ReadOnlyArray<T>, value: T): number;
sortedLastIndexOf<T>(array: Array<T>, value: T): number;
sortedLastIndexOf<T>(array: void | null, value?: ?T): -1;
sortedUniq<T>(array?: ?$ReadOnlyArray<T>): Array<T>;
sortedUniq<T>(array?: ?Array<T>): Array<T>;
sortedUniqBy<T>(
array?: ?$ReadOnlyArray<T>,
array?: ?Array<T>,
iteratee?: ?ValueOnlyIteratee<T>
): Array<T>;
tail<T>(array?: ?$ReadOnlyArray<T>): Array<T>;
take<T>(array?: ?$ReadOnlyArray<T>, n?: ?number): Array<T>;
takeRight<T>(array?: ?$ReadOnlyArray<T>, n?: ?number): Array<T>;
tail<T>(array?: ?Array<T>): Array<T>;
take<T>(array?: ?Array<T>, n?: ?number): Array<T>;
takeRight<T>(array?: ?Array<T>, n?: ?number): Array<T>;
takeRightWhile<T>(array?: ?Array<T>, predicate?: ?Predicate<T>): Array<T>;
takeWhile<T>(array?: ?Array<T>, predicate?: ?Predicate<T>): Array<T>;
union<T>(...arrays?: Array<$ReadOnlyArray<T>>): Array<T>;
@@ -447,59 +442,59 @@ declare module "lodash" {
uniq<T>(array?: ?$ReadOnlyArray<T>): Array<T>;
uniqBy<T>(array?: ?$ReadOnlyArray<T>, iteratee?: ?ValueOnlyIteratee<T>): Array<T>;
uniqWith<T>(array?: ?$ReadOnlyArray<T>, comparator?: ?Comparator<T>): Array<T>;
unzip<T>(array?: ?$ReadOnlyArray<T>): Array<T>;
unzip<T>(array?: ?Array<T>): Array<T>;
unzipWith<T>(array: ?Array<T>, iteratee?: ?Iteratee<T>): Array<T>;
without<T>(array?: ?$ReadOnlyArray<T>, ...values?: Array<?T>): Array<T>;
xor<T>(...array: Array<Array<T>>): Array<T>;
//Workaround until (...parameter: T, parameter2: U) works
xorBy<T>(a1?: ?$ReadOnlyArray<T>, iteratee?: ?ValueOnlyIteratee<T>): Array<T>;
xorBy<T>(a1?: ?Array<T>, iteratee?: ?ValueOnlyIteratee<T>): Array<T>;
xorBy<T>(
a1: $ReadOnlyArray<T>,
a2: $ReadOnlyArray<T>,
a1: Array<T>,
a2: Array<T>,
iteratee?: ValueOnlyIteratee<T>
): Array<T>;
xorBy<T>(
a1: $ReadOnlyArray<T>,
a2: $ReadOnlyArray<T>,
a3: $ReadOnlyArray<T>,
a1: Array<T>,
a2: Array<T>,
a3: Array<T>,
iteratee?: ValueOnlyIteratee<T>
): Array<T>;
xorBy<T>(
a1: $ReadOnlyArray<T>,
a2: $ReadOnlyArray<T>,
a3: $ReadOnlyArray<T>,
a4: $ReadOnlyArray<T>,
a1: Array<T>,
a2: Array<T>,
a3: Array<T>,
a4: Array<T>,
iteratee?: ValueOnlyIteratee<T>
): Array<T>;
//Workaround until (...parameter: T, parameter2: U) works
xorWith<T>(a1?: ?$ReadOnlyArray<T>, comparator?: ?Comparator<T>): Array<T>;
xorWith<T>(a1?: ?Array<T>, comparator?: ?Comparator<T>): Array<T>;
xorWith<T>(
a1: $ReadOnlyArray<T>,
a2: $ReadOnlyArray<T>,
a1: Array<T>,
a2: Array<T>,
comparator?: Comparator<T>
): Array<T>;
xorWith<T>(
a1: $ReadOnlyArray<T>,
a2: $ReadOnlyArray<T>,
a3: $ReadOnlyArray<T>,
a1: Array<T>,
a2: Array<T>,
a3: Array<T>,
comparator?: Comparator<T>
): Array<T>;
xorWith<T>(
a1: $ReadOnlyArray<T>,
a2: $ReadOnlyArray<T>,
a3: $ReadOnlyArray<T>,
a4: $ReadOnlyArray<T>,
a1: Array<T>,
a2: Array<T>,
a3: Array<T>,
a4: Array<T>,
comparator?: Comparator<T>
): Array<T>;
zip<A, B>(a1?: ?($ReadOnlyArray<A>), a2?: ?($ReadOnlyArray<B>)): Array<[A, B]>;
zip<A, B, C>(a1: $ReadOnlyArray<A>, a2: $ReadOnlyArray<B>, a3: $ReadOnlyArray<C>): Array<[A, B, C]>;
zip<A, B, C, D>(a1: $ReadOnlyArray<A>, a2: $ReadOnlyArray<B>, a3: $ReadOnlyArray<C>, a4: $ReadOnlyArray<D>): Array<[A, B, C, D]>;
zip<A, B>(a1?: ?(A[]), a2?: ?(B[])): Array<[A, B]>;
zip<A, B, C>(a1: A[], a2: B[], a3: C[]): Array<[A, B, C]>;
zip<A, B, C, D>(a1: A[], a2: B[], a3: C[], a4: D[]): Array<[A, B, C, D]>;
zip<A, B, C, D, E>(
a1: $ReadOnlyArray<A>,
a2: $ReadOnlyArray<B>,
a3: $ReadOnlyArray<C>,
a4: $ReadOnlyArray<D>,
a5: $ReadOnlyArray<E>
a1: A[],
a2: B[],
a3: C[],
a4: D[],
a5: E[]
): Array<[A, B, C, D, E]>;
zipObject<K, V>(props: Array<K>, values?: ?Array<V>): { [key: K]: V };
@@ -507,44 +502,44 @@ declare module "lodash" {
zipObjectDeep(props: any[], values?: ?any): Object;
zipObjectDeep(props: void | null, values?: ?any): {};
zipWith<A>(a1?: ?$ReadOnlyArray<A>): Array<[A]>;
zipWith<T, A>(a1: $ReadOnlyArray<A>, iteratee: (A) => T): Array<T>;
zipWith<A>(a1?: ?Array<A>): Array<[A]>;
zipWith<T, A>(a1: Array<A>, iteratee: (A) => T): Array<T>;
zipWith<A, B>(a1: $ReadOnlyArray<A>, a2: $ReadOnlyArray<B>): Array<[A, B]>;
zipWith<A, B>(a1: Array<A>, a2: Array<B>): Array<[A, B]>;
zipWith<T, A, B>(
a1: $ReadOnlyArray<A>,
a2: $ReadOnlyArray<B>,
a1: Array<A>,
a2: Array<B>,
iteratee: (A, B) => T
): $ReadOnlyArray<T>;
): Array<T>;
zipWith<A, B, C>(
a1: $ReadOnlyArray<A>,
a2: $ReadOnlyArray<B>,
a3: $ReadOnlyArray<C>
a1: Array<A>,
a2: Array<B>,
a3: Array<C>
): Array<[A, B, C]>;
zipWith<T, A, B, C>(
a1: $ReadOnlyArray<A>,
a2: $ReadOnlyArray<B>,
a3: $ReadOnlyArray<C>,
a1: Array<A>,
a2: Array<B>,
a3: Array<C>,
iteratee: (A, B, C) => T
): Array<T>;
zipWith<A, B, C, D>(
a1: $ReadOnlyArray<A>,
a2: $ReadOnlyArray<B>,
a3: $ReadOnlyArray<C>,
a4: $ReadOnlyArray<D>
a1: Array<A>,
a2: Array<B>,
a3: Array<C>,
a4: Array<D>
): Array<[A, B, C, D]>;
zipWith<T, A, B, C, D>(
a1: $ReadOnlyArray<A>,
a2: $ReadOnlyArray<B>,
a3: $ReadOnlyArray<C>,
a4: $ReadOnlyArray<D>,
a1: Array<A>,
a2: Array<B>,
a3: Array<C>,
a4: Array<D>,
iteratee: (A, B, C, D) => T
): Array<T>;
// Collection
countBy<T>(array: $ReadOnlyArray<T>, iteratee?: ?ValueOnlyIteratee<T>): Object;
countBy<T>(array: Array<T>, iteratee?: ?ValueOnlyIteratee<T>): Object;
countBy<T>(array: void | null, iteratee?: ?ValueOnlyIteratee<T>): {};
countBy<T: Object>(object: T, iteratee?: ?ValueOnlyIteratee<T>): Object;
// alias of _.forEach
@@ -680,7 +675,7 @@ declare module "lodash" {
iteratees?: ?$ReadOnlyArray<Iteratee<T>> | ?string,
orders?: ?$ReadOnlyArray<"asc" | "desc"> | ?string
): Array<T>;
orderBy<V, T: {}>(
orderBy<V, T: Object>(
object: T,
iteratees?: $ReadOnlyArray<OIteratee<*>> | string,
orders?: $ReadOnlyArray<"asc" | "desc"> | string
@@ -748,11 +743,11 @@ declare module "lodash" {
object?: ?T,
predicate?: ?OPredicate<A, T>
): Array<V>;
sample<T>(array: ?$ReadOnlyArray<T>): T;
sample<T>(array: ?Array<T>): T;
sample<V, T: Object>(object: T): V;
sampleSize<T>(array?: ?$ReadOnlyArray<T>, n?: ?number): Array<T>;
sampleSize<T>(array?: ?Array<T>, n?: ?number): Array<T>;
sampleSize<V, T: Object>(object: T, n?: number): Array<V>;
shuffle<T>(array: ?$ReadOnlyArray<T>): Array<T>;
shuffle<T>(array: ?Array<T>): Array<T>;
shuffle<V, T: Object>(object: T): Array<V>;
size(collection: $ReadOnlyArray<any> | Object | string): number;
some<T>(array: void | null, predicate?: ?Predicate<T>): false;
@@ -790,11 +785,7 @@ declare module "lodash" {
curry: Curry;
curry(func: Function, arity?: number): Function;
curryRight(func: Function, arity?: number): Function;
debounce<F: (...any[]) => any>(
func: F,
wait?: number,
options?: DebounceOptions
): F & Cancelable;
debounce<F: (...any[]) => any>(func: F, wait?: number, options?: DebounceOptions): F;
defer(func: (...any[]) => any, ...args?: Array<any>): TimeoutID;
delay(func: Function, wait: number, ...args?: Array<any>): TimeoutID;
flip<R>(func: (...any[]) => R): (...any[]) => R;
@@ -814,7 +805,7 @@ declare module "lodash" {
func: F,
wait?: number,
options?: ThrottleOptions
): F & Cancelable;
): F;
unary<F: (...any[]) => any>(func: F): F;
wrap(value?: any, wrapper?: ?Function): Function;
@@ -839,13 +830,13 @@ declare module "lodash" {
gte(value: any, other: any): boolean;
isArguments(value: void | null): false;
isArguments(value: any): boolean;
isArray(value: $ReadOnlyArray<any>): true;
isArray(value: Array<any>): true;
isArray(value: any): false;
isArrayBuffer(value: ArrayBuffer): true;
isArrayBuffer(value: any): false;
isArrayLike(value: $ReadOnlyArray<any> | string | { length: number }): true;
isArrayLike(value: Array<any> | string | { length: number }): true;
isArrayLike(value: any): false;
isArrayLikeObject(value: { length: number } | $ReadOnlyArray<any>): true;
isArrayLikeObject(value: { length: number } | Array<any>): true;
isArrayLikeObject(value: any): false;
isBoolean(value: boolean): true;
isBoolean(value: any): false;
@@ -948,16 +939,16 @@ declare module "lodash" {
ceil(number: number, precision?: number): number;
divide(dividend: number, divisor: number): number;
floor(number: number, precision?: number): number;
max<T>(array: ?$ReadOnlyArray<T>): T;
max<T>(array: ?Array<T>): T;
maxBy<T>(array: ?$ReadOnlyArray<T>, iteratee?: Iteratee<T>): T;
mean(array: $ReadOnlyArray<*>): number;
mean(array: Array<*>): number;
meanBy<T>(array: Array<T>, iteratee?: Iteratee<T>): number;
min<T>(array: ?$ReadOnlyArray<T>): T;
min<T>(array: ?Array<T>): T;
minBy<T>(array: ?$ReadOnlyArray<T>, iteratee?: Iteratee<T>): T;
multiply(multiplier: number, multiplicand: number): number;
round(number: number, precision?: number): number;
subtract(minuend: number, subtrahend: number): number;
sum(array: $ReadOnlyArray<*>): number;
sum(array: Array<*>): number;
sumBy<T>(array: $ReadOnlyArray<T>, iteratee?: Iteratee<T>): number;
// number
@@ -1075,8 +1066,8 @@ declare module "lodash" {
source: A | B | C | D
) => any | void
): Object;
at(object?: ?Object, ...paths: $ReadOnlyArray<string>): Array<any>;
at(object?: ?Object, paths: $ReadOnlyArray<string>): Array<any>;
at(object?: ?Object, ...paths: Array<string>): Array<any>;
at(object?: ?Object, paths: Array<string>): Array<any>;
create(prototype: void | null, properties: void | null): {};
create<T>(prototype: T, properties: Object): T;
create(prototype: any, properties: void | null): {};
@@ -1246,15 +1237,15 @@ declare module "lodash" {
source: A | B | C | D
) => any | void
): Object;
omit(object?: ?Object, ...props: $ReadOnlyArray<string>): Object;
omit(object?: ?Object, props: $ReadOnlyArray<string>): Object;
omit(object?: ?Object, ...props: Array<string>): Object;
omit(object?: ?Object, props: Array<string>): Object;
omitBy<A, T: { [id: any]: A } | { [id: number]: A }>(
object: T,
predicate?: ?OPredicate<A, T>
): Object;
omitBy<A, T>(object: void | null, predicate?: ?OPredicate<A, T>): {};
pick(object?: ?Object, ...props: $ReadOnlyArray<string>): Object;
pick(object?: ?Object, props: $ReadOnlyArray<string>): Object;
pick(object?: ?Object, ...props: Array<string>): Object;
pick(object?: ?Object, props: Array<string>): Object;
pickBy<A, T: { [id: any]: A } | { [id: number]: A }>(
object: T,
predicate?: ?OPredicate<A, T>
@@ -1767,65 +1758,65 @@ declare module "lodash/fp" {
): number;
// alias of _.head
first<T>(array: $ReadOnlyArray<T>): T;
flatten<T, X>(array: $ReadOnlyArray<$ReadOnlyArray<T> | X>): Array<T | X>;
flatten<T, X>(array: Array<Array<T> | X>): Array<T | X>;
unnest<T, X>(array: Array<Array<T> | X>): Array<T | X>;
flattenDeep<T>(array: any[]): Array<T>;
flattenDepth(depth: number): (array: any[]) => any[];
flattenDepth(depth: number, array: any[]): any[];
fromPairs<A, B>(pairs: Array<[A, B]>): { [key: A]: B };
head<T>(array: $ReadOnlyArray<T>): T;
indexOf<T>(value: T): (array: $ReadOnlyArray<T>) => number;
indexOf<T>(value: T, array: $ReadOnlyArray<T>): number;
indexOf<T>(value: T): (array: Array<T>) => number;
indexOf<T>(value: T, array: Array<T>): number;
indexOfFrom<T>(
value: T
): ((fromIndex: number) => (array: $ReadOnlyArray<T>) => number) &
((fromIndex: number, array: $ReadOnlyArray<T>) => number);
indexOfFrom<T>(value: T, fromIndex: number): (array: $ReadOnlyArray<T>) => number;
indexOfFrom<T>(value: T, fromIndex: number, array: $ReadOnlyArray<T>): number;
initial<T>(array: $ReadOnlyArray<T>): Array<T>;
): ((fromIndex: number) => (array: Array<T>) => number) &
((fromIndex: number, array: Array<T>) => number);
indexOfFrom<T>(value: T, fromIndex: number): (array: Array<T>) => number;
indexOfFrom<T>(value: T, fromIndex: number, array: Array<T>): number;
initial<T>(array: Array<T>): Array<T>;
init<T>(array: Array<T>): Array<T>;
intersection<T>(a1: $ReadOnlyArray<T>): (a2: $ReadOnlyArray<T>) => Array<T>;
intersection<T>(a1: $ReadOnlyArray<T>, a2: $ReadOnlyArray<T>): Array<T>;
intersection<T>(a1: Array<T>): (a2: Array<T>) => Array<T>;
intersection<T>(a1: Array<T>, a2: Array<T>): Array<T>;
intersectionBy<T>(
iteratee: ValueOnlyIteratee<T>
): ((a1: $ReadOnlyArray<T>) => (a2: $ReadOnlyArray<T>) => Array<T>) &
((a1: $ReadOnlyArray<T>, a2: $ReadOnlyArray<T>) => Array<T>);
): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
((a1: Array<T>, a2: Array<T>) => Array<T>);
intersectionBy<T>(
iteratee: ValueOnlyIteratee<T>,
a1: $ReadOnlyArray<T>
a1: Array<T>
): (a2: Array<T>) => Array<T>;
intersectionBy<T>(
iteratee: ValueOnlyIteratee<T>,
a1: $ReadOnlyArray<T>,
a2: $ReadOnlyArray<T>
a1: Array<T>,
a2: Array<T>
): Array<T>;
intersectionWith<T>(
comparator: Comparator<T>
): ((a1: $ReadOnlyArray<T>) => (a2: $ReadOnlyArray<T>) => Array<T>) &
((a1: $ReadOnlyArray<T>, a2: $ReadOnlyArray<T>) => Array<T>);
): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
((a1: Array<T>, a2: Array<T>) => Array<T>);
intersectionWith<T>(
comparator: Comparator<T>,
a1: $ReadOnlyArray<T>
): (a2: $ReadOnlyArray<T>) => Array<T>;
a1: Array<T>
): (a2: Array<T>) => Array<T>;
intersectionWith<T>(
comparator: Comparator<T>,
a1: $ReadOnlyArray<T>,
a2: $ReadOnlyArray<T>
a1: Array<T>,
a2: Array<T>
): Array<T>;
join<T>(separator: string): (array: $ReadOnlyArray<T>) => string;
join<T>(separator: string, array: $ReadOnlyArray<T>): string;
last<T>(array: $ReadOnlyArray<T>): T;
lastIndexOf<T>(value: T): (array: $ReadOnlyArray<T>) => number;
lastIndexOf<T>(value: T, array: $ReadOnlyArray<T>): number;
join<T>(separator: string): (array: Array<T>) => string;
join<T>(separator: string, array: Array<T>): string;
last<T>(array: Array<T>): T;
lastIndexOf<T>(value: T): (array: Array<T>) => number;
lastIndexOf<T>(value: T, array: Array<T>): number;
lastIndexOfFrom<T>(
value: T
): ((fromIndex: number) => (array: $ReadOnlyArray<T>) => number) &
((fromIndex: number, array: $ReadOnlyArray<T>) => number);
): ((fromIndex: number) => (array: Array<T>) => number) &
((fromIndex: number, array: Array<T>) => number);
lastIndexOfFrom<T>(
value: T,
fromIndex: number
): (array: $ReadOnlyArray<T>) => number;
lastIndexOfFrom<T>(value: T, fromIndex: number, array: $ReadOnlyArray<T>): number;
): (array: Array<T>) => number;
lastIndexOfFrom<T>(value: T, fromIndex: number, array: Array<T>): number;
nth<T>(n: number): (array: T[]) => T;
nth<T>(n: number, array: T[]): T;
pull<T>(value: T): (array: Array<T>) => Array<T>;
@@ -1858,154 +1849,154 @@ declare module "lodash/fp" {
reverse<T>(array: Array<T>): Array<T>;
slice<T>(
start: number
): ((end: number) => (array: $ReadOnlyArray<T>) => Array<T>) &
((end: number, array: $ReadOnlyArray<T>) => Array<T>);
slice<T>(start: number, end: number): (array: $ReadOnlyArray<T>) => Array<T>;
slice<T>(start: number, end: number, array: $ReadOnlyArray<T>): Array<T>;
sortedIndex<T>(value: T): (array: $ReadOnlyArray<T>) => number;
sortedIndex<T>(value: T, array: $ReadOnlyArray<T>): number;
): ((end: number) => (array: Array<T>) => Array<T>) &
((end: number, array: Array<T>) => Array<T>);
slice<T>(start: number, end: number): (array: Array<T>) => Array<T>;
slice<T>(start: number, end: number, array: Array<T>): Array<T>;
sortedIndex<T>(value: T): (array: Array<T>) => number;
sortedIndex<T>(value: T, array: Array<T>): number;
sortedIndexBy<T>(
iteratee: ValueOnlyIteratee<T>
): ((value: T) => (array: $ReadOnlyArray<T>) => number) &
): ((value: T) => (array: Array<T>) => number) &
((value: T, array: Array<T>) => number);
sortedIndexBy<T>(
iteratee: ValueOnlyIteratee<T>,
value: T
): (array: $ReadOnlyArray<T>) => number;
): (array: Array<T>) => number;
sortedIndexBy<T>(
iteratee: ValueOnlyIteratee<T>,
value: T,
array: $ReadOnlyArray<T>
array: Array<T>
): number;
sortedIndexOf<T>(value: T): (array: $ReadOnlyArray<T>) => number;
sortedIndexOf<T>(value: T, array: $ReadOnlyArray<T>): number;
sortedLastIndex<T>(value: T): (array: $ReadOnlyArray<T>) => number;
sortedLastIndex<T>(value: T, array: $ReadOnlyArray<T>): number;
sortedIndexOf<T>(value: T): (array: Array<T>) => number;
sortedIndexOf<T>(value: T, array: Array<T>): number;
sortedLastIndex<T>(value: T): (array: Array<T>) => number;
sortedLastIndex<T>(value: T, array: Array<T>): number;
sortedLastIndexBy<T>(
iteratee: ValueOnlyIteratee<T>
): ((value: T) => (array: $ReadOnlyArray<T>) => number) &
): ((value: T) => (array: Array<T>) => number) &
((value: T, array: Array<T>) => number);
sortedLastIndexBy<T>(
iteratee: ValueOnlyIteratee<T>,
value: T
): (array: $ReadOnlyArray<T>) => number;
): (array: Array<T>) => number;
sortedLastIndexBy<T>(
iteratee: ValueOnlyIteratee<T>,
value: T,
array: $ReadOnlyArray<T>
array: Array<T>
): number;
sortedLastIndexOf<T>(value: T): (array: $ReadOnlyArray<T>) => number;
sortedLastIndexOf<T>(value: T, array: $ReadOnlyArray<T>): number;
sortedUniq<T>(array: $ReadOnlyArray<T>): Array<T>;
sortedUniqBy<T>(iteratee: ValueOnlyIteratee<T>, array: $ReadOnlyArray<T>): Array<T>;
tail<T>(array: $ReadOnlyArray<T>): Array<T>;
take<T>(n: number): (array: $ReadOnlyArray<T>) => Array<T>;
take<T>(n: number, array: $ReadOnlyArray<T>): Array<T>;
takeRight<T>(n: number): (array: $ReadOnlyArray<T>) => Array<T>;
takeRight<T>(n: number, array: $ReadOnlyArray<T>): Array<T>;
takeLast<T>(n: number): (array: $ReadOnlyArray<T>) => Array<T>;
takeLast<T>(n: number, array: $ReadOnlyArray<T>): Array<T>;
sortedLastIndexOf<T>(value: T): (array: Array<T>) => number;
sortedLastIndexOf<T>(value: T, array: Array<T>): number;
sortedUniq<T>(array: Array<T>): Array<T>;
sortedUniqBy<T>(iteratee: ValueOnlyIteratee<T>, array: Array<T>): Array<T>;
tail<T>(array: Array<T>): Array<T>;
take<T>(n: number): (array: Array<T>) => Array<T>;
take<T>(n: number, array: Array<T>): Array<T>;
takeRight<T>(n: number): (array: Array<T>) => Array<T>;
takeRight<T>(n: number, array: Array<T>): Array<T>;
takeLast<T>(n: number): (array: Array<T>) => Array<T>;
takeLast<T>(n: number, array: Array<T>): Array<T>;
takeRightWhile<T>(predicate: Predicate<T>): (array: Array<T>) => Array<T>;
takeRightWhile<T>(predicate: Predicate<T>, array: Array<T>): Array<T>;
takeLastWhile<T>(predicate: Predicate<T>): (array: Array<T>) => Array<T>;
takeLastWhile<T>(predicate: Predicate<T>, array: Array<T>): Array<T>;
takeWhile<T>(predicate: Predicate<T>): (array: Array<T>) => Array<T>;
takeWhile<T>(predicate: Predicate<T>, array: Array<T>): Array<T>;
union<T>(a1: $ReadOnlyArray<T>): (a2: Array<T>) => Array<T>;
union<T>(a1: $ReadOnlyArray<T>, a2: $ReadOnlyArray<T>): Array<T>;
union<T>(a1: Array<T>): (a2: Array<T>) => Array<T>;
union<T>(a1: Array<T>, a2: Array<T>): Array<T>;
unionBy<T>(
iteratee: ValueOnlyIteratee<T>
): ((a1: $ReadOnlyArray<T>) => (a2: $ReadOnlyArray<T>) => Array<T>) &
((a1: $ReadOnlyArray<T>, a2: $ReadOnlyArray<T>) => Array<T>);
): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
((a1: Array<T>, a2: Array<T>) => Array<T>);
unionBy<T>(
iteratee: ValueOnlyIteratee<T>,
a1: $ReadOnlyArray<T>
): (a2: $ReadOnlyArray<T>) => Array<T>;
a1: Array<T>
): (a2: Array<T>) => Array<T>;
unionBy<T>(
iteratee: ValueOnlyIteratee<T>,
a1: $ReadOnlyArray<T>,
a2: $ReadOnlyArray<T>
a1: Array<T>,
a2: Array<T>
): Array<T>;
unionWith<T>(
comparator: Comparator<T>
): ((a1: $ReadOnlyArray<T>) => (a2: $ReadOnlyArray<T>) => Array<T>) &
((a1: $ReadOnlyArray<T>, a2: $ReadOnlyArray<T>) => Array<T>);
): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
((a1: Array<T>, a2: Array<T>) => Array<T>);
unionWith<T>(
comparator: Comparator<T>,
a1: $ReadOnlyArray<T>
): (a2: $ReadOnlyArray<T>) => Array<T>;
a1: Array<T>
): (a2: Array<T>) => Array<T>;
unionWith<T>(
comparator: Comparator<T>,
a1: $ReadOnlyArray<T>,
a2: $ReadOnlyArray<T>
a1: Array<T>,
a2: Array<T>
): Array<T>;
uniq<T>(array: $ReadOnlyArray<T>): Array<T>;
uniqBy<T>(iteratee: ValueOnlyIteratee<T>): (array: $ReadOnlyArray<T>) => Array<T>;
uniqBy<T>(iteratee: ValueOnlyIteratee<T>, array: $ReadOnlyArray<T>): Array<T>;
uniqWith<T>(comparator: Comparator<T>): (array: $ReadOnlyArray<T>) => Array<T>;
uniqWith<T>(comparator: Comparator<T>, array: $ReadOnlyArray<T>): Array<T>;
unzip<T>(array: $ReadOnlyArray<T>): Array<T>;
uniq<T>(array: Array<T>): Array<T>;
uniqBy<T>(iteratee: ValueOnlyIteratee<T>): (array: Array<T>) => Array<T>;
uniqBy<T>(iteratee: ValueOnlyIteratee<T>, array: Array<T>): Array<T>;
uniqWith<T>(comparator: Comparator<T>): (array: Array<T>) => Array<T>;
uniqWith<T>(comparator: Comparator<T>, array: Array<T>): Array<T>;
unzip<T>(array: Array<T>): Array<T>;
unzipWith<T>(iteratee: Iteratee<T>): (array: Array<T>) => Array<T>;
unzipWith<T>(iteratee: Iteratee<T>, array: Array<T>): Array<T>;
without<T>(values: $ReadOnlyArray<T>): (array: $ReadOnlyArray<T>) => Array<T>;
without<T>(values: $ReadOnlyArray<T>, array: $ReadOnlyArray<T>): Array<T>;
xor<T>(a1: $ReadOnlyArray<T>): (a2: $ReadOnlyArray<T>) => Array<T>;
xor<T>(a1: $ReadOnlyArray<T>, a2: $ReadOnlyArray<T>): Array<T>;
symmetricDifference<T>(a1: $ReadOnlyArray<T>): (a2: $ReadOnlyArray<T>) => Array<T>;
symmetricDifference<T>(a1: $ReadOnlyArray<T>, a2: $ReadOnlyArray<T>): Array<T>;
without<T>(values: Array<T>): (array: Array<T>) => Array<T>;
without<T>(values: Array<T>, array: Array<T>): Array<T>;
xor<T>(a1: Array<T>): (a2: Array<T>) => Array<T>;
xor<T>(a1: Array<T>, a2: Array<T>): Array<T>;
symmetricDifference<T>(a1: Array<T>): (a2: Array<T>) => Array<T>;
symmetricDifference<T>(a1: Array<T>, a2: Array<T>): Array<T>;
xorBy<T>(
iteratee: ValueOnlyIteratee<T>
): ((a1: $ReadOnlyArray<T>) => (a2: $ReadOnlyArray<T>) => Array<T>) &
((a1: $ReadOnlyArray<T>, a2: $ReadOnlyArray<T>) => Array<T>);
): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
((a1: Array<T>, a2: Array<T>) => Array<T>);
xorBy<T>(
iteratee: ValueOnlyIteratee<T>,
a1: $ReadOnlyArray<T>
): (a2: $ReadOnlyArray<T>) => Array<T>;
a1: Array<T>
): (a2: Array<T>) => Array<T>;
xorBy<T>(
iteratee: ValueOnlyIteratee<T>,
a1: $ReadOnlyArray<T>,
a2: $ReadOnlyArray<T>
a1: Array<T>,
a2: Array<T>
): Array<T>;
symmetricDifferenceBy<T>(
iteratee: ValueOnlyIteratee<T>
): ((a1: $ReadOnlyArray<T>) => (a2: $ReadOnlyArray<T>) => Array<T>) &
((a1: $ReadOnlyArray<T>, a2: $ReadOnlyArray<T>) => Array<T>);
): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
((a1: Array<T>, a2: Array<T>) => Array<T>);
symmetricDifferenceBy<T>(
iteratee: ValueOnlyIteratee<T>,
a1: $ReadOnlyArray<T>
a1: Array<T>
): (a2: Array<T>) => Array<T>;
symmetricDifferenceBy<T>(
iteratee: ValueOnlyIteratee<T>,
a1: $ReadOnlyArray<T>,
a2: $ReadOnlyArray<T>
a1: Array<T>,
a2: Array<T>
): Array<T>;
xorWith<T>(
comparator: Comparator<T>
): ((a1: $ReadOnlyArray<T>) => (a2: $ReadOnlyArray<T>) => Array<T>) &
((a1: $ReadOnlyArray<T>, a2: $ReadOnlyArray<T>) => Array<T>);
): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
((a1: Array<T>, a2: Array<T>) => Array<T>);
xorWith<T>(
comparator: Comparator<T>,
a1: $ReadOnlyArray<T>
): (a2: $ReadOnlyArray<T>) => Array<T>;
xorWith<T>(comparator: Comparator<T>, a1: $ReadOnlyArray<T>, a2: $ReadOnlyArray<T>): Array<T>;
a1: Array<T>
): (a2: Array<T>) => Array<T>;
xorWith<T>(comparator: Comparator<T>, a1: Array<T>, a2: Array<T>): Array<T>;
symmetricDifferenceWith<T>(
comparator: Comparator<T>
): ((a1: $ReadOnlyArray<T>) => (a2: $ReadOnlyArray<T>) => Array<T>) &
((a1: $ReadOnlyArray<T>, a2: $ReadOnlyArray<T>) => Array<T>);
): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
((a1: Array<T>, a2: Array<T>) => Array<T>);
symmetricDifferenceWith<T>(
comparator: Comparator<T>,
a1: $ReadOnlyArray<T>
): (a2: $ReadOnlyArray<T>) => Array<T>;
a1: Array<T>
): (a2: Array<T>) => Array<T>;
symmetricDifferenceWith<T>(
comparator: Comparator<T>,
a1: $ReadOnlyArray<T>,
a2: $ReadOnlyArray<T>
a1: Array<T>,
a2: Array<T>
): Array<T>;
zip<A, B>(a1: $ReadOnlyArray<A>): (a2: $ReadOnlyArray<B>) => Array<[A, B]>;
zip<A, B>(a1: $ReadOnlyArray<A>, a2: $ReadOnlyArray<B>): Array<[A, B]>;
zipAll(arrays: $ReadOnlyArray<$ReadOnlyArray<any>>): Array<any>;
zipObject<K, V>(props?: $ReadOnlyArray<K>): (values?: $ReadOnlyArray<V>) => { [key: K]: V };
zipObject<K, V>(props?: $ReadOnlyArray<K>, values?: $ReadOnlyArray<V>): { [key: K]: V };
zip<A, B>(a1: A[]): (a2: B[]) => Array<[A, B]>;
zip<A, B>(a1: A[], a2: B[]): Array<[A, B]>;
zipAll(arrays: Array<Array<any>>): Array<any>;
zipObject<K, V>(props?: Array<K>): (values?: Array<V>) => { [key: K]: V };
zipObject<K, V>(props?: Array<K>, values?: Array<V>): { [key: K]: V };
zipObj(props: Array<any>): (values: Array<any>) => Object;
zipObj(props: Array<any>, values: Array<any>): Object;
zipObjectDeep(props: any[]): (values: any) => Object;
@@ -2026,10 +2017,10 @@ declare module "lodash/fp" {
// Collection
countBy<T>(
iteratee: ValueOnlyIteratee<T>
): (collection: $ReadOnlyArray<T> | { [id: any]: T }) => { [string]: number };
): (collection: Array<T> | { [id: any]: T }) => { [string]: number };
countBy<T>(
iteratee: ValueOnlyIteratee<T>,
collection: $ReadOnlyArray<T> | { [id: any]: T }
collection: Array<T> | { [id: any]: T }
): { [string]: number };
// alias of _.forEach
each<T>(
@@ -2955,10 +2946,8 @@ declare module "lodash/fp" {
predicate: OPredicate<A>
): (object: T) => Object;
omitBy<A, T: { [id: any]: A }>(predicate: OPredicate<A>, object: T): Object;
pick(...props: Array<string | {}>): Object;
pick(props: $ReadOnlyArray<string>, object: Object): Object;
pick(...props: Array<string>): (object: Object) => Object;
pick(props: $ReadOnlyArray<string>): (object: Object) => Object;
pick(props: Array<string>): (object: Object) => Object;
pick(props: Array<string>, object: Object): Object;
pickAll(props: Array<string>): (object: Object) => Object;
pickAll(props: Array<string>, object: Object): Object;
pickBy<A, T: { [id: any]: A }>(

View File

@@ -1,5 +1,5 @@
// flow-typed signature: d2ddacbbca9700881249a9435381e689
// flow-typed version: c6154227d1/react-redux_v7.x.x/flow_>=v0.89.x <=v0.103.x
// flow-typed signature: f06f00c3ad0cfedb90c0c6de04b219f3
// flow-typed version: 3a6d556e4b/react-redux_v5.x.x/flow_>=v0.89.x
/**
The order of type arguments for connect() is as follows:
@@ -27,7 +27,6 @@ Decrypting the abbreviations:
RMP = Returned merge props
CP = Props for returned component
Com = React Component
SS = Selected state
ST = Static properties of Com
EFO = Extra factory options (used only in connectAdvanced)
*/
@@ -39,7 +38,7 @@ declare module "react-redux" {
declare export type Options<S, OP, SP, MP> = {|
pure?: boolean,
forwardRef?: boolean,
withRef?: boolean,
areStatesEqual?: (next: S, prev: S) => boolean,
areOwnPropsEqual?: (next: OP, prev: OP) => boolean,
areStatePropsEqual?: (next: SP, prev: SP) => boolean,
@@ -199,19 +198,6 @@ declare module "react-redux" {
options?: ?Options<S, OP, SP, P>,
): Connector<P, OP, P>;
// ------------------------------------------------------------
// Typings for Hooks
// ------------------------------------------------------------
declare export function useDispatch<D>(): D;
declare export function useSelector<S, SS>(
selector: (state: S) => SS,
equalityFn?: (a: SS, b: SS) => boolean,
): SS;
declare export function useStore<Store>(): Store;
// ------------------------------------------------------------
// Typings for Provider
// ------------------------------------------------------------
@@ -236,7 +222,7 @@ declare module "react-redux" {
renderCountProp?: string,
shouldHandleStateChanges?: boolean,
storeKey?: string,
forwardRef?: boolean,
withRef?: boolean,
};
declare type SelectorFactoryOptions<Com> = {
@@ -245,7 +231,7 @@ declare module "react-redux" {
renderCountProp: ?string,
shouldHandleStateChanges: boolean,
storeKey: string,
forwardRef: boolean,
withRef: boolean,
displayName: string,
wrappedComponentName: string,
WrappedComponent: Com,
@@ -286,8 +272,5 @@ declare module "react-redux" {
createProvider: typeof createProvider,
connect: typeof connect,
connectAdvanced: typeof connectAdvanced,
useDispatch: typeof useDispatch,
useSelector: typeof useSelector,
useStore: typeof useStore,
};
}

View File

@@ -1,7 +1,8 @@
// flow-typed signature: 99b2d8ebd0ab4be20976dc62a3bbf54c
// flow-typed version: c6154227d1/redux_v4.x.x/flow_>=v0.89.x <=v0.103.x
// flow-typed signature: df80bdd535bfed9cf3223e077f3b4543
// flow-typed version: c4c8963c9c/redux_v4.x.x/flow_>=v0.55.x
declare module 'redux' {
/*
S = State
@@ -10,91 +11,49 @@ declare module 'redux' {
*/
declare export type Action<T> = {
type: T
}
declare export type DispatchAPI<A> = (action: A) => A;
declare export type Dispatch<A: { type: * }> = DispatchAPI<A>;
declare export type Dispatch<A: { type: $Subtype<string> }> = DispatchAPI<A>;
declare export type MiddlewareAPI<S, A, D = Dispatch<A>> = {
dispatch: D,
getState(): S,
dispatch: D;
getState(): S;
};
declare export type Store<S, A, D = Dispatch<A>> = {
// rewrite MiddlewareAPI members in order to get nicer error messages (intersections produce long messages)
dispatch: D,
getState(): S,
subscribe(listener: () => void): () => void,
replaceReducer(nextReducer: Reducer<S, A>): void,
dispatch: D;
getState(): S;
subscribe(listener: () => void): () => void;
replaceReducer(nextReducer: Reducer<S, A>): void
};
declare export type Reducer<S, A> = (state: S | void, action: A) => S;
declare export type CombinedReducer<S, A> = (
state: ($Shape<S> & {}) | void,
action: A
) => S;
declare export type CombinedReducer<S, A> = (state: $Shape<S> & {} | void, action: A) => S;
declare export type Middleware<S, A, D = Dispatch<A>> = (
api: MiddlewareAPI<S, A, D>
) => (next: D) => D;
declare export type Middleware<S, A, D = Dispatch<A>> =
(api: MiddlewareAPI<S, A, D>) =>
(next: D) => D;
declare export type StoreCreator<S, A, D = Dispatch<A>> = {
(reducer: Reducer<S, A>, enhancer?: StoreEnhancer<S, A, D>): Store<S, A, D>,
(
reducer: Reducer<S, A>,
preloadedState: S,
enhancer?: StoreEnhancer<S, A, D>
): Store<S, A, D>,
(reducer: Reducer<S, A>, enhancer?: StoreEnhancer<S, A, D>): Store<S, A, D>;
(reducer: Reducer<S, A>, preloadedState: S, enhancer?: StoreEnhancer<S, A, D>): Store<S, A, D>;
};
declare export type StoreEnhancer<S, A, D = Dispatch<A>> = (
next: StoreCreator<S, A, D>
) => StoreCreator<S, A, D>;
declare export type StoreEnhancer<S, A, D = Dispatch<A>> = (next: StoreCreator<S, A, D>) => StoreCreator<S, A, D>;
declare export function createStore<S, A, D>(
reducer: Reducer<S, A>,
enhancer?: StoreEnhancer<S, A, D>
): Store<S, A, D>;
declare export function createStore<S, A, D>(
reducer: Reducer<S, A>,
preloadedState?: S,
enhancer?: StoreEnhancer<S, A, D>
): Store<S, A, D>;
declare export function createStore<S, A, D>(reducer: Reducer<S, A>, enhancer?: StoreEnhancer<S, A, D>): Store<S, A, D>;
declare export function createStore<S, A, D>(reducer: Reducer<S, A>, preloadedState?: S, enhancer?: StoreEnhancer<S, A, D>): Store<S, A, D>;
declare export function applyMiddleware<S, A, D>(
...middlewares: Array<Middleware<S, A, D>>
): StoreEnhancer<S, A, D>;
declare export function applyMiddleware<S, A, D>(...middlewares: Array<Middleware<S, A, D>>): StoreEnhancer<S, A, D>;
declare export type ActionCreator<A, B> = (...args: Array<B>) => A;
declare export type ActionCreators<K, A> = {
[key: K]: ActionCreator<A, any>,
};
declare export type ActionCreators<K, A> = { [key: K]: ActionCreator<A, any> };
declare export function bindActionCreators<
A,
C: ActionCreator<A, any>,
D: DispatchAPI<A>
>(
actionCreator: C,
dispatch: D
): C;
declare export function bindActionCreators<
A,
K,
C: ActionCreators<K, A>,
D: DispatchAPI<A>
>(
actionCreators: C,
dispatch: D
): C;
declare export function bindActionCreators<A, C: ActionCreator<A, any>, D: DispatchAPI<A>>(actionCreator: C, dispatch: D): C;
declare export function bindActionCreators<A, K, C: ActionCreators<K, A>, D: DispatchAPI<A>>(actionCreators: C, dispatch: D): C;
declare export function combineReducers<O: {}, A>(
reducers: O
): CombinedReducer<$ObjMap<O, <S>(r: Reducer<S, any>) => S>, A>;
declare export function combineReducers<O: Object, A>(reducers: O): CombinedReducer<$ObjMap<O, <S>(r: Reducer<S, any>) => S>, A>;
declare export var compose: $Compose;
}

View File

@@ -1,5 +1,5 @@
// flow-typed signature: 609c1622fc97de96d59519934aa5ce87
// flow-typed version: c6154227d1/uuid_v3.x.x/flow_>=v0.32.x <=v0.103.x
// flow-typed signature: 3cf668e64747095cab0bb360cf2fb34f
// flow-typed version: d659bd0cb8/uuid_v3.x.x/flow_>=v0.32.x
declare module "uuid" {
declare class uuid {

Binary file not shown.

View File

@@ -42,9 +42,7 @@
<glyph unicode="&#xe90c;" glyph-name="exit-full-screen" d="M682 682h128v-84h-212v212h84v-128zM598 214v212h212v-84h-128v-128h-84zM342 682v128h84v-212h-212v84h128zM214 342v84h212v-212h-84v128h-128z" />
<glyph unicode="&#xe90d;" glyph-name="security" d="M768 170v428h-512v-428h512zM768 682c46 0 86-38 86-84v-428c0-46-40-84-86-84h-512c-46 0-86 38-86 84v428c0 46 40 84 86 84h388v86c0 72-60 132-132 132s-132-60-132-132h-82c0 118 96 214 214 214s214-96 214-214v-86h42zM512 298c-46 0-86 40-86 86s40 86 86 86 86-40 86-86-40-86-86-86z" />
<glyph unicode="&#xe90e;" glyph-name="security-locked" d="M768 170v428h-512v-428h512zM380 768v-86h264v86c0 72-60 132-132 132s-132-60-132-132zM768 682c46 0 86-38 86-84v-428c0-46-40-84-86-84h-512c-46 0-86 38-86 84v428c0 46 40 84 86 84h42v86c0 118 96 214 214 214s214-96 214-214v-86h42zM512 298c-46 0-86 40-86 86s40 86 86 86 86-40 86-86-40-86-86-86z" />
<glyph unicode="&#xe90f;" glyph-name="blur-background" d="M469.333 640c0-47.128-38.205-85.333-85.333-85.333s-85.333 38.205-85.333 85.333c0 47.128 38.205 85.333 85.333 85.333s85.333-38.205 85.333-85.333zM725.333 640c0-47.128-38.205-85.333-85.333-85.333s-85.333 38.205-85.333 85.333c0 47.128 38.205 85.333 85.333 85.333s85.333-38.205 85.333-85.333zM469.333 384c0-47.128-38.205-85.333-85.333-85.333s-85.333 38.205-85.333 85.333c0 47.128 38.205 85.333 85.333 85.333s85.333-38.205 85.333-85.333zM426.667 170.667c0-23.564-19.103-42.667-42.667-42.667s-42.667 19.103-42.667 42.667c0 23.564 19.103 42.667 42.667 42.667s42.667-19.103 42.667-42.667zM682.667 170.667c0-23.564-19.103-42.667-42.667-42.667s-42.667 19.103-42.667 42.667c0 23.564 19.103 42.667 42.667 42.667s42.667-19.103 42.667-42.667zM213.333 384c0-23.564-19.103-42.667-42.667-42.667s-42.667 19.103-42.667 42.667c0 23.564 19.103 42.667 42.667 42.667s42.667-19.103 42.667-42.667zM213.333 640c0-23.564-19.103-42.667-42.667-42.667s-42.667 19.103-42.667 42.667c0 23.564 19.103 42.667 42.667 42.667s42.667-19.103 42.667-42.667zM896 384c0-23.564-19.103-42.667-42.667-42.667s-42.667 19.103-42.667 42.667c0 23.564 19.103 42.667 42.667 42.667s42.667-19.103 42.667-42.667zM896 640c0-23.564-19.103-42.667-42.667-42.667s-42.667 19.103-42.667 42.667c0 23.564 19.103 42.667 42.667 42.667s42.667-19.103 42.667-42.667zM426.667 853.333c0-23.564-19.103-42.667-42.667-42.667s-42.667 19.103-42.667 42.667c0 23.564 19.103 42.667 42.667 42.667s42.667-19.103 42.667-42.667zM682.667 853.333c0-23.564-19.103-42.667-42.667-42.667s-42.667 19.103-42.667 42.667c0 23.564 19.103 42.667 42.667 42.667s42.667-19.103 42.667-42.667zM725.333 384c0-47.128-38.205-85.333-85.333-85.333s-85.333 38.205-85.333 85.333c0 47.128 38.205 85.333 85.333 85.333s85.333-38.205 85.333-85.333z" />
<glyph unicode="&#xe910;" glyph-name="microphone" d="M738 554h72c0-146-116-266-256-286v-140h-84v140c-140 20-256 140-256 286h72c0-128 108-216 226-216s226 88 226 216zM512 426c-70 0-128 58-128 128v256c0 70 58 128 128 128s128-58 128-128v-256c0-70-58-128-128-128z" />
<glyph unicode="&#xe911;" glyph-name="send" d="M86 128v298l640 86-640 86v298l896-384z" />
<glyph unicode="&#xe912;" glyph-name="mic-disabled" d="M182 896l714-714-54-54-178 178c-32-20-72-32-110-38v-140h-84v140c-140 20-256 140-256 286h72c0-128 108-216 226-216 34 0 68 8 98 22l-70 70c-8-2-18-4-28-4-70 0-128 58-128 128v32l-256 256zM640 548l-256 254v8c0 70 58 128 128 128s128-58 128-128v-262zM810 554c0-50-14-98-38-140l-52 54c12 26 18 54 18 86h72z" />
<glyph unicode="&#xe913;" glyph-name="link" d="M640 426c114 0 342-56 342-170v-86h-684v86c0 114 228 170 342 170zM256 598h128v-86h-128v-128h-86v128h-128v86h128v128h86v-128zM640 512c-94 0-170 76-170 170s76 172 170 172 170-78 170-172-76-170-170-170z" />
<glyph unicode="&#xe914;" glyph-name="shared-video" d="M512 170c188 0 342 154 342 342s-154 342-342 342-342-154-342-342 154-342 342-342zM512 938c236 0 426-190 426-426s-190-426-426-426-426 190-426 426 190 426 426 426zM426 320v384l256-192z" />

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -50,7 +50,7 @@ var interfaceConfig = {
'fodeviceselection', 'hangup', 'profile', 'info', 'chat', 'recording',
'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
'tileview', 'videobackgroundblur'
'tileview'
],
SETTINGS_SECTIONS: [ 'devices', 'language', 'moderator', 'profile', 'calendar' ],

View File

@@ -1,6 +1,6 @@
platform :ios, '10.0'
workspace 'jitsi-meet'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
target 'jitsi-meet' do
project 'app/app.xcodeproj'
@@ -17,26 +17,19 @@ target 'JitsiMeet' do
# React Native and its dependencies
#
pod 'React', :path => '../node_modules/react-native/'
pod 'React-Core', :path => '../node_modules/react-native/React'
pod 'React-DevSupport', :path => '../node_modules/react-native/React'
pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
pod 'React-RCTWebSocket', :path => '../node_modules/react-native/Libraries/WebSocket'
pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
pod 'React', :path => '../node_modules/react-native', :subspecs => [
'Core',
'CxxBridge',
'DevSupport',
'RCTActionSheet',
'RCTAnimation',
'RCTImage',
'RCTLinkingIOS',
'RCTNetwork',
'RCTText',
'RCTWebSocket',
]
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
@@ -46,8 +39,8 @@ target 'JitsiMeet' do
pod 'react-native-background-timer', :path => '../node_modules/react-native-background-timer'
pod 'react-native-calendar-events', :path => '../node_modules/react-native-calendar-events'
pod 'react-native-fast-image', :path => '../node_modules/react-native-fast-image'
pod 'react-native-keep-awake', :path => '../node_modules/react-native-keep-awake'
pod 'react-native-netinfo', :path => '../node_modules/@react-native-community/netinfo'
pod 'react-native-webview', :path => '../node_modules/react-native-webview'
pod 'react-native-webrtc', :path => '../node_modules/react-native-webrtc'
pod 'BVLinearGradient', :path => '../node_modules/react-native-linear-gradient'
@@ -62,8 +55,6 @@ target 'JitsiMeet' do
pod 'Amplitude-iOS', '~> 4.0.4'
pod 'ObjectiveDropboxOfficial', '~> 3.9.4'
use_native_modules!
end
post_install do |installer|

View File

@@ -1,7 +1,7 @@
PODS:
- Amplitude-iOS (4.0.4)
- boost-for-react-native (1.63.0)
- BVLinearGradient (2.5.6):
- BVLinearGradient (2.5.3):
- React
- Crashlytics (3.12.0):
- Fabric (~> 1.9.0)
@@ -35,12 +35,8 @@ PODS:
- FirebaseCore (~> 5.2)
- GoogleUtilities/Environment (~> 5.2)
- GoogleUtilities/UserDefaults (~> 5.2)
- FLAnimatedImage (1.0.12)
- Folly (2018.10.22.00):
- boost-for-react-native
- DoubleConversion
- Folly/Default (= 2018.10.22.00)
- glog
- Folly/Default (2018.10.22.00):
- boost-for-react-native
- DoubleConversion
- glog
@@ -88,101 +84,89 @@ PODS:
- nanopb/decode (0.3.901)
- nanopb/encode (0.3.901)
- ObjectiveDropboxOfficial (3.9.4)
- React (0.60.5):
- React-Core (= 0.60.5)
- React-DevSupport (= 0.60.5)
- React-RCTActionSheet (= 0.60.5)
- React-RCTAnimation (= 0.60.5)
- React-RCTBlob (= 0.60.5)
- React-RCTImage (= 0.60.5)
- React-RCTLinking (= 0.60.5)
- React-RCTNetwork (= 0.60.5)
- React-RCTSettings (= 0.60.5)
- React-RCTText (= 0.60.5)
- React-RCTVibration (= 0.60.5)
- React-RCTWebSocket (= 0.60.5)
- React-Core (0.60.5):
- Folly (= 2018.10.22.00)
- React-cxxreact (= 0.60.5)
- React-jsiexecutor (= 0.60.5)
- yoga (= 0.60.5.React)
- React-cxxreact (0.60.5):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-jsinspector (= 0.60.5)
- React-DevSupport (0.60.5):
- React-Core (= 0.60.5)
- React-RCTWebSocket (= 0.60.5)
- React-jsi (0.60.5):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-jsi/Default (= 0.60.5)
- React-jsi/Default (0.60.5):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-jsiexecutor (0.60.5):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-cxxreact (= 0.60.5)
- React-jsi (= 0.60.5)
- React-jsinspector (0.60.5)
- React (0.59.8):
- React/Core (= 0.59.8)
- react-native-background-timer (2.1.1):
- React
- react-native-calendar-events (1.7.3):
- react-native-calendar-events (1.6.4):
- React
- react-native-fast-image (5.1.1):
- FLAnimatedImage
- React
- SDWebImage/Core
- SDWebImage/GIF
- react-native-keep-awake (4.0.0):
- React
- react-native-netinfo (4.1.5):
- React
- react-native-webrtc (1.69.2):
- react-native-webrtc (1.69.1):
- React
- react-native-webview (5.8.1):
- React
- React-RCTActionSheet (0.60.5):
- React-Core (= 0.60.5)
- React-RCTAnimation (0.60.5):
- React-Core (= 0.60.5)
- React-RCTBlob (0.60.5):
- React-Core (= 0.60.5)
- React-RCTNetwork (= 0.60.5)
- React-RCTWebSocket (= 0.60.5)
- React-RCTImage (0.60.5):
- React-Core (= 0.60.5)
- React-RCTNetwork (= 0.60.5)
- React-RCTLinking (0.60.5):
- React-Core (= 0.60.5)
- React-RCTNetwork (0.60.5):
- React-Core (= 0.60.5)
- React-RCTSettings (0.60.5):
- React-Core (= 0.60.5)
- React-RCTText (0.60.5):
- React-Core (= 0.60.5)
- React-RCTVibration (0.60.5):
- React-Core (= 0.60.5)
- React-RCTWebSocket (0.60.5):
- React-Core (= 0.60.5)
- React/Core (0.59.8):
- yoga (= 0.59.8.React)
- React/CxxBridge (0.59.8):
- Folly (= 2018.10.22.00)
- React/Core
- React/cxxreact
- React/jsiexecutor
- React/cxxreact (0.59.8):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React/jsinspector
- React/DevSupport (0.59.8):
- React/Core
- React/RCTWebSocket
- React/fishhook (0.59.8)
- React/jsi (0.59.8):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React/jsiexecutor (0.59.8):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React/cxxreact
- React/jsi
- React/jsinspector (0.59.8)
- React/RCTActionSheet (0.59.8):
- React/Core
- React/RCTAnimation (0.59.8):
- React/Core
- React/RCTBlob (0.59.8):
- React/Core
- React/RCTImage (0.59.8):
- React/Core
- React/RCTNetwork
- React/RCTLinkingIOS (0.59.8):
- React/Core
- React/RCTNetwork (0.59.8):
- React/Core
- React/RCTText (0.59.8):
- React/Core
- React/RCTWebSocket (0.59.8):
- React/Core
- React/fishhook
- React/RCTBlob
- RNCAsyncStorage (1.3.4):
- React
- RNGoogleSignin (2.0.0):
- GoogleSignIn (~> 4.4.0)
- React
- RNSound (0.11.0):
- React
- RNSound/Core (= 0.11.0)
- RNSound/Core (0.11.0):
- React
- RNSound (0.10.12):
- React/Core
- RNSound/Core (= 0.10.12)
- RNSound/Core (0.10.12):
- React/Core
- RNVectorIcons (6.0.2):
- React
- RNWatch (0.2.0):
- React
- yoga (0.60.5.React)
- SDWebImage/Core (4.4.6)
- SDWebImage/GIF (4.4.6):
- FLAnimatedImage (~> 1.0)
- SDWebImage/Core
- yoga (0.59.8.React)
DEPENDENCIES:
- Amplitude-iOS (~> 4.0.4)
@@ -195,29 +179,22 @@ DEPENDENCIES:
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- ObjectiveDropboxOfficial (~> 3.9.4)
- React (from `../node_modules/react-native/`)
- React-Core (from `../node_modules/react-native/React`)
- React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
- React-DevSupport (from `../node_modules/react-native/React`)
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- react-native-background-timer (from `../node_modules/react-native-background-timer`)
- react-native-calendar-events (from `../node_modules/react-native-calendar-events`)
- react-native-fast-image (from `../node_modules/react-native-fast-image`)
- react-native-keep-awake (from `../node_modules/react-native-keep-awake`)
- react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)
- react-native-webrtc (from `../node_modules/react-native-webrtc`)
- react-native-webview (from `../node_modules/react-native-webview`)
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
- React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
- React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`)
- React-RCTImage (from `../node_modules/react-native/Libraries/Image`)
- React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`)
- React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`)
- React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
- React-RCTText (from `../node_modules/react-native/Libraries/Text`)
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
- React-RCTWebSocket (from `../node_modules/react-native/Libraries/WebSocket`)
- React/Core (from `../node_modules/react-native`)
- React/CxxBridge (from `../node_modules/react-native`)
- React/DevSupport (from `../node_modules/react-native`)
- React/RCTActionSheet (from `../node_modules/react-native`)
- React/RCTAnimation (from `../node_modules/react-native`)
- React/RCTImage (from `../node_modules/react-native`)
- React/RCTLinkingIOS (from `../node_modules/react-native`)
- React/RCTNetwork (from `../node_modules/react-native`)
- React/RCTText (from `../node_modules/react-native`)
- React/RCTWebSocket (from `../node_modules/react-native`)
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
- RNGoogleSignin (from `../node_modules/react-native-google-signin`)
- RNSound (from `../node_modules/react-native-sound`)
@@ -237,6 +214,7 @@ SPEC REPOS:
- FirebaseCore
- FirebaseDynamicLinks
- FirebaseInstanceID
- FLAnimatedImage
- GoogleAppMeasurement
- GoogleSignIn
- GoogleToolboxForMac
@@ -244,6 +222,7 @@ SPEC REPOS:
- GTMSessionFetcher
- nanopb
- ObjectiveDropboxOfficial
- SDWebImage
EXTERNAL SOURCES:
BVLinearGradient:
@@ -255,51 +234,19 @@ EXTERNAL SOURCES:
glog:
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
React:
:path: "../node_modules/react-native/"
React-Core:
:path: "../node_modules/react-native/React"
React-cxxreact:
:path: "../node_modules/react-native/ReactCommon/cxxreact"
React-DevSupport:
:path: "../node_modules/react-native/React"
React-jsi:
:path: "../node_modules/react-native/ReactCommon/jsi"
React-jsiexecutor:
:path: "../node_modules/react-native/ReactCommon/jsiexecutor"
React-jsinspector:
:path: "../node_modules/react-native/ReactCommon/jsinspector"
:path: "../node_modules/react-native"
react-native-background-timer:
:path: "../node_modules/react-native-background-timer"
react-native-calendar-events:
:path: "../node_modules/react-native-calendar-events"
react-native-fast-image:
:path: "../node_modules/react-native-fast-image"
react-native-keep-awake:
:path: "../node_modules/react-native-keep-awake"
react-native-netinfo:
:path: "../node_modules/@react-native-community/netinfo"
react-native-webrtc:
:path: "../node_modules/react-native-webrtc"
react-native-webview:
:path: "../node_modules/react-native-webview"
React-RCTActionSheet:
:path: "../node_modules/react-native/Libraries/ActionSheetIOS"
React-RCTAnimation:
:path: "../node_modules/react-native/Libraries/NativeAnimation"
React-RCTBlob:
:path: "../node_modules/react-native/Libraries/Blob"
React-RCTImage:
:path: "../node_modules/react-native/Libraries/Image"
React-RCTLinking:
:path: "../node_modules/react-native/Libraries/LinkingIOS"
React-RCTNetwork:
:path: "../node_modules/react-native/Libraries/Network"
React-RCTSettings:
:path: "../node_modules/react-native/Libraries/Settings"
React-RCTText:
:path: "../node_modules/react-native/Libraries/Text"
React-RCTVibration:
:path: "../node_modules/react-native/Libraries/Vibration"
React-RCTWebSocket:
:path: "../node_modules/react-native/Libraries/WebSocket"
RNCAsyncStorage:
:path: "../node_modules/@react-native-community/async-storage"
RNGoogleSignin:
@@ -316,9 +263,9 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
Amplitude-iOS: 2ad4d7270c99186236c1272a3a9425463b1ae1a7
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872
BVLinearGradient: 0d985ec461359c82bc254f26d11008bdae50d17a
Crashlytics: 07fb167b1694128c1c9a5a5cc319b0e9c3ca0933
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
DoubleConversion: bb338842f62ab1d708ceb63ec3d999f0f3d98ecd
Fabric: f988e33c97f08930a413e08123064d2e5f68d655
Firebase: 02f3281965c075426141a0ce1277e9de6649cab9
FirebaseAnalytics: 23851fe602c872130a2c5c55040b302120346cc2
@@ -326,8 +273,9 @@ SPEC CHECKSUMS:
FirebaseCore: 52f851b30e11360f1e67cf04b1edfebf0a47a2d3
FirebaseDynamicLinks: f209c3caccd82102caa0e91d393e3ccc593501fd
FirebaseInstanceID: bd6fc5a258884e206fd5c474ebe4f5b00e21770e
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
FLAnimatedImage: 4a0b56255d9b05f18b6dd7ee06871be5d3b89e31
Folly: de497beb10f102453a1afa9edbf8cf8a251890de
glog: aefd1eb5dda2ab95ba0938556f34b98e2da3a60d
GoogleAppMeasurement: 6cf307834da065863f9faf4c0de0a936d81dd832
GoogleSignIn: 7ff245e1a7b26d379099d3243a562f5747e23d39
GoogleToolboxForMac: ff31605b7d66400dcec09bed5861689aebadda4d
@@ -335,36 +283,21 @@ SPEC CHECKSUMS:
GTMSessionFetcher: 32aeca0aa144acea523e1c8e053089dec2cb98ca
nanopb: 2901f78ea1b7b4015c860c2fdd1ea2fee1a18d48
ObjectiveDropboxOfficial: a5afefc83f6467c42c45f2253f583f2ad1ffc701
React: 53c53c4d99097af47cf60594b8706b4e3321e722
React-Core: ba421f6b4f4cbe2fb17c0b6fc675f87622e78a64
React-cxxreact: 8384287780c4999351ad9b6e7a149d9ed10a2395
React-DevSupport: 197fb409737cff2c4f9986e77c220d7452cb9f9f
React-jsi: 4d8c9efb6312a9725b18d6fc818ffc103f60fec2
React-jsiexecutor: 90ad2f9db09513fc763bc757fdc3c4ff8bde2a30
React-jsinspector: e08662d1bf5b129a3d556eb9ea343a3f40353ae4
React: 76e6aa2b87d05eb6cccb6926d72685c9a07df152
react-native-background-timer: 0d34748e53a972507c66963490c775321a88f6f2
react-native-calendar-events: 2fe35a9294af05de0ed819d3a1b5dac048d2c010
react-native-calendar-events: ee9573e355711ac679e071be70789542431f4ce3
react-native-fast-image: 47487b71169aea34868e7b38bf870b6b3f2157c5
react-native-keep-awake: eba3137546b10003361b37c761f6c429b59814ae
react-native-netinfo: 8d8db463bcc5db66a8ac5c48a7d86beb3b92f61a
react-native-webrtc: 1415d2a54b2246dd85ba95eb3e4bf2b66533f951
react-native-webrtc: 90a847d19deb2d7323fef8cc89ca12b8995fbc90
react-native-webview: a95842e3f351a6d2c8bc8bcc9eab689c7e7e5ad4
React-RCTActionSheet: b0f1ea83f4bf75fb966eae9bfc47b78c8d3efd90
React-RCTAnimation: 359ba1b5690b1e87cc173558a78e82d35919333e
React-RCTBlob: 5e2b55f76e9a1c7ae52b826923502ddc3238df24
React-RCTImage: f5f1c50922164e89bdda67bcd0153952a5cfe719
React-RCTLinking: d0ecbd791e9ddddc41fa1f66b0255de90e8ee1e9
React-RCTNetwork: e26946300b0ab7bb6c4a6348090e93fa21f33a9d
React-RCTSettings: d0d37cb521b7470c998595a44f05847777cc3f42
React-RCTText: b074d89033583d4f2eb5faf7ea2db3a13c7553a2
React-RCTVibration: 2105b2e0e2b66a6408fc69a46c8a7fb5b2fdade0
React-RCTWebSocket: cd932a16b7214898b6b7f788c8bddb3637246ac4
RNCAsyncStorage: 8e31405a9f12fbf42c2bb330e4560bfd79c18323
RNGoogleSignin: d030c6c6591db24c3cee649f64c7babf0a1699a0
RNSound: c980916b596cc15c8dcd2f6ecd3b13c4881dbe20
RNSound: e157320f503bdd4f4ee6d8542e948d54f90c3c3a
RNVectorIcons: d819334932bcda3332deb3d2c8ea4d069e0b98f9
RNWatch: 09738b339eceb66e4d80a2371633ca5fb380fa42
yoga: 312528f5bbbba37b4dcea5ef00e8b4033fdd9411
SDWebImage: 3f3f0c02f09798048c47a5ed0a13f17b063572d8
yoga: 92b2102c3d373d1a790db4ab761d2b0ffc634f64
PODFILE CHECKSUM: 0907bfe60b5b5f11dbdc6b4e65d40a248d000513
PODFILE CHECKSUM: b55338cc43312051ed83f8d9c6aadbd8c9402e6a
COCOAPODS: 1.7.2

View File

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

View File

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

View File

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

View File

@@ -10,6 +10,7 @@
0B412F181EDEC65D00B1A0A6 /* JitsiMeetView.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B412F161EDEC65D00B1A0A6 /* JitsiMeetView.h */; settings = {ATTRIBUTES = (Public, ); }; };
0B412F191EDEC65D00B1A0A6 /* JitsiMeetView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B412F171EDEC65D00B1A0A6 /* JitsiMeetView.m */; };
0B412F221EDEF6EA00B1A0A6 /* JitsiMeetViewDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B412F1B1EDEC80100B1A0A6 /* JitsiMeetViewDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
0B44A0191F902126009D1D64 /* MPVolumeViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B44A0181F902126009D1D64 /* MPVolumeViewManager.m */; };
0B49424520AD8DBD00BD2DE0 /* outgoingStart.wav in Resources */ = {isa = PBXBuildFile; fileRef = 0B49424320AD8DBD00BD2DE0 /* outgoingStart.wav */; };
0B49424620AD8DBD00BD2DE0 /* outgoingRinging.wav in Resources */ = {isa = PBXBuildFile; fileRef = 0B49424420AD8DBD00BD2DE0 /* outgoingRinging.wav */; };
0B93EF7E1EC9DDCD0030D24D /* RCTBridgeWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B93EF7C1EC9DDCD0030D24D /* RCTBridgeWrapper.h */; };
@@ -26,8 +27,6 @@
0BCA496C1EC4BBF900B793EE /* jitsi.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 0BCA496B1EC4BBF900B793EE /* jitsi.ttf */; };
0BD906EA1EC0C00300C8C18E /* JitsiMeet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BD906E81EC0C00300C8C18E /* JitsiMeet.h */; settings = {ATTRIBUTES = (Public, ); }; };
0F65EECE1D95DA94561BB47E /* libPods-JitsiMeet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 03F2ADC957FF109849B7FCA1 /* libPods-JitsiMeet.a */; };
C30F88D0CB0F4F5593216D24 /* liveStreamingOff.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C30F88D1CB0F4F5593216D24 /* liveStreamingOff.mp3 */; };
C30F88D2CB0F4F5593216D24 /* liveStreamingOn.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C30F88D3CB0F4F5593216D24 /* liveStreamingOn.mp3 */; };
6C31EDC820C06D490089C899 /* recordingOn.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 6C31EDC720C06D490089C899 /* recordingOn.mp3 */; };
6C31EDCA20C06D530089C899 /* recordingOff.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 6C31EDC920C06D530089C899 /* recordingOff.mp3 */; };
75635B0A20751D6D00F29C9F /* joined.wav in Resources */ = {isa = PBXBuildFile; fileRef = 75635B0820751D6D00F29C9F /* joined.wav */; };
@@ -58,6 +57,7 @@
0B412F161EDEC65D00B1A0A6 /* JitsiMeetView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JitsiMeetView.h; sourceTree = "<group>"; };
0B412F171EDEC65D00B1A0A6 /* JitsiMeetView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JitsiMeetView.m; sourceTree = "<group>"; };
0B412F1B1EDEC80100B1A0A6 /* JitsiMeetViewDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeetViewDelegate.h; sourceTree = "<group>"; };
0B44A0181F902126009D1D64 /* MPVolumeViewManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPVolumeViewManager.m; sourceTree = "<group>"; };
0B49424320AD8DBD00BD2DE0 /* outgoingStart.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = outgoingStart.wav; path = ../../sounds/outgoingStart.wav; sourceTree = "<group>"; };
0B49424420AD8DBD00BD2DE0 /* outgoingRinging.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = outgoingRinging.wav; path = ../../sounds/outgoingRinging.wav; sourceTree = "<group>"; };
0B93EF7A1EC608550030D24D /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
@@ -77,8 +77,6 @@
0BD906E51EC0C00300C8C18E /* JitsiMeet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JitsiMeet.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0BD906E81EC0C00300C8C18E /* JitsiMeet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeet.h; sourceTree = "<group>"; };
0BD906E91EC0C00300C8C18E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C30F88D1CB0F4F5593216D24 /* liveStreamingOff.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = liveStreamingOff.mp3; path = ../../sounds/liveStreamingOff.mp3; sourceTree = "<group>"; };
C30F88D3CB0F4F5593216D24 /* liveStreamingOn.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = liveStreamingOn.mp3; path = ../../sounds/liveStreamingOn.mp3; sourceTree = "<group>"; };
6C31EDC720C06D490089C899 /* recordingOn.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = recordingOn.mp3; path = ../../sounds/recordingOn.mp3; sourceTree = "<group>"; };
6C31EDC920C06D530089C899 /* recordingOff.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = recordingOff.mp3; path = ../../sounds/recordingOff.mp3; sourceTree = "<group>"; };
75635B0820751D6D00F29C9F /* joined.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = joined.wav; path = ../../sounds/joined.wav; sourceTree = "<group>"; };
@@ -137,8 +135,6 @@
0BCA496B1EC4BBF900B793EE /* jitsi.ttf */,
75635B0820751D6D00F29C9F /* joined.wav */,
75635B0920751D6D00F29C9F /* left.wav */,
C30F88D1CB0F4F5593216D24 /* liveStreamingOff.mp3 */,
C30F88D3CB0F4F5593216D24 /* liveStreamingOn.mp3 */,
0B49424420AD8DBD00BD2DE0 /* outgoingRinging.wav */,
0B49424320AD8DBD00BD2DE0 /* outgoingStart.wav */,
6C31EDC920C06D530089C899 /* recordingOff.mp3 */,
@@ -193,6 +189,7 @@
C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */,
0B412F1B1EDEC80100B1A0A6 /* JitsiMeetViewDelegate.h */,
DEFC743D21B178FA00E4DD96 /* LocaleDetector.m */,
0B44A0181F902126009D1D64 /* MPVolumeViewManager.m */,
C6A3426B204F127900E062DD /* picture-in-picture */,
0BCA495D1EC4B6C600B793EE /* POSIX.m */,
0BCA495E1EC4B6C600B793EE /* Proximity.m */,
@@ -346,8 +343,6 @@
files = (
87FE6F3321E52437004A5DC7 /* incomingMessage.wav in Resources */,
0B49424520AD8DBD00BD2DE0 /* outgoingStart.wav in Resources */,
C30F88D0CB0F4F5593216D24 /* liveStreamingOff.mp3 in Resources */,
C30F88D2CB0F4F5593216D24 /* liveStreamingOn.mp3 in Resources */,
6C31EDCA20C06D530089C899 /* recordingOff.mp3 in Resources */,
A4414AE020B37F1A003546E6 /* rejected.wav in Resources */,
0B49424620AD8DBD00BD2DE0 /* outgoingRinging.wav in Resources */,
@@ -394,7 +389,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export NODE_BINARY=node\nexport NODE_ARGS=\"--max_old_space_size=4096\"\n../../node_modules/react-native/scripts/react-native-xcode.sh\n";
shellScript = "export NODE_BINARY=node\n../../node_modules/react-native/scripts/react-native-xcode.sh\n";
};
26796D8589142D80C8AFDA51 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
@@ -506,6 +501,7 @@
C6CC49AF207412CF000DFA42 /* PiPViewCoordinator.swift in Sources */,
DEFC743F21B178FA00E4DD96 /* LocaleDetector.m in Sources */,
0BCA495F1EC4B6C600B793EE /* AudioMode.m in Sources */,
0B44A0191F902126009D1D64 /* MPVolumeViewManager.m in Sources */,
0BCA49611EC4B6C600B793EE /* Proximity.m in Sources */,
A480429C21EE335600289B73 /* AmplitudeModule.m in Sources */,
C69EFA0C209A0F660027712B /* JMCallKitEmitter.swift in Sources */,

View File

@@ -1,5 +1,6 @@
/*
* Copyright @ 2017-present 8x8, Inc.
* 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.
@@ -16,30 +17,17 @@
#import <AVFoundation/AVFoundation.h>
#import <React/RCTEventEmitter.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTLog.h>
#import <WebRTC/WebRTC.h>
// Audio mode
typedef enum {
kAudioModeDefault,
kAudioModeAudioCall,
kAudioModeVideoCall
} JitsiMeetAudioMode;
// Events
static NSString * const kDevicesChanged = @"org.jitsi.meet:features/audio-mode#devices-update";
// Device types (must match JS and Java)
static NSString * const kDeviceTypeHeadphones = @"HEADPHONES";
static NSString * const kDeviceTypeBluetooth = @"BLUETOOTH";
static NSString * const kDeviceTypeEarpiece = @"EARPIECE";
static NSString * const kDeviceTypeSpeaker = @"SPEAKER";
static NSString * const kDeviceTypeUnknown = @"UNKNOWN";
@interface AudioMode : RCTEventEmitter<RTCAudioSessionDelegate>
@interface AudioMode : NSObject<RCTBridgeModule, RTCAudioSessionDelegate>
@property(nonatomic, strong) dispatch_queue_t workerQueue;
@@ -50,11 +38,6 @@ static NSString * const kDeviceTypeUnknown = @"UNKNOWN";
RTCAudioSessionConfiguration *defaultConfig;
RTCAudioSessionConfiguration *audioCallConfig;
RTCAudioSessionConfiguration *videoCallConfig;
RTCAudioSessionConfiguration *earpieceConfig;
BOOL forceSpeaker;
BOOL forceEarpiece;
BOOL isSpeakerOn;
BOOL isEarpieceOn;
}
RCT_EXPORT_MODULE();
@@ -63,13 +46,8 @@ RCT_EXPORT_MODULE();
return NO;
}
- (NSArray<NSString *> *)supportedEvents {
return @[ kDevicesChanged ];
}
- (NSDictionary *)constantsToExport {
return @{
@"DEVICE_CHANGE_EVENT": kDevicesChanged,
@"AUDIO_CALL" : [NSNumber numberWithInt: kAudioModeAudioCall],
@"DEFAULT" : [NSNumber numberWithInt: kAudioModeDefault],
@"VIDEO_CALL" : [NSNumber numberWithInt: kAudioModeVideoCall]
@@ -80,7 +58,8 @@ RCT_EXPORT_MODULE();
self = [super init];
if (self) {
dispatch_queue_attr_t attributes =
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, -1);
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL,
QOS_CLASS_USER_INITIATED, -1);
_workerQueue = dispatch_queue_create("AudioMode.queue", attributes);
activeMode = kAudioModeDefault;
@@ -92,7 +71,7 @@ RCT_EXPORT_MODULE();
audioCallConfig = [[RTCAudioSessionConfiguration alloc] init];
audioCallConfig.category = AVAudioSessionCategoryPlayAndRecord;
audioCallConfig.categoryOptions = AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionDefaultToSpeaker;
audioCallConfig.categoryOptions = AVAudioSessionCategoryOptionAllowBluetooth;
audioCallConfig.mode = AVAudioSessionModeVoiceChat;
videoCallConfig = [[RTCAudioSessionConfiguration alloc] init];
@@ -100,17 +79,6 @@ RCT_EXPORT_MODULE();
videoCallConfig.categoryOptions = AVAudioSessionCategoryOptionAllowBluetooth;
videoCallConfig.mode = AVAudioSessionModeVideoChat;
// Manually routing audio to the earpiece doesn't quite work unless one disables BT (weird, I know).
earpieceConfig = [[RTCAudioSessionConfiguration alloc] init];
earpieceConfig.category = AVAudioSessionCategoryPlayAndRecord;
earpieceConfig.categoryOptions = 0;
earpieceConfig.mode = AVAudioSessionModeVoiceChat;
forceSpeaker = NO;
forceEarpiece = NO;
isSpeakerOn = NO;
isEarpieceOn = NO;
RTCAudioSession *session = [RTCAudioSession sharedInstance];
[session addDelegate:self];
}
@@ -139,20 +107,24 @@ RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(setMode:(int)mode
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject) {
RTCAudioSessionConfiguration *config = [self configForMode:mode];
RTCAudioSessionConfiguration *config;
NSError *error;
if (config == nil) {
switch (mode) {
case kAudioModeAudioCall:
config = audioCallConfig;
break;
case kAudioModeDefault:
config = defaultConfig;
break;
case kAudioModeVideoCall:
config = videoCallConfig;
break;
default:
reject(@"setMode", @"Invalid mode", nil);
return;
}
// Reset.
if (mode == kAudioModeDefault) {
forceSpeaker = NO;
forceEarpiece = NO;
}
activeMode = mode;
if ([self setConfig:config error:&error]) {
@@ -160,76 +132,6 @@ RCT_EXPORT_METHOD(setMode:(int)mode
} else {
reject(@"setMode", error.localizedDescription, error);
}
[self notifyDevicesChanged];
}
RCT_EXPORT_METHOD(setAudioDevice:(NSString *)device
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject) {
NSLog(@"[AudioMode] Selected device: %@", device);
RTCAudioSession *session = [RTCAudioSession sharedInstance];
[session lockForConfiguration];
BOOL success;
NSError *error = nil;
// Reset these, as we are about to compute them.
forceSpeaker = NO;
forceEarpiece = NO;
// The speaker is special, so test for it first.
if ([device isEqualToString:kDeviceTypeSpeaker]) {
forceSpeaker = NO;
success = [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
} else {
// Here we use AVAudioSession because RTCAudioSession doesn't expose availableInputs.
AVAudioSession *_session = [AVAudioSession sharedInstance];
AVAudioSessionPortDescription *port = nil;
// Find the matching input device.
for (AVAudioSessionPortDescription *portDesc in _session.availableInputs) {
if ([portDesc.UID isEqualToString:device]) {
port = portDesc;
break;
}
}
if (port != nil) {
// First remove the override if we are going to select a different device.
if (isSpeakerOn) {
[session overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:nil];
}
// Special case for the earpiece.
if ([port.portType isEqualToString:AVAudioSessionPortBuiltInMic]) {
forceEarpiece = YES;
[self setConfig:earpieceConfig error:nil];
} else if (isEarpieceOn) {
// Reset the config.
RTCAudioSessionConfiguration *config = [self configForMode:activeMode];
[self setConfig:config error:nil];
}
// Select our preferred input.
success = [session setPreferredInput:port error:&error];
} else {
success = NO;
error = RCTErrorWithMessage(@"Could not find audio device");
}
}
[session unlockForConfiguration];
if (success) {
resolve(nil);
} else {
reject(@"setAudioDevice", error != nil ? error.localizedDescription : @"", error);
}
}
RCT_EXPORT_METHOD(updateDeviceList) {
[self notifyDevicesChanged];
}
#pragma mark - RTCAudioSessionDelegate
@@ -237,141 +139,26 @@ RCT_EXPORT_METHOD(updateDeviceList) {
- (void)audioSessionDidChangeRoute:(RTCAudioSession *)session
reason:(AVAudioSessionRouteChangeReason)reason
previousRoute:(AVAudioSessionRouteDescription *)previousRoute {
// Update JS about the changes.
[self notifyDevicesChanged];
dispatch_async(_workerQueue, ^{
switch (reason) {
case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
// If the device list changed, reset our overrides.
self->forceSpeaker = NO;
self->forceEarpiece = NO;
break;
case AVAudioSessionRouteChangeReasonCategoryChange:
// The category has changed. Check if it's the one we want and adjust as
// needed.
break;
default:
return;
}
// We don't want to touch the category when in default mode.
// This is to play well with other components which could be integrated
// into the final application.
if (self->activeMode != kAudioModeDefault) {
NSLog(@"[AudioMode] Route changed, reapplying RTCAudioSession config");
RTCAudioSessionConfiguration *config = [self configForMode:self->activeMode];
[self setConfig:config error:nil];
if (self->forceSpeaker && !self->isSpeakerOn) {
RTCAudioSession *session = [RTCAudioSession sharedInstance];
[session lockForConfiguration];
[session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
[session unlockForConfiguration];
if (reason == AVAudioSessionRouteChangeReasonCategoryChange) {
// The category has changed. Check if it's the one we want and adjust as
// needed. This notification is posted on a secondary thread, so make
// sure we switch to our worker thread.
dispatch_async(_workerQueue, ^{
// We don't want to touch the category when in default mode.
// This is to play well with other components which could be integrated
// into the final application.
if (self->activeMode != kAudioModeDefault) {
NSLog(@"Audio route changed, reapplying RTCAudioSession config");
RTCAudioSessionConfiguration *config
= self->activeMode == kAudioModeAudioCall ? self->audioCallConfig : self->videoCallConfig;
[self setConfig:config error:nil];
}
}
});
});
}
}
- (void)audioSession:(RTCAudioSession *)audioSession didSetActive:(BOOL)active {
NSLog(@"[AudioMode] Audio session didSetActive:%d", active);
}
#pragma mark - Helper methods
- (RTCAudioSessionConfiguration *)configForMode:(int) mode {
if (mode != kAudioModeDefault && forceEarpiece) {
return earpieceConfig;
}
switch (mode) {
case kAudioModeAudioCall:
return audioCallConfig;
case kAudioModeDefault:
return defaultConfig;
case kAudioModeVideoCall:
return videoCallConfig;
default:
return nil;
}
}
// Here we convert input and output port types into a single type.
- (NSString *)portTypeToString:(AVAudioSessionPort) portType {
if ([portType isEqualToString:AVAudioSessionPortHeadphones]
|| [portType isEqualToString:AVAudioSessionPortHeadsetMic]) {
return kDeviceTypeHeadphones;
} else if ([portType isEqualToString:AVAudioSessionPortBuiltInMic]
|| [portType isEqualToString:AVAudioSessionPortBuiltInReceiver]) {
return kDeviceTypeEarpiece;
} else if ([portType isEqualToString:AVAudioSessionPortBuiltInSpeaker]) {
return kDeviceTypeSpeaker;
} else if ([portType isEqualToString:AVAudioSessionPortBluetoothHFP]
|| [portType isEqualToString:AVAudioSessionPortBluetoothLE]
|| [portType isEqualToString:AVAudioSessionPortBluetoothA2DP]) {
return kDeviceTypeBluetooth;
} else {
return kDeviceTypeUnknown;
}
}
- (void)notifyDevicesChanged {
dispatch_async(_workerQueue, ^{
NSMutableArray *data = [[NSMutableArray alloc] init];
// Here we use AVAudioSession because RTCAudioSession doesn't expose availableInputs.
AVAudioSession *session = [AVAudioSession sharedInstance];
NSString *currentPort = @"";
AVAudioSessionRouteDescription *currentRoute = session.currentRoute;
// Check what the current device is. Because the speaker is somewhat special, we need to
// check for it first.
if (currentRoute != nil) {
AVAudioSessionPortDescription *output = currentRoute.outputs.firstObject;
AVAudioSessionPortDescription *input = currentRoute.inputs.firstObject;
if (output != nil && [output.portType isEqualToString:AVAudioSessionPortBuiltInSpeaker]) {
currentPort = kDeviceTypeSpeaker;
self->isSpeakerOn = YES;
} else if (input != nil) {
currentPort = input.UID;
self->isSpeakerOn = NO;
self->isEarpieceOn = [input.portType isEqualToString:AVAudioSessionPortBuiltInMic];
}
}
BOOL headphonesAvailable = NO;
for (AVAudioSessionPortDescription *portDesc in session.availableInputs) {
if ([portDesc.portType isEqualToString:AVAudioSessionPortHeadsetMic] || [portDesc.portType isEqualToString:AVAudioSessionPortHeadphones]) {
headphonesAvailable = YES;
break;
}
}
for (AVAudioSessionPortDescription *portDesc in session.availableInputs) {
// Skip "Phone" if headphones are present.
if (headphonesAvailable && [portDesc.portType isEqualToString:AVAudioSessionPortBuiltInMic]) {
continue;
}
id deviceData
= @{
@"type": [self portTypeToString:portDesc.portType],
@"name": portDesc.portName,
@"uid": portDesc.UID,
@"selected": [NSNumber numberWithBool:[portDesc.UID isEqualToString:currentPort]]
};
[data addObject:deviceData];
}
// We need to manually add the speaker because it will never show up in the
// previous list, as it's not an input.
[data addObject:
@{ @"type": kDeviceTypeSpeaker,
@"name": @"Speaker",
@"uid": kDeviceTypeSpeaker,
@"selected": [NSNumber numberWithBool:[kDeviceTypeSpeaker isEqualToString:currentPort]]
}];
[self sendEventWithName:kDevicesChanged body:data];
});
}
@end

View File

@@ -42,7 +42,7 @@
*/
@property (nonatomic, nullable) JitsiMeetConferenceOptions *defaultConferenceOptions;
#pragma mark - This class is a singleton
#pragma mak - This class is a singleton
+ (instancetype _Nonnull)sharedInstance;

View File

@@ -0,0 +1,62 @@
/*
* Copyright @ 2017-present 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 <React/RCTUIManager.h>
#import <React/RCTViewManager.h>
@import MediaPlayer;
@interface MPVolumeViewManager : RCTViewManager
@end
@implementation MPVolumeViewManager
RCT_EXPORT_MODULE()
- (UIView *)view {
MPVolumeView *volumeView = [[MPVolumeView alloc] init];
volumeView.showsRouteButton = YES;
volumeView.showsVolumeSlider = NO;
return (UIView *) volumeView;
}
RCT_EXPORT_METHOD(show:(nonnull NSNumber *)reactTag) {
[self.bridge.uiManager addUIBlock:^(
__unused RCTUIManager *uiManager,
NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[MPVolumeView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting \
MPVolumeView, got: %@", view);
} else {
// Simulate a click
UIButton *btn = nil;
for (UIView *buttonView in ((UIView *) view).subviews) {
if ([buttonView isKindOfClass:[UIButton class]]) {
btn = (UIButton *) buttonView;
break;
}
}
if (btn != nil) {
[btn sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
}];
}
@end

View File

@@ -1,6 +1,5 @@
{
"en": "Engels",
"af": "",
"az": "Azerbeidjans",
"bg": "Bulgaars",
"cs": "Tsjeggies",

View File

@@ -1,19 +1,11 @@
{
"en": "İngilis",
"af": "",
"az": "",
"bg": "Bolqar",
"cs": "",
"de": "Alman",
"el": "",
"eo": "",
"es": "İspan",
"fr": "Fransız",
"en": "",
"bg": "",
"de": "",
"es": "",
"fr": "",
"hy": "",
"it": "",
"ja": "",
"ko": "",
"nb": "",
"oc": "",
"pl": "",
"ptBR": "",
@@ -22,6 +14,7 @@
"sl": "",
"sv": "",
"tr": "",
"vi": "",
"zhCN": ""
"zhCN": "",
"nb": "",
"eo": ""
}

View File

@@ -1,18 +1,18 @@
{
"en": "Английски",
"af": "Африканс",
"az": "Азербайджански",
"af": "",
"az": "",
"bg": "Български",
"cs": "Чешки",
"cs": "",
"de": "Немски",
"el": "Гръцки",
"el": "",
"eo": "Есперанто",
"es": "Испански",
"fr": "Френски",
"hy": "Арменски",
"it": "Италиански",
"ja": "Японски",
"ko": "Корейски",
"ja": "",
"ko": "",
"nb": "Норвежки букмол",
"oc": "Окситански",
"pl": "Полски",
@@ -22,6 +22,6 @@
"sl": "Словенски",
"sv": "Шведски",
"tr": "Турски",
"vi": "Виетнамски",
"vi": "",
"zhCN": "Китайски (Китай)"
}

View File

@@ -1,27 +1 @@
{
"en": "",
"af": "",
"az": "",
"bg": "",
"cs": "",
"de": "",
"el": "",
"eo": "",
"es": "",
"fr": "",
"hy": "",
"it": "",
"ja": "",
"ko": "",
"nb": "",
"oc": "",
"pl": "",
"ptBR": "",
"ru": "",
"sk": "",
"sl": "",
"sv": "",
"tr": "",
"vi": "",
"zhCN": ""
}
{}

View File

@@ -1,27 +1,20 @@
{
"en": "Angličtina",
"af": "",
"az": "",
"bg": "Bulharština",
"cs": "",
"de": "Němčina",
"el": "",
"eo": "Esperanto",
"es": "Španělština",
"fr": "Francouština",
"hy": "Arménština",
"it": "Italština",
"ja": "",
"ko": "",
"nb": "Norština Bokmal",
"oc": "Okcitánština",
"pl": "Polština",
"ptBR": "Portugalština (Brazilská)",
"ru": "Ruština",
"sk": "Slovenština",
"sl": "Slovinština",
"sv": "Švédština",
"tr": "Turečtina",
"vi": "",
"zhCN": "Čínština (Čína)"
"de": "",
"es": "",
"fr": "",
"hy": "",
"it": "",
"oc": "",
"pl": "",
"ptBR": "",
"ru": "",
"sk": "",
"sl": "",
"sv": "",
"tr": "",
"zhCN": "",
"nb": "",
"eo": ""
}

View File

@@ -1,6 +1,5 @@
{
"en": "Englisch",
"af": "",
"az": "",
"bg": "Bulgarisch",
"cs": "",

View File

@@ -1,27 +0,0 @@
{
"en": "",
"af": "",
"az": "",
"bg": "",
"cs": "",
"de": "",
"el": "",
"eo": "",
"es": "",
"fr": "",
"hy": "",
"it": "",
"ja": "",
"ko": "",
"nb": "",
"oc": "",
"pl": "",
"ptBR": "",
"ru": "",
"sk": "",
"sl": "",
"sv": "",
"tr": "",
"vi": "",
"zhCN": ""
}

View File

@@ -1,27 +1,20 @@
{
"en": "Angla",
"af": "",
"az": "",
"bg": "Bulgara",
"cs": "",
"de": "Germana",
"el": "",
"eo": "Esperanto",
"es": "Hispana",
"fr": "Franca",
"hy": "Armena",
"it": "Itala",
"ja": "",
"ko": "",
"nb": "Norvega (Bukmola)",
"oc": "Okcitana",
"pl": "Pola",
"ptBR": "Portugala (Brazila)",
"ptBR": "Portugala (Brazilo)",
"ru": "Rusa",
"sk": "Slovaka",
"sl": "Slovena",
"sv": "Sveda",
"tr": "Turka",
"vi": "",
"zhCN": "Ĉina (Ĉinuja)"
"zhCN": "Ĉina (Ĉinujo)",
"nb": "Norvega (Bokmål)",
"eo": "Esperanto"
}

View File

@@ -1,19 +1,11 @@
{
"en": "Inglés",
"af": "Africano",
"az": "Azerbaijani",
"bg": "Búlgaro",
"cs": "Czech",
"de": "Alemán",
"el": "Griego",
"eo": "Esperanto",
"es": "Español",
"fr": "Francés",
"hy": "Armenio",
"it": "Italiano",
"ja": "Jopones",
"ko": "Coreano",
"nb": "Noruego (bokmal)",
"oc": "Occitano",
"pl": "Polaco",
"ptBR": "Portugués (Brasil)",
@@ -22,6 +14,7 @@
"sl": "Esloveno",
"sv": "Sueco",
"tr": "Turco",
"vi": "Vietnamita",
"zhCN": "Chino (China)"
"zhCN": "Chino (China)",
"nb": "Noruego (bokmal)",
"eo": "Esperanto"
}

View File

@@ -1,27 +0,0 @@
{
"en": "",
"af": "",
"az": "",
"bg": "",
"cs": "",
"de": "",
"el": "",
"eo": "",
"es": "",
"fr": "",
"hy": "",
"it": "",
"ja": "",
"ko": "",
"nb": "",
"oc": "",
"pl": "",
"ptBR": "",
"ru": "",
"sk": "",
"sl": "",
"sv": "",
"tr": "",
"vi": "",
"zhCN": ""
}

View File

@@ -1,27 +1,20 @@
{
"en": "انگلیسی",
"af": "",
"az": "آذری , آذربایجان",
"bg": "بلغاری",
"cs": "چک",
"de": "آلمانی",
"el": "یونانی",
"eo": "اسپرانتو",
"es": "اسپانیایی",
"fr": "فرانسوی",
"hy": "ارمنی",
"it": "ایتالیایی",
"ja": "ژاپنی",
"ko": "کره ای",
"nb": "بوکمال نروژی",
"oc": "اکسیتان(قدیمی)",
"pl": "لهستانی",
"ptBR": "پرتغالی (برزیل)",
"ru": "روسی",
"sk": "اسلواکی",
"sl": "اسلوونیایی",
"sv": "سوئدی",
"tr": "ترکی",
"vi": "ویتنامی",
"zhCN": "چینی"
"en": "",
"bg": "",
"de": "",
"es": "",
"fr": "",
"hy": "",
"it": "",
"oc": "",
"pl": "",
"ptBR": "",
"ru": "",
"sk": "",
"sl": "",
"sv": "",
"tr": "",
"zhCN": "",
"nb": "",
"eo": ""
}

View File

@@ -1,27 +0,0 @@
{
"en": "",
"af": "",
"az": "",
"bg": "",
"cs": "",
"de": "",
"el": "",
"eo": "",
"es": "",
"fr": "",
"hy": "",
"it": "",
"ja": "",
"ko": "",
"nb": "",
"oc": "",
"pl": "",
"ptBR": "",
"ru": "",
"sk": "",
"sl": "",
"sv": "",
"tr": "",
"vi": "",
"zhCN": ""
}

View File

@@ -1,31 +1,26 @@
{
"en": "Anglais",
"af": "",
"az": "Azerbaïdjanais",
"bg": "Bulgare",
"ca": "",
"cs": "Tchèque",
"de": "Allemand",
"el": "Grec",
"enGB": "",
"eo": "Espéranto",
"es": "Espagnol",
"esUS": "",
"fi": "",
"fr": "Français",
"frCA": "",
"hr": "",
"hy": "Arménien",
"it": "Italien",
"ja": "Japonais",
"ko": "Coréen",
"nl": "",
"nb": "Norvégien Bokmal",
"oc": "Occitan",
"pl": "Polonais",
"ptBR": "Portugais (Brésil)",
"ru": "Russe",
"sk": "Slovaque",
"sl": "Slovène",
"sv": "Suédois",
"tr": "Turc",
"vi": "Vietnamien",
"zhCN": "Chinois (Chine)",
"zhTW": ""
"zhCN": "Chinois (Chine)"
}

View File

@@ -1,27 +0,0 @@
{
"en": "",
"af": "",
"az": "",
"bg": "",
"cs": "",
"de": "",
"el": "",
"eo": "",
"es": "",
"fr": "",
"hy": "",
"it": "",
"ja": "",
"ko": "",
"nb": "",
"oc": "",
"pl": "",
"ptBR": "",
"ru": "",
"sk": "",
"sl": "",
"sv": "",
"tr": "",
"vi": "",
"zhCN": ""
}

View File

@@ -1,27 +1,27 @@
{
"en": "Engleski",
"af": "Afrikanski",
"az": "Ažerbejdžanski",
"bg": "Bugarski",
"cs": "Češki",
"de": "Njemački",
"el": "Grčki",
"eo": "Esperanto",
"es": "Španjolski",
"fr": "Francuski",
"hy": "Armenski",
"it": "Talijanski",
"ja": "Japanski",
"ko": "Korejski",
"nb": "Norveški Bokmal",
"oc": "Okcitanski",
"pl": "Poljski",
"ptBR": "Portugalski (Brazil)",
"ru": "Ruski",
"sk": "Slovački",
"sl": "Slovenski",
"sv": "Švedski",
"tr": "Turski",
"vi": "Vijetnamski",
"zhCN": "Kineski (Kina)"
"en": "",
"af": "",
"az": "",
"bg": "",
"cs": "",
"de": "",
"el": "",
"eo": "",
"es": "",
"fr": "",
"hy": "",
"it": "",
"ja": "",
"ko": "",
"nb": "",
"oc": "",
"pl": "",
"ptBR": "",
"ru": "",
"sk": "",
"sl": "",
"sv": "",
"tr": "",
"vi": "",
"zhCN": ""
}

View File

@@ -1,27 +1,20 @@
{
"en": "Angol",
"af": "",
"az": "",
"bg": "Bolgár",
"cs": "",
"de": "Német",
"el": "",
"eo": "Eszperantó",
"es": "Spanyol",
"fr": "Francia",
"hy": "Örmény",
"it": "Olasz",
"ja": "",
"ko": "",
"nb": "Norvég bokmal",
"oc": "Okszitán",
"pl": "Lengyel",
"ptBR": "Portugál (Brazil)",
"ru": "Orosz",
"sk": "Szlovák",
"sl": "Szlovén",
"sv": "Svéd",
"tr": "Török",
"vi": "",
"zhCN": "Kínai (Kína)"
"en": "",
"bg": "",
"de": "",
"es": "",
"fr": "",
"hy": "",
"it": "",
"oc": "",
"pl": "",
"ptBR": "",
"ru": "",
"sk": "",
"sl": "",
"sv": "",
"tr": "",
"zhCN": "",
"nb": "",
"eo": ""
}

View File

@@ -1,19 +1,11 @@
{
"en": "Անգլերեն",
"af": "",
"az": "",
"bg": "Բուլղարերեն",
"cs": "",
"de": "Գերմաներեն ",
"el": "",
"eo": "Էսպերանտո",
"es": "Իսպաներեն",
"fr": "Ֆրանսերեն",
"hy": "Հայերեն",
"it": "Իտալերեն",
"ja": "",
"ko": "",
"nb": "Նորվեգերեն",
"oc": "Օքսիտաներեն",
"pl": "Լեհերեն",
"ptBR": "Պորտուգալերեն (Բրազիլիա)",
@@ -22,6 +14,7 @@
"sl": "Սլովեներեն ",
"sv": "Շվեդերեն ",
"tr": "Թուրքերեն",
"vi": "",
"zhCN": "Չիներեն"
"zhCN": "Չիներեն",
"nb": "Նորվեգերեն",
"eo": "Էսպերանտո"
}

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