Compare commits
317 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fa1b210f5 | ||
|
|
15e1633d86 | ||
|
|
de0a7bfcd3 | ||
|
|
5858859838 | ||
|
|
8428dd95c2 | ||
|
|
a26ccf195e | ||
|
|
0a5f60c637 | ||
|
|
f8163de765 | ||
|
|
181580871f | ||
|
|
ea431ca90c | ||
|
|
a902540167 | ||
|
|
823481dc1d | ||
|
|
b5b99301ca | ||
|
|
ef52f09910 | ||
|
|
6a066c3079 | ||
|
|
71e368f70e | ||
|
|
134ff71c78 | ||
|
|
fef1d8b520 | ||
|
|
309fcf9672 | ||
|
|
2eafbacdd4 | ||
|
|
26ea667170 | ||
|
|
5f43e8f8c7 | ||
|
|
9ef83702cf | ||
|
|
fda2548a38 | ||
|
|
eb53944a4d | ||
|
|
2334eb9967 | ||
|
|
04bd4a9038 | ||
|
|
eb8f34cee8 | ||
|
|
b9379f5996 | ||
|
|
40d7d0c9cb | ||
|
|
357f173e85 | ||
|
|
7da26042b3 | ||
|
|
c86c7beb24 | ||
|
|
1020a54a33 | ||
|
|
c84abd543e | ||
|
|
4b17c6f015 | ||
|
|
cb973b61aa | ||
|
|
b096622995 | ||
|
|
ae0bf876a8 | ||
|
|
bba480f329 | ||
|
|
4dbcaf851f | ||
|
|
04dff9059b | ||
|
|
26cd2f17f6 | ||
|
|
60e03e3dec | ||
|
|
bfb45ed0e8 | ||
|
|
e325199075 | ||
|
|
4e4713c3e2 | ||
|
|
ff8386e931 | ||
|
|
8f520086e5 | ||
|
|
5cde674eff | ||
|
|
c018252eee | ||
|
|
c8cab1560c | ||
|
|
d218abfd97 | ||
|
|
9e0fee6c7d | ||
|
|
5dca9e08f4 | ||
|
|
d3a1f7d4f7 | ||
|
|
80bdf908ca | ||
|
|
0d3b4eedf8 | ||
|
|
824a8a8864 | ||
|
|
45c1438fe6 | ||
|
|
8caeabf6b4 | ||
|
|
466561f99f | ||
|
|
8dc866fab3 | ||
|
|
1c8b8e031b | ||
|
|
796489dc77 | ||
|
|
a30412ba65 | ||
|
|
8b35ea8ad5 | ||
|
|
e05f2a9027 | ||
|
|
0d5cc8898d | ||
|
|
7672a88990 | ||
|
|
5a45b52881 | ||
|
|
ce6e8472f0 | ||
|
|
b00aaf1de7 | ||
|
|
e622829c1c | ||
|
|
037e7f59b0 | ||
|
|
df754f4f41 | ||
|
|
fd0749000e | ||
|
|
d727ee80b2 | ||
|
|
e4da0e988e | ||
|
|
1474304cc5 | ||
|
|
d02ab2c641 | ||
|
|
0e07020d09 | ||
|
|
e0deb6d64b | ||
|
|
88325aeef2 | ||
|
|
9f69c4d730 | ||
|
|
e23d4317eb | ||
|
|
547ddee3a5 | ||
|
|
3cf9fd439b | ||
|
|
7cd40353e7 | ||
|
|
04690dfc8f | ||
|
|
9a9890f86c | ||
|
|
9b04a7852a | ||
|
|
df9d17ba18 | ||
|
|
5d0ac7653d | ||
|
|
1ef2e2ee7e | ||
|
|
b3431ab3e7 | ||
|
|
6fbe78eb34 | ||
|
|
b8de5bbfc3 | ||
|
|
b3683068d4 | ||
|
|
94473e5660 | ||
|
|
7f78050513 | ||
|
|
2d9b906a3b | ||
|
|
1f82ce3d19 | ||
|
|
68b710a222 | ||
|
|
9fea5e89b3 | ||
|
|
e1d849e3a0 | ||
|
|
74a92f83c7 | ||
|
|
e47802538e | ||
|
|
e2cf7a788d | ||
|
|
4757c1ebca | ||
|
|
59d046dca9 | ||
|
|
0bbcd3181c | ||
|
|
7a9ff9975a | ||
|
|
10f72f8e40 | ||
|
|
417e1e83e7 | ||
|
|
cacc4bd769 | ||
|
|
1419247801 | ||
|
|
4fb37c38eb | ||
|
|
f3b5ed2ef4 | ||
|
|
7341c7bf84 | ||
|
|
5d31532cbb | ||
|
|
423c8d3f53 | ||
|
|
a1ba7beff9 | ||
|
|
03fc711e81 | ||
|
|
a370a88d19 | ||
|
|
7153d94dad | ||
|
|
240fff74c7 | ||
|
|
7bd8b7948f | ||
|
|
a505c01e9e | ||
|
|
990b1eddf2 | ||
|
|
abbfd3de9a | ||
|
|
bd301403c4 | ||
|
|
d481c6f736 | ||
|
|
ba94ba30c5 | ||
|
|
5305557ce5 | ||
|
|
c9d8b5c827 | ||
|
|
0ad1c88cd2 | ||
|
|
78fbfba573 | ||
|
|
9e53d40b9c | ||
|
|
aa314c10ac | ||
|
|
62c9762793 | ||
|
|
d7dddb2509 | ||
|
|
83243d5980 | ||
|
|
6e05cab46e | ||
|
|
7954d5fd39 | ||
|
|
158cadf4f9 | ||
|
|
f35578c803 | ||
|
|
c087e90099 | ||
|
|
da0ae73d10 | ||
|
|
b4d44f367d | ||
|
|
083f6b400b | ||
|
|
dd5ae49217 | ||
|
|
6a9e6db3be | ||
|
|
c4468cb7b8 | ||
|
|
80c4205fb8 | ||
|
|
aa9efd6f69 | ||
|
|
6f8f64ba48 | ||
|
|
1c3cef1eed | ||
|
|
2720c76e4d | ||
|
|
4ab34589c8 | ||
|
|
ed36132e94 | ||
|
|
f43687944c | ||
|
|
dda0ea0ba9 | ||
|
|
e1f967869a | ||
|
|
8673083829 | ||
|
|
b52e584327 | ||
|
|
4c65262a87 | ||
|
|
7ce670df0c | ||
|
|
f5f341ca9e | ||
|
|
f29fbb6757 | ||
|
|
e5e3c6c6c4 | ||
|
|
dc92fb5073 | ||
|
|
2478176f23 | ||
|
|
12ec982067 | ||
|
|
c9e3e5052d | ||
|
|
22401614a7 | ||
|
|
762f529f1d | ||
|
|
1f6b743bec | ||
|
|
48f4317adb | ||
|
|
75f6786588 | ||
|
|
3ec4d67a99 | ||
|
|
a23eec55e8 | ||
|
|
bdf2ecfe4b | ||
|
|
fc36759114 | ||
|
|
9c2849a663 | ||
|
|
98ff20a026 | ||
|
|
b04661b40b | ||
|
|
112c856850 | ||
|
|
410dc132e1 | ||
|
|
b7f950f5f7 | ||
|
|
7ad875e735 | ||
|
|
41aa704e1f | ||
|
|
e00ea353e8 | ||
|
|
6f93424d7c | ||
|
|
292f3ab1bd | ||
|
|
a3cb081609 | ||
|
|
64c5ae1c48 | ||
|
|
259004b8bf | ||
|
|
4fea22676b | ||
|
|
05a492241f | ||
|
|
8ec4697a27 | ||
|
|
a357b0cf14 | ||
|
|
9eff669b0b | ||
|
|
c7714959e6 | ||
|
|
e898527294 | ||
|
|
bfcd34358b | ||
|
|
871ef9ff0e | ||
|
|
178c8e02ff | ||
|
|
43ac039fd6 | ||
|
|
090f2f9ccb | ||
|
|
d08bbae770 | ||
|
|
30b51ff384 | ||
|
|
c109199e06 | ||
|
|
0ed31f0ae8 | ||
|
|
006e6cc851 | ||
|
|
0680c086df | ||
|
|
698ec1e2d7 | ||
|
|
e217c172f8 | ||
|
|
6146c12533 | ||
|
|
eb64b74493 | ||
|
|
1255b3349b | ||
|
|
2ea5ad68a5 | ||
|
|
fb6f1bdba0 | ||
|
|
25b130f8e8 | ||
|
|
9591cb54a2 | ||
|
|
ca78309427 | ||
|
|
65abd5efd4 | ||
|
|
05de599739 | ||
|
|
1e0550c746 | ||
|
|
45c405de0e | ||
|
|
3aedce11f2 | ||
|
|
f0a180cf0c | ||
|
|
28013f6ffa | ||
|
|
5640524647 | ||
|
|
ac09233558 | ||
|
|
9a3f98a4a0 | ||
|
|
2f3ea1b458 | ||
|
|
ceeefb33c1 | ||
|
|
d6c3ab64fa | ||
|
|
eee87bc546 | ||
|
|
9a42b866ba | ||
|
|
b920140488 | ||
|
|
49acd6bf6a | ||
|
|
7001208d87 | ||
|
|
4a0e55b1f4 | ||
|
|
73cc9a68c7 | ||
|
|
e9c91d194c | ||
|
|
3460fe03e5 | ||
|
|
e65566ad03 | ||
|
|
57206cc36a | ||
|
|
c05c8e0f1e | ||
|
|
87a87eebb9 | ||
|
|
ad497fed7c | ||
|
|
0f6243ee88 | ||
|
|
b39b6640b4 | ||
|
|
870e6bbddc | ||
|
|
b93bac5aa9 | ||
|
|
c86895ae13 | ||
|
|
e28b847fb0 | ||
|
|
f6ace61674 | ||
|
|
63d661ad5e | ||
|
|
e0e2104723 | ||
|
|
6f0b828512 | ||
|
|
1984f8d0c0 | ||
|
|
9b67e796bd | ||
|
|
ee1ec42463 | ||
|
|
76fb3b3c63 | ||
|
|
b49e600267 | ||
|
|
5a3f952a2f | ||
|
|
3ac41bb0c3 | ||
|
|
94813bc0fd | ||
|
|
457b4255b9 | ||
|
|
bed9bd1d5a | ||
|
|
0d4dcffbac | ||
|
|
a5538adf8a | ||
|
|
38b645bc27 | ||
|
|
15bf6b9e30 | ||
|
|
67ac0e8b8a | ||
|
|
b74b29e8a0 | ||
|
|
b258a9fc5e | ||
|
|
a653816f90 | ||
|
|
9ddc5a0e42 | ||
|
|
d79995e14c | ||
|
|
5ffcaca649 | ||
|
|
40df5f97d4 | ||
|
|
aa93a78372 | ||
|
|
6b8b929d92 | ||
|
|
c9b54845d9 | ||
|
|
0eafee2a95 | ||
|
|
de0d69a20e | ||
|
|
eae9ddabad | ||
|
|
569b3547c8 | ||
|
|
d8bc26a8ea | ||
|
|
61e653a510 | ||
|
|
ac3a74c47e | ||
|
|
bf7b723891 | ||
|
|
4829b86352 | ||
|
|
dda4d7a99e | ||
|
|
19702671f6 | ||
|
|
d88b57d35c | ||
|
|
a9b8f49995 | ||
|
|
2306e26287 | ||
|
|
3633f2aac5 | ||
|
|
c320540fa3 | ||
|
|
75bf7638b3 | ||
|
|
379bad0ce6 | ||
|
|
2becfd026b | ||
|
|
cd48ee3dbf | ||
|
|
e4ed02815f | ||
|
|
d1e5e6b93b | ||
|
|
38629b437d | ||
|
|
d0859b3ce1 | ||
|
|
345fcefa7d | ||
|
|
8e8edb0793 | ||
|
|
4ead402388 | ||
|
|
c51d351694 | ||
|
|
f0d3abffc5 |
22
.flowconfig
@@ -12,21 +12,21 @@
|
||||
; 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 polyfills
|
||||
.*/Libraries/polyfills/.*
|
||||
|
||||
; 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/@atlaskit/.*/*.js.flow
|
||||
.*/node_modules/@atlassian
|
||||
.*/node_modules/bower/lib/node_modules/bower-json/test/.*
|
||||
.*/node_modules/immutable/dist/immutable.js.flow
|
||||
.*/node_modules/jsonlint/test/.*
|
||||
|
||||
; FIXME Remove once we update past this commit:
|
||||
; FIXME Remove once we update past commit
|
||||
; https://github.com/facebook/react-native/commit/df8d0d1db9203cc87ad3682e6138b2a9ed714365
|
||||
.*/node_modules/react-native/local-cli/link/link.js
|
||||
|
||||
.*/node_modules/react-native-keep-awake/.*
|
||||
.*/node_modules/styled-components/.*
|
||||
|
||||
@@ -36,21 +36,16 @@
|
||||
|
||||
[libs]
|
||||
node_modules/react-native/Libraries/react-native/react-native-interface.js
|
||||
node_modules/react-native/flow
|
||||
node_modules/react-native/flow/
|
||||
|
||||
[options]
|
||||
emoji=true
|
||||
|
||||
module.system=haste
|
||||
|
||||
; 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
|
||||
|
||||
; FIXME Remove once we update past this commit:
|
||||
; FIXME Remove once we update past commit
|
||||
; https://github.com/facebook/react-native/commit/df8d0d1db9203cc87ad3682e6138b2a9ed714365
|
||||
module.name_mapper='^./link/link$' -> 'emptyObject'
|
||||
|
||||
@@ -62,11 +57,10 @@ suppress_type=$FlowFixMeProps
|
||||
suppress_type=$FlowFixMeState
|
||||
suppress_type=$FixMe
|
||||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(5[0-3]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native_oss[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-3]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native_oss[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(5[0-7]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-7]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowDisableNextLine
|
||||
|
||||
unsafe.enable_getters_and_setters=true
|
||||
|
||||
@@ -83,4 +77,4 @@ module.file_ext=.jsx
|
||||
module.file_ext=.json
|
||||
|
||||
[version]
|
||||
^0.53.0
|
||||
^0.57.0
|
||||
|
||||
20
.gitignore
vendored
@@ -7,6 +7,9 @@ all.css
|
||||
.remote-sync.json
|
||||
.sync-config.cson
|
||||
|
||||
# CocoaPods
|
||||
Pods/
|
||||
|
||||
# The following are automatically generated by the react-native command line
|
||||
# utility (either with the init or upgrade option which pull in the latest
|
||||
# template files recommended by Facebook for React Native).
|
||||
@@ -57,14 +60,11 @@ buck-out/
|
||||
|
||||
# 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
|
||||
# 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://docs.fastlane.tools/best-practices/source-control/
|
||||
|
||||
# CocoaPods
|
||||
Pods/
|
||||
*/fastlane/report.xml
|
||||
*/fastlane/Preview.html
|
||||
*/fastlane/screenshots
|
||||
|
||||
@@ -21,7 +21,7 @@ license agreement as either a [corporation](https://jitsi.org/ccla) or an
|
||||
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
|
||||
- Make sure your code passes the linter rules beforehand. The linter is executed
|
||||
automatically when committing code.
|
||||
- Perform **one** logical change per pull request.
|
||||
- Maintain a clean list of commits, squash them if necessary.
|
||||
|
||||
5
Makefile
@@ -33,9 +33,11 @@ deploy-appbundle:
|
||||
$(BUILD_DIR)/external_api.min.map \
|
||||
$(BUILD_DIR)/device_selection_popup_bundle.min.js \
|
||||
$(BUILD_DIR)/device_selection_popup_bundle.min.map \
|
||||
$(BUILD_DIR)/dial_in_info_bundle.min.js \
|
||||
$(BUILD_DIR)/dial_in_info_bundle.min.map \
|
||||
$(BUILD_DIR)/alwaysontop.min.js \
|
||||
$(BUILD_DIR)/alwaysontop.min.map \
|
||||
$(OUTPUT_DIR)/analytics.js \
|
||||
$(OUTPUT_DIR)/analytics-ga.js \
|
||||
$(DEPLOY_DIR)
|
||||
|
||||
deploy-lib-jitsi-meet:
|
||||
@@ -43,6 +45,7 @@ deploy-lib-jitsi-meet:
|
||||
$(LIBJITSIMEET_DIR)/lib-jitsi-meet.min.js \
|
||||
$(LIBJITSIMEET_DIR)/lib-jitsi-meet.min.map \
|
||||
$(LIBJITSIMEET_DIR)/connection_optimization/external_connect.js \
|
||||
$(LIBJITSIMEET_DIR)/modules/browser/capabilities.json \
|
||||
$(DEPLOY_DIR)
|
||||
|
||||
deploy-css:
|
||||
|
||||
34
README.md
@@ -1,13 +1,15 @@
|
||||
# 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.
|
||||
Jitsi Meet is an open-source (Apache) WebRTC JavaScript application that uses [Jitsi Videobridge](https://jitsi.org/videobridge) to provide high quality, [secure](#security) and scalable video conferences. You can see Jitsi Meet in action [here at the session #482 of the VoIP Users Conference](http://youtu.be/7vFUVClsNh0).
|
||||
|
||||
You can also try it out yourself at https://meet.jit.si .
|
||||
The Jitsi Meet client runs in your browser, without the need for installing anything on your computer. You can also try it out yourself at https://meet.jit.si .
|
||||
|
||||
Jitsi Meet allows for very efficient collaboration. It allows users to stream their desktop or only some windows. It also supports shared document editing with Etherpad.
|
||||
|
||||
## Installation
|
||||
|
||||
On the client side, no installation is necessary. You just point your browser to the URL of your deployment. This section is about installing the Jitsi Meet suite on your server and hosting your own conferencing service.
|
||||
|
||||
Installing Jitsi Meet is quite a simple experience. For Debian-based systems, we recommend following the [quick-install](https://github.com/jitsi/jitsi-meet/blob/master/doc/quick-install.md) document, which uses the package system.
|
||||
|
||||
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).
|
||||
@@ -88,6 +90,19 @@ cd jitsi-meet
|
||||
npm unlink lib-jitsi-meet
|
||||
npm install
|
||||
```
|
||||
## Running with webpack-dev-server for development
|
||||
|
||||
Use it at the CLI, type
|
||||
```
|
||||
node_modules/.bin/webpack-dev-server
|
||||
```
|
||||
|
||||
By default the backend deployment used is `beta.meet.jit.si`, you can point the Jitsi-Meet app at a different backend by using a proxy server. To do this set the WEBPACK_DEV_SERVER_PROXY_TARGET variable, type
|
||||
```
|
||||
WEBPACK_DEV_SERVER_PROXY_TARGET=https://your-example-server.com node_modules/.bin/webpack-dev-server
|
||||
```
|
||||
|
||||
The app should be running at https://localhost:8080/
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -98,6 +113,21 @@ see our [guidelines for contributing](CONTRIBUTING.md).
|
||||
|
||||
Jitsi Meet provides a very flexible way of embedding it in external applications by using the [Jitsi Meet API](doc/api.md).
|
||||
|
||||
## Security
|
||||
WebRTC today does not provide a way of conducting multiparty conversations with
|
||||
end-to-end encryption. As a matter of fact, unless you consistently vocally
|
||||
compare DTLS fingerprints with your peers, the same goes for one-to-one calls.
|
||||
As a result when using a Jitsi Meet instance, your stream is encrypted on the
|
||||
network but decrypted on the machine that hosts the bridge.
|
||||
|
||||
The Jitsi Meet architecture allows you to deploy your own version, including
|
||||
all server components, and in that case your security guarantees will be roughly
|
||||
equivalent to these of a direct one-to-one WebRTC call. This is what's unique to
|
||||
Jitsi Meet in terms of security.
|
||||
|
||||
The [meet.jit.si](https://meet.jit.si) service is maintained by the Jitsi team
|
||||
at [Atlassian](https://atlassian.com).
|
||||
|
||||
## Mobile app
|
||||
Jitsi Meet is also available as a React Native app for Android and iOS.
|
||||
Instructions on how to build it can be found [here](doc/mobile.md).
|
||||
|
||||
154
analytics-ga.js
Normal file
@@ -0,0 +1,154 @@
|
||||
/* global ga */
|
||||
|
||||
(function(ctx) {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function Analytics(options) {
|
||||
/* eslint-disable */
|
||||
|
||||
if (!options.googleAnalyticsTrackingId) {
|
||||
console.log(
|
||||
'Failed to initialize Google Analytics handler, no tracking ID');
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Google Analytics
|
||||
* TODO: Keep this local, there's no need to add it to window.
|
||||
*/
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', options.googleAnalyticsTrackingId, 'jit.si');
|
||||
ga('send', 'pageview');
|
||||
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the integer to use for a Google Analytics event's value field
|
||||
* from a lib-jitsi-meet analytics event.
|
||||
* @param {Object} event - The lib-jitsi-meet analytics event.
|
||||
* @returns {Object} - The integer to use for the 'value' of a Google
|
||||
* Analytics event.
|
||||
* @private
|
||||
*/
|
||||
Analytics.prototype._extractAction = function(event) {
|
||||
// Page events have a single 'name' field.
|
||||
if (event.type === 'page') {
|
||||
return event.name;
|
||||
}
|
||||
|
||||
// All other events have action, actionSubject, and source fields. All
|
||||
// three fields are required, and the often jitsi-meet and
|
||||
// lib-jitsi-meet use the same value when separate values are not
|
||||
// necessary (i.e. event.action == event.actionSubject).
|
||||
// Here we concatenate these three fields, but avoid adding the same
|
||||
// value twice, because it would only make the GA event's action harder
|
||||
// to read.
|
||||
let action = event.action;
|
||||
|
||||
if (event.actionSubject && event.actionSubject !== event.action) {
|
||||
// Intentionally use string concatenation as analytics needs to
|
||||
// work on IE but this file does not go through babel. For some
|
||||
// reason disabling this globally for the file does not have an
|
||||
// effect.
|
||||
// eslint-disable-next-line prefer-template
|
||||
action = event.actionSubject + '.' + action;
|
||||
}
|
||||
if (event.source && event.source !== event.action
|
||||
&& event.source !== event.action) {
|
||||
// eslint-disable-next-line prefer-template
|
||||
action = event.source + '.' + action;
|
||||
}
|
||||
|
||||
return action;
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts the integer to use for a Google Analytics event's value field
|
||||
* from a lib-jitsi-meet analytics event.
|
||||
* @param {Object} event - The lib-jitsi-meet analytics event.
|
||||
* @returns {Object} - The integer to use for the 'value' of a Google
|
||||
* Analytics event, or NaN if the lib-jitsi-meet event doesn't contain a
|
||||
* suitable value.
|
||||
* @private
|
||||
*/
|
||||
Analytics.prototype._extractValue = function(event) {
|
||||
let value = event && event.attributes && event.attributes.value;
|
||||
|
||||
// Try to extract an integer from the "value" attribute.
|
||||
value = Math.round(parseFloat(value));
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts the string to use for a Google Analytics event's label field
|
||||
* from a lib-jitsi-meet analytics event.
|
||||
* @param {Object} event - The lib-jitsi-meet analytics event.
|
||||
* @returns {string} - The string to use for the 'label' of a Google
|
||||
* Analytics event.
|
||||
* @private
|
||||
*/
|
||||
Analytics.prototype._extractLabel = function(event) {
|
||||
let label = '';
|
||||
|
||||
// The label field is limited to 500B. We will concatenate all
|
||||
// attributes of the event, except the user agent because it may be
|
||||
// lengthy and is probably included from elsewhere.
|
||||
for (const property in event.attributes) {
|
||||
if (property !== 'permanent_user_agent'
|
||||
&& property !== 'permanent_callstats_name'
|
||||
&& event.attributes.hasOwnProperty(property)) {
|
||||
// eslint-disable-next-line prefer-template
|
||||
label += property + '=' + event.attributes[property] + '&';
|
||||
}
|
||||
}
|
||||
|
||||
if (label.length > 0) {
|
||||
label = label.slice(0, -1);
|
||||
}
|
||||
|
||||
return label;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the entry point of the API. The function sends an event to
|
||||
* google analytics. The format of the event is described in
|
||||
* AnalyticsAdapter in lib-jitsi-meet.
|
||||
* @param {Object} event - the event in the format specified by
|
||||
* lib-jitsi-meet.
|
||||
*/
|
||||
Analytics.prototype.sendEvent = function(event) {
|
||||
if (!event || !ga) {
|
||||
return;
|
||||
}
|
||||
|
||||
const gaEvent = {
|
||||
'eventCategory': 'jitsi-meet',
|
||||
'eventAction': this._extractAction(event),
|
||||
'eventLabel': this._extractLabel(event)
|
||||
};
|
||||
const value = this._extractValue(event);
|
||||
|
||||
if (!isNaN(value)) {
|
||||
gaEvent.eventValue = value;
|
||||
}
|
||||
|
||||
ga('send', 'event', gaEvent);
|
||||
};
|
||||
|
||||
if (typeof ctx.JitsiMeetJS === 'undefined') {
|
||||
ctx.JitsiMeetJS = {};
|
||||
}
|
||||
if (typeof ctx.JitsiMeetJS.app === 'undefined') {
|
||||
ctx.JitsiMeetJS.app = {};
|
||||
}
|
||||
if (typeof ctx.JitsiMeetJS.app.analyticsHandlers === 'undefined') {
|
||||
ctx.JitsiMeetJS.app.analyticsHandlers = [];
|
||||
}
|
||||
ctx.JitsiMeetJS.app.analyticsHandlers.push(Analytics);
|
||||
})(window);
|
||||
/* eslint-enable prefer-template */
|
||||
47
analytics.js
@@ -1,47 +0,0 @@
|
||||
/* global ga */
|
||||
|
||||
(function(ctx) {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function Analytics() {
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* Google Analytics
|
||||
*/
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-319188-14', 'jit.si');
|
||||
ga('send', 'pageview');
|
||||
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
Analytics.prototype.sendEvent = function(action, data) {
|
||||
// empty label if missing value for it and add the value,
|
||||
// the value should be integer or null
|
||||
let value = data.value;
|
||||
|
||||
value = value ? Math.round(parseFloat(value)) : null;
|
||||
const label = data.label || '';
|
||||
|
||||
// Intentionally use string concatenation as analytics needs to work on
|
||||
// IE but this file does not go through babel.
|
||||
// eslint-disable-next-line prefer-template
|
||||
ga('send', 'event', 'jit.si', action + '.' + data.browserName,
|
||||
label, value);
|
||||
};
|
||||
|
||||
if (typeof ctx.JitsiMeetJS === 'undefined') {
|
||||
ctx.JitsiMeetJS = {};
|
||||
}
|
||||
if (typeof ctx.JitsiMeetJS.app === 'undefined') {
|
||||
ctx.JitsiMeetJS.app = {};
|
||||
}
|
||||
if (typeof ctx.JitsiMeetJS.app.analyticsHandlers === 'undefined') {
|
||||
ctx.JitsiMeetJS.app.analyticsHandlers = [];
|
||||
}
|
||||
ctx.JitsiMeetJS.app.analyticsHandlers.push(Analytics);
|
||||
})(window);
|
||||
@@ -16,7 +16,7 @@
|
||||
`"file:${rootProject.projectDir}/../../../jitsi/jitsi-maven-repository/releases"`
|
||||
in android/build.gradle for the third-party react-native modules which Jitsi
|
||||
Meet SDK for Android depends on and are not publicly available in Maven
|
||||
repositories. Generally, if you are modifying the JavaSource code of Jitsi
|
||||
repositories. Generally, if you are modifying the JavaScript code of Jitsi
|
||||
Meet SDK for Android only, you will very likely need to consider the former
|
||||
only.
|
||||
|
||||
@@ -107,19 +107,19 @@ public class MainActivity extends AppCompatActivity {
|
||||
JitsiMeetView.onNewIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
JitsiMeetView.onHostPause(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
JitsiMeetView.onHostResume(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
|
||||
JitsiMeetView.onHostPause(this);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -132,6 +132,10 @@ which displays a single `JitsiMeetView`.
|
||||
|
||||
See JitsiMeetView.getDefaultURL.
|
||||
|
||||
#### getPictureInPictureEnabled()
|
||||
|
||||
See JitsiMeetView.getPictureInPictureEnabled.
|
||||
|
||||
#### getWelcomePageEnabled()
|
||||
|
||||
See JitsiMeetView.getWelcomePageEnabled.
|
||||
@@ -144,6 +148,10 @@ See JitsiMeetView.loadURL.
|
||||
|
||||
See JitsiMeetView.setDefaultURL.
|
||||
|
||||
#### setPictureInPictureEnabled(boolean)
|
||||
|
||||
See JitsiMeetView.setPictureInPictureEnabled.
|
||||
|
||||
#### setWelcomePageEnabled(boolean)
|
||||
|
||||
See JitsiMeetView.setWelcomePageEnabled.
|
||||
@@ -169,6 +177,12 @@ if set to `null`, the default built in JavaScript is used: https://meet.jit.si.
|
||||
|
||||
Returns the `JitsiMeetViewListener` instance attached to the view.
|
||||
|
||||
#### getPictureInPictureEnabled()
|
||||
|
||||
Returns `true` if Picture-in-Picture is enabled; `false`, otherwise. If not
|
||||
explicitly set (by a preceding `setPictureInPictureEnabled` call), defaults to
|
||||
`true` if the platform supports Picture-in-Picture natively; `false`, otherwise.
|
||||
|
||||
#### getWelcomePageEnabled()
|
||||
|
||||
Returns true if the Welcome page is enabled; otherwise, false. If false, a black
|
||||
@@ -210,19 +224,30 @@ view.loadURLObject(urlObject);
|
||||
|
||||
Sets the default URL. See `getDefaultURL` for more information.
|
||||
|
||||
NOTE: Must be called before `loadURL`/`loadURLString` for it to take effect.
|
||||
NOTE: Must be called before (if at all) `loadURL`/`loadURLString` for it to take
|
||||
effect.
|
||||
|
||||
#### setListener(listener)
|
||||
|
||||
Sets the given listener (class implementing the `JitsiMeetViewListener`
|
||||
interface) on the view.
|
||||
|
||||
#### setPictureInPictureEnabled(boolean)
|
||||
|
||||
Sets whether Picture-in-Picture is enabled. If not set, Jitsi Meet SDK
|
||||
automatically enables/disables Picture-in-Picture based on native platform
|
||||
support.
|
||||
|
||||
NOTE: Must be called (if at all) before `loadURL`/`loadURLString` for it to take
|
||||
effect.
|
||||
|
||||
#### 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.
|
||||
NOTE: Must be called (if at all) before `loadURL`/`loadURLString` for it to take
|
||||
effect.
|
||||
|
||||
#### onBackPressed()
|
||||
|
||||
@@ -247,7 +272,8 @@ This is a static method.
|
||||
|
||||
#### onHostResume(activity)
|
||||
|
||||
Helper method which should be called from the activity's `onResume` method.
|
||||
Helper method which should be called from the activity's `onResume` or `onStop`
|
||||
method.
|
||||
|
||||
This is a static method.
|
||||
|
||||
@@ -259,6 +285,13 @@ activity's `onNewIntent` method.
|
||||
|
||||
This is a static method.
|
||||
|
||||
#### onUserLeaveHint()
|
||||
|
||||
Helper method for integrating automatic Picture-in-Picture. It should be called
|
||||
from the activity's `onUserLeaveHint` method.
|
||||
|
||||
This is a static method.
|
||||
|
||||
#### JitsiMeetViewListener
|
||||
|
||||
`JitsiMeetViewListener` provides an interface apps can implement to listen to
|
||||
@@ -309,3 +342,79 @@ fails.
|
||||
|
||||
The `data` `Map` contains an "error" key with the error and a "url" key with the
|
||||
conference URL which necessitated the loading of the configuration file.
|
||||
|
||||
## ProGuard rules
|
||||
|
||||
When using the SDK on a project some proguard rules have to be added in order
|
||||
to avoid necessary code being stripped. Add the following to your project's
|
||||
rules file:
|
||||
|
||||
```
|
||||
# React Native
|
||||
|
||||
# Keep our interfaces so they can be used by other ProGuard rules.
|
||||
# See http://sourceforge.net/p/proguard/bugs/466/
|
||||
-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
|
||||
-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
|
||||
-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
|
||||
|
||||
# Do not strip any method/class that is annotated with @DoNotStrip
|
||||
-keep @com.facebook.proguard.annotations.DoNotStrip class *
|
||||
-keep @com.facebook.common.internal.DoNotStrip class *
|
||||
-keepclassmembers class * {
|
||||
@com.facebook.proguard.annotations.DoNotStrip *;
|
||||
@com.facebook.common.internal.DoNotStrip *;
|
||||
}
|
||||
|
||||
-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
|
||||
void set*(***);
|
||||
*** get*();
|
||||
}
|
||||
|
||||
-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
|
||||
-keep class * extends com.facebook.react.bridge.NativeModule { *; }
|
||||
-keepclassmembers,includedescriptorclasses class * { native <methods>; }
|
||||
-keepclassmembers class * { @com.facebook.react.uimanager.UIProp <fields>; }
|
||||
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp <methods>; }
|
||||
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup <methods>; }
|
||||
|
||||
-dontwarn com.facebook.react.**
|
||||
|
||||
# TextLayoutBuilder uses a non-public Android constructor within StaticLayout.
|
||||
# See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details.
|
||||
-dontwarn android.text.StaticLayout
|
||||
|
||||
# okhttp
|
||||
|
||||
-keepattributes Signature
|
||||
-keepattributes *Annotation*
|
||||
-keep class okhttp3.** { *; }
|
||||
-keep interface okhttp3.** { *; }
|
||||
-dontwarn okhttp3.**
|
||||
|
||||
# okio
|
||||
|
||||
-keep class sun.misc.Unsafe { *; }
|
||||
-dontwarn java.nio.file.*
|
||||
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
|
||||
-dontwarn okio.**
|
||||
|
||||
# WebRTC
|
||||
|
||||
-keep class org.webrtc.** { *; }
|
||||
-dontwarn org.chromium.build.BuildHooksAndroid
|
||||
|
||||
# Jisti Meet SDK
|
||||
|
||||
-keep class org.jitsi.meet.sdk.** { *; }
|
||||
```
|
||||
|
||||
## Picture-in-Picture
|
||||
|
||||
`JitsiMeetView` will automatically adjust its UI when presented in a
|
||||
Picture-in-Picture style scenario, in a rectangle too small to accommodate its
|
||||
"full" UI.
|
||||
|
||||
Jitsi Meet SDK automatically enables (unless explicitly disabled by a
|
||||
`setPictureInPictureEnabled(false)` call) Android's native Picture-in-Picture
|
||||
mode iff the platform is supported i.e. Android >= Oreo.
|
||||
|
||||
4
android/app/proguard-rules.pro
vendored
@@ -50,6 +50,10 @@
|
||||
|
||||
-dontwarn com.facebook.react.**
|
||||
|
||||
# TextLayoutBuilder uses a non-public Android constructor within StaticLayout.
|
||||
# See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details.
|
||||
-dontwarn android.text.StaticLayout
|
||||
|
||||
# okhttp
|
||||
|
||||
-keepattributes Signature
|
||||
|
||||
@@ -7,10 +7,12 @@
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTask"
|
||||
android:name=".MainActivity"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
@@ -23,6 +23,8 @@ import org.jitsi.meet.sdk.JitsiMeetActivity;
|
||||
import org.jitsi.meet.sdk.JitsiMeetView;
|
||||
import org.jitsi.meet.sdk.JitsiMeetViewListener;
|
||||
|
||||
import com.calendarevents.CalendarEventsPackage;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -95,11 +97,18 @@ public class MainActivity extends JitsiMeetActivity {
|
||||
@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.
|
||||
// want to enable some options.
|
||||
|
||||
// The welcome page 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
CalendarEventsPackage.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,5 @@
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
maven { url 'https://maven.google.com' }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.0.0'
|
||||
classpath 'com.android.tools.build:gradle:3.0.1'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files.
|
||||
@@ -16,9 +16,8 @@ buildscript {
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
google()
|
||||
jcenter()
|
||||
maven { url "https://maven.google.com" } // Required for appcompat.
|
||||
// React Native (JS, Obj-C sources, Android binaries) is installed from
|
||||
// npm.
|
||||
maven { url "$rootDir/../node_modules/react-native/android" }
|
||||
@@ -133,7 +132,7 @@ ext {
|
||||
buildToolsVersion = "26.0.2"
|
||||
compileSdkVersion = 26
|
||||
minSdkVersion = 16
|
||||
targetSdkVersion = 25
|
||||
targetSdkVersion = 26
|
||||
|
||||
// The Maven artifact groupdId of the third-party react-native modules which
|
||||
// Jitsi Meet SDK for Android depends on and which are not available in
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
keystore(
|
||||
name = 'debug',
|
||||
store = 'debug.keystore',
|
||||
properties = 'debug.keystore.properties',
|
||||
visibility = [
|
||||
'PUBLIC',
|
||||
],
|
||||
name = "debug",
|
||||
properties = "debug.keystore.properties",
|
||||
store = "debug.keystore",
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -21,15 +21,18 @@ android {
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
compile 'com.android.support:appcompat-v7:25.4.0'
|
||||
compile 'com.android.support:appcompat-v7:27.0.2'
|
||||
compile 'com.facebook.react:react-native:+'
|
||||
|
||||
compile project(':react-native-background-timer')
|
||||
compile project(':react-native-fetch-blob')
|
||||
compile project(':react-native-immersive')
|
||||
compile project(':react-native-keep-awake')
|
||||
compile project(':react-native-locale-detector')
|
||||
compile project(':react-native-sound')
|
||||
compile project(':react-native-vector-icons')
|
||||
compile project(':react-native-webrtc')
|
||||
compile project(':react-native-calendar-events')
|
||||
}
|
||||
|
||||
// Build process helpers
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<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-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
|
||||
<uses-feature
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
@@ -25,7 +27,7 @@ class AndroidSettingsModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void open() {
|
||||
public void open(Promise promise) {
|
||||
Context context = getReactApplicationContext();
|
||||
Intent intent = new Intent();
|
||||
|
||||
@@ -34,6 +36,15 @@ class AndroidSettingsModule extends ReactContextBaseJavaModule {
|
||||
intent.setData(
|
||||
Uri.fromParts("package", context.getPackageName(), null));
|
||||
|
||||
context.startActivity(intent);
|
||||
try {
|
||||
context.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
// Some devices may give an error here.
|
||||
// https://developer.android.com/reference/android/provider/Settings.html#ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
promise.reject(e);
|
||||
return;
|
||||
}
|
||||
|
||||
promise.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,31 +17,32 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
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 android.view.KeyEvent;
|
||||
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
||||
|
||||
/**
|
||||
* Base Activity for applications integrating Jitsi Meet at a higher level. It
|
||||
* contains all the required wiring between the {@code JKConferenceView} and
|
||||
* contains all the required wiring between the {@code JitsiMeetView} and
|
||||
* the Activity lifecycle methods already implemented.
|
||||
*
|
||||
* In this activity we use a single {@code JKConferenceView} instance. This
|
||||
* In this activity we use a single {@code JitsiMeetView} 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
|
||||
* {@code JKConferenceView} static methods.
|
||||
* {@code JitsiMeetView} static methods.
|
||||
*/
|
||||
public class JitsiMeetActivity
|
||||
extends AppCompatActivity {
|
||||
|
||||
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.
|
||||
@@ -67,6 +68,12 @@ public class JitsiMeetActivity
|
||||
*/
|
||||
private JitsiMeetView view;
|
||||
|
||||
/**
|
||||
* Whether Picture-in-Picture is enabled. The value is used only while
|
||||
* {@link #view} equals {@code null}.
|
||||
*/
|
||||
private Boolean pictureInPictureEnabled;
|
||||
|
||||
/**
|
||||
* Whether the Welcome page is enabled. The value is used only while
|
||||
* {@link #view} equals {@code null}.
|
||||
@@ -89,6 +96,17 @@ public class JitsiMeetActivity
|
||||
return view == null ? defaultURL : view.getDefaultURL();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see JitsiMeetView#getPictureInPictureEnabled()
|
||||
*/
|
||||
public boolean getPictureInPictureEnabled() {
|
||||
return
|
||||
view == null
|
||||
? pictureInPictureEnabled
|
||||
: view.getPictureInPictureEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see JitsiMeetView#getWelcomePageEnabled()
|
||||
@@ -121,6 +139,10 @@ public class JitsiMeetActivity
|
||||
// XXX Before calling JitsiMeetView#loadURL, make sure to call whatever
|
||||
// is documented to need such an order in order to take effect:
|
||||
view.setDefaultURL(defaultURL);
|
||||
if (pictureInPictureEnabled != null) {
|
||||
view.setPictureInPictureEnabled(
|
||||
pictureInPictureEnabled.booleanValue());
|
||||
}
|
||||
view.setWelcomePageEnabled(welcomePageEnabled);
|
||||
|
||||
view.loadURL(null);
|
||||
@@ -199,17 +221,26 @@ public class JitsiMeetActivity
|
||||
JitsiMeetView.onHostDestroy(this);
|
||||
}
|
||||
|
||||
// ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java
|
||||
@Override
|
||||
public void onNewIntent(Intent intent) {
|
||||
JitsiMeetView.onNewIntent(intent);
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
ReactInstanceManager reactInstanceManager;
|
||||
|
||||
if (!super.onKeyUp(keyCode, event)
|
||||
&& BuildConfig.DEBUG
|
||||
&& (reactInstanceManager
|
||||
= JitsiMeetView.getReactInstanceManager())
|
||||
!= null
|
||||
&& keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
reactInstanceManager.showDevOptionsDialog();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
JitsiMeetView.onHostPause(this);
|
||||
defaultBackButtonImpl = null;
|
||||
public void onNewIntent(Intent intent) {
|
||||
JitsiMeetView.onNewIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -220,6 +251,19 @@ public class JitsiMeetActivity
|
||||
JitsiMeetView.onHostResume(this, defaultBackButtonImpl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
|
||||
JitsiMeetView.onHostPause(this);
|
||||
defaultBackButtonImpl = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUserLeaveHint() {
|
||||
JitsiMeetView.onUserLeaveHint();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see JitsiMeetView#setDefaultURL(URL)
|
||||
@@ -232,6 +276,19 @@ public class JitsiMeetActivity
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see JitsiMeetView#setPictureInPictureEnabled(boolean)
|
||||
*/
|
||||
public void setPictureInPictureEnabled(boolean pictureInPictureEnabled) {
|
||||
if (view == null) {
|
||||
this.pictureInPictureEnabled
|
||||
= Boolean.valueOf(pictureInPictureEnabled);
|
||||
} else {
|
||||
view.setPictureInPictureEnabled(pictureInPictureEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see JitsiMeetView#setWelcomePageEnabled(boolean)
|
||||
|
||||
@@ -21,17 +21,23 @@ import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.ReactRootView;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.common.LifecycleState;
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
import com.rnimmersive.RNImmersiveModule;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
@@ -48,6 +54,12 @@ public class JitsiMeetView extends FrameLayout {
|
||||
*/
|
||||
private static final int BACKGROUND_COLOR = 0xFF111111;
|
||||
|
||||
/**
|
||||
* The {@link Log} tag which identifies the source of the log messages of
|
||||
* {@code JitsiMeetView}.
|
||||
*/
|
||||
private final static String TAG = JitsiMeetView.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* React Native bridge. The instance manager allows embedding applications
|
||||
* to create multiple root views off the same JavaScript bundle.
|
||||
@@ -64,7 +76,9 @@ public class JitsiMeetView extends FrameLayout {
|
||||
new AppInfoModule(reactContext),
|
||||
new AudioModeModule(reactContext),
|
||||
new ExternalAPIModule(reactContext),
|
||||
new ProximityModule(reactContext)
|
||||
new PictureInPictureModule(reactContext),
|
||||
new ProximityModule(reactContext),
|
||||
new WiFiStatsModule(reactContext)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -81,6 +95,11 @@ public class JitsiMeetView extends FrameLayout {
|
||||
return null;
|
||||
}
|
||||
|
||||
// XXX Strictly internal use only (at the time of this writing)!
|
||||
static ReactInstanceManager getReactInstanceManager() {
|
||||
return reactInstanceManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to initialize the React Native instance manager. We
|
||||
* create a single instance in order to load the JavaScript bundle a single
|
||||
@@ -95,13 +114,16 @@ public class JitsiMeetView extends FrameLayout {
|
||||
.setApplication(application)
|
||||
.setBundleAssetName("index.android.bundle")
|
||||
.setJSMainModulePath("index.android")
|
||||
.addPackage(new com.calendarevents.CalendarEventsPackage())
|
||||
.addPackage(new com.corbt.keepawake.KCKeepAwakePackage())
|
||||
.addPackage(new com.facebook.react.shell.MainReactPackage())
|
||||
.addPackage(new com.i18n.reactnativei18n.ReactNativeI18n())
|
||||
.addPackage(new com.oblador.vectoricons.VectorIconsPackage())
|
||||
.addPackage(new com.ocetnik.timer.BackgroundTimerPackage())
|
||||
.addPackage(new com.oney.WebRTCModule.WebRTCModulePackage())
|
||||
.addPackage(new com.RNFetchBlob.RNFetchBlobPackage())
|
||||
.addPackage(new com.rnimmersive.RNImmersivePackage())
|
||||
.addPackage(new com.zmxv.RNSound.RNSoundPackage())
|
||||
.addPackage(new ReactPackageAdapter() {
|
||||
@Override
|
||||
public List<NativeModule> createNativeModules(
|
||||
@@ -235,6 +257,38 @@ public class JitsiMeetView extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activity lifecycle method which should be called from
|
||||
* {@code Activity.onUserLeaveHint} so we can do the required internal
|
||||
* processing.
|
||||
*
|
||||
* This is currently not mandatory.
|
||||
*/
|
||||
public static void onUserLeaveHint() {
|
||||
sendEvent("onUserLeaveHint", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to send an event to JavaScript.
|
||||
*
|
||||
* @param eventName {@code String} containing the event name.
|
||||
* @param params {@code WritableMap} optional ancillary data for the event.
|
||||
*/
|
||||
private static void sendEvent(
|
||||
String eventName,
|
||||
@Nullable WritableMap params) {
|
||||
if (reactInstanceManager != null) {
|
||||
ReactContext reactContext
|
||||
= reactInstanceManager.getCurrentReactContext();
|
||||
if (reactContext != null) {
|
||||
reactContext
|
||||
.getJSModule(
|
||||
DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
||||
.emit(eventName, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The default base {@code URL} used to join a conference when a partial URL
|
||||
* (e.g. a room name only) is specified to {@link #loadURLString(String)} or
|
||||
@@ -256,6 +310,13 @@ public class JitsiMeetView extends FrameLayout {
|
||||
*/
|
||||
private JitsiMeetViewListener listener;
|
||||
|
||||
/**
|
||||
* Whether Picture-in-Picture is enabled. If {@code null}, defaults to
|
||||
* {@code true} iff the Android platform supports Picture-in-Picture
|
||||
* natively.
|
||||
*/
|
||||
private Boolean pictureInPictureEnabled;
|
||||
|
||||
/**
|
||||
* React Native root view.
|
||||
*/
|
||||
@@ -320,6 +381,21 @@ public class JitsiMeetView extends FrameLayout {
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether Picture-in-Picture is enabled. Picture-in-Picture is
|
||||
* natively supported on Android API >= 26 (Oreo), so it should not be
|
||||
* enabled on older platform versions.
|
||||
*
|
||||
* @return If Picture-in-Picture is enabled, {@code true}; {@code false},
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean getPictureInPictureEnabled() {
|
||||
return
|
||||
PictureInPictureModule.isPictureInPictureSupported()
|
||||
&& (pictureInPictureEnabled == null
|
||||
|| pictureInPictureEnabled.booleanValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the Welcome page is enabled. If {@code true}, the Welcome
|
||||
* page is rendered when this {@code JitsiMeetView} is not at a URL
|
||||
@@ -361,12 +437,20 @@ public class JitsiMeetView extends FrameLayout {
|
||||
if (defaultURL != null) {
|
||||
props.putString("defaultURL", defaultURL.toString());
|
||||
}
|
||||
|
||||
// externalAPIScope
|
||||
props.putString("externalAPIScope", externalAPIScope);
|
||||
|
||||
// pictureInPictureEnabled
|
||||
props.putBoolean(
|
||||
"pictureInPictureEnabled",
|
||||
getPictureInPictureEnabled());
|
||||
|
||||
// url
|
||||
if (urlObject != null) {
|
||||
props.putBundle("url", urlObject);
|
||||
}
|
||||
|
||||
// welcomePageEnabled
|
||||
props.putBoolean("welcomePageEnabled", welcomePageEnabled);
|
||||
|
||||
@@ -384,7 +468,9 @@ public class JitsiMeetView extends FrameLayout {
|
||||
if (reactRootView == null) {
|
||||
reactRootView = new ReactRootView(getContext());
|
||||
reactRootView.startReactApplication(
|
||||
reactInstanceManager, "App", props);
|
||||
reactInstanceManager,
|
||||
"App",
|
||||
props);
|
||||
reactRootView.setBackgroundColor(BACKGROUND_COLOR);
|
||||
addView(reactRootView);
|
||||
} else {
|
||||
@@ -412,6 +498,43 @@ public class JitsiMeetView extends FrameLayout {
|
||||
loadURLObject(urlObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the window containing this view gains or loses focus.
|
||||
*
|
||||
* @param hasFocus If the window of this view now has focus, {@code true};
|
||||
* otherwise, {@code false}.
|
||||
*/
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
|
||||
// https://github.com/mockingbot/react-native-immersive#restore-immersive-state
|
||||
|
||||
// FIXME The singleton pattern employed by RNImmersiveModule is not
|
||||
// advisable because a react-native mobule is consumable only after its
|
||||
// BaseJavaModule#initialize() has completed and here we have no
|
||||
// knowledge of whether the precondition is really met.
|
||||
RNImmersiveModule immersive = RNImmersiveModule.getInstance();
|
||||
|
||||
if (hasFocus && immersive != null) {
|
||||
try {
|
||||
immersive.emitImmersiveStateChangeEvent();
|
||||
} catch (RuntimeException re) {
|
||||
// FIXME I don't know how to check myself whether
|
||||
// BaseJavaModule#initialize() has been invoked and thus
|
||||
// RNImmersiveModule is consumable. A safe workaround is to
|
||||
// swallow the failure because the whole full-screen/immersive
|
||||
// functionality is brittle anyway, akin to the icing on the
|
||||
// cake, and has been working without onWindowFocusChanged for a
|
||||
// very long time.
|
||||
Log.e(
|
||||
TAG,
|
||||
"RNImmersiveModule#emitImmersiveStateChangeEvent() failed!",
|
||||
re);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default base {@code URL} used to join a conference when a
|
||||
* partial URL (e.g. a room name only) is specified to
|
||||
@@ -436,6 +559,18 @@ public class JitsiMeetView extends FrameLayout {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether Picture-in-Picture is enabled. Because Picture-in-Picture is
|
||||
* natively supported only since certain platform versions, specifying
|
||||
* {@code true} will have no effect on unsupported platform versions.
|
||||
*
|
||||
* @param pictureInPictureEnabled To enable Picture-in-Picture,
|
||||
* {@code true}; otherwise, {@code false}.
|
||||
*/
|
||||
public void setPictureInPictureEnabled(boolean pictureInPictureEnabled) {
|
||||
this.pictureInPictureEnabled = Boolean.valueOf(pictureInPictureEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the Welcome page is enabled. Must be called before
|
||||
* {@link #loadURL(URL)} for it to take effect.
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PictureInPictureParams;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.util.Rational;
|
||||
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
|
||||
public class PictureInPictureModule extends ReactContextBaseJavaModule {
|
||||
private final static String TAG = "PictureInPicture";
|
||||
|
||||
static boolean isPictureInPictureSupported() {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
|
||||
}
|
||||
|
||||
public PictureInPictureModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enters Picture-in-Picture (mode) for the current {@link Activity}.
|
||||
* Supported on Android API >= 26 (Oreo) only.
|
||||
*
|
||||
* @param promise a {@code Promise} which will resolve with a {@code null}
|
||||
* value upon success, and an {@link Exception} otherwise.
|
||||
*/
|
||||
@ReactMethod
|
||||
public void enterPictureInPicture(Promise promise) {
|
||||
if (isPictureInPictureSupported()) {
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
|
||||
if (currentActivity == null) {
|
||||
promise.reject(new Exception("No current Activity!"));
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Entering Picture-in-Picture");
|
||||
|
||||
PictureInPictureParams.Builder builder
|
||||
= new PictureInPictureParams.Builder()
|
||||
.setAspectRatio(new Rational(1, 1));
|
||||
boolean r
|
||||
= currentActivity.enterPictureInPictureMode(builder.build());
|
||||
|
||||
if (r) {
|
||||
promise.resolve(null);
|
||||
} else {
|
||||
promise.reject(
|
||||
new Exception("Failed to enter Picture-in-Picture"));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
promise.reject(new Exception("Picture-in-Picture not supported"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return TAG;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
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 org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* Module exposing WiFi statistics.
|
||||
*
|
||||
* Gathers rssi, signal in percentage, timestamp and the addresses
|
||||
* of the wifi device.
|
||||
*/
|
||||
class WiFiStatsModule extends ReactContextBaseJavaModule {
|
||||
/**
|
||||
* The name of {@code WiFiStatsModule} to be used in the React Native
|
||||
* bridge.
|
||||
*/
|
||||
private static final String MODULE_NAME = "WiFiStats";
|
||||
|
||||
/**
|
||||
* The {@code Log} tag {@code WiFiStatsModule} is to log messages with.
|
||||
*/
|
||||
static final String TAG = MODULE_NAME;
|
||||
|
||||
/**
|
||||
* The scale used for the signal value.
|
||||
* A level of the signal, given in the range
|
||||
* of 0 to SIGNAL_LEVEL_SCALE-1 (both inclusive).
|
||||
*/
|
||||
public final static int SIGNAL_LEVEL_SCALE = 101;
|
||||
|
||||
/**
|
||||
* {@link Handler} for running all operations on the main thread.
|
||||
*/
|
||||
private final Handler mainThreadHandler
|
||||
= new Handler(Looper.getMainLooper());
|
||||
|
||||
/**
|
||||
* 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 WiFiStatsModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link InetAddress} represented by this int.
|
||||
*
|
||||
* @param value the int representation of the ip address.
|
||||
* @return the {@link InetAddress}.
|
||||
* @throws UnknownHostException - if IP address is of illegal length.
|
||||
*/
|
||||
public static InetAddress toInetAddress(int value)
|
||||
throws UnknownHostException {
|
||||
return InetAddress.getByAddress(
|
||||
new byte[] {
|
||||
(byte) value,
|
||||
(byte) (value >> 8),
|
||||
(byte) (value >> 16),
|
||||
(byte) (value >> 24)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Public method to retrieve WiFi stats.
|
||||
*
|
||||
* @param promise a {@link Promise} which will be resolved if WiFi stats are
|
||||
* retrieved successfully, and it will be rejected otherwise.
|
||||
*/
|
||||
@ReactMethod
|
||||
public void getWiFiStats(final Promise promise) {
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
|
||||
Context context
|
||||
= getReactApplicationContext().getApplicationContext();
|
||||
WifiManager wifiManager
|
||||
= (WifiManager) context
|
||||
.getSystemService(Context.WIFI_SERVICE);
|
||||
|
||||
if (!wifiManager.isWifiEnabled()) {
|
||||
promise.reject(new Exception("Wifi not enabled"));
|
||||
return;
|
||||
}
|
||||
|
||||
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
|
||||
|
||||
if (wifiInfo.getNetworkId() == -1) {
|
||||
promise.reject(new Exception("Wifi not connected"));
|
||||
return;
|
||||
}
|
||||
|
||||
int rssi = wifiInfo.getRssi();
|
||||
int signalLevel
|
||||
= WifiManager.calculateSignalLevel(
|
||||
rssi, SIGNAL_LEVEL_SCALE);
|
||||
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("rssi", rssi)
|
||||
.put("signal", signalLevel)
|
||||
.put("timestamp",
|
||||
String.valueOf(System.currentTimeMillis()));
|
||||
|
||||
JSONArray addresses = new JSONArray();
|
||||
|
||||
InetAddress wifiAddress
|
||||
= toInetAddress(wifiInfo.getIpAddress());
|
||||
|
||||
try {
|
||||
Enumeration<NetworkInterface> e
|
||||
= NetworkInterface.getNetworkInterfaces();
|
||||
while (e.hasMoreElements()) {
|
||||
NetworkInterface networkInterface = e.nextElement();
|
||||
boolean found = false;
|
||||
|
||||
// first check whether this is the desired interface
|
||||
Enumeration<InetAddress> as
|
||||
= networkInterface.getInetAddresses();
|
||||
while (as.hasMoreElements()) {
|
||||
InetAddress a = as.nextElement();
|
||||
if(a.equals(wifiAddress)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
// interface found let's put addresses
|
||||
// to the result object
|
||||
as = networkInterface.getInetAddresses();
|
||||
while (as.hasMoreElements()) {
|
||||
InetAddress a = as.nextElement();
|
||||
if (a.isLinkLocalAddress())
|
||||
continue;
|
||||
|
||||
addresses.put(a.getHostAddress());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
Log.wtf(TAG,
|
||||
"Unable to NetworkInterface.getNetworkInterfaces()"
|
||||
);
|
||||
}
|
||||
|
||||
result.put("addresses", addresses);
|
||||
promise.resolve(result.toString());
|
||||
|
||||
Log.d(TAG, "WiFi stats: " + result.toString());
|
||||
} catch (Throwable e) {
|
||||
Log.e(TAG, "Failed to obtain wifi stats", e);
|
||||
promise.reject(
|
||||
new Exception("Failed to obtain wifi stats"));
|
||||
}
|
||||
}
|
||||
};
|
||||
mainThreadHandler.post(r);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,13 @@ 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 ':react-native-locale-detector'
|
||||
project(':react-native-locale-detector').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-locale-detector/android')
|
||||
include ':react-native-sound'
|
||||
project(':react-native-sound').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sound/android')
|
||||
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'
|
||||
project(':react-native-webrtc').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webrtc/android')
|
||||
include ':react-native-calendar-events'
|
||||
project(':react-native-calendar-events').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-calendar-events/android')
|
||||
|
||||
5
app.js
@@ -11,11 +11,6 @@ import 'jquery-contextmenu';
|
||||
import 'jQuery-Impromptu';
|
||||
import 'autosize';
|
||||
|
||||
import 'aui';
|
||||
import 'aui-experimental';
|
||||
import 'aui-css';
|
||||
import 'aui-experimental-css';
|
||||
|
||||
import conference from './conference';
|
||||
import API from './modules/API';
|
||||
import keyboardshortcut from './modules/keyboardshortcut/keyboardshortcut';
|
||||
|
||||
296
conference.js
@@ -7,7 +7,7 @@ import Recorder from './modules/recorder/Recorder';
|
||||
|
||||
import mediaDeviceHelper from './modules/devices/mediaDeviceHelper';
|
||||
|
||||
import { reload, reportError } from './modules/util/helpers';
|
||||
import { reportError } from './modules/util/helpers';
|
||||
|
||||
import * as RemoteControlEvents
|
||||
from './service/remotecontrol/RemoteControlEvents';
|
||||
@@ -15,7 +15,19 @@ import UIEvents from './service/UI/UIEvents';
|
||||
import UIUtil from './modules/UI/util/UIUtil';
|
||||
import * as JitsiMeetConferenceEvents from './ConferenceEvents';
|
||||
|
||||
import { initAnalytics, sendAnalyticsEvent } from './react/features/analytics';
|
||||
import {
|
||||
createDeviceChangedEvent,
|
||||
createScreenSharingEvent,
|
||||
createSelectParticipantFailedEvent,
|
||||
createStreamSwitchDelayEvent,
|
||||
createTrackMutedEvent,
|
||||
initAnalytics,
|
||||
sendAnalytics
|
||||
} from './react/features/analytics';
|
||||
import {
|
||||
redirectWithStoredParams,
|
||||
reloadWithStoredParams
|
||||
} from './react/features/app';
|
||||
|
||||
import EventEmitter from 'events';
|
||||
|
||||
@@ -29,6 +41,7 @@ import {
|
||||
dataChannelOpened,
|
||||
EMAIL_COMMAND,
|
||||
lockStateChanged,
|
||||
onStartMutedPolicyChanged,
|
||||
p2pStatusChanged,
|
||||
sendLocalParticipant
|
||||
} from './react/features/base/conference';
|
||||
@@ -53,8 +66,10 @@ import {
|
||||
setVideoAvailable,
|
||||
setVideoMuted
|
||||
} from './react/features/base/media';
|
||||
import { showNotification } from './react/features/notifications';
|
||||
import {
|
||||
dominantSpeakerChanged,
|
||||
getAvatarURLByParticipantId,
|
||||
getLocalParticipant,
|
||||
getParticipantById,
|
||||
localParticipantConnectionStatusChanged,
|
||||
@@ -74,10 +89,17 @@ import {
|
||||
trackAdded,
|
||||
trackRemoved
|
||||
} from './react/features/base/tracks';
|
||||
import { getLocationContextRoot } from './react/features/base/util';
|
||||
import {
|
||||
getLocationContextRoot,
|
||||
getJitsiMeetGlobalNS
|
||||
} from './react/features/base/util';
|
||||
import { statsEmitter } from './react/features/connection-indicator';
|
||||
import { showDesktopPicker } from './react/features/desktop-picker';
|
||||
import { maybeOpenFeedbackDialog } from './react/features/feedback';
|
||||
import { appendSuffix } from './react/features/display-name';
|
||||
import {
|
||||
maybeOpenFeedbackDialog,
|
||||
submitFeedback
|
||||
} from './react/features/feedback';
|
||||
import {
|
||||
mediaPermissionPromptVisibilityChanged,
|
||||
suspendDetected
|
||||
@@ -186,7 +208,7 @@ function muteLocalVideo(muted) {
|
||||
*
|
||||
* @param {object} options used to decide which particular close page to show
|
||||
* or if close page is disabled, whether we should show the thankyou dialog
|
||||
* @param {boolean} options.thankYouDialogVisible - whether we should
|
||||
* @param {boolean} options.showThankYou - whether we should
|
||||
* show thank you dialog
|
||||
* @param {boolean} options.feedbackSubmitted - whether feedback was submitted
|
||||
*/
|
||||
@@ -198,24 +220,25 @@ function maybeRedirectToWelcomePage(options) {
|
||||
// save whether current user is guest or not, before navigating
|
||||
// to close page
|
||||
window.sessionStorage.setItem('guest', isGuest);
|
||||
assignWindowLocationPathname(`static/${
|
||||
redirectToStaticPage(`static/${
|
||||
options.feedbackSubmitted ? 'close.html' : 'close2.html'}`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// else: show thankYou dialog only if there is no feedback
|
||||
if (options.thankYouDialogVisible) {
|
||||
APP.UI.messageHandler.openMessageDialog(
|
||||
null, 'dialog.thankYou', { appName: interfaceConfig.APP_NAME });
|
||||
if (options.showThankYou) {
|
||||
APP.store.dispatch(showNotification({
|
||||
titleArguments: { appName: interfaceConfig.APP_NAME },
|
||||
titleKey: 'dialog.thankYou'
|
||||
}));
|
||||
}
|
||||
|
||||
// if Welcome page is enabled redirect to welcome page after 3 sec.
|
||||
if (config.enableWelcomePage) {
|
||||
setTimeout(
|
||||
() => {
|
||||
APP.settings.setWelcomePageEnabled(true);
|
||||
assignWindowLocationPathname('./');
|
||||
APP.store.dispatch(redirectWithStoredParams('/'));
|
||||
},
|
||||
3000);
|
||||
}
|
||||
@@ -231,7 +254,7 @@ function maybeRedirectToWelcomePage(options) {
|
||||
* assigning it to window.location.pathname.
|
||||
* @return {void}
|
||||
*/
|
||||
function assignWindowLocationPathname(pathname) {
|
||||
function redirectToStaticPage(pathname) {
|
||||
const windowLocation = window.location;
|
||||
let newPathname = pathname;
|
||||
|
||||
@@ -291,7 +314,7 @@ class ConferenceConnector {
|
||||
|
||||
case JitsiConferenceErrors.NOT_ALLOWED_ERROR: {
|
||||
// let's show some auth not allowed page
|
||||
assignWindowLocationPathname('static/authError.html');
|
||||
redirectToStaticPage('static/authError.html');
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -359,7 +382,7 @@ class ConferenceConnector {
|
||||
break;
|
||||
|
||||
case JitsiConferenceErrors.INCOMPATIBLE_SERVER_VERSIONS:
|
||||
reload();
|
||||
APP.store.dispatch(reloadWithStoredParams());
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -632,11 +655,16 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
// Hide the permissions prompt/overlay as soon as the tracks are
|
||||
// created. Don't wait for the connection to be made, since in some
|
||||
// cases, when auth is rquired, for instance, that won't happen until
|
||||
// the user inputs their credentials, but the dialog would be
|
||||
// overshadowed by the overlay.
|
||||
tryCreateLocalTracks.then(() =>
|
||||
APP.store.dispatch(mediaPermissionPromptVisibilityChanged(false)));
|
||||
|
||||
return Promise.all([ tryCreateLocalTracks, connect(roomName) ])
|
||||
.then(([ tracks, con ]) => {
|
||||
APP.store.dispatch(
|
||||
mediaPermissionPromptVisibilityChanged(false));
|
||||
|
||||
// FIXME If there will be microphone error it will cover any
|
||||
// screensharing dialog, but it's still better than in
|
||||
// the reverse order where the screensharing dialog will
|
||||
@@ -716,14 +744,13 @@ export default {
|
||||
})
|
||||
.then(([ tracks, con ]) => {
|
||||
tracks.forEach(track => {
|
||||
if (track.isAudioTrack() && this.isLocalAudioMuted()) {
|
||||
sendAnalyticsEvent('conference.audio.initiallyMuted');
|
||||
logger.log('Audio mute: initially muted');
|
||||
track.mute();
|
||||
} else if (track.isVideoTrack()
|
||||
&& this.isLocalVideoMuted()) {
|
||||
sendAnalyticsEvent('conference.video.initiallyMuted');
|
||||
logger.log('Video mute: initially muted');
|
||||
if ((track.isAudioTrack() && this.isLocalAudioMuted())
|
||||
|| (track.isVideoTrack() && this.isLocalVideoMuted())) {
|
||||
const mediaType = track.getType();
|
||||
|
||||
sendAnalytics(
|
||||
createTrackMutedEvent(mediaType, 'initial mute'));
|
||||
logger.log(`${mediaType} mute: initially muted.`);
|
||||
track.mute();
|
||||
}
|
||||
});
|
||||
@@ -1297,6 +1324,7 @@ export default {
|
||||
}
|
||||
|
||||
options.applicationName = interfaceConfig.APP_NAME;
|
||||
options.getWiFiStatsMethod = getJitsiMeetGlobalNS().getWiFiStats;
|
||||
|
||||
return options;
|
||||
},
|
||||
@@ -1312,19 +1340,35 @@ export default {
|
||||
replaceLocalTrack(this.localVideo, newStream, room))
|
||||
.then(() => {
|
||||
this.localVideo = newStream;
|
||||
|
||||
this._setSharingScreen(newStream);
|
||||
if (newStream) {
|
||||
this.isSharingScreen = newStream.videoType === 'desktop';
|
||||
|
||||
APP.UI.addLocalStream(newStream);
|
||||
} else {
|
||||
this.isSharingScreen = false;
|
||||
}
|
||||
this.setVideoMuteStatus(this.isLocalVideoMuted());
|
||||
APP.UI.updateDesktopSharingButtons();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets `this.isSharingScreen` depending on provided video stream.
|
||||
* In case new screen sharing status is not equal previous one
|
||||
* it updates desktop sharing buttons in UI
|
||||
* and notifies external application.
|
||||
*
|
||||
* @param {JitsiLocalTrack} [newStream] new stream to use or null
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_setSharingScreen(newStream) {
|
||||
const wasSharingScreen = this.isSharingScreen;
|
||||
|
||||
this.isSharingScreen = newStream && newStream.videoType === 'desktop';
|
||||
|
||||
if (wasSharingScreen !== this.isSharingScreen) {
|
||||
APP.UI.updateDesktopSharingButtons();
|
||||
APP.API.notifyScreenSharingStatusChanged(this.isSharingScreen);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Start using provided audio stream.
|
||||
* Stops previous audio stream.
|
||||
@@ -1427,9 +1471,9 @@ export default {
|
||||
promise = createLocalTracksF({ devices: [ 'video' ] })
|
||||
.then(([ stream ]) => this.useVideoStream(stream))
|
||||
.then(() => {
|
||||
sendAnalyticsEvent(
|
||||
'conference.sharingDesktop.stop');
|
||||
logger.log('switched back to local video');
|
||||
sendAnalytics(createScreenSharingEvent('stopped'));
|
||||
logger.log('Screen sharing stopped, switching to video.');
|
||||
|
||||
if (!this.localVideo && wasVideoMuted) {
|
||||
return Promise.reject('No local video to be muted!');
|
||||
} else if (wasVideoMuted && this.localVideo) {
|
||||
@@ -1584,7 +1628,7 @@ export default {
|
||||
},
|
||||
|
||||
/**
|
||||
* Tries to switch to the screenshairng mode by disposing camera stream and
|
||||
* Tries to switch to the screensharing mode by disposing camera stream and
|
||||
* replacing it with a desktop one.
|
||||
*
|
||||
* @param {Object} [options] - Screen sharing options that will be passed to
|
||||
@@ -1607,8 +1651,8 @@ export default {
|
||||
.then(stream => this.useVideoStream(stream))
|
||||
.then(() => {
|
||||
this.videoSwitchInProgress = false;
|
||||
sendAnalyticsEvent('conference.sharingDesktop.start');
|
||||
logger.log('sharing local desktop');
|
||||
sendAnalytics(createScreenSharingEvent('started'));
|
||||
logger.log('Screen sharing started');
|
||||
})
|
||||
.catch(error => {
|
||||
this.videoSwitchInProgress = false;
|
||||
@@ -1665,12 +1709,6 @@ export default {
|
||||
}
|
||||
);
|
||||
|
||||
return;
|
||||
} else if (error.name === JitsiTrackErrors.FIREFOX_EXTENSION_NEEDED) {
|
||||
APP.UI.showExtensionRequiredDialog(
|
||||
config.desktopSharingFirefoxExtensionURL
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1683,8 +1721,23 @@ export default {
|
||||
let titleKey;
|
||||
|
||||
if (error.name === JitsiTrackErrors.PERMISSION_DENIED) {
|
||||
descriptionKey = 'dialog.screenSharingPermissionDeniedError';
|
||||
titleKey = 'dialog.screenSharingFailedToInstallTitle';
|
||||
|
||||
// in FF the only option for user is to deny access temporary or
|
||||
// permanently and we only receive permission_denied
|
||||
// we always show some info cause in case of permanently, no info
|
||||
// shown will be bad experience
|
||||
//
|
||||
// TODO: detect interval between requesting permissions and received
|
||||
// error, this way we can detect user interaction which will have
|
||||
// longer delay
|
||||
if (JitsiMeetJS.util.browser.isFirefox()) {
|
||||
descriptionKey
|
||||
= 'dialog.screenSharingFirefoxPermissionDeniedError';
|
||||
titleKey = 'dialog.screenSharingFirefoxPermissionDeniedTitle';
|
||||
} else {
|
||||
descriptionKey = 'dialog.screenSharingPermissionDeniedError';
|
||||
titleKey = 'dialog.screenSharingFailedToInstallTitle';
|
||||
}
|
||||
} else {
|
||||
descriptionKey = 'dialog.screenSharingFailedToInstall';
|
||||
titleKey = 'dialog.screenSharingFailedToInstallTitle';
|
||||
@@ -1720,15 +1773,20 @@ export default {
|
||||
if (user.isHidden()) {
|
||||
return;
|
||||
}
|
||||
const displayName = user.getDisplayName();
|
||||
|
||||
APP.store.dispatch(participantJoined({
|
||||
id,
|
||||
name: user.getDisplayName(),
|
||||
name: displayName,
|
||||
role: user.getRole()
|
||||
}));
|
||||
|
||||
logger.log('USER %s connnected', id, user);
|
||||
APP.API.notifyUserJoined(id);
|
||||
APP.API.notifyUserJoined(id, {
|
||||
displayName,
|
||||
formattedDisplayName: appendSuffix(
|
||||
displayName || interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME)
|
||||
});
|
||||
APP.UI.addUser(user);
|
||||
|
||||
// check the roles for the new user and reflect them
|
||||
@@ -1736,6 +1794,9 @@ export default {
|
||||
});
|
||||
|
||||
room.on(JitsiConferenceEvents.USER_LEFT, (id, user) => {
|
||||
if (user.isHidden()) {
|
||||
return;
|
||||
}
|
||||
APP.store.dispatch(participantLeft(id, user));
|
||||
logger.log('USER %s LEFT', id, user);
|
||||
APP.API.notifyUserLeft(id);
|
||||
@@ -1886,6 +1947,7 @@ export default {
|
||||
}
|
||||
|
||||
APP.UI.addListener(UIEvents.SELECTED_ENDPOINT, id => {
|
||||
APP.API.notifyOnStageParticipantChanged(id);
|
||||
try {
|
||||
// do not try to select participant if there is none (we
|
||||
// are alone in the room), otherwise an error will be
|
||||
@@ -1897,8 +1959,7 @@ export default {
|
||||
|
||||
room.selectParticipant(id);
|
||||
} catch (e) {
|
||||
sendAnalyticsEvent(
|
||||
'selectParticipant.failed');
|
||||
sendAnalytics(createSelectParticipantFailedEvent(e));
|
||||
reportError(e);
|
||||
}
|
||||
});
|
||||
@@ -1932,7 +1993,13 @@ export default {
|
||||
id,
|
||||
name: formattedDisplayName
|
||||
}));
|
||||
APP.API.notifyDisplayNameChanged(id, formattedDisplayName);
|
||||
APP.API.notifyDisplayNameChanged(id, {
|
||||
displayName: formattedDisplayName,
|
||||
formattedDisplayName:
|
||||
appendSuffix(
|
||||
formattedDisplayName
|
||||
|| interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME)
|
||||
});
|
||||
APP.UI.changeDisplayName(id, formattedDisplayName);
|
||||
}
|
||||
);
|
||||
@@ -2057,7 +2124,6 @@ export default {
|
||||
id: from,
|
||||
avatarURL: data.value
|
||||
}));
|
||||
APP.UI.setUserAvatarUrl(from, data.value);
|
||||
});
|
||||
|
||||
room.addCommandListener(this.commands.defaults.AVATAR_ID,
|
||||
@@ -2067,24 +2133,16 @@ export default {
|
||||
id: from,
|
||||
avatarID: data.value
|
||||
}));
|
||||
APP.UI.setUserAvatarID(from, data.value);
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.NICKNAME_CHANGED,
|
||||
this.changeLocalDisplayName.bind(this));
|
||||
|
||||
APP.UI.addListener(UIEvents.START_MUTED_CHANGED,
|
||||
(startAudioMuted, startVideoMuted) => {
|
||||
room.setStartMutedPolicy({
|
||||
audio: startAudioMuted,
|
||||
video: startVideoMuted
|
||||
});
|
||||
}
|
||||
);
|
||||
room.on(
|
||||
JitsiConferenceEvents.START_MUTED_POLICY_CHANGED,
|
||||
({ audio, video }) => {
|
||||
APP.UI.onStartMutedChanged(audio, video);
|
||||
APP.store.dispatch(
|
||||
onStartMutedPolicyChanged(audio, video));
|
||||
}
|
||||
);
|
||||
room.on(JitsiConferenceEvents.STARTED_MUTED, () => {
|
||||
@@ -2125,22 +2183,12 @@ export default {
|
||||
APP.UI.addListener(
|
||||
UIEvents.RESOLUTION_CHANGED,
|
||||
(id, oldResolution, newResolution, delay) => {
|
||||
const logObject = {
|
||||
id: 'resolution_change',
|
||||
participant: id,
|
||||
oldValue: oldResolution,
|
||||
newValue: newResolution,
|
||||
delay
|
||||
};
|
||||
|
||||
room.sendApplicationLog(JSON.stringify(logObject));
|
||||
|
||||
// We only care about the delay between simulcast streams.
|
||||
// Longer delays will be caused by something else and will just
|
||||
// poison the data.
|
||||
if (delay < 2000) {
|
||||
sendAnalyticsEvent('stream.switch.delay', { value: delay });
|
||||
}
|
||||
sendAnalytics(createStreamSwitchDelayEvent(
|
||||
{
|
||||
'old_resolution': oldResolution,
|
||||
'new_resolution': newResolution,
|
||||
value: delay
|
||||
}));
|
||||
});
|
||||
|
||||
/* eslint-enable max-params */
|
||||
@@ -2166,7 +2214,7 @@ export default {
|
||||
cameraDeviceId => {
|
||||
const videoWasMuted = this.isLocalVideoMuted();
|
||||
|
||||
sendAnalyticsEvent('settings.changeDevice.video');
|
||||
sendAnalytics(createDeviceChangedEvent('video', 'input'));
|
||||
createLocalTracksF({
|
||||
devices: [ 'video' ],
|
||||
cameraDeviceId,
|
||||
@@ -2205,8 +2253,7 @@ export default {
|
||||
micDeviceId => {
|
||||
const audioWasMuted = this.isLocalAudioMuted();
|
||||
|
||||
sendAnalyticsEvent(
|
||||
'settings.changeDevice.audioIn');
|
||||
sendAnalytics(createDeviceChangedEvent('audio', 'input'));
|
||||
createLocalTracksF({
|
||||
devices: [ 'audio' ],
|
||||
cameraDeviceId: null,
|
||||
@@ -2236,8 +2283,7 @@ export default {
|
||||
APP.UI.addListener(
|
||||
UIEvents.AUDIO_OUTPUT_DEVICE_CHANGED,
|
||||
audioOutputDeviceId => {
|
||||
sendAnalyticsEvent(
|
||||
'settings.changeDevice.audioOut');
|
||||
sendAnalytics(createDeviceChangedEvent('audio', 'output'));
|
||||
APP.settings.setAudioOutputDeviceId(audioOutputDeviceId)
|
||||
.then(() => logger.log('changed audio output device'))
|
||||
.catch(err => {
|
||||
@@ -2368,10 +2414,6 @@ export default {
|
||||
|
||||
APP.UI.initConference();
|
||||
|
||||
APP.UI.addListener(
|
||||
UIEvents.LANG_CHANGED,
|
||||
language => APP.translation.setLanguage(language));
|
||||
|
||||
APP.keyboardshortcut.init();
|
||||
|
||||
if (config.requireDisplayName
|
||||
@@ -2382,7 +2424,20 @@ export default {
|
||||
APP.store.dispatch(conferenceJoined(room));
|
||||
|
||||
APP.UI.mucJoined();
|
||||
APP.API.notifyConferenceJoined(APP.conference.roomName);
|
||||
const displayName = APP.settings.getDisplayName();
|
||||
|
||||
APP.API.notifyConferenceJoined(
|
||||
this.roomName,
|
||||
this._room.myUserId(),
|
||||
{
|
||||
displayName,
|
||||
formattedDisplayName: appendSuffix(
|
||||
displayName,
|
||||
interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME),
|
||||
avatarURL: getAvatarURLByParticipantId(
|
||||
APP.store.getState(), this._room.myUserId())
|
||||
}
|
||||
);
|
||||
APP.UI.markVideoInterrupted(false);
|
||||
},
|
||||
|
||||
@@ -2494,7 +2549,9 @@ export default {
|
||||
// If audio was muted before, or we unplugged current device
|
||||
// and selected new one, then mute new audio track.
|
||||
if (audioWasMuted) {
|
||||
sendAnalyticsEvent('deviceListChanged.audio.muted');
|
||||
sendAnalytics(createTrackMutedEvent(
|
||||
'audio',
|
||||
'device list changed'));
|
||||
logger.log('Audio mute: device list changed');
|
||||
muteLocalAudio(true);
|
||||
}
|
||||
@@ -2502,7 +2559,9 @@ export default {
|
||||
// If video was muted before, or we unplugged current device
|
||||
// and selected new one, then mute new video track.
|
||||
if (!this.isSharingScreen && videoWasMuted) {
|
||||
sendAnalyticsEvent('deviceListChanged.video.muted');
|
||||
sendAnalytics(createTrackMutedEvent(
|
||||
'video',
|
||||
'device list changed'));
|
||||
logger.log('Video mute: device list changed');
|
||||
muteLocalVideo(true);
|
||||
}
|
||||
@@ -2588,37 +2647,6 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Log event to callstats and analytics.
|
||||
* @param {string} name the event name
|
||||
* @param {int} value the value (it's int because google analytics supports
|
||||
* only int).
|
||||
* @param {string} label short text which provides more info about the event
|
||||
* which allows to distinguish between few event cases of the same name
|
||||
* NOTE: Should be used after conference.init
|
||||
*/
|
||||
logEvent(name, value, label) {
|
||||
sendAnalyticsEvent(name, {
|
||||
value,
|
||||
label
|
||||
});
|
||||
if (room) {
|
||||
room.sendApplicationLog(JSON.stringify({ name,
|
||||
value,
|
||||
label }));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Methods logs an application event given in the JSON format.
|
||||
* @param {string} logJSON an event to be logged in JSON format
|
||||
*/
|
||||
logJSON(logJSON) {
|
||||
if (room) {
|
||||
room.sendApplicationLog(logJSON);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Disconnect from the conference and optionally request user feedback.
|
||||
* @param {boolean} [requestFeedback=false] if user feedback should be
|
||||
@@ -2626,6 +2654,7 @@ export default {
|
||||
*/
|
||||
hangup(requestFeedback = false) {
|
||||
eventEmitter.emit(JitsiMeetConferenceEvents.BEFORE_HANGUP);
|
||||
APP.UI.removeLocalMedia();
|
||||
|
||||
let requestFeedbackPromise;
|
||||
|
||||
@@ -2670,7 +2699,7 @@ export default {
|
||||
APP.store.dispatch(participantUpdated({
|
||||
id: localId,
|
||||
local: true,
|
||||
formattedEmail
|
||||
email: formattedEmail
|
||||
}));
|
||||
|
||||
APP.settings.setEmail(formattedEmail);
|
||||
@@ -2698,7 +2727,6 @@ export default {
|
||||
}));
|
||||
|
||||
APP.settings.setAvatarUrl(url);
|
||||
APP.UI.setUserAvatarUrl(id, url);
|
||||
sendData(commands.AVATAR_URL, url);
|
||||
},
|
||||
|
||||
@@ -2753,6 +2781,14 @@ export default {
|
||||
}));
|
||||
|
||||
APP.settings.setDisplayName(formattedNickname);
|
||||
APP.API.notifyDisplayNameChanged(id, {
|
||||
displayName: formattedNickname,
|
||||
formattedDisplayName:
|
||||
appendSuffix(
|
||||
formattedNickname,
|
||||
interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME)
|
||||
});
|
||||
|
||||
if (room) {
|
||||
room.setDisplayName(formattedNickname);
|
||||
APP.UI.changeDisplayName(id, formattedNickname);
|
||||
@@ -2800,5 +2836,21 @@ export default {
|
||||
setAudioMuteStatus(muted) {
|
||||
APP.UI.setAudioMuted(this.getMyUserId(), muted);
|
||||
APP.API.notifyAudioMutedStatusChanged(muted);
|
||||
},
|
||||
|
||||
/**
|
||||
* Dispatches the passed in feedback for submission. The submitted score
|
||||
* should be a number inclusively between 1 through 5, or -1 for no score.
|
||||
*
|
||||
* @param {number} score - a number between 1 and 5 (inclusive) or -1 for no
|
||||
* score.
|
||||
* @param {string} message - An optional message to attach to the feedback
|
||||
* in addition to the score.
|
||||
* @returns {void}
|
||||
*/
|
||||
submitFeedback(score = -1, message = '') {
|
||||
if (score === -1 || (score >= 1 && score <= 5)) {
|
||||
APP.store.dispatch(submitFeedback(score, message, room));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
88
config.js
@@ -94,7 +94,7 @@ var config = {
|
||||
|
||||
// w3c spec-compliant video constraints to use for video capture. Currently
|
||||
// used by browsers that return true from lib-jitsi-meet's
|
||||
// RTCBrowserType#usesNewGumFlow. The constraints are independency from
|
||||
// util#browser#usesNewGumFlow. The constraints are independency from
|
||||
// this config's resolution value. Defaults to requesting an ideal aspect
|
||||
// ratio of 16:9 with an ideal resolution of 1080p.
|
||||
// constraints: {
|
||||
@@ -150,22 +150,14 @@ var config = {
|
||||
// Required version of Chrome extension
|
||||
desktopSharingChromeMinExtVersion: '0.1',
|
||||
|
||||
// The ID of the jidesha extension for Firefox. If null, we assume that no
|
||||
// extension is required.
|
||||
desktopSharingFirefoxExtId: null,
|
||||
|
||||
// Whether desktop sharing should be disabled on Firefox.
|
||||
desktopSharingFirefoxDisabled: false,
|
||||
|
||||
// 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,
|
||||
|
||||
// The URL to the Firefox extension for desktop sharing.
|
||||
desktopSharingFirefoxExtensionURL: null,
|
||||
// Optional desktop sharing frame rate options. Default value: min:5, max:5.
|
||||
// desktopSharingFrameRate: {
|
||||
// min: 5,
|
||||
// max: 5
|
||||
// },
|
||||
|
||||
// Try to start calls with screen-sharing instead of camera video.
|
||||
// startScreenSharing: false,
|
||||
@@ -239,8 +231,11 @@ var config = {
|
||||
// Stats
|
||||
//
|
||||
|
||||
// Whether to enable stats collection or not.
|
||||
// disableStats: false,
|
||||
// Whether to enable stats collection or not in the TraceablePeerConnection.
|
||||
// This can be useful for debugging purposes (post-processing/analysis of
|
||||
// the webrtc stats) as it is done in the jitsi-meet-torture bandwidth
|
||||
// estimation tests.
|
||||
// gatherStats: false,
|
||||
|
||||
// To enable sending statistics to callstats.io you must provide the
|
||||
// Application ID and Secret.
|
||||
@@ -307,16 +302,73 @@ var config = {
|
||||
// backToP2PDelay: 5
|
||||
},
|
||||
|
||||
// A list of scripts to load as lib-jitsi-meet "analytics handlers".
|
||||
// analyticsScriptUrls: [
|
||||
// "libs/analytics-ga.js", // google-analytics
|
||||
// "https://example.com/my-custom-analytics.js"
|
||||
// ],
|
||||
|
||||
// The Google Analytics Tracking ID
|
||||
// googleAnalyticsTrackingId = 'your-tracking-id-here-UA-123456-1',
|
||||
|
||||
// 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"
|
||||
}
|
||||
|
||||
// List of undocumented settings used in jitsi-meet
|
||||
/**
|
||||
alwaysVisibleToolbar
|
||||
autoEnableDesktopSharing
|
||||
autoRecord
|
||||
autoRecordToken
|
||||
debug
|
||||
debugAudioLevels
|
||||
deploymentInfo
|
||||
dialInConfCodeUrl
|
||||
dialInNumbersUrl
|
||||
dialOutAuthUrl
|
||||
dialOutCodesUrl
|
||||
disableRemoteControl
|
||||
displayJids
|
||||
enableLocalVideoFlip
|
||||
etherpad_base
|
||||
externalConnectUrl
|
||||
firefox_fake_device
|
||||
googleApiApplicationClientID
|
||||
iAmRecorder
|
||||
iAmSipGateway
|
||||
peopleSearchQueryTypes
|
||||
peopleSearchUrl
|
||||
requireDisplayName
|
||||
tokenAuthUrl
|
||||
*/
|
||||
|
||||
// List of undocumented settings used in lib-jitsi-meet
|
||||
/**
|
||||
_peerConnStatusOutOfLastNTimeout
|
||||
_peerConnStatusRtcMuteTimeout
|
||||
abTesting
|
||||
avgRtpStatsN
|
||||
callStatsConfIDNamespace
|
||||
callStatsCustomScriptUrl
|
||||
desktopSharingSources
|
||||
disableAEC
|
||||
disableAGC
|
||||
disableAP
|
||||
disableHPF
|
||||
disableNS
|
||||
enableLipSync
|
||||
enableTalkWhileMuted
|
||||
forceJVB121Ratio
|
||||
hiddenDomain
|
||||
ignoreStartMuted
|
||||
nick
|
||||
startBitrate
|
||||
*/
|
||||
};
|
||||
|
||||
/* eslint-enable no-unused-vars, no-var */
|
||||
|
||||
@@ -94,12 +94,15 @@ function connect(id, password, roomName) {
|
||||
JitsiConnectionEvents.CONNECTION_FAILED,
|
||||
connectionFailedHandler);
|
||||
|
||||
/* eslint-disable max-params */
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function connectionFailedHandler(error, message, credentials) {
|
||||
function connectionFailedHandler(error, message, credentials, details) {
|
||||
/* eslint-enable max-params */
|
||||
APP.store.dispatch(
|
||||
connectionFailed(connection, error, message, credentials));
|
||||
connectionFailed(
|
||||
connection, error, message, credentials, details));
|
||||
|
||||
if (isFatalJitsiConnectionError(error)) {
|
||||
connection.removeEventListener(
|
||||
|
||||
@@ -16,14 +16,17 @@ import parseURLParams from '../react/features/base/config/parseURLParams';
|
||||
*/
|
||||
|
||||
if (typeof createConnectionExternally === 'function') {
|
||||
// URL params have higher proirity than config params.
|
||||
// URL params have higher priority than config params.
|
||||
let url
|
||||
= parseURLParams(window.location, true, 'hash')[
|
||||
'config.externalConnectUrl']
|
||||
|| config.externalConnectUrl;
|
||||
const isRecorder
|
||||
= parseURLParams(window.location, true, 'hash')['config.iAmRecorder'];
|
||||
|
||||
let roomName;
|
||||
|
||||
if (url && (roomName = getRoomName())) {
|
||||
if (url && (roomName = getRoomName()) && !isRecorder) {
|
||||
url += `?room=${roomName}`;
|
||||
|
||||
const token = parseURLParams(window.location, true, 'search').jwt;
|
||||
|
||||
229
css/_aui_reset.scss
Normal file
@@ -0,0 +1,229 @@
|
||||
/* Fonts and line heights */
|
||||
/**
|
||||
* RESET
|
||||
*/
|
||||
html,
|
||||
body,
|
||||
p,
|
||||
div,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
img,
|
||||
pre,
|
||||
form,
|
||||
fieldset {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
ul,
|
||||
ol,
|
||||
dl {
|
||||
margin: 0;
|
||||
}
|
||||
img,
|
||||
fieldset {
|
||||
border: 0;
|
||||
}
|
||||
@-moz-document url-prefix() {
|
||||
img {
|
||||
font-size: 0;
|
||||
}
|
||||
img:-moz-broken {
|
||||
font-size: inherit;
|
||||
}
|
||||
}
|
||||
/* https://github.com/necolas/normalize.css */
|
||||
/* Customised to remove styles for unsupported browsers */
|
||||
details,
|
||||
main,
|
||||
summary {
|
||||
display: block;
|
||||
}
|
||||
audio,
|
||||
canvas,
|
||||
progress,
|
||||
video {
|
||||
display: inline-block;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
[hidden],
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
input[type="button"],
|
||||
input[type="submit"],
|
||||
input[type="reset"] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
/**
|
||||
* TYPOGRAPHY - 14px base font size, agnostic font stack
|
||||
*/
|
||||
body {
|
||||
color: #333;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857142857143;
|
||||
}
|
||||
/* International Font Stacks*/
|
||||
[lang|=en] {
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
[lang|=ja] {
|
||||
font-family: "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ Pro W3", "メイリオ", Meiryo, "MS Pゴシック", Verdana, Arial, sans-serif;
|
||||
}
|
||||
/* Default margins */
|
||||
p,
|
||||
ul,
|
||||
ol,
|
||||
dl,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
blockquote,
|
||||
pre {
|
||||
margin: 10px 0 0 0;
|
||||
}
|
||||
/* No top margin to interfere with box padding */
|
||||
p:first-child,
|
||||
ul:first-child,
|
||||
ol:first-child,
|
||||
dl:first-child,
|
||||
h1:first-child,
|
||||
h2:first-child,
|
||||
h3:first-child,
|
||||
h4:first-child,
|
||||
h5:first-child,
|
||||
h6:first-child,
|
||||
blockquote:first-child,
|
||||
pre:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
/* Headings: desired line height in px / font size = unitless line height */
|
||||
h1 {
|
||||
color: #333;
|
||||
font-size: 32px;
|
||||
font-weight: normal;
|
||||
line-height: 1.25;
|
||||
text-transform: none;
|
||||
margin: 30px 0 0 0;
|
||||
}
|
||||
h2 {
|
||||
color: #333;
|
||||
font-size: 24px;
|
||||
font-weight: normal;
|
||||
line-height: 1.25;
|
||||
text-transform: none;
|
||||
margin: 30px 0 0 0;
|
||||
}
|
||||
h3 {
|
||||
color: #333;
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
line-height: 1.5;
|
||||
text-transform: none;
|
||||
margin: 30px 0 0 0;
|
||||
}
|
||||
h4 {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
line-height: 1.25;
|
||||
text-transform: none;
|
||||
margin: 20px 0 0 0;
|
||||
}
|
||||
h5 {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
line-height: 1.42857143;
|
||||
text-transform: none;
|
||||
margin: 20px 0 0 0;
|
||||
}
|
||||
h6 {
|
||||
color: #707070;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
line-height: 1.66666667;
|
||||
text-transform: uppercase;
|
||||
margin: 20px 0 0 0;
|
||||
}
|
||||
h1:first-child,
|
||||
h2:first-child,
|
||||
h3:first-child,
|
||||
h4:first-child,
|
||||
h5:first-child,
|
||||
h6:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
/* Nice styles for using subheadings */
|
||||
h1 + h2,
|
||||
h2 + h3,
|
||||
h3 + h4,
|
||||
h4 + h5,
|
||||
h5 + h6 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* Other typographical elements */
|
||||
small {
|
||||
color: #707070;
|
||||
font-size: 12px;
|
||||
line-height: 1.33333333333333;
|
||||
}
|
||||
code,
|
||||
kbd {
|
||||
font-family: monospace;
|
||||
}
|
||||
var,
|
||||
address,
|
||||
dfn,
|
||||
cite {
|
||||
font-style: italic;
|
||||
}
|
||||
cite:before {
|
||||
content: "\2014 \2009";
|
||||
}
|
||||
blockquote {
|
||||
border-left: 1px solid #ccc;
|
||||
color: #707070;
|
||||
margin-left: 19px;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
blockquote > cite {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
}
|
||||
q {
|
||||
color: #707070;
|
||||
}
|
||||
q:before {
|
||||
content: open-quote;
|
||||
}
|
||||
q:after {
|
||||
content: close-quote;
|
||||
}
|
||||
abbr {
|
||||
border-bottom: 1px #707070 dotted;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #3572b0;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:focus,
|
||||
a:hover,
|
||||
a:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
@@ -123,6 +123,9 @@ form {
|
||||
* Dialogs fade
|
||||
*/
|
||||
.aui-blanket {
|
||||
background: #000;
|
||||
transition: opacity 0.2s, visibility 0.2s;
|
||||
transition-delay: 0.1s;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,11 +13,6 @@
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icon-security,
|
||||
.icon-security-locked {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
#contacts {
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* The dialog content element.
|
||||
*/
|
||||
.dial-out-content {
|
||||
margin-top: 5px;
|
||||
|
||||
/**
|
||||
* Wrap the contents in flex so items can be aligned on the same line.
|
||||
*/
|
||||
.form-control {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/**
|
||||
* The style of the flag icon.
|
||||
*/
|
||||
.dial-out-flag-icon {
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
|
||||
/**
|
||||
* The style of the dial code element.
|
||||
*/
|
||||
.dial-out-code {
|
||||
margin-bottom: 0;
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
/**
|
||||
* The dial-out dialog error element.
|
||||
*/
|
||||
.dial-out-error {
|
||||
color: $errorColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* The style of the dial input element.
|
||||
*/
|
||||
.dial-out-input {
|
||||
display: inline-block;
|
||||
flex: 1;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-styling the default dropdown inside the dial-out-content.
|
||||
*/
|
||||
.dropdown {
|
||||
position: relative;
|
||||
width: 65px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-styling the default form-control inside the dial-out-content.
|
||||
*/
|
||||
.form-control {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: relative;
|
||||
|
||||
input {
|
||||
padding-left: 16px;
|
||||
|
||||
&:read-only {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-trigger-icon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@
|
||||
* The local video identifier.
|
||||
*/
|
||||
&#filmstripLocalVideo {
|
||||
bottom: 32px;
|
||||
align-self: flex-end;
|
||||
display: block;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -24,7 +24,30 @@
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-arrow_back:before {
|
||||
content: "\e5c4";
|
||||
}
|
||||
.icon-event_note:before {
|
||||
content: "\e616";
|
||||
}
|
||||
.icon-menu:before {
|
||||
content: "\e5d2";
|
||||
}
|
||||
.icon-navigate_before:before {
|
||||
content: "\e408";
|
||||
}
|
||||
.icon-navigate_next:before {
|
||||
content: "\e409";
|
||||
}
|
||||
.icon-public:before {
|
||||
content: "\e80b";
|
||||
}
|
||||
.icon-restore:before {
|
||||
content: "\e8b3";
|
||||
}
|
||||
.icon-timer:before {
|
||||
content: "\e425";
|
||||
}
|
||||
.icon-thumb-menu:before {
|
||||
content: "\e5d4";
|
||||
}
|
||||
|
||||
@@ -56,9 +56,6 @@
|
||||
margin-bottom: 0px;
|
||||
width: 100%;
|
||||
border-radius: 0px;
|
||||
> .aui-progress-indicator-value {
|
||||
border-radius: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
&__title {
|
||||
|
||||
@@ -1,3 +1,81 @@
|
||||
.recordingSpinner {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.live-stream-dialog {
|
||||
/**
|
||||
* Set font-size to be consistent with Atlaskit FieldText.
|
||||
*/
|
||||
font-size: 14px;
|
||||
|
||||
.broadcast-dropdown,
|
||||
.broadcast-dropdown-trigger {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.form-footer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.live-stream-cta {
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.google-api {
|
||||
margin-top: 10px;
|
||||
min-height: 36px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Google sign in button must follow Google's design guidelines.
|
||||
* See: https://developers.google.com/identity/branding-guidelines
|
||||
*/
|
||||
.google-sign-in {
|
||||
background-color: #4285f4;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
font-family: Roboto, arial, sans-serif;
|
||||
font-size: 14px;
|
||||
padding: 1px;
|
||||
|
||||
.google-cta {
|
||||
color: white;
|
||||
display: inline-block;
|
||||
/**
|
||||
* Hack the line height for vertical centering of text.
|
||||
*/
|
||||
line-height: 32px;
|
||||
margin: 0 15px;
|
||||
}
|
||||
|
||||
.google-logo {
|
||||
background-color: white;
|
||||
border-radius: 2px;
|
||||
display: inline-block;
|
||||
padding: 8px;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.google-panel {
|
||||
align-items: center;
|
||||
border-bottom: 2px solid rgba(0, 0, 0, 0.3);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.stream-key-form {
|
||||
.helper-link {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,10 @@
|
||||
/**
|
||||
* Form elements and blocks.
|
||||
*/
|
||||
input, select, a,
|
||||
.sideToolbarBlock, .form-control, .button-control {
|
||||
input,
|
||||
a,
|
||||
.sideToolbarBlock,
|
||||
.form-control {
|
||||
display: block;
|
||||
margin-top: 15px;
|
||||
margin-left: 10%;
|
||||
@@ -34,19 +36,11 @@
|
||||
* Specify styling of elements inside a block.
|
||||
*/
|
||||
.sideToolbarBlock {
|
||||
input, button, a, select {
|
||||
input, a {
|
||||
margin-left: 0;
|
||||
margin-top: 5px;
|
||||
width: 100%;
|
||||
}
|
||||
input[type='checkbox'] {
|
||||
display: inline;
|
||||
width: auto !important;
|
||||
> label {
|
||||
margin-top: 5px;
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,42 +74,35 @@
|
||||
font-size: $toolbarTitleFontSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtitle specific properties.
|
||||
*/
|
||||
div.subTitle {
|
||||
color: $defaultSideBarFontColor !important;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
margin-left: 10%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/**
|
||||
* First element after a title.
|
||||
*/
|
||||
.first {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Buttons in the side toolbar container.
|
||||
*/
|
||||
.button-control {
|
||||
margin: 9px 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#device_settings {
|
||||
width : auto !important;
|
||||
text-align: center;
|
||||
}
|
||||
.settings-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-left: 10%;
|
||||
padding-right: 10%;
|
||||
|
||||
#deviceOptionsWrapper {
|
||||
button {
|
||||
float: none;
|
||||
.moderator-checkbox {
|
||||
display: inline-block;
|
||||
margin: 0 5px 0;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.moderator-option {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.subTitle {
|
||||
color: $defaultSideBarFontColor;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,11 +56,14 @@
|
||||
/**
|
||||
* Toolbar button styles for always on top.
|
||||
*/
|
||||
> .button {
|
||||
.button {
|
||||
font-size: $alwaysOnTopToolbarFontSize;
|
||||
height: $alwaysOnTopToolbarSize;
|
||||
line-height: $alwaysOnTopToolbarSize;
|
||||
width: $alwaysOnTopToolbarSize;
|
||||
&_hangup, &_hangup:hover {
|
||||
font-size: $alwaysOnTopToolbarFontSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,10 +153,13 @@
|
||||
|
||||
@include transform(translateX(-50%));
|
||||
|
||||
> a:first-child.button,
|
||||
> div:first-child .button {
|
||||
border-bottom-left-radius: 3px;
|
||||
border-top-left-radius: 3px;
|
||||
}
|
||||
|
||||
> a:last-child.button,
|
||||
> div:last-child .button {
|
||||
border-bottom-right-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
@@ -183,6 +189,7 @@
|
||||
justify-content: flex-start;
|
||||
left: 0;
|
||||
padding-top: 24px;
|
||||
pointer-events: none;
|
||||
top: 0;
|
||||
transform: translateX(-100%);
|
||||
width: $defaultToolbarSize;
|
||||
@@ -194,6 +201,10 @@
|
||||
line-height: $secToolbarLineHeight;
|
||||
}
|
||||
|
||||
> * {
|
||||
pointer-events: auto
|
||||
}
|
||||
|
||||
.button.toggled:not(.icon-raised-hand):not(.button-active) {
|
||||
background: $secondaryToolbarBg;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
.flip-x {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides an element.
|
||||
*/
|
||||
@@ -5,6 +13,10 @@
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.invisible {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an element.
|
||||
*/
|
||||
@@ -35,4 +47,4 @@
|
||||
display: -ms-flexbox !important;
|
||||
display: -webkit-flex !important;
|
||||
display: flex !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,8 +138,8 @@ $formPadding: 16px;
|
||||
/**
|
||||
* Unsupported browser
|
||||
*/
|
||||
$primaryUnsupportedBrowserButtonBgColor: #17a0db;
|
||||
$unsupportedBrowserButtonBgColor: #ff9a00;
|
||||
$primaryUnsupportedBrowserButtonBgColor: #0052CC;
|
||||
$unsupportedBrowserButtonBgColor: rgba(9, 30, 66, 0.04);
|
||||
$unsupportedBrowserTextColor: #4a4a4a;
|
||||
$unsupportedBrowserTextSmallFontSize: 17px;
|
||||
$unsupportedBrowserTitleColor: #fff;
|
||||
@@ -151,4 +151,12 @@ $unsupportedDesktopBrowserTextFontSize: 21px;
|
||||
* The size of the default watermark.
|
||||
*/
|
||||
$watermarkWidth: 186px;
|
||||
$watermarkHeight: 74px;
|
||||
$watermarkHeight: 74px;
|
||||
|
||||
/**
|
||||
* Welcome page variables.
|
||||
*/
|
||||
$welcomePageDescriptionColor: #fff;
|
||||
$welcomePageFontFamily: inherit;
|
||||
$welcomePageHeaderBackground: linear-gradient(#165ecc, #44A5FF);
|
||||
$welcomePageTitleColor: #fff;
|
||||
|
||||
@@ -2,6 +2,23 @@
|
||||
* Override other styles to support vertical filmstrip mode.
|
||||
*/
|
||||
.vertical-filmstrip {
|
||||
/*
|
||||
* Firefox sets flex items to min-height: auto and min-width: auto,
|
||||
* preventing flex children from shrinking like they do on other browsers.
|
||||
* Setting min-height and min-width 0 is a workaround for the issue so
|
||||
* Firefox behaves like other browsers.
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=1043520
|
||||
*/
|
||||
@mixin minHWAutoFix() {
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
#etherpad,
|
||||
#sharedvideo {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.filmstrip {
|
||||
align-items: flex-end;
|
||||
box-sizing: border-box;
|
||||
@@ -55,6 +72,7 @@
|
||||
* vertical filmstrip layout.
|
||||
*/
|
||||
#filmstripLocalVideo {
|
||||
align-self: initial;
|
||||
bottom: 5px;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
@@ -78,6 +96,8 @@
|
||||
}
|
||||
|
||||
#filmstripRemoteVideos {
|
||||
@include minHWAutoFix();
|
||||
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
@@ -86,6 +106,11 @@
|
||||
|
||||
#filmstripRemoteVideosContainer {
|
||||
flex-direction: column-reverse;
|
||||
/**
|
||||
* Add padding as a hack for Firefox not to show scrollbars when
|
||||
* unnecessary.
|
||||
*/
|
||||
padding: 1px 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
@@ -115,6 +140,8 @@
|
||||
}
|
||||
|
||||
#remoteVideos {
|
||||
@include minHWAutoFix();
|
||||
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
}
|
||||
@@ -224,3 +251,35 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Workarounds for Edge, IE11, and Firefox not handling scrolling properly
|
||||
* with flex-direction: column-reverse. The remove videos in filmstrip should
|
||||
* start scrolling from the bottom of the filmstrip, but in those browsers the
|
||||
* scrolling won't happen. Per W3C spec, scrolling should happen from the
|
||||
* bottom. As such, use css hacks to get around the css issue, with the intent
|
||||
* being to remove the hacks as the spec is supported.
|
||||
*/
|
||||
@mixin undoColumnReverseVideos() {
|
||||
.vertical-filmstrip {
|
||||
#remoteVideos #filmstripRemoteVideos #filmstripRemoteVideosContainer {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Firefox detection hack **/
|
||||
@-moz-document url-prefix() {
|
||||
@include undoColumnReverseVideos();
|
||||
}
|
||||
|
||||
/** IE11 detection hack **/
|
||||
@media screen and (-ms-high-contrast: active),
|
||||
screen and (-ms-high-contrast: none) {
|
||||
@include undoColumnReverseVideos();
|
||||
}
|
||||
|
||||
/** Edge detection hack **/
|
||||
@supports (-ms-ime-align:auto) {
|
||||
@include undoColumnReverseVideos();
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.video_blurred_container {
|
||||
#largeVideoBackgroundContainer,
|
||||
.large-video-background {
|
||||
height: 100%;
|
||||
filter: blur(40px);
|
||||
left: 0;
|
||||
@@ -20,6 +21,16 @@
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
|
||||
&.fit-full-height #largeVideoBackground {
|
||||
height: 100%;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.fit-full-width #largeVideoBackground {
|
||||
height: auto;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.videocontainer {
|
||||
@@ -250,6 +261,7 @@
|
||||
/**
|
||||
* Positions video thumbnail display name and editor.
|
||||
*/
|
||||
#alwaysOnTop .displayname,
|
||||
.videocontainer .displayname,
|
||||
.videocontainer .editdisplayname {
|
||||
display: inline-block;
|
||||
@@ -269,6 +281,15 @@
|
||||
z-index: $zindex2;
|
||||
}
|
||||
|
||||
#alwaysOnTop .displayname {
|
||||
font-size: 15px;
|
||||
position: inherit;
|
||||
width: 100%;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Positions video thumbnail display name editor.
|
||||
*/
|
||||
@@ -507,6 +528,20 @@
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#videoNotAvailableScreen {
|
||||
text-align: center;
|
||||
#avatarContainer {
|
||||
height: 50vh;
|
||||
display:inline-block;
|
||||
margin-top: 25vh;
|
||||
|
||||
#avatar {
|
||||
border-radius: 50%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sharedVideoAvatar {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
@@ -1,206 +1,87 @@
|
||||
#welcome_page {
|
||||
.welcome {
|
||||
font-family: $welcomePageFontFamily;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#disable_welcome {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.disable_welcome_position
|
||||
{
|
||||
margin: -139px auto 0px auto;
|
||||
padding-left: 39px;
|
||||
padding-top: 7px;
|
||||
width: 269px;
|
||||
height: 31px;
|
||||
display:block;
|
||||
}
|
||||
|
||||
#disable_welcome + label
|
||||
{
|
||||
background-image: url(../images/welcome_page/disable-welcome.png);
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
background-repeat: no-repeat;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
color: #acacac;
|
||||
z-index: $zindex2;
|
||||
}
|
||||
|
||||
#disable_welcome:checked + label
|
||||
{
|
||||
background-image: url(../images/welcome_page/disable-welcome-selected.png);
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
background-repeat: no-repeat;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
color: #acacac;
|
||||
z-index: $zindex2;
|
||||
}
|
||||
|
||||
#enter_room_form {
|
||||
border-radius: 1px;
|
||||
background-color: #FFFFFF;
|
||||
border: none;
|
||||
-moz-border-radius: 1px;
|
||||
-webkit-border-radius: 1px;
|
||||
-webkit-appearance: none;
|
||||
height: 55px;
|
||||
box-shadow: none;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.domain-name
|
||||
{
|
||||
float: left;
|
||||
height: 55px;
|
||||
line-height: 55px;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
padding-left: 20px;
|
||||
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;
|
||||
.header {
|
||||
align-items: center;
|
||||
background: $welcomePageHeaderBackground;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
z-index: $zindex2;
|
||||
}
|
||||
|
||||
&__reload {
|
||||
display: block;
|
||||
width: 30px;
|
||||
color: #acacac;
|
||||
font-size: 1.9em;
|
||||
line-height: 55px;
|
||||
z-index: $zindex3;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
|
||||
.header-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
margin-top: 120px;
|
||||
margin-bottom: 20px;
|
||||
min-height: 286px;
|
||||
width: 645px;
|
||||
}
|
||||
|
||||
.header-text-title {
|
||||
color: $welcomePageTitleColor;
|
||||
font-size: 48px;
|
||||
letter-spacing: -1px;
|
||||
line-height: 58px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.header-text-description {
|
||||
color: $welcomePageDescriptionColor;
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.header-image {
|
||||
background-image: url(../images/welcome_page/curves.png);
|
||||
background-size: contain;
|
||||
height: 209px;
|
||||
position: absolute;
|
||||
width: 1070px;
|
||||
}
|
||||
|
||||
#new_enter_room {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
|
||||
.enter-room-input {
|
||||
display: inline-block;
|
||||
margin-right: 15px;
|
||||
width: 350px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__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;
|
||||
.welcome-page-button {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
#enter_room_container {
|
||||
margin: 70px auto 0px auto;
|
||||
display: table;
|
||||
.welcome.with-content {
|
||||
.header {
|
||||
min-height: 552px;
|
||||
}
|
||||
.header-image {
|
||||
left: -61px;
|
||||
top: 401px;
|
||||
}
|
||||
}
|
||||
|
||||
#enter_room{
|
||||
float:left;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
#welcome_page_header
|
||||
{
|
||||
background-image: url(../images/welcome_page/pattern-header.png);
|
||||
height: 290px;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#welcome_page_main
|
||||
{
|
||||
background-image:url(../images/welcome_page/pattern-body.png);
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
margin-top: 290px;
|
||||
}
|
||||
|
||||
#brand_header
|
||||
{
|
||||
background-image:url(../images/welcome_page/header-big.png);
|
||||
width: 583px;
|
||||
height: 274px;
|
||||
margin: -110px auto 0px auto;
|
||||
}
|
||||
|
||||
#header_text
|
||||
{
|
||||
width: 885px;
|
||||
height: 100px;
|
||||
color: #ffffff;
|
||||
font-size: 24px;
|
||||
text-align: center;
|
||||
margin: 0px auto 0px auto;
|
||||
}
|
||||
|
||||
#features
|
||||
{
|
||||
margin-top: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.feature_row
|
||||
{
|
||||
position: relative;
|
||||
width: 976px;
|
||||
margin: 0px auto 30px auto;
|
||||
padding-right: 75px;
|
||||
|
||||
}
|
||||
|
||||
.feature_holder
|
||||
{
|
||||
float:left;
|
||||
width: 169px;
|
||||
padding-left: 75px;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
|
||||
.feature_icon
|
||||
{
|
||||
background-image:url(../images/welcome_page/bubble.png);
|
||||
background-repeat: no-repeat;
|
||||
width: 169px;
|
||||
height: 169px;
|
||||
color: #ffffff;
|
||||
font-size: 22px;
|
||||
/*font-weight: bold;*/
|
||||
text-align: center;
|
||||
display: table-cell;
|
||||
padding: 50px 26px 0px 20px;
|
||||
}
|
||||
|
||||
.feature_description
|
||||
{
|
||||
width: 190px;
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
padding-top: 30px;
|
||||
line-height: 22px;
|
||||
font-weight: 200;
|
||||
.welcome.without-content {
|
||||
.header {
|
||||
height: 100%;
|
||||
}
|
||||
.header-image {
|
||||
bottom: -20px;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
1
css/_welcome_page_content.scss
Normal file
@@ -0,0 +1 @@
|
||||
/** Insert custom CSS for any additional content in the welcome page **/
|
||||
@@ -28,11 +28,9 @@
|
||||
@import 'font-awesome';
|
||||
/* Fonts END */
|
||||
|
||||
@import 'flag-icon';
|
||||
|
||||
/* Modules BEGIN */
|
||||
|
||||
@import 'dial-out';
|
||||
@import 'aui_reset';
|
||||
@import 'base';
|
||||
@import 'utils';
|
||||
@import 'overlay/overlay';
|
||||
@@ -54,6 +52,7 @@
|
||||
@import 'chat';
|
||||
@import 'ringing/ringing';
|
||||
@import 'welcome_page';
|
||||
@import 'welcome_page_content';
|
||||
@import 'toolbars';
|
||||
@import 'side_toolbar_container';
|
||||
@import 'jquery.contextMenu';
|
||||
@@ -64,7 +63,6 @@
|
||||
@import 'components/button-control';
|
||||
@import 'components/input-control';
|
||||
@import 'components/input-slider';
|
||||
@import "modals/invite/invite";
|
||||
@import "connection-info";
|
||||
@import 'aui-components/dropdown';
|
||||
@import '404';
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
.dialog {
|
||||
visibility: visible;
|
||||
box-sizing: border-box;
|
||||
height: auto;
|
||||
min-height: 131px;
|
||||
overflow: visible;
|
||||
visibility: visible;
|
||||
width: 400px;
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: $auiDialogColor;
|
||||
@@ -10,10 +14,27 @@
|
||||
|
||||
&-icon {
|
||||
color: $auiDialogColor;
|
||||
text-indent: -999em;
|
||||
|
||||
&-small {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
|
||||
&:before {
|
||||
color: inherit;
|
||||
font-family: "FontAwesome";
|
||||
font-size: 16px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
left: 0;
|
||||
line-height: 1;
|
||||
margin-top: -8px;
|
||||
position: absolute;
|
||||
text-indent: 0;
|
||||
speak: none;
|
||||
top: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +43,10 @@
|
||||
right: 20px;
|
||||
position: absolute;
|
||||
top: -49px;
|
||||
|
||||
&:before {
|
||||
content: "\f00d";
|
||||
}
|
||||
}
|
||||
|
||||
&-dialog2 {
|
||||
@@ -31,8 +56,16 @@
|
||||
}
|
||||
|
||||
&-header {
|
||||
height: em(58, 12);
|
||||
border-bottom: 1px solid $auiBorderColor;
|
||||
border-radius: 5px 5px 0 0;
|
||||
box-sizing: border-box;
|
||||
color: #333;
|
||||
display: table;
|
||||
font-weight: normal;
|
||||
height: em(58, 12);
|
||||
margin-top: -69px;
|
||||
padding: 0 20px;
|
||||
width: 100%;
|
||||
|
||||
h2 {
|
||||
font-size: em(20, 12);
|
||||
@@ -41,19 +74,40 @@
|
||||
}
|
||||
|
||||
&-main {
|
||||
display: table-cell;
|
||||
padding-right: 0;
|
||||
max-width: 400px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
&-footer {
|
||||
border-top: 1px solid $auiBorderColor;
|
||||
border-radius: 0 0 5px 5px;
|
||||
box-sizing: border-box;
|
||||
height: 51px;
|
||||
overflow: hidden;
|
||||
padding: 10px 20px;
|
||||
width: 100%;
|
||||
|
||||
&:empty {
|
||||
height: 5px;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
font-size: em(14, 12);
|
||||
min-height: 0;
|
||||
background-color: $auiDialogContentBg;
|
||||
background-color: $auiDialogBg;
|
||||
box-sizing: border-box;
|
||||
color: $auiDialogColor;
|
||||
font-size: em(14, 12);
|
||||
overflow: auto;
|
||||
max-height: 100%;
|
||||
padding: 20px;
|
||||
|
||||
p,span, h3 {
|
||||
font-weight: $labelFontWeight;
|
||||
@@ -72,13 +126,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
.input-control {
|
||||
background-color: $auiDialogContentBg;
|
||||
color: $auiDialogColor;
|
||||
}
|
||||
|
||||
.form-control:not(:last-child) {
|
||||
border-bottom: 1px solid $auiBorderColor;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 420px) {
|
||||
.aui-dialog2-small .aui-dialog2-content {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-dialog-form {
|
||||
color: $modalTextColor;
|
||||
margin-top: 5px !important;
|
||||
|
||||
.input-control {
|
||||
@@ -90,6 +154,14 @@
|
||||
&-error {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override Atlaskit dropdown styling when in a modal because the dropdown
|
||||
* backgrounds clash with the modal backgrounds.
|
||||
*/
|
||||
.htclLc[data-role=droplistContent] {
|
||||
border: 1px solid #455166;
|
||||
}
|
||||
}
|
||||
.modal-dialog-footer {
|
||||
font-size: $modalButtonFontSize;
|
||||
|
||||
@@ -36,13 +36,12 @@
|
||||
}
|
||||
|
||||
.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);
|
||||
background: rgba(255,255,255,0.3);
|
||||
border-radius: $borderRadius;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
.device-selection {
|
||||
color: $feedbackInputTextColor;
|
||||
|
||||
.device-selectors {
|
||||
font-size: 14px;
|
||||
|
||||
@@ -22,19 +20,15 @@
|
||||
|
||||
/* 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;
|
||||
background-color: #0E1624;
|
||||
border: 1px solid #455166;
|
||||
border-radius: 5px;
|
||||
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 {
|
||||
@@ -108,19 +102,21 @@
|
||||
.audio-output-preview {
|
||||
font-size: 14px;
|
||||
margin-top: 10px;
|
||||
|
||||
a {
|
||||
color: 4C9AFF;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.audio-input-preview {
|
||||
background: #f4f5f7;
|
||||
background: #7b7b7b;
|
||||
border-radius: 5px;
|
||||
height: 6px;
|
||||
|
||||
.audio-input-preview-level {
|
||||
background: #0052cc;
|
||||
background: #4C9AFF;
|
||||
border-radius: 5px;
|
||||
height: 100%;
|
||||
-webkit-transition: width .1s ease-in-out;
|
||||
|
||||
@@ -11,17 +11,11 @@
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Styles the loading element in the MultiSelectAutocomplete.
|
||||
*/
|
||||
.autocomplete-loading {
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
min-width: 260px;
|
||||
padding: 20px;
|
||||
.add-telephone-icon {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,16 +4,20 @@
|
||||
|
||||
.info-dialog-action-link {
|
||||
display: inline-block;
|
||||
line-height: 1.5em;
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.info-dialog-action-link:before {
|
||||
color: $linkFontColor;
|
||||
content: '\2022';
|
||||
font-size: 1.5em;
|
||||
padding: 0 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.info-dialog-action-link:first-child:before {
|
||||
@@ -22,6 +26,8 @@
|
||||
}
|
||||
|
||||
.info-dialog-action-links {
|
||||
font-weight: bold;
|
||||
margin-top: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -39,16 +45,33 @@
|
||||
|
||||
.info-dialog-column {
|
||||
margin-right: 10px;
|
||||
overflow: hidden;
|
||||
|
||||
a,
|
||||
a:active,
|
||||
a:focus,
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.info-dialog-conference-url {
|
||||
margin: 10px 0;
|
||||
max-width: 250px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
user-select: text;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.info-dialog-dial-in {
|
||||
white-space: nowrap;
|
||||
|
||||
.conference-id,
|
||||
.phone-number {
|
||||
user-select: text;
|
||||
}
|
||||
}
|
||||
|
||||
.info-dialog-icon {
|
||||
color: #6453C0;
|
||||
font-size: 16px;
|
||||
@@ -56,5 +79,63 @@
|
||||
|
||||
.info-dialog-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.info-password,
|
||||
.info-dialog-password,
|
||||
.info-password-form {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.info-password-field {
|
||||
margin-left: 2px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.info-password-none,
|
||||
.info-password-remote {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.info-password-input {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
color: inherit;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.info-password-local {
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.conference-id {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.dial-in-page {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 24px;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
|
||||
* {
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.dial-in-numbers-list {
|
||||
font-size: 24px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.dial-in-conference-id {
|
||||
text-align: center;
|
||||
width: 30%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Sets the default cursor the remove password link. The link doesn't use
|
||||
* the href attribute, so we need to set the cursor manually.
|
||||
*/
|
||||
#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;
|
||||
}
|
||||
|
||||
.is-disabled,
|
||||
.is-loading {
|
||||
.dial-in-numbers-trigger-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-control {
|
||||
padding: 0;
|
||||
|
||||
&__container {
|
||||
/**
|
||||
* Ensure contents display in a line and vertically centered.
|
||||
*/
|
||||
align-items: center;
|
||||
|
||||
button {
|
||||
font-size: $modalButtonFontSize;
|
||||
}
|
||||
}
|
||||
|
||||
&__input-container {
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
|
||||
.dropdown-button-trigger {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
@@ -42,10 +42,6 @@
|
||||
width: 55%;
|
||||
}
|
||||
|
||||
.speaker-stats-item:nth-child(even) {
|
||||
background: whitesmoke;
|
||||
}
|
||||
|
||||
.speaker-stats-item__name,
|
||||
.speaker-stats-item__time {
|
||||
overflow: hidden;
|
||||
|
||||
@@ -11,9 +11,16 @@
|
||||
}
|
||||
|
||||
#reloadProgressBar {
|
||||
width: 180px;
|
||||
background: #e9e9e9;
|
||||
border-radius: 3px;
|
||||
height: 5px;
|
||||
margin: 5px auto;
|
||||
> .aui-progress-indicator-value {
|
||||
overflow: hidden;
|
||||
width: 180px;
|
||||
|
||||
.progress-indicator-fill {
|
||||
background: $reloadProgressBarBg;
|
||||
height: 100%;
|
||||
transition: width .5s;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@ $sliderThumbBackground: #3572b0;
|
||||
/**
|
||||
* Buttons
|
||||
*/
|
||||
$buttonBackground: #f5f5f5;
|
||||
$buttonHoverBackground: #e9e9e9;
|
||||
$buttonBorder: #ccc;
|
||||
$buttonHoverBorder: #999;
|
||||
$buttonColor: #333;
|
||||
$buttonBackground: #44A5FF;
|
||||
$buttonHoverBackground: #2c4062;
|
||||
$buttonBorder: transparent;
|
||||
$buttonHoverBorder: transparent;
|
||||
$buttonColor: #eceef1;
|
||||
|
||||
$buttonLightBackground: #f5f5f5;
|
||||
$buttonLightHoverBackground: #e9e9e9;
|
||||
@@ -47,10 +47,10 @@ $reloadProgressBarBg: #0074E0;
|
||||
/**
|
||||
* Dialog colors
|
||||
**/
|
||||
$auiDialogColor: #333;
|
||||
$auiDialogBg: #f5f5f5;
|
||||
$auiDialogContentBg: $baseLight;
|
||||
$auiBorderColor: #ccc;
|
||||
$auiDialogColor: #eceef1;
|
||||
$auiDialogBg: #253858;
|
||||
$auiDialogContentBg: #344563;
|
||||
$auiBorderColor: #253858;
|
||||
$dialogTitleFontWeight: 400;
|
||||
$dialogErrorText: #344563;
|
||||
|
||||
@@ -58,7 +58,7 @@ $dialogErrorText: #344563;
|
||||
* Inlay colors
|
||||
**/
|
||||
$inlayColorBg: lighten($defaultBackground, 20%);
|
||||
$inlayBorderColor: lighten($auiDialogContentBg, 10%);
|
||||
$inlayBorderColor: lighten($baseLight, 10%);
|
||||
$inlayIconBg: #000;
|
||||
$inlayIconColor: #fff;
|
||||
$inlayFilmstripOnlyColor: #474747;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
width: auto;
|
||||
|
||||
&__title {
|
||||
border-bottom: 1px solid $auiBorderColor;
|
||||
border-bottom: 1px solid $inlayBorderColor;
|
||||
color: $unsupportedBrowserTitleColor;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.5px;
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
.unsupported-mobile-browser {
|
||||
background-color: #fff;
|
||||
height: 100vh;
|
||||
padding: 35px 0;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
width: 100vw;
|
||||
|
||||
a {
|
||||
text-decoration: none
|
||||
}
|
||||
|
||||
&__body {
|
||||
color: $unsupportedBrowserTextColor;
|
||||
margin: auto;
|
||||
max-width: 40em;
|
||||
padding: 35px 0 40px 0;
|
||||
text-align: center;
|
||||
width: 75%;
|
||||
|
||||
@@ -16,8 +22,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__text {
|
||||
font-size: 1.8em;
|
||||
&__text,
|
||||
.unsupported-dial-in {
|
||||
font-size: 1.2em;
|
||||
line-height: em(29px, 21px);
|
||||
margin-bottom: 0.65em;
|
||||
|
||||
@@ -39,20 +46,14 @@
|
||||
|
||||
&__button {
|
||||
border: 0;
|
||||
height: 42px;
|
||||
margin: 0 auto;
|
||||
height: 2.2857142857142856em;
|
||||
line-height: 2.2857142857142856em;
|
||||
margin: 18px auto 20px;
|
||||
max-width: 300px;
|
||||
width: 98%;
|
||||
@include border-radius(8px);
|
||||
width: auto;
|
||||
@include border-radius(3px);
|
||||
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;
|
||||
color: #505F79;
|
||||
|
||||
&:active {
|
||||
background-color: $unsupportedBrowserButtonBgColor;
|
||||
@@ -60,10 +61,29 @@
|
||||
|
||||
&_primary {
|
||||
background-color: $primaryUnsupportedBrowserButtonBgColor;
|
||||
color: #FFFFFF;
|
||||
|
||||
&:active {
|
||||
background-color: $primaryUnsupportedBrowserButtonBgColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.unsupported-dial-in {
|
||||
display: none;
|
||||
|
||||
&.has-numbers {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.dial-in-numbers-list {
|
||||
color: $unsupportedBrowserTextColor;
|
||||
}
|
||||
|
||||
.dial-in-numbers-body {
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
19
debian/jitsi-meet-prosody.postinst
vendored
@@ -112,23 +112,18 @@ case "$1" in
|
||||
fi
|
||||
|
||||
if [ ! -f /var/lib/prosody/$JVB_HOSTNAME.crt ]; then
|
||||
HOST="$( (hostname -s; echo localhost) | head -n 1)"
|
||||
DOMAIN="$( (hostname -d; echo localdomain) | head -n 1)"
|
||||
openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj \
|
||||
"/O=$DOMAIN/OU=$HOST/CN=$JVB_HOSTNAME/emailAddress=webmaster@$HOST.$DOMAIN" \
|
||||
-keyout /var/lib/prosody/$JVB_HOSTNAME.key \
|
||||
-out /var/lib/prosody/$JVB_HOSTNAME.crt
|
||||
# prosodyctl takes care for the permissions
|
||||
# echo for using all default values
|
||||
echo | prosodyctl cert generate $JVB_HOSTNAME
|
||||
|
||||
ln -sf /var/lib/prosody/$JVB_HOSTNAME.key /etc/prosody/certs/$JVB_HOSTNAME.key
|
||||
ln -sf /var/lib/prosody/$JVB_HOSTNAME.crt /etc/prosody/certs/$JVB_HOSTNAME.crt
|
||||
fi
|
||||
|
||||
if [ ! -f /var/lib/prosody/$JICOFO_AUTH_DOMAIN.crt ]; then
|
||||
HOST="$( (hostname -s; echo localhost) | head -n 1)"
|
||||
DOMAIN="$( (hostname -d; echo localdomain) | head -n 1)"
|
||||
openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj \
|
||||
"/O=$DOMAIN/OU=$HOST/CN=$JICOFO_AUTH_DOMAIN/emailAddress=webmaster@$HOST.$DOMAIN" \
|
||||
-keyout /var/lib/prosody/$JICOFO_AUTH_DOMAIN.key \
|
||||
-out /var/lib/prosody/$JICOFO_AUTH_DOMAIN.crt
|
||||
# prosodyctl takes care for the permissions
|
||||
# echo for using all default values
|
||||
echo | prosodyctl cert generate $JICOFO_AUTH_DOMAIN
|
||||
|
||||
AUTH_KEY_FILE="/etc/prosody/certs/$JICOFO_AUTH_DOMAIN.key"
|
||||
AUTH_CRT_FILE="/etc/prosody/certs/$JICOFO_AUTH_DOMAIN.crt"
|
||||
|
||||
24
debian/jitsi-meet.README.source
vendored
@@ -1,24 +0,0 @@
|
||||
jitsi-meet for Debian
|
||||
---------------------
|
||||
|
||||
The jitsi-meet package is built from the sources of Jitsi Meet.
|
||||
|
||||
Jitsi Meet is downloaded from https://github.com/jitsi/jitsi-meet and the git files are removed. you can recreate the source with 'git clone https://github.com/jitsi/jitsi-meet.git'.
|
||||
Use something like the script below to update from Git
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
VERSION=1.0.1
|
||||
|
||||
echo "*.min.js export-ignore" > .gitattributes
|
||||
echo "jquery-2.1.1.* export-ignore" >> .gitattributes
|
||||
echo "jquery-ui.js export-ignore" >> .gitattributes
|
||||
echo ".gitignore export-ignore" >> .gitattributes
|
||||
|
||||
sed -i "s/1.0.1/$VERSION/g" debian/changelog
|
||||
|
||||
git archive --worktree-attributes --format tar --prefix jitsi-meet-$VERSION/ -o ../jitsi-meet_${VERSION}.orig.tar master
|
||||
tar --transform "s,^,jitsi-meet-$VERSION/," -rf ../jitsi-meet_${VERSION}.orig.tar
|
||||
cd ..
|
||||
|
||||
bzip2 jitsi-meet_${VERSION}.orig.tar
|
||||
22
debian/patches/jquery-package
vendored
@@ -1,22 +0,0 @@
|
||||
Description: Update the used js files for jquery to generic ones, to be able to use local system installed version (through symlinks).
|
||||
Index: jitsi-meet/index.html
|
||||
===================================================================
|
||||
--- jitsi-meet.orig/index.html
|
||||
+++ jitsi-meet/index.html
|
||||
@@ -10,13 +10,13 @@
|
||||
<meta itemprop="description" content="Join a WebRTC video conference powered by the Jitsi Videobridge"/>
|
||||
<meta itemprop="image" content="/images/jitsilogo.png"/>
|
||||
<script src="https://api.callstats.io/static/callstats.min.js"></script>
|
||||
- <script src="libs/jquery-2.1.1.min.js"></script>
|
||||
+ <script src="libs/jquery.min.js"></script>
|
||||
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsSHA/1.5.0/sha.js"></script>
|
||||
<script src="config.js?v=11"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
|
||||
<script src="libs/strophe/strophe.min.js?v=2"></script>
|
||||
<script src="libs/strophe/strophe.disco.min.js?v=1"></script>
|
||||
<script src="libs/strophe/strophe.caps.jsonly.min.js?v=1"></script>
|
||||
- <script src="libs/jquery-ui.js"></script>
|
||||
+ <script src="libs/jquery-ui.min.js"></script>
|
||||
<script src="libs/tooltip.js?v=1"></script><!-- bootstrap tooltip lib -->
|
||||
<script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
|
||||
- <script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
|
||||
1
debian/patches/series
vendored
@@ -1 +0,0 @@
|
||||
jquery-package
|
||||
@@ -2,11 +2,12 @@
|
||||
1. Go to https://icomoon.io/app/
|
||||
2. Go to "Manage Projects" from the menu on the top left.
|
||||
3. Use "Import project" and select <code>fonts/selection.json</code> from Jitsi Meet.
|
||||
4. Import icons (e.g. svg files) using the "import items" button.
|
||||
5. Go to "generate font" and make sure the identifiers for the new icons are correct.
|
||||
6. Download the result in a zip file using the "download" button.
|
||||
7. Copy <code>selection.json</code> and <code>fonts/jitsi.*</code> from the zip file to <code>fonts/</code> in Jitsi Meet
|
||||
8. Copy the class for the new icon from <code>style.css</code> in the zip file to <code>css/font.css</code> in Jitsi Meet (do *not* copy the whole file)
|
||||
4. Click "load".
|
||||
5. Add the new icons using the "Add icons from library" button...
|
||||
6. Go to "generate font" and make sure the identifiers for the new icons are correct.
|
||||
7. Download the result in a zip file using the "download" button.
|
||||
8. Copy <code>selection.json</code> and <code>fonts/jitsi.*</code> from the zip file to <code>fonts/</code> in Jitsi Meet
|
||||
9. Copy the class for the new icon from <code>style.css</code> in the zip file to <code>css/_font.scss</code> in Jitsi Meet (do *not* copy the whole file)
|
||||
10. Copy the <code>selection.json</code> file to <code>react/features/base/font-icons</code> overwriting <code>jitsi.json</code>
|
||||
|
||||
Sample commit: https://github.com/jitsi/jitsi-meet/commit/68bc819b89aec12364fcf07b81efa83a1900eed6
|
||||
|
||||
|
||||
58
doc/api.md
@@ -27,6 +27,7 @@ Its constructor gets a number of options:
|
||||
* **interfaceConfigOverwrite**: (optional) JS object with overrides for options defined in [interface_config.js].
|
||||
* **noSSL**: (optional, defaults to true) Boolean indicating if the server should be contacted using HTTP or HTTPS.
|
||||
* **jwt**: (optional) [JWT](https://jwt.io/) token.
|
||||
* **onload**: (optional) handler for the iframe onload event.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -140,18 +141,33 @@ The `event` parameter is a String object with the name of the event.
|
||||
The `listener` parameter is a Function object with one argument that will be notified when the event occurs with data related to the event.
|
||||
|
||||
The following events are currently supported:
|
||||
* **avatarChanged** - event notifications about avatar
|
||||
changes. The listener will receive an object with the following structure:
|
||||
```javascript
|
||||
{
|
||||
"id": id, // the id of the participant that changed his avatar.
|
||||
"avatarURL": avatarURL // the new avatar URL.
|
||||
}
|
||||
```
|
||||
|
||||
* **audioAvailabilityChanged** - event notifications about audio availability status changes. The listener will receive an object with the following structure:
|
||||
```javascript
|
||||
{
|
||||
"available": available // new available status - boolean
|
||||
"available": available // new available status - boolean
|
||||
}
|
||||
```
|
||||
|
||||
* **audioMuteStatusChanged** - event notifications about audio mute status changes. The listener will receive an object with the following structure:
|
||||
```javascript
|
||||
{
|
||||
"muted": muted // new muted status - boolean
|
||||
"muted": muted // new muted status - boolean
|
||||
}
|
||||
```
|
||||
|
||||
* **screenSharingStatusChanged** - receives event notifications about turning on/off the local user screen sharing. The listener will receive object with the following structure:
|
||||
```javascript
|
||||
{
|
||||
"on": on //whether screen sharing is on
|
||||
}
|
||||
```
|
||||
|
||||
@@ -159,9 +175,9 @@ The following events are currently supported:
|
||||
messages. The listener will receive an object with the following structure:
|
||||
```javascript
|
||||
{
|
||||
"from": from, // JID of the user that sent the message
|
||||
"nick": nick, // the nickname of the user that sent the message
|
||||
"message": txt // the text of the message
|
||||
"from": from, // The id of the user that sent the message
|
||||
"nick": nick, // the nickname of the user that sent the message
|
||||
"message": txt // the text of the message
|
||||
}
|
||||
```
|
||||
|
||||
@@ -169,7 +185,7 @@ messages. The listener will receive an object with the following structure:
|
||||
messages. The listener will receive an object with the following structure:
|
||||
```javascript
|
||||
{
|
||||
"message": txt // the text of the message
|
||||
"message": txt // the text of the message
|
||||
}
|
||||
```
|
||||
|
||||
@@ -177,50 +193,54 @@ messages. The listener will receive an object with the following structure:
|
||||
changes. The listener will receive an object with the following structure:
|
||||
```javascript
|
||||
{
|
||||
"jid": jid, // the JID of the participant that changed his display name
|
||||
"displayname": displayName // the new display name
|
||||
"id": id, // the id of the participant that changed his display name
|
||||
"displayname": displayName // the new display name
|
||||
}
|
||||
```
|
||||
|
||||
* **participantJoined** - event notifications about new participants who join the room. The listener will receive an object with the following structure:
|
||||
```javascript
|
||||
{
|
||||
"jid": jid // the JID of the participant
|
||||
"id": id, // the id of the participant
|
||||
"displayName": displayName // the display name of the participant
|
||||
}
|
||||
```
|
||||
|
||||
* **participantLeft** - event notifications about participants that leave the room. The listener will receive an object with the following structure:
|
||||
```javascript
|
||||
{
|
||||
"jid": jid // the JID of the participant
|
||||
"id": id // the id of the participant
|
||||
}
|
||||
```
|
||||
|
||||
* **videoConferenceJoined** - event notifications fired when the local user has joined the video conference. The listener will receive an object with the following structure:
|
||||
```javascript
|
||||
{
|
||||
"roomName": room // the room name of the conference
|
||||
"roomName": room, // the room name of the conference
|
||||
"id": id, // the id of the local participant
|
||||
"displayName": displayName, // the display name of the local participant
|
||||
"avatarURL": avatarURL // the avatar URL of the local participant
|
||||
}
|
||||
```
|
||||
|
||||
* **videoConferenceLeft** - event notifications fired when the local user has left the video conference. The listener will receive an object with the following structure:
|
||||
```javascript
|
||||
{
|
||||
"roomName": room // the room name of the conference
|
||||
"roomName": room // the room name of the conference
|
||||
}
|
||||
```
|
||||
|
||||
* **videoAvailabilityChanged** - event notifications about video availability status changes. The listener will receive an object with the following structure:
|
||||
```javascript
|
||||
{
|
||||
"available": available // new available status - boolean
|
||||
"available": available // new available status - boolean
|
||||
}
|
||||
```
|
||||
|
||||
* **videoMuteStatusChanged** - event notifications about video mute status changes. The listener will receive an object with the following structure:
|
||||
```javascript
|
||||
{
|
||||
"muted": muted // new muted status - boolean
|
||||
"muted": muted // new muted status - boolean
|
||||
}
|
||||
```
|
||||
|
||||
@@ -264,6 +284,16 @@ You can get the number of participants in the conference with the following API
|
||||
var numberOfParticipants = api.getNumberOfParticipants();
|
||||
```
|
||||
|
||||
You can get the avatar URL of a participant in the conference with the following API function:
|
||||
```javascript
|
||||
var avatarURL = api.getAvatarURL(participantId);
|
||||
```
|
||||
|
||||
You can get the display name of a participant in the conference with the following API function:
|
||||
```javascript
|
||||
var displayName = api.getDisplayName(participantId);
|
||||
```
|
||||
|
||||
You can get the iframe HTML element where Jitsi Meet is loaded with the following API function:
|
||||
```javascript
|
||||
var iframe = api.getIFrame();
|
||||
|
||||
@@ -45,7 +45,7 @@ modules_enabled = {
|
||||
-- Not essential, but recommended
|
||||
"private"; -- Private XML storage (for room bookmarks, etc.)
|
||||
"vcard"; -- Allow users to set vCards
|
||||
|
||||
|
||||
-- These are commented by default as they have a performance impact
|
||||
--"privacy"; -- Support privacy lists
|
||||
"compression"; -- Stream compression (requires the lua-zlib package installed)
|
||||
@@ -181,6 +181,13 @@ VirtualHost "jitsi.example.com"
|
||||
|
||||
c2s_require_encryption = false
|
||||
|
||||
VirtualHost "auth.jitsi.example.com"
|
||||
ssl = {
|
||||
key = "/var/lib/prosody/auth.jitsi.example.com.key";
|
||||
certificate = "/var/lib/prosody/auth.jitsi.example.com.crt";
|
||||
}
|
||||
authentication = "internal_plain"
|
||||
|
||||
------ Components ------
|
||||
-- You can specify components to add hosts that provide special services,
|
||||
-- like multi-user conferences, and transports.
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
# Server Installation for Jitsi Meet
|
||||
|
||||
|
||||
:warning: **WARNING:** Manual installation is not recommended. We recommend following the [quick-install](https://github.com/jitsi/jitsi-meet/blob/master/doc/quick-install.md) document. The current document describes the steps that are needed to install a working deployment, but steps are easy to mess up, and the debian packages are more up-to-date, where this document sometimes is not updated to latest changes.
|
||||
|
||||
|
||||
|
||||
This describes configuring a server `jitsi.example.com` running Debian or a Debian Derivative. You will need to
|
||||
change references to that to match your host, and generate some passwords for
|
||||
`YOURSECRET1`, `YOURSECRET2` and `YOURSECRET3`.
|
||||
@@ -60,6 +65,10 @@ VirtualHost "jitsi.example.com"
|
||||
- add domain with authentication for conference focus user:
|
||||
```
|
||||
VirtualHost "auth.jitsi.example.com"
|
||||
ssl = {
|
||||
key = "/var/lib/prosody/auth.jitsi.example.com.key";
|
||||
certificate = "/var/lib/prosody/auth.jitsi.example.com.crt";
|
||||
}
|
||||
authentication = "internal_plain"
|
||||
```
|
||||
- add focus user to server admins:
|
||||
@@ -83,8 +92,16 @@ ln -s /etc/prosody/conf.avail/jitsi.example.com.cfg.lua /etc/prosody/conf.d/jits
|
||||
Generate certs for the domain:
|
||||
```sh
|
||||
prosodyctl cert generate jitsi.example.com
|
||||
prosodyctl cert generate auth.jitsi.example.com
|
||||
```
|
||||
|
||||
Add auth.jitsi.example.com to the trusted certificates on the local machine:
|
||||
```sh
|
||||
ln -sf /var/lib/prosody/auth.jitsi.example.com.crt /usr/local/share/ca-certificates/auth.jitsi.example.com.crt
|
||||
update-ca-certificates -f
|
||||
```
|
||||
Note that the `-f` flag is necessary if there are symlinks left from a previous installation.
|
||||
|
||||
Create conference focus user:
|
||||
```sh
|
||||
prosodyctl register focus auth.jitsi.example.com YOURSECRET3
|
||||
|
||||
@@ -84,7 +84,7 @@ Enjoy!
|
||||
## Uninstall
|
||||
|
||||
```sh
|
||||
apt-get purge jigasi jitsi-meet jitsi-meet-web-config jitsi-meet-web jicofo jitsi-videobridge
|
||||
apt-get purge jigasi jitsi-meet jitsi-meet-web-config jitsi-meet-prosody jitsi-meet-web jicofo jitsi-videobridge
|
||||
```
|
||||
|
||||
Sometimes the following packages will fail to uninstall properly:
|
||||
|
||||
4678
flow-typed/npm/lodash_v4.x.x.js
vendored
48
flow-typed/npm/react-redux_v5.x.x.js
vendored
@@ -1,8 +1,5 @@
|
||||
// flow-typed signature: 4e93c65cedbfbf7f1ab3fe4e800943d3
|
||||
// flow-typed version: 9092387fd2/react-redux_v5.x.x/flow_>=v0.53.x <=v0.53.x
|
||||
|
||||
// flow-typed signature: 8db7b853f57c51094bf0ab8b2650fd9c
|
||||
// flow-typed version: ab8db5f14d/react-redux_v5.x.x/flow_>=v0.30.x
|
||||
// flow-typed signature: 59b0c4be0e1408f21e2446be96c79804
|
||||
// flow-typed version: 9092387fd2/react-redux_v5.x.x/flow_>=v0.54.x
|
||||
|
||||
import type { Dispatch, Store } from "redux";
|
||||
|
||||
@@ -34,6 +31,22 @@ declare module "react-redux" {
|
||||
|
||||
declare type Context = { store: Store<*, *> };
|
||||
|
||||
declare type ComponentWithDefaultProps<DP: {}, P: {}, CP: P> = Class<
|
||||
React$Component<CP>
|
||||
> & { defaultProps: DP };
|
||||
|
||||
declare class ConnectedComponentWithDefaultProps<
|
||||
OP,
|
||||
DP,
|
||||
CP
|
||||
> extends React$Component<OP> {
|
||||
static defaultProps: DP, // <= workaround for https://github.com/facebook/flow/issues/4644
|
||||
static WrappedComponent: Class<React$Component<CP>>,
|
||||
getWrappedInstance(): React$Component<CP>,
|
||||
props: OP,
|
||||
state: void
|
||||
}
|
||||
|
||||
declare class ConnectedComponent<OP, P> extends React$Component<OP> {
|
||||
static WrappedComponent: Class<React$Component<P>>,
|
||||
getWrappedInstance(): React$Component<P>,
|
||||
@@ -41,13 +54,18 @@ declare module "react-redux" {
|
||||
state: void
|
||||
}
|
||||
|
||||
declare type ConnectedComponentWithDefaultPropsClass<OP, DP, CP> = Class<
|
||||
ConnectedComponentWithDefaultProps<OP, DP, CP>
|
||||
>;
|
||||
|
||||
declare type ConnectedComponentClass<OP, P> = Class<
|
||||
ConnectedComponent<OP, P>
|
||||
>;
|
||||
|
||||
declare type Connector<OP, P> = (
|
||||
component: React$ComponentType<P>
|
||||
) => ConnectedComponentClass<OP, P>;
|
||||
declare type Connector<OP, P> = (<DP: {}, CP: {}>(
|
||||
component: ComponentWithDefaultProps<DP, P, CP>
|
||||
) => ConnectedComponentWithDefaultPropsClass<OP, DP, CP>) &
|
||||
((component: React$ComponentType<P>) => ConnectedComponentClass<OP, P>);
|
||||
|
||||
declare class Provider<S, A> extends React$Component<{
|
||||
store: Store<S, A>,
|
||||
@@ -77,12 +95,12 @@ declare module "react-redux" {
|
||||
options: ConnectOptions
|
||||
): Connector<OP, $Supertype<{ dispatch: Dispatch<A> } & OP>>;
|
||||
|
||||
declare function connect<S, A, OP, SP>(
|
||||
mapStateToProps: MapStateToProps<S, OP, SP>,
|
||||
mapDispatchToProps: Null,
|
||||
mergeProps: Null,
|
||||
options?: ConnectOptions
|
||||
): Connector<OP, $Supertype<SP & { dispatch: Dispatch<A> } & OP>>;
|
||||
// declare function connect<S, A, OP, SP>(
|
||||
// mapStateToProps: MapStateToProps<S, OP, SP>,
|
||||
// mapDispatchToProps: Null,
|
||||
// mergeProps: Null,
|
||||
// options?: ConnectOptions
|
||||
// ): Connector<OP, $Supertype<SP & { dispatch: Dispatch<A> } & OP>>;
|
||||
|
||||
declare function connect<A, OP, DP>(
|
||||
mapStateToProps: Null,
|
||||
@@ -93,7 +111,7 @@ declare module "react-redux" {
|
||||
|
||||
declare function connect<S, A, OP, SP, DP>(
|
||||
mapStateToProps: MapStateToProps<S, OP, SP>,
|
||||
mapDispatchToProps: MapDispatchToProps<A, OP, DP>,
|
||||
mapDispatchToProps: MapDispatchToProps<A, OP, DP> | Null,
|
||||
mergeProps: Null,
|
||||
options?: ConnectOptions
|
||||
): Connector<OP, $Supertype<SP & DP & OP>>;
|
||||
|
||||
58
flow-typed/npm/redux_v3.x.x.js
vendored
@@ -1,5 +1,5 @@
|
||||
// flow-typed signature: 33b83b6284653250e74578cf4dbe6124
|
||||
// flow-typed version: e282e4128f/redux_v3.x.x/flow_>=v0.33.x
|
||||
// flow-typed signature: ec7daead5cb4fec5ab25fedbedef29e8
|
||||
// flow-typed version: 2c04631d20/redux_v3.x.x/flow_>=v0.55.x
|
||||
|
||||
declare module 'redux' {
|
||||
|
||||
@@ -55,55 +55,5 @@ declare module 'redux' {
|
||||
|
||||
declare export function combineReducers<O: Object, A>(reducers: O): CombinedReducer<$ObjMap<O, <S>(r: Reducer<S, any>) => S>, A>;
|
||||
|
||||
declare export function compose<A, B>(ab: (a: A) => B): (a: A) => B
|
||||
declare export function compose<A, B, C>(
|
||||
bc: (b: B) => C,
|
||||
ab: (a: A) => B
|
||||
): (a: A) => C
|
||||
declare export function compose<A, B, C, D>(
|
||||
cd: (c: C) => D,
|
||||
bc: (b: B) => C,
|
||||
ab: (a: A) => B
|
||||
): (a: A) => D
|
||||
declare export function compose<A, B, C, D, E>(
|
||||
de: (d: D) => E,
|
||||
cd: (c: C) => D,
|
||||
bc: (b: B) => C,
|
||||
ab: (a: A) => B
|
||||
): (a: A) => E
|
||||
declare export function compose<A, B, C, D, E, F>(
|
||||
ef: (e: E) => F,
|
||||
de: (d: D) => E,
|
||||
cd: (c: C) => D,
|
||||
bc: (b: B) => C,
|
||||
ab: (a: A) => B
|
||||
): (a: A) => F
|
||||
declare export function compose<A, B, C, D, E, F, G>(
|
||||
fg: (f: F) => G,
|
||||
ef: (e: E) => F,
|
||||
de: (d: D) => E,
|
||||
cd: (c: C) => D,
|
||||
bc: (b: B) => C,
|
||||
ab: (a: A) => B
|
||||
): (a: A) => G
|
||||
declare export function compose<A, B, C, D, E, F, G, H>(
|
||||
gh: (g: G) => H,
|
||||
fg: (f: F) => G,
|
||||
ef: (e: E) => F,
|
||||
de: (d: D) => E,
|
||||
cd: (c: C) => D,
|
||||
bc: (b: B) => C,
|
||||
ab: (a: A) => B
|
||||
): (a: A) => H
|
||||
declare export function compose<A, B, C, D, E, F, G, H, I>(
|
||||
hi: (h: H) => I,
|
||||
gh: (g: G) => H,
|
||||
fg: (f: F) => G,
|
||||
ef: (e: E) => F,
|
||||
de: (d: D) => E,
|
||||
cd: (c: C) => D,
|
||||
bc: (b: B) => C,
|
||||
ab: (a: A) => B
|
||||
): (a: A) => I
|
||||
|
||||
}
|
||||
declare export var compose: $Compose;
|
||||
}
|
||||
BIN
fonts/jitsi.eot
@@ -11,11 +11,19 @@
|
||||
<glyph unicode="" glyph-name="add" d="M810 470h-256v-256h-84v256h-256v84h256v256h84v-256h256v-84z" />
|
||||
<glyph unicode="" glyph-name="bluetooth" d="M550 328l-80 82v-162zM470 776v-162l80 82zM670 696l-184-184 184-184-244-242h-42v324l-196-196-60 60 238 238-238 238 60 60 196-196v324h42zM834 738c40-64 62-142 62-222 0-84-24-160-66-226l-50 50c26 52 42 110 42 172s-16 120-42 172zM608 512l98 98c12-30 20-64 20-98s-8-70-20-100z" />
|
||||
<glyph unicode="" glyph-name="headset" d="M512 982c212 0 384-172 384-384v-300c0-70-58-128-128-128h-128v342h170v86c0 166-132 298-298 298s-298-132-298-298v-86h170v-342h-128c-70 0-128 58-128 128v300c0 212 172 384 384 384z" />
|
||||
<glyph unicode="" glyph-name="navigate_before" d="M658 708l-196-196 196-196-60-60-256 256 256 256z" />
|
||||
<glyph unicode="" glyph-name="navigate_next" d="M426 768l256-256-256-256-60 60 196 196-196 196z" />
|
||||
<glyph unicode="" glyph-name="timer" d="M512 170c166 0 298 134 298 300s-132 298-298 298-298-132-298-298 132-300 298-300zM812 708c52-66 84-148 84-238 0-212-172-384-384-384s-384 172-384 384 172 384 384 384c90 0 174-34 240-86l60 62c22-18 42-38 60-60zM470 426v256h84v-256h-84zM640 982v-86h-256v86h256z" />
|
||||
<glyph unicode="" glyph-name="arrow_back" d="M854 554v-84h-520l238-240-60-60-342 342 342 342 60-60-238-240h520z" />
|
||||
<glyph unicode="" glyph-name="menu" d="M128 768h768v-86h-768v86zM128 470v84h768v-84h-768zM128 256v86h768v-86h-768z" />
|
||||
<glyph unicode="" glyph-name="thumb-menu" d="M512 342c46 0 86-40 86-86s-40-86-86-86-86 40-86 86 40 86 86 86zM512 598c46 0 86-40 86-86s-40-86-86-86-86 40-86 86 40 86 86 86zM512 682c-46 0-86 40-86 86s40 86 86 86 86-40 86-86-40-86-86-86z" />
|
||||
<glyph unicode="" glyph-name="presentation" horiz-adv-x="1088" d="M952.495 1019.065h-818.689c-72.81 0-132.183-60.63-132.183-135.162v-750.719c0-74.473 59.372-135.101 132.183-135.101h818.686c72.936 0 132.314 60.625 132.314 135.101v750.722c0.003 74.532-59.378 135.159-132.311 135.159zM946.346 139.651h-806.14v737.822h806.015l0.126-737.822zM685.753 738.544h216.911v-566.758h-216.911v566.758zM428.672 610.002h216.911v-438.216h-216.911v438.216zM172.339 481.46h216.161v-309.677h-216.161v309.677z" />
|
||||
<glyph unicode="" glyph-name="recDisable" horiz-adv-x="1140" d="M1123.444 1003.015c-23.593 26.481-64.131 28.989-90.74 5.395l-1008.269-893.436c-26.609-23.468-28.991-64.131-5.46-90.676 12.674-14.306 30.308-21.649 48.126-21.649 15.123 0 30.372 5.401 42.544 16.195l130.045 115.22c90.743-81.844 210.569-132.165 342.473-132.101 282.816 0.061 510.913 227.969 511.287 510.972 0.126 109.934-34.682 211.367-93.499 294.72l118.088 104.625c26.483 23.526 28.997 64.129 5.404 90.735zM944.422 513.818c0.128-200.922-161.896-363.201-362.509-362.952-87.56 0.123-167.573 31.151-230.061 82.569l331.277 293.509v-73.176c1.071-60.993 32.696-92.18 94.944-93.692 61.997 1.512 93.686 32.763 95.131 93.756v41.096h-72.227v-47.499c0.251-4.642-0.564-10.607-2.511-17.949-1.25-3.261-3.448-6.020-6.525-8.093-3.197-2.572-7.845-3.828-13.868-3.828-10.543 0.31-17.132 4.268-19.827 11.921-1.068 3.512-1.947 6.905-2.508 10.163-0.254 2.887-0.377 5.532-0.377 7.786v143.511l42.477 37.634c0.215-0.432 0.452-0.851 0.63-1.303 1.947-6.467 2.762-12.799 2.511-19.076v-36.772h72.227v30.121c-0.246 31.245-9.086 54.699-26.363 70.447l40.711 36.069c35.787-56.055 56.803-122.585 56.867-194.244zM239.795 395.47c-12.613 37.023-19.827 76.557-19.827 117.913-0.19 200.236 161.584 362.009 361.945 362.135 56.853 0 110.313-13.302 158.133-36.398l117.846 104.421c-79.444 50.952-173.758 80.817-275.292 80.948-283.377 0.181-511.354-227.729-511.789-511.675-0.126-79.567 18.636-154.679 51.137-221.882l117.848 104.538zM388.576 690.020h-97.514v-249.057l72.23 64.070v0.689h0.815l117.72 104.418c0 0.564 0.123 0.94 0.123 1.509 0.753 53.898-30.369 80.069-93.374 78.37zM405.959 625.517c1.942-2.767 3.074-6.469 3.323-11.112 0.312-4.452 0.438-9.6 0.438-15.246 0.251-10.916-0.689-19.83-2.949-26.985-2.952-7.594-10.983-11.357-24.159-11.357h-19.325v74.043h15.31c7.842 0 13.865-0.683 18.072-2.19 4.397-1.573 7.468-3.953 9.29-7.153z" />
|
||||
<glyph unicode="" glyph-name="recEnable" horiz-adv-x="1142" d="M581.278 1025.708c284.857-0.19 514.807-230.517 514.427-514.997-0.378-285.047-230.073-514.553-514.869-514.615-284.541-0.062-515.311 230.517-514.933 514.422 0.439 285.936 230.009 515.439 515.375 515.19zM580.579 875.756c-201.764-0.123-364.666-163.032-364.478-364.663 0-202.018 162.524-364.735 364.478-364.984 202.018-0.316 365.174 163.030 365.048 365.423-0.252 201.767-163.156 364.35-365.048 364.224zM287.698 688.907h98.196c63.442 1.767 94.785-24.518 94.027-78.863 0.254-19.081-2.211-34.882-7.456-47.521-6.005-12.508-18.706-21.988-38.167-28.181v-0.819c28.373-6.259 43.031-23.573 43.981-51.946v-57.689c0-11.247 0.254-22.813 0.758-34.756 0.819-12.005 3.033-20.979 6.696-27.043h-71.846c-3.727 6.064-6.128 15.038-7.14 27.043-1.012 11.943-1.454 23.509-1.138 34.756v52.321c0 9.603-2.214 16.553-6.573 20.979-4.675 4.107-12.701 6.19-24.012 6.19h-14.599v-141.291h-72.73v326.82zM360.428 558.861h19.463c13.271 0 21.359 3.794 24.331 11.375 2.276 7.204 3.221 16.304 2.969 27.171 0 5.815-0.126 10.867-0.442 15.418-0.252 4.675-1.392 8.404-3.352 11.247-1.831 3.157-4.926 5.561-9.352 7.14-4.233 1.454-10.299 2.211-18.2 2.211h-15.418v-74.564zM498.372 688.907h162.082v-62.687h-89.35v-65.587h78.103v-62.685h-78.103v-73.11h92.822v-62.749h-165.557v326.818zM682.507 599.999c0.316 31.782 9.416 55.542 27.425 71.407 17.44 15.29 40.185 22.936 68.181 22.936 28.247 0 51.119-7.646 68.623-23 17.82-15.798 26.92-39.623 27.171-71.407v-30.333h-72.73v37.031c0.254 6.192-0.57 12.639-2.527 19.209-1.264 3.157-3.475 5.938-6.573 8.214-3.221 1.515-7.898 2.404-13.964 2.404-10.615-0.316-17.249-3.855-19.967-10.618-2.211-6.573-3.223-13.017-2.907-19.209v-161.956c0-2.273 0.126-4.865 0.38-7.772 0.568-3.411 1.454-6.824 2.527-10.233 2.717-7.775 9.352-11.756 19.967-12.007 6.067 0 10.744 1.261 13.964 3.791 3.098 2.15 5.309 4.867 6.573 8.216 1.96 7.33 2.782 13.33 2.527 18.007v47.837h72.73v-41.328c-1.451-61.547-33.364-93.015-95.794-94.469-62.685 1.454-94.53 32.922-95.607 94.343v148.937z" />
|
||||
<glyph unicode="" glyph-name="event_note" d="M598 426v-84h-300v84h300zM810 214v468h-596v-468h596zM810 896c46 0 86-40 86-86v-596c0-46-40-86-86-86h-596c-48 0-86 40-86 86v596c0 46 38 86 86 86h42v86h86v-86h340v86h86v-86h42zM726 598v-86h-428v86h428z" />
|
||||
<glyph unicode="" glyph-name="phone-talk" d="M640 512c0 70-58 128-128 128v86c118 0 214-96 214-214h-86zM810 512c0 166-132 298-298 298v86c212 0 384-172 384-384h-86zM854 362c24 0 42-18 42-42v-150c0-24-18-42-42-42-400 0-726 326-726 726 0 24 18 42 42 42h150c24 0 42-18 42-42 0-54 8-104 24-152 4-14 2-32-10-44l-94-94c62-122 162-220 282-282l94 94c12 12 30 14 44 10 48-16 98-24 152-24z" />
|
||||
<glyph unicode="" glyph-name="public" d="M764 282c56 60 90 142 90 230 0 142-88 266-214 316v-18c0-46-40-84-86-84h-84v-86c0-24-20-42-44-42h-84v-86h256c24 0 42-18 42-42v-128h42c38 0 70-26 82-60zM470 174v82c-46 0-86 40-86 86v42l-204 204c-6-24-10-50-10-76 0-174 132-318 300-338zM512 938c236 0 426-190 426-426s-190-426-426-426-426 190-426 426 190 426 426 426z" />
|
||||
<glyph unicode="" glyph-name="restore" d="M512 682h64v-180l150-90-32-52-182 110v212zM554 896c212 0 384-172 384-384s-172-384-384-384c-106 0-200 42-270 112l60 62c54-54 128-88 210-88 166 0 300 132 300 298s-134 298-300 298-298-132-298-298h128l-172-172-4 6-166 166h128c0 212 172 384 384 384z" />
|
||||
<glyph unicode="" glyph-name="avatar" d="M512 204c106 0 200 56 256 138-2 84-172 132-256 132-86 0-254-48-256-132 56-82 150-138 256-138zM512 810c-70 0-128-58-128-128s58-128 128-128 128 58 128 128-58 128-128 128zM512 938c236 0 426-190 426-426s-190-426-426-426-426 190-426 426 190 426 426 426z" />
|
||||
<glyph unicode="" glyph-name="download" d="M726 470h-128v170h-172v-170h-128l214-214zM826 596c110-8 198-100 198-212 0-118-96-214-214-214h-554c-142 0-256 114-256 256 0 132 100 240 228 254 54 102 160 174 284 174 156 0 284-110 314-258z" />
|
||||
<glyph unicode="" glyph-name="mic-camera-combined" d="M756.704 628.138l267.296 202.213v-635.075l-267.296 202.213v-191.923c0-12.085-11.296-21.863-25.216-21.863h-706.272c-13.92 0-25.216 9.777-25.216 21.863v612.25c0 12.085 11.296 21.863 25.216 21.863h706.272c13.92 0 25.216-9.777 25.216-21.863v-189.679zM371.338 376.228c47.817 0 86.529 40.232 86.529 89.811v184.835c0 49.651-38.713 89.883-86.529 89.883-47.788 0-86.515-40.232-86.515-89.883v-184.835c0-49.579 38.756-89.811 86.515-89.811v0zM356.754 314.070v-32.78h33.718v33.412c73.858 9.606 131.235 73.73 131.235 151.351v88.232h-30.636v-88.232c0-67.57-53.696-122.534-119.734-122.534-66.024 0-119.691 54.964-119.691 122.534v88.232h-30.636v-88.232c0-79.215 59.674-144.502 135.744-151.969v-0.014z" />
|
||||
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 20 KiB |
BIN
fonts/jitsi.ttf
BIN
fonts/jitsi.woff
@@ -1,6 +1,222 @@
|
||||
{
|
||||
"IcoMoonType": "selection",
|
||||
"icons": [
|
||||
{
|
||||
"icon": {
|
||||
"paths": [
|
||||
"M512 342h64v180l150 90-32 52-182-110v-212zM554 128c212 0 384 172 384 384s-172 384-384 384c-106 0-200-42-270-112l60-62c54 54 128 88 210 88 166 0 300-132 300-298s-134-298-300-298-298 132-298 298h128l-172 172-4-6-166-166h128c0-212 172-384 384-384z"
|
||||
],
|
||||
"attrs": [],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"tags": [
|
||||
"restore"
|
||||
],
|
||||
"defaultCode": 59571,
|
||||
"grid": 24
|
||||
},
|
||||
"attrs": [],
|
||||
"properties": {
|
||||
"ligatures": "history, restore",
|
||||
"id": 385,
|
||||
"order": 930,
|
||||
"prevSize": 24,
|
||||
"code": 59571,
|
||||
"name": "restore"
|
||||
},
|
||||
"setIdx": 0,
|
||||
"setId": 2,
|
||||
"iconIdx": 385
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
"paths": [
|
||||
"M426 256l256 256-256 256-60-60 196-196-196-196z"
|
||||
],
|
||||
"attrs": [],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"tags": [
|
||||
"navigate_next"
|
||||
],
|
||||
"defaultCode": 58377,
|
||||
"grid": 24
|
||||
},
|
||||
"attrs": [],
|
||||
"properties": {
|
||||
"ligatures": "chevron_right, navigate_next",
|
||||
"id": 153,
|
||||
"order": 927,
|
||||
"prevSize": 24,
|
||||
"code": 58377,
|
||||
"name": "navigate_next"
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 0
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
"paths": [
|
||||
"M128 256h768v86h-768v-86zM128 554v-84h768v84h-768zM128 768v-86h768v86h-768z"
|
||||
],
|
||||
"attrs": [],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"tags": [
|
||||
"menu"
|
||||
],
|
||||
"defaultCode": 58834,
|
||||
"grid": 24
|
||||
},
|
||||
"attrs": [],
|
||||
"properties": {
|
||||
"ligatures": "menu",
|
||||
"id": 489,
|
||||
"order": 926,
|
||||
"prevSize": 24,
|
||||
"code": 58834,
|
||||
"name": "menu"
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 1
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
"paths": [
|
||||
"M854 470v84h-520l238 240-60 60-342-342 342-342 60 60-238 240h520z"
|
||||
],
|
||||
"attrs": [],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"tags": [
|
||||
"arrow_back"
|
||||
],
|
||||
"defaultCode": 58820,
|
||||
"grid": 24
|
||||
},
|
||||
"attrs": [],
|
||||
"properties": {
|
||||
"ligatures": "arrow_back",
|
||||
"id": 45,
|
||||
"order": 924,
|
||||
"prevSize": 24,
|
||||
"code": 58820,
|
||||
"name": "arrow_back"
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 2
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
"paths": [
|
||||
"M658 316l-196 196 196 196-60 60-256-256 256-256z"
|
||||
],
|
||||
"attrs": [],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"tags": [
|
||||
"navigate_before"
|
||||
],
|
||||
"defaultCode": 58376,
|
||||
"grid": 24
|
||||
},
|
||||
"attrs": [],
|
||||
"properties": {
|
||||
"ligatures": "chevron_left, navigate_before",
|
||||
"id": 152,
|
||||
"order": 923,
|
||||
"prevSize": 24,
|
||||
"code": 58376,
|
||||
"name": "navigate_before"
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 3
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
"paths": [
|
||||
"M764 742c56-60 90-142 90-230 0-142-88-266-214-316v18c0 46-40 84-86 84h-84v86c0 24-20 42-44 42h-84v86h256c24 0 42 18 42 42v128h42c38 0 70 26 82 60zM470 850v-82c-46 0-86-40-86-86v-42l-204-204c-6 24-10 50-10 76 0 174 132 318 300 338zM512 86c236 0 426 190 426 426s-190 426-426 426-426-190-426-426 190-426 426-426z"
|
||||
],
|
||||
"attrs": [],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"tags": [
|
||||
"public"
|
||||
],
|
||||
"defaultCode": 59403,
|
||||
"grid": 24
|
||||
},
|
||||
"attrs": [],
|
||||
"properties": {
|
||||
"ligatures": "public",
|
||||
"id": 605,
|
||||
"order": 920,
|
||||
"prevSize": 24,
|
||||
"code": 59403,
|
||||
"name": "public"
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 4
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
"paths": [
|
||||
"M598 598v84h-300v-84h300zM810 810v-468h-596v468h596zM810 128c46 0 86 40 86 86v596c0 46-40 86-86 86h-596c-48 0-86-40-86-86v-596c0-46 38-86 86-86h42v-86h86v86h340v-86h86v86h42zM726 426v86h-428v-86h428z"
|
||||
],
|
||||
"attrs": [],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"tags": [
|
||||
"event_note"
|
||||
],
|
||||
"defaultCode": 58902,
|
||||
"grid": 24
|
||||
},
|
||||
"attrs": [],
|
||||
"properties": {
|
||||
"ligatures": "event_note",
|
||||
"id": 252,
|
||||
"order": 919,
|
||||
"prevSize": 24,
|
||||
"code": 58902,
|
||||
"name": "event_note"
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 5
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
"paths": [
|
||||
"M512 854c166 0 298-134 298-300s-132-298-298-298-298 132-298 298 132 300 298 300zM812 316c52 66 84 148 84 238 0 212-172 384-384 384s-384-172-384-384 172-384 384-384c90 0 174 34 240 86l60-62c22 18 42 38 60 60zM470 598v-256h84v256h-84zM640 42v86h-256v-86h256z"
|
||||
],
|
||||
"attrs": [],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"tags": [
|
||||
"timer"
|
||||
],
|
||||
"defaultCode": 58405,
|
||||
"grid": 24
|
||||
},
|
||||
"attrs": [],
|
||||
"properties": {
|
||||
"ligatures": "timer",
|
||||
"id": 760,
|
||||
"order": 928,
|
||||
"prevSize": 24,
|
||||
"code": 58405,
|
||||
"name": "timer"
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 6
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
"paths": [
|
||||
@@ -24,9 +240,9 @@
|
||||
"code": 57770,
|
||||
"name": "bluetooth"
|
||||
},
|
||||
"setIdx": 0,
|
||||
"setId": 2,
|
||||
"iconIdx": 79
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 7
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -51,9 +267,9 @@
|
||||
"code": 58128,
|
||||
"name": "headset"
|
||||
},
|
||||
"setIdx": 0,
|
||||
"setId": 2,
|
||||
"iconIdx": 376
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 8
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -78,9 +294,9 @@
|
||||
"code": 58909,
|
||||
"name": "phone-talk"
|
||||
},
|
||||
"setIdx": 0,
|
||||
"setId": 2,
|
||||
"iconIdx": 566
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 9
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -107,7 +323,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 40
|
||||
"iconIdx": 10
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -136,7 +352,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 41
|
||||
"iconIdx": 11
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -163,7 +379,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 42
|
||||
"iconIdx": 12
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -190,7 +406,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 43
|
||||
"iconIdx": 13
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -219,7 +435,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 0
|
||||
"iconIdx": 14
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -248,7 +464,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 1
|
||||
"iconIdx": 15
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -277,7 +493,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 2
|
||||
"iconIdx": 16
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -306,7 +522,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 3
|
||||
"iconIdx": 17
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -335,7 +551,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 4
|
||||
"iconIdx": 18
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -361,7 +577,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 5
|
||||
"iconIdx": 19
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -387,7 +603,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 6
|
||||
"iconIdx": 20
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -413,7 +629,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 7
|
||||
"iconIdx": 21
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -439,7 +655,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 8
|
||||
"iconIdx": 22
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -465,7 +681,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 9
|
||||
"iconIdx": 23
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -491,7 +707,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 10
|
||||
"iconIdx": 24
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -517,7 +733,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 11
|
||||
"iconIdx": 25
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -535,7 +751,7 @@
|
||||
"attrs": [],
|
||||
"properties": {
|
||||
"id": 10,
|
||||
"order": 900,
|
||||
"order": 922,
|
||||
"ligatures": "expand_less",
|
||||
"prevSize": 32,
|
||||
"code": 59679,
|
||||
@@ -543,7 +759,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 12
|
||||
"iconIdx": 26
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -569,7 +785,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 13
|
||||
"iconIdx": 27
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -595,7 +811,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 14
|
||||
"iconIdx": 28
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -621,7 +837,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 15
|
||||
"iconIdx": 29
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -647,7 +863,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 16
|
||||
"iconIdx": 30
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -673,7 +889,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 17
|
||||
"iconIdx": 31
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -699,7 +915,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 18
|
||||
"iconIdx": 32
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -725,7 +941,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 19
|
||||
"iconIdx": 33
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -751,7 +967,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 20
|
||||
"iconIdx": 34
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -777,7 +993,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 21
|
||||
"iconIdx": 35
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -803,7 +1019,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 22
|
||||
"iconIdx": 36
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -829,7 +1045,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 23
|
||||
"iconIdx": 37
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -855,7 +1071,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 24
|
||||
"iconIdx": 38
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -881,7 +1097,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 25
|
||||
"iconIdx": 39
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -907,7 +1123,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 26
|
||||
"iconIdx": 40
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -933,7 +1149,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 27
|
||||
"iconIdx": 41
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -959,7 +1175,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 28
|
||||
"iconIdx": 42
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -985,7 +1201,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 29
|
||||
"iconIdx": 43
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -1011,7 +1227,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 30
|
||||
"iconIdx": 44
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -1037,7 +1253,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 31
|
||||
"iconIdx": 45
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -1063,7 +1279,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 32
|
||||
"iconIdx": 46
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -1089,7 +1305,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 33
|
||||
"iconIdx": 47
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -1118,7 +1334,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 34
|
||||
"iconIdx": 48
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -1148,7 +1364,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 35
|
||||
"iconIdx": 49
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -1178,7 +1394,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 36
|
||||
"iconIdx": 50
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -1204,7 +1420,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 37
|
||||
"iconIdx": 51
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -1230,7 +1446,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 38
|
||||
"iconIdx": 52
|
||||
},
|
||||
{
|
||||
"icon": {
|
||||
@@ -1256,7 +1472,7 @@
|
||||
},
|
||||
"setIdx": 1,
|
||||
"setId": 1,
|
||||
"iconIdx": 39
|
||||
"iconIdx": 53
|
||||
}
|
||||
],
|
||||
"height": 1024,
|
||||
|
||||
BIN
images/calendar@2x.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
images/calendar@3x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
@@ -1,9 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="480" width="640" viewBox="0 0 640 480">
|
||||
<g stroke-width="1pt">
|
||||
<path fill="#006" d="M0 0h640v480H0z"/>
|
||||
<path d="M0 0v27.95L307.037 250h38.647v-27.95L38.647 0H0zm345.684 0v27.95L38.647 250H0v-27.95L307.037 0h38.647z" fill="#fff"/>
|
||||
<path d="M144.035 0v250h57.614V0h-57.615zM0 83.333v83.333h345.684V83.333H0z" fill="#fff"/>
|
||||
<path d="M0 100v50h345.684v-50H0zM155.558 0v250h34.568V0h-34.568zM0 250l115.228-83.334h25.765L25.765 250H0zM0 0l115.228 83.333H89.463L0 18.633V0zm204.69 83.333L319.92 0h25.764L230.456 83.333H204.69zM345.685 250l-115.228-83.334h25.765l89.464 64.7V250z" fill="#c00"/>
|
||||
<path d="M299.762 392.523l-43.653 3.795 6.013 43.406-30.187-31.764-30.186 31.764 6.014-43.406-43.653-3.795 37.68-22.364-24.244-36.495 40.97 15.514 13.42-41.713 13.42 41.712 40.97-15.515-24.242 36.494m224.444 62.372l-10.537-15.854 17.81 6.742 5.824-18.125 5.825 18.126 17.807-6.742-10.537 15.854 16.37 9.718-18.965 1.65 2.616 18.85-13.116-13.793-13.117 13.794 2.616-18.85-18.964-1.65m16.368-291.815l-10.537-15.856 17.81 6.742 5.824-18.122 5.825 18.12 17.807-6.74-10.537 15.855 16.37 9.717-18.965 1.65 2.616 18.85-13.116-13.793-13.117 13.794 2.616-18.85-18.964-1.65m-89.418 104.883l-10.537-15.853 17.808 6.742 5.825-18.125 5.825 18.125 17.808-6.742-10.536 15.853 16.37 9.72-18.965 1.65 2.615 18.85-13.117-13.795-13.117 13.795 2.617-18.85-18.964-1.65m216.212-37.929l-10.558-15.854 17.822 6.742 5.782-18.125 5.854 18.125 17.772-6.742-10.508 15.854 16.362 9.718-18.97 1.65 2.608 18.85-13.118-13.793-13.117 13.793 2.61-18.85-18.936-1.65m-22.251 73.394l-10.367 6.425 2.914-11.84-9.316-7.863 12.165-.896 4.605-11.29 4.606 11.29 12.165.897-9.317 7.863 2.912 11.84" fill-rule="evenodd" fill="#fff"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,6 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="480" width="640" viewBox="0 0 640 480">
|
||||
<g transform="translate(74.118) scale(.9375)">
|
||||
<path fill="#fff" d="M81.137 0h362.276v512H81.137z"/>
|
||||
<path fill="#bf0a30" d="M-100 0H81.138v512H-100zm543.413 0H624.55v512H443.414zM135.31 247.41l-14.067 4.808 65.456 57.446c4.95 14.764-1.72 19.116-5.97 26.86l71.06-9.02-1.85 71.512 14.718-.423-3.21-70.918 71.13 8.432c-4.402-9.297-8.32-14.233-4.247-29.098l65.414-54.426-11.447-4.144c-9.36-7.222 4.044-34.784 6.066-52.178 0 0-38.195 13.135-40.698 6.262l-9.727-18.685-34.747 38.17c-3.796.91-5.413-.6-6.304-3.808l16.053-79.766-25.42 14.297c-2.128.91-4.256.125-5.658-2.355l-24.45-49.06-25.21 50.95c-1.9 1.826-3.803 2.037-5.382.796l-24.204-13.578 14.53 79.143c-1.156 3.14-3.924 4.025-7.18 2.324l-33.216-37.737c-4.345 6.962-7.29 18.336-13.033 20.885-5.744 2.387-24.98-4.823-37.873-7.637 4.404 15.895 18.176 42.302 9.46 50.957z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 934 B |
@@ -1,5 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="480" width="640" viewBox="0 0 640 480">
|
||||
<path fill="#ffce00" d="M0 320h640v160.002H0z"/>
|
||||
<path d="M0 0h640v160H0z"/>
|
||||
<path fill="#d00" d="M0 160h640v160H0z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 220 B |
@@ -1,7 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="480" width="640" viewBox="0 0 640 480">
|
||||
<g fill-rule="evenodd" stroke-width="1pt">
|
||||
<path fill="#fff" d="M0 0h640v480H0z"/>
|
||||
<path fill="#00267f" d="M0 0h213.337v480H0z"/>
|
||||
<path fill="#f31830" d="M426.662 0H640v480H426.662z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 301 B |
@@ -1,15 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="480" width="640" viewBox="0 0 640 480">
|
||||
<defs>
|
||||
<clipPath id="a">
|
||||
<path fill-opacity=".67" d="M-85.333 0h682.67v512h-682.67z"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g clip-path="url(#a)" transform="translate(80) scale(.94)">
|
||||
<g stroke-width="1pt">
|
||||
<path fill="#006" d="M-256 0H768.02v512.01H-256z"/>
|
||||
<path d="M-256 0v57.244l909.535 454.768H768.02V454.77L-141.515 0H-256zM768.02 0v57.243L-141.515 512.01H-256v-57.243L653.535 0H768.02z" fill="#fff"/>
|
||||
<path d="M170.675 0v512.01h170.67V0h-170.67zM-256 170.67v170.67H768.02V170.67H-256z" fill="#fff"/>
|
||||
<path d="M-256 204.804v102.402H768.02V204.804H-256zM204.81 0v512.01h102.4V0h-102.4zM-256 512.01L85.34 341.34h76.324l-341.34 170.67H-256zM-256 0L85.34 170.67H9.016L-256 38.164V0zm606.356 170.67L691.696 0h76.324L426.68 170.67h-76.324zM768.02 512.01L426.68 341.34h76.324L768.02 473.848v38.162z" fill="#c00"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 956 B |
@@ -1,18 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="480" width="640" viewBox="0 0 640 480">
|
||||
<g fill-rule="evenodd" transform="scale(.9375)">
|
||||
<g stroke-width="1pt">
|
||||
<path d="M0 0h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0z" fill="#bd3d44"/>
|
||||
<path d="M0 39.385h972.81V78.77H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0z" fill="#fff"/>
|
||||
</g>
|
||||
<path fill="#192f5d" d="M0 0h389.12v275.69H0z"/>
|
||||
<g fill="#fff">
|
||||
<path d="M32.427 11.8l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.853 0l3.541 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735H93.74zm64.856 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.269 6.734 3.54-10.896-9.269-6.735h11.458zm64.852 0l3.54 10.896h11.457l-9.269 6.735 3.54 10.896-9.268-6.734-9.27 6.734 3.541-10.896-9.27-6.735h11.458zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.27 6.734 3.542-10.896-9.27-6.735h11.458zM64.855 39.37l3.54 10.896h11.458L70.583 57l3.542 10.897-9.27-6.734-9.269 6.734L59.126 57l-9.269-6.734h11.458zm64.852 0l3.54 10.896h11.457L135.435 57l3.54 10.897-9.268-6.734-9.27 6.734L123.978 57l-9.27-6.734h11.458zm64.855 0l3.54 10.896h11.458L200.29 57l3.541 10.897-9.27-6.734-9.268 6.734L188.833 57l-9.269-6.734h11.457zm64.855 0l3.54 10.896h11.458L265.145 57l3.541 10.897-9.269-6.734-9.27 6.734L253.69 57l-9.27-6.734h11.458zm64.852 0l3.54 10.896h11.457L329.997 57l3.54 10.897-9.268-6.734-9.27 6.734L318.54 57l-9.27-6.734h11.458zM32.427 66.939l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.853 0l3.541 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735H93.74zm64.856 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.269 6.734 3.54-10.896-9.269-6.735h11.458zm64.852 0l3.54 10.896h11.457l-9.269 6.735 3.54 10.896-9.268-6.734-9.27 6.734 3.541-10.896-9.27-6.735h11.458zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.27 6.734 3.542-10.896-9.27-6.735h11.458zM64.855 94.508l3.54 10.897h11.458l-9.27 6.734 3.542 10.897-9.27-6.734-9.269 6.734 3.54-10.897-9.269-6.734h11.458zm64.852 0l3.54 10.897h11.457l-9.269 6.734 3.54 10.897-9.268-6.734-9.27 6.734 3.541-10.897-9.27-6.734h11.458zm64.855 0l3.54 10.897h11.458l-9.27 6.734 3.541 10.897-9.27-6.734-9.268 6.734 3.54-10.897-9.269-6.734h11.457zm64.855 0l3.54 10.897h11.458l-9.27 6.734 3.541 10.897-9.269-6.734-9.27 6.734 3.542-10.897-9.27-6.734h11.458zm64.852 0l3.54 10.897h11.457l-9.269 6.734 3.54 10.897-9.268-6.734-9.27 6.734 3.541-10.897-9.27-6.734h11.458zM32.427 122.078l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.853 0l3.541 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735H93.74zm64.856 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.269 6.734 3.54-10.896-9.269-6.735h11.458zm64.852 0l3.54 10.896h11.457l-9.269 6.735 3.54 10.896-9.268-6.734-9.27 6.734 3.541-10.896-9.27-6.735h11.458zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.27 6.734 3.542-10.896-9.27-6.735h11.458zM64.855 149.647l3.54 10.897h11.458l-9.27 6.734 3.542 10.897-9.27-6.734-9.269 6.734 3.54-10.897-9.269-6.734h11.458zm64.852 0l3.54 10.897h11.457l-9.269 6.734 3.54 10.897-9.268-6.734-9.27 6.734 3.541-10.897-9.27-6.734h11.458zm64.855 0l3.54 10.897h11.458l-9.27 6.734 3.541 10.897-9.27-6.734-9.268 6.734 3.54-10.897-9.269-6.734h11.457zm64.855 0l3.54 10.897h11.458l-9.27 6.734 3.541 10.897-9.269-6.734-9.27 6.734 3.542-10.897-9.27-6.734h11.458zm64.852 0l3.54 10.897h11.457l-9.269 6.734 3.54 10.897-9.268-6.734-9.27 6.734 3.541-10.897-9.27-6.734h11.458z"/>
|
||||
<g>
|
||||
<path d="M32.427 177.217l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.853 0l3.541 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735H93.74zm64.856 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.269 6.734 3.54-10.896-9.269-6.735h11.458zm64.852 0l3.54 10.896h11.457l-9.269 6.735 3.54 10.896-9.268-6.734-9.27 6.734 3.541-10.896-9.27-6.735h11.458zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.27 6.734 3.542-10.896-9.27-6.735h11.458zM64.855 204.786l3.54 10.897h11.458l-9.27 6.734 3.542 10.897-9.27-6.734-9.269 6.734 3.54-10.897-9.269-6.734h11.458zm64.852 0l3.54 10.897h11.457l-9.269 6.734 3.54 10.897-9.268-6.734-9.27 6.734 3.541-10.897-9.27-6.734h11.458zm64.855 0l3.54 10.897h11.458l-9.27 6.734 3.541 10.897-9.27-6.734-9.268 6.734 3.54-10.897-9.269-6.734h11.457zm64.855 0l3.54 10.897h11.458l-9.27 6.734 3.541 10.897-9.269-6.734-9.27 6.734 3.542-10.897-9.27-6.734h11.458zm64.852 0l3.54 10.897h11.457l-9.269 6.734 3.54 10.897-9.268-6.734-9.27 6.734 3.541-10.897-9.27-6.734h11.458z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="M32.427 232.356l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.853 0l3.541 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735H93.74zm64.856 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.269 6.734 3.54-10.896-9.269-6.735h11.458zm64.852 0l3.54 10.896h11.457l-9.269 6.735 3.54 10.896-9.268-6.734-9.27 6.734 3.541-10.896-9.27-6.735h11.458zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.27 6.734 3.542-10.896-9.27-6.735h11.458z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.1 KiB |
11
images/googleLogo.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="18px" height="18px" viewBox="0 0 48 48" class="abcRioButtonSvg">
|
||||
<g>
|
||||
<path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"></path>
|
||||
<path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"></path>
|
||||
<path fill="#FBBC05" d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"></path>
|
||||
<path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"></path>
|
||||
<path fill="none" d="M0 0h48v48H0z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 909 B |
|
Before Width: | Height: | Size: 7.8 KiB |
BIN
images/welcome_page/curves.png
Normal file
|
After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 794 B |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 9.8 KiB |
@@ -4,6 +4,9 @@
|
||||
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!--#include virtual="base.html" -->
|
||||
|
||||
<link rel="stylesheet" href="css/all.css">
|
||||
|
||||
<script>
|
||||
window.indexLoadedTime = window.performance.now();
|
||||
console.log("(TIME) index.html loaded:\t", indexLoadedTime);
|
||||
@@ -134,8 +137,8 @@
|
||||
<script src="libs/lib-jitsi-meet.min.js?v=139"></script>
|
||||
<script src="libs/app.bundle.min.js?v=139"></script>
|
||||
<!--#include virtual="title.html" -->
|
||||
<link rel="stylesheet" href="css/all.css">
|
||||
<!--#include virtual="plugin.head.html" -->
|
||||
<!--#include virtual="static/welcomePageAdditionalContent.html" -->
|
||||
</head>
|
||||
<body>
|
||||
<div id="react"></div>
|
||||
|
||||
@@ -24,6 +24,7 @@ var interfaceConfig = {
|
||||
BRAND_WATERMARK_LINK: '',
|
||||
SHOW_POWERED_BY: false,
|
||||
GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true,
|
||||
DISPLAY_WELCOME_PAGE_CONTENT: true,
|
||||
APP_NAME: 'Jitsi Meet',
|
||||
LANG_DETECTION: false, // Allow i18n to detect the system language
|
||||
INVITATION_POWERED_BY: true,
|
||||
@@ -40,7 +41,7 @@ var interfaceConfig = {
|
||||
TOOLBAR_BUTTONS: [
|
||||
|
||||
// main toolbar
|
||||
'microphone', 'camera', 'desktop', 'invite', 'fullscreen', 'fodeviceselection', 'hangup',
|
||||
'microphone', 'camera', 'desktop', 'fullscreen', 'fodeviceselection', 'hangup',
|
||||
|
||||
// extended toolbar
|
||||
'profile', 'contacts', 'info', 'chat', 'recording', 'etherpad', 'sharedvideo', 'settings', 'raisehand', 'videoquality', 'filmstrip' ],
|
||||
@@ -49,7 +50,7 @@ var interfaceConfig = {
|
||||
* Main Toolbar Buttons
|
||||
* All of them should be in TOOLBAR_BUTTONS
|
||||
*/
|
||||
MAIN_TOOLBAR_BUTTONS: [ 'microphone', 'camera', 'desktop', 'invite', 'fullscreen', 'fodeviceselection', 'hangup' ],
|
||||
MAIN_TOOLBAR_BUTTONS: [ 'microphone', 'camera', 'desktop', 'fullscreen', 'fodeviceselection', 'hangup' ],
|
||||
SETTINGS_SECTIONS: [ 'language', 'devices', 'moderator' ],
|
||||
INVITE_OPTIONS: [ 'invite', 'dialout', 'addtocall' ],
|
||||
|
||||
@@ -150,6 +151,21 @@ var interfaceConfig = {
|
||||
* @type {boolean}
|
||||
*/
|
||||
VIDEO_QUALITY_LABEL_DISABLED: false
|
||||
|
||||
/**
|
||||
* Specify custom URL for downloading android mobile app.
|
||||
*/
|
||||
// MOBILE_DOWNLOAD_LINK_ANDROID: 'https://play.google.com/store/apps/details?id=org.jitsi.meet',
|
||||
|
||||
/**
|
||||
* Specify URL for downloading ios mobile app.
|
||||
*/
|
||||
// MOBILE_DOWNLOAD_LINK_IOS: 'https://itunes.apple.com/us/app/jitsi-meet/id1165103905',
|
||||
|
||||
/**
|
||||
* Specify mobile app scheme for opening the app from the mobile browser.
|
||||
*/
|
||||
// MOBILE_APP_SCHEME: 'org.jitsi.meet'
|
||||
};
|
||||
|
||||
/* eslint-enable no-unused-vars, no-var, max-len */
|
||||
|
||||
@@ -25,8 +25,13 @@ target 'JitsiMeet' do
|
||||
:path => '../node_modules/react-native-fetch-blob'
|
||||
pod 'react-native-keep-awake',
|
||||
:path => '../node_modules/react-native-keep-awake'
|
||||
pod 'react-native-locale-detector',
|
||||
:path => '../node_modules/react-native-locale-detector'
|
||||
pod 'react-native-webrtc', :path => '../node_modules/react-native-webrtc'
|
||||
pod 'RNSound', :path => '../node_modules/react-native-sound'
|
||||
pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons'
|
||||
pod 'react-native-calendar-events',
|
||||
:path => '../node_modules/react-native-calendar-events'
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
|
||||
@@ -1,52 +1,63 @@
|
||||
PODS:
|
||||
- React (0.49.5):
|
||||
- React/Core (= 0.49.5)
|
||||
- React (0.51.0):
|
||||
- React/Core (= 0.51.0)
|
||||
- react-native-background-timer (2.0.0):
|
||||
- React
|
||||
- react-native-calendar-events (1.4.3):
|
||||
- React
|
||||
- react-native-fetch-blob (0.10.6):
|
||||
- React/Core
|
||||
- react-native-keep-awake (2.0.6):
|
||||
- React
|
||||
- react-native-locale-detector (1.0.0):
|
||||
- React
|
||||
- react-native-webrtc (1.58.2)
|
||||
- React/BatchedBridge (0.49.5):
|
||||
- React/BatchedBridge (0.51.0):
|
||||
- React/Core
|
||||
- React/cxxreact_legacy
|
||||
- React/Core (0.49.5):
|
||||
- yoga (= 0.49.5.React)
|
||||
- React/cxxreact_legacy (0.49.5):
|
||||
- React/Core (0.51.0):
|
||||
- yoga (= 0.51.0.React)
|
||||
- React/cxxreact_legacy (0.51.0):
|
||||
- React/jschelpers_legacy
|
||||
- React/DevSupport (0.49.5):
|
||||
- React/DevSupport (0.51.0):
|
||||
- React/Core
|
||||
- React/RCTWebSocket
|
||||
- React/fishhook (0.49.5)
|
||||
- React/jschelpers_legacy (0.49.5)
|
||||
- React/RCTActionSheet (0.49.5):
|
||||
- React/fishhook (0.51.0)
|
||||
- React/jschelpers_legacy (0.51.0)
|
||||
- React/RCTActionSheet (0.51.0):
|
||||
- React/Core
|
||||
- React/RCTAnimation (0.49.5):
|
||||
- React/RCTAnimation (0.51.0):
|
||||
- React/Core
|
||||
- React/RCTBlob (0.49.5):
|
||||
- React/RCTBlob (0.51.0):
|
||||
- React/Core
|
||||
- React/RCTImage (0.49.5):
|
||||
- React/RCTImage (0.51.0):
|
||||
- React/Core
|
||||
- React/RCTNetwork
|
||||
- React/RCTLinkingIOS (0.49.5):
|
||||
- React/RCTLinkingIOS (0.51.0):
|
||||
- React/Core
|
||||
- React/RCTNetwork (0.49.5):
|
||||
- React/RCTNetwork (0.51.0):
|
||||
- React/Core
|
||||
- React/RCTText (0.49.5):
|
||||
- React/RCTText (0.51.0):
|
||||
- React/Core
|
||||
- React/RCTWebSocket (0.49.5):
|
||||
- React/RCTWebSocket (0.51.0):
|
||||
- React/Core
|
||||
- React/fishhook
|
||||
- React/RCTBlob
|
||||
- RNSound (0.10.4):
|
||||
- React/Core
|
||||
- RNSound/Core (= 0.10.4)
|
||||
- RNSound/Core (0.10.4):
|
||||
- React/Core
|
||||
- RNVectorIcons (4.4.2):
|
||||
- React
|
||||
- yoga (0.49.5.React)
|
||||
- yoga (0.51.0.React)
|
||||
|
||||
DEPENDENCIES:
|
||||
- react-native-background-timer (from `../node_modules/react-native-background-timer`)
|
||||
- react-native-calendar-events (from `../node_modules/react-native-calendar-events`)
|
||||
- react-native-fetch-blob (from `../node_modules/react-native-fetch-blob`)
|
||||
- react-native-keep-awake (from `../node_modules/react-native-keep-awake`)
|
||||
- react-native-locale-detector (from `../node_modules/react-native-locale-detector`)
|
||||
- react-native-webrtc (from `../node_modules/react-native-webrtc`)
|
||||
- React/BatchedBridge (from `../node_modules/react-native`)
|
||||
- React/Core (from `../node_modules/react-native`)
|
||||
@@ -58,6 +69,7 @@ DEPENDENCIES:
|
||||
- React/RCTNetwork (from `../node_modules/react-native`)
|
||||
- React/RCTText (from `../node_modules/react-native`)
|
||||
- React/RCTWebSocket (from `../node_modules/react-native`)
|
||||
- RNSound (from `../node_modules/react-native-sound`)
|
||||
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
|
||||
- yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
||||
|
||||
@@ -66,26 +78,35 @@ EXTERNAL SOURCES:
|
||||
:path: ../node_modules/react-native
|
||||
react-native-background-timer:
|
||||
:path: ../node_modules/react-native-background-timer
|
||||
react-native-calendar-events:
|
||||
:path: ../node_modules/react-native-calendar-events
|
||||
react-native-fetch-blob:
|
||||
:path: ../node_modules/react-native-fetch-blob
|
||||
react-native-keep-awake:
|
||||
:path: ../node_modules/react-native-keep-awake
|
||||
react-native-locale-detector:
|
||||
:path: ../node_modules/react-native-locale-detector
|
||||
react-native-webrtc:
|
||||
:path: ../node_modules/react-native-webrtc
|
||||
RNSound:
|
||||
:path: ../node_modules/react-native-sound
|
||||
RNVectorIcons:
|
||||
:path: ../node_modules/react-native-vector-icons
|
||||
yoga:
|
||||
:path: ../node_modules/react-native/ReactCommon/yoga
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
React: 9d5a23842dcc75ffef540ee2d2ef0eee1904ee58
|
||||
react-native-background-timer: 10063c04bf85d7f8811dff8c74399f0aa715245f
|
||||
react-native-fetch-blob: 2bef9be702de8726f4d7bf58d2345579aaaee60d
|
||||
react-native-keep-awake: bb4dbb6fd21a7879432f9538b0b7d71398fe9f81
|
||||
react-native-webrtc: 6fd0b3aa890d7a9b9b4d01d30f958d17ae88a785
|
||||
RNVectorIcons: c1821d56c775cc5a3bca66c77dfc8cb4a90d27e2
|
||||
yoga: 596e987aa8aac0165abb235d2977982f090476a0
|
||||
React: 541ba768b9855e10cdc76f55427a5cd0653ca806
|
||||
react-native-background-timer: 63dcbf37dbcf294b5c6c071afcdc661fa06a7594
|
||||
react-native-calendar-events: fe6fbc8ed337a7423c98f2c9012b25f20444de09
|
||||
react-native-fetch-blob: 63394b1d7b0781547b3e4463b3195790177b1222
|
||||
react-native-keep-awake: 0de4bd66de0c23178107dce0c2fcc3354b2a8e94
|
||||
react-native-locale-detector: d1b2c6fe5abb56e3a1efb6c2d6f308c05c4251f1
|
||||
react-native-webrtc: bc044ca9530fc802e7533f247aa08fe1b6bf8dc5
|
||||
RNSound: d0818fe2435254fe30540fae48a429c5ffb72e09
|
||||
RNVectorIcons: c0dbfbf6068fefa240c37b0f71bd03b45dddac44
|
||||
yoga: 17521bbb0dd54a47c0b3ac43253e78cdac7488e0
|
||||
|
||||
PODFILE CHECKSUM: a7cb8c7365f8cf9a01ee4eb78325139933776faf
|
||||
PODFILE CHECKSUM: 4a5a310403b99b9c2d619e0b18da89bf0fe5858c
|
||||
|
||||
COCOAPODS: 1.3.1
|
||||
COCOAPODS: 1.4.0
|
||||
|
||||
@@ -53,14 +53,24 @@ partial URL (e.g. a room name only) is specified to
|
||||
`loadURLString:`/`loadURLObject:`. If not set or if set to `nil`, the default
|
||||
built in JavaScript is used: https://meet.jit.si.
|
||||
|
||||
NOTE: Must be set before `loadURL:`/`loadURLString:` for it to take effect.
|
||||
NOTE: Must be set (if at all) before `loadURL:`/`loadURLString:` for it to take
|
||||
effect.
|
||||
|
||||
#### pictureInPictureEnabled
|
||||
|
||||
Property to get / set whether Picture-in-Picture is enabled. Defaults to `YES`
|
||||
if `delegate` implements `enterPictureInPicture:`; otherwise, `NO`.
|
||||
|
||||
NOTE: Must be set (if at all) before `loadURL:`/`loadURLString:` for it to take
|
||||
effect.
|
||||
|
||||
#### welcomePageEnabled
|
||||
|
||||
Property to get/set whether the Welcome page is enabled. If `NO`, a black empty
|
||||
view will be rendered when not in a conference. Defaults to `NO`.
|
||||
|
||||
NOTE: Must be set before `loadURL:`/`loadURLString:` for it to take effect.
|
||||
NOTE: Must be set (if at all) before `loadURL:`/`loadURLString:` for it to take
|
||||
effect.
|
||||
|
||||
#### loadURL:NSURL
|
||||
|
||||
@@ -170,6 +180,16 @@ Called before a conference is left.
|
||||
|
||||
The `data` dictionary contains a "url" key with the conference URL.
|
||||
|
||||
#### enterPictureInPicture
|
||||
|
||||
Called when entering Picture-in-Picture is requested by the user. The app should
|
||||
now activate its Picture-in-Picture implementation (and resize the associated
|
||||
`JitsiMeetView`. The latter will automatically detect its new size and adjust
|
||||
its user interface to a variant appropriate for the small size ordinarily
|
||||
associated with Picture-in-Picture.)
|
||||
|
||||
The `data` dictionary is empty.
|
||||
|
||||
#### loadConfigError
|
||||
|
||||
Called when loading the main configuration file from the Jitsi Meet deployment
|
||||
@@ -178,3 +198,17 @@ fails.
|
||||
The `data` dictionary contains an "error" key with the error and a "url" key
|
||||
with the conference URL which necessitated the loading of the configuration
|
||||
file.
|
||||
|
||||
### Picture-in-Picture
|
||||
|
||||
`JitsiMeetView` will automatically adjust its UI when presented in a
|
||||
Picture-in-Picture style scenario, in a rectangle too small to accommodate its
|
||||
"full" UI.
|
||||
|
||||
Jitsi Meet SDK does not currently implement native Picture-in-Picture on iOS. If
|
||||
desired, apps need to implement non-native Picture-in-Picture themselves and
|
||||
resize `JitsiMeetView`.
|
||||
|
||||
If `pictureInPictureEnabled` is set to `YES` or `delegate` implements
|
||||
`enterPictureInPicture:`, the in-call toolbar will render a button to afford the
|
||||
user to request entering Picture-in-Picture.
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
83CBB9F71A601CBA00E9B192 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0820;
|
||||
LastUpgradeCheck = 0920;
|
||||
ORGANIZATIONNAME = Facebook;
|
||||
TargetAttributes = {
|
||||
13B07F861A680F5B00A75B9A = {
|
||||
@@ -321,14 +321,20 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
@@ -371,14 +377,20 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0820"
|
||||
LastUpgradeVersion = "0920"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "NO"
|
||||
@@ -40,6 +40,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
@@ -59,6 +60,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
||||
|
After Width: | Height: | Size: 47 KiB |
@@ -2,103 +2,109 @@
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "20x20"
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "29x29"
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-40@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "40x40"
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "60x60"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "60x60"
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "20x20"
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "29x29"
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-29@2x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "40x40"
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-40@2x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76@1x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "76x76"
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76@2x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "76x76"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "AppIcon-83.5@2x.png",
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "83.5x83.5"
|
||||
"filename" : "AppIcon-83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "AppIcon-1024@1x.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 158 KiB |
@@ -2,103 +2,109 @@
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "20x20"
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "29x29"
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-40@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "40x40"
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "60x60"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "60x60"
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "20x20"
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "29x29"
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-29@2x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "40x40"
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-40@2x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76@1x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "76x76"
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76@2x.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "76x76"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "AppIcon-83.5@2x.png",
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "83.5x83.5"
|
||||
"filename" : "AppIcon-83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "AppIcon-1024@1x.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
||||