Compare commits

...

30 Commits

Author SHA1 Message Date
Saúl Ibarra Corretgé
b768b88491 android: add ability to override SDK version when releasing 2019-04-12 15:39:29 +02:00
Saúl Ibarra Corretgé
9f339c452b android: raise SDK version 2019-04-12 15:39:29 +02:00
Leonard Kim
c34f9cf233 fix(screenshare): properly gate autopin behavior behind flag check 2019-04-11 09:09:48 -07:00
virtuacoplenny
76642b7c4b feat(screenshare): add auto pin of latest screen share (#4076) 2019-04-11 08:53:34 -07:00
Saúl Ibarra Corretgé
b78989f5f2 android: improve SDK release script
- don't hardcode defaults in gradle files
- allow for uploading also to HTTP URLs
- support HTTP authentication when publishing
2019-04-11 17:43:33 +02:00
virtuacoplenny
088b5d95c2 chore(deps): update lib for listener leak fix (#4084) 2019-04-11 08:00:05 -07:00
virtuacoplenny
c6e5adbe0e fix(large-video): respect update in progress when queuing update (#4078)
When a fade in/out animation is in progress, another large
video update can be queued but can try to force itself onto
large video. For example a pin can be in progress and while
the fade in/out animation plays, local video can change its
video type during the animation and forcing an update of
large video. This results in local video getting forcible
updated onto large video while the pinned video is left on
small video only.
2019-04-10 08:16:02 -07:00
Bettenbuk Zoltan
8bb56be317 [RN] Add conference connecting overlay 2019-04-10 15:47:36 +02:00
Bettenbuk Zoltan
84b917d708 Reorg overlay feature files 2019-04-10 15:47:36 +02:00
Bettenbuk Zoltan
18d908ce84 Fix flow errors from base/connection 2019-04-10 15:47:36 +02:00
Bettenbuk Zoltan
3987655f2a Refactor config loading 2019-04-10 15:47:36 +02:00
Saúl Ibarra Corretgé
ee3b8af4cf ios: remove PiP sample application
It now lives here: https://github.com/jitsi/jitsi-meet-sdk-samples
2019-04-10 15:10:47 +02:00
Saúl Ibarra Corretgé
9625be1db3 misc: don't show a warning on Safari with VP8 2019-04-10 14:15:02 +02:00
Saúl Ibarra Corretgé
21c0745504 android,ios: now working on version 19.2 2019-04-10 14:14:04 +02:00
Saúl Ibarra Corretgé
26c9ee5f9c deps: lib-jitsi-meet@9659b4e413b12c637810fb2ab52354f1357a177e 2019-04-10 12:32:57 +02:00
Saúl Ibarra Corretgé
9b7af64e11 ios: raise SDK version 2019-04-09 16:08:45 +02:00
Saúl Ibarra Corretgé
f26c5570df ios: update sample PiP app
- Xcode 10.2 + Swift 5
- Latest SDK API
- Fix warnings
2019-04-09 16:08:45 +02:00
Saúl Ibarra Corretgé
d37a0eee3a ios: fix compilation warnings 2019-04-09 16:08:45 +02:00
Saúl Ibarra Corretgé
024fc73e63 ios: update to Xcode 5 and Swift 5 2019-04-09 16:08:45 +02:00
Saúl Ibarra Corretgé
bdaabf6d3d odeps: react-native@0.59.4
Fixes a crash on some old Android devices.
2019-04-09 16:08:45 +02:00
virtuacoplenny
7a677ead93 ref(device-selection): set audio output sink id after receiving ref (#4066)
The Audio.js setRef callback does not behave like react ref callback
in that the former will not have fired before componentDidMount
but the later will have. So for audio output preview, trying to set
sink id on mount will no-op because it does not have a ref yet to
Audio.js, possibly leading to audio output previews playing on
the default speaker device. This generally has not been a user
visible problem due to coincidence; other re-renders necessary
by the parent of audio output preview will have triggered
componentDidUpdates on the audio out preview, which would then
set the sink id on the Audio.js ref it should have received
by then.
2019-04-08 10:38:06 -07:00
virtuacoplenny
e7812c7d84 fix(device-selection): search for device by label and kind (#4064)
Searching for a device (id) by label alone can result in
false results when devices share labels, such as a mic
and speaker having the same label. To prevent such,
specify the device kind to be found instead of iterating
over all device kinds.
2019-04-08 10:03:45 -07:00
damencho
ea54713f9a Supports prosody 0.11 when configuring.
Doing few changes needed for general config and for tokens.
2019-04-05 17:18:17 +02:00
virtuacoplenny
5a99697ae2 fix(toolbox): fix typo in action type for hide timeout (#4069) 2019-04-04 10:53:14 -07:00
virtuacoplenny
ec09085a50 fix(device-selection): set audio output device on initial configuration
When the iFrame api is used to set a preferred audio output using
options passed into the JitsiMeetExternalAPI constructor, no logic
fires to actually change the audio output destination.
2019-04-04 08:10:01 -07:00
virtuacoplenny
b731459ea4 fix(device-selection): use device kind when getting current devices (#4059)
Devices of different kinds can have the same id, such as speaker
and mic both being default. Using id only can then lead to
incorrectly setting device descriptions in the current devices
object.
2019-04-03 08:06:41 -07:00
Saúl Ibarra Corretgé
f73d3a4063 ios: add SDK release script 2019-04-03 16:15:11 +02:00
Saúl Ibarra Corretgé
4c3cf8c14a android: add an improved SDK release script
It releases the SDK and all dependencies (including React Native) to the
specified Maven repo.
2019-04-03 16:15:11 +02:00
Saúl Ibarra Corretgé
1f371ab055 android: simplify qualifying dependencies when publishing
Use an ever increasing number so no manual updates are necessary.
2019-04-03 16:15:11 +02:00
Saúl Ibarra Corretgé
dfeb26597b android: make Maven repo used for publising configurable 2019-04-03 16:15:11 +02:00
91 changed files with 978 additions and 1403 deletions

View File

@@ -2,7 +2,9 @@
## Build your own, or use a pre-build SDK artifacts/binaries
Jitsi conveniently provides a pre-build SDK artifacts/binaries in its Maven repository. When you do not require any modification to the SDK itself, it's suggested to use the pre-build SDK. This avoids the complexity of building and installing your own SDK artifacts/binaries.
Jitsi conveniently provides a pre-build SDK artifacts/binaries in its Maven repository. When you do not require any
modification to the SDK itself or any of its dependencies, it's suggested to use the pre-build SDK. This avoids the
complexity of building and installing your own SDK artifacts/binaries.
### Use pre-build SDK artifacts/binaries
@@ -29,7 +31,7 @@ Dependency definitions belong in the individual module `build.gradle` files:
```gradle
dependencies {
// (other dependencies)
implementation ('org.jitsi.react:jitsi-meet-sdk:+') { transitive = true }
implementation ('org.jitsi.react:jitsi-meet-sdk:2.+') { transitive = true }
}
```
@@ -44,49 +46,20 @@ A note on dependencies: Apart from the SDK, Jitsi also publishes a binary Maven
If you want to use a SDK that is built from source, you will likely benefit from composing a local Maven repository that contains these dependencies. The text below describes how you create a repository that includes both the SDK as well as these dependencies. For illustration purposes, we'll define the location of this local Maven repository as `/tmp/repo`
In source code form, the Android SDK dependencies are locked/pinned by package.json and package-lock.json of the Jitsi Meet project. To obtain the data, execute NPM in the parent directory:
In source code form, the Android SDK dependencies are locked/pinned by package.json and package-lock.json of the Jitsi Meet project. To obtain the data, execute NPM in the jitsi-meet project directory:
$ (cd ..; npm install)
npm install
This will pull in the dependencies in either binary format, or in source code format, somewhere under /node_modules/
At the time of writing, there are two packages pulled in in binary format.
Third-party React Native _modules_, which Jitsi Meet SDK for Android depends on, are download by NPM in source code
or binary form. These need to be assembled into Maven artifacts, and then published to your local Maven repository.
A script is provided to facilitate this. From the root of the jitsi-meet project repository, run:
To copy React Native to your local Maven repository, you can simply copy part of the directory structure that was pulled in by NPM:
./android/scripts/release-sdk.sh /tmp/repo
$ cp -r ../node_modules/react-native/android/com /tmp/repo/
Alternatively, you can use the scripts located in the android/scripts directory to publish these dependencies to your Maven repo.
Third-party React Native _modules_, which Jitsi Meet SDK for Android depends on, are download by NPM in source code form. These need to be assembled into Maven artifacts, and then published to your local Maven repository. The SDK project facilitates this.
To prepare, Configure the Maven repositories in which you are going to publish the SDK artifacts/binaries. In `android/sdk/build.gradle` as well as in `android/build.gradle` modify the lines that contain:
"file:${rootProject.projectDir}/../../jitsi-maven-repository/releases"
Change this value (which represents the Maven repository location used internally by the Jitsi Developers) to the location of the repository that you'd like to use:
"file:/tmp/repo"
Make sure to do this in both files! Each file should require one line to be changed.
To prevent artifacts from previous builds affecting you're outcome, it's good to start with cleaning your work directories:
$ ./gradlew clean
To create the release assembly for any _specific_ third-party React Native module that you need, you can execture the following commands, replace the module name in the examples below.
$ ./gradlew :react-native-webrtc:assembleRelease
$ ./gradlew :react-native-webrtc:publish
You build and publish the SDK itself in the same way:
$ ./gradlew :sdk:assembleRelease
$ ./gradlew :sdk:publish
Alternatively, you can assemble and publish _all_ subprojects, which include the react-native modules, but also the SDK itself, with a single command:
$ ./gradlew clean assembleRelease publish
This will build and publish the SDK, and all of its dependencies to the specified Maven repository (`/tmp/repo`) in
this example.
You're now ready to use the artifacts. In _your_ project, add the Maven repository that you used above (`/tmp/repo`) into your top-level `build.gradle` file:
@@ -104,7 +77,8 @@ Then, define the dependency `org.jitsi.react:jitsi-meet-sdk` into the `build.gra
implementation ('org.jitsi.react:jitsi-meet-sdk:+') { transitive = true }
Note that there should not be a need to explicitly add the other dependencies, as they will be pulled in as transitive dependencies of `jitsi-meet-sdk`.
Note that there should not be a need to explicitly add the other dependencies, as they will be pulled in as transitive
dependencies of `jitsi-meet-sdk`.
</details>

View File

@@ -55,45 +55,33 @@ allprojects {
publishing {
publications {}
repositories {
maven { url "file:${rootProject.projectDir}/../../jitsi-maven-repository/releases" }
maven {
url rootProject.ext.mavenRepo
if (!rootProject.ext.mavenRepo.startsWith("file")) {
credentials {
username rootProject.ext.mavenUser
password rootProject.ext.mavenPassword
}
}
}
}
}
}
// Use the number of seconds/10 since Jan 1 2019 as the version qualifier number.
// This will last for the next ~680 years.
// https://stackoverflow.com/a/38643838
def versionQualifierNumber = (int)(((new Date().getTime()/1000) - 1546297200) / 10)
afterEvaluate { project ->
if (project.name.startsWith('react-native-')) {
def npmManifest = project.file('../package.json')
def json = new JsonSlurper().parseText(npmManifest.text)
// React Native modules have an npm peer dependency on react-native,
// they do not have an npm dependency on it. Further below though we
// choose a react-native version (range) when we represent them as
// Maven artifacts. Effectively, we are forking the projects by not
// complying with the full range of their npm peer dependency and,
// consequently, we should qualify their version.
def versionQualifier = '-jitsi-1'
if ('react-native-background-timer' == project.name)
versionQualifier = '-jitsi-4' // 2.1.1 + react-native 0.59
else if ('react-native-calendar-events' == project.name)
versionQualifier = '-jitsi-3' // 1.6.4 + react-native 0.59
else if ('react-native-fast-image' == project.name)
versionQualifier = '-jitsi-3' // 5.1.1 + react-native 0.59
else if ('react-native-google-signin' == project.name)
versionQualifier = '-jitsi-3' // 1.0.2 + react-native 0.59
else if ('react-native-immersive' == project.name)
versionQualifier = '-jitsi-6' // 2.0.0 + react-native 0.59
else if ('react-native-keep-awake' == project.name)
versionQualifier = '-jitsi-5' // 4.0.0 + react-native 0.59
else if ('react-native-linear-gradient' == project.name)
versionQualifier = '-jitsi-2' // 2.5.3 + react-native 0.59
else if ('react-native-sound' == project.name)
versionQualifier = '-jitsi-3' // 0.10.12 + react-native 0.59
else if ('react-native-vector-icons' == project.name)
versionQualifier = '-jitsi-4' // 6.0.2 + react-native 0.59
else if ('react-native-webrtc' == project.name)
versionQualifier = '-jitsi-10' // 032ee5c90e2c5ff27ab2f952217104772fcbd155 + react-native 0.59
// Release every dependency the SDK has with a -jitsi-XXX qualified version. This allows
// us to pin the dependencies and make sure they are always updated, no matter what.
project.version = "${json.version}${versionQualifier}"
project.version = "${json.version}-jitsi-${versionQualifierNumber}"
project.android {
compileSdkVersion rootProject.ext.compileSdkVersion
@@ -171,6 +159,11 @@ ext {
// of ours.
moduleGroupId = 'com.facebook.react'
// Maven repo where artifacts will be published
mavenRepo = System.env.MVN_REPO ?: ""
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

View File

@@ -17,5 +17,5 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
appVersion=19.1.0
sdkVersion=2.0.0
appVersion=19.2.0
sdkVersion=2.1.0

View File

@@ -1,19 +0,0 @@
#!/bin/bash
CWD=$(dirname $0)
MVN_REPO=$(realpath $1)
RN_VERSION=$(jq -r '.dependencies."react-native"' ${CWD}/../../package.json)
pushd ${CWD}/../../node_modules/react-native/android/com/facebook/react/react-native/${RN_VERSION}
mvn \
deploy:deploy-file \
-Durl=file://${MVN_REPO} \
-Dfile=react-native-${RN_VERSION}.aar \
-Dpackaging=aar \
-Dsources=react-native-${RN_VERSION}-sources.jar \
-Djavadoc=react-native-${RN_VERSION}-javadoc.jar \
-DgeneratePom=false \
-DpomFile=react-native-${RN_VERSION}.pom
popd

81
android/scripts/release-sdk.sh Executable file
View File

@@ -0,0 +1,81 @@
#!/bin/bash
set -e -u
THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
DEFAULT_MVN_REPO="${THIS_DIR}/../../../jitsi-maven-repository/releases"
THE_MVN_REPO=${MVN_REPO:-${1:-$DEFAULT_MVN_REPO}}
MVN_HTTP=0
DEFAULT_SDK_VERSION=$(grep sdkVersion ${THIS_DIR}/../gradle.properties | cut -d"=" -f2)
SDK_VERSION=${OVERRIDE_SDK_VERSION:-${DEFAULT_SDK_VERSION}}
RN_VERSION=$(jq -r '.dependencies."react-native"' ${THIS_DIR}/../../package.json)
if [[ $THE_MVN_REPO == http* ]]; then
MVN_HTTP=1
else
MVN_REPO_PATH=$(realpath $THE_MVN_REPO)
THE_MVN_REPO="file:${MVN_REPO_PATH}"
fi
export MVN_REPO=$THE_MVN_REPO
echo "Releasing Jitsi Meet SDK ${SDK_VERSION}"
echo "Using ${MVN_REPO} as the Maven repo"
if [[ $MVN_HTTP == 1 ]]; then
# Push React Native
echo "Pushing React Native ${RN_VERSION} to the Maven repo"
pushd ${THIS_DIR}/../../node_modules/react-native/android/com/facebook/react/react-native/${RN_VERSION}
mvn \
deploy:deploy-file \
-Durl=${MVN_REPO} \
-DrepositoryId=${MVN_REPO_ID} \
-Dfile=react-native-${RN_VERSION}.aar \
-Dpackaging=aar \
-DgeneratePom=false \
-DpomFile=react-native-${RN_VERSION}.pom || true
popd
else
# Check if an SDK with that same version has already been released
if [[ -d ${MVN_REPO}/org/jitsi/react/jitsi-meet-sdk/${SDK_VERSION} ]]; then
echo "There is already a release with that version in the Maven repo!"
exit 1
fi
# First push React Native, if necessary
if [[ ! -d ${MVN_REPO}/com/facebook/react/react-native/${RN_VERSION} ]]; then
echo "Pushing React Native ${RN_VERSION} to the Maven repo"
pushd ${THIS_DIR}/../../node_modules/react-native/android/com/facebook/react/react-native/${RN_VERSION}
mvn \
deploy:deploy-file \
-Durl=${MVN_REPO} \
-Dfile=react-native-${RN_VERSION}.aar \
-Dpackaging=aar \
-DgeneratePom=false \
-DpomFile=react-native-${RN_VERSION}.pom
popd
fi
fi
# Now build and publish the Jitsi Meet SDK and its dependencies
echo "Building and publishing the Jitsi Meet SDK"
pushd ${THIS_DIR}/../
./gradlew clean assembleRelease publish
popd
if [[ $MVN_HTTP == 0 ]]; then
# The artifacts are now on the Maven repo, commit them
pushd ${MVN_REPO_PATH}
if [[ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" == "true" ]]; then
git add -A .
git commit -m "Jitsi Meet SDK + dependencies"
fi
popd
# Tag the release
git tag -a android-sdk-${SDK_VERSION}
fi
# Done!
echo "Finished! Don't forget to push the tag and the Maven repo artifacts."

View File

@@ -167,7 +167,7 @@ publishing {
aarArchive(MavenPublication) {
groupId 'org.jitsi.react'
artifactId 'jitsi-meet-sdk'
version project.sdkVersion
version System.env.OVERRIDE_SDK_VERSION ?: project.sdkVersion
artifact("${project.buildDir}/outputs/aar/${project.name}-release.aar") {
extension "aar"
@@ -201,6 +201,14 @@ publishing {
}
repositories {
maven { url "file:${rootProject.projectDir}/../../jitsi-maven-repository/releases" }
maven {
url rootProject.ext.mavenRepo
if (!rootProject.ext.mavenRepo.startsWith("file")) {
credentials {
username rootProject.ext.mavenUser
password rootProject.ext.mavenPassword
}
}
}
}
}

4
debian/control vendored
View File

@@ -36,7 +36,7 @@ Description: Configuration for web serving of Jitsi Meet
Package: jitsi-meet-prosody
Architecture: all
Depends: openssl, prosody | prosody-trunk
Depends: openssl, prosody | prosody-trunk | prosody-0.11
Description: Prosody configuration for Jitsi Meet
Jitsi Meet is a WebRTC JavaScript application that uses Jitsi
Videobridge to provide high quality, scalable video conferences.
@@ -50,6 +50,6 @@ Description: Prosody configuration for Jitsi Meet
Package: jitsi-meet-tokens
Architecture: all
Depends: ${misc:Depends}, prosody-trunk (>= 1nightly607), libssl-dev, luarocks, jitsi-meet-prosody
Depends: ${misc:Depends}, prosody-trunk (>= 1nightly747) | prosody-0.11 | prosody (>= 0.11.2), libssl-dev, luarocks, jitsi-meet-prosody
Description: Prosody token authentication plugin for Jitsi Meet

View File

@@ -125,6 +125,19 @@ case "$1" in
ln -sf /var/lib/prosody/$JVB_HOSTNAME.crt /etc/prosody/certs/$JVB_HOSTNAME.crt
fi
PR11_INSTALL_CHECK="$(dpkg-query -f '${Status}' -W 'prosody-0.11' 2>/dev/null | awk '{print $3}' || true)"
echo "PR11_INSTALL_CHECK is $PR11_INSTALL_CHECK"
PR_VER_INSTALLED=$(dpkg-query -f='${Version}\n' --show prosody 2>/dev/null || true)
echo "PR_VER_INSTALLED is $PR_VER_INSTALLED"
if [ "$PR11_INSTALL_CHECK" = "installed" ] \
|| [ "$PR11_INSTALL_CHECK" = "unpacked" ] \
|| dpkg --compare-versions "$PR_VER_INSTALLED" gt "0.11" ; then
sed -i 's/storage = \"null\"/storage = \"memory\"/g' $PROSODY_HOST_CONFIG
# trigger a restart
PROSODY_CONFIG_PRESENT="false"
fi
if [ ! -f /var/lib/prosody/$JICOFO_AUTH_DOMAIN.crt ]; then
# prosodyctl takes care for the permissions
# echo for using all default values

View File

@@ -69,14 +69,17 @@ case "$1" in
echo "Failed to install basexx - try installing it manually"
fi
PR11_INSTALL_CHECK="$(dpkg-query -f '${Status}' -W 'prosody-0.11' 2>/dev/null | awk '{print $3}' || true)"
PR_VER_INSTALLED=$(dpkg-query -f='${Version}\n' --show prosody 2>/dev/null || true)
if [ "$PR11_INSTALL_CHECK" = "installed" ] \
|| [ "$PR11_INSTALL_CHECK" = "unpacked" ] \
|| dpkg --compare-versions "$PR_VER_INSTALLED" gt "0.11" ; then
sed -i 's/module:hook/module:hook_global/g' /usr/share/jitsi-meet/prosody-plugins/mod_auth_token.lua
fi
if [ -x "/etc/init.d/prosody" ]; then
invoke-rc.d prosody restart
fi
echo "This package requires BOSH Prosody module to be patched !"
echo "Use the following command, after this package has been installed and"
echo "after every prosody-trunk upgrade:"
echo "sudo patch -N /usr/lib/prosody/modules/mod_bosh.lua /usr/share/jitsi-meet/prosody-plugins/mod_bosh.lua.patch"
fi
else
echo "Prosody config not found at $PROSODY_HOST_CONFIG - unable to auto-configure token authentication"

View File

@@ -195,6 +195,12 @@ var interfaceConfig = {
*/
// ANDROID_APP_PACKAGE: 'org.jitsi.meet',
/**
* A UX mode where the last screen share participant is automatically
* pinned. Note: this mode is experimental and subject to breakage.
*/
// AUTO_PIN_LATEST_SCREEN_SHARE: false,
/**
* Override the behavior of some notifications to remain displayed until
* explicitly dismissed through a user action. The value is how long, in

View File

@@ -84,8 +84,8 @@ PODS:
- nanopb/decode (0.3.901)
- nanopb/encode (0.3.901)
- ObjectiveDropboxOfficial (3.9.4)
- React (0.59.2):
- React/Core (= 0.59.2)
- React (0.59.4):
- React/Core (= 0.59.4)
- react-native-background-timer (2.1.1):
- React
- react-native-calendar-events (1.6.4):
@@ -99,50 +99,50 @@ PODS:
- React
- react-native-webrtc (1.69.0):
- React
- React/Core (0.59.2):
- yoga (= 0.59.2.React)
- React/CxxBridge (0.59.2):
- React/Core (0.59.4):
- yoga (= 0.59.4.React)
- React/CxxBridge (0.59.4):
- Folly (= 2018.10.22.00)
- React/Core
- React/cxxreact
- React/jsiexecutor
- React/cxxreact (0.59.2):
- React/cxxreact (0.59.4):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React/jsinspector
- React/DevSupport (0.59.2):
- React/DevSupport (0.59.4):
- React/Core
- React/RCTWebSocket
- React/fishhook (0.59.2)
- React/jsi (0.59.2):
- React/fishhook (0.59.4)
- React/jsi (0.59.4):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React/jsiexecutor (0.59.2):
- React/jsiexecutor (0.59.4):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React/cxxreact
- React/jsi
- React/jsinspector (0.59.2)
- React/RCTActionSheet (0.59.2):
- React/jsinspector (0.59.4)
- React/RCTActionSheet (0.59.4):
- React/Core
- React/RCTAnimation (0.59.2):
- React/RCTAnimation (0.59.4):
- React/Core
- React/RCTBlob (0.59.2):
- React/RCTBlob (0.59.4):
- React/Core
- React/RCTImage (0.59.2):
- React/RCTImage (0.59.4):
- React/Core
- React/RCTNetwork
- React/RCTLinkingIOS (0.59.2):
- React/RCTLinkingIOS (0.59.4):
- React/Core
- React/RCTNetwork (0.59.2):
- React/RCTNetwork (0.59.4):
- React/Core
- React/RCTText (0.59.2):
- React/RCTText (0.59.4):
- React/Core
- React/RCTWebSocket (0.59.2):
- React/RCTWebSocket (0.59.4):
- React/Core
- React/fishhook
- React/RCTBlob
@@ -160,7 +160,7 @@ PODS:
- SDWebImage/GIF (4.4.6):
- FLAnimatedImage (~> 1.0)
- SDWebImage/Core
- yoga (0.59.2.React)
- yoga (0.59.4.React)
DEPENDENCIES:
- Amplitude-iOS (~> 4.0.4)
@@ -268,7 +268,7 @@ SPEC CHECKSUMS:
GTMSessionFetcher: 32aeca0aa144acea523e1c8e053089dec2cb98ca
nanopb: 2901f78ea1b7b4015c860c2fdd1ea2fee1a18d48
ObjectiveDropboxOfficial: a5afefc83f6467c42c45f2253f583f2ad1ffc701
React: 9d063e2f356c8cd2f54dd550d4507740037cbabe
React: 5cb71fb1a15b5ce04794ab49e24b48ebe4c94e65
react-native-background-timer: 0d34748e53a972507c66963490c775321a88f6f2
react-native-calendar-events: ee9573e355711ac679e071be70789542431f4ce3
react-native-fast-image: 47487b71169aea34868e7b38bf870b6b3f2157c5
@@ -278,7 +278,7 @@ SPEC CHECKSUMS:
RNSound: e157320f503bdd4f4ee6d8542e948d54f90c3c3a
RNVectorIcons: d819334932bcda3332deb3d2c8ea4d069e0b98f9
SDWebImage: 3f3f0c02f09798048c47a5ed0a13f17b063572d8
yoga: 3768a3026ade0fb46a68f3a31a917cf86bc34fc4
yoga: 596e61c9b57751d08a22b07aba310dbd3e65ab75
PODFILE CHECKSUM: 4a11c3d66127a9845d4a5b2c7fad49f58a9c7a89

View File

@@ -166,7 +166,7 @@
83CBB9F71A601CBA00E9B192 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1000;
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = Facebook;
TargetAttributes = {
13B07F861A680F5B00A75B9A = {
@@ -185,7 +185,7 @@
};
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "app" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
@@ -456,6 +456,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
@@ -514,6 +515,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1000"
LastUpgradeVersion = "1020"
version = "1.3">
<BuildAction
parallelizeBuildables = "NO"

View File

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

View File

@@ -1,416 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 48;
objects = {
/* Begin PBXBuildFile section */
C6245F57205044120040BE68 /* JitsiMeet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C6F99C4F204DE79F0001F710 /* JitsiMeet.framework */; };
C6245F58205044150040BE68 /* WebRTC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C6A34247204DF18000E062DD /* WebRTC.framework */; };
C6A34249204DF18000E062DD /* WebRTC.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C6A34247204DF18000E062DD /* WebRTC.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
C6F99C3B204DE6BE0001F710 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F99C3A204DE6BE0001F710 /* AppDelegate.swift */; };
C6F99C3D204DE6BE0001F710 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F99C3C204DE6BE0001F710 /* ViewController.swift */; };
C6F99C40204DE6BE0001F710 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C6F99C3E204DE6BE0001F710 /* Main.storyboard */; };
C6F99C42204DE6BE0001F710 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C6F99C41204DE6BE0001F710 /* Assets.xcassets */; };
C6F99C45204DE6BE0001F710 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C6F99C43204DE6BE0001F710 /* LaunchScreen.storyboard */; };
C6F99C60204DEDC10001F710 /* JitsiMeet.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C6F99C4F204DE79F0001F710 /* JitsiMeet.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
C6F99C61204DEDC20001F710 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
C6F99C60204DEDC10001F710 /* JitsiMeet.framework in Embed Frameworks */,
C6A34249204DF18000E062DD /* WebRTC.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
C6A34247204DF18000E062DD /* WebRTC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebRTC.framework; path = "../../node_modules/react-native-webrtc/ios/WebRTC.framework"; sourceTree = "<group>"; };
C6F99C37204DE6BE0001F710 /* example-pip-app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "example-pip-app.app"; sourceTree = BUILT_PRODUCTS_DIR; };
C6F99C3A204DE6BE0001F710 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
C6F99C3C204DE6BE0001F710 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
C6F99C3F204DE6BE0001F710 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
C6F99C41204DE6BE0001F710 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
C6F99C44204DE6BE0001F710 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
C6F99C46204DE6BE0001F710 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C6F99C4F204DE79F0001F710 /* JitsiMeet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = JitsiMeet.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
C6F99C34204DE6BE0001F710 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C6245F57205044120040BE68 /* JitsiMeet.framework in Frameworks */,
C6245F58205044150040BE68 /* WebRTC.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
C6F99C2E204DE6BE0001F710 = {
isa = PBXGroup;
children = (
C6F99C4D204DE79F0001F710 /* Frameworks */,
C6F99C38204DE6BE0001F710 /* Products */,
C6F99C4C204DE7230001F710 /* src */,
);
sourceTree = "<group>";
};
C6F99C38204DE6BE0001F710 /* Products */ = {
isa = PBXGroup;
children = (
C6F99C37204DE6BE0001F710 /* example-pip-app.app */,
);
name = Products;
sourceTree = "<group>";
};
C6F99C4C204DE7230001F710 /* src */ = {
isa = PBXGroup;
children = (
C6F99C3A204DE6BE0001F710 /* AppDelegate.swift */,
C6F99C41204DE6BE0001F710 /* Assets.xcassets */,
C6F99C46204DE6BE0001F710 /* Info.plist */,
C6F99C43204DE6BE0001F710 /* LaunchScreen.storyboard */,
C6F99C3E204DE6BE0001F710 /* Main.storyboard */,
C6F99C3C204DE6BE0001F710 /* ViewController.swift */,
);
path = src;
sourceTree = "<group>";
};
C6F99C4D204DE79F0001F710 /* Frameworks */ = {
isa = PBXGroup;
children = (
C6F99C4F204DE79F0001F710 /* JitsiMeet.framework */,
C6A34247204DF18000E062DD /* WebRTC.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
C6F99C36204DE6BE0001F710 /* example-pip-app */ = {
isa = PBXNativeTarget;
buildConfigurationList = C6F99C49204DE6BE0001F710 /* Build configuration list for PBXNativeTarget "example-pip-app" */;
buildPhases = (
C6A3424A204DF91D00E062DD /* Run Adjust ATS for loading JS bundle */,
C6F99C62204DEFFE0001F710 /* Run React Packager */,
C6F99C33204DE6BE0001F710 /* Sources */,
C6F99C34204DE6BE0001F710 /* Frameworks */,
C6F99C35204DE6BE0001F710 /* Resources */,
C6F99C61204DEDC20001F710 /* Embed Frameworks */,
C6A3426E20503ECC00E062DD /* Adjust embedded framework architectures */,
);
buildRules = (
);
dependencies = (
);
name = "example-pip-app";
productName = "example-pip-app";
productReference = C6F99C37204DE6BE0001F710 /* example-pip-app.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
C6F99C2F204DE6BE0001F710 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 0920;
ORGANIZATIONNAME = "Atlassian Inc";
TargetAttributes = {
C6F99C36204DE6BE0001F710 = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.BackgroundModes = {
enabled = 1;
};
};
};
};
};
buildConfigurationList = C6F99C32204DE6BE0001F710 /* Build configuration list for PBXProject "example-pip-app" */;
compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = C6F99C2E204DE6BE0001F710;
productRefGroup = C6F99C38204DE6BE0001F710 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
C6F99C36204DE6BE0001F710 /* example-pip-app */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
C6F99C35204DE6BE0001F710 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C6F99C45204DE6BE0001F710 /* LaunchScreen.storyboard in Resources */,
C6F99C42204DE6BE0001F710 /* Assets.xcassets in Resources */,
C6F99C40204DE6BE0001F710 /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
C6A3424A204DF91D00E062DD /* Run Adjust ATS for loading JS bundle */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Adjust ATS for loading JS bundle";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "../scripts/fixup-ats.sh";
};
C6A3426E20503ECC00E062DD /* Adjust embedded framework architectures */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Adjust embedded framework architectures";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "../scripts/fixup-frameworks.sh";
};
C6F99C62204DEFFE0001F710 /* Run React Packager */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run React Packager";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "../scripts/run-packager.sh";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
C6F99C33204DE6BE0001F710 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C6F99C3D204DE6BE0001F710 /* ViewController.swift in Sources */,
C6F99C3B204DE6BE0001F710 /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
C6F99C3E204DE6BE0001F710 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
C6F99C3F204DE6BE0001F710 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
C6F99C43204DE6BE0001F710 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
C6F99C44204DE6BE0001F710 /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
C6F99C47204DE6BE0001F710 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
C6F99C48204DE6BE0001F710 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
C6F99C4A204DE6BE0001F710 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
FRAMEWORK_SEARCH_PATHS = "../../node_modules/react-native-webrtc/ios";
INFOPLIST_FILE = src/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.jitsi.example-pip-app";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
C6F99C4B204DE6BE0001F710 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
FRAMEWORK_SEARCH_PATHS = "../../node_modules/react-native-webrtc/ios";
INFOPLIST_FILE = src/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.jitsi.example-pip-app";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
C6F99C32204DE6BE0001F710 /* Build configuration list for PBXProject "example-pip-app" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C6F99C47204DE6BE0001F710 /* Debug */,
C6F99C48204DE6BE0001F710 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C6F99C49204DE6BE0001F710 /* Build configuration list for PBXNativeTarget "example-pip-app" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C6F99C4A204DE6BE0001F710 /* Debug */,
C6F99C4B204DE6BE0001F710 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = C6F99C2F204DE6BE0001F710 /* Project object */;
}

View File

@@ -1,41 +0,0 @@
/*
* 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 JitsiMeet
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
guard let launchOptions = launchOptions else { return false }
return JitsiMeetView.application(application, didFinishLaunchingWithOptions: launchOptions)
}
// MARK: - Linking delegate methods
func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
return JitsiMeetView.application(application, continue: userActivity, restorationHandler: restorationHandler)
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
return JitsiMeetView.application(application, open: url, sourceApplication: sourceApplication, annotation: annotation)
}
}

View File

@@ -1,98 +0,0 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>

View File

@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="example-pip-app" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QxY-C8-fwD">
<rect key="frame" x="116" y="324.5" width="143" height="38"/>
<fontDescription key="fontDescription" type="system" pointSize="21"/>
<state key="normal" title="Open Jitsi Meet"/>
<connections>
<action selector="openJitsiMeetWithSender:" destination="BYZ-38-t0r" eventType="touchUpInside" id="79C-XR-05w"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="QxY-C8-fwD" firstAttribute="centerX" secondItem="6Tk-OE-BBY" secondAttribute="centerX" id="6a6-l1-7Ct"/>
<constraint firstItem="QxY-C8-fwD" firstAttribute="centerY" secondItem="6Tk-OE-BBY" secondAttribute="centerY" id="Hfg-TH-0g2"/>
</constraints>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
<connections>
<outlet property="videoButton" destination="QxY-C8-fwD" id="Zwa-Hx-Zub"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="32.799999999999997" y="658.92053973013503"/>
</scene>
</scenes>
</document>

View File

@@ -1,64 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@@ -1,93 +0,0 @@
/*
* 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 UIKit
import JitsiMeet
class ViewController: UIViewController {
@IBOutlet weak var videoButton: UIButton?
fileprivate var pipViewCoordinator: PiPViewCoordinator?
fileprivate var jitsiMeetView: JitsiMeetView?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillTransition(to size: CGSize,
with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
let rect = CGRect(origin: CGPoint.zero, size: size)
pipViewCoordinator?.resetBounds(bounds: rect)
}
// MARK: - Actions
@IBAction func openJitsiMeet(sender: Any?) {
cleanUp()
// create and configure jitsimeet view
let jitsiMeetView = JitsiMeetView()
jitsiMeetView.welcomePageEnabled = true
jitsiMeetView.pictureInPictureEnabled = true
jitsiMeetView.load(nil)
jitsiMeetView.delegate = self
self.jitsiMeetView = jitsiMeetView
// Enable jitsimeet view to be a view that can be displayed
// on top of all the things, and let the coordinator to manage
// the view state and interactions
pipViewCoordinator = PiPViewCoordinator(withView: jitsiMeetView)
pipViewCoordinator?.configureAsStickyView(withParentView: view)
// animate in
jitsiMeetView.alpha = 0
pipViewCoordinator?.show()
}
fileprivate func cleanUp() {
jitsiMeetView?.removeFromSuperview()
jitsiMeetView = nil
pipViewCoordinator = nil
}
}
extension ViewController: JitsiMeetViewDelegate {
func conferenceFailed(_ data: [AnyHashable : Any]!) {
hideJitsiMeetViewAndCleanUp()
}
func conferenceLeft(_ data: [AnyHashable : Any]!) {
hideJitsiMeetViewAndCleanUp()
}
func enterPicture(inPicture data: [AnyHashable : Any]!) {
DispatchQueue.main.async {
self.pipViewCoordinator?.enterPictureInPicture()
}
}
private func hideJitsiMeetViewAndCleanUp() {
DispatchQueue.main.async {
self.pipViewCoordinator?.hide() { _ in
self.cleanUp()
}
}
}
}

View File

@@ -1,9 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:example-pip-app/example-pip-app.xcodeproj">
</FileRef>
<FileRef
location = "group:app/app.xcodeproj">
</FileRef>

44
ios/scripts/release-sdk.sh Executable file
View File

@@ -0,0 +1,44 @@
#!/bin/bash
set -e -u
THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
PROJECT_REPO=$(realpath ${THIS_DIR}/../..)
RELEASE_REPO=$(realpath ${THIS_DIR}/../../../jitsi-meet-ios-sdk-releases)
SDK_VERSION=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" ${THIS_DIR}/../sdk/src/Info.plist)
echo "Releasing Jitsi Meet SDK ${SDK_VERSION}"
pushd ${RELEASE_REPO}
# Generate podspec file
cat JitsiMeetSDK.podspec.tpl | sed -e s/VERSION/${SDK_VERSION}/g > JitsiMeetSDK.podspec
# Cleanup
rm -rf Frameworks/*
popd
# Build the SDK
pushd ${PROJECT_REPO}
rm -rf ios/sdk/JitsiMeet.framework
xcodebuild -workspace ios/jitsi-meet.xcworkspace -scheme JitsiMeet -destination='generic/platform=iOS' -configuration Release archive
git tag -a ios-sdk-${SDK_VERSION}
popd
pushd ${RELEASE_REPO}
# Put the new files in the repo
cp -r ${PROJECT_REPO}/ios/sdk/JitsiMeet.framework Frameworks/
cp -r ${PROJECT_REPO}/node_modules/react-native-webrtc/ios/WebRTC.framework Frameworks/
# Add all files to git
git add -A .
git commit -m "${SDK_VERSION}"
git tag ${SDK_VERSION}
popd
echo "Finished! Don't forget to push the tags and releases repo artifacts."
echo "The new pod can be pushed to CocoaPods by doing: pod trunk push JitsiMeetSDK.podspec"

View File

@@ -293,7 +293,7 @@
0BD906DC1EC0C00300C8C18E /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1000;
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = Jitsi;
TargetAttributes = {
0BD906E41EC0C00300C8C18E = {
@@ -305,10 +305,11 @@
};
buildConfigurationList = 0BD906DF1EC0C00300C8C18E /* Build configuration list for PBXProject "sdk" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 0BD906DB1EC0C00300C8C18E;
productRefGroup = 0BD906E61EC0C00300C8C18E /* Products */;
@@ -486,6 +487,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
@@ -547,6 +549,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
@@ -622,8 +625,8 @@
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = On;
SWIFT_VERSION = 4.2;
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
@@ -649,8 +652,8 @@
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_SWIFT3_OBJC_INFERENCE = On;
SWIFT_VERSION = 4.2;
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 5.0;
};
name = Release;
};

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1000"
LastUpgradeVersion = "1020"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"

View File

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

View File

@@ -44,23 +44,23 @@
#pragma mak - This class is a singleton
+ (instancetype)sharedInstance;
+ (instancetype _Nonnull)sharedInstance;
#pragma mark - Methods that the App delegate must call
- (BOOL)application:(UIApplication *_Nonnull)application
didFinishLaunchingWithOptions:(NSDictionary *_Nonnull)launchOptions;
- (BOOL)application:(UIApplication * _Nonnull)application
continueUserActivity:(NSUserActivity * _Nonnull)userActivity
restorationHandler:(void (^ _Nullable)(NSArray * _Nullable))restorationHandler;
- (BOOL)application:(UIApplication *_Nonnull)application
continueUserActivity:(NSUserActivity *_Nonnull)userActivity
restorationHandler:(void (^_Nullable)(NSArray<id<UIUserActivityRestoring>> *_Nonnull))restorationHandler;
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options;
- (BOOL)application:(UIApplication *_Nonnull)app
openURL:(NSURL *_Nonnull)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *_Nonnull)options;
#pragma mark - Utility methods
- (JitsiMeetConferenceOptions *)getInitialConferenceOptions;
- (JitsiMeetConferenceOptions *_Nonnull)getInitialConferenceOptions;
@end

View File

@@ -70,7 +70,7 @@
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler {
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *))restorationHandler {
JitsiMeetConferenceOptions *options = [self optionsFromUserActivity:userActivity];

View File

@@ -67,7 +67,7 @@
@property (nonatomic, readonly) BOOL welcomePageEnabled;
+ (instancetype)fromBuilder:(void (^)(JitsiMeetConferenceOptionsBuilder *))initBlock;
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype _Nonnull)fromBuilder:(void (^_Nonnull)(JitsiMeetConferenceOptionsBuilder *_Nonnull))initBlock;
- (instancetype _Nonnull)init NS_UNAVAILABLE;
@end

View File

@@ -19,7 +19,7 @@
@interface JitsiMeetView ()
+ (instancetype)viewForExternalAPIScope:(NSString *)externalAPIScope;
+ (instancetype _Nullable)viewForExternalAPIScope:(NSString *_Nonnull)externalAPIScope;
+ (BOOL)setPropsInViews:(NSDictionary *_Nonnull)newProps;
@end

View File

@@ -31,7 +31,7 @@
* is an already active conference it will be automatically left prior to
* joining the new one.
*/
- (void)join:(JitsiMeetConferenceOptions *)options;
- (void)join:(JitsiMeetConferenceOptions *_Nullable)options;
/**
* Leaves the currently active conference.
*/

View File

@@ -130,13 +130,10 @@ internal final class JMCallKitEmitter: NSObject, CXProviderDelegate {
fileprivate struct JMCallKitEventListenerWrapper: Hashable {
public var hashValue: Int
internal weak var listener: JMCallKitListener?
public init(listener: JMCallKitListener) {
self.listener = listener
self.hashValue = listener.hash
}
public static func ==(lhs: JMCallKitEventListenerWrapper,
@@ -145,4 +142,8 @@ fileprivate struct JMCallKitEventListenerWrapper: Hashable {
// necessarily equal to each other."
return lhs.hashValue == rhs.hashValue
}
func hash(into hasher: inout Hasher) {
hasher.combine(self.listener?.hash)
}
}

View File

@@ -57,6 +57,9 @@
},
"title": "Chat"
},
"connectingOverlay": {
"joiningRoom": "Connecting you to your meeting..."
},
"connection": {
"ATTACHED": "Attached",
"AUTHENTICATING": "Authenticating",

View File

@@ -168,6 +168,13 @@ export default class LargeVideoManager {
get id() {
const container = this.getCurrentContainer();
// If a user switch for large video is in progress then provide what
// will be the end result of the update.
if (this.updateInProcess
&& this.newStreamData
&& this.newStreamData.id !== container.id) {
return this.newStreamData.id;
}
return container.id;
}
@@ -184,8 +191,8 @@ export default class LargeVideoManager {
// Include hide()/fadeOut only if we're switching between users
// eslint-disable-next-line eqeqeq
const isUserSwitch = this.newStreamData.id != this.id;
const container = this.getCurrentContainer();
const isUserSwitch = this.newStreamData.id !== container.id;
const preUpdate = isUserSwitch ? container.hide() : Promise.resolve();
preUpdate.then(() => {

72
package-lock.json generated
View File

@@ -2071,9 +2071,9 @@
},
"dependencies": {
"core-js": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.0.0.tgz",
"integrity": "sha512-WBmxlgH2122EzEJ6GH8o9L/FeoUKxxxZ6q6VUxoTlsE4EvbTWKJb447eyVxTEuq0LpXjlq/kCB2qgBvsYRkLvQ=="
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.0.1.tgz",
"integrity": "sha512-sco40rF+2KlE0ROMvydjkrVMMG1vYilP2ALoRXcYR4obqbYIuV3Bg+51GEDW+HF8n7NRA+iaA4qD0nD9lo9mew=="
},
"find-cache-dir": {
"version": "2.1.0",
@@ -2128,9 +2128,9 @@
}
},
"p-try": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz",
"integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA=="
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
},
"pify": {
"version": "4.0.1",
@@ -2146,9 +2146,9 @@
}
},
"semver": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg=="
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
}
}
},
@@ -2250,9 +2250,9 @@
}
},
"@jitsi/sdp-interop": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/@jitsi/sdp-interop/-/sdp-interop-0.1.13.tgz",
"integrity": "sha512-U/UI1W9NULZj7PgP9GVzWfvIQ4T2LJBvMj4dNKclHqLMXIZ9aSuWEeYe/Q9jB+J7vot+M9ofALtO4w5xifffoQ==",
"version": "0.1.14",
"resolved": "https://registry.npmjs.org/@jitsi/sdp-interop/-/sdp-interop-0.1.14.tgz",
"integrity": "sha512-v60VAtBx9LO46c9In9oMNY+Ho5993UMOLHBg6VcrcyoVTIWIeqs/9YjjmrQ3Sf4I5aMRABNl7HTby/1lHcqFJw==",
"requires": {
"sdp-transform": "2.3.0"
}
@@ -2275,9 +2275,9 @@
}
},
"@react-native-community/cli": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-1.5.1.tgz",
"integrity": "sha512-HFCYxI6WW3SoayrOSdhYxor5CaF/SBp7W73TyvTRRNAqQdA9/NX9wMZly+UpmFQkQFkiLvgc2yqS5vT918XXUw==",
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-1.6.0.tgz",
"integrity": "sha512-OV3N5O/wzjb8OTZDiFerX0gf9/KzLJOvDttU38BqIvn8+OLkH6SIgGrKked9vrKKvH5bFG6jmCmKCW5gP+tOwQ==",
"requires": {
"chalk": "^1.1.1",
"commander": "^2.19.0",
@@ -4258,9 +4258,9 @@
}
},
"commander": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
"integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg=="
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ=="
},
"comment-parser": {
"version": "0.4.2",
@@ -4543,9 +4543,9 @@
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
},
"js-yaml": {
"version": "3.13.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz",
"integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==",
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
@@ -5519,8 +5519,8 @@
}
},
"eslint-config-jitsi": {
"version": "github:jitsi/eslint-config-jitsi#1f3fbcea8baa1ab95929a351be3977e00cb162ec",
"from": "github:jitsi/eslint-config-jitsi#1.0.0",
"version": "github:jitsi/eslint-config-jitsi#5f9fe4fd00be471ab6f5d06f77ffc90bba0853e8",
"from": "github:jitsi/eslint-config-jitsi#1.0.1",
"dev": true
},
"eslint-import-resolver-node": {
@@ -8634,10 +8634,10 @@
}
},
"lib-jitsi-meet": {
"version": "github:jitsi/lib-jitsi-meet#83af6e78a82466153e93d4a467e1459c9c97d5ee",
"from": "github:jitsi/lib-jitsi-meet#83af6e78a82466153e93d4a467e1459c9c97d5ee",
"version": "github:jitsi/lib-jitsi-meet#86e3badd5c04e1df72435205d28a58c8a64e343a",
"from": "github:jitsi/lib-jitsi-meet#86e3badd5c04e1df72435205d28a58c8a64e343a",
"requires": {
"@jitsi/sdp-interop": "0.1.13",
"@jitsi/sdp-interop": "0.1.14",
"@jitsi/sdp-simulcast": "0.2.1",
"async": "0.9.0",
"current-executing-script": "0.1.3",
@@ -11745,9 +11745,9 @@
}
},
"react-native": {
"version": "0.59.2",
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.59.2.tgz",
"integrity": "sha512-gIygrCr42rGEQnfjcAZdCOqgjC0oZtTIp+mdbUW+yqHpNUU1PbYKzUkLlvSFGeN+IUcL8WTaC1JtJvghKhaLmA==",
"version": "0.59.4",
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.59.4.tgz",
"integrity": "sha512-etnXQp9IZgC8Vj5gsxZEDP4xRjJVNIj5/BSE1WcNAONG6tu6+mDBntx1jxHInwh61WYNgoQJuQGsbN5Na59ZDw==",
"requires": {
"@babel/runtime": "^7.0.0",
"@react-native-community/cli": "^1.2.1",
@@ -14026,9 +14026,12 @@
}
},
"stacktrace-parser": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.4.tgz",
"integrity": "sha1-ATl5IuX2Ls8whFUiyVxP4dJefU4="
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.5.tgz",
"integrity": "sha512-fjJ563lEMEXdqUH8fZR84sczWxM+Pi3bViix1n7371mFr8sL7UPewec79+IhHkN4UMmGbXoXj58WIaF7lIciRA==",
"requires": {
"type-fest": "^0.3.0"
}
},
"static-extend": {
"version": "0.1.2",
@@ -14999,6 +15002,11 @@
"prelude-ls": "~1.1.2"
}
},
"type-fest": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.0.tgz",
"integrity": "sha512-fg3sfdDdJDtdHLUpeGsf/fLyG1aapk6zgFiYG5+MDUPybGrJemH4SLk5tP7hGRe8ntxjg0q5LYW53b6YpJIQ9Q=="
},
"type-is": {
"version": "1.6.16",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",

View File

@@ -51,7 +51,7 @@
"js-utils": "github:jitsi/js-utils#73a67a7a60d52f8e895f50939c8fcbd1f20fe7b5",
"jsrsasign": "8.0.12",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#83af6e78a82466153e93d4a467e1459c9c97d5ee",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#86e3badd5c04e1df72435205d28a58c8a64e343a",
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"lodash": "4.17.11",
"moment": "2.19.4",
@@ -62,7 +62,7 @@
"react-emoji-render": "0.4.6",
"react-i18next": "7.13.0",
"react-linkify": "0.2.2",
"react-native": "0.59.2",
"react-native": "0.59.4",
"react-native-background-timer": "2.1.1",
"react-native-calendar-events": "1.6.4",
"react-native-callstats": "3.58.2",
@@ -99,7 +99,7 @@
"clean-css": "3.4.25",
"css-loader": "0.28.7",
"eslint": "5.6.1",
"eslint-config-jitsi": "github:jitsi/eslint-config-jitsi#1.0.0",
"eslint-config-jitsi": "github:jitsi/eslint-config-jitsi#1.0.1",
"eslint-plugin-flowtype": "2.50.3",
"eslint-plugin-import": "2.14.0",
"eslint-plugin-jsdoc": "3.8.0",

View File

@@ -31,176 +31,70 @@ declare var APP: Object;
* @returns {Function}
*/
export function appNavigate(uri: ?string) {
return (dispatch: Dispatch<any>, getState: Function) =>
_appNavigateToOptionalLocation(dispatch, getState, parseURIString(uri));
}
return async (dispatch: Dispatch<any>, getState: Function) => {
let location = parseURIString(uri);
/**
* Triggers an in-app navigation to a specific location URI.
*
* @param {Dispatch} dispatch - The redux {@code dispatch} function.
* @param {Function} getState - The redux function that gets/retrieves the redux
* state.
* @param {Object} newLocation - The location URI to navigate to. The value
* cannot be undefined and is assumed to have all properties such as
* {@code host}, {@code contextRoot}, and {@code room} defined. Depending on the
* property, it may have a value equal to {@code undefined} and that may be
* acceptable.
* @private
* @returns {Promise<void>}
*/
function _appNavigateToMandatoryLocation(
dispatch: Dispatch<any>, getState: Function,
newLocation: Object
): Promise<void> {
const { room } = newLocation;
const locationURL = new URL(newLocation.toString());
// If the specified location (URI) does not identify a host, use the app's
// default.
if (!location || !location.host) {
const defaultLocation = parseURIString(getDefaultURL(getState));
dispatch(configWillLoad(locationURL));
if (location) {
location.host = defaultLocation.host;
return (
_loadConfig(dispatch, getState, newLocation)
.then(
config => loadConfigSettled(/* error */ undefined, config),
error => loadConfigSettled(error, /* config */ undefined))
.then(() => dispatch(setRoom(room))));
// FIXME Turn location's host, hostname, and port properties into
// setters in order to reduce the risks of inconsistent state.
location.hostname = defaultLocation.hostname;
location.pathname
= defaultLocation.pathname + location.pathname.substr(1);
location.port = defaultLocation.port;
location.protocol = defaultLocation.protocol;
} else {
location = defaultLocation;
}
}
location.protocol || (location.protocol = 'https:');
const { contextRoot, host, room } = location;
const locationURL = new URL(location.toString());
dispatch(configWillLoad(locationURL, room));
let protocol = location.protocol.toLowerCase();
// The React Native app supports an app-specific scheme which is sure to not
// be supported by fetch.
protocol !== 'http:' && protocol !== 'https:' && (protocol = 'https:');
const baseURL = `${protocol}//${host}${contextRoot || '/'}`;
let url = `${baseURL}config.js`;
// XXX In order to support multiple shards, tell the room to the deployment.
room && (url += `?room=${room.toLowerCase()}`);
let config;
try {
config = await loadConfig(url);
dispatch(storeConfig(baseURL, config));
} catch (error) {
config = restoreConfig(baseURL);
if (!config) {
dispatch(loadConfigError(error, locationURL));
return;
}
}
/**
* Notifies that an attempt to load a configuration has completed. Due to
* the asynchronous nature of the loading, the specified {@code config} may
* or may not be required by the time the notification arrives.
*
* @param {string|undefined} error - If the loading has failed, the error
* detailing the cause of the failure.
* @param {Object|undefined} config - If the loading has succeeded, the
* loaded configuration.
* @returns {void}
*/
function loadConfigSettled(error, config) {
// Due to the asynchronous nature of the loading, the specified config
// may or may not be required by the time the notification arrives. If
// we receive the config for a location we are no longer interested in,
// "ignore" it - deliver it to the external API, for example, but do not
// proceed with the appNavigate procedure/process.
if (getState()['features/base/config'].locationURL === locationURL) {
dispatch(setLocationURL(locationURL));
dispatch(setConfig(config));
dispatch(setRoom(room));
} else {
// eslint-disable-next-line no-param-reassign
error || (error = new Error('Config no longer needed!'));
// XXX The failure could be, for example, because of a
// certificate-related error. In which case the connection will fail
// later in Strophe anyway.
dispatch(loadConfigError(error, locationURL));
throw error;
dispatch(loadConfigError(new Error('Config no longer needed!'), locationURL));
}
}
}
/**
* Triggers an in-app navigation to a specific or undefined location (URI).
*
* @param {Dispatch} dispatch - The redux {@code dispatch} function.
* @param {Function} getState - The redux function that gets/retrieves the redux
* state.
* @param {Object} location - The location (URI) to navigate to. The value may
* be undefined.
* @private
* @returns {void}
*/
function _appNavigateToOptionalLocation(
dispatch: Dispatch<any>, getState: Function,
location: Object) {
// If the specified location (URI) does not identify a host, use the app's
// default.
if (!location || !location.host) {
const defaultLocation = parseURIString(getDefaultURL(getState));
if (location) {
location.host = defaultLocation.host;
// FIXME Turn location's host, hostname, and port properties into
// setters in order to reduce the risks of inconsistent state.
location.hostname = defaultLocation.hostname;
location.pathname
= defaultLocation.pathname + location.pathname.substr(1);
location.port = defaultLocation.port;
location.protocol = defaultLocation.protocol;
} else {
// eslint-disable-next-line no-param-reassign
location = defaultLocation;
}
}
location.protocol || (location.protocol = 'https:');
return _appNavigateToMandatoryLocation(dispatch, getState, location);
}
/**
* Loads config.js from a specific host.
*
* @param {Dispatch} dispatch - The redux {@code dispatch} function.
* @param {Function} getState - The redux {@code getState} function.
* @param {Object} location - The location URI which specifies the host to load
* the config.js from.
* @private
* @returns {Promise<Object>}
*/
function _loadConfig(
dispatch: Dispatch<any>,
getState: Function,
{ contextRoot, host, protocol, room }) {
// XXX As the mobile/React Native app does not employ config on the
// WelcomePage, do not download config.js from the deployment when
// navigating to the WelcomePage - the perceived/visible navigation will be
// faster.
if (!room && typeof APP === 'undefined') {
return Promise.resolve();
}
/* eslint-disable no-param-reassign */
protocol = protocol.toLowerCase();
// The React Native app supports an app-specific scheme which is sure to not
// be supported by fetch (or whatever loadConfig utilizes).
protocol !== 'http:' && protocol !== 'https:' && (protocol = 'https:');
// TDOO userinfo
const baseURL = `${protocol}//${host}${contextRoot || '/'}`;
let url = `${baseURL}config.js`;
// XXX In order to support multiple shards, tell the room to the deployment.
room && (url += `?room=${room.toLowerCase()}`);
/* eslint-enable no-param-reassign */
return loadConfig(url).then(
/* onFulfilled */ config => {
// FIXME If the config is no longer needed (in the terms of
// _loadConfig) and that happened because of an intervening
// _loadConfig for the same baseURL, then the unneeded config may be
// stored after the needed config. Anyway.
dispatch(storeConfig(baseURL, config));
return config;
},
/* onRejected */ error => {
// XXX The (down)loading of config failed. Try to use the last
// successfully fetched for that deployment. It may not match the
// shard.
const config = restoreConfig(baseURL);
if (config) {
return config;
}
throw error;
});
};
}
/**

View File

@@ -1 +1,3 @@
// @flow
export * from './App';

View File

@@ -1,3 +1,5 @@
// @flow
export * from './actions';
export * from './components';
export * from './functions';

View File

@@ -5,7 +5,8 @@ import { Text, TextInput, View } from 'react-native';
import { connect as reduxConnect } from 'react-redux';
import type { Dispatch } from 'redux';
import { connect, toJid } from '../../base/connection';
import { toJid } from '../../base/connection';
import { connect } from '../../base/connection/actions.native';
import {
CustomSubmitDialog,
FIELD_UNDERLINE,

View File

@@ -117,7 +117,7 @@ export default class BaseApp extends Component<*, State> {
render() {
const { route: { component }, store } = this.state;
if (store && component) {
if (store) {
return (
<I18nextProvider i18n = { i18next }>
<Provider store = { store }>
@@ -160,7 +160,7 @@ export default class BaseApp extends Component<*, State> {
* @protected
*/
_createMainElement(component, props) {
return React.createElement(component, props || {});
return component ? React.createElement(component, props || {}) : null;
}
/**

View File

@@ -29,6 +29,10 @@ export default {
'LargeVideo': {
background: ColorPalette.black
},
'LoadConfigOverlay': {
background: ColorPalette.black,
text: ColorPalette.white
},
'Thumbnail': {
activeParticipantHighlight: ColorPalette.blue,
activeParticipantTint: ColorPalette.black,

View File

@@ -4,7 +4,8 @@
*
* {
* type: CONFIG_WILL_LOAD,
* locationURL: URL
* locationURL: URL,
* room: string
* }
*/
export const CONFIG_WILL_LOAD = 'CONFIG_WILL_LOAD';

View File

@@ -15,15 +15,18 @@ import { setConfigFromURLParams } from './functions';
*
* @param {URL} locationURL - The URL of the location which necessitated the
* loading of a configuration.
* @param {string} room - The name of the room (conference) for which we're loading the config for.
* @returns {{
* type: CONFIG_WILL_LOAD,
* locationURL: URL
* locationURL: URL,
* room: string
* }}
*/
export function configWillLoad(locationURL: URL) {
export function configWillLoad(locationURL: URL, room: string) {
return {
type: CONFIG_WILL_LOAD,
locationURL
locationURL,
room
};
}

View File

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

View File

@@ -8,16 +8,16 @@ import { toState } from '../redux';
*
* @param {Function|Object} stateOrGetState - The redux state or redux's
* {@code getState} function.
* @returns {string|undefined}
* @returns {string}
*/
export function getInviteURL(stateOrGetState: Function | Object): ?string {
export function getInviteURL(stateOrGetState: Function | Object): string {
const state = toState(stateOrGetState);
const locationURL
= state instanceof URL
? state
: state['features/base/connection'].locationURL;
return locationURL ? getURLWithoutParams(locationURL).href : undefined;
return getURLWithoutParams(locationURL).href;
}
/**

View File

@@ -1,3 +1,5 @@
// @flow
export * from './actions';
export * from './actionTypes';
export * from './functions';

View File

@@ -11,9 +11,12 @@ import {
import {
areDeviceLabelsInitialized,
getDeviceIdByLabel,
getDevicesFromURL
getDevicesFromURL,
setAudioOutputDeviceId
} from './functions';
const logger = require('jitsi-meet-logger').getLogger(__filename);
/**
* Adds a pending device request.
*
@@ -36,11 +39,12 @@ export function addPendingDeviceRequest(request) {
* @returns {Function}
*/
export function configureInitialDevices() {
return (dispatch, getState) => new Promise(resolve => {
return (dispatch, getState) => {
const deviceLabels = getDevicesFromURL(getState());
let updateSettingsPromise;
if (deviceLabels) {
dispatch(getAvailableDevices()).then(() => {
updateSettingsPromise = dispatch(getAvailableDevices()).then(() => {
const state = getState();
if (!areDeviceLabelsInitialized(state)) {
@@ -59,7 +63,6 @@ export function configureInitialDevices() {
responseCallback() {}
}));
});
resolve();
return;
}
@@ -72,7 +75,7 @@ export function configureInitialDevices() {
Object.keys(deviceLabels).forEach(key => {
const label = deviceLabels[key];
const deviceId = getDeviceIdByLabel(state, label);
const deviceId = getDeviceIdByLabel(state, label, key);
if (deviceId) {
newSettings[devicesKeysToSettingsKeys[key]] = deviceId;
@@ -80,13 +83,21 @@ export function configureInitialDevices() {
});
dispatch(updateSettings(newSettings));
resolve();
});
} else {
resolve();
updateSettingsPromise = Promise.resolve();
}
});
return updateSettingsPromise
.then(() => {
const { audioOutputDeviceId }
= getState()['features/base/settings'];
return setAudioOutputDeviceId(audioOutputDeviceId, dispatch)
.catch(ex => logger.warn(`Failed to set audio output device.
Default audio output device will be used instead ${ex}`));
});
};
}
/**

View File

@@ -44,19 +44,26 @@ export function getAudioOutputDeviceId() {
*
* @param {Object} state - The redux state.
* @param {string} label - The label.
* @param {string} kind - The type of the device. One of "audioInput",
* "audioOutput", and "videoInput". Also supported is all lowercase versions
* of the preceding types.
* @returns {string|undefined}
*/
export function getDeviceIdByLabel(state: Object, label: string) {
const types = [ 'audioInput', 'audioOutput', 'videoInput' ];
export function getDeviceIdByLabel(state: Object, label: string, kind: string) {
const webrtcKindToJitsiKindTranslator = {
audioinput: 'audioInput',
audiooutput: 'audioOutput',
videoinput: 'videoInput'
};
for (const type of types) {
const device
= (state['features/base/devices'].availableDevices[type] || [])
.find(d => d.label === label);
const kindToSearch = webrtcKindToJitsiKindTranslator[kind] || kind;
if (device) {
return device.deviceId;
}
const device
= (state['features/base/devices'].availableDevices[kindToSearch] || [])
.find(d => d.label === label);
if (device) {
return device.deviceId;
}
}

View File

@@ -100,20 +100,14 @@ export function isFatalJitsiConnectionError(error: Object | string) {
* Loads config.js from a specific remote server.
*
* @param {string} url - The URL to load.
* @param {number} [timeout] - The timeout in milliseconds for the {@code url}
* to load. If not specified, a default value deemed appropriate for the purpose
* is used.
* @returns {Promise<Object>}
*/
export function loadConfig(
url: string,
timeout: ?number = 10 /* seconds */ * 1000 /* in milliseconds */
): Promise<Object> {
export function loadConfig(url: string): Promise<Object> {
let promise;
if (typeof APP === 'undefined') {
promise
= loadScript(url, timeout)
= loadScript(url, 2.5 * 1000 /* Timeout in ms */)
.then(() => {
const { config } = window;

View File

@@ -7,6 +7,11 @@ import { ColorPalette } from '../../../styles';
type Props = {
/**
* The color of the spinner.
*/
color: ?string,
/**
* Prop to set the size of the indicator. This is the same as the
* prop of the native component.
@@ -27,6 +32,7 @@ export default class LoadingIndicator extends Component<Props> {
* @returns {ReactElement}
*/
render() {
const { color = ColorPalette.white } = this.props;
let { size = 'large' } = this.props;
if (size === 'medium') {
@@ -35,7 +41,7 @@ export default class LoadingIndicator extends Component<Props> {
const props = {
animating: true,
color: ColorPalette.white,
color,
...this.props,
size
};
@@ -43,7 +49,6 @@ export default class LoadingIndicator extends Component<Props> {
return (
<ActivityIndicator
animating = { true }
color = { ColorPalette.white }
{ ...props }
size = { size } />
);

View File

@@ -4,7 +4,7 @@ import { randomHexString } from 'js-utils/random';
import _ from 'lodash';
import { APP_WILL_MOUNT } from '../app';
import JitsiMeetJS, { browser } from '../lib-jitsi-meet';
import { browser } from '../lib-jitsi-meet';
import { ReducerRegistry } from '../redux';
import { PersistenceRegistry } from '../storage';
import { assignIfDefined } from '../util';
@@ -136,17 +136,6 @@ function _initSettings(featureState) {
localFlipX,
micDeviceId
}, settings);
if (settings.audioOutputDeviceId
!== JitsiMeetJS.mediaDevices.getAudioOutputDevice()) {
JitsiMeetJS.mediaDevices.setAudioOutputDevice(
settings.audioOutputDeviceId
).catch(ex => {
logger.warn('Failed to set audio output device from local '
+ 'storage. Default audio output device will be used'
+ 'instead.', ex);
});
}
}
// Things we stored in profile earlier

View File

@@ -21,6 +21,7 @@ export function maybeShowSuboptimalExperienceNotification(dispatch, t) {
&& !browser.isFirefox()
&& !browser.isNWJS()
&& !browser.isElectron()
&& !(browser.isSafariWithVP8() && browser.usesPlanB())
// Adding react native to the list of recommended browsers is not
// necessary for now because the function won't be executed at all

View File

@@ -42,19 +42,8 @@ class AudioOutputPreview extends Component<Props> {
this._audioElement = null;
this._audioElementReady = this._audioElementReady.bind(this);
this._onClick = this._onClick.bind(this);
this._setAudioElement = this._setAudioElement.bind(this);
}
/**
* Sets the target output device on the component's audio element after
* initial render.
*
* @inheritdoc
* @returns {void}
*/
componentDidMount() {
this._setAudioSink();
}
/**
@@ -81,12 +70,28 @@ class AudioOutputPreview extends Component<Props> {
{ this.props.t('deviceSelection.testAudio') }
</a>
<Audio
setRef = { this._setAudioElement }
setRef = { this._audioElementReady }
src = { TEST_SOUND_PATH } />
</div>
);
}
_audioElementReady: (Object) => void;
/**
* Sets the instance variable for the component's audio element so it can be
* accessed directly.
*
* @param {Object} element - The DOM element for the component's audio.
* @private
* @returns {void}
*/
_audioElementReady(element: Object) {
this._audioElement = element;
this._setAudioSink();
}
_onClick: () => void;
/**
@@ -97,21 +102,7 @@ class AudioOutputPreview extends Component<Props> {
*/
_onClick() {
this._audioElement
&& this._audioElement.play();
}
_setAudioElement: (Object) => void;
/**
* Sets the instance variable for the component's audio element so it can be
* accessed directly.
*
* @param {Object} element - The DOM element for the component's audio.
* @private
* @returns {void}
*/
_setAudioElement(element: Object) {
this._audioElement = element;
&& this._audioElement.play();
}
/**
@@ -122,7 +113,7 @@ class AudioOutputPreview extends Component<Props> {
*/
_setAudioSink() {
this._audioElement
&& this._audioElement.setSinkId(this.props.deviceId);
&& this._audioElement.setSinkId(this.props.deviceId);
}
}

View File

@@ -82,31 +82,36 @@ export function processExternalDeviceRequest( // eslint-disable-line max-params
case 'getCurrentDevices':
dispatch(getAvailableDevices()).then(devices => {
if (areDeviceLabelsInitialized(state)) {
let audioInput, audioOutput, videoInput;
const audioOutputDeviceId = getAudioOutputDeviceId();
const { cameraDeviceId, micDeviceId } = settings;
const deviceDescriptions = {
audioInput: undefined,
audioOutput: undefined,
videoInput: undefined
};
const currentlyUsedDeviceIds = new Set([
getAudioOutputDeviceId(),
settings.micDeviceId,
settings.cameraDeviceId
]);
devices.forEach(device => {
const { deviceId } = device;
const { deviceId, kind } = device;
switch (deviceId) {
case micDeviceId:
audioInput = device;
break;
case audioOutputDeviceId:
audioOutput = device;
break;
case cameraDeviceId:
videoInput = device;
break;
if (currentlyUsedDeviceIds.has(deviceId)) {
switch (kind) {
case 'audioinput':
deviceDescriptions.audioInput = device;
break;
case 'audiooutput':
deviceDescriptions.audioOutput = device;
break;
case 'videoinput':
deviceDescriptions.videoInput = device;
break;
}
}
});
responseCallback({
audioInput,
audioOutput,
videoInput
});
responseCallback(deviceDescriptions);
} else {
// The labels are not available if the A/V permissions are
// not yet granted.
@@ -150,7 +155,9 @@ export function processExternalDeviceRequest( // eslint-disable-line max-params
}
const { label, id } = device;
const deviceId = label ? getDeviceIdByLabel(state, device.label) : id;
const deviceId = label
? getDeviceIdByLabel(state, device.label, device.kind)
: id;
if (deviceId) {
switch (device.kind) {

View File

@@ -1,3 +1,5 @@
// @flow
/**
* The type of the Redux action which signals that the prompt for media
* permission is visible or not.
@@ -12,16 +14,6 @@
export const MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED
= 'MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED';
/**
* The type of the Redux action which signals that a suspend was detected.
*
* {
* type: SUSPEND_DETECTED
* }
* @public
*/
export const SUSPEND_DETECTED = 'SUSPEND_DETECTED';
/**
* Adjust the state of the fatal error which shows/hides the reload screen. See
* action methods's description for more info about each of the fields.
@@ -33,3 +25,13 @@ export const SUSPEND_DETECTED = 'SUSPEND_DETECTED';
* @public
*/
export const SET_FATAL_ERROR = 'SET_FATAL_ERROR';
/**
* The type of the Redux action which signals that a suspend was detected.
*
* {
* type: SUSPEND_DETECTED
* }
* @public
*/
export const SUSPEND_DETECTED = 'SUSPEND_DETECTED';

View File

@@ -1,3 +1,5 @@
// @flow
import {
MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
SET_FATAL_ERROR,
@@ -17,7 +19,7 @@ import {
* isVisible: {boolean}
* }}
*/
export function mediaPermissionPromptVisibilityChanged(isVisible, browser) {
export function mediaPermissionPromptVisibilityChanged(isVisible: boolean, browser: string) {
return {
type: MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
browser,
@@ -51,7 +53,7 @@ export function suspendDetected() {
* fatalError: ?Error
* }}
*/
export function setFatalError(fatalError) {
export function setFatalError(fatalError: Object) {
return {
type: SET_FATAL_ERROR,
fatalError

View File

@@ -14,7 +14,7 @@ import {
isFatalJitsiConnectionError
} from '../../base/lib-jitsi-meet';
import ReloadButton from './ReloadButton';
import ReloadButton from './web/ReloadButton';
declare var APP: Object;
@@ -82,6 +82,8 @@ type State = {
/**
* Implements an abstract React {@link Component} for the page reload overlays.
*
* FIXME: This is not really an abstract class as some components and functions are very web specific.
*/
export default class AbstractPageReloadOverlay<P: Props>
extends Component<P, State> {

View File

@@ -0,0 +1,3 @@
// @flow
export * from './native';

View File

@@ -0,0 +1,3 @@
// @flow
export * from './web';

View File

@@ -1,15 +1,4 @@
// @flow
export { default as OverlayContainer } from './OverlayContainer';
export {
default as PageReloadFilmstripOnlyOverlay
} from './PageReloadFilmstripOnlyOverlay';
export { default as PageReloadOverlay } from './PageReloadOverlay';
export {
default as SuspendedFilmstripOnlyOverlay
} from './SuspendedFilmstripOnlyOverlay';
export { default as SuspendedOverlay } from './SuspendedOverlay';
export {
default as UserMediaPermissionsFilmstripOnlyOverlay
} from './UserMediaPermissionsFilmstripOnlyOverlay';
export {
default as UserMediaPermissionsOverlay
} from './UserMediaPermissionsOverlay';
export * from './_';

View File

@@ -0,0 +1,92 @@
// @flow
import React, { Component } from 'react';
import { SafeAreaView, Text } from 'react-native';
import { ColorSchemeRegistry } from '../../../base/color-scheme';
import { translate } from '../../../base/i18n';
import { LoadingIndicator } from '../../../base/react';
import { connect } from '../../../base/redux';
import { StyleType } from '../../../base/styles';
import OverlayFrame from './OverlayFrame';
import styles from './styles';
type Props = {
/**
* The color schemed style of the component.
*/
_styles: StyleType,
/**
* The Function to be invoked to translate i18n keys.
*/
t: Function
};
/**
* Implements an overlay to tell the user that there is an operation in progress in the background during connect
* so then the app doesn't seem hung.
*/
class LoadConfigOverlay extends Component<Props> {
/**
* Determines whether this overlay needs to be rendered (according to a
* specific redux state). Called by {@link OverlayContainer}.
*
* @param {Object} state - The redux state.
* @returns {boolean} - If this overlay needs to be rendered, {@code true};
* {@code false}, otherwise.
*/
static needsRender(state: Object) {
return Boolean(state['features/overlay'].loadConfigOverlayVisible);
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const { _styles } = this.props;
return (
<OverlayFrame>
<SafeAreaView
style = { [
styles.loadingOverlayWrapper,
_styles.loadingOverlayWrapper
] }>
<LoadingIndicator
color = { _styles.indicatorColor }
size = 'large'
style = { styles.connectIndicator } />
<Text
style = { [
styles.loadingOverlayText,
_styles.loadingOverlayText
] }>
{ this.props.t('connectingOverlay.joiningRoom') }
</Text>
</SafeAreaView>
</OverlayFrame>
);
}
}
/**
* Maps part of the Redux state to the props of this component.
*
* @param {Object} state - The Redux state.
* @returns {{
* _styles: StyleType
* }}
*/
function _mapStateToProps(state) {
return {
_styles: ColorSchemeRegistry.get(state, 'LoadConfigOverlay')
};
}
export default translate(connect(_mapStateToProps)(LoadConfigOverlay));

View File

@@ -3,7 +3,7 @@
import React, { Component, type Node } from 'react';
import { SafeAreaView, View } from 'react-native';
import { overlayFrame as styles } from './styles';
import styles from './styles';
/**
* The type of the React {@code Component} props of {@code OverlayFrame}.

View File

@@ -3,18 +3,20 @@
import React from 'react';
import { Text } from 'react-native';
import { appNavigate, reloadNow } from '../../app';
import { ColorSchemeRegistry } from '../../base/color-scheme';
import { ConfirmDialog } from '../../base/dialog';
import { translate } from '../../base/i18n';
import { connect } from '../../base/redux';
import { StyleType } from '../../base/styles';
import { appNavigate, reloadNow } from '../../../app';
import { ColorSchemeRegistry } from '../../../base/color-scheme';
import { ConfirmDialog } from '../../../base/dialog';
import { translate } from '../../../base/i18n';
import { connect } from '../../../base/redux';
import { StyleType } from '../../../base/styles';
import { setFatalError } from '../../actions';
import AbstractPageReloadOverlay, {
abstractMapStateToProps,
type Props as AbstractProps
} from './AbstractPageReloadOverlay';
import { setFatalError } from '../actions';
} from '../AbstractPageReloadOverlay';
import OverlayFrame from './OverlayFrame';
type Props = AbstractProps & {

View File

@@ -0,0 +1,5 @@
// @flow
export { default as LoadConfigOverlay } from './LoadConfigOverlay';
export { default as OverlayFrame } from './OverlayFrame';
export { default as PageReloadOverlay } from './PageReloadOverlay';

View File

@@ -0,0 +1,54 @@
// @flow
import { StyleSheet } from 'react-native';
import { ColorSchemeRegistry, schemeColor } from '../../../base/color-scheme';
import { BoxModel, ColorPalette } from '../../../base/styles';
/**
* The React {@code Component} styles of the overlay feature.
*/
export default {
connectIndicator: {
margin: BoxModel.margin
},
/**
* Style for a backdrop overlay covering the screen the the overlay is
* rendered.
*/
container: {
...StyleSheet.absoluteFillObject,
backgroundColor: ColorPalette.black
},
loadingOverlayText: {
color: ColorPalette.white
},
loadingOverlayWrapper: {
alignItems: 'center',
flex: 1,
flexDirection: 'column',
justifyContent: 'center'
},
safeContainer: {
flex: 1
}
};
/**
* Color schemed styles for all the component based on the abstract dialog.
*/
ColorSchemeRegistry.register('LoadConfigOverlay', {
indicatorColor: schemeColor('text'),
loadingOverlayText: {
color: schemeColor('text')
},
loadingOverlayWrapper: {
backgroundColor: schemeColor('background')
}
});

View File

@@ -1,21 +0,0 @@
import { StyleSheet } from 'react-native';
import { ColorPalette, createStyleSheet } from '../../base/styles';
/**
* The React {@code Component} styles of {@code OverlayFrame}.
*/
export const overlayFrame = createStyleSheet({
/**
* Style for a backdrop overlay covering the screen the the overlay is
* rendered.
*/
container: {
...StyleSheet.absoluteFillObject,
backgroundColor: ColorPalette.black
},
safeContainer: {
flex: 1
}
});

View File

@@ -6,8 +6,8 @@ import {
Avatar,
getAvatarURL,
getLocalParticipant
} from '../../base/participants';
import { connect } from '../../base/redux';
} from '../../../base/participants';
import { connect } from '../../../base/redux';
import OverlayFrame from './OverlayFrame';

View File

@@ -1,4 +1,4 @@
/* @flow */
// @flow
import React, { Component } from 'react';

View File

@@ -1,10 +1,13 @@
// @flow
import React from 'react';
import { translate } from '../../base/i18n';
import { connect } from '../../base/redux';
import { translate } from '../../../base/i18n';
import { connect } from '../../../base/redux';
import AbstractPageReloadOverlay, { type Props, abstractMapStateToProps }
from '../AbstractPageReloadOverlay';
import AbstractPageReloadOverlay, { abstractMapStateToProps }
from './AbstractPageReloadOverlay';
import FilmstripOnlyOverlayFrame from './FilmstripOnlyOverlayFrame';
/**
@@ -12,7 +15,7 @@ import FilmstripOnlyOverlayFrame from './FilmstripOnlyOverlayFrame';
* mode. Shown before the conference is reloaded. Shows a warning message and
* counts down towards the reload.
*/
class PageReloadFilmstripOnlyOverlay extends AbstractPageReloadOverlay {
class PageReloadFilmstripOnlyOverlay extends AbstractPageReloadOverlay<Props> {
/**
* Implements React's {@link Component#render()}.
*
@@ -38,6 +41,10 @@ class PageReloadFilmstripOnlyOverlay extends AbstractPageReloadOverlay {
</FilmstripOnlyOverlayFrame>
);
}
_renderButton: () => React$Element<*> | null
_renderProgressBar: () => React$Element<*> | null
}
export default translate(

View File

@@ -2,13 +2,14 @@
import React from 'react';
import { translate } from '../../base/i18n';
import { connect } from '../../base/redux';
import { translate } from '../../../base/i18n';
import { connect } from '../../../base/redux';
import AbstractPageReloadOverlay, {
abstractMapStateToProps,
type Props
} from './AbstractPageReloadOverlay';
} from '../AbstractPageReloadOverlay';
import OverlayFrame from './OverlayFrame';
/**

View File

@@ -1,10 +1,10 @@
/* @flow */
// @flow
import React, { Component } from 'react';
import { reloadNow } from '../../app';
import { translate } from '../../base/i18n';
import { connect } from '../../base/redux';
import { reloadNow } from '../../../app';
import { translate } from '../../../base/i18n';
import { connect } from '../../../base/redux';
/**
* The type of the React {@code Component} props of {@link ReloadButton}.

View File

@@ -1,6 +1,8 @@
// @flow
import React from 'react';
import { translate, translateToHTML } from '../../base/i18n';
import { translate, translateToHTML } from '../../../base/i18n';
import AbstractSuspendedOverlay from './AbstractSuspendedOverlay';
import FilmstripOnlyOverlayFrame from './FilmstripOnlyOverlayFrame';

View File

@@ -1,6 +1,8 @@
// @flow
import React from 'react';
import { translate, translateToHTML } from '../../base/i18n';
import { translate, translateToHTML } from '../../../base/i18n';
import AbstractSuspendedOverlay from './AbstractSuspendedOverlay';
import OverlayFrame from './OverlayFrame';

View File

@@ -1,7 +1,9 @@
// @flow
import React from 'react';
import { translate, translateToHTML } from '../../base/i18n';
import { connect } from '../../base/redux';
import { translate, translateToHTML } from '../../../base/i18n';
import { connect } from '../../../base/redux';
import AbstractUserMediaPermissionsOverlay, { abstractMapStateToProps }
from './AbstractUserMediaPermissionsOverlay';

View File

@@ -1,39 +1,21 @@
/* global interfaceConfig */
// @flow
import React from 'react';
import { translate, translateToHTML } from '../../base/i18n';
import { connect } from '../../base/redux';
import { translate, translateToHTML } from '../../../base/i18n';
import { connect } from '../../../base/redux';
import AbstractUserMediaPermissionsOverlay, { abstractMapStateToProps }
from './AbstractUserMediaPermissionsOverlay';
import OverlayFrame from './OverlayFrame';
declare var interfaceConfig: Object;
/**
* Implements a React Component for overlay with guidance how to proceed with
* gUM prompt.
*/
class UserMediaPermissionsOverlay extends AbstractUserMediaPermissionsOverlay {
/**
* Initializes a new UserMediaPermissionsOverlay instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
* @public
*/
constructor(props) {
super(props);
this.state = {
/**
* The src value of the image for the policy logo.
*
* @type {string}
*/
policyLogoSrc: interfaceConfig.POLICY_LOGO
};
}
/**
* Implements React's {@link Component#render()}.
*
@@ -80,7 +62,7 @@ class UserMediaPermissionsOverlay extends AbstractUserMediaPermissionsOverlay {
* @returns {ReactElement|null}
*/
_renderPolicyLogo() {
const { policyLogoSrc } = this.state;
const policyLogoSrc = interfaceConfig.POLICY_LOGO;
if (policyLogoSrc) {
return (

View File

@@ -0,0 +1,19 @@
// @flow
export { default as FilmstripOnlyOverlayFrame } from './FilmstripOnlyOverlayFrame';
export { default as OverlayFrame } from './OverlayFrame';
export {
default as PageReloadFilmstripOnlyOverlay
} from './PageReloadFilmstripOnlyOverlay';
export { default as PageReloadOverlay } from './PageReloadOverlay';
export {
default as SuspendedFilmstripOnlyOverlay
} from './SuspendedFilmstripOnlyOverlay';
export { default as SuspendedOverlay } from './SuspendedOverlay';
export {
default as UserMediaPermissionsFilmstripOnlyOverlay
} from './UserMediaPermissionsFilmstripOnlyOverlay';
export {
default as UserMediaPermissionsOverlay
} from './UserMediaPermissionsOverlay';

View File

@@ -1,49 +1,6 @@
// @flow
import {
PageReloadFilmstripOnlyOverlay,
PageReloadOverlay,
SuspendedFilmstripOnlyOverlay,
SuspendedOverlay,
UserMediaPermissionsFilmstripOnlyOverlay,
UserMediaPermissionsOverlay
} from './components';
declare var interfaceConfig: Object;
/**
* Returns the list of available overlays that might be rendered.
*
* @private
* @returns {Array<?React$ComponentType<*>>}
*/
function _getOverlays() {
const filmstripOnly
= typeof interfaceConfig === 'object' && interfaceConfig.filmStripOnly;
let overlays;
if (filmstripOnly) {
overlays = [
PageReloadFilmstripOnlyOverlay,
SuspendedFilmstripOnlyOverlay,
UserMediaPermissionsFilmstripOnlyOverlay
];
} else {
overlays = [
PageReloadOverlay
];
}
// Mobile only has a PageReloadOverlay.
if (navigator.product !== 'ReactNative') {
overlays.push(...[
SuspendedOverlay,
UserMediaPermissionsOverlay
]);
}
return overlays;
}
import { getOverlays } from './overlays';
/**
* Returns the overlay to be currently rendered.
@@ -52,7 +9,7 @@ function _getOverlays() {
* @returns {?React$ComponentType<*>}
*/
export function getOverlayToRender(state: Object) {
for (const overlay of _getOverlays()) {
for (const overlay of getOverlays()) {
// react-i18n / react-redux wrap components and thus we cannot access
// the wrapped component's static methods directly.
const component = overlay.WrappedComponent || overlay;

View File

@@ -1,3 +1,5 @@
// @flow
export * from './actions';
export * from './components';
export * from './functions';

View File

@@ -0,0 +1,18 @@
// @flow
import {
LoadConfigOverlay,
PageReloadOverlay
} from './components/native';
/**
* Returns the list of available platform specific overlays.
*
* @returns {Array<React$Element>}
*/
export function getOverlays(): Array<React$Element<*>> {
return [
LoadConfigOverlay,
PageReloadOverlay
];
}

View File

@@ -0,0 +1,38 @@
// @flow
import {
PageReloadFilmstripOnlyOverlay,
PageReloadOverlay,
SuspendedFilmstripOnlyOverlay,
SuspendedOverlay,
UserMediaPermissionsFilmstripOnlyOverlay,
UserMediaPermissionsOverlay
} from './components/web';
declare var interfaceConfig: Object;
/**
* Returns the list of available platform specific overlays.
*
* @returns {Array<Object>}
*/
export function getOverlays(): Array<Object> {
const overlays = [
SuspendedOverlay,
UserMediaPermissionsOverlay
];
const filmstripOnly
= typeof interfaceConfig === 'object' && interfaceConfig.filmStripOnly;
if (filmstripOnly) {
overlays.push(
PageReloadFilmstripOnlyOverlay,
SuspendedFilmstripOnlyOverlay,
UserMediaPermissionsFilmstripOnlyOverlay);
} else {
overlays.push(PageReloadOverlay);
}
return overlays;
}

View File

@@ -1,5 +1,6 @@
// @flow
import { CONFIG_WILL_LOAD, LOAD_CONFIG_ERROR, SET_CONFIG } from '../base/config';
import { assign, ReducerRegistry, set } from '../base/redux';
import {
@@ -15,6 +16,13 @@ import {
*/
ReducerRegistry.register('features/overlay', (state = { }, action) => {
switch (action.type) {
case CONFIG_WILL_LOAD:
return _setShowLoadConfigOverlay(state, Boolean(action.room));
case LOAD_CONFIG_ERROR:
case SET_CONFIG:
return _setShowLoadConfigOverlay(false);
case MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED:
return _mediaPermissionPromptVisibilityChanged(state, action);
@@ -48,15 +56,15 @@ function _mediaPermissionPromptVisibilityChanged(
}
/**
* Reduces a specific redux action SUSPEND_DETECTED of the feature overlay.
* Sets the {@code LoadConfigOverlay} overlay visible or not.
*
* @param {Object} state - The redux state of the feature overlay.
* @private
* @param {boolean} show - Whether to show or not the overlay.
* @returns {Object} The new state of the feature overlay after the reduction of
* the specified action.
*/
function _suspendDetected(state) {
return set(state, 'suspendDetected', true);
function _setShowLoadConfigOverlay(state, show) {
return set(state, 'loadConfigOverlayVisible', show);
}
/**
@@ -72,3 +80,15 @@ function _suspendDetected(state) {
function _setFatalError(state, { fatalError }) {
return set(state, 'fatalError', fatalError);
}
/**
* Reduces a specific redux action SUSPEND_DETECTED of the feature overlay.
*
* @param {Object} state - The redux state of the feature overlay.
* @private
* @returns {Object} The new state of the feature overlay after the reduction of
* the specified action.
*/
function _suspendDetected(state) {
return set(state, 'suspendDetected', true);
}

View File

@@ -91,7 +91,7 @@ export const SET_TOOLBOX_TIMEOUT = 'SET_TOOLBOX_TIMEOUT';
* timeoutMS: number
* }
*/
export const SET_TOOLBOX_TIMEOUT_MS = 'SET_TOOLBOX_TIMEOUT';
export const SET_TOOLBOX_TIMEOUT_MS = 'SET_TOOLBOX_TIMEOUT_MS';
/**
* The type of the (redux) action which shows/hides the Toolbox.

View File

@@ -1,3 +1,15 @@
/**
* The type of the action which sets the list of known participant IDs which
* have an active screen share.
*
* @returns {{
* type: SCREEN_SHARE_PARTICIPANTS_UPDATED,
* participantIds: Array<string>
* }}
*/
export const SCREEN_SHARE_PARTICIPANTS_UPDATED
= 'SCREEN_SHARE_PARTICIPANTS_UPDATED';
/**
* The type of the action which enables or disables the feature for showing
* video thumbnails in a two-axis tile view.

View File

@@ -1,6 +1,27 @@
// @flow
import { SET_TILE_VIEW } from './actionTypes';
import {
SCREEN_SHARE_PARTICIPANTS_UPDATED,
SET_TILE_VIEW
} from './actionTypes';
/**
* Creates a (redux) action which signals that the list of known participants
* with screen shares has changed.
*
* @param {string} participantIds - The participants which currently have active
* screen share streams.
* @returns {{
* type: SCREEN_SHARE_PARTICIPANTS_UPDATED,
* participantId: string
* }}
*/
export function setParticipantsWithScreenShare(participantIds: Array<string>) {
return {
type: SCREEN_SHARE_PARTICIPANTS_UPDATED,
participantIds
};
}
/**
* Creates a (redux) action which signals to set the UI layout to be tiled view

View File

@@ -3,14 +3,30 @@
import { ReducerRegistry } from '../base/redux';
import { PersistenceRegistry } from '../base/storage';
import { SET_TILE_VIEW } from './actionTypes';
import {
SCREEN_SHARE_PARTICIPANTS_UPDATED,
SET_TILE_VIEW
} from './actionTypes';
const DEFAULT_STATE = {
screenShares: []
};
const STORE_NAME = 'features/video-layout';
PersistenceRegistry.register(STORE_NAME);
PersistenceRegistry.register(STORE_NAME, {
tileViewEnabled: true
});
ReducerRegistry.register(STORE_NAME, (state = {}, action) => {
ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
switch (action.type) {
case SCREEN_SHARE_PARTICIPANTS_UPDATED: {
return {
...state,
screenShares: action.participantIds
};
}
case SET_TILE_VIEW:
return {
...state,

View File

@@ -4,9 +4,16 @@ import {
VIDEO_QUALITY_LEVELS,
setMaxReceiverVideoQuality
} from '../base/conference';
import { StateListenerRegistry } from '../base/redux';
import {
getPinnedParticipant,
pinParticipant
} from '../base/participants';
import { StateListenerRegistry, equals } from '../base/redux';
import { selectParticipant } from '../large-video';
import { shouldDisplayTileView } from './functions';
import { setParticipantsWithScreenShare } from './actions';
declare var interfaceConfig: Object;
/**
* StateListenerRegistry provides a reliable way of detecting changes to
@@ -14,11 +21,89 @@ import { shouldDisplayTileView } from './functions';
*/
StateListenerRegistry.register(
/* selector */ state => shouldDisplayTileView(state),
/* listener */ (displayTileView, { dispatch }) => {
/* listener */ (displayTileView, store) => {
const { dispatch } = store;
dispatch(selectParticipant());
if (!displayTileView) {
dispatch(setMaxReceiverVideoQuality(VIDEO_QUALITY_LEVELS.HIGH));
dispatch(
setMaxReceiverVideoQuality(VIDEO_QUALITY_LEVELS.HIGH));
if (typeof interfaceConfig === 'object'
&& interfaceConfig.AUTO_PIN_LATEST_SCREEN_SHARE) {
_updateAutoPinnedParticipant(store);
}
}
}
);
/**
* For auto-pin mode, listen for changes to the known media tracks and look
* for updates to screen shares.
*/
StateListenerRegistry.register(
/* selector */ state => state['features/base/tracks'],
/* listener */ (tracks, store) => {
if (typeof interfaceConfig !== 'object'
|| !interfaceConfig.AUTO_PIN_LATEST_SCREEN_SHARE) {
return;
}
const oldScreenSharesOrder
= store.getState()['features/video-layout'].screenShares || [];
const knownSharingParticipantIds = tracks.reduce((acc, track) => {
if (track.mediaType === 'video' && track.videoType === 'desktop') {
acc.push(track.participantId);
}
return acc;
}, []);
// Filter out any participants which are no longer screen sharing
// by looping through the known sharing participants and removing any
// participant IDs which are no longer sharing.
const newScreenSharesOrder = oldScreenSharesOrder.filter(
participantId => knownSharingParticipantIds.includes(participantId));
// Make sure all new sharing participant get added to the end of the
// known screen shares.
knownSharingParticipantIds.forEach(participantId => {
if (!newScreenSharesOrder.includes(participantId)) {
newScreenSharesOrder.push(participantId);
}
});
if (!equals(oldScreenSharesOrder, newScreenSharesOrder)) {
store.dispatch(
setParticipantsWithScreenShare(newScreenSharesOrder));
_updateAutoPinnedParticipant(store);
}
}
);
/**
* Private helper to automatically pin the latest screen share stream or unpin
* if there are no more screen share streams.
*
* @param {Store} store - The redux store.
* @returns {void}
*/
function _updateAutoPinnedParticipant({ dispatch, getState }) {
const state = getState();
const screenShares = state['features/video-layout'].screenShares;
if (!screenShares) {
return;
}
const latestScreenshareParticipantId
= screenShares[screenShares.length - 1];
if (latestScreenshareParticipantId) {
dispatch(pinParticipant(latestScreenshareParticipantId));
} else if (getPinnedParticipant(state['features/base/participants'])) {
dispatch(pinParticipant(null));
}
}

View File

@@ -1,12 +0,0 @@
--- /usr/lib/prosody/modules/mod_bosh.lua 2015-12-16 14:28:34.000000000 -0600
+++ /usr/lib/prosody/modules/mod_bosh.lua 2015-12-22 10:45:59.818197967 -0600
@@ -294,6 +294,9 @@
session.log("debug", "BOSH session created for request from %s", session.ip);
log("info", "New BOSH session, assigned it sid '%s'", sid);
+
+ hosts[session.host].events.fire_event(
+ "bosh-session", { session = session, request = request });
-- Send creation response
local creating_session = true;

View File

@@ -56,7 +56,20 @@ const config = {
// Tell babel to avoid compiling imports into CommonJS
// so that webpack may do tree shaking.
{ modules: false }
{
modules: false,
// Specify our target browsers so no transpiling is
// done unnecessarily. For browsers not specified
// here, the ES2015+ profile will be used.
targets: {
chrome: 58,
electron: 2,
firefox: 54,
safari: 11
}
}
],
require.resolve('@babel/preset-flow'),
require.resolve('@babel/preset-react')