Compare commits

..

1 Commits

Author SHA1 Message Date
paweldomas
cf83b4142a ref(config): move loggingConfig to config.js 2016-12-01 16:59:39 -06:00
710 changed files with 15918 additions and 47623 deletions

View File

@@ -3,7 +3,6 @@ build/*
# Third-party source code which we (1) do not want to modify or (2) try to
# modify as little as possible.
flow-typed/*
libs/*
# ESLint will by default ignore its own configuration file. However, there does

View File

@@ -4,10 +4,7 @@ module.exports = {
'commonjs': true,
'es6': true
},
'extends': [
'eslint:recommended',
'plugin:flowtype/recommended'
],
'extends': 'eslint:recommended',
'globals': {
// The globals that (1) are accessed but not defined within many of our
// files, (2) are certainly defined, and (3) we would like to use
@@ -15,16 +12,12 @@ module.exports = {
// files.
'__filename': false
},
'parser': 'babel-eslint',
'parserOptions': {
'ecmaFeatures': {
'experimentalObjectRestSpread': true
},
'sourceType': 'module'
},
'plugins': [
'flowtype'
],
'rules': {
'new-cap': [
'error',

View File

@@ -1,72 +0,0 @@
[ignore]
; We fork some components by platform
.*/*[.]android.js
; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/
; Ignore unexpected extra "@providesModule"
.*/node_modules/.*/node_modules/fbjs/.*
; Ignore duplicate module providers
; For RN Apps installed via npm, "Libraries" folder is inside
; "node_modules/react-native" but in the source repo it is in the root
.*/Libraries/react-native/React.js
.*/Libraries/react-native/ReactNative.js
; Ignore packages in node_modules which we (i.e. the jitsi-meet project) have
; seen to cause errors and we have chosen not to fix.
.*/node_modules/babel-core/.*
.*/node_modules/bower/.*
.*/node_modules/jsonlint/.*
.*/node_modules/promise/index.js.flow
.*/node_modules/styled-components/.*
[include]
[libs]
node_modules/react-native/Libraries/react-native/react-native-interface.js
node_modules/react-native/flow
flow/
[options]
emoji=true
module.system=haste
experimental.strict_type_args=true
; FIXME: munge_underscores should be false but right now there are some errors
; if we change the value to false
; Treats class properties with underscore as private. Disabled because currently
; for us "_" can mean protected too.
; munge_underscores=false
munge_underscores=true
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FixMe
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-8]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-8]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
suppress_comment=\\(.\\|\n\\)*\\$FlowDisableNextLine
unsafe.enable_getters_and_setters=true
; We (i.e. the jitsi-meet project) are using the haste module system on Web as
; well, not only on React Native. Unfortunately, Flow does not support .web.js
; by default. Override Flow's defaults to include .web.js as well. Technically,
; we have .native.js as well so the choice of .web.js may lead to errors.
; Practically though, it is a potential future problem that we do not have at
; the time of this writing.
module.file_ext=.web.js
; Flow's defaults:
module.file_ext=.js
module.file_ext=.jsx
module.file_ext=.json
[version]
^0.38.0

1
.gitattributes vendored
View File

@@ -1,3 +1,2 @@
*.bundle.js -text -diff
*.pbxproj -text
lib-jitsi-meet.js -text -diff

25
.gitignore vendored
View File

@@ -4,6 +4,7 @@ deploy-local.sh
libs/
all.css
*css.map
unsupported_browser.css
.remote-sync.json
.sync-config.cson
@@ -35,37 +36,21 @@ DerivedData
*.xcuserstate
project.xcworkspace
# Android/IntelliJ
# Android/IJ
#
build/
*.iml
.idea
.gradle
local.properties
*.iml
# node.js
#
node_modules/
npm-debug.log
yarn-error.log
# BUCK
#
buck-out/
\.buckd/
*.keystore
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use
# fastlane to re-generate the screenshots whenever they are needed. For more
# information about the recommended setup visit:
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
#
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
# CocoaPods
Pods/
Podfile.lock
android/app/libs
android/keystores/debug.keystore

View File

@@ -1,22 +1,7 @@
# The following do not need to be checked because they do not represent JS
# source code.
build/
debian/
libs/
node_modules/
# The following are checked by ESLint with the maximum configuration which
# supersedes JSHint.
flow-typed/
modules/API/
modules/remotecontrol/
modules/transport/
react/
# The following are checked by ESLint with the minimum configuration which does
# not supersede JSHint but take advantage of advanced language features such as
# Facebook Flow which are not supported by JSHint.
app.js
modules/translation/translation.js
analytics.js
webpack.config.babel.js

View File

@@ -1,7 +1,7 @@
<html>
<head>
<link rel="stylesheet" href="../css/all.css"/>
<!--#include virtual="/title.html" -->
<link rel="stylesheet" href="css/all.css"/>
<!--#include virtual="title.html" -->
</head>
<body>
<div class="error_page">

View File

@@ -1,29 +0,0 @@
# How to contribute
We would love to have your help. Before you start working however, please read
and follow this short guide.
# Reporting Issues
Provide as much information as possible. Mention the version of Jitsi Meet,
Jicofo and JVB you are using, and explain (as detailed as you can) how the
problem can be reproduced.
# Code contributions
Found a bug and know how to fix it? Great! Please read on.
## Contributor License Agreement
While the Jitsi projects are released under the
[Apache License 2.0](https://github.com/jitsi/jitsi-meet/blob/master/LICENSE), the copyright
holder and principal creator is [Atlassian](https://www.atlassian.com/). To
ensure that we can continue making these projects available under an Open Source license,
we need you to sign our Apache-based contributor
license agreement as either a [corporation](https://jitsi.org/ccla) or an
[individual](https://jitsi.org/icla). If you cannot accept the terms laid out
in the agreement, unfortunately, we cannot accept your contribution.
## Creating Pull Requests
- Make sure your code passes the linter rules beforehand. The linter is exeuted
automatically when committing code.
- Perform **one** logical change per pull request.
- Maintain a clean list of commits, squash them if necessary.
- Rebase your topic branch on top of the master branch before creating the pull
request.

View File

@@ -1,11 +0,0 @@
/**
* Notifies interested parties that hangup procedure will start.
*/
export const BEFORE_HANGUP = "conference.before_hangup";
/**
* Notifies interested parties that desktop sharing enable/disable state is
* changed.
*/
export const DESKTOP_SHARING_ENABLED_CHANGED
= "conference.desktop_sharing_enabled_changed";

View File

@@ -8,9 +8,16 @@ OUTPUT_DIR = .
STYLES_BUNDLE = css/all.bundle.css
STYLES_DESTINATION = css/all.css
STYLES_MAIN = css/main.scss
STYLES_UNSUPPORTED_BROWSER = css/unsupported_browser.scss
WEBPACK = ./node_modules/.bin/webpack
all: compile deploy clean
all: update-deps compile deploy clean
# FIXME: there is a problem with node-sass not correctly installed (compiled)
# a quick fix to make sure it is installed on every update
# the problem appears on linux and not on macosx
update-deps:
$(NPM) update && $(NPM) install node-sass
compile:
$(WEBPACK) -p
@@ -27,12 +34,8 @@ deploy-appbundle:
cp \
$(BUILD_DIR)/app.bundle.min.js \
$(BUILD_DIR)/app.bundle.min.map \
$(BUILD_DIR)/do_external_connect.min.js \
$(BUILD_DIR)/do_external_connect.min.map \
$(BUILD_DIR)/external_api.min.js \
$(BUILD_DIR)/external_api.min.map \
$(BUILD_DIR)/device_selection_popup_bundle.min.js \
$(BUILD_DIR)/device_selection_popup_bundle.min.map \
$(OUTPUT_DIR)/analytics.js \
$(DEPLOY_DIR)
@@ -44,6 +47,7 @@ deploy-lib-jitsi-meet:
$(DEPLOY_DIR)
deploy-css:
$(NODE_SASS) css/unsupported_browser.scss css/unsupported_browser.css ; \
$(NODE_SASS) $(STYLES_MAIN) $(STYLES_BUNDLE) && \
$(CLEANCSS) $(STYLES_BUNDLE) > $(STYLES_DESTINATION) ; \
rm $(STYLES_BUNDLE)
@@ -53,7 +57,8 @@ deploy-local:
source-package:
mkdir -p source_package/jitsi-meet/css && \
cp -r *.js *.html connection_optimization favicon.ico fonts images libs static sounds LICENSE lang source_package/jitsi-meet && \
cp -r *.js *.html connection_optimization favicon.ico fonts images libs sounds LICENSE lang source_package/jitsi-meet && \
cp css/all.css source_package/jitsi-meet/css && \
cp css/unsupported_browser.css source_package/jitsi-meet/css && \
(cd source_package ; tar cjf ../jitsi-meet.tar.bz2 jitsi-meet) && \
rm -rf source_package

View File

@@ -1,5 +1,5 @@
# Jitsi Meet - Secure, Simple and Scalable Video Conferences
Jitsi Meet - Secure, Simple and Scalable Video Conferences
====
Jitsi Meet is an open-source (Apache) WebRTC JavaScript application that uses [Jitsi Videobridge](https://jitsi.org/videobridge) to provide high quality, scalable video conferences. You can see [Jitsi Meet in action](http://youtu.be/7vFUVClsNh0) here at the session #482 of the VoIP Users Conference.
You can also try it out yourself at https://meet.jit.si .
@@ -12,23 +12,9 @@ Installing Jitsi Meet is quite a simple experience. For Debian-based systems, we
For other systems, or if you wish to install all components manually, see the [detailed manual installation instructions](https://github.com/jitsi/jitsi-meet/blob/master/doc/manual-install.md).
## Download
You can download Debian/Ubuntu binaries:
* [stable](https://download.jitsi.org/stable/) ([instructions](https://jitsi.org/downloads/ubuntu-debian-installations-instructions/))
* [testing](https://download.jitsi.org/testing/) ([instructions](https://jitsi.org/downloads/ubuntu-debian-installations-instructions-for-testing/))
* [nightly](https://download.jitsi.org/unstable/) ([instructions](https://jitsi.org/downloads/ubuntu-debian-installations-instructions-nightly/))
You can download source archives (produced by ```make source-package```):
* [source builds](https://download.jitsi.org/jitsi-meet/src/)
You can get our mobile versions from here:
* [Android](https://play.google.com/store/apps/details?id=org.jitsi.meet)
* [iOS](https://itunes.apple.com/us/app/jitsi-meet/id1165103905)
## Building the sources
Node.js >= 6 is required.
Jitsi Meet uses [Browserify](http://browserify.org). If you want to make changes in the code you need to [install Browserify](http://browserify.org/#install). Browserify requires [nodejs](http://nodejs.org).
On Debian/Ubuntu systems, the required packages can be installed with:
```
@@ -42,7 +28,7 @@ To build the Jitsi Meet application, just type
make
```
## Working with the library sources (lib-jitsi-meet)
## Working with the library sources(lib-jitsi-meet).
By default the library is build from its git repository sources. The default dependency path in package.json is :
```json
@@ -89,18 +75,8 @@ npm unlink lib-jitsi-meet
npm install
```
## Contributing
If you are looking to contribute to Jitsi Meet, first of all, thank you! Please
see our [guidelines for contributing](CONTRIBUTING.md).
## Embedding in external applications
Jitsi Meet provides a very flexible way of embedding it in external applications by using the [Jitsi Meet API](doc/api.md).
## Mobile app
Jitsi Meet is also available as a React Native application for Android and iOS.
Instructions on how to build it can be found [here](doc/mobile.md).
## Discuss
Please use the [Jitsi dev mailing list](http://lists.jitsi.org/pipermail/dev/) to discuss feature requests before opening an issue on Github.
## Acknowledgements

View File

@@ -1,216 +0,0 @@
# Jitsi Meet SDK for Android
This directory contains the source code of the Jitsi Meet app and the Jitsi Meet
SDK for Android.
## Jitsi Meet SDK
Jitsi Meet SDK is an Android library which embodies the whole Jitsi Meet
experience and makes it reusable by third-party apps.
To get started, extends your `android.app.Activity` from
`org.jitsi.meet.sdk.JitsiMeetActivity`:
```java
package org.jitsi.example;
import org.jitsi.meet.sdk.JitsiMeetActivity;
public class MainActivity extends JitsiMeetActivity {
}
```
Alternatively, you can use the `org.jitsi.meet.sdk.JitsiMeetView` class which
extends `android.view.View`:
```java
package org.jitsi.example;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import org.jitsi.meet.sdk.JitsiMeetView;
public class MainActivity extends AppCompatActivity {
private JitsiMeetView view;
@Override
public void onBackPressed() {
if (!JitsiMeetView.onBackPressed()) {
// Invoke the default handler if it wasn't handled by React.
super.onBackPressed();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view = new JitsiMeetView(this);
view.loadURL(null);
setContentView(view);
}
@Override
protected void onDestroy() {
super.onDestroy();
JitsiMeetView.onHostDestroy(this);
}
@Override
public void onNewIntent(Intent intent) {
JitsiMeetView.onNewIntent(intent);
}
@Override
protected void onPause() {
super.onPause();
JitsiMeetView.onHostPause(this);
}
@Override
protected void onResume() {
super.onResume();
JitsiMeetView.onHostResume(this);
}
}
```
### JitsiMeetActivity
This class encapsulates a high level API in the form of an Android `Activity`
which displays a single `JitsiMeetView`.
#### getWelcomePageEnabled()
See JitsiMeetView.getWelcomePageEnabled.
#### loadURL(URL)
See JitsiMeetView.loadURL.
#### loadURLString(String)
See JitsiMeetView.loadURLString.
#### setWelcomePageEnabled(boolean)
See JitsiMeetView.setWelcomePageEnabled.
### JitsiMeetView
The `JitsiMeetView` class is the core of Jitsi Meet SDK. It's designed to
display a Jitsi Meet conference (or a welcome page).
#### getListener()
Returns the `JitsiMeetViewListener` instance attached to the view.
#### getWelcomePageEnabled()
Returns true if the Welcome page is enabled; otherwise, false. If false, a black
empty view will be rendered when not in a conference. Defaults to false.
#### loadURL(URL)
Loads a specific URL which may identify a conference to join. If the specified
URL is null, the Welcome page is displayed instead.
#### loadURLString(String)
Loads a specific URL which may identify a conference to join. If the specified
URL is null, the Welcome page is displayed instead.
#### setListener(listener)
Sets the given listener (class implementing the `JitsiMeetViewListener`
interface) on the view.
#### setWelcomePageEnabled(boolean)
Sets whether the Welcome page is enabled. See `getWelcomePageEnabled` for more
information.
NOTE: Must be called before `loadURL`/`loadURLString` for it to take effect.
#### onBackPressed()
Helper method which should be called from the activity's `onBackPressed` method.
If this function returns `true`, it means the action was handled and thus no
extra processing is required; otherwise the app should call the parent's
`onBackPressed` method.
This is a static method.
#### onHostDestroy(activity)
Helper method which should be called from the activity's `onDestroy` method.
This is a static method.
#### onHostPause(activity)
Helper method which should be called from the activity's `onPause` method.
This is a static method.
#### onHostResume(activity)
Helper method which should be called from the activity's `onResume` method.
This is a static method.
#### onNewIntent(intent)
Helper method for integrating the *deep linking* functionality. If your app's
activity is launched in "singleTask" mode this method should be called from the
activity's `onNewIntent` method.
This is a static method.
#### JitsiMeetViewListener
`JitsiMeetViewListener` provides an interface apps can implement to listen to
the state of the Jitsi Meet conference displayed in a `JitsiMeetView`.
### JitsiMeetViewAdapter
A default implementation of the `JitsiMeetViewListener` interface. Apps may
extend the class instead of implementing the interface in order to minimize
boilerplate.
##### onConferenceFailed
Called when a joining a conference was unsuccessful or when there was an error
while in a conference.
The `data` HashMap contains an "error" key describing the error and a "url"
key with the conference URL.
#### onConferenceJoined
Called when a conference was joined.
The `data` HashMap contains a "url" key with the conference URL.
#### onConferenceLeft
Called when a conference was left.
The `data` HashMap contains a "url" key with the conference URL.
#### onConferenceWillJoin
Called before a conference is joined.
The `data` HashMap contains a "url" key with the conference URL.
#### onConferenceWillLeave
Called before a conference is left.
The `data` HashMap contains a "url" key with the conference URL.

66
android/app/BUCK Normal file
View File

@@ -0,0 +1,66 @@
import re
# To learn about Buck see [Docs](https://buckbuild.com/).
# To run your application with Buck:
# - install Buck
# - `npm start` - to start the packager
# - `cd android`
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
# - `buck install -r android/app` - compile, install and run application
#
lib_deps = []
for jarfile in glob(['libs/*.jar']):
name = 'jars__' + re.sub(r'^.*/([^/]+)\.jar$', r'\1', jarfile)
lib_deps.append(':' + name)
prebuilt_jar(
name = name,
binary_jar = jarfile,
)
for aarfile in glob(['libs/*.aar']):
name = 'aars__' + re.sub(r'^.*/([^/]+)\.aar$', r'\1', aarfile)
lib_deps.append(':' + name)
android_prebuilt_aar(
name = name,
aar = aarfile,
)
android_library(
name = 'all-libs',
exported_deps = lib_deps
)
android_library(
name = 'app-code',
srcs = glob([
'src/main/java/**/*.java',
]),
deps = [
':all-libs',
':build_config',
':res',
],
)
android_build_config(
name = 'build_config',
package = 'org.jitsi.jitsi_meet_react',
)
android_resource(
name = 'res',
res = 'src/main/res',
package = 'org.jitsi.jitsi_meet_react',
)
android_binary(
name = 'app',
package_type = 'debug',
manifest = 'src/main/AndroidManifest.xml',
keystore = '//android/keystores:debug',
deps = [
':app-code',
],
)

View File

@@ -1,41 +1,173 @@
buildscript {
repositories {
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
classpath 'io.fabric.tools:gradle:1.+'
}
}
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
import com.android.build.OutputFile
/**
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
* and bundleReleaseJsAndAssets).
* These basically call `react-native bundle` with the correct arguments during the Android build
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
* bundle directly from the development server. Below you can see all the possible configurations
* and their defaults. If you decide to add a configuration block, make sure to add it before the
* `apply from: "../../node_modules/react-native/react.gradle"` line.
*
* project.ext.react = [
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
* // the entry file for bundle generation
* entryFile: "index.android.js",
*
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
* // whether to bundle JS and assets in release mode
* bundleInRelease: true,
*
* // whether to bundle JS and assets in another build variant (if configured).
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
* // The configuration property can be in the following formats
* // 'bundleIn${productFlavor}${buildType}'
* // 'bundleIn${buildType}'
* // bundleInFreeDebug: true,
* // bundleInPaidRelease: true,
* // bundleInBeta: true,
*
* // the root of your project, i.e. where "package.json" lives
* root: "../../",
*
* // where to put the JS bundle asset in debug mode
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
*
* // where to put the JS bundle asset in release mode
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in debug mode
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in release mode
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
*
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
* // for example, you might want to remove it from here.
* inputExcludes: ["android/**", "ios/**"],
*
* // override which node gets called and with what additional arguments
* nodeExecutableAndArgs: ["node"]
*
* // supply additional arguments to the packager
* extraPackagerArgs: []
* ]
*/
apply from: '../../node_modules/react-native/react.gradle'
/**
* Set this to true to create two separate APKs instead of one:
* - An APK that only works on ARM devices
* - An APK that only works on x86 devices
* The advantage is the size of the APK is reduced by about 4MB.
* Upload all the APKs to the Play Store and people will download
* the correct one based on the CPU architecture of their device.
*/
def enableSeparateBuildPerCPUArchitecture = false
/**
* Run Proguard to shrink the Java bytecode in release builds.
*/
def enableProguardInReleaseBuilds = false
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
compileSdkVersion 23
buildToolsVersion '23.0.1'
defaultConfig {
applicationId 'org.jitsi.meet'
versionCode Integer.parseInt("${version}")
versionName "1.4.${version}"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
applicationId 'org.jitsi.jitsi_meet_react'
minSdkVersion 16
targetSdkVersion 22
versionCode 1
versionName '1.0'
ndk {
abiFilters 'armeabi-v7a', 'x86'
}
packagingOptions {
// The project react-native does not provide 64-bit binaries at the
// time of this writing. Unfortunately, packaging any 64-bit
// binaries into the .apk will crash the app at runtime on 64-bit
// platforms.
exclude '/lib/mips64/**'
exclude '/lib/arm64-v8a/**'
exclude '/lib/x86_64/**'
exclude 'lib/x86_64/libjingle_peerconnection_so.so'
exclude 'lib/arm64-v8a/libjingle_peerconnection_so.so'
}
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include 'armeabi-v7a', 'x86'
}
}
buildTypes {
release {
minifyEnabled false
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
def versionCodes = ['armeabi-v7a':1, 'x86':2]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':sdk')
if (project.hasProperty('JITSI_SIGNING')
&& new File(project.property('JITSI_SIGNING')).exists()) {
apply from: project.property('JITSI_SIGNING');
}
repositories {
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
compile project(':react-native-vector-icons')
compile project(':react-native-webrtc')
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.facebook.react:react-native:+'
compile('com.crashlytics.sdk.android:crashlytics:2.6.5@aar') {
transitive = true
}
}
apply from: '../../node_modules/react-native-vector-icons/fonts.gradle'
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
}

View File

@@ -1,36 +1,50 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.jitsi.meet">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.jitsi.jitsi_meet_react"
android:versionCode="1"
android:versionName="1.0">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><!-- WebRTC -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="22" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:launchMode="singleTask"
android:name=".MainActivity"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:host="beta.hipchat.me" android:scheme="https" />
<data android:host="beta.meet.jit.si" android:scheme="https" />
<data android:host="chaos.hipchat.me" android:scheme="https" />
<data android:host="enso.me" android:scheme="https" />
<data android:host="hipchat.me" android:scheme="https" />
<data android:host="meet.jit.si" android:scheme="https" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="org.jitsi.meet" />
</intent-filter>
</activity>
</application>
android:name=".MainApplication"
android:theme="@style/AppTheme">
<activity
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTask"
android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:host="beta.meet.jit.si" android:scheme="https" />
<data android:host="chaos.hipchat.me" android:scheme="https" />
<data android:host="enso.me" android:scheme="https" />
<data android:host="meet.jit.si" android:scheme="https" />
</intent-filter>
</activity>
<activity
android:name="com.facebook.react.devsupport.DevSettingsActivity" />
<meta-data
android:name="io.fabric.ApiKey"
android:value="a8ae24a58302ba79da1d312138e941f6b86e3242" />
</application>
</manifest>

Binary file not shown.

View File

@@ -0,0 +1,56 @@
package org.jitsi.jitsi_meet_react;
import android.os.Bundle;
import com.crashlytics.android.Crashlytics;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import io.fabric.sdk.android.Fabric;
public class MainActivity extends ReactActivity {
/**
* {@inheritDoc}
*
* Overrides {@link ReactActivity#createRootActivityDelegate()} to customize
* the {@link ReactRootView} with a background color that is in accord with
* the JavaScript and iOS parts of the application and causes less perceived
* visual flicker than the default background color.
*/
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this, getMainComponentName()) {
/**
* {@inheritDoc}
*
* Overrides {@link ReactActivityDelegate#createRootView()} to
* customize the {@link ReactRootView} with a background color that
* is in accord with the JavaScript and iOS parts of the application
* and causes less perceived visual flicker than the default
* background color.
*/
@Override
protected ReactRootView createRootView() {
ReactRootView rootView = super.createRootView();
rootView.setBackgroundColor(0xFF111111);
return rootView;
}
};
}
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "App";
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Fabric.with(this, new Crashlytics());
}
}

View File

@@ -0,0 +1,39 @@
package org.jitsi.jitsi_meet_react;
import android.app.Application;
import android.util.Log;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.oblador.vectoricons.VectorIconsPackage;
import com.oney.WebRTCModule.WebRTCModulePackage;
import java.util.Arrays;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new VectorIconsPackage(),
new WebRTCModulePackage()
);
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
}

View File

@@ -1,49 +0,0 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet;
import android.os.Bundle;
import org.jitsi.meet.sdk.JitsiMeetActivity;
/**
* The one and only {@link Activity} that the Jitsi Meet app needs. The
* {@code Activity} is launched in {@code singleTask} mode, so it will be
* created upon application initialization and there will be a single instance
* of it. Further attempts at launching the application once it was already
* launched will result in {@link Activity#onNewIntent(Intent)} being called.
*
* This {@code Activity} extends {@link JitsiMeetActivity} to keep the React
* Native CLI working, since the latter always tries to launch an
* {@code Activity} named {@code MainActivity} when doing
* {@code react-native run-android}.
*/
public class MainActivity extends JitsiMeetActivity {
/**
* {@inheritDoc}
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
// As this is the Jitsi Meet app (i.e. not the Jitsi Meet SDK), we do
// want the Welcome page to be enabled. It defaults to disabled in the
// SDK at the time of this writing but it is clearer to be explicit
// about what we want anyway.
setWelcomePageEnabled(true);
super.onCreate(savedInstanceState);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -1,7 +1,8 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>

View File

@@ -1,16 +1,14 @@
// Top-level build file where you can add configuration options common to all
// sub-projects/modules.
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
maven { url 'https://maven.google.com' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-alpha6'
classpath 'com.android.tools.build:gradle:1.3.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files.
// in the individual module build.gradle files
}
}
@@ -19,30 +17,8 @@ allprojects {
mavenLocal()
jcenter()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is
// installed from npm.
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
}
}
ext {
compileSdkVersion = 25
buildToolsVersion = "25.0.3"
minSdkVersion = 16
targetSdkVersion = 23
}
// 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.
subprojects { subproject ->
afterEvaluate{
if (subproject.plugins.hasPlugin('android')
|| subproject.plugins.hasPlugin('android-library')) {
android {
buildToolsVersion rootProject.ext.buildToolsVersion
}
}
}
}

View File

@@ -18,4 +18,3 @@
# org.gradle.parallel=true
android.useDeprecatedNdk=true
version=1

View File

@@ -1,6 +1,5 @@
#Mon Jul 17 18:25:08 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-milestone-1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip

View File

@@ -1,121 +0,0 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
publishNonDefault true
}
buildTypes {
debug {}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.facebook.react:react-native:+'
compile project(':react-native-background-timer')
compile project(':react-native-immersive')
compile project(':react-native-keep-awake')
compile project(':react-native-vector-icons')
compile project(':react-native-webrtc')
}
// Build process helpers
//
void runBefore(String dependentTaskName, Task task) {
Task dependentTask = tasks.findByPath(dependentTaskName);
if (dependentTask != null) {
dependentTask.dependsOn task
}
}
gradle.projectsEvaluated {
android.buildTypes.all { buildType ->
def buildNameCapitalized = "${buildType.name.capitalize()}"
def bundlePath = "${buildDir}/intermediates/bundles/${buildType.name}"
// Bundle fonts in react-native-vector-icons.
//
def currentFontTask = tasks.create(
name: "copy${buildNameCapitalized}Fonts",
type: Copy) {
from("${projectDir}/../../fonts/jitsi.ttf")
from("${projectDir}/../../node_modules/react-native-vector-icons/Fonts/")
into("${bundlePath}/assets/fonts")
}
currentFontTask.dependsOn("merge${buildNameCapitalized}Resources")
currentFontTask.dependsOn("merge${buildNameCapitalized}Assets")
runBefore("processArmeabi-v7a${buildNameCapitalized}Resources", currentFontTask)
runBefore("processX86${buildNameCapitalized}Resources", currentFontTask)
runBefore("processUniversal${buildNameCapitalized}Resources", currentFontTask)
runBefore("process${buildNameCapitalized}Resources", currentFontTask)
// Bundle JavaScript and React resources.
// (adapted from react-native/react.gradle)
//
// React JS bundle directories
def jsBundleDir = file("${bundlePath}/assets")
def resourcesDir = file("${bundlePath}/res/merged")
def jsBundleFile = file("${jsBundleDir}/index.android.bundle")
// Bundle task name for variant.
def bundleJsAndAssetsTaskName = "bundle${buildNameCapitalized}JsAndAssets"
def currentBundleTask = tasks.create(
name: bundleJsAndAssetsTaskName,
type: Exec) {
// Set up inputs and outputs so gradle can cache the result.
def reactRoot = file("${projectDir}/../../")
inputs.files fileTree(dir: reactRoot, excludes: ['android/**', 'ios/**'])
outputs.dir jsBundleDir
outputs.dir resourcesDir
// Set up the call to the react-native cli.
workingDir reactRoot
// Create JS bundle
def devEnabled = !buildNameCapitalized.toLowerCase().contains('release')
commandLine(
'node',
'node_modules/react-native/local-cli/cli.js',
'bundle',
'--assets-dest', resourcesDir,
'--bundle-output', jsBundleFile,
'--dev', "${devEnabled}",
'--entry-file', 'index.android.js',
'--platform', 'android',
'--reset-cache')
// Disable bundling on dev builds
enabled !devEnabled
}
// Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process
currentBundleTask.dependsOn("merge${buildNameCapitalized}Resources")
currentBundleTask.dependsOn("merge${buildNameCapitalized}Assets")
runBefore("processArmeabi-v7a${buildNameCapitalized}Resources", currentBundleTask)
runBefore("processX86${buildNameCapitalized}Resources", currentBundleTask)
runBefore("processUniversal${buildNameCapitalized}Resources", currentBundleTask)
runBefore("process${buildNameCapitalized}Resources", currentBundleTask)
}
}

View File

@@ -1,25 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/scorretge/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -1,24 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.jitsi.meet.sdk">
<!-- XXX: ACCESS_NETWORK_STATE is required by WebRTC. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus"/>
<!-- Tell the system this app requires OpenGL ES 2.0. -->
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<application android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true">
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
</manifest>

View File

@@ -1,199 +0,0 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet.sdk;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import java.net.URL;
/**
* Base Activity for applications integrating Jitsi Meet at a higher level. It
* contains all the required wiring between the <tt>JKConferenceView</tt> and
* the Activity lifecycle methods already implemented.
*
* In this activity we use a single <tt>JKConferenceView</tt> instance. This
* instance gives us access to a view which displays the welcome page and the
* conference itself. All lifetime methods associated with this Activity are
* hooked to the React Native subsystem via proxy calls through the
* <tt>JKConferenceView</tt> static methods.
*/
public class JitsiMeetActivity extends AppCompatActivity {
/**
* The request code identifying requests for the permission to draw on top
* of other apps. The value must be 16-bit and is arbitrarily chosen here.
*/
private static final int OVERLAY_PERMISSION_REQUEST_CODE
= (int) (Math.random() * Short.MAX_VALUE);
/**
* Instance of the {@link JitsiMeetView} which this activity will display.
*/
private JitsiMeetView view;
/**
* Whether the Welcome page is enabled. The value is used only while
* {@link #view} equals {@code null}.
*/
private boolean welcomePageEnabled;
private boolean canRequestOverlayPermission() {
return
BuildConfig.DEBUG
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& getApplicationInfo().targetSdkVersion
>= Build.VERSION_CODES.M;
}
/**
*
* @see JitsiMeetView#getWelcomePageEnabled
*/
public boolean getWelcomePageEnabled() {
return view == null ? welcomePageEnabled : view.getWelcomePageEnabled();
}
/**
* Initializes the {@link #view} of this {@code JitsiMeetActivity} with a
* new {@link JitsiMeetView} instance.
*/
private void initializeView() {
view = new JitsiMeetView(this);
// In order to have the desired effect
// JitsiMeetView#setWelcomePageEnabled(boolean) must be invoked before
// JitsiMeetView#loadURL(URL).
view.setWelcomePageEnabled(welcomePageEnabled);
view.loadURL(null);
setContentView(view);
}
/**
* Loads the given URL and displays the conference. If the specified URL is
* null, the welcome page is displayed instead.
*
* @param url - The conference URL.
*/
public void loadURL(@Nullable URL url) {
view.loadURL(url);
}
/**
* {@inheritDoc}
*/
@Override
protected void onActivityResult(
int requestCode,
int resultCode,
Intent data) {
if (requestCode == OVERLAY_PERMISSION_REQUEST_CODE
&& canRequestOverlayPermission()) {
if (Settings.canDrawOverlays(this)) {
initializeView();
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void onBackPressed() {
if (!JitsiMeetView.onBackPressed()) {
// Invoke the default handler if it wasn't handled by React.
super.onBackPressed();
}
}
/**
* {@inheritDoc}
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// In Debug builds React needs permission to write over other apps in
// order to display the warning and error overlays.
if (canRequestOverlayPermission() && !Settings.canDrawOverlays(this)) {
Intent intent
= new Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST_CODE);
return;
}
initializeView();
}
/**
* {@inheritDoc}
*/
@Override
protected void onDestroy() {
super.onDestroy();
JitsiMeetView.onHostDestroy(this);
}
/**
* {@inheritDoc}
*/
@Override
public void onNewIntent(Intent intent) {
JitsiMeetView.onNewIntent(intent);
}
/**
* {@inheritDoc}
*/
@Override
protected void onPause() {
super.onPause();
JitsiMeetView.onHostPause(this);
}
/**
* {@inheritDoc}
*/
@Override
protected void onResume() {
super.onResume();
JitsiMeetView.onHostResume(this);
}
/**
*
* @see JitsiMeetView#setWelcomePageEnabled
*/
public void setWelcomePageEnabled(boolean welcomePageEnabled) {
if (view == null) {
this.welcomePageEnabled = welcomePageEnabled;
} else {
view.setWelcomePageEnabled(welcomePageEnabled);
}
}
}

View File

@@ -1,290 +0,0 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet.sdk;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.widget.FrameLayout;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.common.LifecycleState;
import java.net.URL;
import java.util.Collections;
import java.util.Set;
import java.util.UUID;
import java.util.WeakHashMap;
public class JitsiMeetView extends FrameLayout {
/**
* Background color used by {@code JitsiMeetView} and the React Native root
* view.
*/
private static final int BACKGROUND_COLOR = 0xFF111111;
/**
* React Native bridge. The instance manager allows embedding applications
* to create multiple root views off the same JavaScript bundle.
*/
private static ReactInstanceManager reactInstanceManager;
private static final Set<JitsiMeetView> views
= Collections.newSetFromMap(new WeakHashMap<JitsiMeetView, Boolean>());
public static JitsiMeetView findViewByExternalAPIScope(
String externalAPIScope) {
for (JitsiMeetView view : views) {
if (view.externalAPIScope.equals(externalAPIScope)) {
return view;
}
}
return null;
}
/**
* Internal method to initialize the React Native instance manager. We
* create a single instance in order to load the JavaScript bundle a single
* time. All <tt>ReactRootView</tt> instances will be tied to the one and
* only <tt>ReactInstanceManager</tt>.
*
* @param application - <tt>Application</tt> instance which is running.
*/
private static void initReactInstanceManager(Application application) {
reactInstanceManager
= ReactInstanceManager.builder()
.setApplication(application)
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
.addPackage(new com.corbt.keepawake.KCKeepAwakePackage())
.addPackage(new com.facebook.react.shell.MainReactPackage())
.addPackage(new com.oblador.vectoricons.VectorIconsPackage())
.addPackage(new com.ocetnik.timer.BackgroundTimerPackage())
.addPackage(new com.oney.WebRTCModule.WebRTCModulePackage())
.addPackage(new com.rnimmersive.RNImmersivePackage())
.addPackage(new org.jitsi.meet.sdk.audiomode.AudioModePackage())
.addPackage(
new org.jitsi.meet.sdk.externalapi.ExternalAPIPackage())
.addPackage(new org.jitsi.meet.sdk.proximity.ProximityPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
}
/**
* Activity lifecycle method which should be called from
* <tt>Activity.onBackPressed</tt> so we can do the required internal
* processing.
*
* @return - true if the back-press was processed, false otherwise. In case
* false is returned the application should call the parent's
* implementation.
*/
public static boolean onBackPressed() {
if (reactInstanceManager != null) {
reactInstanceManager.onBackPressed();
return true;
} else {
return false;
}
}
/**
* Activity lifecycle method which should be called from
* <tt>Activity.onDestroy</tt> so we can do the required internal
* processing.
*
* @param activity - <tt>Activity</tt> being destroyed.
*/
public static void onHostDestroy(Activity activity) {
if (reactInstanceManager != null) {
reactInstanceManager.onHostDestroy(activity);
}
}
/**
* Activity lifecycle method which should be called from
* <tt>Activity.onPause</tt> so we can do the required internal processing.
*
* @param activity - <tt>Activity</tt> being paused.
*/
public static void onHostPause(Activity activity) {
if (reactInstanceManager != null) {
reactInstanceManager.onHostPause(activity);
}
}
/**
* Activity lifecycle method which should be called from
* <tt>Activity.onResume</tt> so we can do the required internal processing.
*
* @param activity - <tt>Activity</tt> being resumed.
*/
public static void onHostResume(Activity activity) {
if (reactInstanceManager != null) {
reactInstanceManager.onHostResume(activity, null);
}
}
/**
* Activity lifecycle method which should be called from
* <tt>Activity.onNewIntent</tt> so we can do the required internal
* processing. Note that this is only needed if the activity's "launchMode"
* was set to "singleTask". This is required for deep linking to work once
* the application is already running.
*
* @param intent - <tt>Intent</tt> instance which was received.
*/
public static void onNewIntent(Intent intent) {
if (reactInstanceManager != null) {
reactInstanceManager.onNewIntent(intent);
}
}
/**
* The unique identifier of this {@code JitsiMeetView} within the process
* for the purposes of {@link ExternalAPI}. The name scope was inspired by
* postis which we use on Web for the similar purposes of the iframe-based
* external API.
*/
private final String externalAPIScope;
/**
* {@link JitsiMeetViewListener} instance for reporting events occurring in
* Jitsi Meet.
*/
private JitsiMeetViewListener listener;
/**
* React Native root view.
*/
private ReactRootView reactRootView;
/**
* Whether the Welcome page is enabled.
*/
private boolean welcomePageEnabled;
public JitsiMeetView(@NonNull Context context) {
super(context);
setBackgroundColor(BACKGROUND_COLOR);
if (reactInstanceManager == null) {
initReactInstanceManager(((Activity) context).getApplication());
}
// Hook this JitsiMeetView into ExternalAPI.
externalAPIScope = UUID.randomUUID().toString();
views.add(this);
}
/**
* Gets the {@link JitsiMeetViewListener} set on this {@code JitsiMeetView}.
*
* @return The {@code JitsiMeetViewListener} set on this
* {@code JitsiMeetView}.
*/
public JitsiMeetViewListener getListener() {
return listener;
}
/**
* Gets whether the Welcome page is enabled. If {@code true}, the Welcome
* page is rendered when this {@code JitsiMeetView} is not at a URL
* identifying a Jitsi Meet conference/room.
*
* @return {@true} if the Welcome page is enabled; otherwise, {@code false}.
*/
public boolean getWelcomePageEnabled() {
return welcomePageEnabled;
}
/**
* Loads a specific {@link URL} which may identify a conference to join. If
* the specified {@code URL} is {@code null}, the Welcome page is displayed
* instead.
*
* @param url - The {@code URL} to load which may identify a conference to
* join.
*/
public void loadURL(@Nullable URL url) {
loadURLString(url == null ? null : url.toString());
}
/**
* Loads a specific URL {@link String} which may identify a conference to
* join. If the specified URL {@code String} is {@code null}, the Welcome
* page is displayed instead.
*
* @param urlString - The URL {@code String} to load which may identify a
* conference to join.
*/
public void loadURLString(@Nullable String urlString) {
Bundle props = new Bundle();
// externalAPIScope
props.putString("externalAPIScope", externalAPIScope);
// url
if (urlString != null) {
props.putString("url", urlString);
}
// welcomePageEnabled
props.putBoolean("welcomePageEnabled", welcomePageEnabled);
// TODO: ReactRootView#setAppProperties is only available on React
// Native 0.45, so destroy the current root view and create a new one.
if (reactRootView != null) {
removeView(reactRootView);
reactRootView = null;
}
reactRootView = new ReactRootView(getContext());
reactRootView
.startReactApplication(reactInstanceManager, "App", props);
reactRootView.setBackgroundColor(BACKGROUND_COLOR);
addView(reactRootView);
}
/**
* Sets a specific {@link JitsiMeetViewListener} on this
* {@code JitsiMeetView}.
*
* @param listener - The {@code JitsiMeetViewListener} to set on this
* {@code JitsiMeetView}.
*/
public void setListener(JitsiMeetViewListener listener) {
this.listener = listener;
}
/**
* Sets whether the Welcome page is enabled. Must be called before
* {@link #loadURL(URL)} for it to take effect.
*
* @param welcomePageEnabled {@code true} to enable the Welcome page;
* otherwise, {@code false}.
*/
public void setWelcomePageEnabled(boolean welcomePageEnabled) {
this.welcomePageEnabled = welcomePageEnabled;
}
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet.sdk;
import java.util.Map;
/**
* Implements {@link JitsiMeetViewListener} so apps don't have to add stubs for
* all methods in the interface if they are only interested in some.
*/
public abstract class JitsiMeetViewAdapter implements JitsiMeetViewListener {
/**
* {@inheritDoc}
*/
@Override
public void onConferenceFailed(Map<String, Object> data) {
}
/**
* {@inheritDoc}
*/
@Override
public void onConferenceJoined(Map<String, Object> data) {
}
/**
* {@inheritDoc}
*/
@Override
public void onConferenceLeft(Map<String, Object> data) {
}
/**
* {@inheritDoc}
*/
@Override
public void onConferenceWillJoin(Map<String, Object> data) {
}
/**
* {@inheritDoc}
*/
@Override
public void onConferenceWillLeave(Map<String, Object> data) {
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet.sdk;
import java.util.Map;
/**
* Interface for listening to events coming from Jitsi Meet.
*/
public interface JitsiMeetViewListener {
/**
* Called when joining a conference fails or an ongoing conference is
* interrupted due to a failure.
*
* @param data - Map with an "error" key describing the problem, and
* a "url" key with the conference URL.
*/
void onConferenceFailed(Map<String, Object> data);
/**
* Called when a conference was joined.
*
* @param data - Map with a "url" key with the conference URL.
*/
void onConferenceJoined(Map<String, Object> data);
/**
* Called when the conference was left, typically after hanging up.
*
* @param data - Map with a "url" key with the conference URL.
*/
void onConferenceLeft(Map<String, Object> data);
/**
* Called before the conference is joined.
*
* @param data - Map with a "url" key with the conference URL.
*/
void onConferenceWillJoin(Map<String, Object> data);
/**
* Called before the conference is left.
*
* @param data - Map with a "url" key with the conference URL.
*/
void onConferenceWillLeave(Map<String, Object> data);
}

View File

@@ -1,349 +0,0 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet.sdk.audiomode;
import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.HashMap;
import java.util.Map;
/**
* Module implementing a simple API to select the appropriate audio device for a
* conference call.
*
* Audio calls should use <tt>AudioModeModule.AUDIO_CALL</tt>, which uses the
* builtin earpiece, wired headset or bluetooth headset. The builtin earpiece is
* the default audio device.
*
* Video calls should should use <tt>AudioModeModule.VIDEO_CALL</tt>, which uses
* the builtin speaker, earpiece, wired headset or bluetooth headset. The
* builtin speaker is the default audio device.
*
* Before a call has started and after it has ended the
* <tt>AudioModeModule.DEFAULT</tt> mode should be used.
*/
public class AudioModeModule extends ReactContextBaseJavaModule {
/**
* Constants representing the audio mode.
* - DEFAULT: Used before and after every call. It represents the default
* audio routing scheme.
* - AUDIO_CALL: Used for audio only calls. It will use the earpiece by
* default, unless a wired or Bluetooth headset is connected.
* - VIDEO_CALL: Used for video calls. It will use the speaker by default,
* unless a wired or Bluetooth headset is connected.
*/
private static final int DEFAULT = 0;
private static final int AUDIO_CALL = 1;
private static final int VIDEO_CALL = 2;
/**
*
*/
private static final String ACTION_HEADSET_PLUG
= (Build.VERSION.SDK_INT >= 21)
? AudioManager.ACTION_HEADSET_PLUG
: Intent.ACTION_HEADSET_PLUG;
/**
* React Native module name.
*/
private static final String MODULE_NAME = "AudioMode";
/**
* Tag used when logging messages.
*/
static final String TAG = MODULE_NAME;
/**
* {@link AudioManager} instance used to interact with the Android audio
* subsystem.
*/
private final AudioManager audioManager;
/**
* {@link BluetoothHeadsetMonitor} for detecting Bluetooth device changes in
* old (< M) Android versions.
*/
private BluetoothHeadsetMonitor bluetoothHeadsetMonitor;
/**
* {@link Handler} for running all operations on the main thread.
*/
private final Handler mainThreadHandler
= new Handler(Looper.getMainLooper());
/**
* {@link Runnable} for running update operation on the main thread.
*/
private final Runnable mainThreadRunner
= new Runnable() {
@Override
public void run() {
if (mode != -1) {
updateAudioRoute(mode);
}
}
};
/**
* Audio mode currently in use.
*/
private int mode = -1;
/**
* Initializes a new module instance. There shall be a single instance of
* this module throughout the lifetime of the application.
*
* @param reactContext the {@link ReactApplicationContext} where this module
* is created.
*/
public AudioModeModule(ReactApplicationContext reactContext) {
super(reactContext);
audioManager
= (AudioManager)
reactContext.getSystemService(Context.AUDIO_SERVICE);
// Setup runtime device change detection.
setupAudioRouteChangeDetection();
}
/**
* Gets a mapping with the constants this module is exporting.
*
* @return a {@link Map} mapping the constants to be exported with their
* values.
*/
@Override
public Map<String, Object> getConstants() {
Map<String, Object> constants = new HashMap<>();
constants.put("AUDIO_CALL", AUDIO_CALL);
constants.put("DEFAULT", DEFAULT);
constants.put("VIDEO_CALL", VIDEO_CALL);
return constants;
}
/**
* Gets the name for this module, to be used in the React Native bridge.
*
* @return a string with the module name.
*/
@Override
public String getName() {
return MODULE_NAME;
}
/**
* Helper method to trigger an audio route update when devices change. It
* makes sure the operation is performed on the main thread.
*/
void onAudioDeviceChange() {
mainThreadHandler.post(mainThreadRunner);
}
/**
* Helper method to set the output route to a Bluetooth device.
*
* @param enabled true if Bluetooth should use used, false otherwise.
*/
private void setBluetoothAudioRoute(boolean enabled) {
if (enabled) {
audioManager.startBluetoothSco();
audioManager.setBluetoothScoOn(true);
} else {
audioManager.setBluetoothScoOn(false);
audioManager.stopBluetoothSco();
}
}
/**
* Public method to set the current audio mode.
*
* @param mode the desired audio mode.
* @param promise a {@link Promise} which will be resolved if the audio mode
* could be updated successfully, and it will be rejected otherwise.
*/
@ReactMethod
public void setMode(final int mode, final Promise promise) {
if (mode != DEFAULT && mode != AUDIO_CALL && mode != VIDEO_CALL) {
promise.reject("setMode", "Invalid audio mode " + mode);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
boolean success;
try {
success = updateAudioRoute(mode);
} catch (Throwable e) {
success = false;
Log.e(
TAG,
"Failed to update audio route for mode: " + mode,
e);
}
if (success) {
AudioModeModule.this.mode = mode;
promise.resolve(null);
} else {
promise.reject(
"setMode",
"Failed to set audio mode to " + mode);
}
}
};
mainThreadHandler.post(r);
}
/**
* Setup the audio route change detection mechanism. We use the
* {@link android.media.AudioDeviceCallback} API on Android >= 23 only.
*/
private void setupAudioRouteChangeDetection() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setupAudioRouteChangeDetectionM();
} else {
setupAudioRouteChangeDetectionPreM();
}
}
/**
* Audio route change detection mechanism for Android API >= 23.
*/
@TargetApi(Build.VERSION_CODES.M)
private void setupAudioRouteChangeDetectionM() {
android.media.AudioDeviceCallback audioDeviceCallback =
new android.media.AudioDeviceCallback() {
@Override
public void onAudioDevicesAdded(
AudioDeviceInfo[] addedDevices) {
Log.d(TAG, "Audio devices added");
onAudioDeviceChange();
}
@Override
public void onAudioDevicesRemoved(
AudioDeviceInfo[] removedDevices) {
Log.d(TAG, "Audio devices removed");
onAudioDeviceChange();
}
};
audioManager.registerAudioDeviceCallback(audioDeviceCallback, null);
}
/**
* Audio route change detection mechanism for Android API < 23.
*/
private void setupAudioRouteChangeDetectionPreM() {
Context context = getReactApplicationContext();
// Detect changes in wired headset connections.
IntentFilter wiredHeadSetFilter = new IntentFilter(ACTION_HEADSET_PLUG);
BroadcastReceiver wiredHeadsetReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Wired headset added / removed");
onAudioDeviceChange();
}
};
context.registerReceiver(wiredHeadsetReceiver, wiredHeadSetFilter);
// Detect Bluetooth device changes.
bluetoothHeadsetMonitor = new BluetoothHeadsetMonitor(this, context);
}
/**
* Updates the audio route for the given mode.
*
* @param mode the audio mode to be used when computing the audio route.
* @return true if the audio route was updated successfully, false
* otherwise.
*/
private boolean updateAudioRoute(int mode) {
Log.d(TAG, "Update audio route for mode: " + mode);
if (mode == DEFAULT) {
audioManager.setMode(AudioManager.MODE_NORMAL);
audioManager.abandonAudioFocus(null);
audioManager.setSpeakerphoneOn(false);
audioManager.setMicrophoneMute(true);
setBluetoothAudioRoute(false);
return true;
}
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
audioManager.setMicrophoneMute(false);
if (audioManager.requestAudioFocus(
null,
AudioManager.STREAM_VOICE_CALL,
AudioManager.AUDIOFOCUS_GAIN)
== AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
Log.d(TAG, "Audio focus request failed");
return false;
}
boolean useSpeaker = (mode == VIDEO_CALL);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// On Android >= M we use the AudioDeviceCallback API, so turn on
// Bluetooth SCO from the start.
if (audioManager.isBluetoothScoAvailableOffCall()) {
audioManager.startBluetoothSco();
}
} else {
// On older Android versions we must set the Bluetooth route
// manually. Also disable the speaker in that case.
setBluetoothAudioRoute(
bluetoothHeadsetMonitor.isHeadsetAvailable());
if (bluetoothHeadsetMonitor.isHeadsetAvailable()) {
useSpeaker = false;
}
}
// XXX: isWiredHeadsetOn is not deprecated when used just for knowing if
// there is a wired headset connected, regardless of audio being routed
// to it.
audioManager.setSpeakerphoneOn(
useSpeaker
&& !(audioManager.isWiredHeadsetOn()
|| audioManager.isBluetoothScoOn()));
return true;
}
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet.sdk.audiomode;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Implements {@link ReactPackage} for {@link AudioModeModule}.
*/
public class AudioModePackage implements ReactPackage {
/**
* {@inheritDoc}
*/
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
/**
* {@inheritDoc}
*
* @return List of native modules to be exposed by React Native.
*/
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new AudioModeModule(reactContext));
return modules;
}
/**
* {@inheritDoc}
*/
@Override
public List<ViewManager> createViewManagers(
ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

View File

@@ -1,204 +0,0 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet.sdk.audiomode;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
/**
* Helper class to detect and handle Bluetooth device changes. It monitors
* Bluetooth headsets being connected / disconnected and notifies the module
* about device changes when this occurs.
*/
public class BluetoothHeadsetMonitor {
/**
* {@link AudioModeModule} where this monitor reports.
*/
private final AudioModeModule audioModeModule;
/**
* The {@link Context} in which {@link #audioModeModule} executes.
*/
private final Context context;
/**
* Reference to a proxy object which allows us to query connected devices.
*/
private BluetoothHeadset headset;
/**
* Flag indicating if there are any Bluetooth headset devices currently
* available.
*/
private boolean headsetAvailable = false;
/**
* {@link Handler} for running all operations on the main thread.
*/
private final Handler mainThreadHandler
= new Handler(Looper.getMainLooper());
/**
* Helper for running Bluetooth operations on the main thread.
*/
private final Runnable updateDevicesRunnable
= new Runnable() {
@Override
public void run() {
headsetAvailable
= (headset != null)
&& !headset.getConnectedDevices().isEmpty();
audioModeModule.onAudioDeviceChange();
}
};
public BluetoothHeadsetMonitor(
AudioModeModule audioModeModule,
Context context) {
this.audioModeModule = audioModeModule;
this.context = context;
AudioManager audioManager
= (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
if (!audioManager.isBluetoothScoAvailableOffCall()) {
Log.w(AudioModeModule.TAG, "Bluetooth SCO is not available");
return;
}
if (getBluetoothHeadsetProfileProxy()) {
registerBluetoothReceiver();
// Initial detection.
updateDevices();
}
}
private boolean getBluetoothHeadsetProfileProxy() {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter == null) {
Log.w(AudioModeModule.TAG, "Device doesn't support Bluetooth");
return false;
}
// XXX: The profile listener listens for system services of the given
// type being available to the application. That is, if our Bluetooth
// adapter has the "headset" profile.
BluetoothProfile.ServiceListener listener
= new BluetoothProfile.ServiceListener() {
@Override
public void onServiceConnected(
int profile,
BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
headset = (BluetoothHeadset) proxy;
updateDevices();
}
}
@Override
public void onServiceDisconnected(int profile) {
// The logic is the same as the logic of onServiceConnected.
onServiceConnected(profile, /* proxy */ null);
}
};
return
adapter.getProfileProxy(
context,
listener,
BluetoothProfile.HEADSET);
}
/**
* Returns the current headset availability.
*
* @return true if there is a Bluetooth headset connected, false otherwise.
*/
public boolean isHeadsetAvailable() {
return headsetAvailable;
}
private void onBluetoothReceiverReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
// XXX: This action will be fired when a Bluetooth headset is
// connected or disconnected to the system. This is not related to
// audio routing.
int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, -99);
switch (state) {
case BluetoothHeadset.STATE_CONNECTED:
case BluetoothHeadset.STATE_DISCONNECTED:
Log.d(
AudioModeModule.TAG,
"BT headset connection state changed: " + state);
updateDevices();
break;
}
} else if (action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)) {
// XXX: This action will be fired when the connection established
// with a Bluetooth headset (called a SCO connection) changes state.
// When the SCO connection is active we route audio to it.
int state
= intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -99);
switch (state) {
case AudioManager.SCO_AUDIO_STATE_CONNECTED:
case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:
Log.d(
AudioModeModule.TAG,
"BT SCO connection state changed: " + state);
updateDevices();
break;
}
}
}
private void registerBluetoothReceiver() {
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
onBluetoothReceiverReceive(context, intent);
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
context.registerReceiver(receiver, filter);
}
/**
* Detects if there are new devices connected / disconnected and fires the
* {@link AudioModeModule#onAudioDeviceChange()} callback.
*/
private void updateDevices() {
mainThreadHandler.post(updateDevicesRunnable);
}
}

View File

@@ -1,119 +0,0 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet.sdk.externalapi;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import org.jitsi.meet.sdk.JitsiMeetView;
import org.jitsi.meet.sdk.JitsiMeetViewListener;
import java.util.HashMap;
/**
* Module implementing a simple API to enable a proximity sensor-controlled
* wake lock. When the lock is held, if the proximity sensor detects a nearby
* object it will dim the screen and disable touch controls. The functionality
* is used with the conference audio-only mode.
*/
public class ExternalAPIModule extends ReactContextBaseJavaModule {
/**
* React Native module name.
*/
private static final String MODULE_NAME = "ExternalAPI";
/**
* Initializes a new module instance. There shall be a single instance of
* this module throughout the lifetime of the application.
*
* @param reactContext the {@link ReactApplicationContext} where this module
* is created.
*/
public ExternalAPIModule(ReactApplicationContext reactContext) {
super(reactContext);
}
/**
* Gets the name of this module to be used in the React Native bridge.
*
* @return The name of this module to be used in the React Native bridge.
*/
@Override
public String getName() {
return MODULE_NAME;
}
/**
* Dispatches an event that occurred on JavaScript to the view's listener.
*
* @param name The name of the event.
* @param data The details/specifics of the event to send determined
* by/associated with the specified {@code name}.
* @param scope
*/
@ReactMethod
public void sendEvent(String name, ReadableMap data, String scope) {
// The JavaScript App needs to provide uniquely identifying information
// to the native ExternalAPI module so that the latter may match the
// former to the native JitsiMeetView which hosts it.
JitsiMeetView view = JitsiMeetView.findViewByExternalAPIScope(scope);
if (view == null) {
return;
}
JitsiMeetViewListener listener = view.getListener();
if (listener == null) {
return;
}
// TODO Converting a ReadableMap to a HashMap is not supported until
// React Native 0.46.
HashMap<String, Object> dataMap = new HashMap<>();
switch (name) {
case "CONFERENCE_FAILED":
dataMap.put("error", data.getString("error"));
dataMap.put("url", data.getString("url"));
listener.onConferenceFailed(dataMap);
break;
case "CONFERENCE_JOINED":
dataMap.put("url", data.getString("url"));
listener.onConferenceJoined(dataMap);
break;
case "CONFERENCE_LEFT":
dataMap.put("url", data.getString("url"));
listener.onConferenceLeft(dataMap);
break;
case "CONFERENCE_WILL_JOIN":
dataMap.put("url", data.getString("url"));
listener.onConferenceWillJoin(dataMap);
break;
case "CONFERENCE_WILL_LEAVE":
dataMap.put("url", data.getString("url"));
listener.onConferenceWillLeave(dataMap);
break;
}
}
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet.sdk.externalapi;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Implements {@link ReactPackage} for {@link ExternalAPIModule}.
*/
public class ExternalAPIPackage implements ReactPackage {
/**
* {@inheritDoc}
*/
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
/**
* {@inheritDoc}
*
* @return List of native modules to be exposed by React Native.
*/
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new ExternalAPIModule(reactContext));
return modules;
}
/**
* {@inheritDoc}
*/
@Override
public List<ViewManager> createViewManagers(
ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

View File

@@ -1,117 +0,0 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet.sdk.proximity;
import android.content.Context;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.UiThreadUtil;
/**
* Module implementing a simple API to enable a proximity sensor-controlled
* wake lock. When the lock is held, if the proximity sensor detects a nearby
* object it will dim the screen and disable touch controls. The functionality
* is used with the conference audio-only mode.
*/
public class ProximityModule extends ReactContextBaseJavaModule {
/**
* React Native module name.
*/
private static final String MODULE_NAME = "Proximity";
/**
* This type of wake lock (the one activated by the proximity sensor) has
* been available for a while, but the constant was only exported in API
* level 21 (Android Marshmallow) so make no assumptions and use its value
* directly.
*
* TODO: Remove when we bump the API level to 21.
*/
private static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32;
/**
* {@link WakeLock} instance.
*/
private final WakeLock wakeLock;
/**
* Initializes a new module instance. There shall be a single instance of
* this module throughout the lifetime of the application.
*
* @param reactContext The {@link ReactApplicationContext} where this module
* is created.
*/
public ProximityModule(ReactApplicationContext reactContext) {
super(reactContext);
WakeLock wakeLock;
PowerManager powerManager
= (PowerManager)
reactContext.getSystemService(Context.POWER_SERVICE);
try {
wakeLock
= powerManager.newWakeLock(
PROXIMITY_SCREEN_OFF_WAKE_LOCK,
MODULE_NAME);
} catch (Throwable ignored) {
wakeLock = null;
}
this.wakeLock = wakeLock;
}
/**
* Gets the name of this module to be used in the React Native bridge.
*
* @return The name of this module to be used in the React Native bridge.
*/
@Override
public String getName() {
return MODULE_NAME;
}
/**
* Acquires / releases the proximity sensor wake lock.
*
* @param enabled {@code true} to enable the proximity sensor; otherwise,
* {@code false}.
*/
@ReactMethod
public void setEnabled(final boolean enabled) {
if (wakeLock == null) {
return;
}
UiThreadUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
if (enabled) {
if (!wakeLock.isHeld()) {
wakeLock.acquire();
}
} else if (wakeLock.isHeld()) {
wakeLock.release();
}
}
});
}
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright @ 2017-present Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.meet.sdk.proximity;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Implements {@link ReactPackage} for {@link ProximityModule}.
*/
public class ProximityPackage implements ReactPackage {
/**
* {@inheritDoc}
*/
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
/**
* {@inheritDoc}
*
* @return List of native modules to be exposed by React Native.
*/
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new ProximityModule(reactContext));
return modules;
}
/**
* {@inheritDoc}
*/
@Override
public List<ViewManager> createViewManagers(
ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

View File

@@ -1,3 +0,0 @@
<resources>
<string name="app_name">Jitsi Meet SDK</string>
</resources>

View File

@@ -1,12 +1,6 @@
rootProject.name = 'jitsi-meet'
rootProject.name = 'jitsi-meet-react'
include ':app', ':sdk'
include ':react-native-background-timer'
project(':react-native-background-timer').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-background-timer/android')
include ':react-native-immersive'
project(':react-native-immersive').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-immersive/android')
include ':react-native-keep-awake'
project(':react-native-keep-awake').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keep-awake/android')
include ':app'
include ':react-native-vector-icons'
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
include ':react-native-webrtc'

327
app.js
View File

@@ -1,59 +1,314 @@
/* global $, config, getRoomName, loggingConfig, JitsiMeetJS */
/* application specific logic */
const logger = require("jitsi-meet-logger").getLogger(__filename);
import 'jquery';
import 'jquery-contextmenu';
import 'jquery-ui';
import 'strophe';
import 'strophe-disco';
import 'jQuery-Impromptu';
import 'autosize';
import "babel-polyfill";
import "jquery";
import "jquery-contextmenu";
import "jquery-ui";
import "strophe";
import "strophe-disco";
import "strophe-caps";
import "jQuery-Impromptu";
import "autosize";
import 'aui';
import 'aui-experimental';
import 'aui-css';
import 'aui-experimental-css';
window.toastr = require('toastr');
window.toastr = require("toastr");
const Logger = require("jitsi-meet-logger");
const LogCollector = Logger.LogCollector;
import JitsiMeetLogStorage from "./modules/util/JitsiMeetLogStorage";
import URLProcessor from "./modules/config/URLProcessor";
import RoomnameGenerator from './modules/util/RoomnameGenerator';
import UI from "./modules/UI/UI";
import settings from "./modules/settings/Settings";
import conference from './conference';
import API from './modules/API';
import keyboardshortcut from './modules/keyboardshortcut/keyboardshortcut';
import remoteControl from './modules/remotecontrol/RemoteControl';
import settings from './modules/settings/Settings';
import translation from './modules/translation/translation';
import UI from './modules/UI/UI';
import ConferenceUrl from './modules/URL/ConferenceUrl';
import API from './modules/API/API';
window.APP = {
API,
conference,
import UIEvents from './service/UI/UIEvents';
import getTokenData from "./modules/tokendata/TokenData";
import translation from "./modules/translation/translation";
const ConferenceEvents = JitsiMeetJS.events.conference;
/**
* Tries to push history state with the following parameters:
* 'VideoChat', `Room: ${roomName}`, URL. If fail, prints the error and returns
* it.
*/
function pushHistoryState(roomName, URL) {
try {
window.history.pushState(
'VideoChat', `Room: ${roomName}`, URL
);
} catch (e) {
logger.warn("Push history state failed with parameters:",
'VideoChat', `Room: ${roomName}`, URL, e);
return e;
}
return null;
}
/**
* Replaces current history state(replaces the URL displayed by the browser).
* @param {string} newUrl the URL string which is to be displayed by the browser
* to the user.
*/
function replaceHistoryState (newUrl) {
if (window.history
&& typeof window.history.replaceState === 'function') {
window.history.replaceState({}, document.title, newUrl);
}
}
/**
* Builds and returns the room name.
*/
function buildRoomName () {
let roomName = getRoomName();
if(!roomName) {
let word = RoomnameGenerator.generateRoomWithoutSeparator();
roomName = word.toLowerCase();
let historyURL = window.location.href + word;
//Trying to push state with current URL + roomName
pushHistoryState(word, historyURL);
}
return roomName;
}
/**
* Adjusts the logging levels.
* @private
*/
function configureLoggingLevels () {
// NOTE The library Logger is separated from the app loggers, so the levels
// have to be set in two places
// Set default logging level
const defaultLogLevel
= loggingConfig.defaultLogLevel || JitsiMeetJS.logLevels.TRACE;
Logger.setLogLevel(defaultLogLevel);
JitsiMeetJS.setLogLevel(defaultLogLevel);
// NOTE console was used on purpose here to go around the logging
// and always print the default logging level to the console
console.info("Default logging level set to: " + defaultLogLevel);
// Set log level for each logger
if (loggingConfig) {
Object.keys(loggingConfig).forEach(function(loggerName) {
if ('defaultLogLevel' !== loggerName) {
const level = loggingConfig[loggerName];
Logger.setLogLevelById(level, loggerName);
JitsiMeetJS.setLogLevelById(level, loggerName);
}
});
}
}
const APP = {
// Used by do_external_connect.js if we receive the attach data after
// connect was already executed. status property can be 'initialized',
// 'ready', or 'connecting'. We are interested in 'ready' status only which
// connect was already executed. status property can be "initialized",
// "ready" or "connecting". We are interested in "ready" status only which
// means that connect was executed but we have to wait for the attach data.
// In status 'ready' handler property will be set to a function that will
// In status "ready" handler property will be set to a function that will
// finish the connect process when the attach data or error is received.
connect: {
handler: null,
status: 'initialized'
status: "initialized",
handler: null
},
// Used for automated performance tests.
// Used for automated performance tests
connectionTimes: {
'index.loaded': window.indexLoadedTime
"index.loaded": window.indexLoadedTime
},
keyboardshortcut,
remoteControl,
UI,
settings,
conference,
translation,
UI
/**
* The log collector which captures JS console logs for this app.
* @type {LogCollector}
*/
logCollector: null,
/**
* Indicates if the log collector has been started (it will not be started
* if the welcome page is displayed).
*/
logCollectorStarted : false,
/**
* After the APP has been initialized provides utility methods for dealing
* with the conference room URL(address).
* @type ConferenceUrl
*/
ConferenceUrl : null,
connection: null,
API,
init () {
this.initLogging();
this.keyboardshortcut =
require("./modules/keyboardshortcut/keyboardshortcut");
this.configFetch = require("./modules/config/HttpConfigFetch");
this.tokenData = getTokenData();
},
initLogging () {
// Adjust logging level
configureLoggingLevels();
// Create the LogCollector and register it as the global log transport.
// It is done early to capture as much logs as possible. Captured logs
// will be cached, before the JitsiMeetLogStorage gets ready (statistics
// module is initialized).
if (!this.logCollector && !loggingConfig.disableLogCollector) {
this.logCollector = new LogCollector(new JitsiMeetLogStorage());
Logger.addGlobalTransport(this.logCollector);
JitsiMeetJS.addGlobalLogTransport(this.logCollector);
}
}
};
// TODO The execution of the mobile app starts from react/index.native.js.
// Similarly, the execution of the Web app should start from react/index.web.js
// for the sake of consistency and ease of understanding. Temporarily though
// because we are at the beginning of introducing React into the Web app, allow
// the execution of the Web app to start from app.js in order to reduce the
// complexity of the beginning step.
import './react';
/**
* If JWT token data it will be used for local user settings
*/
function setTokenData() {
let localUser = APP.tokenData.caller;
if(localUser) {
APP.settings.setEmail((localUser.getEmail() || "").trim(), true);
APP.settings.setAvatarUrl((localUser.getAvatarUrl() || "").trim());
APP.settings.setDisplayName((localUser.getName() || "").trim(), true);
}
}
function init() {
setTokenData();
// Initialize the conference URL handler
APP.ConferenceUrl = new ConferenceUrl(window.location);
// Clean up the URL displayed by the browser
replaceHistoryState(APP.ConferenceUrl.getInviteUrl());
// TODO The execution of the mobile app starts from react/index.native.js.
// Similarly, the execution of the Web app should start from
// react/index.web.js for the sake of consistency and ease of understanding.
// Temporarily though because we are at the beginning of introducing React
// into the Web app, allow the execution of the Web app to start from app.js
// in order to reduce the complexity of the beginning step.
require('./react');
const isUIReady = APP.UI.start();
if (isUIReady) {
APP.conference.init({roomName: buildRoomName()}).then(() => {
if (APP.logCollector) {
// Start the LogCollector's periodic "store logs" task only if
// we're in the conference and not on the welcome page. This is
// determined by the value of "isUIReady" const above.
APP.logCollector.start();
APP.logCollectorStarted = true;
// Make an attempt to flush in case a lot of logs have been
// cached, before the collector was started.
APP.logCollector.flush();
// This event listener will flush the logs, before
// the statistics module (CallStats) is stopped.
//
// NOTE The LogCollector is not stopped, because this event can
// be triggered multiple times during single conference
// (whenever statistics module is stopped). That includes
// the case when Jicofo terminates the single person left in the
// room. It will then restart the media session when someone
// eventually join the room which will start the stats again.
APP.conference.addConferenceListener(
ConferenceEvents.BEFORE_STATISTICS_DISPOSED,
() => {
if (APP.logCollector) {
APP.logCollector.flush();
}
}
);
}
APP.UI.initConference();
APP.UI.addListener(UIEvents.LANG_CHANGED, language => {
APP.translation.setLanguage(language);
APP.settings.setLanguage(language);
});
APP.keyboardshortcut.init();
}).catch(err => {
APP.UI.hideRingOverLay();
APP.API.notifyConferenceLeft(APP.conference.roomName);
logger.error(err);
});
}
}
/**
* If we have an HTTP endpoint for getting config.json configured we're going to
* read it and override properties from config.js and interfaceConfig.js.
* If there is no endpoint we'll just continue with initialization.
* Keep in mind that if the endpoint has been configured and we fail to obtain
* the config for any reason then the conference won't start and error message
* will be displayed to the user.
*/
function obtainConfigAndInit() {
let roomName = APP.conference.roomName;
if (config.configLocation) {
APP.configFetch.obtainConfig(
config.configLocation, roomName,
// Get config result callback
function(success, error) {
if (success) {
var now = APP.connectionTimes["configuration.fetched"] =
window.performance.now();
logger.log("(TIME) configuration fetched:\t", now);
init();
} else {
// Show obtain config error,
// pass the error object for report
APP.UI.messageHandler.openReportDialog(
null, "dialog.connectError", error);
}
});
} else {
require("./modules/config/BoshAddressChoice").chooseAddress(
config, roomName);
init();
}
}
$(document).ready(function () {
var now = APP.connectionTimes["document.ready"] = window.performance.now();
logger.log("(TIME) document ready:\t", now);
URLProcessor.setConfigParametersFromUrl();
APP.init();
APP.translation.init(settings.getLanguage());
APP.API.init(APP.tokenData.externalAPISettings);
obtainConfigAndInit();
});
$(window).bind('beforeunload', function () {
// Stop the LogCollector
if (APP.logCollectorStarted) {
APP.logCollector.stop();
APP.logCollectorStarted = false;
}
APP.API.dispose();
});
module.exports = APP;

View File

@@ -1,7 +1,7 @@
<html>
<head>
<link rel="stylesheet" href="../css/all.css"/>
<!--#include virtual="/title.html" -->
<link rel="stylesheet" href="css/all.css"/>
<!--#include virtual="title.html" -->
</head>
<body>
<div class="redirectPageMessage">Sorry! You are not allowed to be here :(</div>

View File

@@ -1,7 +1,7 @@
<html>
<head>
<link rel="stylesheet" href="../css/all.css"/>
<!--#include virtual="/title.html" -->
<link rel="stylesheet" href="css/all.css"/>
<!--#include virtual="title.html" -->
<script><!--#include virtual="/interface_config.js" --></script>
<script src="close.js"></script>
</head>
@@ -12,7 +12,7 @@
</div>
<div class="hint-msg">
<p>
<span id="hintQuestion">Did you know?</span>
<span>Did you know?</span>
<span class="hint-msg__holder" id="hintMessage"></span>
</p>
<div class="happy-software"></div>

View File

@@ -32,7 +32,7 @@ function insertTextMsg(id, msg){
var el = document.getElementById(id);
if (el)
el.innerHTML = msg;
el.innerText = msg;
}
/**
@@ -42,17 +42,6 @@ function onLoad() {
//Works only for close2.html because close.html doesn't have this element.
insertTextMsg('thanksMessage',
'Thank you for using ' + interfaceConfig.APP_NAME);
// If there is a setting show a special message only for the guests
if (interfaceConfig.CLOSE_PAGE_GUEST_HINT) {
if ( window.sessionStorage.getItem('guest') === 'true' ) {
var element = document.getElementById('hintQuestion');
element.classList.add('hide');
insertTextMsg('hintMessage', interfaceConfig.CLOSE_PAGE_GUEST_HINT);
return;
}
}
insertTextMsg('hintMessage', getHint());
}

View File

@@ -1,7 +1,7 @@
<html>
<head>
<link rel="stylesheet" href="../css/all.css"/>
<!--#include virtual="/title.html" -->
<link rel="stylesheet" href="css/all.css"/>
<!--#include virtual="title.html" -->
<script><!--#include virtual="/interface_config.js" --></script>
<script src="close.js"></script>
</head>
@@ -12,7 +12,7 @@
</div>
<div class="hint-msg">
<p>
<span id="hintQuestion">Did you know?</span>
<span>Did you know?</span>
<span class="hint-msg__holder" id="hintMessage"></span>
</p>
<div class="happy-software"></div>

File diff suppressed because it is too large Load Diff

View File

@@ -11,17 +11,6 @@ var config = { // eslint-disable-line no-unused-vars
//call_control: 'callcontrol.jitsi-meet.example.com',
//focus: 'focus.jitsi-meet.example.com', // defaults to 'focus.jitsi-meet.example.com'
},
testing: {
/**
* Enables experimental simulcast support on Firefox.
*/
enableFirefoxSimulcast: false,
/**
* P2P test mode disables automatic switching to P2P when there are 2
* participants in the conference.
*/
p2pTestMode: false,
},
// getroomnode: function (path) { return 'someprefixpossiblybasedonpath'; },
// useStunTurn: true, // use XEP-0215 to fetch STUN and TURN server
// useIPv6: true, // ipv6 support. use at your own risk
@@ -30,14 +19,11 @@ var config = { // eslint-disable-line no-unused-vars
clientNode: 'http://jitsi.org/jitsimeet', // The name of client node advertised in XEP-0115 'c' stanza
//focusUserJid: 'focus@auth.jitsi-meet.example.com', // The real JID of focus participant - can be overridden here
//defaultSipNumber: '', // Default SIP number
/**
* Disables desktop sharing functionality.
*/
disableDesktopSharing: false,
// Desktop sharing method. Can be set to 'ext', 'webrtc' or false to disable.
desktopSharingChromeMethod: 'ext',
// The ID of the jidesha extension for Chrome.
desktopSharingChromeExtId: null,
// Whether desktop sharing should be disabled on Chrome.
desktopSharingChromeDisabled: true,
desktopSharingChromeExtId: 'diibjkoicjeejcmhdnailmkgecihlobk',
// The media sources to use when using screen sharing with the Chrome
// extension.
desktopSharingChromeSources: ['screen', 'window', 'tab'],
@@ -48,13 +34,13 @@ var config = { // eslint-disable-line no-unused-vars
// extension is required.
desktopSharingFirefoxExtId: null,
// Whether desktop sharing should be disabled on Firefox.
desktopSharingFirefoxDisabled: false,
desktopSharingFirefoxDisabled: true,
// The maximum version of Firefox which requires a jidesha extension.
// Example: if set to 41, we will require the extension for Firefox versions
// up to and including 41. On Firefox 42 and higher, we will run without the
// extension.
// If set to -1, an extension will be required for all versions of Firefox.
desktopSharingFirefoxMaxVersionExtRequired: 51,
desktopSharingFirefoxMaxVersionExtRequired: -1,
// The URL to the Firefox extension for desktop sharing.
desktopSharingFirefoxExtensionURL: null,
@@ -64,20 +50,18 @@ var config = { // eslint-disable-line no-unused-vars
webrtcIceTcpDisable: false,
openSctp: true, // Toggle to enable/disable SCTP channels
// Disable hiding of remote thumbnails when in a 1-on-1 conference call.
disable1On1Mode: false,
disableStats: false,
disableAudioLevels: false,
channelLastN: -1, // The default value of the channel attribute last-n.
adaptiveLastN: false,
//disableAdaptiveSimulcast: false,
enableRecording: false,
enableWelcomePage: true,
//enableClosePage: false, // enabling the close page will ignore the welcome
// page redirection when call is hangup
disableSimulcast: false,
logStats: false, // Enable logging of PeerConnection stats via the focus
// requireDisplayName: true, // Forces the participants that doesn't have display name to enter it when they enter the room.
startAudioOnly: false, // Will start the conference in the audio only mode (no video is being received nor sent)
startScreenSharing: false, // Will try to start with screensharing instead of camera
// startAudioMuted: 10, // every participant after the Nth will start audio muted
// startVideoMuted: 10, // every participant after the Nth will start video muted
// defaultLanguage: "en",
@@ -88,47 +72,19 @@ var config = { // eslint-disable-line no-unused-vars
'During that time service will not be available. ' +
'Apologise for inconvenience.',*/
disableThirdPartyRequests: false,
// The minumum value a video's height (or width, whichever is smaller) needs
// to be in order to be considered high-definition.
minHDHeight: 540,
// If true - all users without token will be considered guests and all users
// with token will be considered non-guests. Only guests will be allowed to
// edit their profile.
enableUserRolesBasedOnToken: false,
// Suspending video might cause problems with audio playback. Disabling until these are fixed.
disableSuspendVideo: true,
// disables or enables RTX (RFC 4588) (defaults to false).
disableRtx: false,
// Sets the preferred resolution (height) for local video. Defaults to 720.
resolution: 720,
// Peer-To-Peer mode: used (if enabled) when there are just 2 participants.
p2p: {
// Enables peer to peer mode. When enabled system will try to establish
// direct connection given that there are exactly 2 participants in
// the room. If that succeeds the conference will stop sending data
// through the JVB and use the peer to peer connection instead. When 3rd
// participant joins the conference will be moved back to the JVB
// connection.
enabled: true,
// The STUN servers that will be used in the peer to peer connections
// useStunTurn: true, // use XEP-0215 to fetch STUN and TURN server
stunServers: [
{ urls: "stun:stun.l.google.com:19302" },
{ urls: "stun:stun1.l.google.com:19302" },
{ urls: "stun:stun2.l.google.com:19302" }
],
// If set to true, it will prefer to use H.264 for P2P calls (if H.264
// is supported).
preferH264: true
// How long we're going to wait, before going back to P2P after
// the 3rd participant has left the conference (to filter out page reload)
//backToP2PDelay: 5
},
// Information about the jitsi-meet instance we are connecting to, including the
// user region as seen by the server.
deploymentInfo: {
//shard: "shard1",
//region: "europe",
//userRegion: "asia"
}
enableUserRolesBasedOnToken: false
};
// Logging configuration
var loggingConfig = { // eslint-disable-line no-unused-vars
//default log level for the app and lib-jitsi-meet
defaultLogLevel: 'trace',
// Option to disable LogCollector (which stores the logs on CallStats)
//disableLogCollector: true,
// Logging level adjustments for verbose modules:
'modules/xmpp/strophe.util.js': 'log'
};

View File

@@ -1,19 +1,11 @@
/* global APP, JitsiMeetJS, config */
const logger = require("jitsi-meet-logger").getLogger(__filename);
import AuthHandler from './modules/UI/authentication/AuthHandler';
import jitsiLocalStorage from './modules/util/JitsiLocalStorage';
import {
connectionEstablished,
connectionFailed
} from './react/features/base/connection';
import {
isFatalJitsiConnectionError
} from './react/features/base/lib-jitsi-meet';
const ConnectionEvents = JitsiMeetJS.events.connection;
const ConnectionErrors = JitsiMeetJS.errors.connection;
const logger = require("jitsi-meet-logger").getLogger(__filename);
/**
* Checks if we have data to use attach instead of connect. If we have the data
@@ -61,49 +53,33 @@ function checkForAttachParametersAndConnect(id, password, connection) {
* everything is ok, else error.
*/
function connect(id, password, roomName) {
const connectionConfig = Object.assign({}, config);
const { issuer, jwt } = APP.store.getState()['features/jwt'];
let connectionConfig = Object.assign({}, config);
connectionConfig.bosh += '?room=' + roomName;
let connection
= new JitsiMeetJS.JitsiConnection(
null,
jwt && issuer && issuer !== 'anonymous' ? jwt : undefined,
connectionConfig);
= new JitsiMeetJS.JitsiConnection(null, config.token, connectionConfig);
return new Promise(function (resolve, reject) {
connection.addEventListener(
ConnectionEvents.CONNECTION_ESTABLISHED,
handleConnectionEstablished);
ConnectionEvents.CONNECTION_ESTABLISHED, handleConnectionEstablished
);
connection.addEventListener(
ConnectionEvents.CONNECTION_FAILED,
handleConnectionFailed);
connection.addEventListener(
ConnectionEvents.CONNECTION_FAILED,
connectionFailedHandler);
function connectionFailedHandler(error, errMsg) {
APP.store.dispatch(connectionFailed(connection, error, errMsg));
if (isFatalJitsiConnectionError(error)) {
connection.removeEventListener(
ConnectionEvents.CONNECTION_FAILED,
connectionFailedHandler);
}
}
ConnectionEvents.CONNECTION_FAILED, handleConnectionFailed
);
function unsubscribe() {
connection.removeEventListener(
ConnectionEvents.CONNECTION_ESTABLISHED,
handleConnectionEstablished);
handleConnectionEstablished
);
connection.removeEventListener(
ConnectionEvents.CONNECTION_FAILED,
handleConnectionFailed);
handleConnectionFailed
);
}
function handleConnectionEstablished() {
APP.store.dispatch(connectionEstablished(connection));
unsubscribe();
resolve(connection);
}
@@ -132,6 +108,7 @@ function connect(id, password, roomName) {
* @returns {Promise<JitsiConnection>}
*/
export function openConnection({id, password, retry, roomName}) {
let usernameOverride
= jitsiLocalStorage.getItem("xmpp_username_override");
let passwordOverride
@@ -140,20 +117,25 @@ export function openConnection({id, password, retry, roomName}) {
if (usernameOverride && usernameOverride.length > 0) {
id = usernameOverride;
}
if (passwordOverride && passwordOverride.length > 0) {
password = passwordOverride;
}
return connect(id, password, roomName).catch(err => {
if (retry) {
const { issuer, jwt } = APP.store.getState()['features/jwt'];
if (err === ConnectionErrors.PASSWORD_REQUIRED
&& (!jwt || issuer === 'anonymous')) {
return AuthHandler.requestAuth(roomName, connect);
}
return connect(id, password, roomName).catch(function (err) {
if (!retry) {
throw err;
}
throw err;
if (err === ConnectionErrors.PASSWORD_REQUIRED) {
// do not retry if token is not valid
if (config.token) {
throw err;
} else {
return AuthHandler.requestAuth(roomName, connect);
}
} else {
throw err;
}
});
}

View File

@@ -1,3 +0,0 @@
module.exports = {
'extends': '../react/.eslintrc.js'
};

View File

@@ -1,82 +1,75 @@
/* global config, createConnectionExternally */
import getRoomName from '../react/features/base/config/getRoomName';
import parseURLParams from '../react/features/base/config/parseURLParams';
/* global config, getRoomName, getConfigParamsFromUrl */
/* global createConnectionExternally */
/**
* Implements external connect using createConnectionExternally function defined
* in external_connect.js for Jitsi Meet. Parses the room name and JSON Web
* Token (JWT) from the URL and executes createConnectionExternally.
* Implements extrnal connect using createConnectionExtenally function defined
* in external_connect.js for Jitsi Meet. Parses the room name and token from
* the url and executes createConnectionExtenally.
*
* NOTE: If you are using lib-jitsi-meet without Jitsi Meet, you should use this
* file as reference only because the implementation is Jitsi Meet-specific.
* NOTE: If you are using lib-jitsi-meet without Jitsi Meet you should use this
* file as reference only because the implementation is Jitsi Meet specific.
*
* NOTE: For optimal results this file should be included right after
* external_connect.js.
* exrnal_connect.js.
*/
if (typeof createConnectionExternally === 'function') {
// URL params have higher proirity than config params.
let url
= parseURLParams(window.location, true, 'hash')[
'config.externalConnectUrl']
|| config.externalConnectUrl;
let roomName;
/**
* Executes createConnectionExternally function.
*/
(function () {
var hashParams = getConfigParamsFromUrl("hash", true);
var searchParams = getConfigParamsFromUrl("search", true);
if (url && (roomName = getRoomName())) {
url += `?room=${roomName}`;
//Url params have higher proirity than config params
var url = config.externalConnectUrl;
if(hashParams.hasOwnProperty('config.externalConnectUrl'))
url = hashParams["config.externalConnectUrl"];
const token = parseURLParams(window.location, true, 'search').jwt;
/**
* Check if connect from connection.js was executed and executes the handler
* that is going to finish the connect work.
*/
function checkForConnectHandlerAndConnect() {
if (token) {
url += `&token=${token}`;
if(window.APP && window.APP.connect.status === "ready") {
window.APP.connect.handler();
}
createConnectionExternally(
url,
connectionInfo => {
// Sets that global variable to be used later by connect method
// in connection.js.
window.XMPPAttachInfo = {
status: 'success',
data: connectionInfo
};
checkForConnectHandlerAndConnect();
},
errorCallback);
} else {
errorCallback();
}
} else {
errorCallback();
}
/**
* Check if connect from connection.js was executed and executes the handler
* that is going to finish the connect work.
*
* @returns {void}
*/
function checkForConnectHandlerAndConnect() {
window.APP
&& window.APP.connect.status === 'ready'
&& window.APP.connect.handler();
}
function error_callback(error){
if(error) //error=undefined if external connect is disabled.
console.warn(error);
// Sets that global variable to be used later by connect method in
// connection.js
window.XMPPAttachInfo = {
status: "error"
};
checkForConnectHandlerAndConnect();
}
/**
* Implements a callback to be invoked if anything goes wrong.
*
* @param {Error} error - The specifics of what went wrong.
* @returns {void}
*/
function errorCallback(error) {
// The value of error is undefined if external connect is disabled.
error && console.warn(error);
if(!url || !window.createConnectionExternally) {
error_callback();
return;
}
var room_name = getRoomName();
if(!room_name) {
error_callback();
return;
}
// Sets that global variable to be used later by connect method in
// connection.js.
window.XMPPAttachInfo = {
status: 'error'
};
checkForConnectHandlerAndConnect();
}
url += "?room=" + room_name;
var token = hashParams["config.token"] || config.token ||
searchParams.jwt;
if(token)
url += "&token=" + token;
createConnectionExternally(url, function(connectionInfo) {
// Sets that global variable to be used later by connect method in
// connection.js
window.XMPPAttachInfo = {
status: "success",
data: connectionInfo
};
checkForConnectHandlerAndConnect();
}, error_callback);
})();

View File

@@ -66,4 +66,18 @@
@include keyframes(slideInExtContainer) {
from { width: 0; }
to { width: $sidebarWidth; }
}
/**
* Fade in / out animations
**/
@include keyframes(fadeIn) {
from { opacity: 0; }
to { opacity: 1; }
}
@include keyframes(fadeOut) {
from { opacity: 1; }
to { opacity: 0; }
}

View File

@@ -1,32 +1,23 @@
/**
* Safari will limit input in input elements to one character when user-select
* none is applied. Other browsers already support selecting within inputs while
* user-select is none. As such, disallow user-select except on inputs.
*/
*:not(input) {
* {
-webkit-user-select: none;
user-select: none;
}
body {
margin: 0px;
width: 100%;
height: 100%;
html, body{
margin:0px;
height:100%;
color: $defaultColor;
font-size: 12px;
font-weight: 400;
background: #000000;
overflow: hidden;
color: $defaultColor;
background: $defaultBackground;
&.filmstrip-only {
background: transparent;
}
}
p {
margin: 0;
}
body, input, textarea, keygen, select, button {
html, body, input, textarea, keygen, select, button {
font-family: $baseFontFamily !important;
}
@@ -41,11 +32,16 @@ body, input, textarea, keygen, select, button {
button, input, select, textarea {
margin: 0;
vertical-align: baseline;
color: $inputColor;
font-size: 1em;
}
button, select, input[type="button"],
input[type="reset"], input[type="submit"] {
height: 32px;
line-height: 32px;
padding-left: 4px;
padding-right: 4px;
cursor: pointer;
}
@@ -84,10 +80,11 @@ form {
height: 74px;
background-size: contain;
background-repeat: no-repeat;
z-index: $zindex2;
z-index: 2;
}
.leftwatermark {
display: none;
left: $defaultToolbarSize;
margin-left: 10px;
background-image: url($defaultWatermarkLink);
@@ -95,18 +92,20 @@ form {
}
.rightwatermark {
display: none;
right: 15;
background-position: center right;
}
.poweredby {
display: none;
position: absolute;
left: 25;
bottom: 7;
font-size: 11pt;
color: rgba(255,255,255,.50);
text-decoration: none;
z-index: $poweredByZ;
z-index: 100;
}
.connected {
@@ -126,7 +125,6 @@ form {
z-index: $tooltipsZ;
&-inner {
background-color: $tooltipBg;
max-width: 350px;
}
&-arrow {
@@ -144,29 +142,4 @@ form {
#inviteLinkRef {
-webkit-user-select: text;
user-select: text;
}
/**
* Re-style default OS scrollbar.
*/
::-webkit-scrollbar {
background: transparent;
width: 7px;
}
::-webkit-scrollbar-button {
display: none;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-track-piece {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, .5);
border-radius: 4px;
}
}

View File

@@ -31,28 +31,6 @@
a:active {
color: black;
}
&::-webkit-scrollbar {
background: #06a5df;
width: 7px;
}
&::-webkit-scrollbar-button {
display: none;
}
&::-webkit-scrollbar-track {
background: black;
}
&::-webkit-scrollbar-track-piece {
background: black;
}
&::-webkit-scrollbar-thumb {
background: #06a5df;
border-radius: 4px;
}
}
#chat_container.is-conversation-mode #chatconversation {
@@ -234,6 +212,28 @@
line-height: 30px;
}
::-webkit-scrollbar {
background: #06a5df;
width: 7px;
}
::-webkit-scrollbar-button {
display: none;
}
::-webkit-scrollbar-track {
background: black;
}
::-webkit-scrollbar-track-piece {
background: black;
}
::-webkit-scrollbar-thumb {
background: #06a5df;
border-radius: 4px;
}
#usermsg::-webkit-scrollbar-track-piece {
background: #3a3a3a;
}

View File

@@ -0,0 +1,31 @@
.settingsContent {
display: flex;
display: -webkit-flex;
#localVideoPreview {
width: 50%;
align-self: baseline;
}
.deviceSelection {
display: flex;
display: -webkit-flex;
-webkit-flex: 1;
flex: 1;
flex-direction: column;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: left;
margin-left: 10px;
.device {
display: flex;
margin-bottom: 5px;
select {
flex: 1;
margin_right: 5px;
}
}
}
}

View File

@@ -1,64 +0,0 @@
/**
* The dialog content element.
*/
.dial-out-content {
margin-top: 5px;
/**
* The style of the flag icon.
*/
.dial-out-flag-icon {
position: absolute;
left: 5px;
top: 10px;
}
/**
* The style of the dial code element.
*/
.dial-out-code {
padding-left: 25px !important;
}
/**
* The dial-out dialog error element.
*/
.dial-out-error {
color: $errorColor;
}
/**
* The style of the dial input element.
*/
.dial-out-input {
padding-left: 70px;
}
/**
* Re-styling the default dropdown inside the dial-out-content.
*/
.dropdown {
left: $formPadding;
position: absolute !important;
width: 65px
}
/**
* Re-styling the default form-control inside the dial-out-content.
*/
.form-control {
padding-bottom: 8px !important;
}
.dropdown {
display: inline-block;
position: relative;
overflow: hidden;
}
.dropdown-trigger-icon {
position: absolute;
right: 0;
top: 4px;
}
}

View File

@@ -17,8 +17,8 @@
flex-direction: column-reverse;
flex-wrap: nowrap;
position: relative;
z-index: $zindex1; // Set z-index to make element visible.
width: $filmstripToggleButtonWidth;
z-index: 1; // Set z-index to make element visible
width: $hideFilmstripButtonWidth;
button {
font-size: 14px;
@@ -50,35 +50,25 @@
position:relative;
height:196px;
padding: 0;
/* The filmstrip should not be covered by the left toolbar. */
padding-left: 17px;
bottom: 0;
width:auto;
z-index: $filmstripVideosZ;
border: $thumbnailsBorder solid transparent;
z-index: 5;
transition: bottom 2s;
overflow: visible !important;
/*!!! Removes the gap between the local video container and the remote
videos. */
font-size: 0pt;
&#remoteVideos {
border: $thumbnailsBorder solid transparent;
padding-left: $defaultToolbarSize + 5;
}
font-size: 0pt; /*!!!Removes the gap between the local video container and the remote videos.*/
&.hidden {
bottom: -196px;
}
.remote-videos-container {
display: flex;
}
.videocontainer {
display: none;
position: relative;
background-size: contain;
border: $thumbnailVideoBorder solid transparent;
border-radius: $borderRadius;
border-radius:1px;
margin: 0 $thumbnailVideoMargin;
&.videoContainerFocused, &:hover {
@@ -86,8 +76,8 @@
}
/**
* Focused video thumbnail.
*/
* Focused video thumbnail.
*/
&.videoContainerFocused {
transition-duration: 0.5s;
-webkit-transition-duration: 0.5s;
@@ -99,50 +89,33 @@
0 0 3px $videoThumbnailSelected !important;
}
.remotevideomenu > .icon-menu {
.remotevideomenu {
display: none;
}
/**
* Hovered video thumbnail.
*/
* Hovered video thumbnail.
*/
&:hover {
cursor: hand;
border: $thumbnailVideoBorder solid $videoThumbnailHovered;
box-shadow: inset 0 0 3px $videoThumbnailHovered,
0 0 3px $videoThumbnailHovered;
.remotevideomenu > .icon-menu {
.remotevideomenu {
display: inline-block;
}
}
/* With the TemasysWebRTC plugin <object/> element is used
/* With TemasysWebRTC plugin <object/> element is used
instead of <video/> */
& > video,
& > object {
cursor: hand;
border-radius: $borderRadius;
border-radius:1px;
object-fit: cover;
overflow: hidden;
}
}
}
/**
* Style the filmstrip videos in filmstrip-only mode.
*/
&__videos-filmstripOnly {
margin-top: auto;
margin-bottom: auto;
}
.remote-videos-container {
transition: opacity 1s;
&.hide-videos {
opacity: 0;
pointer-events: none;
}
}
}
}

View File

@@ -1,35 +0,0 @@
.flag-icon-background {
background-size: contain;
background-position: 50%;
background-repeat: no-repeat;
}
.flag-icon {
background-size: contain;
background-position: 50%;
background-repeat: no-repeat;
position: relative;
display: inline-block;
width: 1.33333333em;
line-height: 1em;
}
.flag-icon:before {
content: "\00a0";
}
.flag-icon-au {
background-image: url(../images/countries/au.svg);
}
.flag-icon-ca {
background-image: url(../images/countries/ca.svg);
}
.flag-icon-de {
background-image: url(../images/countries/de.svg);
}
.flag-icon-gb {
background-image: url(../images/countries/gb.svg);
}
.flag-icon-fr {
background-image: url(../images/countries/fr.svg);
}
.flag-icon-us {
background-image: url(../images/countries/us.svg);
}

View File

@@ -25,135 +25,115 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-thumb-menu:before {
content: "\e5d4";
}
.icon-mic-camera-combined:before {
content: "\e903";
}
.icon-feedback:before {
content: "\e91d";
content: "\e91d";
}
.icon-toggle-filmstrip:before {
content: "\e91c";
content: "\e91c";
}
.icon-avatar:before {
content: "\e901";
content: "\e901";
}
.icon-autorenew:before {
content: "\e903";
}
.icon-hangup:before {
content: "\e905";
content: "\e905";
}
.icon-chat:before {
content: "\e906";
}
.icon-download:before {
content: "\e902";
content: "\e906";
}
.icon-edit:before {
content: "\e907";
content: "\e907";
}
.icon-share-doc:before {
content: "\e908";
content: "\e908";
}
.icon-telephone:before {
content: "\e909";
}
.icon-kick:before {
content: "\e904";
content: "\e904";
}
.icon-menu:before {
content: "\e91f";
}
.icon-menu-up:before {
content: "\e91f";
content: "\e91f";
}
.icon-menu-down:before {
content: "\e920";
content: "\e920";
}
.icon-full-screen:before {
content: "\e90b";
content: "\e90b";
}
.icon-exit-full-screen:before {
content: "\e90c";
}
.icon-star-full:before {
content: "\e90a";
}
.icon-security:before {
content: "\e90d";
}
.icon-security-locked:before {
content: "\e90e";
}
.icon-reload:before {
content: "\e90f";
}
.icon-microphone:before {
content: "\e910";
}
.icon-mic-empty:before {
content: "\e911";
}
.icon-mic-disabled:before {
content: "\e912";
}
.icon-ninja:before {
content: "\e909";
}
.icon-raised-hand:before {
content: "\e91e";
}
.icon-contactList:before {
content: "\e91b";
}
.icon-link:before {
content: "\e913";
}
.icon-shared-video:before {
content: "\e914";
}
.icon-settings:before {
content: "\e915";
content: "\e90c";
}
.icon-star:before {
content: "\e916";
}
.icon-switch-camera:before {
content: "\e921";
.icon-star-full:before {
content: "\e90a";
}
.icon-security:before {
content: "\e90d";
}
.icon-security-locked:before {
content: "\e90e";
}
.icon-reload:before {
content: "\e90f";
}
.icon-microphone:before {
content: "\e910";
}
.icon-mic-empty:before {
content: "\e911";
}
.icon-mic-disabled:before {
content: "\e912";
}
.icon-raised-hand:before {
content: "\e91e";
}
.icon-contactList:before {
content: "\e91b";
}
.icon-link:before {
content: "\e913";
}
.icon-shared-video:before {
content: "\e914";
}
.icon-settings:before {
content: "\e915";
}
.icon-share-desktop:before {
content: "\e917";
content: "\e917";
}
.icon-camera:before {
content: "\e918";
content: "\e918";
}
.icon-camera-disabled:before {
content: "\e919";
content: "\e919";
}
.icon-volume:before {
content: "\e91a";
content: "\e91a";
}
.icon-connection-lost:before {
content: "\e900";
content: "\e900";
}
.icon-connection:before {
content: "\e61a";
content: "\e61a";
}
.icon-recDisable:before {
content: "\e613";
content: "\e613";
}
.icon-recEnable:before {
content: "\e614";
content: "\e614";
}
// FIXME not used anymore - consider removing in the next font update
.icon-presentation:before {
content: "\e603";
}
.icon-dialpad:before {
content: "\e925";
}
.icon-visibility:before {
content: "\e923";
}
.icon-visibility-off:before {
content: "\e924";
}
.icon-telephone:before {
content: "\e0cd";
}
.icon-add:before {
content: "\e145";
content: "\e603";
}

View File

@@ -1,6 +1,6 @@
.inlay {
margin-top: 14%;
@include border-radius(4px);
@include border-radius(3px);
padding: 40px 38px 44px;
color: #fff;
background: $inlayColorBg;
@@ -27,87 +27,7 @@
font-size: 50px;
}
&-filmstrip-only {
background-color: $inlayFilmstripOnlyBg;
color: $inlayFilmstripOnlyColor;
margin-left: 20px;
margin-right: 20px;
margin-top: 20px;
bottom: 30px;
position: absolute;
display: flex;
max-height: 120px;
height: 80%;
right: 0px;
border-radius: 4px;
overflow: hidden;
&__content {
padding: 20px;
display: flex;
justify-content: center;
position: relative;
> .button-control {
align-self: center;
}
> #reloadProgressBar {
position: absolute;
left: 0px;
bottom: 0px;
margin-bottom: 0px;
width: 100%;
border-radius: 0px;
> .aui-progress-indicator-value {
border-radius: 0px;
}
}
}
&__title {
font-size: 18px;
font-weight: 600;
}
&__container {
align-self: center;
}
&__text {
margin-top: 10px;
font-size: 14px;
font-weight: 600;
}
&__icon {
font-size: 50px;
align-self: center;
color: $inlayIconColor;
opacity: 0.6;
}
&__icon-container {
text-align: center;
display: flex;
justify-content: center;
position: absolute;
width: 100%;
height: 100%;
top: 0px;
}
&__avatar-container {
height: 100%;
position: relative;
> img {
height: 100%;
}
}
&__icon-background {
background: $inlayIconBg;
opacity: 0.6;
position: absolute;
width: 100%;
height: 100%;
top: 0px;
}
&__button {
float: none !important;
}
}
}

View File

@@ -2,46 +2,25 @@
position: absolute;
top: 0;
left: 0;
z-index: $jitsipopoverZ;
display: table;
visibility: hidden;
z-index: 1010;
display: none;
max-width: 300px;
min-width: 100px;
text-align: left;
color: $popoverFontColor;
background-color: $popoverBg;
background-clip: padding-box;
border-radius: $borderRadius;
border-radius: 3px;
/*-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);*/
/*box-shadow: 0 5px 10px rgba(0, 0, 0, 0.4);*/
white-space: normal;
margin-top: -$popoverMenuPadding;
&__menu-padding,
&__menu-padding-top {
position: absolute;
width: 100px;
}
/**
* Invisible padding is added to the bottom of the popover to extend its
* height so it does not close when moving the mouse from the trigger
* element towards the popover itself.
*/
&__menu-padding {
bottom: -$popoverMenuPadding;
height: $popoverMenuPadding;
}
/**
* Invisible padding is added to the top of the popover to extend its height
* so it does not close automatically when its height is shrunk from showing
* less video statistics.
*/
&__menu-padding-top {
height: 20px;
top: -20px;
width: 100px;
position: absolute;
bottom: -$popoverMenuPadding;
}
&__showmore {
@@ -65,28 +44,4 @@
border-width: 5px;
border-bottom-width: 0;
}
/**
* Override default "top" styles to support popovers appearing from the
* left of the popover trigger element.
*/
&.left {
margin-left: -$popoverMenuPadding;
margin-top: 0;
.arrow {
border-color: transparent transparent transparent $popoverBg;
border-width: 5px 0px 5px 5px;
margin-left: 0;
margin-top: -5px;
}
.jitsipopover {
&__menu-padding {
bottom: 0;
height: 100%;
width: $popoverMenuPadding;
}
}
}
}

View File

@@ -1,18 +1,18 @@
@charset "UTF-8";
/*!
* jQuery contextMenu - Plugin for simple contextMenu handling
*
* Version: v2.1.1
*
* Authors: Björn Brala (SWIS.nl), Rodney Rehm, Addy Osmani (patches for FF)
* Web: http://swisnl.github.io/jQuery-contextMenu/
*
* Copyright (c) 2011-2016 SWIS BV and contributors
*
* Licensed under
* MIT License http://www.opensource.org/licenses/mit-license
*
* Date: 2016-02-28T09:53:18.890Z
/*!
* jQuery contextMenu - Plugin for simple contextMenu handling
*
* Version: v2.1.1
*
* Authors: Björn Brala (SWIS.nl), Rodney Rehm, Addy Osmani (patches for FF)
* Web: http://swisnl.github.io/jQuery-contextMenu/
*
* Copyright (c) 2011-2016 SWIS BV and contributors
*
* Licensed under
* MIT License http://www.opensource.org/licenses/mit-license
*
* Date: 2016-02-28T09:53:18.890Z
*/
@font-face {
font-family: "context-menu-icons";
@@ -88,7 +88,7 @@
list-style-type: none;
background: #fff;
border: 1px solid #bebebe;
border-radius: $borderRadius;
border-radius: 3px;
-webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, .5);
box-shadow: 0 2px 5px rgba(0, 0, 0, .5);
}
@@ -143,7 +143,7 @@
position: absolute;
top: 50%;
right: 8px;
z-index: $zindex1;
z-index: 1;
width: 0;
height: 0;
content: '';
@@ -156,8 +156,8 @@
transform: translateY(-50%);
}
/**
* Inputs
/**
* Inputs
*/
.context-menu-item.context-menu-input {
padding: 5px 10px;

View File

@@ -6,7 +6,7 @@
overflow: hidden;
padding: 20px;
margin-left: 10px;
z-index: $zindex10;
z-index: 10;
border-radius: $borderRadius;
background-attachment: scroll;
background-size: auto auto;

View File

@@ -1,10 +1,34 @@
/*Initialize*/
div.loginmenu {
ul.loginmenu {
font-family: $baseFontFamily;
line-height: normal;
display:none;
position: absolute;
margin: 0;
padding: 5px;
top: 40px;
left: 20px;
padding-bottom: 7px;
top: 45px;
left: -5px;
background-color: rgba(0,0,0,0.9);
border: 1px solid rgba(256, 256, 256, 0.2);
border-radius:8px;
}
ul.loginmenu li {
list-style-type: none;
padding: 7px;
color: #fff;
font-size: 11pt;
cursor: default;
white-space: pre;
}
ul.loginmenu:after {
content: url('../images/dropdownPointer.png');
display: block;
position: absolute;
top: -7px;
left: 18px;
}
a.disabled {
@@ -12,7 +36,23 @@ a.disabled {
pointer-events: none;
}
.loginmenuPadding {
width: 50px;
height: 30px;
position: absolute;
top: -30px;
left: 0px;
}
.loginmenu.extendedToolbarPopup {
top: 20px;
left: 40px;
left: 55px;
top: 0px;
}
ul.loginmenu.extendedToolbarPopup:after {
content: url('../images/leftDropdownPointer.png');
display: block;
position: absolute;
top: 18px;
left: -7px;
}

View File

@@ -2,52 +2,52 @@
* Animation mixin.
*/
@mixin animation($animate...) {
$max: length($animate);
$animations: '';
$max: length($animate);
$animations: '';
@for $i from 1 through $max {
$animations: #{$animations + nth($animate, $i)};
@for $i from 1 through $max {
$animations: #{$animations + nth($animate, $i)};
@if $i < $max {
$animations: #{$animations + ", "};
}
@if $i < $max {
$animations: #{$animations + ", "};
}
-webkit-animation: $animations;
-moz-animation: $animations;
-o-animation: $animations;
animation: $animations;
}
-webkit-animation: $animations;
-moz-animation: $animations;
-o-animation: $animations;
animation: $animations;
}
@mixin flex() {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
}
/**
* Keyframes mixin.
*/
@mixin keyframes($animationName) {
@-webkit-keyframes #{$animationName} {
@content;
}
@-moz-keyframes #{$animationName} {
@content;
}
@-o-keyframes #{$animationName} {
@content;
}
@keyframes #{$animationName} {
@content;
}
@-webkit-keyframes #{$animationName} {
@content;
}
@-moz-keyframes #{$animationName} {
@content;
}
@-o-keyframes #{$animationName} {
@content;
}
@keyframes #{$animationName} {
@content;
}
}
@mixin circle($diameter) {
width: $diameter;
height: $diameter;
border-radius: 50%;
width: $diameter;
height: $diameter;
border-radius: 50%;
}
/**
@@ -60,10 +60,10 @@
}
@mixin absoluteAligning() {
top: 50%;
left: 50%;
position: absolute;
@include transform(translate(-50%, -50%));
top: 50%;
left: 50%;
position: absolute;
@include transform(translate(-50%, -50%));
}
/**
@@ -75,121 +75,79 @@
}
@mixin transform($func) {
-moz-transform: $func;
-ms-transform: $func;
-webkit-transform: $func;
-o-transform: $func;
transform: $func;
-moz-transform: $func;
-ms-transform: $func;
-webkit-transform: $func;
-o-transform: $func;
transform: $func;
}
@mixin transition($transition...) {
-moz-transition: $transition;
-o-transition: $transition;
-webkit-transition: $transition;
transition: $transition;
-moz-transition: $transition;
-o-transition: $transition;
-webkit-transition: $transition;
transition: $transition;
}
/**
* Mixin styling a placeholder.
**/
* Mixin styling placeholder
**/
@mixin placeholder() {
$selectors: (
"::-webkit-input-placeholder",
"::-moz-placeholder",
":-moz-placeholder",
":-ms-input-placeholder"
);
$selectors: (
"::-webkit-input-placeholder",
"::-moz-placeholder",
":-moz-placeholder",
":-ms-input-placeholder"
);
@each $selector in $selectors {
#{$selector} {
@content;
}
@each $selector in $selectors {
#{$selector} {
@content;
}
}
/**
* Mixin styling a slider track for different browsers.
**/
@mixin slider() {
$selectors: (
"input[type=range]::-webkit-slider-runnable-track",
"input[type=range]::-moz-range-track",
"input[type=range]::-ms-track"
);
@each $selector in $selectors {
#{$selector} {
@content;
}
}
}
/**
* Mixin styling a slider thumb for different browsers.
**/
@mixin slider-thumb() {
$selectors: (
"input[type=range]::-webkit-slider-thumb",
"input[type=range]::-moz-range-thumb",
"input[type=range]::-ms-thumb"
);
@each $selector in $selectors {
#{$selector} {
@content;
}
}
}
@mixin box-shadow($h, $y, $blur, $color, $inset: false) {
@if $inset {
-webkit-box-shadow: inset $h $y $blur $color;
-moz-box-shadow: inset $h $y $blur $color;
box-shadow: inset $h $y $blur $color;
} @else {
-webkit-box-shadow: $h $y $blur $color;
-moz-box-shadow: $h $y $blur $color;
box-shadow: $h $y $blur $color;
}
@if $inset {
-webkit-box-shadow: inset $h $y $blur $color;
-moz-box-shadow: inset $h $y $blur $color;
box-shadow: inset $h $y $blur $color;
} @else {
-webkit-box-shadow: $h $y $blur $color;
-moz-box-shadow: $h $y $blur $color;
box-shadow: $h $y $blur $color;
}
}
@mixin no-box-shadow {
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
@mixin box-sizing($box-model) {
-webkit-box-sizing: $box-model; // Safari <= 5
-moz-box-sizing: $box-model; // Firefox <= 19
box-sizing: $box-model;
-webkit-box-sizing: $box-model; // Safari <= 5
-moz-box-sizing: $box-model; // Firefox <= 19
box-sizing: $box-model;
}
@mixin border-radius($radius) {
-webkit-border-radius: $radius;
border-radius: $radius;
/* stops bg color from leaking outside the border: */
background-clip: padding-box;
-webkit-border-radius: $radius;
border-radius: $radius;
/* stops bg color from leaking outside the border: */
background-clip: padding-box;
}
@mixin opacity($opacity) {
opacity: $opacity;
$opacity-ie: $opacity * 100;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=$opacity-ie);
filter: alpha(opacity=$opacity-ie); //IE8
opacity: $opacity;
$opacity-ie: $opacity * 100;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=$opacity-ie);
filter: alpha(opacity=$opacity-ie); //IE8
}
@mixin text-truncate {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/**
* Creates a semi-transparent background with the given color and alpha
* (opacity) value.
*/
@mixin transparentBg($color, $alpha) {
background-color: rgba(red($color), green($color), blue($color), $alpha);
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

View File

@@ -1,15 +1,11 @@
.notice {
position: absolute;
left: 50%;
z-index: $zindex3;
#notice {
position: relative;
z-index: 3;
margin-top: 6px;
@include transform(translateX(-50%));
&__message {
background-color: #000000;
color: white;
padding: 3px;
border-radius: 5px;
}
}
#noticeText {
background-color: #000000;
color: white;
padding: 3px;
border-radius: 5px;
}

View File

@@ -2,7 +2,7 @@
position: absolute;
top: 0;
left: 0;
z-index: $popoverZ;
z-index: 1015;
display: none;
max-width: 300px;
min-width: 100px;

View File

@@ -6,6 +6,7 @@
padding: 0;
margin: 2px 0;
bottom: 0;
width: 100px;
height: auto;
&:first-child {
@@ -23,8 +24,7 @@
}
// Link Appearance
&__link,
&__contents {
&__link {
display: block;
box-sizing: border-box;
text-decoration: none;
@@ -46,32 +46,11 @@
vertical-align: middle;
}
&__contents {
display: flex;
/**
* Positioning styles on the slider and its container are used to make
* the container fit the popup width, by removing the slider from the
* page flow, and then making the slider fit the container.
*/
.popupmenu__slider_container {
position: relative;
width: 100%;
.popupmenu__slider {
position: absolute;
top: 50%;
transform: translate(0, -50%);
width: 100%;
}
}
}
&__icon {
vertical-align: middle;
position: relative;
display: inline-block;
min-width: 20px;
width: 20px;
height: 100%;
text-align: center;
@@ -87,9 +66,4 @@
span.remotevideomenu:hover ul.popupmenu, ul.popupmenu:hover {
display:block !important;
}
.remote-control-spinner {
top: 6px;
left: 2px;
}
}

View File

@@ -1,3 +1,10 @@
html, body {
width: 100%;
height:100%;
color: $defaultColor;
background: $defaultBackground;
}
.redirectPageMessage {
width: 30%;
margin: 20% auto;

View File

@@ -2,7 +2,7 @@
* Toolbar side panel main container element.
*/
#sideToolbarContainer {
background-color: $sideToolbarContainerBg;
background-color: rgba(0,0,0,0.8);
height: 100%;
left: $defaultToolbarSize;
max-width: $sidebarWidth;
@@ -10,7 +10,7 @@
position: absolute;
top: 0;
width: 0;
z-index: $sideToolbarContainerZ;
z-index: 800;
/**
* Labels inside the side panel.
@@ -113,12 +113,6 @@
text-align: center;
}
#deviceOptionsWrapper {
button {
float: none;
}
}
/**
* Profile
*/

View File

@@ -12,7 +12,7 @@
*/
.toast-title,
.toast-message .title {
.toast-message .nickname {
font-weight: bold;
margin: 0 0 3px;
@include text-truncate;
@@ -94,7 +94,7 @@
#toast-container.notification-bottom-right {
$videoOffset: 2 * ($thumbnailVideoMargin + $thumbnailsBorder) + $thumbnailVideoBorder;
bottom: 135px;
right: $filmstripToggleButtonWidth + $videoOffset;
right: $hideFilmstripButtonWidth + $videoOffset;
}
#toast-container * {
@@ -104,4 +104,4 @@
#toast-container .toast {
width: $notificationWidth;
margin: 0 0 8px;
}
}

View File

@@ -1,271 +1,184 @@
.toolbar {
background-color: $toolbarBackground;
position: relative;
z-index: $toolbarZ;
height: 100%;
pointer-events: auto;
/**
* Splitter button in the toolbar.
*/
&__splitter {
display: inline-block;
vertical-align: middle;
width: 1px;
height: 50%;
margin: 0 $splitterToolbarButtonMargin;
background: $splitterColor;
}
}
#mainToolbarContainer{
display: block;
position: absolute;
text-align: center;
top:0;
left:0;
right:0;
z-index: $toolbarZ;
pointer-events: none;
min-height: 100px;
opacity: 0;
}
#subject {
position: relative;
z-index: 3;
width: auto;
padding: 5px;
margin-left: 40%;
margin-right: 40%;
text-align: center;
background: linear-gradient(to bottom, rgba(255,255,255,.85) , rgba(255,255,255,.35));
box-shadow: 0 0 2px #000000, 0 0 10px #000000;
border-bottom-left-radius: 12px;
border-bottom-right-radius: 12px;
}
#mainToolbar {
height: $defaultToolbarSize;
display: inline-block;
position: relative;
top: 30px;
margin-left: auto;
margin-right: auto;
width: auto;
border-radius: 3px;
.button:first-child {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}
.button:last-child {
border-bottom-right-radius: 3px;
border-top-right-radius: 3px;
}
}
#extendedToolbar {
display: -moz-box;
display: -ms-flexbox;
display: -webkit-box;
display: -webkit-flex;
display: flex;
width: $defaultToolbarSize;
height: 100%;
top: 0;
left: 0;
padding-top: 10px;
box-sizing: border-box;
flex-direction: column;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
transform: translateX(-100%);
-webkit-transform: translateX(-100%);
}
#toolbar_button_hangup {
color: #BF2117;
font-size: $hangupFontSize !important;
}
#toolbar_button_etherpad {
display: none;
}
#mainToolbar a.button:last-child::after {
content: none;
}
.button {
display: inline-block;
position: relative;
color: #FFFFFF;
top:0px;
width: 50px;
height: 50px;
cursor: pointer;
text-align: center;
z-index: 1;
font-size: $toolbarFontSize !important;
line-height: 50px !important;
vertical-align: middle;
}
.button[disabled] {
opacity: 0.5;
}
.button.unclickable {
cursor: default;
}
.button.toggled {
background: $toolbarToggleBackground !important;
}
a.button.unclickable:hover,
a.button.unclickable:active,
a.button.unclickable.selected{
cursor: default;
background: none;
}
a.button:hover,
a.button:active,
a.button.selected {
cursor: pointer;
text-decoration: none;
// sum opacity with background layer should give us 0.8
background: $toolbarSelectBackground;
}
a.button>#avatar {
width: 30px;
border-radius: 50%;
padding-top: 10px;
padding-bottom: 10px;
}
#feedbackButton {
margin-top: auto;
}
/**
* Round badge.
*/
.badge-round {
background-color: $toolbarBadgeBackground;
border-radius: 50%;
box-sizing: border-box;
color: $toolbarBadgeColor;
font-size: 9px;
line-height: 13px;
font-weight: 700;
text-align: center;
border-radius: 50%;
min-width: 13px;
overflow: hidden;
text-overflow: ellipsis;
box-sizing: border-box;
vertical-align: middle;
// Do not inherit the font-family from the toolbar button, because it's an
// icon style.
font-family: $baseFontFamily;
font-size: 9px;
font-weight: 700;
line-height: 13px;
min-width: 13px;
overflow: hidden;
text-align: center;
text-overflow: ellipsis;
vertical-align: middle;
}
.toolbar-container {
display: block;
left:0;
min-height: 100px;
opacity: 0;
pointer-events: none;
position: absolute;
right:0;
text-align: center;
top:0;
z-index: $toolbarZ;
}
/**
* Common toolbar styles.
* Toolbar specific round badge.
*/
.toolbar {
color: $modalTextColor;
height: 100%;
pointer-events: auto;
position: relative;
z-index: $toolbarZ;
/**
* Toolbar button styles.
*/
.button {
color: $toolbarButtonColor;
cursor: pointer;
z-index: $zindex1;
display: inline-block;
font-size: $toolbarFontSize;
height: $defaultToolbarSize;
line-height: $defaultToolbarSize;
position: relative;
text-align: center;
top:0px;
vertical-align: middle;
width: $defaultToolbarSize;
&_hangup {
color: $hangupColor;
font-size: $hangupFontSize;
}
&[disabled] {
opacity: 0.5;
}
&:hover, &:active {
cursor: pointer;
text-decoration: none;
}
&:not(.toggled) {
&:hover, &:active {
// sum opacity with background layer should give us 0.8
background: $toolbarSelectBackground;
}
}
&.toggled {
background: $toolbarToggleBackground;
&.icon-camera {
@extend .icon-camera-disabled;
}
&.icon-full-screen {
@extend .icon-exit-full-screen;
}
&.icon-microphone {
@extend .icon-mic-disabled;
}
&.icon-visibility {
@extend .icon-visibility-off;
}
}
&.unclickable {
cursor: default;
&:hover, &:active, &.selected {
background: none;
cursor: default;
}
}
}
/**
* Primary toolbar styles.
*/
&_primary {
background-color: $toolbarBackground;
position: absolute;
left: 50%;
top: 30px;
display: inline-block;
width: auto;
height: $defaultToolbarSize;
border-radius: 3px;
opacity: 0;
@include transform(translateX(-50%));
.button:first-child {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}
.button:last-child {
border-bottom-right-radius: 3px;
border-top-right-radius: 3px;
}
}
&_primary a.button:last-child::after {
content: none;
}
/**
* Secondary toolbar styles.
*/
&_secondary {
background-color: $secondaryToolbarBg;
position: absolute;
align-items: center;
box-sizing: border-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-box;
display: -webkit-flex;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
height: 100%;
justify-content: flex-start;
left: 0;
padding-top: 10px;
top: 0;
transform: translateX(-100%);
width: $defaultToolbarSize;
-webkit-transform: translateX(-100%);
.button {
font-size: $secToolbarFontSize;
height: $secToolbarLineHeight;
line-height: $secToolbarLineHeight;
}
.button.toggled:not(.icon-raised-hand):not(.button-active) {
background: $secondaryToolbarBg;
cursor: pointer;
text-decoration: none;
&.unclickable {
cursor: default;
&:hover, &:active, &.selected {
background: none;
cursor: default;
}
}
}
}
/**
* Styles the toolbar in filmstrip-only mode.
*/
&_filmstrip-only {
border-radius: 3px;
display: inline-block;
height: auto;
width: $defaultFilmStripOnlyToolbarSize;
.button {
height: 37px;
line-height: 37px !important;
width: 37px;
}
.button:first-child {
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}
.button:last-child {
border-bottom-right-radius: 3px;
border-bottom-left-radius: 3px;
}
}
/**
* Toolbar specific round badge.
*/
.badge-round {
bottom: 9px;
position: absolute;
right: 9px;
}
}
.filmstrip-only {
.toolbox,
.toolbox-toolbars {
align-items: center;
display: flex;
}
}
.subject {
background: linear-gradient(to bottom, rgba(255,255,255,.85) , rgba(255,255,255,.35));
border-bottom-left-radius: 12px;
border-bottom-right-radius: 12px;
box-shadow: 0 0 2px #000000, 0 0 10px #000000;
margin-left: 40%;
margin-right: 40%;
padding: 5px;
position: relative;
text-align: center;
width: auto;
z-index: $zindex3;
&.subject_slide-in {
top: 80px;
@include transition(top .3s ease-in);
}
&.subject_slide-out {
top: 0;
@include transition(top .3s ease-out);
}
}
#toolbar_button_profile {
height: $toolbarAvatarSize + 2*$toolbarAvatarPadding;
}
a.button>#avatar {
border-radius: 50%;
padding-bottom: $toolbarAvatarPadding;
padding-top: $toolbarAvatarPadding;
width: $toolbarAvatarSize;
}
#feedbackButton {
margin-top: auto;
.toolbar .badge-round {
position: absolute;
right: 9px;
bottom: 9px;
}
/**
@@ -359,13 +272,9 @@ a.button>#avatar {
* START of fade in animation for main toolbar
*/
.fadeIn {
opacity: 1;
@include transition(all .3s ease-in);
@include animation('fadeIn .3s linear .2s forwards');
}
.fadeOut {
opacity: 0;
@include transition(all .3s ease-out);
@include animation('fadeOut .5s linear forwards');
}

View File

@@ -4,21 +4,22 @@
* Style variables
*/
$baseFontFamily: 'open_sanslight', 'Helvetica Neue', Helvetica, Arial, sans-serif;
$hangupColor: #bf2117;
$toolbarFontSize: 1.9em;
$hangupFontSize: 2em;
/**
* Size variables.
*/
$defaultToolbarSize: 50px;
// Video layout.
$thumbnailToolbarHeight: 22px;
$thumbnailIndicatorBorder: 2px;
$thumbnailIndicatorSize: $thumbnailToolbarHeight;
$thumbnailIndicatorBorder: 0;
$thumbnailIndicatorSize: 3em;
$thumbnailVideoMargin: 2px;
$thumbnailsBorder: 2px;
$thumbnailVideoBorder: 2px;
$filmstripToggleButtonWidth: 17px;
$hideFilmstripButtonWidth: 17px;
/**
@@ -33,23 +34,23 @@ $tooltipBg: rgba(0,0,0, 0.7);
/**
* Toolbar
*/
$defaultToolbarSize: 50px;
$defaultFilmStripOnlyToolbarSize: 37px;
$secToolbarFontSize: 1.9em;
$secToolbarLineHeight: 45px;
$toolbarAvatarPadding: 10px;
$toolbarAvatarSize: 40px;
$toolbarFontSize: 1.9em;
$toolbarTitleColor: #FFFFFF;
$toolbarTitleFontSize: 19px;
$toolbarBackground: rgba(0, 0, 0, 0.5);
$toolbarSelectBackground: rgba(0, 0, 0, .6);
$toolbarBadgeBackground: #165ECC;
$toolbarBadgeColor: #FFFFFF;
$toolbarToggleBackground: #12499C;
$splitterToolbarButtonMargin: 18px;
/**
/*
* Main controls
* TODO: looks like we don't use it
*/
$inputSemiBackground: rgba(132, 132, 132, .8);
$inputLightBackground: #EBEBEB;
/**
/*
* Video layout
*/
$videoThumbnailHovered: rgba(22, 94, 204, .4);
@@ -77,14 +78,6 @@ $rateStarDefault: #ccc;
$rateStarActivity: #165ecc;
$rateStarSize: 34px;
/**
* Modals
*/
$modalButtonFontSize: 14px;
$modalMockAKInputBackground: #fafbfc;
$modalMockAKInputBorder: 1px solid #f4f5f7;
$modalTextColor: #333;
/**
* Notifications
*/
@@ -102,7 +95,7 @@ $notificationWidth: 215px;
/**
* Misc.
*/
$borderRadius: 4px;
$borderRadius: 3px;
$defaultWatermarkLink: '../images/watermark.png';
$sidebarWidth: 220px;
$popoverMenuPadding: 13px;
@@ -111,26 +104,13 @@ $happySoftwareBackground: transparent;
/**
* Z-indexes. TODO: Replace this by a function.
*/
$zindex0: 0;
$zindex1: 1;
$zindex2: 2;
$zindex3: 3;
$filmstripVideosZ: 5;
$zindex10: 10;
$reloadZ: 20;
$poweredByZ: 100;
$ringingZ: 300;
$sideToolbarContainerZ: 300;
$toolbarZ: 400;
$tooltipsZ: 401;
$dropdownMaskZ: 900;
$tooltipsZ: 901;
$toolbarZ: 900;
$overlayZ: 902;
$notificationZ: 1012;
$ringingZ: 800;
$dropdownZ: 901;
$centeredVideoLabelZ: 1010;
$notificationZ: 1011;
$jitsipopoverZ: 1012;
$popoverZ: 1015;
$overlayZ: 1016;
$dropdownMaskZ: 900;
/**
* Font Colors
@@ -146,17 +126,4 @@ $defaultDarkFontColor: #000;
$inputControlEmColor: #f29424;
//buttons
$linkFontColor: #489afe;
$linkHoverFontColor: #287ade;
$formPadding: 16px;
/**
* Unsupported browser
*/
$primaryUnsupportedBrowserButtonBgColor: #17a0db;
$unsupportedBrowserButtonBgColor: #ff9a00;
$unsupportedBrowserTextColor: #4a4a4a;
$unsupportedBrowserTextSmallFontSize: 17px;
$unsupportedBrowserTitleColor: #fff;
$unsupportedBrowserTitleFontSize: 24px;
$unsupportedDesktopBrowserTextColor: rgba(255, 255, 255, 0.7);
$unsupportedDesktopBrowserTextFontSize: 21px;
$linkHoverFontColor: #287ade;

View File

@@ -1,173 +0,0 @@
/**
* Override other styles to support vertical filmstrip mode.
*/
.vertical-filmstrip {
.filmstrip {
align-items: flex-end;
box-sizing: border-box;
display: flex;
flex-direction: column-reverse;
height: 100%;
/**
* Hide videos by making them slight to the right.
*/
.filmstrip__videos {
right: 0;
transition: right 2s;
&.hidden {
bottom: auto;
right: -196px;
}
}
#filmstripLocalVideo {
height: auto;
justify-content: flex-end;
}
/**
* Remove unnecssary padding that is normally used to prevent horizontal
* filmstrip from overlapping the left edge of the screen.
*/
#filmstripLocalVideo,
#filmstripRemoteVideos {
padding: 0;
}
#filmstripRemoteVideos {
display: flex;
flex: 1;
flex-direction: column;
height: auto;
overflow-x: hidden !important;
.remote-videos-container {
flex-direction: column;
}
}
/**
* Rotate the hide filmstrip icon so it points towards the right edge
* of the screen.
*/
&__toolbar {
transform: rotate(-90deg);
}
/**
* Move the remote video menu trigger to the bottom left of the
* video thumbnail.
*/
.remotevideomenu {
bottom: 0;
left: 0;
top: auto;
right: auto;
margin-bottom: 7px;
transform: translate3d(0,0,0);
}
#remoteVideos {
flex-direction: column-reverse;
flex-grow: 1;
}
.videocontainer {
&__toolbar,
&__toptoolbar {
transform: translate3d(0,0,0);
}
/**
* Move status icons to the bottom right of the thumbnail.
*/
&__toolbar {
text-align: right;
.toolbar-icon {
float: none;
margin: auto;
}
}
}
}
&.filmstrip-only {
.filmstrip {
flex-direction: row-reverse;
}
.filmstrip__videos-filmstripOnly {
height: 100%;
}
/**
* In filmstrip only mode, the toolbar is normally displayed in the
* vertical center of the filmstrip strip. In vertical filmstrip mode,
* that alignment makes the toolbar appear floating and detached from
* the filmstrip. So, instead anchor the toolbar next to the local
* video.
*/
.toolbar_filmstrip-only {
bottom: 0;
top: auto;
transform: none;
}
}
/**
* These styles are for the video labels that display on the top right. The
* styles adjust the labels' positioning as the filmstrip itself or
* filmstrip's remote videos appear and disappear.
*
* The class with-filmstrip is for when the filmstrip is visible.
* The class without-filmstrip is for when the filmstrip has been toggled to
* be hidden.
* The class opening is for when the filmstrip is transitioning from hidden
* to visible.
* The class with-remote-videos is for when the filmstrip has remote videos
* displayed, as opposed to 1-on-1 mode where they might be hidden.
* The class without-remote-videos is for when the filmstrip is visible
* but it has no videos to display.
*/
.video-state-indicator.moveToCorner {
transition: right 0.5s;
&.with-filmstrip.with-remote-videos {
&#recordingLabel {
right: 200px;
}
&#videoResolutionLabel {
right: 150px;
}
}
&.with-filmstrip.without-remote-videos {
transition-delay: 0.5s;
}
&.with-filmstrip.with-remote-videos.opening {
transition: 0.9s;
transition-timing-function: ease-in-out;
}
&.without-filmstrip {
transition: 1.2s ease-in-out;
transition-delay: 0.1s;
}
}
/**
* Move toastr closer to the bottom of the screen and move left to avoid
* overlapping of videos when they are configured at default height.
*/
#toast-container {
&.notification-bottom-right {
bottom: 25px;
right: 130 + 2 * ($thumbnailVideoMargin + $thumbnailsBorder) + $thumbnailVideoBorder;
}
}
}

View File

@@ -12,26 +12,15 @@
overflow: hidden;
}
.video_blurred_container {
height: 100%;
filter: blur(40px);
left: 0;
overflow: hidden;
position: absolute;
top: 0;
width: 100%;
}
.videocontainer {
position: relative;
text-align: center;
&__background {
@include topLeft();
background-color: black;
border-radius: $borderRadius;
width: 100%;
height: 100%;
background-color: black;
}
/**
@@ -41,7 +30,7 @@
&__toptoolbar {
position: absolute;
left: 0;
z-index: $zindex3;
z-index: 3;
width: 100%;
box-sizing: border-box; // Includes the padding in the 100% width.
}
@@ -58,34 +47,26 @@
padding: $toolbarPadding;
padding-bottom: 0;
.connection-indicator,
span.indicator {
margin-right: em(5, 8);
}
span.indicator {
display: none;
&:last-child {
margin-right: 0;
}
}
.connection-indicator,
span.indicator {
position: relative;
font-size: 8px;
text-align: center;
line-height: $thumbnailIndicatorSize;
display: none;
padding: 0;
margin-right: em(5, 8);
float: left;
@include circle($thumbnailIndicatorSize);
box-sizing: border-box;
z-index: $zindex3;
z-index: 3;
background: $dominantSpeakerBg;
color: $thumbnailPictogramColor;
border: $thumbnailIndicatorBorder solid $thumbnailPictogramColor;
&:last-child {
margin-right: 0;
}
.indicatoricon {
@include absoluteAligning();
}
@@ -115,11 +96,6 @@
color: #FFFFFF;/*#15A1ED*/
overflow: hidden;
}
&_ninja
{
font-size: 1.5em;
}
}
.icon-connection,
@@ -130,19 +106,12 @@
}
&__hoverOverlay {
background: rgba(0,0,0,.6);
border-radius: $borderRadius;
position: relative;
width: 100%;
height: 100%;
visibility: hidden;
z-index: $zindex2;
}
&.audio-only {
.videoThumbnailProblemFilter {
filter: none;
}
background: rgba(0,0,0,.6);
z-index: 2;
}
}
@@ -157,10 +126,10 @@
-o-transform: scale(-1, 1);
}
#localVideoWrapper video,
#localVideoWrapper object {
border-radius: $borderRadius !important;
#localVideoWrapper>video,
#localVideoWrapper>object {
cursor: hand;
border-radius:1px !important;
object-fit: cover;
}
@@ -171,10 +140,6 @@
text-align: center;
}
#largeVideoWrapper {
box-shadow: 0 0 20px -2px #444;
}
#largeVideo,
#largeVideoWrapper
{
@@ -183,8 +148,8 @@
#sharedVideo,
#etherpad,
#localVideoWrapper video,
#localVideoWrapper object,
#localVideoWrapper>video,
#localVideoWrapper>object,
#localVideoWrapper,
#largeVideoWrapper,
#largeVideoWrapper>video,
@@ -194,7 +159,7 @@
position: absolute;
left: 0;
top: 0;
z-index: $zindex1;
z-index: 1;
width: 100%;
height: 100%;
}
@@ -204,7 +169,7 @@
}
#etherpad {
z-index: $zindex0;
z-index: 0;
}
/**
@@ -226,7 +191,7 @@
overflow: hidden;
white-space: nowrap;
line-height: $thumbnailToolbarHeight;
z-index: $zindex2;
z-index: 2;
}
/**
@@ -246,7 +211,6 @@
.videocontainer .displayname {
pointer-events: none;
padding: 0 3px 0 3px;
}
.videocontainer .editdisplayname {
@@ -266,7 +230,7 @@
padding: 3px 5px;
font-size: 9pt;
cursor: pointer;
z-index: $zindex2;
z-index: 2;
}
/**
@@ -301,11 +265,11 @@
margin: 0px 0px 0px 5px;
}
.raisehandindicator {
#raisehandindicator {
background: $raiseHandBg;
}
.connection-indicator {
#connectionindicator {
background: $connectionIndicatorBg;
}
@@ -315,23 +279,18 @@
position: absolute;
top: 0px;
right: 0;
margin-top: 7px;
z-index: $zindex3;
margin: 7px;
z-index: 3;
width: 18px;
height: 13px;
color: #FFF;
font-size: 10pt;
>i{
cursor: hand;
}
font-size: 8pt;
}
/**
* Audio indicator on video thumbnails.
*/
.videocontainer>span.audioindicator,
.videocontainer>.audioindicator-container {
.videocontainer>span.audioindicator {
position: absolute;
display: inline-block;
left: 6px;
@@ -339,7 +298,7 @@
margin-top: -17px;
width: 6px;
height: 35px;
z-index: $zindex2;
z-index: 2;
border: none;
.audiodot-top,
@@ -382,13 +341,13 @@
background-clip: padding-box;
-webkit-border-radius: 5px;
-webkit-background-clip: padding-box;
z-index: $reloadZ; /*The reload button should appear on top of the header!*/
z-index: 20; /*The reload button should appear on top of the header!*/
}
.audiolevel {
display: inline-block;
position: absolute;
z-index: $zindex0;
z-index: 0;
border-radius:1px;
pointer-events: none;
}
@@ -446,7 +405,7 @@
.noMic {
position: absolute;
border-radius: 8px;
z-index: $zindex1;
z-index: 1;
width: 100%;
height: 100%;
background-image: url("../images/noMic.png");
@@ -458,7 +417,7 @@
.noVideo {
position: absolute;
border-radius: 8px;
z-index: $zindex1;
z-index: 1;
width: 100%;
height: 100%;
background-image: url("../images/noVideo.png");
@@ -491,7 +450,7 @@
display: none;
position: absolute;
width: auto;
z-index: $zindex2;
z-index: 2;
font-weight: 600;
font-size: 14px;
text-align: center;
@@ -512,10 +471,9 @@
#localConnectionMessage {
display: none;
position: absolute;
left: 0;
width: 100%;
top:50%;
z-index: $zindex2;
z-index: 2;
font-weight: 600;
font-size: 14px;
text-align: center;
@@ -527,42 +485,31 @@
0px 0px 1px rgba(0,0,0,0.3);
}
.filmstrip-only {
#videoResolutionLabel {
display: none;
}
}
.video-state-indicator {
background: $videoStateIndicatorBackground;
color: $videoStateIndicatorColor;
cursor: pointer;
font-size: 13px;
height: 40px;
line-height: 20px;
text-align: center;
min-width: 40px;
height: 40px;
padding: 10px 5px;
border-radius: 50%;
position: absolute;
box-sizing: border-box;
i {
cursor: pointer;
}
}
#videoResolutionLabel,
.centeredVideoLabel.moveToCorner {
z-index: $tooltipsZ;
.centeredVideoLabel {
display: none;
z-index: 1011;
}
.centeredVideoLabel {
bottom: 45%;
border-radius: 2px;
display: none;
-webkit-transition: all 2s 2s linear;
transition: all 2s 2s linear;
z-index: $centeredVideoLabelZ;
&.moveToCorner {
bottom: auto;
@@ -577,60 +524,4 @@
.moveToCorner + .moveToCorner {
right: 80px;
}
.video-state-indicator-menu {
display: none;
padding: 10px;
position: absolute;
right: -10px;
top: 20px;
.video-state-indicator-menu-options {
background: $popoverBg;
border-radius: 3px;
color: $popoverFontColor;
margin-top: 20px;
padding: 5px 0;
position: relative;
div {
cursor: pointer;
padding: 10px;
padding-right: 30px;
text-align: left;
white-space: nowrap;
&.active {
background: $toolbarToggleBackground;
}
&:hover:not(.active) {
background: $popupMenuSelectedItemBackground;
}
i {
margin-right: 5px;
vertical-align: middle;
}
}
}
.video-state-indicator-menu-options::after {
content: " ";
border-color: transparent transparent $popoverBg transparent;
border-style: solid;
border-width: 5px;
position: absolute;
right: 15px;
top: -10px;
}
}
.video-state-indicator:hover,
.video-state-indicator *:hover {
background: $toolbarSelectBackground;
.video-state-indicator-menu {
display: block;
}
}
}

View File

@@ -22,7 +22,7 @@
font-weight: 500;
font-size: 16px;
color: #acacac;
z-index: $zindex2;
z-index: 2;
}
#disable_welcome:checked + label
@@ -35,7 +35,7 @@
font-weight: 500;
font-size: 16px;
color: #acacac;
z-index: $zindex2;
z-index: 2;
}
#enter_room_form {
@@ -50,7 +50,7 @@
float: left;
}
.domain-name
#domain_name
{
float: left;
height: 55px;
@@ -61,51 +61,37 @@
color: $defaultDarkColor;
}
.enter-room {
&__field {
font-size: 15px;
border: none;
-webkit-appearance: none;
width: 228px;
height: 55px;
line-height: 55px;
font-weight: 500;
box-shadow: none;
float: left;
background-color: #FFFFFF;
position: relative;
z-index: $zindex2;
}
#enter_room_field {
font-size: 15px;
border: none;
-webkit-appearance: none;
width: 228px;
height: 55px;
line-height: 55px;
font-weight: 500;
box-shadow: none;
float: left;
background-color: #FFFFFF;
position: relative;
z-index: 2;
}
&__reload {
display: block;
width: 30px;
color: #acacac;
font-size: 1.9em;
line-height: 55px;
z-index: $zindex3;
float: left;
cursor: pointer;
text-align: center;
}
&__button {
width: 73px;
height: 45px;
background-color: #21B9FC;
moz-border-radius: 1px;
-webkit-border-radius: 1px;
color: #ffffff;
font-weight: 600;
border: none;
margin-top: 5px;
font-size: 19px;
padding-top: 6px;
outline: none;
float:left;
position: relative;
z-index: $zindex2;
}
#enter_room_button {
width: 73px;
height: 45px;
background-color: #21B9FC;
moz-border-radius: 1px;
-webkit-border-radius: 1px;
color: #ffffff;
font-weight: 600;
border: none;
margin-top: 5px;
font-size: 19px;
padding-top: 6px;
outline: none;
float:left;
position: relative;
z-index: 2;
}
#enter_room_container {
@@ -198,3 +184,16 @@
line-height: 22px;
font-weight: 200;
}
#reload_roomname
{
width: 30px;
color: #acacac;
font-size: 1.9em;
line-height: 55px;
z-index: 3;
float: left;
cursor: pointer;
text-align: center;
display: none;
}

View File

@@ -57,18 +57,6 @@
}
}
&_overlay {
color: $primaryButtonColor;
background-color: $overlayButtonBg;
border-radius: 2px;
border: none;
&:hover {
background-color: $primaryButtonBackground;
border: none;
}
}
&_primary {
background-color: $primaryButtonBackground;
border: 1px solid $primaryButtonBackground;
@@ -94,8 +82,4 @@
color: $linkHoverFontColor;
}
}
&_center {
float: none !important;
}
}
}

View File

@@ -1,5 +1,5 @@
.form-control {
padding: $formPadding 0;
padding: 16px 0;
&:first-child {
padding-top: 0;

View File

@@ -3,10 +3,13 @@
display: inline-block;
width: 100%;
padding: 5px 7px;
color: $inputColor;
border-radius: $borderRadius;
line-height: 32px;
height: 32px;
text-align: left;
border:1px solid $inputBorderColor;
background-color: $inputBackground;
margin-bottom: 8px;
&:last-child {

View File

@@ -1,41 +0,0 @@
/**
* Disable the default webkit styles for range inputs (sliders).
*/
input[type=range]{
-webkit-appearance: none;
background: none;
}
/**
* Disable the default focus styles for webkit range inputs (sliders).
*/
input[type=range]:focus {
outline: none;
}
/**
* Include the mixin for a range input style.
*/
@include slider {
background: $sliderTrackBackground;
border: none;
border-radius: 3px;
cursor: pointer;
height: 6px;
width: 100%;
}
/**
* Include the mixin for a range input thumb style.
*/
@include slider-thumb {
-webkit-appearance: none;
background: white;
border: 1px solid $sliderThumbBackground;
border-radius: 50%;
box-shadow: 0px 0px 1px $sliderThumbBackground;
cursor: pointer;
height: 14px;
margin-top: -4px;
width: 14px;
}

View File

@@ -8,13 +8,4 @@
text-decoration: underline;
@include transition(color .1s ease-in);
}
}
/**
* Helper links are links that are meant to open a documentation page or more
* detailed info.
*/
.helper-link {
@extend .link;
font-size: 12px;
}

View File

@@ -26,24 +26,19 @@
@import 'font';
@import 'font-awesome';
/* Fonts END */
@import 'flag-icon';
/* Fonts END */
/* Modules BEGIN */
@import 'dial-out';
@import 'toastr';
@import 'base';
@import 'utils';
@import 'overlay/overlay';
@import 'inlay';
@import 'reload_overlay/reload_overlay';
@import 'modals/desktop-picker/desktop-picker';
@import 'modals/device-selection/device-selection';
@import 'modals/dialog';
@import 'modals/feedback/feedback';
@import 'modals/speaker_stats/speaker_stats';
@import 'videolayout_default';
@import 'notice';
@import 'popup_menu';
@@ -57,6 +52,7 @@
@import 'welcome_page';
@import 'toolbars';
@import 'side_toolbar_container';
@import 'device_settings_dialog';
@import 'jquery.contextMenu';
@import 'keyboard-shortcuts';
@import 'redirect_page';
@@ -64,16 +60,12 @@
@import 'components/link';
@import 'shortcuts/main';
@import 'components/button-control';
@import 'components/input-control';
@import 'components/input-slider';
@import 'components/_input-control.scss';
@import "modals/invite/invite";
@import "connection-info";
@import 'aui-components/dropdown';
@import '404';
@import 'policy';
@import 'filmstrip';
@import 'unsupported-browser/main';
@import 'modals/invite/add-people';
@import 'vertical_filmstrip_overrides';
/* Modules END */

View File

@@ -76,39 +76,3 @@
border-bottom: 1px solid $auiBorderColor;
}
}
.modal-dialog-form {
color: $modalTextColor;
margin-top: 5px !important;
.input-control {
background: $modalMockAKInputBackground;
border: $modalMockAKInputBorder;
color: inherit;
}
&-error {
margin-bottom: 8px;
}
}
.modal-dialog-footer {
font-size: $modalButtonFontSize;
}
/**
* Styling inline dialog errors.
*/
.inline-dialog-error {
margin-top: 16px;
&-text {
color: $dialogErrorText;
margin-bottom: 8px;
text-align: center;
}
&-button {
display: block;
margin: 16px auto 0 auto;
}
}

View File

@@ -1,59 +0,0 @@
.desktop-picker-pane {
height: 320px;
overflow-x: hidden;
overflow-y: auto;
width: 100%;
&.source-type-screen {
.desktop-picker-source {
margin-left: auto;
margin-right: auto;
width: 50%;
}
.desktop-source-preview-thumbnail {
width: 100%;
}
.desktop-source-preview-label {
display: none;
}
}
&.source-type-window {
.desktop-picker-source {
display: inline-block;
width: 30%;
}
}
}
.desktop-picker-source {
color: $defaultDarkFontColor;
margin-top: 10px;
text-align: center;
&.is-selected {
.desktop-source-preview-image-container {
background: rgba(0, 0, 0, 0.1);
border-radius: $borderRadius;
}
}
}
.desktop-source-preview-label {
margin-top: 3px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.desktop-source-preview-thumbnail {
box-shadow: 5px 5px 5px grey;
height: auto;
max-width: 100%;
}
.desktop-source-preview-image-container {
padding: 10px;
}

View File

@@ -1,132 +0,0 @@
.device-selection {
color: $feedbackInputTextColor;
.device-selectors {
font-size: 14px;
> div {
display: block;
margin-bottom: 10px;
}
> div:last-child {
margin-bottom: 5px;
}
.device-selector-icon {
align-self: center;
color: inherit;
font-size: 20px;
margin-left: 3px;
}
/* device-selector-trigger stylings attempt to mimic AtlasKit button */
.device-selector-trigger {
background-color: rgba(9, 30, 66, 0.04);
border-radius: 3px;
color: #505f79;
display: flex;
height: 2.3em;
justify-content: space-between;
line-height: 2.3em;
overflow: hidden;
padding: 0 8px;
&:hover {
background-color: rgba(9,30,66,.08);
}
}
.device-selector-trigger-disabled {
.device-selector-trigger {
color: #a5adba;
cursor: default;
}
}
.device-selector-trigger-text {
overflow: hidden;
margin-left: 8px;
text-overflow: ellipsis;
white-space: nowrap;
width: 100%;
}
}
.device-selection-column {
box-sizing: border-box;
display: inline-block;
vertical-align: top;
&.column-selectors {
margin-left: 15px;
width: 45%;
}
&.column-video {
width: 50%;
}
}
.device-selection-video-container {
border-radius: 3px;
margin-bottom: 5px;
.video-input-preview {
margin-top: 2px;
position: relative;
> video {
border-radius: 3px;
}
.video-input-preview-error {
color: $participantNameColor;
display: none;
left: 0;
position: absolute;
right: 0;
text-align: center;
top: 50%;
}
&.video-preview-has-error {
background: black;
.video-input-preview-error {
display: block;
}
}
.video-input-preview-display {
height: auto;
overflow: hidden;
width: 100%;
}
}
}
.audio-output-preview {
font-size: 14px;
margin-top: 10px;
a {
cursor: pointer;
text-decoration: none;
}
}
.audio-input-preview {
background: #f4f5f7;
border-radius: 5px;
height: 6px;
.audio-input-preview-level {
background: #0052cc;
border-radius: 5px;
height: 100%;
-webkit-transition: width .1s ease-in-out;
-moz-transition: width .1s ease-in-out;
-o-transition: width .1s ease-in-out;
transition: width .1s ease-in-out;
}
}
}

View File

@@ -1,32 +0,0 @@
/**
* Styles errors and links in the AddPeopleDialog.
*/
.modal-dialog-form {
.add-people-form-wrap {
.error {
padding-left: 5px;
a {
padding-left: 5px;
}
}
}
}
/**
* Styles the loading element in the MultiSelectAutocomplete.
*/
.autocomplete-loading {
justify-content: center;
display: flex;
min-width: 260px;
padding: 20px;
}
/**
* Styles errors in the MultiSelectAutocomplete.
*/
.autocomplete-error {
min-width: 260px;
}

View File

@@ -4,84 +4,4 @@
*/
#inviteDialogRemovePassword {
cursor: hand;
}
.invite-dialog {
.dial-in-numbers {
.dial-in-numbers-conference-id {
color: orange;
margin-left: 3px;
}
/*
* dial-in-numbers-copy styling is needed for the feature of copying
* text to the clipboard. The styling keeps the element invisible
* to the user but still programmatically selectable for copying.
*/
.dial-in-numbers-copy {
opacity: 0;
pointer-events: none;
position: fixed;
-webkit-user-select: text;
user-select: text;
}
.dial-in-numbers-trigger {
position: relative;
width: 100%;
.dial-in-numbers-trigger-icon {
position: absolute;
right: 0;
top: 4px;
}
}
.is-disabled,
.is-loading {
.dial-in-numbers-trigger-icon {
display: none;
}
}
}
.form-control {
padding: 0;
}
.inviteLink {
color: $readOnlyInputColor;
}
.lock-state {
display: flex;
}
.password-overview {
margin-top: 10px;
.form-control {
margin-top: 10px;
}
.password-overview-status,
.remove-password {
display: flex;
justify-content: space-between;
}
.password-overview-toggle-edit,
.remove-password-link {
cursor: pointer;
text-decoration: none;
}
.remove-password {
margin-top: 15px;
}
}
.remove-password-current {
color: $inputControlEmColor;
}
}
}

View File

@@ -1,55 +0,0 @@
.speaker-stats {
list-style: none;
padding: 0;
width: 100%;
font-weight: 500;
.speaker-stats-item__status-dot {
position: relative;
display: block;
width: 9px;
height: 9px;
border-radius: 50%;
margin: 0 auto;
&.status-active {
background: green;
}
&.status-inactive {
background: gray;
}
}
.status-user-left {
color: $placeHolderColor;
}
.speaker-stats-item__status,
.speaker-stats-item__name,
.speaker-stats-item__time {
display: inline-block;
margin: 5px 0;
vertical-align: middle;
}
.speaker-stats-item__status {
width: 5%;
}
.speaker-stats-item__name {
width: 40%;
}
.speaker-stats-item__time {
width: 55%;
}
.speaker-stats-item:nth-child(even) {
background: whitesmoke;
}
.speaker-stats-item__name,
.speaker-stats-item__time {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}

View File

@@ -1,6 +1,5 @@
.overlay {
&__container,
&__container-light {
&__container {
top: 0;
left: 0;
width: 100%;
@@ -8,16 +7,6 @@
position: fixed;
z-index: $overlayZ;
background: $defaultBackground;
&.filmstrip-only {
@include transparentBg($filmstripOnlyOverlayBg, 0.8);
}
}
&__container-light {
@include transparentBg($defaultBackground, 0.7);
&.filmstrip-only {
@include transparentBg($filmstripOnlyOverlayBg, 0.2);
}
}
&__content {
@@ -27,11 +16,6 @@
width: 56%;
left: 50%;
@include transform(translateX(-50%));
&.filmstrip-only {
left: 0px;
width: 100%;
@include transform(none);
}
&_bottom {
position: absolute;
@@ -44,4 +28,4 @@
bottom: 24px;
width: 100%;
}
}
}

View File

@@ -4,7 +4,7 @@
line-height: 20px;
}
.reload_overlay_text {
.reload_overlay_msg {
display: block;
font-size: 12px;
line-height: 30px;
@@ -13,7 +13,4 @@
#reloadProgressBar {
width: 180px;
margin: 5px auto;
> .aui-progress-indicator-value {
background: $reloadProgressBarBg;
}
}
}

View File

@@ -8,8 +8,6 @@ $baseLight: #FFFFFF;
*/
$controlBackground: $baseLight;
$controlColor: #333333;
$sliderTrackBackground: #474747;
$sliderThumbBackground: #3572b0;
/**
* Buttons
@@ -35,14 +33,10 @@ $primaryButtonFontWeight: 400;
$buttonShadowColor: #192d4f;
$overlayButtonBg: #0074E0;
/**
* Color variables
**/
$defaultBackground: #474747;
$filmstripOnlyOverlayBg: #000;
$reloadProgressBarBg: #0074E0;
/**
* Connection indicator
@@ -58,19 +52,17 @@ $auiDialogBg: #f5f5f5;
$auiDialogContentBg: $baseLight;
$auiBorderColor: #ccc;
$dialogTitleFontWeight: 400;
$dialogErrorText: #344563;
/**
* Inlay colors
**/
$inlayColorBg: lighten($defaultBackground, 20%);
$inlayBorderColor: lighten($auiDialogContentBg, 10%);
$inlayIconBg: #000;
$inlayIconColor: #fff;
$inlayFilmstripOnlyColor: #474747;
$inlayFilmstripOnlyBg: #fff;
// Main controls
$inputBackground: $controlBackground;
$inputBorderColor: #ccc;
$inputColor: $controlColor;
$placeHolderColor: #a7a7a7;
$readOnlyInputColor: #a7a7a7;
$defaultDarkSelectionColor: #ccc;
@@ -91,17 +83,7 @@ $popoverFontColor: #ffffff;
$popupMenuSelectedItemBackground: rgba(256, 256, 256, .2);
// Toolbar
$secondaryToolbarBg: rgba(0, 0, 0, 0.5);
// TOFIX: Once moved to react rename to match the side panel class name.
$sideToolbarContainerBg: rgba(0, 0, 0, 0.75);
$toolbarBackground: rgba(0, 0, 0, 0.5);
$toolbarBadgeBackground: #165ECC;
$toolbarBadgeColor: #FFFFFF;
$toolbarButtonColor: #FFFFFF;
$toolbarSelectBackground: rgba(0, 0, 0, .6);
$toolbarTitleColor: #FFFFFF;
$toolbarToggleBackground: #12499C;
$splitterColor: #ccc;
/**
* Forms

View File

@@ -1,3 +0,0 @@
@import 'no-mobile-app';
@import 'unsupported-desktop-browser';
@import 'unsupported-mobile-browser';

View File

@@ -1,21 +0,0 @@
.no-mobile-app {
margin: 30% auto 0;
max-width: 25em;
text-align: center;
width: auto;
&__title {
border-bottom: 1px solid $auiBorderColor;
color: $unsupportedBrowserTitleColor;
font-weight: 400;
letter-spacing: 0.5px;
padding-bottom: em(17, 24);
}
&__description {
font-size: $unsupportedBrowserTextSmallFontSize;
font-weight: 300;
letter-spacing: 1px;
margin-top: 1em;
}
}

View File

@@ -1,39 +0,0 @@
.unsupported-desktop-browser {
@include absoluteAligning();
display: block;
text-align: center;
&__title {
color: $unsupportedBrowserTitleColor;
font-weight: 300;
font-size: $unsupportedBrowserTitleFontSize;
letter-spacing: 1px;
}
&__description {
color: $unsupportedDesktopBrowserTextColor;
font-size: $unsupportedDesktopBrowserTextFontSize;
font-weight: 300;
letter-spacing: 1px;
margin-top: 16px;
&_small {
@extend .unsupported-desktop-browser__description;
font-size: $unsupportedBrowserTextSmallFontSize;
}
}
&__link {
color: $linkFontColor;
@include transition(color .1s ease-out);
&:hover {
color: $linkHoverFontColor;
cursor: pointer;
text-decoration: none;
@include transition(color .1s ease-in);
}
}
}

View File

@@ -1,69 +0,0 @@
.unsupported-mobile-browser {
background-color: #fff;
height: 100vh;
padding: 35px 0;
width: 100vw;
&__body {
color: $unsupportedBrowserTextColor;
margin: auto;
max-width: 40em;
text-align: center;
width: 75%;
a:active {
text-decoration: none;
}
}
&__text {
font-size: 1.8em;
line-height: em(29px, 21px);
margin-bottom: 0.65em;
&_small {
font-size: 1.5em;
margin-bottom: 1em;
margin-top: em(21, 18);
strong {
font-size: em(21, 18);
}
}
}
&__logo {
height: 108px;
width: 77px;
}
&__button {
border: 0;
height: 42px;
margin: 0 auto;
max-width: 300px;
width: 98%;
@include border-radius(8px);
background-color: $unsupportedBrowserButtonBgColor;
font-size: 1.5em;
font-weight: 300;
letter-spacing: 0.5px;
text-shadow: 0px 1px 2px $unsupportedBrowserTextColor;
// Disable standard button effects.
box-shadow: none;
outline: none;
&:active {
background-color: $unsupportedBrowserButtonBgColor;
}
&_primary {
background-color: $primaryUnsupportedBrowserButtonBgColor;
&:active {
background-color: $primaryUnsupportedBrowserButtonBgColor;
}
}
}
}

View File

@@ -0,0 +1,138 @@
@import 'variables';
body {
width:100%;
height:100%;
background-color: white;
color: #424242;
font-family: $baseFontFamily;
font-size: 28px;
margin:0;
padding:0;
}
#wrap{
display: block;
position: absolute;
width:500px;
height: 565px;
overflow:hidden;
text-align: center;
margin: auto;
top: 0; left: 0; bottom: 0; right: 0;
}
.firefox{
font-size: 11pt;
color: #c8c8c8;
width: 468px;
text-align: center;
margin: 30px auto 0px auto;
padding-left: 15px;
}
#text{
display:inline-block;
font-size: 28px;
/* width: 568px; */
vertical-align:middle;
padding-top: 25px;
}
a {
color: #087dba;
text-decoration:none;
}
.browser {
width: 138px;
height: 163px;
margin-top: 5px;
background-color: #e8e8e8;
border: 1px solid #cfcfcf;
border-radius: 10px;
}
.browser_wrapper
{
width: 138px;
/* height: 188px; */
vertical-align: middle;
color: #929391;
font-size: 20px;
float: left;
margin-left: 15px;
margin-top: 5px;
}
.browser_text
{
height: 2em;
}
.supported_browsers
{
margin: 0px auto 0px auto;
/* width: 660px; */
}
.clear
{
clear: both;
}
.button
{
background-color: #62c82a;
border: 1px solid #3c8117;
border-radius: 10px;
color: #FFFFFF;
font-size: 12px;
text-align: center;
width: 115px;
height: 26px;
padding-top: 13px;
margin: 15px auto 0px auto;
}
.logo
{
margin: 20px auto 0px auto;
}
#chrome_logo
{
width: 78px;
height: 78px;
background-image: url('../images/chrome.png');
}
#chromium_logo
{
width: 77px;
height: 78px;
background-image: url('../images/chromium.png');
}
#firefox_logo
{
width: 86px;
height: 80px;
background-image: url('../images/firefox.png');
}
#opera_logo
{
width: 73px;
height: 78px;
background-image: url('../images/opera.png');
}
#safari_logo
{
width: 78px;
height: 79px;
background-image: url('../images/safari.png');
}
#ie_logo
{
width: 80px;
height: 78px;
background-image: url('../images/ie.png');
}

5
debian/control vendored
View File

@@ -21,7 +21,8 @@ Description: WebRTC JavaScript video conferences
Package: jitsi-meet-web-config
Architecture: all
Depends: openssl, openjdk-8-jre-headless | nginx | apache2
Depends: openssl, openjdk-8-jre-headless | nginx | apache2,
jitsi-meet-web
Description: Configuration for web serving of Jitsi Meet
Jitsi Meet is a WebRTC JavaScript application that uses Jitsi
Videobridge to provide high quality, scalable video conferences.
@@ -36,7 +37,7 @@ Description: Configuration for web serving of Jitsi Meet
Package: jitsi-meet-prosody
Architecture: all
Depends: openssl, prosody | prosody-trunk
Depends: openssl, prosody | prosody-trunk, jitsi-meet-web
Description: Prosody configuration for Jitsi Meet
Jitsi Meet is a WebRTC JavaScript application that uses Jitsi
Videobridge to provide high quality, scalable video conferences.

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