Compare commits

..

100 Commits

Author SHA1 Message Date
Jaya Allamsetty
ed82443ffa clean-up 2019-12-10 15:59:06 -05:00
Jaya Allamsetty
a3cd331369 fix: Workaround on FF for getting the resolution of the desktop track 2019-12-10 15:59:06 -05:00
Leonard Kim
9c77ab7f4d ref(api): use Transport modules from js-utils
PostMessageTransportBackend and Transport, along
with the constants file they both use, were
moved int js-utils for jitsi-meet-spot.
2019-12-10 06:48:19 -08:00
Saúl Ibarra Corretgé
55983ff62a rn,welcome: update join button text 2019-12-10 15:13:37 +01:00
damencho
b4be1bcd05 Adds some checks about async.
There are modules that will not work with prosody 0.10 as they depend on util.async. Adds a safeguard and print error about it in the logs.
And others that just do not work because of the muc module API that they use.
2019-12-10 10:55:56 +01:00
damencho
2420a68be9 Enables speakerstats component and module by default. 2019-12-10 10:55:56 +01:00
damencho
ebfc5a95ff Activates multidomain by default when installing with nginx. 2019-12-10 10:55:56 +01:00
Leonard Kim
68cad276bd fix(lock): ensure lock prompt is closed on password submit
This addresses a bug, in which submitting a password
through the iframe api no longer closes RoomLockPrompt,
by explicitly closing prompts for a lock or password.
2019-12-09 08:44:18 -08:00
Bettenbuk Zoltan
e683d70a18 Add support for avatar status badge (presence) 2019-12-09 11:58:23 +01:00
Andrei Gavrilescu
9645391180 update package links 2019-12-06 11:37:08 +00:00
Andrei Gavrilescu
851b1a76a9 Address code review 2019-12-06 11:37:08 +00:00
Andrei Gavrilescu
4890390ea2 fix action uid name / remove imports 2019-12-06 11:37:08 +00:00
Andrei Gavrilescu
7828bf8d46 setNoSrcDataNotificationUid 2019-12-06 11:37:08 +00:00
Andrei Gavrilescu
191da551e3 refactor / address code review 2019-12-06 11:37:08 +00:00
Andrei Gavrilescu
55f35933e8 address code review 2019-12-06 11:37:08 +00:00
Andrei Gavrilescu
b125bff7c7 refactor / enable VAD talk while muted 2019-12-06 11:37:08 +00:00
Andrei Gavrilescu
c1d261445e Initial commit 2019-12-06 11:37:08 +00:00
Andrei Gavrilescu
c494d6c48b feat: show no audio signal notification 2019-12-06 11:37:08 +00:00
Saúl Ibarra Corretgé
4134d47f6e recording: remove beta label from LiveStreamButton 2019-12-05 16:23:27 +01:00
Jaya Allamsetty
0b25e62c5c fix: Reuse the existing JitsiLocalTrack on presenter unmute 2019-12-05 09:25:34 -05:00
damencho
4d0cbff5a1 Ignore errors when restarting services.
Sometimes conflicting or wrong configuration can leave the package in broken state and users cannot even uninstall/purge the packages, and it also breaks any other package installation.
2019-12-04 17:21:12 +00:00
damencho
c79463aaee Fixes including config.js template. 2019-12-04 17:21:12 +00:00
damencho
339e1c5fab Moves config template files out of doc folder. 2019-12-04 09:50:55 +00:00
Saúl Ibarra Corretgé
36455c24c8 auth: fix rendering error and progress messages
Also removed some no longer used styles.
2019-12-03 14:33:26 +01:00
Saúl Ibarra Corretgé
a622a4c713 android: handle ConnectionService failures more resiliently
Some Samsung devices will fail to fully engage ConnectionService if no SIM card
was ever installed on the device. We could check for it, but it would require
the CALL_PHONE permission, which is not something we want to do, so fallback to
not using ConnectionService.
2019-12-03 11:56:04 +01:00
Hristo Terezov
1aaaae24ee feat(Amplitude): enable referrer 2019-11-29 15:43:14 +00:00
Hristo Terezov
9191000da4 chore(package.json): Update lib-jitsi-meet 2019-11-29 13:41:14 +00:00
Bettenbuk Zoltan
8eb93086bd fix: set an avatar icon size relative to the container 2019-11-29 14:37:35 +01:00
Bettenbuk Zoltan
b64294af6d fix: emoji in links 2019-11-29 14:36:42 +01:00
Hristo Terezov
bbf33a8895 feat(welcome-page): Add viewed analytics event. 2019-11-28 15:36:12 +00:00
Jaya Allamsetty
bcc1289a23 feat(presenter): Modify the default behavior for presenter mode, it set to off when screensharing is turned on. Also, revert video to the original state when screensharing is turned off. 2019-11-27 11:13:36 -08:00
Saúl Ibarra Corretgé
58bd48c1ae android: disable ConnectionService if permissions are not granted
Some devices seem to have a bug in their Android versions and startCall fails
with SecurityError because the CALL_PHONE permissions is not granted. This is
not a requirement for self-managed connection services as per the official
documentation though:
https://developer.android.com/guide/topics/connectivity/telecom/selfManaged

Alas, connection services takes over audio device management too, so let's
handle the error and disable CS if we get SecurityError.
2019-11-27 14:33:25 +01:00
Saúl Ibarra Corretgé
1a3736bf98 android: unregister phone account if startCall fails 2019-11-27 14:33:25 +01:00
Saúl Ibarra Corretgé
0eec182df4 android: remove old code for accepting SDK license
It can now be automated in a CI environment as follows:

yes | sdkmanager --licenses
2019-11-27 14:24:29 +01:00
Saúl Ibarra Corretgé
c526844eb2 chore: remove unused images 2019-11-26 21:20:50 +01:00
Saúl Ibarra Corretgé
d856c1f328 ios: add apple-touch-icon icon
Ref: https://webhint.io/docs/user-guide/hints/hint-apple-touch-icons/
2019-11-26 21:13:02 +01:00
Saúl Ibarra Corretgé
15e47a9eb3 android: update native dependencies 2019-11-26 20:33:38 +01:00
Saúl Ibarra Corretgé
da98d39b61 doc: add app download badges to README 2019-11-26 14:58:35 +01:00
Bettenbuk Zoltan
411bafb5a6 feat: minimized bottom menu 2019-11-26 12:08:43 +01:00
Jaya Allamsetty
0a64bf2068 feat(presenter): add Presenter Mode
- Adds the ability to share video as a "PiP" when screenshare is in progress.
- Add a method for creating a local presenter track.
- Make sure isLocalVideoTrackMuted returns the correct mute state when only screenshare is present.
- Make sure we get the updated window size of the window being shared before painting it on the canvas.
- Make sure we check if the shared window has been resized
2019-11-26 11:57:03 +01:00
damencho
db6a2673de Handles unique Id for a meeting. 2019-11-26 10:37:19 +00:00
damencho
e11d4d3101 Installs prosody plugins with jitsi-meet-prosody package. 2019-11-26 10:37:19 +00:00
Saúl Ibarra Corretgé
8fd3bb2302 android: fallbacck to speaker in ConnectionService handler
It has been our default for a while.
2019-11-26 11:30:18 +01:00
theunafraid
fb3a832a52 Add shortcut key for toggle tile view (#4882)
* Add shortcut key for toggle tile view

* Toggle tile view shortcut - undo main-enGB.json

* Add analytics

* Use already defined toolbar translations
2019-11-22 16:15:39 +00:00
Saúl Ibarra Corretgé
9c146c1245 subject: hide participant count for 1-1 calls
refs: https://github.com/jitsi/jitsi-meet/issues/4871
2019-11-22 10:49:24 +01:00
Saúl Ibarra Corretgé
792f506425 ios: drop support for iOS 10 2019-11-22 10:46:02 +01:00
Bettenbuk Zoltan
6121e9fc65 feat: improve chat UX 2019-11-21 18:11:58 +01:00
Bettenbuk Zoltan
955fa1f49f fix: undefined is not an object on bitrate 2019-11-21 18:11:58 +01:00
damencho
2544d0a084 Fixes the message for who kicked you. 2019-11-20 17:01:00 +02:00
Bettenbuk Zoltan
8f0a12016a fix: return room lock conference, when there is no other 2019-11-20 13:28:47 +01:00
Leonard Kim
34ccd3524f fix(chat): preserve intentional linebreaks in message display 2019-11-20 08:58:02 +01:00
Leonard Kim
563e99ecd3 fix(chat): wrap long text 2019-11-18 09:31:47 -08:00
Leonard Kim
70f14be50f fix(large-video): center dominant speaker avatar using css
The vertical alignment was being set with javascript.
Recent changes might make the setting of alignment exit
early due to height 0 video. As position can be set
declaratively with css, use css to set position.
2019-11-15 07:51:59 -08:00
Bettenbuk Zoltan
8bd0da886e feat: safe decodeURIComponent 2019-11-15 15:18:20 +01:00
damencho
1fd326f980 Fixes nginx match rule, containing wrong chars.
Also adds a missing '/'.
2019-11-15 14:10:55 +00:00
yanas
d9cc664ea6 Merge pull request #4865 from jitsi/position-status-message
fix(remote-status-message): position
2019-11-15 14:10:34 +00:00
Hristo Terezov
d65e241056 fix(remote-status-message): position 2019-11-15 12:33:01 +00:00
Saúl Ibarra Corretgé
fe2b1f3d9f rn: refactor aspect ratio and reduced UI detectors 2019-11-15 12:54:44 +01:00
virtuacoplenny
17c1f50fc3 fix(mobile-landing): do not attempt opening download link in new window
Instead let the mobile OS take care of opening the URL
in the appropriate application. Without target _blank,
iOS 13.2.2 on Chrome will open about:blank and immediately
close the tab instead of opening the store.
2019-11-15 09:43:18 +01:00
Saúl Ibarra Corretgé
5c1c022291 doc: add open beta links to README 2019-11-15 09:30:42 +01:00
Boris Grozev
72435dee56 Order fields alphabetically. 2019-11-14 17:49:06 -06:00
Boris Grozev
42f2eff02a Whitelists the "stereo" flag. 2019-11-14 17:49:06 -06:00
Saúl Ibarra Corretgé
0b68bef0be ios: set Fastlane test groups 2019-11-14 18:21:37 +01:00
Saúl Ibarra Corretgé
676e943d81 ios: fix typo in Fastlane file 2019-11-14 16:02:39 +01:00
Saúl Ibarra Corretgé
2b4307dee9 ios: fix Fastlane beta build submissions 2019-11-14 15:49:09 +01:00
Hristo Terezov
f3f936c196 fix(large-video): missing video. 2019-11-14 06:29:27 -08:00
Saúl Ibarra Corretgé
eb900ddbe1 android: fix track name in Fastlane 2019-11-14 15:27:32 +01:00
Saúl Ibarra Corretgé
c2c323347a rn: skip logging potentially sensitive data 2019-11-14 15:01:29 +01:00
Saúl Ibarra Corretgé
af6642b91b rn: allow for userInfo and token to be set from the SDK 2019-11-14 12:30:15 +01:00
drimovecz
ffded8d82a Drimovecz/speakerstats (#4851)
* Correctly process speaker stats events when the conference contains a subdomain
2019-11-13 15:37:09 +00:00
Saúl Ibarra Corretgé
00b57c7983 fix(transport): remove legacy code
It has been around bor > 2.5 years already.
2019-11-13 16:15:29 +01:00
Saúl Ibarra Corretgé
5d40a8992a ios: disable bitcode when building the SDK for a release
This makes it possible to compile the SDK with Xcode 10 and 11. The problem is
that the Google SDK (used for sign-in) is compiled with Xcode 11. This avoids
the issue.
2019-11-13 13:17:51 +01:00
Saúl Ibarra Corretgé
e543625295 rn,settings: set the placeholder text color 2019-11-13 10:38:05 +01:00
Saúl Ibarra Corretgé
0b25ff649e ios: fix not displaying TextInput values in SettingsView 2019-11-13 10:38:05 +01:00
Saúl Ibarra Corretgé
63344ac62d deps: react-native-webrtc@1.75.2
Fixes an Android crash on craptacular devices.
2019-11-13 08:31:05 +01:00
Saúl Ibarra Corretgé
2e60aafebf fastlane,ios: add ability to set the changelog 2019-11-12 18:14:02 +01:00
Saúl Ibarra Corretgé
131e8f4aea fastlane: prepare for open beta access 2019-11-12 16:06:15 +01:00
Bettenbuk Zoltan
53f01a39c9 feat: private message interface config flag 2019-11-12 15:48:53 +01:00
Дамян Минков
50f4796144 Adds an option to set email through iframe API init and to stats. (#4842)
* Adds an option to set email through iframe API init and to stats.

* Simplifies configuring email and displayName in stats.

Removes enableStatsID as not needed as when off we are sending as callstats id xmpp resource which is unique per call and id must be something that sticks between calls (callstatsUsername).

* Adds email and displayName in stats config for mobile.

* chore(deps): Updates lib-jitsi-meet to latest dd31f0a.

* Removes enableStatsID from config and whitelist.
2019-11-12 13:37:54 +00:00
Дамян Минков
5bdfae377f Adds a hook to insert body & head html. (#4843)
* Adds a hook to insert body html.

* Adds a hook to insert head html.
2019-11-12 13:37:48 +00:00
Saúl Ibarra Corretgé
44970648ea rn: now working on versions 19.5 / 2.5 2019-11-08 15:21:55 +01:00
Saúl Ibarra Corretgé
3cd7f0b77d settings: fix loading disableCallIntegration 2019-11-08 12:15:49 +01:00
Saúl Ibarra Corretgé
4d243f9b92 android: fix selecting the Bluetooth route
Samsung devices (of course) seem to stick with the earpiece if we first select
Bluetooth but then set speaker to false. Reverse the order to make everyone
happy.

This only applies to the generic and legacy handlers.
2019-11-08 12:15:49 +01:00
Saúl Ibarra Corretgé
6b716f8f56 android: fix initializing audio device handler modules too early
When ConnectionService is used (the default) we were attaching the handlers too
early, and since attaching them requires that the RNConnectionService module is
loaded, it silently failed. Instead, use the initialize() method, which gets
called after all the Catalyst (aka native) modules have been loaded.
2019-11-08 12:15:49 +01:00
Saúl Ibarra Corretgé
5b99219f29 android: log a warning if listeners could not be attached 2019-11-08 12:15:49 +01:00
Saúl Ibarra Corretgé
f0dcb51915 android: make code a bit more readable 2019-11-08 12:15:49 +01:00
Bettenbuk Zoltan
3ff658a13b fix: respect safe area in conference on ios 2019-11-07 12:26:54 +01:00
Bettenbuk Zoltan
3a46513d4b ref: remove unused code 2019-11-07 12:26:54 +01:00
Saúl Ibarra Corretgé
ad0064993d ios: enable Swift mobule stability for the SDK target
Supersedes: https://github.com/jitsi/jitsi-meet/pull/4818
Fixes: https://github.com/jitsi/jitsi-meet/issues/4812
2019-11-06 18:30:26 +01:00
Saúl Ibarra Corretgé
458d4acd22 ios: use the "new" Xcode build system
It was introduced in Xcode 9 and made the default in Xcode 10. We were forcing
the use of the legacy version, which doesn't support some new features that we
wish to enable, such as building the SDK for distribution.
2019-11-06 18:30:26 +01:00
Saúl Ibarra Corretgé
8ebc99175c ios: set deployment target on Pods to 10.0
Matches the app / SDK deployment target and avoids compilation warnings.
2019-11-06 18:30:26 +01:00
Vlad Piersec
9889cb2b69 Add conference name as fallback for subject 2019-11-06 17:23:18 +01:00
Saúl Ibarra Corretgé
191e530071 uri: avoid using String.prototype.normalize
It crashes on Android. Well, on the JSC version React Native uses on Android.

While we could use this fallback only on Android, we have decided to use it
on all mobile platforms for consistency.
2019-11-06 15:37:14 +01:00
Mihai Uscat
ae30d39b4d feat(PromotionalFooter): Implement 2019-11-06 03:29:49 -08:00
Leonard Kim
c354e46846 chore(deps): update lib so newer FF does not need click for gum 2019-11-06 07:47:14 +00:00
Hristo Terezov
5da4e43e50 fix(settings): respect configWhitelist 2019-11-05 02:13:54 -08:00
Hristo Terezov
eae6f7760f fix(configWhitelist): add startWithAudioMuted. 2019-11-05 02:13:54 -08:00
Mihai Uscat
00161212c8 feat(welcome): Add responsive text to go button 2019-11-04 05:48:55 -08:00
Mark Anthony Sison
8976b92842 doc(install): adds cd command to jitsi-meet installation 2019-11-03 19:46:34 +00:00
Vlad Piersec
c3a6a8fb17 Add participants count 2019-10-31 09:08:59 -07:00
198 changed files with 2650 additions and 2299 deletions

View File

@@ -27,10 +27,25 @@ You can download Debian/Ubuntu binaries:
You can download source archives (produced by ```make source-package```):
* [source builds](https://download.jitsi.org/jitsi-meet/src/)
You can get our mobile versions from here:
### Mobile apps
* [Android](https://play.google.com/store/apps/details?id=org.jitsi.meet)
[<img src="resources/img/google-play-badge.png" height="50">](https://play.google.com/store/apps/details?id=org.jitsi.meet)
* [Android (F-Droid)](https://f-droid.org/en/packages/org.jitsi.meet/)
[<img src="resources/img/f-droid-badge.png" height="50">](https://f-droid.org/en/packages/org.jitsi.meet/)
* [iOS](https://itunes.apple.com/us/app/jitsi-meet/id1165103905)
[<img src="resources/img/appstore-badge.png" height="50">](https://itunes.apple.com/us/app/jitsi-meet/id1165103905)
You can also sign up for our open beta testing here:
* [Android](https://play.google.com/apps/testing/org.jitsi.meet)
* [iOS](https://testflight.apple.com/join/isy6ja7S)
## Development
For web development see [here](doc/development.md), and for mobile see [here](doc/mobile.md).

View File

@@ -69,7 +69,9 @@ repositories {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.appcompat:appcompat:1.1.0'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-beta-5'
if (!rootProject.ext.libreBuild) {
implementation 'com.google.android.gms:play-services-auth:16.0.1'
@@ -83,9 +85,6 @@ dependencies {
}
implementation project(':sdk')
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.1'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'
}
gradle.projectsEvaluated {

View File

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

View File

@@ -1,36 +0,0 @@
/*
* Copyright @ 2018-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.
*/
package org.jitsi.meet;
import android.app.Application;
import com.squareup.leakcanary.LeakCanary;
/**
* Simple {@link Application} for hooking up LeakCanary:
* https://github.com/square/leakcanary
*/
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (!LeakCanary.isInAnalyzerProcess(this)) {
LeakCanary.install(this);
}
}
}

View File

@@ -13,8 +13,8 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'
classpath 'com.google.gms:google-services:4.2.0'
classpath 'io.fabric.tools:gradle:1.27.0'
classpath 'com.google.gms:google-services:4.3.3'
classpath 'io.fabric.tools:gradle:1.28.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files.
@@ -165,50 +165,6 @@ ext {
libreBuild = (System.env.LIBRE_BUILD ?: "false").toBoolean()
}
// If Android SDK is not installed, accept its license so that it
// is automatically downloaded.
afterEvaluate { project ->
// Either the environment variable ANDROID_HOME or the property sdk.dir in
// local.properties identifies where Android SDK is installed.
def androidHome = System.env.ANDROID_HOME
if (!androidHome) {
// ANDROID_HOME is not set. Is sdk.dir set?
def file = file("${project.rootDir}/local.properties")
def props = new Properties()
if (file.canRead()) {
file.withInputStream {
props.load(it)
androidHome = props.'sdk.dir'
}
}
if (!androidHome && (!file.exists() || file.canWrite())) {
// Neither ANDROID_HOME nor sdk.dir is set. Set sdk.dir (because
// environment variables cannot be set).
props.'sdk.dir' = "${project.buildDir}/android-sdk".toString()
file.withOutputStream {
props.store(it, null)
androidHome = props.'sdk.dir'
}
}
}
// If the license is not accepted, accept it so that automatic downloading
// kicks in.
// The license hash can be taken from the accepted licenses, by doing this
// on your local machine the file is
// ${androidHome}/licenses/android-sdk-license
if (androidHome) {
def dir = file("${androidHome}/licenses")
dir.mkdirs()
def file = file("${dir.path}/android-sdk-license")
if (!file.exists()) {
file.withWriter {
def hash = 'd56f5187479451eabf01fb78af6dfcb131a6481e'
it.write(hash, 0, hash.length())
}
}
}
}
// Force the version of the Android build tools we have chosen on all
// subprojects. The forcing was introduced for react-native and the third-party
// modules that we utilize such as react-native-background-timer.

View File

@@ -24,7 +24,7 @@ platform :android do
# Upload built artifact to the Closed Beta track
upload_to_play_store(
track: "Closed Beta",
track: "beta",
json_key: ENV["JITSI_JSON_KEY_FILE"],
skip_upload_metadata: true,
skip_upload_images: true,

View File

@@ -20,5 +20,5 @@
android.useAndroidX=true
android.enableJetifier=true
appVersion=19.4.0
sdkVersion=2.4.0
appVersion=19.5.0
sdkVersion=2.5.0

View File

@@ -37,10 +37,12 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.fragment:fragment:1.0.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.fragment:fragment:1.1.0'
//noinspection GradleDynamicVersion
api 'com.facebook.react:react-native:+'
//noinspection GradleDynamicVersion
implementation 'org.webkit:android-jsc:+'
implementation 'com.dropbox.core:dropbox-core-sdk:3.0.8'

View File

@@ -18,6 +18,7 @@ package org.jitsi.meet.sdk;
import android.content.Context;
import android.os.Build;
import android.telecom.CallAudioState;
import androidx.annotation.RequiresApi;
import java.util.HashSet;
@@ -52,20 +53,20 @@ class AudioDeviceHandlerConnectionService implements
*/
private static int audioDeviceToRouteInt(String audioDevice) {
if (audioDevice == null) {
return android.telecom.CallAudioState.ROUTE_EARPIECE;
return CallAudioState.ROUTE_SPEAKER;
}
switch (audioDevice) {
case AudioModeModule.DEVICE_BLUETOOTH:
return android.telecom.CallAudioState.ROUTE_BLUETOOTH;
return CallAudioState.ROUTE_BLUETOOTH;
case AudioModeModule.DEVICE_EARPIECE:
return android.telecom.CallAudioState.ROUTE_EARPIECE;
return CallAudioState.ROUTE_EARPIECE;
case AudioModeModule.DEVICE_HEADPHONES:
return android.telecom.CallAudioState.ROUTE_WIRED_HEADSET;
return CallAudioState.ROUTE_WIRED_HEADSET;
case AudioModeModule.DEVICE_SPEAKER:
return android.telecom.CallAudioState.ROUTE_SPEAKER;
return CallAudioState.ROUTE_SPEAKER;
default:
JitsiMeetLogger.e(TAG + " Unsupported device name: " + audioDevice);
return android.telecom.CallAudioState.ROUTE_EARPIECE;
return CallAudioState.ROUTE_SPEAKER;
}
}
@@ -78,20 +79,16 @@ class AudioDeviceHandlerConnectionService implements
*/
private static Set<String> routesToDeviceNames(int supportedRouteMask) {
Set<String> devices = new HashSet<>();
if ((supportedRouteMask & android.telecom.CallAudioState.ROUTE_EARPIECE)
== android.telecom.CallAudioState.ROUTE_EARPIECE) {
if ((supportedRouteMask & CallAudioState.ROUTE_EARPIECE) == CallAudioState.ROUTE_EARPIECE) {
devices.add(AudioModeModule.DEVICE_EARPIECE);
}
if ((supportedRouteMask & android.telecom.CallAudioState.ROUTE_BLUETOOTH)
== android.telecom.CallAudioState.ROUTE_BLUETOOTH) {
if ((supportedRouteMask & CallAudioState.ROUTE_BLUETOOTH) == CallAudioState.ROUTE_BLUETOOTH) {
devices.add(AudioModeModule.DEVICE_BLUETOOTH);
}
if ((supportedRouteMask & android.telecom.CallAudioState.ROUTE_SPEAKER)
== android.telecom.CallAudioState.ROUTE_SPEAKER) {
if ((supportedRouteMask & CallAudioState.ROUTE_SPEAKER) == CallAudioState.ROUTE_SPEAKER) {
devices.add(AudioModeModule.DEVICE_SPEAKER);
}
if ((supportedRouteMask & android.telecom.CallAudioState.ROUTE_WIRED_HEADSET)
== android.telecom.CallAudioState.ROUTE_WIRED_HEADSET) {
if ((supportedRouteMask & CallAudioState.ROUTE_WIRED_HEADSET) == CallAudioState.ROUTE_WIRED_HEADSET) {
devices.add(AudioModeModule.DEVICE_HEADPHONES);
}
return devices;
@@ -109,13 +106,13 @@ class AudioDeviceHandlerConnectionService implements
}
@Override
public void onCallAudioStateChange(final android.telecom.CallAudioState callAudioState) {
public void onCallAudioStateChange(final CallAudioState state) {
module.runInAudioThread(new Runnable() {
@Override
public void run() {
boolean audioRouteChanged
= audioDeviceToRouteInt(module.getSelectedDevice()) != callAudioState.getRoute();
int newSupportedRoutes = callAudioState.getSupportedRouteMask();
= audioDeviceToRouteInt(module.getSelectedDevice()) != state.getRoute();
int newSupportedRoutes = state.getSupportedRouteMask();
boolean audioDevicesChanged = supportedRouteMask != newSupportedRoutes;
if (audioDevicesChanged) {
supportedRouteMask = newSupportedRoutes;
@@ -140,6 +137,8 @@ class AudioDeviceHandlerConnectionService implements
RNConnectionService rcs = ReactInstanceManagerHolder.getNativeModule(RNConnectionService.class);
if (rcs != null) {
rcs.setCallAudioStateListener(this);
} else {
JitsiMeetLogger.w(TAG + " Couldn't set call audio state listener, module is null");
}
}
@@ -148,6 +147,8 @@ class AudioDeviceHandlerConnectionService implements
RNConnectionService rcs = ReactInstanceManagerHolder.getNativeModule(RNConnectionService.class);
if (rcs != null) {
rcs.setCallAudioStateListener(null);
} else {
JitsiMeetLogger.w(TAG + " Couldn't set call audio state listener, module is null");
}
}

View File

@@ -198,11 +198,11 @@ class AudioDeviceHandlerGeneric implements
@Override
public void setAudioRoute(String device) {
// Turn bluetooth on / off
setBluetoothAudioRoute(device.equals(AudioModeModule.DEVICE_BLUETOOTH));
// Turn speaker on / off
audioManager.setSpeakerphoneOn(device.equals(AudioModeModule.DEVICE_SPEAKER));
// Turn bluetooth on / off
setBluetoothAudioRoute(device.equals(AudioModeModule.DEVICE_BLUETOOTH));
}
@Override

View File

@@ -196,11 +196,11 @@ class AudioDeviceHandlerLegacy implements
@Override
public void setAudioRoute(String device) {
// Turn bluetooth on / off
setBluetoothAudioRoute(device.equals(AudioModeModule.DEVICE_BLUETOOTH));
// Turn speaker on / off
audioManager.setSpeakerphoneOn(device.equals(AudioModeModule.DEVICE_SPEAKER));
// Turn bluetooth on / off
setBluetoothAudioRoute(device.equals(AudioModeModule.DEVICE_BLUETOOTH));
}
@Override

View File

@@ -136,8 +136,6 @@ class AudioModeModule extends ReactContextBaseJavaModule {
*/
public AudioModeModule(ReactApplicationContext reactContext) {
super(reactContext);
setAudioDeviceHandler();
}
/**
@@ -193,6 +191,16 @@ class AudioModeModule extends ReactContextBaseJavaModule {
return NAME;
}
/**
* Initializes the audio device handler module. This function is called *after* all Catalyst
* modules have been created, and that's why we use it, because {@link AudioDeviceHandlerConnectionService}
* needs access to another Catalyst module, so doing this in the constructor would be too early.
*/
@Override
public void initialize() {
setAudioDeviceHandler();
}
private void setAudioDeviceHandler() {
if (audioDeviceHandler != null) {
audioDeviceHandler.stop();

View File

@@ -123,14 +123,17 @@ public class ConnectionService extends android.telecom.ConnectionService {
* {@link android.telecom.Connection#STATE_ACTIVE}.
*
* @param callUUID the call UUID which identifies the connection.
* @return Whether the connection was set as active or not.
*/
static void setConnectionActive(String callUUID) {
static boolean setConnectionActive(String callUUID) {
ConnectionImpl connection = connections.get(callUUID);
if (connection != null) {
connection.setActive();
return true;
} else {
JitsiMeetLogger.e("%s setConnectionActive - no connection for UUID: %s", TAG, callUUID);
JitsiMeetLogger.w("%s setConnectionActive - no connection for UUID: %s", TAG, callUUID);
return false;
}
}

View File

@@ -349,7 +349,7 @@ public class JitsiMeetConferenceOptions implements Parcelable {
urlProps.putString("jwt", token);
}
if (token == null && userInfo != null) {
if (userInfo != null) {
props.putBundle("userInfo", userInfo.asBundle());
}

View File

@@ -105,15 +105,22 @@ class RNConnectionService extends ReactContextBaseJavaModule {
ConnectionService.registerStartCallPromise(callUUID, promise);
try {
TelecomManager tm
= (TelecomManager) ctx.getSystemService(
Context.TELECOM_SERVICE);
TelecomManager tm = null;
try {
tm = (TelecomManager) ctx.getSystemService(Context.TELECOM_SERVICE);
tm.placeCall(address, extras);
} catch (Exception e) {
JitsiMeetLogger.e(e, TAG + " error in startCall");
if (tm != null) {
tm.unregisterPhoneAccount(accountHandle);
}
ConnectionService.unregisterStartCallPromise(callUUID);
promise.reject(e);
if (e instanceof SecurityException) {
promise.reject("SECURITY_ERROR", "Required permissions not granted.");
} else {
promise.reject(e);
}
}
}
@@ -151,8 +158,11 @@ class RNConnectionService extends ReactContextBaseJavaModule {
@ReactMethod
public void reportConnectedOutgoingCall(String callUUID, Promise promise) {
JitsiMeetLogger.d(TAG + " reportConnectedOutgoingCall " + callUUID);
ConnectionService.setConnectionActive(callUUID);
promise.resolve(null);
if (ConnectionService.setConnectionActive(callUUID)) {
promise.resolve(null);
} else {
promise.reject("CONNECTION_NOT_FOUND_ERROR", "Connection wasn't found.");
}
}
@Override

0
body.html Normal file
View File

View File

@@ -93,10 +93,15 @@ import {
participantRoleChanged,
participantUpdated
} from './react/features/base/participants';
import { updateSettings } from './react/features/base/settings';
import {
getUserSelectedCameraDeviceId,
updateSettings
} from './react/features/base/settings';
import {
createLocalPresenterTrack,
createLocalTracksF,
destroyLocalTracks,
isLocalVideoTrackMuted,
isLocalTrackMuted,
isUserInteractionRequiredForUnmute,
replaceLocalTrack,
@@ -113,7 +118,9 @@ import {
import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay';
import { suspendDetected } from './react/features/power-monitor';
import { setSharedVideoStatus } from './react/features/shared-video';
import { createPresenterEffect } from './react/features/stream-effects/presenter';
import { endpointMessageReceived } from './react/features/subtitles';
import { createRnnoiseProcessorPromise } from './react/features/rnnoise';
const logger = require('jitsi-meet-logger').getLogger(__filename);
@@ -437,6 +444,11 @@ export default {
*/
localAudio: null,
/**
* The local presenter video track (if any).
*/
localPresenterVideo: null,
/**
* The local video track (if any).
* FIXME tracks from redux store should be the single source of truth, but
@@ -468,14 +480,18 @@ export default {
audioOnlyError,
screenSharingError,
videoOnlyError;
const initialDevices = [];
let requestedAudio = false;
const initialDevices = [ 'audio' ];
const requestedAudio = true;
let requestedVideo = false;
if (!options.startWithAudioMuted) {
initialDevices.push('audio');
requestedAudio = true;
// Always get a handle on the audio input device so that we have statistics even if the user joins the
// conference muted. Previous implementation would only acquire the handle when the user first unmuted,
// which would results in statistics ( such as "No audio input" or "Are you trying to speak?") being available
// only after that point.
if (options.startWithAudioMuted) {
this.muteAudio(true, true);
}
if (!options.startWithVideoMuted
&& !options.startAudioOnly
&& !options.startScreenSharing) {
@@ -722,9 +738,8 @@ export default {
isLocalVideoMuted() {
// If the tracks are not ready, read from base/media state
return this._localTracksInitialized
? isLocalTrackMuted(
APP.store.getState()['features/base/tracks'],
MEDIA_TYPE.VIDEO)
? isLocalVideoTrackMuted(
APP.store.getState()['features/base/tracks'])
: isVideoMutedByUser(APP.store);
},
@@ -798,6 +813,35 @@ export default {
this.muteAudio(!this.isLocalAudioMuted(), showUI);
},
/**
* Simulates toolbar button click for presenter video mute. Used by
* shortcuts and API.
* @param mute true for mute and false for unmute.
* @param {boolean} [showUI] when set to false will not display any error
* dialogs in case of media permissions error.
*/
async mutePresenter(mute, showUI = true) {
const maybeShowErrorDialog = error => {
showUI && APP.store.dispatch(notifyCameraError(error));
};
if (mute) {
try {
await this.localVideo.setEffect(undefined);
} catch (err) {
logger.error('Failed to remove the presenter effect', err);
maybeShowErrorDialog(err);
}
} else {
try {
await this.localVideo.setEffect(await this._createPresenterStreamEffect());
} catch (err) {
logger.error('Failed to apply the presenter effect', err);
maybeShowErrorDialog(err);
}
}
},
/**
* Simulates toolbar button click for video mute. Used by shortcuts and API.
* @param mute true for mute and false for unmute.
@@ -812,6 +856,10 @@ export default {
return;
}
if (this.isSharingScreen) {
return this._mutePresenterVideo(mute);
}
// If not ready to modify track's state yet adjust the base/media
if (!this._localTracksInitialized) {
// This will only modify base/media.video.muted which is then synced
@@ -1205,17 +1253,22 @@ export default {
_getConferenceOptions() {
const options = config;
const { email, name: nick } = getLocalParticipant(APP.store.getState());
const nick = APP.store.getState()['features/base/settings'].displayName;
const { locationURL } = APP.store.getState()['features/base/connection'];
if (nick) {
options.displayName = nick;
if (options.enableDisplayNameInStats && nick) {
options.statisticsDisplayName = nick;
}
if (options.enableEmailInStats && email) {
options.statisticsId = email;
}
options.applicationName = interfaceConfig.APP_NAME;
options.getWiFiStatsMethod = this._getWiFiStatsMethod;
options.confID = `${locationURL.host}${locationURL.pathname}`;
options.createVADProcessor = createRnnoiseProcessorPromise;
return options;
},
@@ -1347,7 +1400,7 @@ export default {
* in case it fails.
* @private
*/
_turnScreenSharingOff(didHaveVideo, wasVideoMuted) {
_turnScreenSharingOff(didHaveVideo) {
this._untoggleScreenSharing = null;
this.videoSwitchInProgress = true;
const { receiver } = APP.remoteControl;
@@ -1365,13 +1418,7 @@ export default {
.then(([ stream ]) => this.useVideoStream(stream))
.then(() => {
sendAnalytics(createScreenSharingEvent('stopped'));
logger.log('Screen sharing stopped, switching to video.');
if (!this.localVideo && wasVideoMuted) {
return Promise.reject('No local video to be muted!');
} else if (wasVideoMuted && this.localVideo) {
return this.localVideo.mute();
}
logger.log('Screen sharing stopped.');
})
.catch(error => {
logger.error('failed to switch back to local video', error);
@@ -1386,6 +1433,16 @@ export default {
promise = this.useVideoStream(null);
}
// mute the presenter track if it exists.
if (this.localPresenterVideo) {
APP.store.dispatch(
setVideoMuted(true, MEDIA_TYPE.PRESENTER));
this.localPresenterVideo.dispose();
APP.store.dispatch(
trackRemoved(this.localPresenterVideo));
this.localPresenterVideo = null;
}
return promise.then(
() => {
this.videoSwitchInProgress = false;
@@ -1411,7 +1468,7 @@ export default {
* 'window', etc.).
* @return {Promise.<T>}
*/
toggleScreenSharing(toggle = !this._untoggleScreenSharing, options = {}) {
async toggleScreenSharing(toggle = !this._untoggleScreenSharing, options = {}) {
if (this.videoSwitchInProgress) {
return Promise.reject('Switch in progress.');
}
@@ -1425,7 +1482,15 @@ export default {
}
if (toggle) {
return this._switchToScreenSharing(options);
try {
await this._switchToScreenSharing(options);
return;
} catch (err) {
logger.error('Failed to switch to screensharing', err);
return;
}
}
return this._untoggleScreenSharing
@@ -1450,8 +1515,7 @@ export default {
_createDesktopTrack(options = {}) {
let externalInstallation = false;
let DSExternalInstallationInProgress = false;
const didHaveVideo = Boolean(this.localVideo);
const wasVideoMuted = this.isLocalVideoMuted();
const didHaveVideo = !this.isLocalVideoMuted();
const getDesktopStreamPromise = options.desktopStream
? Promise.resolve([ options.desktopStream ])
@@ -1502,8 +1566,7 @@ export default {
// Stores the "untoggle" handler which remembers whether was
// there any video before and whether was it muted.
this._untoggleScreenSharing
= this._turnScreenSharingOff
.bind(this, didHaveVideo, wasVideoMuted);
= this._turnScreenSharingOff.bind(this, didHaveVideo);
desktopStream.on(
JitsiTrackEvents.LOCAL_TRACK_STOPPED,
() => {
@@ -1528,6 +1591,95 @@ export default {
});
},
/**
* Creates a new instance of presenter effect. A new video track is created
* using the new set of constraints that are calculated based on
* the height of the desktop that is being currently shared.
*
* @param {number} height - The height of the desktop stream that is being
* currently shared.
* @param {string} cameraDeviceId - The device id of the camera to be used.
* @return {Promise<JitsiStreamPresenterEffect>} - A promise resolved with
* {@link JitsiStreamPresenterEffect} if it succeeds.
*/
async _createPresenterStreamEffect(height = null, cameraDeviceId = null) {
if (!this.localPresenterVideo) {
try {
this.localPresenterVideo = await createLocalPresenterTrack({ cameraDeviceId }, height);
} catch (err) {
logger.error('Failed to create a camera track for presenter', err);
return;
}
APP.store.dispatch(trackAdded(this.localPresenterVideo));
}
try {
const effect = await createPresenterEffect(this.localPresenterVideo.stream);
return effect;
} catch (err) {
logger.error('Failed to create the presenter effect', err);
}
},
/**
* Tries to turn the presenter video track on or off. If a presenter track
* doesn't exist, a new video track is created.
*
* @param mute - true for mute and false for unmute.
*
* @private
*/
async _mutePresenterVideo(mute) {
const maybeShowErrorDialog = error => {
APP.store.dispatch(notifyCameraError(error));
};
if (!this.localPresenterVideo && !mute) {
// create a new presenter track and apply the presenter effect.
let { height } = this.localVideo.track.getSettings();
// Workaround for Firefox since it doesn't return the correct width/height of the desktop stream
// that is being currently shared.
if (!height) {
const desktopResizeConstraints = {
width: 1280,
height: 720,
resizeMode: 'crop-and-scale'
};
try {
await this.localVideo.track.applyConstraints(desktopResizeConstraints);
} catch (err) {
logger.error('Failed to apply constraints on the desktop stream for presenter mode', err);
return;
}
height = desktopResizeConstraints.height;
}
const defaultCamera = getUserSelectedCameraDeviceId(APP.store.getState());
let effect;
try {
effect = await this._createPresenterStreamEffect(height,
defaultCamera);
} catch (err) {
logger.error('Failed to unmute Presenter Video');
maybeShowErrorDialog(err);
return;
}
try {
await this.localVideo.setEffect(effect);
APP.store.dispatch(setVideoMuted(mute, MEDIA_TYPE.PRESENTER));
} catch (err) {
logger.error('Failed to apply the Presenter effect', err);
}
} else {
APP.store.dispatch(setVideoMuted(mute, MEDIA_TYPE.PRESENTER));
}
},
/**
* Tries to switch to the screensharing mode by disposing camera stream and
* replacing it with a desktop one.
@@ -1988,36 +2140,62 @@ export default {
const videoWasMuted = this.isLocalVideoMuted();
sendAnalytics(createDeviceChangedEvent('video', 'input'));
createLocalTracksF({
devices: [ 'video' ],
cameraDeviceId,
micDeviceId: null
})
.then(([ stream ]) => {
// if we are in audio only mode or video was muted before
// changing device, then mute
if (this.isAudioOnly() || videoWasMuted) {
return stream.mute()
.then(() => stream);
}
return stream;
})
.then(stream => {
// if we are screen sharing we do not want to stop it
if (this.isSharingScreen) {
return Promise.resolve();
}
// If both screenshare and video are in progress, restart the
// presenter mode with the new camera device.
if (this.isSharingScreen && !videoWasMuted) {
const { height } = this.localVideo.track.getSettings();
return this.useVideoStream(stream);
})
.then(() => {
// dispose the existing presenter track and create a new
// camera track.
this.localPresenterVideo.dispose();
this.localPresenterVideo = null;
return this._createPresenterStreamEffect(height, cameraDeviceId)
.then(effect => this.localVideo.setEffect(effect))
.then(() => {
this.setVideoMuteStatus(false);
logger.log('switched local video device');
this._updateVideoDeviceId();
})
.catch(err => APP.store.dispatch(notifyCameraError(err)));
// If screenshare is in progress but video is muted, update the default device
// id for video, dispose the existing presenter track and create a new effect
// that can be applied on un-mute.
} else if (this.isSharingScreen && videoWasMuted) {
logger.log('switched local video device');
const { height } = this.localVideo.track.getSettings();
this._updateVideoDeviceId();
})
.catch(err => {
APP.store.dispatch(notifyCameraError(err));
});
this.localPresenterVideo.dispose();
this.localPresenterVideo = null;
this._createPresenterStreamEffect(height, cameraDeviceId);
// if there is only video, switch to the new camera stream.
} else {
createLocalTracksF({
devices: [ 'video' ],
cameraDeviceId,
micDeviceId: null
})
.then(([ stream ]) => {
// if we are in audio only mode or video was muted before
// changing device, then mute
if (this.isAudioOnly() || videoWasMuted) {
return stream.mute()
.then(() => stream);
}
return stream;
})
.then(stream => this.useVideoStream(stream))
.then(() => {
logger.log('switched local video device');
this._updateVideoDeviceId();
})
.catch(err => APP.store.dispatch(notifyCameraError(err)));
}
}
);
@@ -2247,6 +2425,13 @@ export default {
cameraDeviceId: this.localVideo.getDeviceId()
}));
}
// If screenshare is in progress, get the device id from the presenter track.
if (this.localPresenterVideo) {
APP.store.dispatch(updateSettings({
cameraDeviceId: this.localPresenterVideo.getDeviceId()
}));
}
},
/**

View File

@@ -73,6 +73,11 @@ var config = {
// Disable measuring of audio levels.
// disableAudioLevels: false,
// Enabling this will run the lib-jitsi-meet no audio detection module which
// will notify the user if the current selected microphone has no audio
// input and will suggest another valid device if one is present.
// enableNoAudioDetection: false
// Start the conference in audio only mode (no video is being received nor
// sent).
// startAudioOnly: false,
@@ -292,13 +297,11 @@ var config = {
// callStatsID: '',
// callStatsSecret: '',
// enables callstatsUsername to be reported as statsId and used
// by callstats as repoted remote id
// enableStatsID: false
// enables sending participants display name to callstats
// enableDisplayNameInStats: false
// enables sending participants email if available to callstats and other analytics
// enableEmailInStats: false
// Privacy
//

View File

@@ -1,12 +1,23 @@
.avatar {
align-items: center;
background-color: #AAA;
display: flex;
border-radius: 50%;
color: rgba(255, 255, 255, 0.6);
font-weight: 100;
justify-content: center;
object-fit: cover;
&.avatar-small {
height: 28px !important;
width: 28px !important;
}
&.avatar-xsmall {
height: 16px !important;
width: 16px !important;
}
.jitsi-icon {
transform: translateY(50%);
}
}
.avatar-foreign {
@@ -28,4 +39,28 @@
.defaultAvatar {
opacity: 0.6
}
.avatar-badge {
position: relative;
&-available::after {
@include avatarBadge;
background-color: $presence-available;
}
&-away::after {
@include avatarBadge;
background-color: $presence-away;
}
&-busy::after {
@include avatarBadge;
background-color: $presence-busy;
}
&-idle::after {
@include avatarBadge;
background-color: $presence-idle;
}
}

View File

@@ -205,6 +205,10 @@
border-radius: 6px 0px 6px 6px;
}
.usermessage {
white-space: pre-wrap;
}
&.error {
border-radius: 0px;
@@ -226,6 +230,8 @@
.messagecontent {
margin: 5px 10px;
max-width: 100%;
overflow: hidden;
}
}

View File

@@ -192,4 +192,17 @@
*/
@mixin transparentBg($color, $alpha) {
background-color: rgba(red($color), green($color), blue($color), $alpha);
}
}
/**
* Avatar status badge mixin
*/
@mixin avatarBadge {
border-radius: 50%;
content: '';
display: block;
height: 35%;
position: absolute;
bottom: 0;
width: 35%;
}

View File

@@ -0,0 +1,26 @@
.participants-count {
background: #fff;
border-radius: 4px;
color: #5e6d7a;
cursor: pointer;
display: inline-block;
font-size: 13px;
line-height: 20px;
margin-left: 16px;
padding: 4px 8px;
pointer-events: auto;
&-number {
margin-right: 8px;
vertical-align: middle;
}
&-icon {
background: url('../images/user-groups.svg');
background-repeat: no-repeat;
display: inline-block;
height: 16px;
width: 16px;
vertical-align: middle;
}
}

View File

@@ -0,0 +1 @@
/** Insert custom CSS for any additional content in the promotional footer **/

View File

@@ -9,7 +9,7 @@
text-align: center;
font-size: 17px;
color: #fff;
z-index: $toolbarBackgroundZ;
z-index: $zindex10;
overflow: hidden;
text-overflow: ellipsis;
box-sizing: border-box;
@@ -19,4 +19,8 @@
&.visible {
top: 0px;
}
&-text {
vertical-align: middle;
}
}

View File

@@ -29,6 +29,10 @@ $defaultSideBarFontColor: #44A5FF;
$defaultSemiDarkColor: #ACACAC;
$defaultDarkColor: #2b3d5c;
$defaultWarningColor: rgb(215, 121, 118);
$presence-available: rgb(110, 176, 5);
$presence-away: rgb(250, 201, 20);
$presence-busy: rgb(233, 0, 27);
$presence-idle: rgb(172, 172, 172);
/**
* Toolbar
@@ -220,4 +224,39 @@ $welcomePageButtonLineHeight: 35px;
* Deep-linking page variables.
*/
$deepLinkingMobileLogoHeight: 40px;
$deepLinkingMobileHeaderBackground: #f1f2f5;
$deepLinkingMobileLinkColor: inherit;
$deepLinkingMobileTextFontSize: inherit;
$deepLinkingMobileTextLineHeight: inherit;
$deepLinkingDialInConferenceIdMargin: 10px 0 10px 0;
$deepLinkingDialInConferenceIdPadding: inherit;
$deepLinkingDialInConferenceIdBackgroundColor: inherit;
$deepLinkingDialInConferenceIdBorderRadius: inherit;
$deepLinkingDialInConferenceNameFontSize: inherit;
$deepLinkingDialInConferenceNameLineHeight: inherit;
$deepLinkingDialInConferenceNameMarginBottom: none;
$deepLinkingDialInConferenceNameFontWeight: inherit;
$deepLinkingDialInConferenceDescriptionFontSize: 0.8em;
$deepLinkingDialInConferenceDescriptionLineHeight: inherit;
$deepLinkingDialInConferenceDescriptionMarginBottom: none;
$deepLinkingDialInConferencePinFontSize: inherit;
$deepLinkingDialInConferencePinLineHeight: inherit;
$depLinkingMobileHrefLineHeight: 2.2857142857142856em;
$deepLinkingMobileHrefFontWeight: bolder;
$deepLinkingMobileHrefFontSize: inherit;
$deepLinkingMobileButtonHeight: 2.2857142857142856em;
$deepLinkingMobileButtonLineHeight: 2.2857142857142856em;
$deepLinkingMobileButtonMargin: 18px auto 10px;
$deepLinkingMobileButtonWidth: auto;
$deepLinkingMobileButtonFontWeight: bold;
$deepLinkingMobileButtonFontSize: inherit;
$primaryDeepLinkingMobileButtonBorderRadius: inherit;

View File

@@ -489,6 +489,8 @@
height: 300px;
margin: auto;
position: relative;
top: 50%;
transform: translateY(-50%);
}
#mixedstream {

View File

@@ -19,7 +19,8 @@
}
a {
text-decoration: none
text-decoration: none;
color: $deepLinkingMobileLinkColor;
}
&__body {
@@ -41,6 +42,8 @@
&__text {
font-weight: bolder;
font-size: $deepLinkingMobileTextFontSize;
line-height: $deepLinkingMobileTextLineHeight;
padding: 10px 10px 0px 10px;
}
@@ -65,11 +68,28 @@
}
.dial-in-conference-id {
margin: 10px 0 10px 0;
margin: $deepLinkingDialInConferenceIdMargin;
padding: $deepLinkingDialInConferenceIdPadding;
background-color: $deepLinkingDialInConferenceIdBackgroundColor;
border-radius: $deepLinkingDialInConferenceIdBorderRadius;
}
.dial-in-conference-name {
font-size: $deepLinkingDialInConferenceNameFontSize;
line-height: $deepLinkingDialInConferenceNameLineHeight;
margin-bottom: $deepLinkingDialInConferenceNameMarginBottom;
font-weight: $deepLinkingDialInConferenceNameFontWeight;
}
.dial-in-conference-description {
font-size: 0.8em;
font-size: $deepLinkingDialInConferenceDescriptionFontSize;
line-height: $deepLinkingDialInConferenceDescriptionLineHeight;
margin-bottom: $deepLinkingDialInConferenceDescriptionMarginBottom;
}
.dial-in-conference-pin {
font-size: $deepLinkingDialInConferencePinFontSize;
line-height: $deepLinkingDialInConferencePinLineHeight;
}
.toll-free-list {
@@ -88,25 +108,27 @@
&__href {
height: 2.2857142857142856em;
line-height: 2.2857142857142856em;
line-height: $depLinkingMobileHrefLineHeight;
margin: 18px auto 20px;
max-width: 300px;
width: auto;
font-weight: bolder;
font-weight: $deepLinkingMobileHrefFontWeight;
font-size: $deepLinkingMobileHrefFontSize;
}
&__button {
border: 0;
height: 2.2857142857142856em;
line-height: 2.2857142857142856em;
margin: 18px auto 10px;
height: $deepLinkingMobileButtonHeight;
line-height: $deepLinkingMobileButtonLineHeight;
margin: $deepLinkingMobileButtonMargin;
padding: 0px 10px 0px 10px;
max-width: 300px;
width: auto;
width: $deepLinkingMobileButtonWidth;
@include border-radius(3px);
background-color: $unsupportedBrowserButtonBgColor;
color: #505F79;
font-weight: bold;
font-weight: $deepLinkingMobileButtonFontWeight;
font-size: $deepLinkingMobileButtonFontSize;
&:active {
background-color: $unsupportedBrowserButtonBgColor;
@@ -115,7 +137,7 @@
&_primary {
background-color: $primaryUnsupportedBrowserButtonBgColor;
color: #FFFFFF;
border-radius: $primaryDeepLinkingMobileButtonBorderRadius;
&:active {
background-color: $primaryUnsupportedBrowserButtonBgColor;
}

View File

@@ -45,6 +45,7 @@ $flagsImagePath: "../images/";
@import 'videolayout_default';
@import 'notice';
@import 'subject';
@import 'participants-count';
@import 'popup_menu';
@import 'recording';
@import 'login_menu';
@@ -83,5 +84,6 @@ $flagsImagePath: "../images/";
@import 'third-party-branding/google';
@import 'third-party-branding/microsoft';
@import 'avatar';
@import 'promotional-footer';
/* Modules END */

1
debian/control vendored
View File

@@ -37,6 +37,7 @@ Description: Configuration for web serving of Jitsi Meet
Package: jitsi-meet-prosody
Architecture: all
Depends: openssl, prosody | prosody-trunk | prosody-0.11
Replaces: jitsi-meet-tokens
Description: Prosody configuration for Jitsi Meet
Jitsi Meet is a WebRTC JavaScript application that uses Jitsi
Videobridge to provide high quality, scalable video conferences.

View File

@@ -1,2 +1 @@
doc/debian/jitsi-meet-prosody/prosody.cfg.lua-jvb.example
doc/debian/jitsi-meet-prosody/README

2
debian/jitsi-meet-prosody.install vendored Normal file
View File

@@ -0,0 +1,2 @@
doc/debian/jitsi-meet-prosody/prosody.cfg.lua-jvb.example /usr/share/jitsi-meet-prosody/
resources/prosody-plugins/ /usr/share/jitsi-meet/

View File

@@ -93,7 +93,7 @@ case "$1" in
PROSODY_CONFIG_PRESENT="false"
mkdir -p /etc/prosody/conf.avail/
mkdir -p /etc/prosody/conf.d/
cp /usr/share/doc/jitsi-meet-prosody/prosody.cfg.lua-jvb.example $PROSODY_HOST_CONFIG
cp /usr/share/jitsi-meet-prosody/prosody.cfg.lua-jvb.example $PROSODY_HOST_CONFIG
sed -i "s/jitmeet.example.com/$JVB_HOSTNAME/g" $PROSODY_HOST_CONFIG
sed -i "s/jitmeetSecret/$JVB_SECRET/g" $PROSODY_HOST_CONFIG
sed -i "s/focusSecret/$JICOFO_SECRET/g" $PROSODY_HOST_CONFIG
@@ -179,7 +179,7 @@ case "$1" in
fi
if [ "$PROSODY_CONFIG_PRESENT" = "false" ]; then
invoke-rc.d prosody restart
invoke-rc.d prosody restart || true
fi
;;

View File

@@ -1 +0,0 @@
resources/prosody-plugins/ /usr/share/jitsi-meet/

View File

@@ -78,7 +78,7 @@ case "$1" in
fi
if [ -x "/etc/init.d/prosody" ]; then
invoke-rc.d prosody restart
invoke-rc.d prosody restart || true
fi
fi
else

View File

@@ -41,7 +41,7 @@ case "$1" in
sed -i 's/authentication = "token"/authentication = "anonymous"/g' $PROSODY_HOST_CONFIG
sed -i "s/ app_id=\"$APP_ID\"/ --app_id=\"example_app_id\"/g" $PROSODY_HOST_CONFIG
sed -i "s/ app_secret=\"$APP_SECRET\"/ --app_secret=\"example_app_secret\"/g" $PROSODY_HOST_CONFIG
sed -i 's/ modules_enabled = { "token_verification" }/ --modules_enabled = { "token_verification" }/g' $PROSODY_HOST_CONFIG
sed -i 's/ -- "token_verification"/ "token_verification"/g' $PROSODY_HOST_CONFIG
if [ -x "/etc/init.d/prosody" ]; then
invoke-rc.d prosody restart

View File

@@ -1,4 +1 @@
doc/debian/jitsi-meet/jitsi-meet.example
doc/debian/jitsi-meet/jitsi-meet.example-apache
doc/debian/jitsi-meet/README
config.js

3
debian/jitsi-meet-web-config.install vendored Normal file
View File

@@ -0,0 +1,3 @@
doc/debian/jitsi-meet/jitsi-meet.example /usr/share/jitsi-meet-web-config/
doc/debian/jitsi-meet/jitsi-meet.example-apache /usr/share/jitsi-meet-web-config/
config.js /usr/share/jitsi-meet-web-config/

View File

@@ -98,7 +98,9 @@ case "$1" in
# jitsi meet
JITSI_MEET_CONFIG="/etc/jitsi/meet/$JVB_HOSTNAME-config.js"
if [ ! -f $JITSI_MEET_CONFIG ] ; then
cp /usr/share/doc/jitsi-meet-web-config/config.js $JITSI_MEET_CONFIG
cp /usr/share/jitsi-meet-web-config/config.js $JITSI_MEET_CONFIG
# replaces needed config for multidomain as it works only with nginx
sed -i "s/conference.jitsi-meet.example.com/conference.<\!--# echo var=\"subdomain\" default=\"\" -->jitsi-meet.example.com/g" $JITSI_MEET_CONFIG
sed -i "s/jitsi-meet.example.com/$JVB_HOSTNAME/g" $JITSI_MEET_CONFIG
fi
@@ -167,7 +169,7 @@ case "$1" in
db_set jitsi-meet/jvb-serve "true"
invoke-rc.d jitsi-videobridge restart
invoke-rc.d jitsi-videobridge restart || true
elif [[ "$FORCE_NGINX" = "true" && ( -z "$JVB_HOSTNAME_OLD" || "$RECONFIGURING" = "true" ) ]] ; then
# this is a reconfigure, lets just delete old links
if [ "$RECONFIGURING" = "true" ] ; then
@@ -177,7 +179,7 @@ case "$1" in
# nginx conf
if [ ! -f /etc/nginx/sites-available/$JVB_HOSTNAME.conf ] ; then
cp /usr/share/doc/jitsi-meet-web-config/jitsi-meet.example /etc/nginx/sites-available/$JVB_HOSTNAME.conf
cp /usr/share/jitsi-meet-web-config/jitsi-meet.example /etc/nginx/sites-available/$JVB_HOSTNAME.conf
if [ ! -f /etc/nginx/sites-enabled/$JVB_HOSTNAME.conf ] ; then
ln -s /etc/nginx/sites-available/$JVB_HOSTNAME.conf /etc/nginx/sites-enabled/$JVB_HOSTNAME.conf
fi
@@ -196,7 +198,7 @@ case "$1" in
/etc/nginx/sites-available/$JVB_HOSTNAME.conf
fi
invoke-rc.d nginx reload
invoke-rc.d nginx reload || true
elif [[ "$FORCE_APACHE" = "true" && ( -z "$JVB_HOSTNAME_OLD" || "$RECONFIGURING" = "true" ) ]] ; then
# this is a reconfigure, lets just delete old links
if [ "$RECONFIGURING" = "true" ] ; then
@@ -208,7 +210,7 @@ case "$1" in
if [ ! -f /etc/apache2/sites-available/$JVB_HOSTNAME.conf ] ; then
# when creating new config, make sure all needed modules are enabled
a2enmod rewrite ssl headers proxy_http include
cp /usr/share/doc/jitsi-meet-web-config/jitsi-meet.example-apache /etc/apache2/sites-available/$JVB_HOSTNAME.conf
cp /usr/share/jitsi-meet-web-config/jitsi-meet.example-apache /etc/apache2/sites-available/$JVB_HOSTNAME.conf
a2ensite $JVB_HOSTNAME.conf
sed -i "s/jitsi-meet.example.com/$JVB_HOSTNAME/g" /etc/apache2/sites-available/$JVB_HOSTNAME.conf
fi
@@ -225,7 +227,7 @@ case "$1" in
/etc/apache2/sites-available/$JVB_HOSTNAME.conf
fi
invoke-rc.d apache2 reload
invoke-rc.d apache2 reload || true
fi
echo "----------------"

2
debian/rules vendored
View File

@@ -14,7 +14,7 @@ override_dh_auto_build:
override_dh_install: $(LANGUAGES)
dh_installdirs
dh_install -X/config.js -X/package.json
dh_install
$(LANGUAGES):
LOCALE=$$(echo $@ | cut -c1-2) ; \

View File

@@ -30,6 +30,7 @@ Its constructor gets a number of options:
* **onload**: (optional) handler for the iframe onload event.
* **invitees**: (optional) Array of objects containing information about new participants that will be invited in the call.
* **devices**: (optional) A map containing information about the initial devices that will be used in the call.
* **userInfo**: (optional) JS object containing information about the participant opening the meeting, such as `email`.
Example:
@@ -84,6 +85,19 @@ const options = {
const api = new JitsiMeetExternalAPI(domain, options);
```
You can set the userInfo(email) for the call:
```javascript
var domain = "meet.jit.si";
var options = {
...
userInfo: {
email: 'email@jitsiexamplemail.com'
}
}
var api = new JitsiMeetExternalAPI(domain, options);
```
### Controlling the embedded Jitsi Meet Conference
Device management `JitsiMeetExternalAPI` methods:

View File

@@ -1,5 +1,7 @@
-- Plugins path gets uncommented during jitsi-meet-tokens package install - that's where token plugin is located
--plugin_paths = { "/usr/share/jitsi-meet/prosody-plugins/" }
plugin_paths = { "/usr/share/jitsi-meet/prosody-plugins/" }
-- domain mapper options, must at least have domain base set to use the mapper
muc_mapper_domain_base = "jitmeet.example.com";
VirtualHost "jitmeet.example.com"
-- enabled = false -- Remove this line to enable this host
@@ -16,18 +18,23 @@ VirtualHost "jitmeet.example.com"
key = "/etc/prosody/certs/jitmeet.example.com.key";
certificate = "/etc/prosody/certs/jitmeet.example.com.crt";
}
speakerstats_component = "speakerstats.jitmeet.example.com"
-- we need bosh
modules_enabled = {
"bosh";
"pubsub";
"ping"; -- Enable mod_ping
"speakerstats";
}
c2s_require_encryption = false
Component "conference.jitmeet.example.com" "muc"
storage = "null"
--modules_enabled = { "token_verification" }
modules_enabled = {
"muc_meeting_id";
"muc_domain_mapper";
-- "token_verification";
}
admins = { "focusUser@auth.jitmeet.example.com" }
Component "jitsi-videobridge.jitmeet.example.com"
@@ -38,3 +45,6 @@ VirtualHost "auth.jitmeet.example.com"
Component "focus.jitmeet.example.com"
component_secret = "focusSecret"
Component "speakerstats.jitmeet.example.com" "speakerstats_component"
muc_component = "conference.jitmeet.example.com"

View File

@@ -19,7 +19,11 @@ server {
ssl_certificate_key /etc/jitsi/meet/jitsi-meet.example.com.key;
root /usr/share/jitsi-meet;
# ssi on with javascript for multidomain variables in config.js
ssi on;
ssi_types application/x-javascript application/javascript;
index index.html index.htm;
error_page 404 /static/404.html;
@@ -45,11 +49,35 @@ server {
proxy_set_header Host $http_host;
}
location ~ ^/([^?&:’“]+)$ {
location ~ ^/([^/?&:'"]+)$ {
try_files $uri @root_path;
}
location @root_path {
rewrite ^/(.*)$ / break;
}
location ~ ^/([^/?&:'"]+)/config.js$
{
set $subdomain "$1.";
set $subdir "$1/";
alias /etc/jitsi/meet/jitsi-meet.example.com-config.js;
}
#Anything that didn't match above, and isn't a real file, assume it's a room name and redirect to /
location ~ ^/([^/?&:'"]+)/(.*)$ {
set $subdomain "$1.";
set $subdir "$1/";
rewrite ^/([^/?&:'"]+)/(.*)$ /$2;
}
# BOSH for subdomains
location ~ ^/([^/?&:'"]+)/http-bind {
set $subdomain "$1.";
set $subdir "$1/";
set $prefix "$1";
rewrite ^/(.*)$ /http-bind;
}
}

View File

@@ -36,10 +36,6 @@ server {
rewrite ^/(.*)$ / break;
}
location / {
ssi on;
}
location ~ ^/([^/?&:'"]+)/config.js$
{
set $subdomain "$1.";
@@ -64,4 +60,4 @@ server {
rewrite ^/(.*)$ /http-bind;
}
}
}

View File

@@ -83,8 +83,6 @@ modules_enabled = {
"adhoc";
"websocket";
"http_altconnect";
-- include domain mapper as global level module
"muc_domain_mapper";
}
-- domain mapper options, must at least have domain base set to use the mapper

View File

@@ -210,6 +210,7 @@ Checkout and configure Jitsi Meet:
cd /srv
git clone https://github.com/jitsi/jitsi-meet.git
mv jitsi-meet/ jitsi.example.com
cd jitsi.example.com
npm install
make
```

0
head.html Normal file
View File

BIN
images/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="324px" height="63.8px" viewBox="0 0 324 63.8" style="enable-background:new 0 0 324 63.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:#0061FF;}
.st1{display:none;}
.st2{display:inline;}
.st3{fill:none;}
</style>
<path class="st0" d="M37.6,12L18.8,24l18.8,12L18.8,48L0,35.9l18.8-12L0,12L18.8,0L37.6,12z M18.7,51.8l18.8-12l18.8,12l-18.8,12
L18.7,51.8z M37.6,35.9l18.8-12L37.6,12L56.3,0l18.8,12L56.3,24l18.8,12L56.3,48L37.6,35.9z"/>
<path d="M89.8,12H105c9.7,0,17.7,5.6,17.7,18.4v2.7c0,12.9-7.5,18.7-17.4,18.7H89.8V12z M98.3,19.2v25.3h6.5c5.5,0,9.2-3.6,9.2-11.6
v-2.1c0-8-3.9-11.6-9.5-11.6H98.3z M127.2,19.6h6.8l1.1,7.5c1.3-5.1,4.6-7.8,10.6-7.8h2.1v8.6h-3.5c-6.9,0-8.6,2.4-8.6,9.2v14.8
h-8.4V19.6H127.2z M149.5,36.4v-0.9c0-10.8,6.9-16.7,16.3-16.7c9.6,0,16.3,5.9,16.3,16.7v0.9c0,10.6-6.5,16.3-16.3,16.3
C155.4,52.6,149.5,47,149.5,36.4z M173.5,36.3v-0.8c0-6-3-9.6-7.8-9.6c-4.7,0-7.8,3.3-7.8,9.6v0.8c0,5.8,3,9.1,7.8,9.1
C170.5,45.3,173.5,42.1,173.5,36.3z M186.5,19.6h7l0.8,6.1c1.7-4.1,5.3-6.9,10.6-6.9c8.2,0,13.6,5.9,13.6,16.8v0.9
c0,10.6-6,16.2-13.6,16.2c-5.1,0-8.6-2.3-10.3-6V63h-8.2L186.5,19.6L186.5,19.6z M210,36.3v-0.7c0-6.4-3.3-9.6-7.7-9.6
c-4.7,0-7.8,3.6-7.8,9.6v0.6c0,5.7,3,9.3,7.7,9.3C207,45.4,210,42.3,210,36.3z M230.9,45.9l-0.7,5.9H223v-43h8.2v16.5
c1.8-4.2,5.4-6.5,10.5-6.5c7.7,0.1,13.4,5.4,13.4,16.1v1c0,10.7-5.4,16.8-13.6,16.8C236.1,52.6,232.6,50.1,230.9,45.9z M246.5,35.9
v-0.8c0-5.9-3.2-9.2-7.7-9.2c-4.6,0-7.8,3.7-7.8,9.3v0.7c0,6,3.1,9.5,7.7,9.5C243.6,45.4,246.5,42.3,246.5,35.9z M258.7,36.4v-0.9
c0-10.8,6.9-16.7,16.3-16.7c9.6,0,16.3,5.9,16.3,16.7v0.9c0,10.6-6.6,16.3-16.3,16.3C264.6,52.6,258.7,47,258.7,36.4z M282.8,36.3
v-0.8c0-6-3-9.6-7.8-9.6c-4.7,0-7.8,3.3-7.8,9.6v0.8c0,5.8,3,9.1,7.8,9.1C279.8,45.3,282.8,42.1,282.8,36.3z M302.3,35.1L291,19.6
h9.7l6.5,9.7l6.6-9.7h9.6L311.9,35L324,51.8h-9.5l-7.4-10.7l-7.2,10.7H290L302.3,35.1z"/>
<g id="Editble" class="st1">
<g class="st2">
<rect x="-105" y="5" class="st3" width="506" height="71.8"/>
<path d="M0.2,13.6h16.3c10.4,0,19,6.1,19,19.8v2.9c0,13.8-8,20-18.7,20H0.2V13.6z M9.4,21.3v27.2h7c5.9,0,9.9-3.9,9.9-12.5v-2.2
c0-8.6-4.1-12.5-10.2-12.5H9.4z M40.4,21.8h7.3l1.1,8c1.4-5.5,4.9-8.3,11.3-8.3h2.2v9.2h-3.7c-7.4,0-9.2,2.6-9.2,9.9v15.8h-9
C40.4,56.4,40.4,21.8,40.4,21.8z M64.3,39.8v-1c0-11.6,7.4-17.9,17.5-17.9c10.3,0,17.5,6.4,17.5,17.9v1c0,11.4-7,17.5-17.5,17.5
C70.6,57.3,64.3,51.2,64.3,39.8z M90.1,39.7v-0.8c0-6.5-3.2-10.3-8.3-10.3c-5,0-8.4,3.5-8.4,10.3v0.8c0,6.2,3.2,9.7,8.3,9.7
C86.9,49.4,90.1,46,90.1,39.7z M104,21.8h7.6l0.9,6.6c1.9-4.4,5.7-7.4,11.4-7.4c8.8,0,14.6,6.4,14.6,18v1
c0,11.4-6.4,17.3-14.6,17.3c-5.5,0-9.2-2.5-11-6.5v17.5H104V21.8z M129.3,39.8V39c0-6.9-3.5-10.3-8.3-10.3c-5,0-8.4,3.8-8.4,10.3
v0.7c0,6.1,3.2,10,8.2,10C126,49.5,129.3,46.1,129.3,39.8z M151.7,50.1l-0.7,6.3h-7.8V10.2h8.8V28c1.9-4.5,5.8-7,11.2-7
c8.2,0.1,14.3,5.8,14.3,17.3v1c0,11.5-5.8,18-14.6,18C157.3,57.3,153.5,54.5,151.7,50.1z M168.5,39.3v-0.8c0-6.4-3.5-9.8-8.3-9.8
c-5,0-8.4,4-8.4,10v0.7c0,6.5,3.3,10.2,8.3,10.2C165.3,49.5,168.5,46.1,168.5,39.3z M181.6,39.8v-1c0-11.6,7.4-17.9,17.5-17.9
c10.3,0,17.5,6.4,17.5,17.9v1c0,11.4-7.1,17.5-17.5,17.5C187.9,57.3,181.6,51.2,181.6,39.8z M207.4,39.7v-0.8
c0-6.5-3.2-10.3-8.3-10.3c-5,0-8.4,3.5-8.4,10.3v0.8c0,6.2,3.2,9.7,8.3,9.7C204.2,49.4,207.4,46,207.4,39.7z M228.3,38.4
l-12.1-16.7h10.4l7,10.4l7.1-10.4H251l-12.3,16.6l13,18h-10.2l-8-11.5l-7.7,11.5h-10.6L228.3,38.4z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

0
images/dropboxLogo_square.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -1,182 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg3526"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:export-filename="/Users/ystamcheva/Dropbox/Designs/appLogo.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
sodipodi:docname="logo-blue.svg">
<defs
id="defs3528" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.49497475"
inkscape:cx="817.30793"
inkscape:cy="496.00851"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1440"
inkscape:window-height="851"
inkscape:window-x="0"
inkscape:window-y="1"
inkscape:window-maximized="1" />
<metadata
id="metadata3531">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g4181">
<g
style="fill:#17a0db;fill-opacity:1"
transform="translate(43.272677,-6.8248629)"
id="g33">
<path
d="m 257.311,591.057 c 27.544,0 85.707,-16.445 124.179,-27.332 5.595,-1.575 10.81,-3.049 15.549,-4.371 0.767,-0.211 1.51,-0.403 2.213,-0.579 -2.161,-2.139 -5.755,-5.387 -11.612,-10.295 -25.628,-17.369 -49.827,-25.456 -76.146,-25.456 -5.741,0 -11.707,0.352 -18.208,1.088 -22.283,2.535 -40.848,7.845 -49.767,10.39 -4.521,1.296 -5.883,1.683 -7.292,1.683 -2.688,0 -4.997,-1.599 -5.9,-4.069 -0.904,-2.483 -0.13,-5.223 1.969,-6.981 l 0.127,-0.102 c 15.379,-12.883 44.032,-36.866 98.39,-47.582 9.428,-1.853 19.514,-2.796 29.968,-2.796 24.334,0 49.53,5.026 74.869,14.925 34.511,13.474 58.094,30.771 77.062,44.67 10.211,7.489 19.03,13.959 26.705,17.516 1.961,0.912 2.979,1.169 3.453,1.236 0.349,-0.452 1.106,-1.7 2.219,-4.974 0.298,-0.867 2.453,-10.019 -13.007,-62.071 -8.985,-30.217 -19.822,-61.077 -25.465,-74.778 -10.916,-26.509 -8.237,-45.296 -4.877,-56.284 -9.248,3.399 -18.701,8.688 -28.646,15.993 l -0.62,0.458 c -4.969,3.684 -10.031,7.853 -15.482,12.725 -32.074,28.718 -56.104,43.69 -71.455,44.504 l -0.423,0.021 -0.421,-0.036 c -13.524,-1.148 -34.019,-20.834 -42.403,-30.801 -1.743,-1.169 -3.729,-1.699 -6.35,-1.699 -2.632,0 -5.583,0.553 -8.438,1.095 -2.077,0.394 -4.218,0.795 -6.341,1.01 -6.767,0.679 -16.252,2.867 -25.406,4.974 -4.413,1.014 -8.967,2.063 -13.13,2.922 -0.079,0.013 -1.866,0.382 -5.06,1.224 -22.624,6.693 -39.673,14.372 -48.012,21.628 -0.091,0.079 -0.36,0.288 -0.789,0.603 -5.64,4.009 -19.199,15.447 -23.29,34.907 l -0.043,0.162 c -8.541,35.837 4.408,80.28 21.615,105.666 8.093,11.932 16.814,19.376 23.944,20.42 1.775,0.252 3.905,0.386 6.321,0.386 z"
id="path35"
inkscape:connector-curvature="0"
style="fill:#17a0db;fill-opacity:1" />
</g>
<g
style="fill:#17a0db;fill-opacity:1"
transform="translate(43.272677,-6.8248629)"
id="g37">
<path
d="m 383.729,400.995 c 0.549,0.108 1.191,0.162 1.9,0.162 14.785,0 47.804,-21.408 53.912,-31.205 l 0.486,-0.78 0.694,-0.611 c 2.083,-2.056 8.099,-12.885 11.019,-19.367 -31.312,-9.394 -34.767,-26.347 -37.821,-41.41 -0.355,-1.749 -0.667,-3.324 -0.946,-4.732 -0.357,-1.842 -0.731,-3.713 -1.052,-5.159 -46.646,15.471 -60.905,24.154 -68.687,30.611 -4.027,3.345 -6.398,12.858 5.215,39.189 5.932,13.422 26.386,31.591 35.28,33.302 z"
id="path39"
inkscape:connector-curvature="0"
style="fill:#17a0db;fill-opacity:1" />
</g>
<path
style="fill:#17a0db;fill-opacity:1"
inkscape:connector-curvature="0"
id="path43"
d="m 183.03568,710.19014 c -5.799,-6.834 -8.258,-15.447 -7.293,-25.624 4.105,-49.397 -1.525,-61.33 -4.132,-64.162 -0.629,-0.685 -0.969,-0.685 -1.238,-0.685 -0.101,0 -0.195,0.006 -0.296,0.016 -4.84,1.157 -37.441,23.198 -44.638,89.005 -3.471,31.758 2.611,72.542 7.794,97.348 4.165,-14.646 10.742,-30.779 23.483,-47.384 11.862,-15.444 24.801,-27.623 40.852,-38.298 -4.99,-2.075 -10.346,-5.274 -14.532,-10.216 z" />
<g
style="fill:#17a0db;fill-opacity:1"
transform="translate(43.272677,-6.8248629)"
id="g45">
<path
d="m 485.028,154.141 c -3.896,25.701 -10.239,50.115 -22.077,75.883 12.904,-14.609 20.445,-30.481 22.971,-48.296 1.051,-7.38 2.045,-14.439 -0.894,-27.587 z"
id="path47"
inkscape:connector-curvature="0"
style="fill:#17a0db;fill-opacity:1" />
</g>
<g
style="fill:#17a0db;fill-opacity:1"
transform="translate(43.272677,-6.8248629)"
id="g49">
<path
d="m 413.102,273.797 c 23.135,-20.915 37.22,-55.455 43.078,-75.971 -20.149,19.407 -44.636,29.82 -60.351,36.512 -5.412,2.308 -10.08,4.295 -12.878,5.926 -1.178,0.685 -2.367,1.374 -3.571,2.069 -9.533,5.515 -23.924,13.85 -26.022,18.987 l -0.06,0.167 -0.078,0.165 c -6.529,13.72 -10.208,34.352 -11.387,46.184 15.135,-9.242 30.738,-15.41 43.699,-20.529 12.03,-4.753 22.432,-8.863 27.57,-13.51 z"
id="path51"
inkscape:connector-curvature="0"
style="fill:#17a0db;fill-opacity:1" />
</g>
<g
style="fill:#17a0db;fill-opacity:1"
transform="translate(43.272677,-6.8248629)"
id="g53">
<path
d="m 436.439,291.877 c -0.141,0.357 -0.292,0.695 -0.455,1.017 -3.833,11.143 1.446,26.3 11.227,32.017 2.602,1.522 5.132,2.452 7.559,2.772 0.334,0.014 0.666,0.027 1.001,0.027 7.601,0 13.801,-5.56 18.4,-16.519 2.896,-8.34 3.308,-18.23 1.125,-27.158 -1.696,-6.936 -6.084,-15.215 -8.88,-19.343 -5.219,3.582 -15.533,11.462 -22.615,17.716 -4.946,4.777 -6.733,7.785 -7.362,9.471 z"
id="path55"
inkscape:connector-curvature="0"
style="fill:#17a0db;fill-opacity:1" />
</g>
<g
style="fill:#17a0db;fill-opacity:1"
transform="translate(43.272677,-6.8248629)"
id="g57">
<path
d="m 501.845,575.103 c 8.403,-2.29 15.076,-4.165 19.998,-5.623 -10.137,-7.061 -21.871,-15.846 -37.823,-28.253 -39.096,-30.404 -81.019,-45.826 -124.587,-45.826 -23.861,0 -44.647,4.592 -61.098,10.151 4.101,-0.255 8.271,-0.377 12.554,-0.377 5.088,0 10.42,0.179 15.842,0.541 16.949,1.136 60.616,8.845 100.106,55.931 7.956,9.469 16.507,17.307 40.828,17.307 8.679,0 18.796,-0.967 30.913,-2.959 0.749,-0.209 1.882,-0.518 3.267,-0.892 z"
id="path59"
inkscape:connector-curvature="0"
style="fill:#17a0db;fill-opacity:1" />
</g>
<g
style="fill:#17a0db;fill-opacity:1"
transform="translate(43.272677,-6.8248629)"
id="g61">
<path
d="m 557.268,369.949 c -7.755,-12.043 -17.498,-19.524 -25.41,-19.524 -1.464,0 -2.862,0.258 -4.154,0.765 -4.239,1.672 -10.952,21.042 -7.979,35.126 2.023,9.582 13.67,41.96 19.262,57.52 2.142,5.958 3.18,8.869 3.527,9.951 0.275,0.853 0.67,2.077 1.17,3.621 4.517,13.765 16.111,49.145 19.562,77.793 7.175,-30.554 11.239,-67.36 9.647,-111.409 -0.723,-20.199 -6.274,-39.323 -15.625,-53.843 z"
id="path63"
inkscape:connector-curvature="0"
style="fill:#17a0db;fill-opacity:1" />
</g>
<g
style="fill:#17a0db;fill-opacity:1"
transform="translate(43.272677,-6.8248629)"
id="g65">
<path
d="m 412.08,575.289 c -0.153,-0.2 -0.3,-0.397 -0.445,-0.585 -0.614,0.1 -1.616,0.319 -3.185,0.776 l -0.657,0.197 c -8.011,2.95 -22.707,7.908 -39.694,13.64 -20.387,6.87 -43.477,14.659 -62.808,21.595 -24.596,9.165 -32.572,12.781 -35.073,14.048 -0.454,1.218 -0.963,2.772 -1.53,4.486 -5.817,17.705 -19.139,58.23 -84.831,86.562 13.568,13.744 43.101,38.415 101.24,38.415 5.035,0 10.258,-0.188 15.494,-0.566 43.896,-3.121 85.158,-22.544 116.206,-54.673 28.233,-29.21 44.259,-65.641 44.507,-100.76 -6.871,-0.571 -18.519,-2.281 -29.301,-7.4 -0.125,-0.061 -12.447,-6.002 -19.923,-15.735 z"
id="path67"
inkscape:connector-curvature="0"
style="fill:#17a0db;fill-opacity:1" />
</g>
<g
style="fill:#17a0db;fill-opacity:1"
transform="translate(43.272677,-6.8248629)"
id="g69">
<path
d="m 162.104,639.109 c -0.122,10.334 -1.489,20.245 -2.82,29.907 -0.716,5.216 -1.464,10.615 -2.014,16.041 -0.746,10.914 1.612,14.717 2.659,15.829 0.571,0.629 1.513,1.346 3.536,1.346 1.558,0 3.418,-0.432 5.383,-1.251 19.507,-8.176 38.032,-22.367 46.937,-30.243 -13.668,-6.095 -34.689,-19.26 -53.681,-31.629 z"
id="path71"
inkscape:connector-curvature="0"
style="fill:#17a0db;fill-opacity:1" />
</g>
<g
style="fill:#17a0db;fill-opacity:1"
transform="translate(43.272677,-6.8248629)"
id="g73">
<path
d="m 484.26,598.224 c -0.552,7.258 -1.737,20.949 -3.631,31.378 -2.295,12.629 -6.095,23.31 -8.305,28.889 3.945,3.648 7.878,7.228 10.429,9.488 10.265,-6.718 43.961,-32.297 67.208,-90.368 -7.447,5.03 -17.906,9.456 -31.465,13.332 -13.797,3.929 -27.204,6.229 -34.236,7.281 z"
id="path75"
inkscape:connector-curvature="0"
style="fill:#17a0db;fill-opacity:1" />
</g>
<g
transform="translate(43.272677,-6.8248629)"
id="g85"
style="fill:#17a0db;fill-opacity:1">
<path
style="fill:#17a0db;fill-opacity:1"
inkscape:connector-curvature="0"
id="path87"
d="M 627.562,350.519 C 613.5,321.124 593.893,306.283 580.351,297.677 568.965,290.444 555.872,285.188 541.339,282 c -1.622,-10.158 -4.397,-20.542 -8.198,-30.646 24.507,-36.531 30.407,-77.605 17.008,-119.213 C 539.858,100.151 531.868,79.524 524.996,67.213 510.15,40.585 489.58,34.997 474.936,34.997 c -15.09,0 -29.538,6.412 -39.667,17.61 -10.37,11.462 -15.213,26.462 -13.634,42.228 1.349,13.446 -2.178,37.872 -4.519,46.594 -0.04,0.117 -4.202,11.776 -35.168,26.784 -0.746,0.268 -2.332,0.811 -4.773,1.629 -17.812,5.965 -50.913,17.062 -72.963,46.219 -16.847,20.407 -20.985,40.629 -25.766,64.036 -2.858,13.955 -5.846,32.187 -5.105,53.745 -55.35,12.291 -95.226,37.338 -118.609,74.54 -24.203,38.52 -28.402,86.272 -12.468,141.993 l 0.14,0.414 c 0.292,1.014 0.6,2.024 0.921,3.03 -2.718,-0.466 -5.465,-0.858 -8.285,-1.169 -2.469,-0.284 -5.015,-0.42 -7.54,-0.42 -27.636,0 -57.043,17.371 -78.666,46.474 -16.427,22.098 -36.156,61.131 -36.852,121.593 -0.523,44.905 4.279,86.306 14.283,123.054 7.461,27.381 15.784,44.202 18.979,50.09 l 67.793,127.079 31.06,-140.731 c 10.6,-47.935 21.066,-68.283 34.571,-81.732 31.425,18.938 68.541,28.901 107.941,28.901 43.919,0 89.715,-12.667 128.934,-35.662 25.477,-14.954 47.193,-33.324 64.629,-54.658 0.236,0 0.469,0 0.704,0 l 1.857,-0.038 c 10.782,-0.365 25.522,-5.697 40.434,-14.63 12.421,-7.433 31.147,-21.108 49.946,-44.064 18.945,-23.155 34.402,-51.324 45.926,-83.731 13.5,-37.939 21.717,-82.115 24.404,-131.272 3.253,-45.723 -2.078,-83.533 -15.881,-112.384 z m -31.124,109.427 c -2.415,44.805 -9.745,84.66 -21.764,118.441 -9.713,27.302 -22.502,50.739 -38.005,69.69 -26.696,32.611 -52.783,41.355 -55.551,41.465 l -0.22,0 c -2.528,0 -4.012,-1.032 -11.095,-5.988 -1.979,-1.379 -4.969,-3.467 -7.436,-5.075 -14.813,28.811 -39.145,53.701 -70.659,72.185 -32.098,18.824 -69.432,29.202 -105.1,29.202 -42.352,0 -79.532,-13.979 -107.842,-40.493 -38.621,24.556 -61.833,45.044 -80.652,130.273 l -3.562,16.157 -7.787,-14.59 C 84.8,867.621 78.058,854.32 71.708,830.982 62.852,798.444 58.598,761.384 59.071,720.842 c 0.944,-80.909 44.373,-121.518 68.427,-121.518 0.792,0 1.578,0.039 2.328,0.128 22.8,2.551 37.699,12.402 64.745,30.291 2.796,1.853 5.74,3.8 8.843,5.838 9.69,6.36 23.387,14.125 26.835,14.791 6.562,-0.381 12.986,-15.079 14.853,-28.713 0.114,-0.829 0.226,-1.598 0.334,-2.315 0.147,-1.612 0.227,-3.03 0.27,-4.194 -1.144,-0.399 -2.333,-0.869 -3.547,-1.403 l -0.27,-0.091 c -17.012,-5.857 -41.868,-34.625 -54.378,-76.385 -12.081,-42.21 -9.691,-77.122 7.099,-103.83 27.221,-43.328 86.307,-53.515 105.849,-56.861 6.109,-1.214 12.498,-2.351 18.999,-3.378 3.035,-0.762 5.11,-1.399 6.449,-1.978 0.58,-0.403 0.835,-0.833 0.439,-2.403 l 0.53,-0.148 -0.513,0.115 c -0.237,-1.065 -0.565,-2.311 -0.941,-3.753 -0.521,-1.997 -1.103,-4.256 -1.705,-6.936 -6.05,-27.141 -2.962,-49.884 0.863,-68.559 4.297,-21.019 6.678,-32.656 16.605,-44.279 13.152,-18.103 36.803,-26.025 50.953,-30.77 3.948,-1.322 7.359,-2.462 9.331,-3.412 43.344,-20.789 57.145,-42.646 61.091,-57.318 3.127,-11.642 8.084,-42.253 5.931,-63.63 -0.239,-2.425 0.326,-4.421 1.695,-5.935 1.215,-1.341 2.942,-2.104 4.748,-2.104 4.061,0 9.623,0 30.377,64.478 10.949,33.996 2.785,65.868 -24.244,94.74 -0.347,0.375 -0.7,0.742 -1.04,1.095 -0.738,0.76 -1.848,1.909 -1.999,2.326 0.006,0 -0.048,1.042 1.755,4.031 11.425,18.864 17.633,42.323 15.832,59.763 -0.429,4.062 -1.206,7.971 -1.879,11.411 -0.4,1.968 -0.879,4.377 -1.126,6.241 0.111,0 0.226,0 0.347,0 3.088,-0.327 7.867,-0.7 13.628,-0.7 13.556,0 32.969,2.077 48.503,11.951 9.382,5.952 21.255,15.137 29.981,33.404 10.281,21.472 14.096,51.453 11.369,89.114 z" />
</g>
</g>
<path
style="fill:#ffffff"
d=""
id="path3618"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width='20px' height='20px' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="uil-spin"><rect x="0" y="0" width="100" height="100" fill="none" class="bk"></rect><g transform="translate(50 50)"><g transform="rotate(0) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#ffffff"><animate attributeName="opacity" from="1" to="0.1" begin="0s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g><g transform="rotate(45) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#ffffff"><animate attributeName="opacity" from="1" to="0.1" begin="0.12s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0.12s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g><g transform="rotate(90) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#ffffff"><animate attributeName="opacity" from="1" to="0.1" begin="0.25s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0.25s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g><g transform="rotate(135) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#ffffff"><animate attributeName="opacity" from="1" to="0.1" begin="0.37s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0.37s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g><g transform="rotate(180) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#ffffff"><animate attributeName="opacity" from="1" to="0.1" begin="0.5s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0.5s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g><g transform="rotate(225) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#ffffff"><animate attributeName="opacity" from="1" to="0.1" begin="0.62s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0.62s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g><g transform="rotate(270) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#ffffff"><animate attributeName="opacity" from="1" to="0.1" begin="0.75s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0.75s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g><g transform="rotate(315) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#ffffff"><animate attributeName="opacity" from="1" to="0.1" begin="0.87s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0.87s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g></g></svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

3
images/user-groups.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.33331 2C6.28101 2 7.09675 2.56499 7.46207 3.37651C7.00766 3.45023 6.58406 3.61583 6.21095 3.85361C6.04111 3.54356 5.71176 3.33333 5.33331 3.33333C4.78103 3.33333 4.33331 3.78105 4.33331 4.33333C4.33331 4.75895 4.59921 5.12246 4.97395 5.26682C4.77672 5.69245 4.66665 6.16671 4.66665 6.66667L4.66678 6.6967C3.12249 6.85332 2.66665 7.65415 2.66665 9.83333C2.66665 9.89666 2.66835 9.95222 2.67088 10H3.13441C2.977 10.3982 2.86114 10.8423 2.7841 11.3333H2.33331C1.66665 11.3333 1.33331 10.8333 1.33331 9.83333C1.33331 7.60559 1.88097 6.20498 3.39417 5.63152C3.14521 5.26038 2.99998 4.81382 2.99998 4.33333C2.99998 3.04467 4.04465 2 5.33331 2ZM9.78901 3.85361C9.4159 3.61583 8.9923 3.45023 8.53788 3.37651C8.90321 2.56499 9.71895 2 10.6666 2C11.9553 2 13 3.04467 13 4.33333C13 4.81382 12.8547 5.26038 12.6058 5.63152C14.119 6.20498 14.6666 7.60559 14.6666 9.83333C14.6666 10.8333 14.3333 11.3333 13.6666 11.3333H13.2159C13.1388 10.8423 13.023 10.3982 12.8656 10H13.3291C13.3316 9.95222 13.3333 9.89666 13.3333 9.83333C13.3333 7.65415 12.8775 6.85332 11.3332 6.6967L11.3333 6.66667C11.3333 6.1667 11.2232 5.69245 11.026 5.26682C11.4008 5.12246 11.6666 4.75895 11.6666 4.33333C11.6666 3.78105 11.2189 3.33333 10.6666 3.33333C10.2882 3.33333 9.95885 3.54356 9.78901 3.85361ZM4.49998 14.6667C3.7222 14.6667 3.33331 14.1111 3.33331 13C3.33331 10.4598 4.0062 8.8875 5.87888 8.28308C5.5366 7.83462 5.33331 7.27438 5.33331 6.66667C5.33331 5.19391 6.52722 4 7.99998 4C9.47274 4 10.6666 5.19391 10.6666 6.66667C10.6666 7.27438 10.4634 7.83462 10.1211 8.28308C11.9938 8.8875 12.6666 10.4598 12.6666 13C12.6666 14.1111 12.2778 14.6667 11.5 14.6667H4.49998ZM9.33331 6.66667C9.33331 7.40305 8.73636 8 7.99998 8C7.2636 8 6.66665 7.40305 6.66665 6.66667C6.66665 5.93029 7.2636 5.33333 7.99998 5.33333C8.73636 5.33333 9.33331 5.93029 9.33331 6.66667ZM11.3333 13C11.3333 13.1426 11.3252 13.2536 11.3152 13.3333H4.68477C4.67476 13.2536 4.66665 13.1426 4.66665 13C4.66665 10.1957 5.42021 9.33333 7.99998 9.33333C10.5797 9.33333 11.3333 10.1957 11.3333 13Z" fill="#5E6D7A"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -1,64 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="480"
height="270"
id="svg2"
version="1.1"
inkscape:version="0.48.2 r9819"
sodipodi:docname="videomask.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="-16.428571"
inkscape:cy="520"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="998"
inkscape:window-height="711"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-782.36218)">
<rect
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.92795467;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
id="rect2985"
width="479.07202"
height="269.07205"
x="0.46397734"
y="782.82617"
ry="20" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,10 +1,12 @@
<html itemscope itemtype="http://schema.org/Product" prefix="og: http://ogp.me/ns#" xmlns="http://www.w3.org/1999/html">
<head>
<!--#include virtual="head.html" -->
<meta charset="utf-8">
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!--#include virtual="base.html" -->
<link rel="apple-touch-icon" href="images/apple-touch-icon.png">
<link rel="stylesheet" href="css/all.css">
<script>
@@ -151,6 +153,7 @@
<!--#include virtual="static/settingsToolbarAdditionalContent.html" -->
</head>
<body>
<!--#include virtual="body.html" -->
<div id="react"></div>
</body>
</html>

View File

@@ -1,4 +1,4 @@
platform :ios, '10.0'
platform :ios, '11.0'
workspace 'jitsi-meet'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
@@ -82,6 +82,7 @@ post_install do |installer|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'YES'
config.build_settings['SUPPORTS_MACCATALYST'] = 'NO'
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0'
end
end
end

View File

@@ -274,7 +274,7 @@ PODS:
- React
- react-native-netinfo (4.1.5):
- React
- react-native-webrtc (1.75.0):
- react-native-webrtc (1.75.2):
- React
- react-native-webview (7.4.1):
- React
@@ -534,7 +534,7 @@ SPEC CHECKSUMS:
react-native-calendar-events: 2fe35a9294af05de0ed819d3a1b5dac048d2c010
react-native-keep-awake: eba3137546b10003361b37c761f6c429b59814ae
react-native-netinfo: 8d8db463bcc5db66a8ac5c48a7d86beb3b92f61a
react-native-webrtc: c5e3d631179a933548a8e49bddbd8fad02586095
react-native-webrtc: f6783727706d8bec5fb302b76eda60c33dfe3191
react-native-webview: 4dbc1d2a4a6b9c5e9e723c62651917aa2b5e579e
React-RCTActionSheet: 94671eef55b01a93be735605822ef712d5ea208e
React-RCTAnimation: 524ae33e73de9c0fe6501a7a4bda8e01d26499d9
@@ -553,6 +553,6 @@ SPEC CHECKSUMS:
RNWatch: 09738b339eceb66e4d80a2371633ca5fb380fa42
Yoga: 02036f6383c0008edb7ef0773a0e6beb6ce82bd1
PODFILE CHECKSUM: cb84b325b724c6ef7c8b24aa52ca7b6f681a095c
PODFILE CHECKSUM: 0fdfa45ae809c9460c80be3e0d4bbb822fccc418
COCOAPODS: 1.8.1

View File

@@ -747,7 +747,6 @@
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
);
INFOPLIST_FILE = src/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = (
@@ -758,7 +757,6 @@
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet;
PRODUCT_NAME = "jitsi-meet";
PROVISIONING_PROFILE_SPECIFIER = "";
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
@@ -783,7 +781,6 @@
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
);
INFOPLIST_FILE = src/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = (
@@ -794,7 +791,6 @@
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet;
PRODUCT_NAME = "jitsi-meet";
PROVISIONING_PROFILE_SPECIFIER = "";
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
@@ -850,10 +846,11 @@
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
);
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
@@ -902,10 +899,11 @@
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
);
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;

View File

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

View File

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

View File

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

View File

@@ -61,7 +61,21 @@ platform :ios do
)
# Upload the build to TestFlight (but don't distribute it)
upload_to_testflight(skip_submission: true, skip_waiting_for_build_processing: true)
upload_to_testflight(
beta_app_description: ENV["JITSI_CHANGELOG"],
beta_app_feedback_email: ENV["JITSI_REVIEW_EMAIL"],
beta_app_review_info: {
contact_email: ENV["JITSI_REVIEW_EMAIL"],
demo_account_name: ENV["JITSI_DEMO_ACCOUNT"],
demo_account_password: ENV["JITSI_DEMO_PASSWORD"],
},
changelog: ENV["JITSI_CHANGELOG"],
demo_account_required: false,
distribute_external: true,
groups: ENV["JITSI_BETA_TESTING_GROUPS"],
reject_build_waiting_for_review: true,
uses_non_exempt_encryption: false
)
# Cleanup
clean_build_artifacts

View File

@@ -2,7 +2,7 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildSystemType</key>
<string>Original</string>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@@ -25,7 +25,7 @@ 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
xcodebuild -workspace ios/jitsi-meet.xcworkspace -scheme JitsiMeet -destination='generic/platform=iOS' -configuration Release ENABLE_BITCODE=NO clean archive
if [[ $DO_GIT_TAG == 1 ]]; then
git tag ios-sdk-${SDK_VERSION}
fi

View File

@@ -555,7 +555,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -611,7 +611,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
@@ -627,6 +627,7 @@
baseConfigurationReference = 98E09B5C73D9036B4ED252FC /* Pods-JitsiMeet.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
BUILD_LIBRARY_FOR_DISTRIBUTION = NO;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
@@ -638,7 +639,6 @@
ENABLE_BITCODE = NO;
INFOPLIST_FILE = src/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.JitsiMeetSDK.ios;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -649,7 +649,6 @@
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
@@ -658,6 +657,7 @@
baseConfigurationReference = 9C77CA3CC919B081F1A52982 /* Pods-JitsiMeet.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
@@ -669,7 +669,6 @@
ENABLE_BITCODE = YES;
INFOPLIST_FILE = src/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.JitsiMeetSDK.ios;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -679,7 +678,6 @@
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};

View File

@@ -29,8 +29,6 @@
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -51,8 +49,6 @@
ReferencedContainer = "container:sdk.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
@@ -81,7 +77,7 @@
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Script"
scriptText = "exec &gt; /tmp/${PROJECT_NAME}_archive.log 2&gt;&amp;1&#10;&#10;UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal&#10;&#10;if [ &quot;true&quot; == ${ALREADYINVOKED:-false} ]&#10;then&#10;echo &quot;RECURSION: Detected, stopping&quot;&#10;else&#10;export ALREADYINVOKED=&quot;true&quot;&#10;&#10;# make sure the output directory exists&#10;mkdir -p &quot;${UNIVERSAL_OUTPUTFOLDER}&quot;&#10;&#10;echo &quot;Building for iPhoneSimulator&quot;&#10;xcodebuild -workspace &quot;${WORKSPACE_PATH}&quot; -scheme &quot;${TARGET_NAME}&quot; -configuration ${CONFIGURATION} -sdk iphonesimulator -destination &apos;platform=iOS Simulator,name=iPhone 8&apos; ONLY_ACTIVE_ARCH=NO ARCHS=&apos;i386 x86_64&apos; BUILD_DIR=&quot;${BUILD_DIR}&quot; BUILD_ROOT=&quot;${BUILD_ROOT}&quot; ENABLE_BITCODE=YES OTHER_CFLAGS=&quot;-fembed-bitcode&quot; BITCODE_GENERATION_MODE=bitcode clean build&#10;&#10;# Step 1. Copy the framework structure (from iphoneos build) to the universal folder&#10;echo &quot;Copying to output folder&quot;&#10;cp -R &quot;${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FULL_PRODUCT_NAME}&quot; &quot;${UNIVERSAL_OUTPUTFOLDER}/&quot;&#10;&#10;# Step 2. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory&#10;SIMULATOR_SWIFT_MODULES_DIR=&quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/.&quot;&#10;if [ -d &quot;${SIMULATOR_SWIFT_MODULES_DIR}&quot; ]; then&#10;cp -R &quot;${SIMULATOR_SWIFT_MODULES_DIR}&quot; &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule&quot;&#10;fi&#10;&#10;# Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory&#10;echo &quot;Combining executables&quot;&#10;lipo -create -output &quot;${UNIVERSAL_OUTPUTFOLDER}/${EXECUTABLE_PATH}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${EXECUTABLE_PATH}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphoneos/${EXECUTABLE_PATH}&quot;&#10;&#10;# Step 4. Create universal binaries for embedded frameworks&#10;#for SUB_FRAMEWORK in $( ls &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks&quot; ); do&#10;#BINARY_NAME=&quot;${SUB_FRAMEWORK%.*}&quot;&#10;#lipo -create -output &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SUB_FRAMEWORK}/${BINARY_NAME}&quot; &quot;${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}&quot;&#10;#done&#10;&#10;# Step 5. Convenience step to copy the framework to the project&apos;s directory&#10;echo &quot;Copying to project dir&quot;&#10;yes | cp -Rf &quot;${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}&quot; &quot;${PROJECT_DIR}&quot;&#10;&#10;fi&#10;">
scriptText = "exec &gt; /tmp/${PROJECT_NAME}_archive.log 2&gt;&amp;1&#10;&#10;UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal&#10;&#10;if [ &quot;true&quot; == ${ALREADYINVOKED:-false} ]&#10;then&#10;echo &quot;RECURSION: Detected, stopping&quot;&#10;else&#10;export ALREADYINVOKED=&quot;true&quot;&#10;&#10;# make sure the output directory exists&#10;mkdir -p &quot;${UNIVERSAL_OUTPUTFOLDER}&quot;&#10;&#10;echo &quot;Building for iPhoneSimulator&quot;&#10;xcodebuild -workspace &quot;${WORKSPACE_PATH}&quot; -scheme &quot;${TARGET_NAME}&quot; -configuration ${CONFIGURATION} -sdk iphonesimulator -destination &apos;platform=iOS Simulator,name=iPhone 8&apos; ONLY_ACTIVE_ARCH=NO ARCHS=&apos;i386 x86_64&apos; BUILD_DIR=&quot;${BUILD_DIR}&quot; BUILD_ROOT=&quot;${BUILD_ROOT}&quot; ENABLE_BITCODE=YES OTHER_CFLAGS=&quot;-fembed-bitcode&quot; BITCODE_GENERATION_MODE=bitcode build&#10;&#10;# Step 1. Copy the framework structure (from iphoneos build) to the universal folder&#10;echo &quot;Copying to output folder&quot;&#10;cp -R &quot;${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FULL_PRODUCT_NAME}&quot; &quot;${UNIVERSAL_OUTPUTFOLDER}/&quot;&#10;&#10;# Step 2. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory&#10;SIMULATOR_SWIFT_MODULES_DIR=&quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/.&quot;&#10;if [ -d &quot;${SIMULATOR_SWIFT_MODULES_DIR}&quot; ]; then&#10;cp -R &quot;${SIMULATOR_SWIFT_MODULES_DIR}&quot; &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule&quot;&#10;fi&#10;&#10;# Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory&#10;echo &quot;Combining executables&quot;&#10;lipo -create -output &quot;${UNIVERSAL_OUTPUTFOLDER}/${EXECUTABLE_PATH}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${EXECUTABLE_PATH}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphoneos/${EXECUTABLE_PATH}&quot;&#10;&#10;# Step 4. Create universal binaries for embedded frameworks&#10;#for SUB_FRAMEWORK in $( ls &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks&quot; ); do&#10;#BINARY_NAME=&quot;${SUB_FRAMEWORK%.*}&quot;&#10;#lipo -create -output &quot;${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}&quot; &quot;${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SUB_FRAMEWORK}/${BINARY_NAME}&quot; &quot;${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}&quot;&#10;#done&#10;&#10;# Step 5. Convenience step to copy the framework to the project&apos;s directory&#10;echo &quot;Copying to project dir&quot;&#10;yes | cp -Rf &quot;${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}&quot; &quot;${PROJECT_DIR}&quot;&#10;&#10;fi&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"

View File

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

View File

@@ -225,7 +225,7 @@ static NSString *const WelcomePageEnabledFeatureFlag = @"welcomepage.enabled";
urlProps[@"jwt"] = _token;
}
if (_token == nil && _userInfo != nil) {
if (_userInfo != nil) {
props[@"userInfo"] = [self.userInfo asDict];
}

View File

@@ -47,8 +47,10 @@
},
"chat": {
"error": "Error: your message was not sent. Reason: {{error}}",
"fieldPlaceHolder": "Type your message here",
"messagebox": "Type a message",
"messageTo": "Private message to {{recipient}}",
"noMessagesMessage": "There are no messages in the meeting yet. Start a conversation here!",
"nickname": {
"popover": "Choose a nickname",
"title": "Enter a nickname to use chat"
@@ -628,6 +630,10 @@
"lowerYourHand": "Lower your hand",
"moreActions": "More actions",
"mute": "Mute / Unmute",
"noAudioSignalTitle": "There is no input coming from your mic!",
"noAudioSignalDesc": "If you did not purposely mute it from system settings or hardware, consider changing the device.",
"noAudioSignalDescSuggestion": "If you did not purposely mute it from system settings or hardware, consider using the following device:",
"openChat": "Open chat",
"pip": "Enter Picture-in-Picture mode",
"privateMessage": "Send private message",
@@ -733,7 +739,8 @@
"enterRoomTitle": "Start a new meeting",
"roomNameAllowedChars": "Meeting name should not contain any of these characters: ?, &, :, ', \", %, #.",
"go": "GO",
"join": "JOIN",
"goSmall": "GO",
"join": "CREATE / JOIN",
"info": "Info",
"privacy": "Privacy",
"recentList": "Recent",

View File

@@ -232,6 +232,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
* information about new participants that will be invited in the call.
* @param {Array<Object>} [options.devices] - Array of objects containing
* information about the initial devices that will be used in the call.
* @param {Object} [options.userInfo] - Object containing information about
* the participant opening the meeting.
*/
constructor(domain, ...args) {
super();
@@ -246,7 +248,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
jwt = undefined,
onload = undefined,
invitees,
devices
devices,
userInfo
} = parseArguments(args);
this._parentNode = parentNode;
@@ -256,7 +259,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
jwt,
noSSL,
roomName,
devices
devices,
userInfo
});
this._createIFrame(height, width, onload);
this._transport = new Transport({

View File

@@ -683,8 +683,8 @@ export default class LargeVideoManager {
}
/**
* Dispatches an action to update the known resolution state of the
* large video and adjusts container sizes when the resolution changes.
* Dispatches an action to update the known resolution state of the large video and adjusts container sizes when the
* resolution changes.
*
* @private
* @returns {void}
@@ -697,7 +697,7 @@ export default class LargeVideoManager {
APP.store.dispatch(updateKnownLargeVideoResolution(height));
}
const currentAspectRatio = width / height;
const currentAspectRatio = height === 0 ? 0 : width / height;
if (this._videoAspectRatio !== currentAspectRatio) {
this._videoAspectRatio = currentAspectRatio;

View File

@@ -5,10 +5,8 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { browser } from '../../../react/features/base/lib-jitsi-meet';
import {
ORIENTATION,
LargeVideoBackground
} from '../../../react/features/large-video';
import { ORIENTATION, LargeVideoBackground } from '../../../react/features/large-video';
import { LAYOUTS, getCurrentLayout } from '../../../react/features/video-layout';
/* eslint-enable no-unused-vars */
import Filmstrip from './Filmstrip';
@@ -55,8 +53,12 @@ function computeDesktopVideoSize( // eslint-disable-line max-params
videoHeight,
videoSpaceWidth,
videoSpaceHeight) {
const aspectRatio = videoWidth / videoHeight;
if (videoWidth === 0 || videoHeight === 0 || videoSpaceWidth === 0 || videoSpaceHeight === 0) {
// Avoid NaN values caused by devision by 0.
return [ 0, 0 ];
}
const aspectRatio = videoWidth / videoHeight;
let availableWidth = Math.max(videoWidth, videoSpaceWidth);
let availableHeight = Math.max(videoHeight, videoSpaceHeight);
@@ -99,6 +101,11 @@ function computeCameraVideoSize( // eslint-disable-line max-params
videoSpaceWidth,
videoSpaceHeight,
videoLayoutFit) {
if (videoWidth === 0 || videoHeight === 0 || videoSpaceWidth === 0 || videoSpaceHeight === 0) {
// Avoid NaN values caused by devision by 0.
return [ 0, 0 ];
}
const aspectRatio = videoWidth / videoHeight;
switch (videoLayoutFit) {
@@ -322,7 +329,7 @@ export class VideoContainer extends LargeContainer {
* @param {number} containerHeight container height
* @returns {{availableWidth, availableHeight}}
*/
getVideoSize(containerWidth, containerHeight) {
_getVideoSize(containerWidth, containerHeight) {
const { width, height } = this.getStreamSize();
if (this.stream && this.isScreenSharing()) {
@@ -414,13 +421,29 @@ export class VideoContainer extends LargeContainer {
if (this.$video.length === 0) {
return;
}
const currentLayout = getCurrentLayout(APP.store.getState());
const [ width, height ]
= this.getVideoSize(containerWidth, containerHeight);
if (currentLayout === LAYOUTS.TILE_VIEW) {
// We don't need to resize the large video since it won't be displayed and we'll resize when returning back
// to stage view.
return;
}
this.positionRemoteStatusMessages();
const [ width, height ] = this._getVideoSize(containerWidth, containerHeight);
if (width === 0 || height === 0) {
// We don't need to set 0 for width or height since the visibility is controled by the visibility css prop
// on the largeVideoElementsContainer. Also if the width/height of the video element is 0 the attached
// stream won't be played. Normally if we attach a new stream we won't resize the video element until the
// stream has been played. But setting width/height to 0 will prevent the video from playing.
return;
}
if ((containerWidth > width) || (containerHeight > height)) {
this._backgroundOrientation = containerWidth > width
? ORIENTATION.LANDSCAPE : ORIENTATION.PORTRAIT;
this._backgroundOrientation = containerWidth > width ? ORIENTATION.LANDSCAPE : ORIENTATION.PORTRAIT;
this._hideBackground = false;
} else {
this._hideBackground = true;
@@ -429,15 +452,7 @@ export class VideoContainer extends LargeContainer {
this._updateBackground();
const { horizontalIndent, verticalIndent }
= this.getVideoPosition(width, height,
containerWidth, containerHeight);
// update avatar position
const top = (containerHeight / 2) - (this.avatarHeight / 4 * 3);
this.$avatar.css('top', top);
this.positionRemoteStatusMessages();
= this.getVideoPosition(width, height, containerWidth, containerHeight);
this.$wrapper.animate({
width,

View File

@@ -22,7 +22,6 @@ import SharedVideoThumb from '../shared_video/SharedVideoThumb';
import Filmstrip from './Filmstrip';
import UIEvents from '../../../service/UI/UIEvents';
import UIUtil from '../util/UIUtil';
import RemoteVideo from './RemoteVideo';
import LargeVideoManager from './LargeVideoManager';
@@ -663,14 +662,6 @@ const VideoLayout = {
largeVideo.updateContainerSize();
largeVideo.resize(animate);
}
// Calculate available width and height.
const availableHeight = window.innerHeight;
const availableWidth = UIUtil.getAvailableVideoWidth();
if (availableWidth < 0 || availableHeight < 0) {
return;
}
},
getSmallVideo(id) {

View File

@@ -1,174 +0,0 @@
import Postis from 'postis';
/**
* The default options for postis.
*
* @type {Object}
*/
const DEFAULT_POSTIS_OPTIONS = {
window: window.opener || window.parent
};
/**
* The list of methods of incoming postis messages that we have to support for
* backward compatibility for the users that are directly sending messages to
* Jitsi Meet (without using external_api.js)
*
* @type {string[]}
*/
const LEGACY_INCOMING_METHODS = [
'avatar-url',
'display-name',
'email',
'toggle-audio',
'toggle-chat',
'toggle-film-strip',
'toggle-share-screen',
'toggle-video',
'video-hangup'
];
/**
* The list of methods of outgoing postis messages that we have to support for
* backward compatibility for the users that are directly listening to the
* postis messages send by Jitsi Meet(without using external_api.js).
*
* @type {string[]}
*/
const LEGACY_OUTGOING_METHODS = [
'display-name-change',
'incoming-message',
'outgoing-message',
'participant-joined',
'participant-left',
'video-conference-joined',
'video-conference-left',
'video-ready-to-close'
];
/**
* The postis method used for all messages.
*
* @type {string}
*/
const POSTIS_METHOD_NAME = 'message';
/**
* Implements message transport using the postMessage API.
*/
export default class PostMessageTransportBackend {
/**
* Creates new PostMessageTransportBackend instance.
*
* @param {Object} options - Optional parameters for configuration of the
* transport.
*/
constructor({ enableLegacyFormat, postisOptions } = {}) {
// eslint-disable-next-line new-cap
this.postis = Postis({
...DEFAULT_POSTIS_OPTIONS,
...postisOptions
});
/**
* If true PostMessageTransportBackend will process and send messages
* using the legacy format and in the same time the current format.
* Otherwise all messages (outgoing and incoming) that are using the
* legacy format will be ignored.
*
* @type {boolean}
*/
this._enableLegacyFormat = enableLegacyFormat;
if (this._enableLegacyFormat) {
// backward compatibility
LEGACY_INCOMING_METHODS.forEach(method =>
this.postis.listen(
method,
params =>
this._legacyMessageReceivedCallback(method, params)
)
);
}
this._receiveCallback = () => {
// Do nothing until a callback is set by the consumer of
// PostMessageTransportBackend via setReceiveCallback.
};
this.postis.listen(
POSTIS_METHOD_NAME,
message => this._receiveCallback(message));
}
/**
* Handles incoming legacy postis messages.
*
* @param {string} method - The method property from the postis message.
* @param {Any} params - The params property from the postis message.
* @returns {void}
*/
_legacyMessageReceivedCallback(method, params = {}) {
this._receiveCallback({
data: {
name: method,
data: params
}
});
}
/**
* Sends the passed message via postis using the old format.
*
* @param {Object} legacyMessage - The message to be sent.
* @returns {void}
*/
_sendLegacyMessage({ name, ...data }) {
if (name && LEGACY_OUTGOING_METHODS.indexOf(name) !== -1) {
this.postis.send({
method: name,
params: data
});
}
}
/**
* Disposes the allocated resources.
*
* @returns {void}
*/
dispose() {
this.postis.destroy();
}
/**
* Sends the passed message.
*
* @param {Object} message - The message to be sent.
* @returns {void}
*/
send(message) {
this.postis.send({
method: POSTIS_METHOD_NAME,
params: message
});
if (this._enableLegacyFormat) {
// For the legacy use case we don't need any new fields defined in
// Transport class. That's why we are passing only the original
// object passed by the consumer of the Transport class which is
// message.data.
this._sendLegacyMessage(message.data || {});
}
}
/**
* Sets the callback for receiving data.
*
* @param {Function} callback - The new callback.
* @returns {void}
*/
setReceiveCallback(callback) {
this._receiveCallback = callback;
}
}

View File

@@ -1,267 +0,0 @@
import {
MESSAGE_TYPE_EVENT,
MESSAGE_TYPE_REQUEST,
MESSAGE_TYPE_RESPONSE
} from './constants';
/**
* Stores the currnet transport backend that have to be used. Also implements
* request/response mechanism.
*/
export default class Transport {
/**
* Creates new instance.
*
* @param {Object} options - Optional parameters for configuration of the
* transport backend.
*/
constructor({ backend } = {}) {
/**
* Maps an event name and listener that have been added to the Transport
* instance.
*
* @type {Map<string, Function>}
*/
this._listeners = new Map();
/**
* The request ID counter used for the id property of the request. This
* property is used to match the responses with the request.
*
* @type {number}
*/
this._requestID = 0;
/**
* Maps an IDs of the requests and handlers that will process the
* responses of those requests.
*
* @type {Map<number, Function>}
*/
this._responseHandlers = new Map();
/**
* A set with the events and requests that were received but not
* processed by any listener. They are later passed on every new
* listener until they are processed.
*
* @type {Set<Object>}
*/
this._unprocessedMessages = new Set();
/**
* Alias.
*/
this.addListener = this.on;
if (backend) {
this.setBackend(backend);
}
}
/**
* Disposes the current transport backend.
*
* @returns {void}
*/
_disposeBackend() {
if (this._backend) {
this._backend.dispose();
this._backend = null;
}
}
/**
* Handles incoming messages from the transport backend.
*
* @param {Object} message - The message.
* @returns {void}
*/
_onMessageReceived(message) {
if (message.type === MESSAGE_TYPE_RESPONSE) {
const handler = this._responseHandlers.get(message.id);
if (handler) {
handler(message);
this._responseHandlers.delete(message.id);
}
} else if (message.type === MESSAGE_TYPE_REQUEST) {
this.emit('request', message.data, (result, error) => {
this._backend.send({
type: MESSAGE_TYPE_RESPONSE,
error,
id: message.id,
result
});
});
} else {
this.emit('event', message.data);
}
}
/**
* Disposes the allocated resources.
*
* @returns {void}
*/
dispose() {
this._responseHandlers.clear();
this._unprocessedMessages.clear();
this.removeAllListeners();
this._disposeBackend();
}
/**
* Calls each of the listeners registered for the event named eventName, in
* the order they were registered, passing the supplied arguments to each.
*
* @param {string} eventName - The name of the event.
* @returns {boolean} True if the event has been processed by any listener,
* false otherwise.
*/
emit(eventName, ...args) {
const listenersForEvent = this._listeners.get(eventName);
let isProcessed = false;
if (listenersForEvent && listenersForEvent.size) {
listenersForEvent.forEach(listener => {
isProcessed = listener(...args) || isProcessed;
});
}
if (!isProcessed) {
this._unprocessedMessages.add(args);
}
return isProcessed;
}
/**
* Adds the listener function to the listeners collection for the event
* named eventName.
*
* @param {string} eventName - The name of the event.
* @param {Function} listener - The listener that will be added.
* @returns {Transport} References to the instance of Transport class, so
* that calls can be chained.
*/
on(eventName, listener) {
let listenersForEvent = this._listeners.get(eventName);
if (!listenersForEvent) {
listenersForEvent = new Set();
this._listeners.set(eventName, listenersForEvent);
}
listenersForEvent.add(listener);
this._unprocessedMessages.forEach(args => {
if (listener(...args)) {
this._unprocessedMessages.delete(args);
}
});
return this;
}
/**
* Removes all listeners, or those of the specified eventName.
*
* @param {string} [eventName] - The name of the event. If this parameter is
* not specified all listeners will be removed.
* @returns {Transport} References to the instance of Transport class, so
* that calls can be chained.
*/
removeAllListeners(eventName) {
if (eventName) {
this._listeners.delete(eventName);
} else {
this._listeners.clear();
}
return this;
}
/**
* Removes the listener function from the listeners collection for the event
* named eventName.
*
* @param {string} eventName - The name of the event.
* @param {Function} listener - The listener that will be removed.
* @returns {Transport} References to the instance of Transport class, so
* that calls can be chained.
*/
removeListener(eventName, listener) {
const listenersForEvent = this._listeners.get(eventName);
if (listenersForEvent) {
listenersForEvent.delete(listener);
}
return this;
}
/**
* Sends the passed event.
*
* @param {Object} event - The event to be sent.
* @returns {void}
*/
sendEvent(event = {}) {
if (this._backend) {
this._backend.send({
type: MESSAGE_TYPE_EVENT,
data: event
});
}
}
/**
* Sending request.
*
* @param {Object} request - The request to be sent.
* @returns {Promise}
*/
sendRequest(request) {
if (!this._backend) {
return Promise.reject(new Error('No transport backend defined!'));
}
this._requestID++;
const id = this._requestID;
return new Promise((resolve, reject) => {
this._responseHandlers.set(id, ({ error, result }) => {
if (typeof result !== 'undefined') {
resolve(result);
// eslint-disable-next-line no-negated-condition
} else if (typeof error !== 'undefined') {
reject(error);
} else { // no response
reject(new Error('Unexpected response format!'));
}
});
this._backend.send({
type: MESSAGE_TYPE_REQUEST,
data: request,
id
});
});
}
/**
* Changes the current backend transport.
*
* @param {Object} backend - The new transport backend that will be used.
* @returns {void}
*/
setBackend(backend) {
this._disposeBackend();
this._backend = backend;
this._backend.setReceiveCallback(this._onMessageReceived.bind(this));
}
}

View File

@@ -1,20 +0,0 @@
/**
* The message type for events.
*
* @type {string}
*/
export const MESSAGE_TYPE_EVENT = 'event';
/**
* The message type for requests.
*
* @type {string}
*/
export const MESSAGE_TYPE_REQUEST = 'request';
/**
* The message type for responses.
*
* @type {string}
*/
export const MESSAGE_TYPE_RESPONSE = 'response';

View File

@@ -3,8 +3,7 @@
import { API_ID } from '../API/constants';
import { getJitsiMeetGlobalNS } from '../../react/features/base/util';
import PostMessageTransportBackend from './PostMessageTransportBackend';
import Transport from './Transport';
import { PostMessageTransportBackend, Transport } from 'js-utils/transport';
export {
PostMessageTransportBackend,
@@ -36,12 +35,7 @@ let transport;
*/
export function getJitsiMeetTransport() {
if (!transport) {
transport = new Transport({
backend: new PostMessageTransportBackend({
enableLegacyFormat: true,
postisOptions
})
});
transport = new Transport({ backend: new PostMessageTransportBackend({ postisOptions }) });
}
return transport;

92
package-lock.json generated
View File

@@ -22,38 +22,6 @@
"@atlaskit/type-helpers": "^2.0.0"
}
},
"@atlaskit/avatar": {
"version": "14.1.7",
"resolved": "https://registry.npmjs.org/@atlaskit/avatar/-/avatar-14.1.7.tgz",
"integrity": "sha512-KGtV0lRr3g+JX3XLZQKDGxGhtbVFRvM/Ku5C+CEJw2uDl1KFY0dJxfr2a/E32bEgUuvmqSL7D3ROrTrlHJ2fMA==",
"requires": {
"@atlaskit/analytics-next": "^3.1.2",
"@atlaskit/theme": "^7.0.1",
"@atlaskit/tooltip": "^12.1.13",
"@babel/runtime": "^7.0.0"
},
"dependencies": {
"@atlaskit/analytics-next": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@atlaskit/analytics-next/-/analytics-next-3.1.2.tgz",
"integrity": "sha512-bkYDvl3Ojsnim+bsc9BALfvOjiL7xdb2rTp/4yqUP9pfidtf5HudbOJ849+dKcRCmk/rFbfB/nhDBRU6rv1Ueg==",
"requires": {
"@babel/runtime": "^7.0.0",
"babel-runtime": "^6.26.0",
"prop-types": "^15.5.10"
}
},
"@atlaskit/theme": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@atlaskit/theme/-/theme-7.0.1.tgz",
"integrity": "sha512-wxXDnkUablJketNCrQuNUuazufYEA7kv0Y6Yzv6uvqfuyNpWUQt4H1psz/MW8DbZmCdku9dEYbNVK3nFP5TDGg==",
"requires": {
"@babel/runtime": "^7.0.0",
"prop-types": "^15.5.10"
}
}
}
},
"@atlaskit/blanket": {
"version": "8.0.3",
"resolved": "https://registry.npmjs.org/@atlaskit/blanket/-/blanket-8.0.3.tgz",
@@ -10702,11 +10670,12 @@
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
},
"js-utils": {
"version": "github:jitsi/js-utils#192b1c996e8c05530eb1f19e82a31069c3021e31",
"from": "github:jitsi/js-utils#192b1c996e8c05530eb1f19e82a31069c3021e31",
"version": "github:jitsi/js-utils#964294793a7dbb85b2a38c87abe5ae46c4acf0af",
"from": "github:jitsi/js-utils#964294793a7dbb85b2a38c87abe5ae46c4acf0af",
"requires": {
"bowser": "1.9.1",
"js-md5": "0.7.3"
"js-md5": "0.7.3",
"postis": "2.2.0"
},
"dependencies": {
"js-md5": {
@@ -10931,8 +10900,8 @@
}
},
"lib-jitsi-meet": {
"version": "github:jitsi/lib-jitsi-meet#5521a40aa85cb6f128f8a6dad9b72a5646132484",
"from": "github:jitsi/lib-jitsi-meet#5521a40aa85cb6f128f8a6dad9b72a5646132484",
"version": "github:jitsi/lib-jitsi-meet#4e7034ee6a0d0e68487c583c981f4e07ab73926c",
"from": "github:jitsi/lib-jitsi-meet#4e7034ee6a0d0e68487c583c981f4e07ab73926c",
"requires": {
"@jitsi/sdp-interop": "0.1.14",
"@jitsi/sdp-simulcast": "0.2.2",
@@ -14830,6 +14799,39 @@
"jssha": "^2.2.0"
}
},
"react-native-collapsible": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/react-native-collapsible/-/react-native-collapsible-1.5.1.tgz",
"integrity": "sha512-uQQ2s6l+7+L/pzJroisWsDsyVYVF5bQ+jGbLATNioRh/03SpEL8pcQEVKqVWswcNNR0B9GENixHaLzmuZIwpQg==",
"requires": {
"prop-types": "^15.6.2"
},
"dependencies": {
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"prop-types": {
"version": "15.7.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.8.1"
}
},
"react-is": {
"version": "16.12.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz",
"integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q=="
}
}
},
"react-native-immersive": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/react-native-immersive/-/react-native-immersive-2.0.0.tgz",
@@ -14871,6 +14873,11 @@
}
}
},
"react-native-swipe-gestures": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/react-native-swipe-gestures/-/react-native-swipe-gestures-1.0.4.tgz",
"integrity": "sha512-C/vz0KPHNyqHk3uF4Cz/jzd/0N8z34ZgsjAZUh/RsXPH2FtJJf3Fw73pQDWJSoCMtvVadlztb8xQ+/aEQrll7w=="
},
"react-native-swipeout": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/react-native-swipeout/-/react-native-swipeout-2.3.6.tgz",
@@ -14887,8 +14894,9 @@
"integrity": "sha512-l3Quzbb+qa4in2U5RSt/lT0/pHrIpEChT1NnqrVAAXNrjkXjVOsxduaaEDdDhTzNJQEm/PcAcoyrFmgvGOohxw=="
},
"react-native-webrtc": {
"version": "github:react-native-webrtc/react-native-webrtc#a12a6cdfdefe53d03b388394e4cf10966bd99fca",
"from": "github:react-native-webrtc/react-native-webrtc#a12a6cdfdefe53d03b388394e4cf10966bd99fca",
"version": "1.75.2",
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.75.2.tgz",
"integrity": "sha512-mdEukmHNhiyVIiwdooxk4kVXWG83OOENFV9YIkC7dtGU/sOdL81vDzynqd6Af9YbGMeOr0xdpFuEGsc1OFnKZg==",
"requires": {
"base64-js": "^1.1.2",
"event-target-shim": "^1.0.5",
@@ -17595,6 +17603,12 @@
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
},
"unorm": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz",
"integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==",
"dev": true
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",

View File

@@ -15,7 +15,6 @@
"author": "",
"readmeFilename": "README.md",
"dependencies": {
"@atlaskit/avatar": "14.1.7",
"@atlaskit/button": "10.1.1",
"@atlaskit/checkbox": "5.0.10",
"@atlaskit/dropdown-menu": "6.1.25",
@@ -54,15 +53,14 @@
"jquery-contextmenu": "2.4.5",
"jquery-i18next": "1.2.1",
"js-md5": "0.6.1",
"js-utils": "github:jitsi/js-utils#192b1c996e8c05530eb1f19e82a31069c3021e31",
"js-utils": "github:jitsi/js-utils#964294793a7dbb85b2a38c87abe5ae46c4acf0af",
"jsrsasign": "8.0.12",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#5521a40aa85cb6f128f8a6dad9b72a5646132484",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#4e7034ee6a0d0e68487c583c981f4e07ab73926c",
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"lodash": "4.17.13",
"moment": "2.19.4",
"moment-duration-format": "2.2.2",
"postis": "2.2.0",
"react": "16.9",
"react-dom": "16.9",
"react-emoji-render": "1.0.0",
@@ -72,15 +70,17 @@
"react-native-background-timer": "2.1.1",
"react-native-calendar-events": "github:jitsi/react-native-calendar-events#902e6e92d6bae450a6052f76ba4d02f977ffd8f2",
"react-native-callstats": "3.61.0",
"react-native-collapsible": "1.5.1",
"react-native-immersive": "2.0.0",
"react-native-keep-awake": "4.0.0",
"react-native-linear-gradient": "2.5.6",
"react-native-sound": "0.11.0",
"react-native-svg": "9.7.1",
"react-native-svg-transformer": "0.13.0",
"react-native-swipe-gestures": "1.0.4",
"react-native-swipeout": "2.3.6",
"react-native-watch-connectivity": "0.2.0",
"react-native-webrtc": "github:react-native-webrtc/react-native-webrtc#a12a6cdfdefe53d03b388394e4cf10966bd99fca",
"react-native-webrtc": "1.75.2",
"react-native-webview": "7.4.1",
"react-redux": "7.1.0",
"react-textarea-autosize": "7.1.0",
@@ -126,6 +126,7 @@
"precommit-hook": "3.0.0",
"string-replace-loader": "2.1.1",
"style-loader": "0.19.0",
"unorm": "1.6.0",
"webpack": "4.27.1",
"webpack-bundle-analyzer": "3.4.1",
"webpack-cli": "3.1.2",

View File

@@ -27,7 +27,7 @@ export default class AmplitudeHandler extends AbstractHandler {
host
};
amplitude.getInstance(this._amplitudeOptions).init(amplitudeAPPKey);
amplitude.getInstance(this._amplitudeOptions).init(amplitudeAPPKey, undefined, { includeReferrer: true });
if (user) {
amplitude.getInstance(this._amplitudeOptions).setUserId(user);

View File

@@ -35,9 +35,12 @@ class Amplitude {
* Sets an identifier for the current user.
*
* @param {string} userId - The new user id.
* @param {string} opt_userId - Currently not used.
* @param {Object} opt_config - Currently not used.
* @param {Function} opt_callback - Currently not used.
* @returns {void}
*/
setUserId(userId) {
setUserId(userId, opt_userId, opt_config, opt_callback) { // eslint-disable-line camelcase, no-unused-vars
AmplitudeNative.setUserId(this._instanceName, userId);
}

View File

@@ -147,9 +147,10 @@ MiddlewareRegistry.register(store => next => action => {
const state = getState();
const { localTracksDuration } = state['features/analytics'];
if (localTracksDuration.conference.startedTime === -1) {
if (localTracksDuration.conference.startedTime === -1 || action.mediaType === 'presenter') {
// We don't want to track the media duration if the conference is not joined yet because otherwise we won't
// be able to compare them with the conference duration (from conference join to conference will leave).
// Also, do not track media duration for presenter tracks.
break;
}
dispatch({

View File

@@ -9,10 +9,7 @@ import { DialogContainer } from '../../base/dialog';
import { CALL_INTEGRATION_ENABLED, updateFlags } from '../../base/flags';
import '../../base/jwt';
import { Platform } from '../../base/react';
import {
AspectRatioDetector,
ReducedUIDetector
} from '../../base/responsive-ui';
import '../../base/responsive-ui';
import { updateSettings } from '../../base/settings';
import '../../google-api';
import '../../mobile/audio-mode';
@@ -110,22 +107,6 @@ export class App extends AbstractApp {
});
}
/**
* Injects {@link AspectRatioDetector} in order to detect the aspect ratio
* of this {@code App}'s user interface and afford {@link AspectRatioAware}.
*
* @override
*/
_createMainElement(component, props) {
return (
<AspectRatioDetector>
<ReducedUIDetector>
{ super._createMainElement(component, props) }
</ReducedUIDetector>
</AspectRatioDetector>
);
}
/**
* Attempts to disable the use of React Native
* {@link ExceptionsManager#handleException} on platforms and in

View File

@@ -5,9 +5,9 @@ import React from 'react';
import { DialogContainer } from '../../base/dialog';
import '../../base/user-interaction';
import '../../base/responsive-ui';
import '../../chat';
import '../../external-api';
import '../../no-audio-signal';
import '../../power-monitor';
import '../../room-lock';
import '../../talk-while-muted';

View File

@@ -5,6 +5,7 @@ import { Text, TextInput, View } from 'react-native';
import { connect as reduxConnect } from 'react-redux';
import type { Dispatch } from 'redux';
import { ColorSchemeRegistry } from '../../base/color-scheme';
import { toJid } from '../../base/connection';
import { connect } from '../../base/connection/actions.native';
import {
@@ -19,7 +20,9 @@ import { JitsiConnectionErrors } from '../../base/lib-jitsi-meet';
import type { StyleType } from '../../base/styles';
import { authenticateAndUpgradeRole, cancelLogin } from '../actions';
import styles from './styles';
// Register styles.
import './styles';
/**
* The type of the React {@link Component} props of {@link LoginDialog}.
@@ -58,6 +61,11 @@ type Props = {
*/
_progress: number,
/**
* The color-schemed stylesheet of this feature.
*/
_styles: StyleType,
/**
* Redux store dispatch method.
*/
@@ -144,46 +152,10 @@ class LoginDialog extends Component<Props, State> {
const {
_connecting: connecting,
_dialogStyles,
_error: error,
_progress: progress,
_styles: styles,
t
} = this.props;
let messageKey;
const messageOptions = {};
if (progress && progress < 1) {
messageKey = 'connection.FETCH_SESSION_ID';
} else if (error) {
const { name } = error;
if (name === JitsiConnectionErrors.PASSWORD_REQUIRED) {
// Show a message that the credentials are incorrect only if the
// credentials which have caused the connection to fail are the
// ones which the user sees.
const { credentials } = error;
if (credentials
&& credentials.jid
=== toJid(
this.state.username,
this.props._configHosts)
&& credentials.password === this.state.password) {
messageKey = 'dialog.incorrectPassword';
}
} else if (name) {
messageKey = 'dialog.connectErrorWithMsg';
messageOptions.msg = `${name} ${error.message}`;
}
}
const showMessage = messageKey || connecting;
const message = messageKey
? t(messageKey, messageOptions)
: connecting
? t('connection.CONNECTING')
: '';
return (
<CustomSubmitDialog
okDisabled = { connecting }
@@ -210,16 +182,77 @@ class LoginDialog extends Component<Props, State> {
] }
underlineColorAndroid = { FIELD_UNDERLINE }
value = { this.state.password } />
{ showMessage && (
<Text style = { styles.dialogText }>
{ message }
</Text>
) }
{ this._renderMessage() }
</View>
</CustomSubmitDialog>
);
}
/**
* Renders an optional message, if applicable.
*
* @returns {ReactElement}
* @private
*/
_renderMessage() {
const {
_connecting: connecting,
_error: error,
_progress: progress,
_styles: styles,
t
} = this.props;
let messageKey;
let messageIsError = false;
const messageOptions = {};
if (progress && progress < 1) {
messageKey = 'connection.FETCH_SESSION_ID';
} else if (error) {
const { name } = error;
if (name === JitsiConnectionErrors.PASSWORD_REQUIRED) {
// Show a message that the credentials are incorrect only if the
// credentials which have caused the connection to fail are the
// ones which the user sees.
const { credentials } = error;
if (credentials
&& credentials.jid
=== toJid(
this.state.username,
this.props._configHosts)
&& credentials.password === this.state.password) {
messageKey = 'dialog.incorrectPassword';
messageIsError = true;
}
} else if (name) {
messageKey = 'dialog.connectErrorWithMsg';
messageOptions.msg = `${name} ${error.message}`;
messageIsError = true;
}
} else if (connecting) {
messageKey = 'connection.CONNECTING';
}
if (messageKey) {
const message = t(messageKey, messageOptions);
const messageStyles = [
styles.dialogText,
messageIsError ? styles.errorMessage : styles.progressMessage
];
return (
<Text style = { messageStyles }>
{ message }
</Text>
);
}
return null;
}
_onUsernameChange: (string) => void;
/**
@@ -295,14 +328,7 @@ class LoginDialog extends Component<Props, State> {
*
* @param {Object} state - The Redux state.
* @private
* @returns {{
* _conference: JitsiConference,
* _configHosts: Object,
* _connecting: boolean,
* _dialogStyles: StyleType,
* _error: Object,
* _progress: number
* }}
* @returns {Props}
*/
function _mapStateToProps(state) {
const {
@@ -323,7 +349,8 @@ function _mapStateToProps(state) {
_configHosts: configHosts,
_connecting: Boolean(connecting) || Boolean(thenableWithCancel),
_error: connectionError || authenticateAndUpgradeRoleError,
_progress: progress
_progress: progress,
_styles: ColorSchemeRegistry.get(state, 'LoginDialog')
};
}

View File

@@ -1,50 +1,41 @@
import { BoxModel, ColorPalette, createStyleSheet } from '../../base/styles';
/**
* The style common to {@code LoginDialog} and {@code WaitForOwnerDialog}.
*/
const dialog = {
marginBottom: BoxModel.margin,
marginTop: BoxModel.margin
};
/**
* The style common to {@code Text} rendered by {@code LoginDialog} and
* {@code WaitForOwnerDialog}.
*/
const text = {
color: ColorPalette.white
};
import { ColorSchemeRegistry, schemeColor } from '../../base/color-scheme';
import { BoxModel } from '../../base/styles';
/**
* The styles of the authentication feature.
*/
export default createStyleSheet({
ColorSchemeRegistry.register('LoginDialog', {
/**
* The style of {@code Text} rendered by the {@code Dialog}s of the
* feature authentication.
*/
dialogText: {
...text,
margin: BoxModel.margin,
marginTop: BoxModel.margin * 2
},
/**
* The style used when an error message is rendered.
*/
errorMessage: {
color: schemeColor('errorText')
},
/**
* The style of {@code LoginDialog}.
*/
loginDialog: {
...dialog,
flex: 0,
flexDirection: 'column'
flexDirection: 'column',
marginBottom: BoxModel.margin,
marginTop: BoxModel.margin
},
/**
* The style of {@code WaitForOwnerDialog}.
* The style used then a progress message is rendered.
*/
waitForOwnerDialog: {
...dialog,
...text
progressMessage: {
color: schemeColor('text')
}
});

View File

@@ -54,6 +54,11 @@ export type Props = {
*/
size: number,
/**
* One of the expected status strings (e.g. 'available') to render a badge on the avatar, if necessary.
*/
status?: ?string,
/**
* URL of the avatar, if any.
*/
@@ -117,6 +122,7 @@ class Avatar<P: Props> extends PureComponent<P, State> {
colorBase,
id,
size,
status,
url
} = this.props;
const { avatarFailed } = this.state;
@@ -128,6 +134,7 @@ class Avatar<P: Props> extends PureComponent<P, State> {
initials: undefined,
onAvatarLoadError: undefined,
size,
status,
url: undefined
};

View File

@@ -12,6 +12,11 @@ import styles from './styles';
type Props = AbstractProps & {
/**
* One of the expected status strings (e.g. 'available') to render a badge on the avatar, if necessary.
*/
status?: ?string,
/**
* External style passed to the componant.
*/
@@ -46,18 +51,40 @@ export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
}
return (
<View
style = { [
styles.avatarContainer(size),
style
] }>
{ avatar }
<View>
<View
style = { [
styles.avatarContainer(size),
style
] }>
{ avatar }
</View>
{ this._renderAvatarStatus() }
</View>
);
}
_isIcon: (?string | ?Object) => boolean
/**
* Renders a badge representing the avatar status.
*
* @returns {React$Elementaa}
*/
_renderAvatarStatus() {
const { size, status } = this.props;
if (!status) {
return null;
}
return (
<View style = { styles.badgeContainer }>
<View style = { styles.badge(size, status) } />
</View>
);
}
/**
* Renders the default avatar.
*

View File

@@ -1,5 +1,7 @@
// @flow
import { StyleSheet } from 'react-native';
import { ColorPalette } from '../../../styles';
const DEFAULT_SIZE = 65;
@@ -27,6 +29,38 @@ export default {
};
},
badge: (size: number = DEFAULT_SIZE, status: string) => {
let color;
switch (status) {
case 'available':
color = 'rgb(110, 176, 5)';
break;
case 'away':
color = 'rgb(250, 201, 20)';
break;
case 'busy':
color = 'rgb(233, 0, 27)';
break;
case 'idle':
color = 'rgb(172, 172, 172)';
break;
}
return {
backgroundColor: color,
borderRadius: size / 2,
bottom: 0,
height: size * 0.3,
position: 'absolute',
width: size * 0.3
};
},
badgeContainer: {
...StyleSheet.absoluteFillObject
},
initialsContainer: {
alignItems: 'center',
alignSelf: 'stretch',

View File

@@ -21,7 +21,12 @@ type Props = AbstractProps & {
/**
* ID of the component to be rendered.
*/
id?: string
id?: string,
/**
* One of the expected status strings (e.g. 'available') to render a badge on the avatar, if necessary.
*/
status?: ?string
};
/**
@@ -40,29 +45,33 @@ export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
if (this._isIcon(url)) {
return (
<div
className = { this._getAvatarClassName() }
className = { `${this._getAvatarClassName()} ${this._getBadgeClassName()}` }
id = { this.props.id }
style = { this._getAvatarStyle(this.props.color) }>
<Icon src = { url } />
<Icon
size = '50%'
src = { url } />
</div>
);
}
if (url) {
return (
<img
className = { this._getAvatarClassName() }
id = { this.props.id }
onError = { this.props.onAvatarLoadError }
src = { url }
style = { this._getAvatarStyle() } />
<div className = { this._getBadgeClassName() }>
<img
className = { this._getAvatarClassName() }
id = { this.props.id }
onError = { this.props.onAvatarLoadError }
src = { url }
style = { this._getAvatarStyle() } />
</div>
);
}
if (initials) {
return (
<div
className = { this._getAvatarClassName() }
className = { `${this._getAvatarClassName()} ${this._getBadgeClassName()}` }
id = { this.props.id }
style = { this._getAvatarStyle(this.props.color) }>
<svg
@@ -85,11 +94,13 @@ export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
// default avatar
return (
<img
className = { this._getAvatarClassName('defaultAvatar') }
id = { this.props.id }
src = { this.props.defaultAvatar || 'images/avatar.png' }
style = { this._getAvatarStyle() } />
<div className = { this._getBadgeClassName() }>
<img
className = { this._getAvatarClassName('defaultAvatar') }
id = { this.props.id }
src = { this.props.defaultAvatar || 'images/avatar.png' }
style = { this._getAvatarStyle() } />
</div>
);
}
@@ -120,5 +131,20 @@ export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
return `avatar ${additional || ''} ${this.props.className || ''}`;
}
/**
* Generates a class name to render a badge on the avatar, if necessary.
*
* @returns {string}
*/
_getBadgeClassName() {
const { status } = this.props;
if (status) {
return `avatar-badge avatar-badge-${status}`;
}
return '';
}
_isIcon: (?string | ?Object) => boolean
}

View File

@@ -10,6 +10,7 @@ export default {
// Generic app theme colors that are used accross the entire app.
// All scheme definitions below inherit these values.
background: 'rgb(255, 255, 255)',
errorText: ColorPalette.red,
icon: 'rgb(28, 32, 37)',
text: 'rgb(28, 32, 37)'
},

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