Compare commits
206 Commits
saghul-pat
...
jitsi-meet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6654feacee | ||
|
|
3d4defd799 | ||
|
|
e15bf2d4dd | ||
|
|
6de935b372 | ||
|
|
3397b9cbc9 | ||
|
|
45626a0d23 | ||
|
|
b7bccb0801 | ||
|
|
475ec6d427 | ||
|
|
a28b155c41 | ||
|
|
5f44c7580d | ||
|
|
3d1eb5282c | ||
|
|
10935ec692 | ||
|
|
95a0a8418f | ||
|
|
0a5e914862 | ||
|
|
02ff359de2 | ||
|
|
fecac0322e | ||
|
|
bd1c3332ea | ||
|
|
5ee0738e45 | ||
|
|
c3518208e1 | ||
|
|
21116c09f4 | ||
|
|
875a9cbaf3 | ||
|
|
5fd050b77f | ||
|
|
fee6ecc82d | ||
|
|
2ba57730cd | ||
|
|
78c304cba8 | ||
|
|
b082354773 | ||
|
|
8bd377098d | ||
|
|
7d6990b3f8 | ||
|
|
a51e97f318 | ||
|
|
bc65d21ce4 | ||
|
|
e9236fd9ff | ||
|
|
c4dff9a75e | ||
|
|
edf0a35392 | ||
|
|
f291dc90f4 | ||
|
|
ea0f9e7934 | ||
|
|
480b6f7cdc | ||
|
|
19f91bea84 | ||
|
|
59420ea1a8 | ||
|
|
d969a5311e | ||
|
|
3e025c9f01 | ||
|
|
1e558b143f | ||
|
|
5cfc0378f7 | ||
|
|
6ad8ad3506 | ||
|
|
c2488f4071 | ||
|
|
a63a344f6e | ||
|
|
53acd386f0 | ||
|
|
4469917d45 | ||
|
|
f967efa3e4 | ||
|
|
dc6ee21b5d | ||
|
|
481e8634e0 | ||
|
|
bca746cfc4 | ||
|
|
29663bcec2 | ||
|
|
bd7b2c6e7a | ||
|
|
eee80941b0 | ||
|
|
06c571cafb | ||
|
|
5c3ea96131 | ||
|
|
e6bf6a09f4 | ||
|
|
6e6a3b2f72 | ||
|
|
cbfa5e38b3 | ||
|
|
94c55f7aa4 | ||
|
|
9843aca00a | ||
|
|
816e991ae5 | ||
|
|
cfbdbd4783 | ||
|
|
f83ad5af27 | ||
|
|
a5afd011a1 | ||
|
|
c88891da5b | ||
|
|
b1af0c800b | ||
|
|
146d2c8b66 | ||
|
|
a18e193611 | ||
|
|
6ae0bc36cc | ||
|
|
b1410c34e0 | ||
|
|
070991d7ef | ||
|
|
874f59f0ff | ||
|
|
fa547b5aac | ||
|
|
d27580c016 | ||
|
|
2093ef1ea2 | ||
|
|
75540a588d | ||
|
|
fe51b4c56a | ||
|
|
c7c42f6983 | ||
|
|
68df1b1281 | ||
|
|
00efcfaae5 | ||
|
|
c6b194a073 | ||
|
|
8ac44dfbb3 | ||
|
|
ea2ab9edc0 | ||
|
|
9d27c705f6 | ||
|
|
ebdd9755ba | ||
|
|
fa2a8c5084 | ||
|
|
ac2d73b57c | ||
|
|
93902e6364 | ||
|
|
42163731b3 | ||
|
|
01ce04fe9b | ||
|
|
5d29363764 | ||
|
|
bfe8bc9b73 | ||
|
|
a6f6235dd0 | ||
|
|
ee6bf011e9 | ||
|
|
bea8a7f984 | ||
|
|
2edca5dacb | ||
|
|
69ac73c556 | ||
|
|
89556ecd66 | ||
|
|
462f91f070 | ||
|
|
d29a77b15f | ||
|
|
c31fe521c4 | ||
|
|
8f6f542e9c | ||
|
|
69d9e7d405 | ||
|
|
5e6748a88a | ||
|
|
8bc70f9c87 | ||
|
|
357d226987 | ||
|
|
6b1f7138c6 | ||
|
|
55219dc51b | ||
|
|
0eb3a9a43c | ||
|
|
4d7136b7a7 | ||
|
|
b7d9e1d85d | ||
|
|
a714058328 | ||
|
|
02ff4a1bac | ||
|
|
7833e1337e | ||
|
|
18e0e64ca0 | ||
|
|
80a3d88359 | ||
|
|
5d72028872 | ||
|
|
e89776848c | ||
|
|
70bc78e765 | ||
|
|
4fceae7733 | ||
|
|
23b7dd4abf | ||
|
|
0216bbd1d9 | ||
|
|
15a4fa45e0 | ||
|
|
f2d9ffd5f6 | ||
|
|
b0ba7c8671 | ||
|
|
e5fa25892e | ||
|
|
ae5fe24556 | ||
|
|
b9ef0aa27a | ||
|
|
f30625acf0 | ||
|
|
66d70305a0 | ||
|
|
9108b7ebec | ||
|
|
9454049220 | ||
|
|
2ce2e01803 | ||
|
|
ab25d6c5ab | ||
|
|
1b0dc0cfb0 | ||
|
|
33e484a847 | ||
|
|
67bebc0491 | ||
|
|
9186a74ae3 | ||
|
|
67d9a9819e | ||
|
|
16b88a29db | ||
|
|
9783793514 | ||
|
|
93de398a09 | ||
|
|
23e97a4284 | ||
|
|
9bb906551e | ||
|
|
b1ad82cef9 | ||
|
|
09c9f2930c | ||
|
|
74efbd7a61 | ||
|
|
1b1e7d9bce | ||
|
|
dc98fc4839 | ||
|
|
a815f97c7e | ||
|
|
8261cf2811 | ||
|
|
f2238935b5 | ||
|
|
5f12f76ada | ||
|
|
5a9464697f | ||
|
|
f44601a82b | ||
|
|
3d3de4a884 | ||
|
|
c02ad56b6d | ||
|
|
ea7c5ccd58 | ||
|
|
7ec3eae72b | ||
|
|
edf7d18308 | ||
|
|
6bf4a4e91d | ||
|
|
5fd966f042 | ||
|
|
e275f20055 | ||
|
|
ff624a34d8 | ||
|
|
c98050224c | ||
|
|
5bee373091 | ||
|
|
db4ab34ddf | ||
|
|
ef138fb5aa | ||
|
|
13bfdaed68 | ||
|
|
ff656f4e6b | ||
|
|
a27b78cef0 | ||
|
|
4fa426ace0 | ||
|
|
ac34f524fa | ||
|
|
31a4f2a4ec | ||
|
|
dc908512f9 | ||
|
|
ae983645d1 | ||
|
|
3514b22191 | ||
|
|
405af3af5f | ||
|
|
a6d333c07a | ||
|
|
0387cdc888 | ||
|
|
f670f39dd2 | ||
|
|
7262465777 | ||
|
|
75b4049529 | ||
|
|
ac6185424c | ||
|
|
9e15df8e3d | ||
|
|
83f83c17eb | ||
|
|
3e1adcd9b7 | ||
|
|
8105127571 | ||
|
|
bc99a72984 | ||
|
|
e10eaaa3d9 | ||
|
|
0e831074c0 | ||
|
|
326b694bf2 | ||
|
|
9e1f3de4e5 | ||
|
|
07a25a1f00 | ||
|
|
d6bbe07cf2 | ||
|
|
e9a8fd5392 | ||
|
|
aea9c5e79e | ||
|
|
b60210d0ad | ||
|
|
f0d2106c1a | ||
|
|
13f1cb13c5 | ||
|
|
c27ca779ab | ||
|
|
aedb43ec5b | ||
|
|
0a68eed294 | ||
|
|
3f51b10245 | ||
|
|
5260cd7e30 |
@@ -17,3 +17,8 @@ react/features/face-landmarks/resources/*
|
||||
|
||||
# Not worth it.
|
||||
actionTypes.ts
|
||||
|
||||
# It's not complete until all files are copied at build time.
|
||||
react-native-sdk/
|
||||
|
||||
*.d.ts
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
module.exports = {
|
||||
'extends': [
|
||||
extends: [
|
||||
'@jitsi/eslint-config'
|
||||
],
|
||||
'ignorePatterns': [ '*.d.ts' ]
|
||||
]
|
||||
};
|
||||
|
||||
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
npm -v
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v41
|
||||
uses: jitsi/changed-files@main
|
||||
- name: Get changed lang files
|
||||
id: lang-files
|
||||
run: echo "all=$(echo "${{ steps.changed-files.outputs.all_changed_files }}" | grep -oE 'lang\/\S+' | tr '\n' ' ')" >> "$GITHUB_OUTPUT"
|
||||
@@ -88,17 +88,17 @@ jobs:
|
||||
run: |
|
||||
uname -a
|
||||
xcode-select -p
|
||||
sudo xcode-select -s /Applications/Xcode_16.0.app/Contents/Developer
|
||||
sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer
|
||||
xcodebuild -version
|
||||
- name: setup-cocoapods
|
||||
uses: maxim-lobanov/setup-cocoapods@v1
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
podfile-path: ios/Podfile.lock
|
||||
ruby-version: '3.4'
|
||||
bundler-cache: true
|
||||
- run: npx react-native info
|
||||
- name: Install Pods
|
||||
run: |
|
||||
pod --version
|
||||
cd ios
|
||||
pod install --repo-update --deployment
|
||||
working-directory: ./ios
|
||||
run: bundle exec pod install --repo-update --deployment
|
||||
- run: npx react-native bundle --entry-file react/index.native.js --platform ios --bundle-output /tmp/ios.bundle --reset-cache
|
||||
android-sdk-build:
|
||||
name: Build mobile SDK (Android)
|
||||
@@ -137,17 +137,17 @@ jobs:
|
||||
run: |
|
||||
uname -a
|
||||
xcode-select -p
|
||||
sudo xcode-select -s /Applications/Xcode_16.0.app/Contents/Developer
|
||||
sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer
|
||||
xcodebuild -version
|
||||
- name: setup-cocoapods
|
||||
uses: maxim-lobanov/setup-cocoapods@v1
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
podfile-path: ios/Podfile.lock
|
||||
ruby-version: '3.4'
|
||||
bundler-cache: true
|
||||
- run: npx react-native info
|
||||
- name: Install Pods
|
||||
run: |
|
||||
pod --version
|
||||
cd ios
|
||||
pod install --repo-update --deployment
|
||||
working-directory: ./ios
|
||||
run: bundle exec pod install --repo-update --deployment
|
||||
- run: |
|
||||
xcodebuild clean \
|
||||
-workspace ios/jitsi-meet.xcworkspace \
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -62,6 +62,7 @@ buck-out/
|
||||
|
||||
# fastlane
|
||||
#
|
||||
.bundle/
|
||||
**/fastlane/report.xml
|
||||
**/fastlane/Preview.html
|
||||
**/fastlane/test_output
|
||||
|
||||
16
Gemfile
Normal file
16
Gemfile
Normal file
@@ -0,0 +1,16 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
ruby ">= 3.4.0"
|
||||
|
||||
gem "cocoapods", "~> 1.16"
|
||||
|
||||
# (Optional) Fastlane for automation
|
||||
gem "fastlane"
|
||||
gem "abbrev"
|
||||
gem "logger"
|
||||
gem "mutex_m"
|
||||
gem "csv"
|
||||
gem "bigdecimal"
|
||||
|
||||
# (Optional) Bundler itself to ensure consistency
|
||||
gem "bundler"
|
||||
331
Gemfile.lock
Normal file
331
Gemfile.lock
Normal file
@@ -0,0 +1,331 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (3.0.7)
|
||||
base64
|
||||
nkf
|
||||
rexml
|
||||
abbrev (0.1.2)
|
||||
activesupport (7.2.2.1)
|
||||
base64
|
||||
benchmark (>= 0.3)
|
||||
bigdecimal
|
||||
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||
connection_pool (>= 2.2.5)
|
||||
drb
|
||||
i18n (>= 1.6, < 2)
|
||||
logger (>= 1.4.2)
|
||||
minitest (>= 5.1)
|
||||
securerandom (>= 0.3)
|
||||
tzinfo (~> 2.0, >= 2.0.5)
|
||||
addressable (2.8.7)
|
||||
public_suffix (>= 2.0.2, < 7.0)
|
||||
algoliasearch (1.27.5)
|
||||
httpclient (~> 2.8, >= 2.8.3)
|
||||
json (>= 1.5.1)
|
||||
artifactory (3.0.17)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.3.1)
|
||||
aws-partitions (1.1050.0)
|
||||
aws-sdk-core (3.218.1)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.992.0)
|
||||
aws-sigv4 (~> 1.9)
|
||||
base64
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.98.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-s3 (1.181.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sigv4 (1.11.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
babosa (1.0.4)
|
||||
base64 (0.2.0)
|
||||
benchmark (0.4.0)
|
||||
bigdecimal (3.1.9)
|
||||
claide (1.1.0)
|
||||
cocoapods (1.16.2)
|
||||
addressable (~> 2.8)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
cocoapods-core (= 1.16.2)
|
||||
cocoapods-deintegrate (>= 1.0.3, < 2.0)
|
||||
cocoapods-downloader (>= 2.1, < 3.0)
|
||||
cocoapods-plugins (>= 1.0.0, < 2.0)
|
||||
cocoapods-search (>= 1.0.0, < 2.0)
|
||||
cocoapods-trunk (>= 1.6.0, < 2.0)
|
||||
cocoapods-try (>= 1.1.0, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
escape (~> 0.0.4)
|
||||
fourflusher (>= 2.3.0, < 3.0)
|
||||
gh_inspector (~> 1.0)
|
||||
molinillo (~> 0.8.0)
|
||||
nap (~> 1.0)
|
||||
ruby-macho (>= 2.3.0, < 3.0)
|
||||
xcodeproj (>= 1.27.0, < 2.0)
|
||||
cocoapods-core (1.16.2)
|
||||
activesupport (>= 5.0, < 8)
|
||||
addressable (~> 2.8)
|
||||
algoliasearch (~> 1.0)
|
||||
concurrent-ruby (~> 1.1)
|
||||
fuzzy_match (~> 2.0.4)
|
||||
nap (~> 1.0)
|
||||
netrc (~> 0.11)
|
||||
public_suffix (~> 4.0)
|
||||
typhoeus (~> 1.0)
|
||||
cocoapods-deintegrate (1.0.5)
|
||||
cocoapods-downloader (2.1)
|
||||
cocoapods-plugins (1.0.0)
|
||||
nap
|
||||
cocoapods-search (1.0.1)
|
||||
cocoapods-trunk (1.6.0)
|
||||
nap (>= 0.8, < 2.0)
|
||||
netrc (~> 0.11)
|
||||
cocoapods-try (1.2.0)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
commander (4.6.0)
|
||||
highline (~> 2.0.0)
|
||||
concurrent-ruby (1.3.5)
|
||||
connection_pool (2.5.0)
|
||||
csv (3.3.2)
|
||||
declarative (0.0.20)
|
||||
digest-crc (0.7.0)
|
||||
rake (>= 12.0.0, < 14.0.0)
|
||||
domain_name (0.6.20240107)
|
||||
dotenv (2.8.1)
|
||||
drb (2.2.1)
|
||||
emoji_regex (3.2.3)
|
||||
escape (0.0.4)
|
||||
ethon (0.16.0)
|
||||
ffi (>= 1.15.0)
|
||||
excon (0.112.0)
|
||||
faraday (1.10.4)
|
||||
faraday-em_http (~> 1.0)
|
||||
faraday-em_synchrony (~> 1.0)
|
||||
faraday-excon (~> 1.1)
|
||||
faraday-httpclient (~> 1.0)
|
||||
faraday-multipart (~> 1.0)
|
||||
faraday-net_http (~> 1.0)
|
||||
faraday-net_http_persistent (~> 1.0)
|
||||
faraday-patron (~> 1.0)
|
||||
faraday-rack (~> 1.0)
|
||||
faraday-retry (~> 1.0)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-cookie_jar (0.0.7)
|
||||
faraday (>= 0.8.0)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday-em_http (1.0.0)
|
||||
faraday-em_synchrony (1.0.0)
|
||||
faraday-excon (1.1.0)
|
||||
faraday-httpclient (1.0.1)
|
||||
faraday-multipart (1.1.0)
|
||||
multipart-post (~> 2.0)
|
||||
faraday-net_http (1.0.2)
|
||||
faraday-net_http_persistent (1.2.0)
|
||||
faraday-patron (1.0.0)
|
||||
faraday-rack (1.0.0)
|
||||
faraday-retry (1.0.3)
|
||||
faraday_middleware (1.2.1)
|
||||
faraday (~> 1.0)
|
||||
fastimage (2.4.0)
|
||||
fastlane (2.226.0)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.8, < 3.0.0)
|
||||
artifactory (~> 3.0)
|
||||
aws-sdk-s3 (~> 1.0)
|
||||
babosa (>= 1.0.3, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 3.0.0)
|
||||
colored (~> 1.2)
|
||||
commander (~> 4.6)
|
||||
dotenv (>= 2.1.1, < 3.0.0)
|
||||
emoji_regex (>= 0.1, < 4.0)
|
||||
excon (>= 0.71.0, < 1.0.0)
|
||||
faraday (~> 1.0)
|
||||
faraday-cookie_jar (~> 0.0.6)
|
||||
faraday_middleware (~> 1.0)
|
||||
fastimage (>= 2.1.0, < 3.0.0)
|
||||
fastlane-sirp (>= 1.0.0)
|
||||
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||
google-apis-androidpublisher_v3 (~> 0.3)
|
||||
google-apis-playcustomapp_v1 (~> 0.1)
|
||||
google-cloud-env (>= 1.6.0, < 2.0.0)
|
||||
google-cloud-storage (~> 1.31)
|
||||
highline (~> 2.0)
|
||||
http-cookie (~> 1.0.5)
|
||||
json (< 3.0.0)
|
||||
jwt (>= 2.1.0, < 3)
|
||||
mini_magick (>= 4.9.4, < 5.0.0)
|
||||
multipart-post (>= 2.0.0, < 3.0.0)
|
||||
naturally (~> 2.2)
|
||||
optparse (>= 0.1.1, < 1.0.0)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
rubyzip (>= 2.0.0, < 3.0.0)
|
||||
security (= 0.1.5)
|
||||
simctl (~> 1.6.3)
|
||||
terminal-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-table (~> 3)
|
||||
tty-screen (>= 0.6.3, < 1.0.0)
|
||||
tty-spinner (>= 0.8.0, < 1.0.0)
|
||||
word_wrap (~> 1.0.0)
|
||||
xcodeproj (>= 1.13.0, < 2.0.0)
|
||||
xcpretty (~> 0.4.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
|
||||
fastlane-sirp (1.0.0)
|
||||
sysrandom (~> 1.0)
|
||||
ffi (1.17.1)
|
||||
ffi (1.17.1-aarch64-linux-gnu)
|
||||
ffi (1.17.1-aarch64-linux-musl)
|
||||
ffi (1.17.1-arm-linux-gnu)
|
||||
ffi (1.17.1-arm-linux-musl)
|
||||
ffi (1.17.1-arm64-darwin)
|
||||
ffi (1.17.1-x86-linux-gnu)
|
||||
ffi (1.17.1-x86-linux-musl)
|
||||
ffi (1.17.1-x86_64-darwin)
|
||||
ffi (1.17.1-x86_64-linux-gnu)
|
||||
ffi (1.17.1-x86_64-linux-musl)
|
||||
fourflusher (2.3.1)
|
||||
fuzzy_match (2.0.4)
|
||||
gh_inspector (1.1.3)
|
||||
google-apis-androidpublisher_v3 (0.54.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-core (0.11.3)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
httpclient (>= 2.8.1, < 3.a)
|
||||
mini_mime (~> 1.0)
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.a)
|
||||
rexml
|
||||
google-apis-iamcredentials_v1 (0.17.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-playcustomapp_v1 (0.13.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-storage_v1 (0.31.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-cloud-core (1.7.1)
|
||||
google-cloud-env (>= 1.0, < 3.a)
|
||||
google-cloud-errors (~> 1.0)
|
||||
google-cloud-env (1.6.0)
|
||||
faraday (>= 0.17.3, < 3.0)
|
||||
google-cloud-errors (1.4.0)
|
||||
google-cloud-storage (1.47.0)
|
||||
addressable (~> 2.8)
|
||||
digest-crc (~> 0.4)
|
||||
google-apis-iamcredentials_v1 (~> 0.1)
|
||||
google-apis-storage_v1 (~> 0.31.0)
|
||||
google-cloud-core (~> 1.6)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
mini_mime (~> 1.0)
|
||||
googleauth (1.8.1)
|
||||
faraday (>= 0.17.3, < 3.a)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (>= 0.16, < 2.a)
|
||||
highline (2.0.3)
|
||||
http-cookie (1.0.8)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
i18n (1.14.7)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jmespath (1.6.2)
|
||||
json (2.10.1)
|
||||
jwt (2.10.1)
|
||||
base64
|
||||
logger (1.6.6)
|
||||
mini_magick (4.13.2)
|
||||
mini_mime (1.1.5)
|
||||
minitest (5.25.4)
|
||||
molinillo (0.8.0)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.4.1)
|
||||
mutex_m (0.3.0)
|
||||
nanaimo (0.4.0)
|
||||
nap (1.1.0)
|
||||
naturally (2.2.1)
|
||||
netrc (0.11.0)
|
||||
nkf (0.2.0)
|
||||
optparse (0.6.0)
|
||||
os (1.1.4)
|
||||
plist (3.7.2)
|
||||
public_suffix (4.0.7)
|
||||
rake (13.2.1)
|
||||
representable (3.2.0)
|
||||
declarative (< 0.1.0)
|
||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rexml (3.4.1)
|
||||
rouge (3.28.0)
|
||||
ruby-macho (2.5.1)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.4.1)
|
||||
securerandom (0.4.1)
|
||||
security (0.1.5)
|
||||
signet (0.19.0)
|
||||
addressable (~> 2.8)
|
||||
faraday (>= 0.17.5, < 3.a)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simctl (1.6.10)
|
||||
CFPropertyList
|
||||
naturally
|
||||
sysrandom (1.0.5)
|
||||
terminal-notifier (2.0.0)
|
||||
terminal-table (3.0.2)
|
||||
unicode-display_width (>= 1.1.1, < 3)
|
||||
trailblazer-option (0.1.2)
|
||||
tty-cursor (0.7.1)
|
||||
tty-screen (0.8.2)
|
||||
tty-spinner (0.9.3)
|
||||
tty-cursor (~> 0.7)
|
||||
typhoeus (1.4.1)
|
||||
ethon (>= 0.9.0)
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
uber (0.1.0)
|
||||
unicode-display_width (2.6.0)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.27.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.4.0)
|
||||
rexml (>= 3.3.6, < 4.0)
|
||||
xcpretty (0.4.0)
|
||||
rouge (~> 3.28.0)
|
||||
xcpretty-travis-formatter (1.0.1)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
|
||||
PLATFORMS
|
||||
aarch64-linux-gnu
|
||||
aarch64-linux-musl
|
||||
arm-linux-gnu
|
||||
arm-linux-musl
|
||||
arm64-darwin
|
||||
ruby
|
||||
x86-linux-gnu
|
||||
x86-linux-musl
|
||||
x86_64-darwin
|
||||
x86_64-linux-gnu
|
||||
x86_64-linux-musl
|
||||
|
||||
DEPENDENCIES
|
||||
abbrev
|
||||
bigdecimal
|
||||
bundler
|
||||
cocoapods (~> 1.16)
|
||||
csv
|
||||
fastlane
|
||||
logger
|
||||
mutex_m
|
||||
|
||||
RUBY VERSION
|
||||
ruby 3.4.2p28
|
||||
|
||||
BUNDLED WITH
|
||||
2.6.3
|
||||
2
Makefile
2
Makefile
@@ -48,8 +48,6 @@ deploy-appbundle:
|
||||
$(BUILD_DIR)/external_api.min.js.map \
|
||||
$(BUILD_DIR)/alwaysontop.min.js \
|
||||
$(BUILD_DIR)/alwaysontop.min.js.map \
|
||||
$(BUILD_DIR)/analytics-ga.min.js \
|
||||
$(BUILD_DIR)/analytics-ga.min.js.map \
|
||||
$(BUILD_DIR)/face-landmarks-worker.min.js \
|
||||
$(BUILD_DIR)/face-landmarks-worker.min.js.map \
|
||||
$(BUILD_DIR)/noise-suppressor-worklet.min.js \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# <p align="center">Jitsi Meet</p>
|
||||
|
||||
TEST. Jitsi Meet is a set of Open Source projects which empower users to use and deploy
|
||||
Jitsi Meet is a set of Open Source projects which empower users to use and deploy
|
||||
video conferencing platforms with state-of-the-art video quality and features.
|
||||
|
||||
<hr />
|
||||
|
||||
@@ -30,9 +30,12 @@ import android.view.KeyEvent;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.oney.WebRTCModule.WebRTCModuleOptions;
|
||||
|
||||
import org.jitsi.meet.sdk.JitsiMeet;
|
||||
import org.jitsi.meet.sdk.JitsiMeetActivity;
|
||||
import org.jitsi.meet.sdk.JitsiMeetConferenceOptions;
|
||||
import org.webrtc.Logging;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
@@ -79,6 +82,10 @@ public class MainActivity extends JitsiMeetActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
JitsiMeet.showSplashScreen(this);
|
||||
|
||||
WebRTCModuleOptions options = WebRTCModuleOptions.getInstance();
|
||||
options.loggingSeverity = Logging.Severity.LS_ERROR;
|
||||
|
||||
super.onCreate(null);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ ext {
|
||||
googleServicesEnabled = project.file('app/google-services.json').exists() && !libreBuild
|
||||
|
||||
//React Native and Hermes Version
|
||||
rnVersion = "0.75.4"
|
||||
rnVersion = "0.75.5"
|
||||
}
|
||||
|
||||
allprojects {
|
||||
@@ -69,10 +69,29 @@ allprojects {
|
||||
}
|
||||
}
|
||||
|
||||
// Due to a dependency conflict between React Native and the Fresco library used by GiphySDK,
|
||||
// GIFs appear as static images instead of animating
|
||||
// https://github.com/Giphy/giphy-react-native-sdk/commit/7fe466ed6fddfaec95f9cbc959d33bd75ad8f900
|
||||
|
||||
configurations.configureEach {
|
||||
resolutionStrategy {
|
||||
forcedModules = [
|
||||
'com.facebook.fresco:fresco:3.2.0',
|
||||
'com.facebook.fresco:animated-gif:3.2.0',
|
||||
'com.facebook.fresco:animated-base:3.2.0',
|
||||
'com.facebook.fresco:animated-drawable:3.2.0',
|
||||
'com.facebook.fresco:animated-webp:3.2.0',
|
||||
'com.facebook.fresco:webpsupport:3.2.0',
|
||||
'com.facebook.fresco:imagepipeline-okhttp3:3.2.0',
|
||||
'com.facebook.fresco:middleware:3.2.0',
|
||||
'com.facebook.fresco:nativeimagetranscoder:3.2.0'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// Third-party react-native modules which Jitsi Meet SDK for Android depends
|
||||
// on and which are not available in third-party Maven repositories need to
|
||||
// be deployed in a Maven repository of ours.
|
||||
//
|
||||
|
||||
if (project.name.startsWith('react-native-')) {
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
@@ -89,9 +89,11 @@ dependencies {
|
||||
implementation project(':react-native-splash-screen')
|
||||
implementation project(':react-native-svg')
|
||||
implementation project(':react-native-video')
|
||||
implementation project(':react-native-webrtc')
|
||||
implementation project(':react-native-webview')
|
||||
|
||||
// Use `api` here so consumers can use WebRTCModuleOptions.
|
||||
api project(':react-native-webrtc')
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,6 @@ package org.jitsi.meet.sdk;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.facebook.react.bridge.WritableNativeMap;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Wraps the name and extra data for events that were broadcasted locally.
|
||||
*/
|
||||
@@ -16,57 +10,21 @@ public class BroadcastAction {
|
||||
private static final String TAG = BroadcastAction.class.getSimpleName();
|
||||
|
||||
private final Type type;
|
||||
private final HashMap<String, Object> data;
|
||||
private final Bundle data;
|
||||
|
||||
public BroadcastAction(Intent intent) {
|
||||
this.type = Type.buildTypeFromAction(intent.getAction());
|
||||
this.data = buildDataFromBundle(intent.getExtras());
|
||||
this.data = intent.getExtras();
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public HashMap<String, Object> getData() {
|
||||
public Bundle getData() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public WritableNativeMap getDataAsWritableNativeMap() {
|
||||
WritableNativeMap nativeMap = new WritableNativeMap();
|
||||
|
||||
for (String key : this.data.keySet()) {
|
||||
try {
|
||||
if (this.data.get(key) instanceof Boolean) {
|
||||
nativeMap.putBoolean(key, (Boolean) this.data.get(key));
|
||||
} else if (this.data.get(key) instanceof Integer) {
|
||||
nativeMap.putInt(key, (Integer) this.data.get(key));
|
||||
} else if (this.data.get(key) instanceof Double) {
|
||||
nativeMap.putDouble(key, (Double) this.data.get(key));
|
||||
} else if (this.data.get(key) instanceof String) {
|
||||
nativeMap.putString(key, (String) this.data.get(key));
|
||||
} else {
|
||||
throw new Exception("Unsupported extra data type");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
JitsiMeetLogger.w(TAG + " invalid extra data in event", e);
|
||||
}
|
||||
}
|
||||
|
||||
return nativeMap;
|
||||
}
|
||||
|
||||
private static HashMap<String, Object> buildDataFromBundle(Bundle bundle) {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
|
||||
if (bundle != null) {
|
||||
for (String key : bundle.keySet()) {
|
||||
map.put(key, bundle.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
enum Type {
|
||||
SET_AUDIO_MUTED("org.jitsi.meet.SET_AUDIO_MUTED"),
|
||||
HANG_UP("org.jitsi.meet.HANG_UP"),
|
||||
@@ -78,7 +36,13 @@ public class BroadcastAction {
|
||||
SEND_CHAT_MESSAGE("org.jitsi.meet.SEND_CHAT_MESSAGE"),
|
||||
SET_VIDEO_MUTED("org.jitsi.meet.SET_VIDEO_MUTED"),
|
||||
SET_CLOSED_CAPTIONS_ENABLED("org.jitsi.meet.SET_CLOSED_CAPTIONS_ENABLED"),
|
||||
TOGGLE_CAMERA("org.jitsi.meet.TOGGLE_CAMERA");
|
||||
TOGGLE_CAMERA("org.jitsi.meet.TOGGLE_CAMERA"),
|
||||
SHOW_NOTIFICATION("org.jitsi.meet.SHOW_NOTIFICATION"),
|
||||
HIDE_NOTIFICATION("org.jitsi.meet.HIDE_NOTIFICATION"),
|
||||
START_RECORDING("org.jitsi.meet.START_RECORDING"),
|
||||
STOP_RECORDING("org.jitsi.meet.STOP_RECORDING"),
|
||||
OVERWRITE_CONFIG("org.jitsi.meet.OVERWRITE_CONFIG"),
|
||||
SEND_CAMERA_FACING_MODE_MESSAGE("org.jitsi.meet.SEND_CAMERA_FACING_MODE_MESSAGE");
|
||||
|
||||
private final String action;
|
||||
|
||||
|
||||
@@ -91,7 +91,9 @@ public class BroadcastEvent {
|
||||
VIDEO_MUTED_CHANGED("org.jitsi.meet.VIDEO_MUTED_CHANGED"),
|
||||
READY_TO_CLOSE("org.jitsi.meet.READY_TO_CLOSE"),
|
||||
TRANSCRIPTION_CHUNK_RECEIVED("org.jitsi.meet.TRANSCRIPTION_CHUNK_RECEIVED"),
|
||||
CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED("org.jitsi.meet.CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED");
|
||||
CUSTOM_BUTTON_PRESSED("org.jitsi.meet.CUSTOM_BUTTON_PRESSED"),
|
||||
CONFERENCE_UNIQUE_ID_SET("org.jitsi.meet.CONFERENCE_UNIQUE_ID_SET"),
|
||||
RECORDING_STATUS_CHANGED("org.jitsi.meet.RECORDING_STATUS_CHANGED");
|
||||
|
||||
private static final String CONFERENCE_BLURRED_NAME = "CONFERENCE_BLURRED";
|
||||
private static final String CONFERENCE_FOCUSED_NAME = "CONFERENCE_FOCUSED";
|
||||
@@ -109,7 +111,9 @@ public class BroadcastEvent {
|
||||
private static final String VIDEO_MUTED_CHANGED_NAME = "VIDEO_MUTED_CHANGED";
|
||||
private static final String READY_TO_CLOSE_NAME = "READY_TO_CLOSE";
|
||||
private static final String TRANSCRIPTION_CHUNK_RECEIVED_NAME = "TRANSCRIPTION_CHUNK_RECEIVED";
|
||||
private static final String CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED_NAME = "CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED";
|
||||
private static final String CUSTOM_BUTTON_PRESSED_NAME = "CUSTOM_BUTTON_PRESSED";
|
||||
private static final String CONFERENCE_UNIQUE_ID_SET_NAME = "CONFERENCE_UNIQUE_ID_SET";
|
||||
private static final String RECORDING_STATUS_CHANGED_NAME = "RECORDING_STATUS_CHANGED";
|
||||
|
||||
private final String action;
|
||||
|
||||
@@ -164,8 +168,12 @@ public class BroadcastEvent {
|
||||
return READY_TO_CLOSE;
|
||||
case TRANSCRIPTION_CHUNK_RECEIVED_NAME:
|
||||
return TRANSCRIPTION_CHUNK_RECEIVED;
|
||||
case CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED_NAME:
|
||||
return CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED;
|
||||
case CUSTOM_BUTTON_PRESSED_NAME:
|
||||
return CUSTOM_BUTTON_PRESSED;
|
||||
case CONFERENCE_UNIQUE_ID_SET_NAME:
|
||||
return CONFERENCE_UNIQUE_ID_SET;
|
||||
case RECORDING_STATUS_CHANGED_NAME:
|
||||
return RECORDING_STATUS_CHANGED;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class BroadcastIntentHelper {
|
||||
public static Intent buildSetAudioMutedIntent(boolean muted) {
|
||||
Intent intent = new Intent(BroadcastAction.Type.SET_AUDIO_MUTED.getAction());
|
||||
intent.putExtra("muted", muted);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
@@ -17,18 +19,21 @@ public class BroadcastIntentHelper {
|
||||
Intent intent = new Intent(BroadcastAction.Type.SEND_ENDPOINT_TEXT_MESSAGE.getAction());
|
||||
intent.putExtra("to", to);
|
||||
intent.putExtra("message", message);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static Intent buildToggleScreenShareIntent(boolean enabled) {
|
||||
Intent intent = new Intent(BroadcastAction.Type.TOGGLE_SCREEN_SHARE.getAction());
|
||||
intent.putExtra("enabled", enabled);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static Intent buildOpenChatIntent(String participantId) {
|
||||
Intent intent = new Intent(BroadcastAction.Type.OPEN_CHAT.getAction());
|
||||
intent.putExtra("to", participantId);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
@@ -40,28 +45,113 @@ public class BroadcastIntentHelper {
|
||||
Intent intent = new Intent(BroadcastAction.Type.SEND_CHAT_MESSAGE.getAction());
|
||||
intent.putExtra("to", participantId);
|
||||
intent.putExtra("message", message);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static Intent buildSetVideoMutedIntent(boolean muted) {
|
||||
Intent intent = new Intent(BroadcastAction.Type.SET_VIDEO_MUTED.getAction());
|
||||
intent.putExtra("muted", muted);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static Intent buildSetClosedCaptionsEnabledIntent(boolean enabled) {
|
||||
Intent intent = new Intent(BroadcastAction.Type.SET_CLOSED_CAPTIONS_ENABLED.getAction());
|
||||
intent.putExtra("enabled", enabled);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
|
||||
public static Intent buildRetrieveParticipantsInfo(String requestId) {
|
||||
Intent intent = new Intent(BroadcastAction.Type.RETRIEVE_PARTICIPANTS_INFO.getAction());
|
||||
intent.putExtra("requestId", requestId);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static Intent buildToggleCameraIntent() {
|
||||
return new Intent(BroadcastAction.Type.TOGGLE_CAMERA.getAction());
|
||||
}
|
||||
|
||||
public static Intent buildShowNotificationIntent(
|
||||
String appearance, String description, String timeout, String title, String uid) {
|
||||
Intent intent = new Intent(BroadcastAction.Type.SHOW_NOTIFICATION.getAction());
|
||||
intent.putExtra("appearance", appearance);
|
||||
intent.putExtra("description", description);
|
||||
intent.putExtra("timeout", timeout);
|
||||
intent.putExtra("title", title);
|
||||
intent.putExtra("uid", uid);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static Intent buildHideNotificationIntent(String uid) {
|
||||
Intent intent = new Intent(BroadcastAction.Type.HIDE_NOTIFICATION.getAction());
|
||||
intent.putExtra("uid", uid);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
public enum RecordingMode {
|
||||
FILE("file"),
|
||||
STREAM("stream");
|
||||
|
||||
private final String mode;
|
||||
|
||||
RecordingMode(String mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public String getMode() {
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
|
||||
public static Intent buildStartRecordingIntent(
|
||||
RecordingMode mode,
|
||||
String dropboxToken,
|
||||
boolean shouldShare,
|
||||
String rtmpStreamKey,
|
||||
String rtmpBroadcastID,
|
||||
String youtubeStreamKey,
|
||||
String youtubeBroadcastID,
|
||||
Bundle extraMetadata,
|
||||
boolean transcription) {
|
||||
Intent intent = new Intent(BroadcastAction.Type.START_RECORDING.getAction());
|
||||
intent.putExtra("mode", mode.getMode());
|
||||
intent.putExtra("dropboxToken", dropboxToken);
|
||||
intent.putExtra("shouldShare", shouldShare);
|
||||
intent.putExtra("rtmpStreamKey", rtmpStreamKey);
|
||||
intent.putExtra("rtmpBroadcastID", rtmpBroadcastID);
|
||||
intent.putExtra("youtubeStreamKey", youtubeStreamKey);
|
||||
intent.putExtra("youtubeBroadcastID", youtubeBroadcastID);
|
||||
intent.putExtra("extraMetadata", extraMetadata);
|
||||
intent.putExtra("transcription", transcription);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static Intent buildStopRecordingIntent(RecordingMode mode, boolean transcription) {
|
||||
Intent intent = new Intent(BroadcastAction.Type.STOP_RECORDING.getAction());
|
||||
intent.putExtra("mode", mode.getMode());
|
||||
intent.putExtra("transcription", transcription);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static Intent buildOverwriteConfigIntent(Bundle config) {
|
||||
Intent intent = new Intent(BroadcastAction.Type.OVERWRITE_CONFIG.getAction());
|
||||
intent.putExtra("config", config);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static Intent buildSendCameraFacingModeMessageIntent(String to, String facingMode) {
|
||||
Intent intent = new Intent(BroadcastAction.Type.SEND_CAMERA_FACING_MODE_MESSAGE.getAction());
|
||||
intent.putExtra("to", to);
|
||||
intent.putExtra("facingMode", facingMode);
|
||||
|
||||
return intent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ package org.jitsi.meet.sdk;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
@@ -28,7 +31,14 @@ public class BroadcastReceiver extends android.content.BroadcastReceiver {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
BroadcastAction action = new BroadcastAction(intent);
|
||||
String actionName = action.getType().getAction();
|
||||
|
||||
ReactInstanceManagerHolder.emitEvent(actionName, action.getDataAsWritableNativeMap());
|
||||
Bundle data = action.getData();
|
||||
|
||||
// For actions without data bundle (like hangup), we create an empty map
|
||||
// instead of attempting to convert a null bundle to avoid crashes.
|
||||
if (data != null) {
|
||||
ReactInstanceManagerHolder.emitEvent(actionName, Arguments.fromBundle(data));
|
||||
} else {
|
||||
ReactInstanceManagerHolder.emitEvent(actionName, Arguments.createMap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +97,12 @@ class ExternalAPIModule extends ReactContextBaseJavaModule {
|
||||
constants.put("SET_VIDEO_MUTED", BroadcastAction.Type.SET_VIDEO_MUTED.getAction());
|
||||
constants.put("SET_CLOSED_CAPTIONS_ENABLED", BroadcastAction.Type.SET_CLOSED_CAPTIONS_ENABLED.getAction());
|
||||
constants.put("TOGGLE_CAMERA", BroadcastAction.Type.TOGGLE_CAMERA.getAction());
|
||||
constants.put("SHOW_NOTIFICATION", BroadcastAction.Type.SHOW_NOTIFICATION.getAction());
|
||||
constants.put("HIDE_NOTIFICATION", BroadcastAction.Type.HIDE_NOTIFICATION.getAction());
|
||||
constants.put("START_RECORDING", BroadcastAction.Type.START_RECORDING.getAction());
|
||||
constants.put("STOP_RECORDING", BroadcastAction.Type.STOP_RECORDING.getAction());
|
||||
constants.put("OVERWRITE_CONFIG", BroadcastAction.Type.OVERWRITE_CONFIG.getAction());
|
||||
constants.put("SEND_CAMERA_FACING_MODE_MESSAGE", BroadcastAction.Type.SEND_CAMERA_FACING_MODE_MESSAGE.getAction());
|
||||
|
||||
return constants;
|
||||
}
|
||||
|
||||
@@ -272,8 +272,16 @@ public class JitsiMeetActivity extends AppCompatActivity
|
||||
// }
|
||||
|
||||
// protected void onCustomButtonPressed(HashMap<String, Object> extraData) {
|
||||
// JitsiMeetLogger.i("Custom button pressed: " + extraData);
|
||||
// }
|
||||
// JitsiMeetLogger.i("Custom button pressed: " + extraData);
|
||||
// }
|
||||
|
||||
// protected void onConferenceUniqueIdSet(HashMap<String, Object> extraData) {
|
||||
// JitsiMeetLogger.i("Conference unique id set: " + extraData);
|
||||
// }
|
||||
|
||||
// protected void onRecordingStatusChanged(HashMap<String, Object> extraData) {
|
||||
// JitsiMeetLogger.i("Recording status changed: " + extraData);
|
||||
// }
|
||||
|
||||
// Activity lifecycle methods
|
||||
//
|
||||
@@ -358,12 +366,18 @@ public class JitsiMeetActivity extends AppCompatActivity
|
||||
case READY_TO_CLOSE:
|
||||
onReadyToClose();
|
||||
break;
|
||||
// case TRANSCRIPTION_CHUNK_RECEIVED:
|
||||
// onTranscriptionChunkReceived(event.getData());
|
||||
// break;
|
||||
// case CUSTOM_BUTTON_PRESSED:
|
||||
// onCustomButtonPressed(event.getData());
|
||||
// break;
|
||||
// case TRANSCRIPTION_CHUNK_RECEIVED:
|
||||
// onTranscriptionChunkReceived(event.getData());
|
||||
// break;
|
||||
// case CUSTOM_BUTTON_PRESSED:
|
||||
// onCustomButtonPressed(event.getData());
|
||||
// break;
|
||||
// case CONFERENCE_UNIQUE_ID_SET:
|
||||
// onConferenceUniqueIdSet(event.getData());
|
||||
// break;
|
||||
// case RECORDING_STATUS_CHANGED:
|
||||
// onRecordingStatusChanged(event.getData());
|
||||
// break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,10 +33,9 @@ import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
public class JitsiMeetView extends FrameLayout {
|
||||
|
||||
/**
|
||||
* Background color used by {@code BaseReactView} and the React Native root
|
||||
* view.
|
||||
* Background color. Should match the background color set in JS.
|
||||
*/
|
||||
private static final int BACKGROUND_COLOR = 0xFF111111;
|
||||
private static final int BACKGROUND_COLOR = 0xFF040404;
|
||||
|
||||
/**
|
||||
* React Native root view.
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
/*
|
||||
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.oney.WebRTCModule.webrtcutils.SoftwareVideoDecoderFactoryProxy;
|
||||
|
||||
import org.webrtc.EglBase;
|
||||
import org.webrtc.HardwareVideoDecoderFactory;
|
||||
import org.webrtc.PlatformSoftwareVideoDecoderFactory;
|
||||
import org.webrtc.VideoCodecInfo;
|
||||
import org.webrtc.VideoDecoder;
|
||||
import org.webrtc.VideoDecoderFactory;
|
||||
import org.webrtc.VideoDecoderFallback;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
/**
|
||||
* Custom decoder factory which uses HW decoders and falls back to SW.
|
||||
*/
|
||||
public class JitsiVideoDecoderFactory implements VideoDecoderFactory {
|
||||
private final VideoDecoderFactory hardwareVideoDecoderFactory;
|
||||
private final VideoDecoderFactory softwareVideoDecoderFactory = new SoftwareVideoDecoderFactoryProxy();
|
||||
private final @Nullable VideoDecoderFactory platformSoftwareVideoDecoderFactory;
|
||||
|
||||
/**
|
||||
* Create decoder factory using default hardware decoder factory.
|
||||
*/
|
||||
public JitsiVideoDecoderFactory(@Nullable EglBase.Context eglContext) {
|
||||
this.hardwareVideoDecoderFactory = new HardwareVideoDecoderFactory(eglContext);
|
||||
this.platformSoftwareVideoDecoderFactory = new PlatformSoftwareVideoDecoderFactory(eglContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create decoder factory using explicit hardware decoder factory.
|
||||
*/
|
||||
JitsiVideoDecoderFactory(VideoDecoderFactory hardwareVideoDecoderFactory) {
|
||||
this.hardwareVideoDecoderFactory = hardwareVideoDecoderFactory;
|
||||
this.platformSoftwareVideoDecoderFactory = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable VideoDecoder createDecoder(VideoCodecInfo codecType) {
|
||||
VideoDecoder softwareDecoder = softwareVideoDecoderFactory.createDecoder(codecType);
|
||||
final VideoDecoder hardwareDecoder = hardwareVideoDecoderFactory.createDecoder(codecType);
|
||||
if (softwareDecoder == null && platformSoftwareVideoDecoderFactory != null) {
|
||||
softwareDecoder = platformSoftwareVideoDecoderFactory.createDecoder(codecType);
|
||||
}
|
||||
if (hardwareDecoder != null && softwareDecoder != null) {
|
||||
// Both hardware and software supported, wrap it in a software fallback
|
||||
return new VideoDecoderFallback(
|
||||
/* fallback= */ softwareDecoder, /* primary= */ hardwareDecoder);
|
||||
}
|
||||
return hardwareDecoder != null ? hardwareDecoder : softwareDecoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VideoCodecInfo[] getSupportedCodecs() {
|
||||
LinkedHashSet<VideoCodecInfo> supportedCodecInfos = new LinkedHashSet<>();
|
||||
|
||||
supportedCodecInfos.addAll(Arrays.asList(softwareVideoDecoderFactory.getSupportedCodecs()));
|
||||
supportedCodecInfos.addAll(Arrays.asList(hardwareVideoDecoderFactory.getSupportedCodecs()));
|
||||
if (platformSoftwareVideoDecoderFactory != null) {
|
||||
supportedCodecInfos.addAll(
|
||||
Arrays.asList(platformSoftwareVideoDecoderFactory.getSupportedCodecs()));
|
||||
}
|
||||
|
||||
return supportedCodecInfos.toArray(new VideoCodecInfo[supportedCodecInfos.size()]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.oney.WebRTCModule.webrtcutils.H264AndSoftwareVideoEncoderFactory;
|
||||
|
||||
import org.webrtc.EglBase;
|
||||
|
||||
/**
|
||||
* Custom encoder factory which uses HW for H.264 and SW for everything else.
|
||||
*/
|
||||
public class JitsiVideoEncoderFactory extends H264AndSoftwareVideoEncoderFactory {
|
||||
public JitsiVideoEncoderFactory(@Nullable EglBase.Context eglContext) {
|
||||
super(eglContext);
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -32,12 +32,10 @@ import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
import com.oney.WebRTCModule.EglUtils;
|
||||
import com.oney.WebRTCModule.WebRTCModuleOptions;
|
||||
import com.oney.WebRTCModule.webrtcutils.H264AndSoftwareVideoDecoderFactory;
|
||||
import com.oney.WebRTCModule.webrtcutils.H264AndSoftwareVideoEncoderFactory;
|
||||
|
||||
import org.devio.rn.splashscreen.SplashScreenModule;
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
import org.webrtc.EglBase;
|
||||
import org.webrtc.Logging;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
@@ -126,31 +124,31 @@ class ReactInstanceManagerHolder {
|
||||
// AmplitudeReactNativePackage
|
||||
try {
|
||||
Class<?> amplitudePackageClass = Class.forName("com.amplitude.reactnative.AmplitudeReactNativePackage");
|
||||
Constructor constructor = amplitudePackageClass.getConstructor();
|
||||
Constructor<?> constructor = amplitudePackageClass.getConstructor();
|
||||
packages.add((ReactPackage)constructor.newInstance());
|
||||
} catch (Exception e) {
|
||||
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
|
||||
Log.d(TAG, "Not loading AmplitudeReactNativePackage");
|
||||
JitsiMeetLogger.d(TAG, "Not loading AmplitudeReactNativePackage");
|
||||
}
|
||||
|
||||
// GiphyReactNativeSdkPackage
|
||||
try {
|
||||
Class<?> giphyPackageClass = Class.forName("com.giphyreactnativesdk.GiphyReactNativeSdkPackage");
|
||||
Constructor constructor = giphyPackageClass.getConstructor();
|
||||
Constructor<?> constructor = giphyPackageClass.getConstructor();
|
||||
packages.add((ReactPackage)constructor.newInstance());
|
||||
} catch (Exception e) {
|
||||
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
|
||||
Log.d(TAG, "Not loading GiphyReactNativeSdkPackage");
|
||||
JitsiMeetLogger.d(TAG, "Not loading GiphyReactNativeSdkPackage");
|
||||
}
|
||||
|
||||
// RNGoogleSignInPackage
|
||||
try {
|
||||
Class<?> googlePackageClass = Class.forName("com.reactnativegooglesignin.RNGoogleSigninPackage");
|
||||
Constructor constructor = googlePackageClass.getConstructor();
|
||||
Constructor<?> constructor = googlePackageClass.getConstructor();
|
||||
packages.add((ReactPackage)constructor.newInstance());
|
||||
} catch (Exception e) {
|
||||
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
|
||||
Log.d(TAG, "Not loading RNGoogleSignInPackage");
|
||||
JitsiMeetLogger.d(TAG, "Not loading RNGoogleSignInPackage");
|
||||
}
|
||||
|
||||
return packages;
|
||||
@@ -169,7 +167,7 @@ class ReactInstanceManagerHolder {
|
||||
= ReactInstanceManagerHolder.getReactInstanceManager();
|
||||
|
||||
if (reactInstanceManager != null) {
|
||||
ReactContext reactContext
|
||||
@SuppressLint("VisibleForTests") ReactContext reactContext
|
||||
= reactInstanceManager.getCurrentReactContext();
|
||||
|
||||
if (reactContext != null) {
|
||||
@@ -192,7 +190,7 @@ class ReactInstanceManagerHolder {
|
||||
*/
|
||||
static <T extends NativeModule> T getNativeModule(
|
||||
Class<T> nativeModuleClass) {
|
||||
ReactContext reactContext
|
||||
@SuppressLint("VisibleForTests") ReactContext reactContext
|
||||
= reactInstanceManager != null
|
||||
? reactInstanceManager.getCurrentReactContext() : null;
|
||||
|
||||
@@ -219,15 +217,18 @@ class ReactInstanceManagerHolder {
|
||||
|
||||
// Initialize the WebRTC module options.
|
||||
WebRTCModuleOptions options = WebRTCModuleOptions.getInstance();
|
||||
|
||||
EglBase.Context eglContext = EglUtils.getRootEglBaseContext();
|
||||
|
||||
options.videoDecoderFactory = new H264AndSoftwareVideoDecoderFactory(eglContext);
|
||||
options.videoEncoderFactory = new H264AndSoftwareVideoEncoderFactory(eglContext);
|
||||
options.enableMediaProjectionService = true;
|
||||
// options.loggingSeverity = Logging.Severity.LS_INFO;
|
||||
if (options.videoDecoderFactory == null || options.videoEncoderFactory == null) {
|
||||
EglBase.Context eglContext = EglUtils.getRootEglBaseContext();
|
||||
if (options.videoDecoderFactory == null) {
|
||||
options.videoDecoderFactory = new JitsiVideoDecoderFactory(eglContext);
|
||||
}
|
||||
if (options.videoEncoderFactory == null) {
|
||||
options.videoEncoderFactory = new JitsiVideoEncoderFactory(eglContext);
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(TAG, "initializing RN with Activity");
|
||||
JitsiMeetLogger.d(TAG, "initializing RN");
|
||||
|
||||
reactInstanceManager
|
||||
= ReactInstanceManager.builder()
|
||||
|
||||
30
app.js
30
app.js
@@ -1,9 +1,5 @@
|
||||
/* Jitsi Meet app main entrypoint. */
|
||||
|
||||
// Polyfill Promise.withReolvers.
|
||||
// FIXME(saghul) webpack + core-js v3 should polyfill this.
|
||||
import 'promise.withresolvers/auto';
|
||||
|
||||
// Re-export jQuery
|
||||
// FIXME: Remove this requirement from torture tests.
|
||||
import $ from 'jquery';
|
||||
@@ -14,6 +10,32 @@ import '@matrix-org/olm';
|
||||
|
||||
import 'focus-visible';
|
||||
|
||||
/*
|
||||
* Safari polyfill for createImageBitmap
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap
|
||||
*
|
||||
* Support source image types: Canvas.
|
||||
*/
|
||||
if (!('createImageBitmap' in window)) {
|
||||
window.createImageBitmap = function(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let dataURL;
|
||||
|
||||
if (data instanceof HTMLCanvasElement) {
|
||||
dataURL = data.toDataURL();
|
||||
} else {
|
||||
reject(new Error('createImageBitmap does not handle the provided image source type'));
|
||||
}
|
||||
const img = document.createElement('img');
|
||||
|
||||
img.addEventListener('load', () => {
|
||||
resolve(img);
|
||||
});
|
||||
img.src = dataURL;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// We need to setup the jitsi-local-storage as early as possible so that we can start using it.
|
||||
// NOTE: If jitsi-local-storage is used before the initial setup is performed this will break the use case when we use
|
||||
// the local storage from the parent page when the localStorage is disabled. Also the setup is relying that
|
||||
|
||||
@@ -172,7 +172,9 @@ let room;
|
||||
|
||||
/*
|
||||
* Logic to open a desktop picker put on the window global for
|
||||
* lib-jitsi-meet to detect and invoke
|
||||
* lib-jitsi-meet to detect and invoke.
|
||||
*
|
||||
* TODO: remove once the Electron SDK supporting gDM has been out for a while.
|
||||
*/
|
||||
window.JitsiMeetScreenObtainer = {
|
||||
openDesktopPicker(options, onSourceChoose) {
|
||||
@@ -287,7 +289,7 @@ class ConferenceConnector {
|
||||
},
|
||||
descriptionKey: 'dialog.reservationErrorMsg',
|
||||
titleKey: 'dialog.reservationError'
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
|
||||
}));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -295,7 +297,7 @@ class ConferenceConnector {
|
||||
APP.store.dispatch(showErrorNotification({
|
||||
descriptionKey: 'dialog.gracefulShutdown',
|
||||
titleKey: 'dialog.serviceUnavailable'
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
|
||||
}));
|
||||
break;
|
||||
|
||||
// FIXME FOCUS_DISCONNECTED is a confusing event name.
|
||||
@@ -599,7 +601,7 @@ export default {
|
||||
|
||||
const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(initialOptions, true);
|
||||
|
||||
tryCreateLocalTracks.then(async tr => {
|
||||
tryCreateLocalTracks.then(tr => {
|
||||
const createLocalTracksEnd = window.performance.now();
|
||||
|
||||
connectionTimes['conference.init.createLocalTracks.end'] = createLocalTracksEnd;
|
||||
@@ -2276,8 +2278,10 @@ export default {
|
||||
* @param {boolean} [requestFeedback=false] if user feedback should be
|
||||
* @param {string} [hangupReason] the reason for leaving the meeting
|
||||
* requested
|
||||
* @param {boolean} [notifyOnConferenceTermination] whether to notify
|
||||
* the user on conference termination
|
||||
*/
|
||||
hangup(requestFeedback = false, hangupReason) {
|
||||
hangup(requestFeedback = false, hangupReason, notifyOnConferenceTermination) {
|
||||
APP.store.dispatch(disableReceiver());
|
||||
|
||||
this._stopProxyConnection();
|
||||
@@ -2296,7 +2300,7 @@ export default {
|
||||
|
||||
if (requestFeedback) {
|
||||
const feedbackDialogClosed = (feedbackResult = {}) => {
|
||||
if (!feedbackResult.wasDialogShown && hangupReason) {
|
||||
if (!feedbackResult.wasDialogShown && hangupReason && notifyOnConferenceTermination) {
|
||||
return APP.store.dispatch(
|
||||
openLeaveReasonDialog(hangupReason)).then(() => feedbackResult);
|
||||
}
|
||||
|
||||
22
config.js
22
config.js
@@ -393,6 +393,9 @@ var config = {
|
||||
// // showPrejoinWarning: true,
|
||||
// // If true, the notification for recording start will display a link to download the cloud recording.
|
||||
// // showRecordingLink: true,
|
||||
// // If true, mutes audio and video when a recording begins and displays a dialog
|
||||
// // explaining the effect of unmuting.
|
||||
// // requireConsent: true,
|
||||
// },
|
||||
|
||||
// recordingService: {
|
||||
@@ -600,6 +603,7 @@ var config = {
|
||||
// short: 2500,
|
||||
// medium: 5000,
|
||||
// long: 10000,
|
||||
// extraLong: 60000,
|
||||
// },
|
||||
|
||||
// // Options for the recording limit notification.
|
||||
@@ -751,6 +755,9 @@ var config = {
|
||||
// and microsoftApiApplicationClientID
|
||||
// enableCalendarIntegration: false,
|
||||
|
||||
// Whether to notify when the conference is terminated because it was destroyed.
|
||||
// notifyOnConferenceDestruction: true,
|
||||
|
||||
// The client id for the google APIs used for the calendar integration, youtube livestreaming, etc.
|
||||
// googleApiApplicationClientID: '<client_id>',
|
||||
|
||||
@@ -1091,9 +1098,6 @@ var config = {
|
||||
// True if the analytics should be disabled
|
||||
// disabled: false,
|
||||
|
||||
// The Google Analytics Tracking ID:
|
||||
// googleAnalyticsTrackingId: 'your-tracking-id-UA-123456-1',
|
||||
|
||||
// Matomo configuration:
|
||||
// matomoEndpoint: 'https://your-matomo-endpoint/',
|
||||
// matomoSiteID: '42',
|
||||
@@ -1131,7 +1135,6 @@ var config = {
|
||||
|
||||
// Array of script URLs to load as lib-jitsi-meet "analytics handlers".
|
||||
// scriptURLs: [
|
||||
// "libs/analytics-ga.min.js", // google-analytics
|
||||
// "https://example.com/my-custom-analytics.js",
|
||||
// ],
|
||||
|
||||
@@ -1375,8 +1378,12 @@ var config = {
|
||||
The config file should be in JSON.
|
||||
None of the fields are mandatory and the response must have the shape:
|
||||
{
|
||||
// Whether participant can only send group chat message if `send-groupchat` feature is enabled in jwt.
|
||||
groupChatRequiresPermission: false,
|
||||
// Whether participant can only create polls if `create-polls` feature is enabled in jwt.
|
||||
pollCreationRequiresPermission: false,
|
||||
// The domain url to apply (will replace the domain in the sharing conference link/embed section)
|
||||
inviteDomain: 'example-company.org,
|
||||
inviteDomain: 'example-company.org',
|
||||
// The hex value for the colour used as background
|
||||
backgroundColor: '#fff',
|
||||
// The url for the image used as background
|
||||
@@ -1564,6 +1571,8 @@ var config = {
|
||||
// You can enable tokenAuthUrlAutoRedirect which will detect that you have logged in successfully before
|
||||
// and will automatically redirect to the token service to get the token for the meeting.
|
||||
// tokenAuthUrlAutoRedirect: false
|
||||
// An option to respect the context.tenant jwt field compared to the current tenant from the url
|
||||
// tokenRespectTenant: false,
|
||||
|
||||
// You can put an array of values to target different entity types in the invite dialog.
|
||||
// Valid values are "phone", "room", "sip", "user", "videosipgw" and "email"
|
||||
@@ -1861,6 +1870,9 @@ var config = {
|
||||
|
||||
// Hide login button on auth dialog, you may want to enable this if you are using JWT tokens to authenticate users
|
||||
// hideLoginButton: true,
|
||||
|
||||
// If true remove the tint foreground on focused user camera in filmstrip
|
||||
// disableCameraTintForeground: false,
|
||||
};
|
||||
|
||||
// Set the default values for JaaS customers
|
||||
|
||||
@@ -111,7 +111,7 @@ form {
|
||||
height: $watermarkHeight;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
z-index: $zindex2;
|
||||
z-index: $watermarkZ;
|
||||
}
|
||||
|
||||
.leftwatermark {
|
||||
@@ -142,7 +142,7 @@ form {
|
||||
font-size: 11pt;
|
||||
color: rgba(255,255,255,.50);
|
||||
text-decoration: none;
|
||||
z-index: 100;
|
||||
z-index: $watermarkZ;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
flex-grow: 1;
|
||||
|
||||
.meetings-list-empty {
|
||||
text-align: center;
|
||||
@@ -174,4 +174,12 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) { /* Targets iPads and smaller devices */
|
||||
.item {
|
||||
.delete-meeting {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,10 @@
|
||||
}
|
||||
|
||||
.welcome-footer-row-block {
|
||||
display: block;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap:12px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ $zindex1: 1;
|
||||
$zindex2: 2;
|
||||
$zindex3: 3;
|
||||
$toolbarZ: 250;
|
||||
$watermarkZ: 253;
|
||||
|
||||
// Place filmstrip videos over toolbar in order
|
||||
// to make connection info visible.
|
||||
$filmstripVideosZ: $toolbarZ + 1;
|
||||
@@ -75,9 +77,12 @@ $welcomePageHeaderBackground: linear-gradient(0deg, rgba(0, 0, 0, 0.2), rgba(0,
|
||||
$welcomePageHeaderBackgroundPosition: center;
|
||||
$welcomePageHeaderBackgroundRepeat: none;
|
||||
$welcomePageHeaderBackgroundSize: cover;
|
||||
$welcomePageHeaderPaddingBottom: 15px;
|
||||
$welcomePageHeaderPadding: 1rem;
|
||||
$welcomePageHeaderTitleMaxWidth: initial;
|
||||
$welcomePageHeaderTextAlign: center;
|
||||
$welcomePageButtonBg: #0074E0;
|
||||
$welcomePageButtonHoverBg: #4687ED;
|
||||
$welcomePageButtonFocusOutline: #00225A;
|
||||
|
||||
$welcomePageHeaderContainerMarginTop: 104px;
|
||||
$welcomePageHeaderContainerDisplay: flex;
|
||||
|
||||
@@ -18,7 +18,7 @@ body.welcome-page {
|
||||
background-position: $welcomePageHeaderBackgroundPosition;
|
||||
background-repeat: $welcomePageHeaderBackgroundRepeat;
|
||||
background-size: $welcomePageHeaderBackgroundSize;
|
||||
padding-bottom: $welcomePageHeaderPaddingBottom;
|
||||
padding: $welcomePageHeaderPadding;
|
||||
background-color: #131519;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
@@ -219,14 +219,18 @@ body.welcome-page {
|
||||
.welcome-page-button {
|
||||
border: 0;
|
||||
font-size: 14px;
|
||||
background: #0074E0;
|
||||
background: $welcomePageButtonBg;
|
||||
border-radius: 3px;
|
||||
color: #FFFFFF;
|
||||
cursor: pointer;
|
||||
padding: 16px 20px;
|
||||
|
||||
transition: all 0.2s;
|
||||
&:focus-within {
|
||||
outline: auto 2px #022e61;
|
||||
outline: auto 2px $welcomePageButtonFocusOutline;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $welcomePageButtonHoverBg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,8 +268,7 @@ body.welcome-page {
|
||||
|
||||
&.without-content {
|
||||
.welcome-card {
|
||||
min-width: 500px;
|
||||
max-width: 580px;
|
||||
max-width: 100dvw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,6 +349,6 @@ body.welcome-page {
|
||||
|
||||
.welcome-footer-row-1-text {
|
||||
max-width: 200px;
|
||||
margin-right: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
42
debian/jitsi-meet-prosody.postinst
vendored
42
debian/jitsi-meet-prosody.postinst
vendored
@@ -131,16 +131,6 @@ case "$1" in
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$PROSODY_CREATE_JICOFO_USER" = "true" ]; then
|
||||
# create 'focus@auth.domain' prosody user
|
||||
prosodyctl register $JICOFO_AUTH_USER $JICOFO_AUTH_DOMAIN $JICOFO_AUTH_PASSWORD
|
||||
# trigger a restart
|
||||
PROSODY_CONFIG_PRESENT="false"
|
||||
fi
|
||||
|
||||
# creates the user if it does not exist
|
||||
echo -e "$JVB_SECRET\n$JVB_SECRET" | prosodyctl adduser jvb@$JICOFO_AUTH_DOMAIN > /dev/null || true
|
||||
|
||||
# Check whether prosody config has the internal muc, if not add it,
|
||||
# as we are migrating configs
|
||||
if [ -f $PROSODY_HOST_CONFIG ] && ! grep -q "internal.$JICOFO_AUTH_DOMAIN" $PROSODY_HOST_CONFIG; then
|
||||
@@ -184,6 +174,12 @@ case "$1" in
|
||||
PROSODY_CONFIG_PRESENT="false"
|
||||
fi
|
||||
|
||||
# Since prosody 13 admins are not automatically room owners and we expect that for jicofo
|
||||
if ! grep -q -- 'component_admins_as_room_owners = ' $PROSODY_HOST_CONFIG ;then
|
||||
sed -i "1s/^/component_admins_as_room_owners = true\n/" $PROSODY_HOST_CONFIG
|
||||
PROSODY_CONFIG_PRESENT="false"
|
||||
fi
|
||||
|
||||
JAAS_HOST_CONFIG="/etc/prosody/conf.avail/jaas.cfg.lua"
|
||||
if [ "${JAAS_INPUT}" = "true" ] && [ ! -f $JAAS_HOST_CONFIG ]; then
|
||||
sed -i "s/enabled = false -- Jitsi meet components/enabled = true -- Jitsi meet components/g" $PROSODY_HOST_CONFIG
|
||||
@@ -207,9 +203,6 @@ case "$1" in
|
||||
fi
|
||||
fi
|
||||
|
||||
# Make sure the focus@auth user's roster includes the proxy component (this is idempotent)
|
||||
prosodyctl mod_roster_command subscribe focus.$JVB_HOSTNAME $JICOFO_AUTH_USER@$JICOFO_AUTH_DOMAIN
|
||||
|
||||
if [ ! -f /var/lib/prosody/$JVB_HOSTNAME.crt ]; then
|
||||
# prosodyctl takes care for the permissions
|
||||
# echo for using all default values
|
||||
@@ -252,6 +245,29 @@ case "$1" in
|
||||
if [ "$PROSODY_CONFIG_PRESENT" = "false" ]; then
|
||||
invoke-rc.d prosody restart || true
|
||||
|
||||
# give it some time to warm up
|
||||
sleep 10
|
||||
|
||||
if [ "$PROSODY_CREATE_JICOFO_USER" = "true" ]; then
|
||||
# create 'focus@auth.domain' prosody user
|
||||
echo -e "$JICOFO_AUTH_PASSWORD\n$JICOFO_AUTH_PASSWORD" | prosodyctl adduser $JICOFO_AUTH_USER@$JICOFO_AUTH_DOMAIN > /dev/null || true
|
||||
|
||||
# trigger a restart
|
||||
PROSODY_CONFIG_PRESENT="false"
|
||||
fi
|
||||
|
||||
# creates the user if it does not exist
|
||||
echo -e "$JVB_SECRET\n$JVB_SECRET" | prosodyctl adduser jvb@$JICOFO_AUTH_DOMAIN > /dev/null || true
|
||||
|
||||
# Make sure the focus@auth user's roster includes the proxy component (this is idempotent)
|
||||
prosodyctl mod_roster_command subscribe focus.$JVB_HOSTNAME $JICOFO_AUTH_USER@$JICOFO_AUTH_DOMAIN
|
||||
|
||||
# To make sure the roster command is loaded
|
||||
# Once we have https://issues.prosody.im/1908 we can start using prosodyctl shell roster subscribe
|
||||
# and drop the wait and the prosody restart
|
||||
sleep 1
|
||||
invoke-rc.d prosody restart || true
|
||||
|
||||
# In case we had updated the certificates and restarted prosody, let's restart and the bridge and jicofo if possible
|
||||
if [ -d /run/systemd/system ] && [ "$CERT_ADDED_TO_TRUST" = "true" ]; then
|
||||
systemctl restart jitsi-videobridge2.service >/dev/null || true
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
-- We need this for prosody 13.0
|
||||
component_admins_as_room_owners = true
|
||||
|
||||
plugin_paths = { "/usr/share/jitsi-meet/prosody-plugins/" }
|
||||
|
||||
-- domain mapper options, must at least have domain base set to use the mapper
|
||||
|
||||
23
ios/Podfile
23
ios/Podfile
@@ -78,8 +78,6 @@ target 'JitsiMeetSDKLite' do
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
|
||||
PLIST_BUDDY_PATH = '/usr/libexec/PlistBuddy'
|
||||
react_native_post_install(
|
||||
installer,
|
||||
use_native_modules![:reactNativePath],
|
||||
@@ -98,23 +96,8 @@ post_install do |installer|
|
||||
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.1'
|
||||
config.build_settings['OTHER_SWIFT_FLAGS'] = '$(inherited) -no-verify-emitted-module-interface'
|
||||
end
|
||||
|
||||
# Can be removed when updated to RN 0.76
|
||||
# Issue https://github.com/facebook/react-native/issues/35863#issuecomment-1387465588
|
||||
if target.name == "hermes-engine"
|
||||
installer.pods_project.files.each do |fileref|
|
||||
if fileref.path.end_with? "hermes.xcframework"
|
||||
hermes_plist_file = "#{fileref.real_path}/Info.plist"
|
||||
# Patch Hermes to remove the debug symbols entry from the Info.plist (as it's not shipped with it)
|
||||
# This might be removed once Hermes starts to ship with Debug symbols or we remove our
|
||||
# direct dependency from the Main iOS target on "hermes.xcframework"
|
||||
Open3.capture3(PLIST_BUDDY_PATH, '-c', 'Delete :AvailableLibraries:0:DebugSymbolsPath', hermes_plist_file)
|
||||
Open3.capture3(PLIST_BUDDY_PATH, '-c', 'Delete :AvailableLibraries:1:DebugSymbolsPath', hermes_plist_file)
|
||||
Open3.capture3(PLIST_BUDDY_PATH, '-c', 'Delete :AvailableLibraries:2:DebugSymbolsPath', hermes_plist_file)
|
||||
Open3.capture3(PLIST_BUDDY_PATH, '-c', 'Delete :AvailableLibraries:3:DebugSymbolsPath', hermes_plist_file)
|
||||
Open3.capture3(PLIST_BUDDY_PATH, '-c', 'Delete :AvailableLibraries:4:DebugSymbolsPath', hermes_plist_file)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Patch SocketRocket to support TLS 1.3
|
||||
%x(patch Pods/SocketRocket/SocketRocket/SRSecurityPolicy.m -N < patches/ws-tls13.diff)
|
||||
end
|
||||
|
||||
578
ios/Podfile.lock
578
ios/Podfile.lock
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,6 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
0B412F1F1EDEE6E800B1A0A6 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B412F1E1EDEE6E800B1A0A6 /* ViewController.m */; };
|
||||
0B412F211EDEE95300B1A0A6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0B412F201EDEE95300B1A0A6 /* Main.storyboard */; };
|
||||
0B5418471F7C5D8C00A2DD86 /* MeetingRowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B5418461F7C5D8C00A2DD86 /* MeetingRowController.swift */; };
|
||||
0B7001701F7C51CC005944F4 /* InCallController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B70016F1F7C51CC005944F4 /* InCallController.swift */; };
|
||||
0BEA5C291F7B8F73000D0AB4 /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0BEA5C271F7B8F73000D0AB4 /* Interface.storyboard */; };
|
||||
@@ -19,10 +17,8 @@
|
||||
0BEA5C3B1F7B8F73000D0AB4 /* ComplicationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BEA5C3A1F7B8F73000D0AB4 /* ComplicationController.swift */; };
|
||||
0BEA5C3D1F7B8F73000D0AB4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0BEA5C3C1F7B8F73000D0AB4 /* Assets.xcassets */; };
|
||||
0BEA5C411F7B8F73000D0AB4 /* JitsiMeetCompanion.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 0BEA5C251F7B8F73000D0AB4 /* JitsiMeetCompanion.app */; };
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
|
||||
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
2681BB562C7A0B42CFBA6719 /* libPods-JitsiMeet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D6152FF9E9F7B0E86F70A21D /* libPods-JitsiMeet.a */; };
|
||||
361974E2A13624D7735D619D /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 5C1BE20ECD5DEEB48FED90B5 /* PrivacyInfo.xcprivacy */; };
|
||||
4341A9062CF0D63200940D93 /* hermes.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4341A9052CF0D63200940D93 /* hermes.xcframework */; };
|
||||
@@ -34,7 +30,8 @@
|
||||
4EB0603C260E09D000F524C5 /* SocketConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB06039260E09D000F524C5 /* SocketConnection.swift */; };
|
||||
4EB0603D260E09D000F524C5 /* DarwinNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB0603A260E09D000F524C5 /* DarwinNotificationCenter.swift */; };
|
||||
4EB0603E260E09D000F524C5 /* SampleUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB0603B260E09D000F524C5 /* SampleUploader.swift */; };
|
||||
DE4C456121DE1E4E00EA0709 /* FIRUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = DE4C455F21DE1E4E00EA0709 /* FIRUtilities.m */; };
|
||||
DEA0B7122D7EF16E0062A9F6 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEA0B7112D7EF16E0062A9F6 /* ViewController.swift */; };
|
||||
DEA0B7142D7EF7590062A9F6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEA0B7132D7EF7590062A9F6 /* AppDelegate.swift */; };
|
||||
DEA9F289258A6EA800D4CD74 /* JitsiMeetSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DEA9F288258A6EA800D4CD74 /* JitsiMeetSDK.framework */; };
|
||||
DEA9F28A258A6EA800D4CD74 /* JitsiMeetSDK.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DEA9F288258A6EA800D4CD74 /* JitsiMeetSDK.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
DED016F128ECBC9D009D5E8D /* WebRTC.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = DED016F028ECBC9D009D5E8D /* WebRTC.xcframework */; };
|
||||
@@ -121,12 +118,8 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0B26BE6D1EC5BC3C00EEFB41 /* JitsiMeet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = JitsiMeet.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0B412F1D1EDEE6E800B1A0A6 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
|
||||
0B412F1E1EDEE6E800B1A0A6 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
|
||||
0B412F201EDEE95300B1A0A6 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
0B5418461F7C5D8C00A2DD86 /* MeetingRowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingRowController.swift; sourceTree = "<group>"; };
|
||||
0B70016F1F7C51CC005944F4 /* InCallController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InCallController.swift; sourceTree = "<group>"; };
|
||||
0BBD021F212EB69D00CCB19F /* Types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Types.h; sourceTree = "<group>"; };
|
||||
0BD6B4361EF82A6B00D1F4CD /* WebRTC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebRTC.framework; path = "../../node_modules/react-native-webrtc/ios/WebRTC.framework"; sourceTree = "<group>"; };
|
||||
0BEA5C251F7B8F73000D0AB4 /* JitsiMeetCompanion.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JitsiMeetCompanion.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0BEA5C281F7B8F73000D0AB4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Interface.storyboard; sourceTree = "<group>"; };
|
||||
@@ -139,12 +132,9 @@
|
||||
0BEA5C3C1F7B8F73000D0AB4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
0BEA5C3E1F7B8F73000D0AB4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
13B07F961A680F5B00A75B9A /* jitsi-meet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "jitsi-meet.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
3E0F4ED943C0B12BE77F6B45 /* Pods-JitsiMeet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.release.xcconfig"; path = "Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.release.xcconfig"; sourceTree = "<group>"; };
|
||||
4341A9052CF0D63200940D93 /* hermes.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = hermes.xcframework; path = "../Pods/hermes-engine/destroot/Library/Frameworks/universal/hermes.xcframework"; sourceTree = "<group>"; };
|
||||
4E90F93F2632D1AB001102D4 /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = "<group>"; };
|
||||
@@ -157,13 +147,12 @@
|
||||
4EB0603B260E09D000F524C5 /* SampleUploader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SampleUploader.swift; sourceTree = "<group>"; };
|
||||
4EC49B8625BED71300E76218 /* ReplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReplayKit.framework; path = System/Library/Frameworks/ReplayKit.framework; sourceTree = SDKROOT; };
|
||||
5C1BE20ECD5DEEB48FED90B5 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
6132EF172BDFF13200BBE14D /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = ../PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
756FCE06C08D9B947653C98A /* Pods-JitsiMeet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.debug.xcconfig"; path = "Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
B3B083EB1D4955FF0069CEE7 /* app.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = app.entitlements; sourceTree = "<group>"; };
|
||||
D6152FF9E9F7B0E86F70A21D /* libPods-JitsiMeet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-JitsiMeet.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DE050388256E904600DEE3A5 /* WebRTC.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = WebRTC.xcframework; path = "../../node_modules/react-native-webrtc/apple/WebRTC.xcframework"; sourceTree = "<group>"; };
|
||||
DE4C455F21DE1E4E00EA0709 /* FIRUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRUtilities.m; sourceTree = "<group>"; };
|
||||
DE4C456021DE1E4E00EA0709 /* FIRUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FIRUtilities.h; sourceTree = "<group>"; };
|
||||
DEA0B7112D7EF16E0062A9F6 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
DEA0B7132D7EF7590062A9F6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
DEA9F288258A6EA800D4CD74 /* JitsiMeetSDK.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = JitsiMeetSDK.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DED016F028ECBC9D009D5E8D /* WebRTC.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = WebRTC.xcframework; path = ../Pods/JitsiWebRTC/WebRTC.xcframework; sourceTree = "<group>"; };
|
||||
DEFDBBDB25656E3B00344B23 /* WebRTC.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = WebRTC.xcframework; path = "../../node_modules/react-native-webrtc/ios/WebRTC.xcframework"; sourceTree = "<group>"; };
|
||||
@@ -258,18 +247,11 @@
|
||||
13B07FAE1A68108700A75B9A /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.m */,
|
||||
DE4C456021DE1E4E00EA0709 /* FIRUtilities.h */,
|
||||
DE4C455F21DE1E4E00EA0709 /* FIRUtilities.m */,
|
||||
DEA0B7132D7EF7590062A9F6 /* AppDelegate.swift */,
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */,
|
||||
13B07FB61A68108700A75B9A /* Info.plist */,
|
||||
13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
|
||||
13B07FB71A68108700A75B9A /* main.m */,
|
||||
0B412F201EDEE95300B1A0A6 /* Main.storyboard */,
|
||||
0BBD021F212EB69D00CCB19F /* Types.h */,
|
||||
0B412F1D1EDEE6E800B1A0A6 /* ViewController.h */,
|
||||
0B412F1E1EDEE6E800B1A0A6 /* ViewController.m */,
|
||||
DEA0B7112D7EF16E0062A9F6 /* ViewController.swift */,
|
||||
);
|
||||
path = src;
|
||||
sourceTree = "<group>";
|
||||
@@ -302,7 +284,6 @@
|
||||
0BEA5C351F7B8F73000D0AB4 /* WatchKit extension */,
|
||||
4EB06025260E026600F524C5 /* JitsiMeetBroadcast Extension */,
|
||||
CDD71F5E1157E9F283DF92A8 /* Pods */,
|
||||
6132EF172BDFF13200BBE14D /* PrivacyInfo.xcprivacy */,
|
||||
5C1BE20ECD5DEEB48FED90B5 /* PrivacyInfo.xcprivacy */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
@@ -435,6 +416,7 @@
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
13B07F861A680F5B00A75B9A = {
|
||||
LastSwiftMigration = 1620;
|
||||
SystemCapabilities = {
|
||||
com.apple.SafariKeychain = {
|
||||
enabled = 1;
|
||||
@@ -492,7 +474,6 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0B412F211EDEE95300B1A0A6 /* Main.storyboard in Resources */,
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
|
||||
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
|
||||
361974E2A13624D7735D619D /* PrivacyInfo.xcprivacy in Resources */,
|
||||
@@ -660,10 +641,8 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0B412F1F1EDEE6E800B1A0A6 /* ViewController.m in Sources */,
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
|
||||
DE4C456121DE1E4E00EA0709 /* FIRUtilities.m in Sources */,
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */,
|
||||
DEA0B7122D7EF16E0062A9F6 /* ViewController.swift in Sources */,
|
||||
DEA0B7142D7EF7590062A9F6 /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -869,6 +848,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconDebug;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = app.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
@@ -893,6 +873,8 @@
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 6.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -903,6 +885,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconRelease;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = app.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
@@ -926,6 +909,7 @@
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_VERSION = 6.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright @ 2017-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (nonatomic, strong) UIWindow *window;
|
||||
|
||||
@end
|
||||
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
* Copyright @ 2018-present 8x8, Inc.
|
||||
* Copyright @ 2017-2018 Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "FIRUtilities.h"
|
||||
#import "Types.h"
|
||||
#import "ViewController.h"
|
||||
|
||||
@import Firebase;
|
||||
@import JitsiMeetSDK;
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application
|
||||
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||
JitsiMeet *jitsiMeet = [JitsiMeet sharedInstance];
|
||||
|
||||
jitsiMeet.conferenceActivityType = JitsiMeetConferenceActivityType;
|
||||
jitsiMeet.customUrlScheme = @"org.jitsi.meet";
|
||||
jitsiMeet.universalLinkDomains = @[@"meet.jit.si", @"alpha.jitsi.net", @"beta.meet.jit.si"];
|
||||
|
||||
jitsiMeet.defaultConferenceOptions = [JitsiMeetConferenceOptions fromBuilder:^(JitsiMeetConferenceOptionsBuilder *builder) {
|
||||
|
||||
// For testing configOverrides a room needs to be set
|
||||
// builder.room = @"test0988test";
|
||||
|
||||
[builder setFeatureFlag:@"welcomepage.enabled" withBoolean:YES];
|
||||
[builder setFeatureFlag:@"ios.screensharing.enabled" withBoolean:YES];
|
||||
[builder setFeatureFlag:@"ios.recording.enabled" withBoolean:YES];
|
||||
}];
|
||||
|
||||
[jitsiMeet application:application didFinishLaunchingWithOptions:launchOptions];
|
||||
|
||||
// Initialize Crashlytics and Firebase if a valid GoogleService-Info.plist file was provided.
|
||||
if ([FIRUtilities appContainsRealServiceInfoPlist]) {
|
||||
NSLog(@"Enabling Firebase");
|
||||
[FIRApp configure];
|
||||
// Crashlytics defaults to disabled with the FirebaseCrashlyticsCollectionEnabled Info.plist key.
|
||||
[[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:![jitsiMeet isCrashReportingDisabled]];
|
||||
}
|
||||
|
||||
ViewController *rootController = (ViewController *)self.window.rootViewController;
|
||||
[jitsiMeet showSplashScreen:rootController.view];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void) applicationWillTerminate:(UIApplication *)application {
|
||||
NSLog(@"Application will terminate!");
|
||||
// Try to leave the current meeting graceefully.
|
||||
ViewController *rootController = (ViewController *)self.window.rootViewController;
|
||||
[rootController terminate];
|
||||
}
|
||||
|
||||
#pragma mark Linking delegate methods
|
||||
|
||||
- (BOOL)application:(UIApplication *)application
|
||||
continueUserActivity:(NSUserActivity *)userActivity
|
||||
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *restorableObjects))restorationHandler {
|
||||
|
||||
if ([FIRUtilities appContainsRealServiceInfoPlist]) {
|
||||
// 1. Attempt to handle Universal Links through Firebase in order to support
|
||||
// its Dynamic Links (which we utilize for the purposes of deferred deep
|
||||
// linking).
|
||||
BOOL handled
|
||||
= [[FIRDynamicLinks dynamicLinks]
|
||||
handleUniversalLink:userActivity.webpageURL
|
||||
completion:^(FIRDynamicLink * _Nullable dynamicLink, NSError * _Nullable error) {
|
||||
NSURL *firebaseUrl = [FIRUtilities extractURL:dynamicLink];
|
||||
if (firebaseUrl != nil) {
|
||||
userActivity.webpageURL = firebaseUrl;
|
||||
[[JitsiMeet sharedInstance] application:application
|
||||
continueUserActivity:userActivity
|
||||
restorationHandler:restorationHandler];
|
||||
}
|
||||
}];
|
||||
|
||||
if (handled) {
|
||||
return handled;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Default to plain old, non-Firebase-assisted Universal Links.
|
||||
return [[JitsiMeet sharedInstance] application:application
|
||||
continueUserActivity:userActivity
|
||||
restorationHandler:restorationHandler];
|
||||
}
|
||||
|
||||
- (BOOL)application:(UIApplication *)app
|
||||
openURL:(NSURL *)url
|
||||
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
|
||||
|
||||
// This shows up during a reload in development, skip it.
|
||||
// https://github.com/firebase/firebase-ios-sdk/issues/233
|
||||
if ([[url absoluteString] containsString:@"google/link/?dismiss=1&is_weak_match=1"]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSURL *openUrl = url;
|
||||
|
||||
if ([FIRUtilities appContainsRealServiceInfoPlist]) {
|
||||
// Process Firebase Dynamic Links
|
||||
FIRDynamicLink *dynamicLink = [[FIRDynamicLinks dynamicLinks] dynamicLinkFromCustomSchemeURL:url];
|
||||
NSURL *firebaseUrl = [FIRUtilities extractURL:dynamicLink];
|
||||
if (firebaseUrl != nil) {
|
||||
openUrl = firebaseUrl;
|
||||
}
|
||||
}
|
||||
|
||||
return [[JitsiMeet sharedInstance] application:app
|
||||
openURL:openUrl
|
||||
options:options];
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientationMask)application:(UIApplication *)application
|
||||
supportedInterfaceOrientationsForWindow:(UIWindow *)window {
|
||||
return [[JitsiMeet sharedInstance] application:application
|
||||
supportedInterfaceOrientationsForWindow:window];
|
||||
}
|
||||
|
||||
@end
|
||||
109
ios/app/src/AppDelegate.swift
Normal file
109
ios/app/src/AppDelegate.swift
Normal file
@@ -0,0 +1,109 @@
|
||||
import UIKit
|
||||
import Firebase
|
||||
import JitsiMeetSDK
|
||||
|
||||
@main
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
self.window = UIWindow(frame: UIScreen.main.bounds)
|
||||
|
||||
let jitsiMeet = JitsiMeet.sharedInstance()
|
||||
|
||||
// jitsiMeet.webRtcLoggingSeverity = .verbose
|
||||
|
||||
jitsiMeet.conferenceActivityType = "org.jitsi.JitsiMeet.ios.conference" // Must match the one defined in Info.plist{}
|
||||
jitsiMeet.customUrlScheme = "org.jitsi.meet"
|
||||
jitsiMeet.universalLinkDomains = ["meet.jit.si", "alpha.jitsi.net", "beta.meet.jit.si"]
|
||||
|
||||
jitsiMeet.defaultConferenceOptions = JitsiMeetConferenceOptions.fromBuilder { builder in
|
||||
// For testing configOverrides a room needs to be set
|
||||
// builder.room = "https://meet.jit.si/test0988test"
|
||||
|
||||
builder.setFeatureFlag("welcomepage.enabled", withBoolean: true)
|
||||
builder.setFeatureFlag("ios.screensharing.enabled", withBoolean: true)
|
||||
builder.setFeatureFlag("ios.recording.enabled", withBoolean: true)
|
||||
}
|
||||
|
||||
jitsiMeet.application(application, didFinishLaunchingWithOptions: launchOptions ?? [:])
|
||||
|
||||
if self.appContainsRealServiceInfoPlist() {
|
||||
print("Enabling Firebase")
|
||||
FirebaseApp.configure()
|
||||
Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(!jitsiMeet.isCrashReportingDisabled())
|
||||
}
|
||||
|
||||
let vc = ViewController()
|
||||
self.window?.rootViewController = vc
|
||||
jitsiMeet.showSplashScreen(vc.view)
|
||||
|
||||
self.window?.makeKeyAndVisible()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
print("Application will terminate!")
|
||||
if let rootController = self.window?.rootViewController as? ViewController {
|
||||
rootController.terminate()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Linking delegate methods
|
||||
|
||||
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
|
||||
if self.appContainsRealServiceInfoPlist() {
|
||||
let handled = DynamicLinks.dynamicLinks().handleUniversalLink(userActivity.webpageURL!) { dynamicLink, error in
|
||||
if let firebaseUrl = self.extractURL(from: dynamicLink) {
|
||||
userActivity.webpageURL = firebaseUrl
|
||||
JitsiMeet.sharedInstance().application(application, continue: userActivity, restorationHandler: restorationHandler)
|
||||
}
|
||||
}
|
||||
|
||||
if handled {
|
||||
return handled
|
||||
}
|
||||
}
|
||||
|
||||
return JitsiMeet.sharedInstance().application(application, continue: userActivity, restorationHandler: restorationHandler)
|
||||
}
|
||||
|
||||
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
|
||||
if url.absoluteString.contains("google/link/?dismiss=1&is_weak_match=1") {
|
||||
return false
|
||||
}
|
||||
|
||||
var openUrl = url
|
||||
|
||||
if self.appContainsRealServiceInfoPlist() {
|
||||
if let dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url),
|
||||
let firebaseUrl = self.extractURL(from: dynamicLink) {
|
||||
openUrl = firebaseUrl
|
||||
}
|
||||
}
|
||||
|
||||
return JitsiMeet.sharedInstance().application(app, open: openUrl, options: options)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
|
||||
return JitsiMeet.sharedInstance().application(application, supportedInterfaceOrientationsFor: window)
|
||||
}
|
||||
}
|
||||
|
||||
// Firebase utilities
|
||||
extension AppDelegate {
|
||||
func appContainsRealServiceInfoPlist() -> Bool {
|
||||
return InfoPlistUtil.containsRealServiceInfoPlist(in: Bundle.main)
|
||||
}
|
||||
|
||||
func extractURL(from dynamicLink: DynamicLink?) -> URL? {
|
||||
guard let dynamicLink = dynamicLink,
|
||||
let dynamicLinkURL = dynamicLink.url,
|
||||
dynamicLink.matchType == .unique || dynamicLink.matchType == .default else {
|
||||
return nil
|
||||
}
|
||||
return dynamicLinkURL
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="u7g-vg-A8m">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="xSm-U5-Hdu">
|
||||
<objects>
|
||||
<viewController id="u7g-vg-A8m" customClass="ViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="d40-fc-Y8P"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="1KD-Ho-g0H"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="QpR-jB-WOw" customClass="JitsiMeetView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="ZIj-K3-jVH" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="28" y="138"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@import Firebase;
|
||||
|
||||
|
||||
@interface FIRUtilities : NSObject
|
||||
|
||||
+ (BOOL)appContainsRealServiceInfoPlist;
|
||||
+ (NSURL *_Nullable)extractURL: (FIRDynamicLink* _Nullable)dynamicLink;
|
||||
|
||||
@end
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "FIRUtilities.h"
|
||||
|
||||
@import JitsiMeetSDK;
|
||||
|
||||
@implementation FIRUtilities
|
||||
|
||||
+ (BOOL)appContainsRealServiceInfoPlist {
|
||||
static BOOL containsRealServiceInfoPlist = NO;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSBundle *bundle = [NSBundle mainBundle];
|
||||
containsRealServiceInfoPlist = [InfoPlistUtil containsRealServiceInfoPlistInBundle:bundle];
|
||||
});
|
||||
return containsRealServiceInfoPlist;
|
||||
}
|
||||
|
||||
+ (NSURL *)extractURL: (FIRDynamicLink*)dynamicLink {
|
||||
NSURL *url = nil;
|
||||
if (dynamicLink != nil) {
|
||||
NSURL *dynamicLinkURL = dynamicLink.url;
|
||||
if (dynamicLinkURL != nil
|
||||
&& (dynamicLink.matchType == FIRDLMatchTypeUnique
|
||||
|| dynamicLink.matchType == FIRDLMatchTypeDefault)) {
|
||||
// Strong match, process it.
|
||||
url = dynamicLinkURL;
|
||||
}
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -88,8 +88,6 @@
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// This must match what's defined in the NSUserActivityTypes array in the
|
||||
// Info.plist file.
|
||||
static NSString *const JitsiMeetConferenceActivityType
|
||||
= @"org.jitsi.JitsiMeet.ios.conference";
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright @ 2017-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@import UIKit;
|
||||
@import JitsiMeetSDK;
|
||||
|
||||
@interface ViewController : UIViewController<JitsiMeetViewDelegate>
|
||||
|
||||
- (void)terminate;
|
||||
|
||||
@end
|
||||
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright @ 2017-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@import CoreSpotlight;
|
||||
@import MobileCoreServices;
|
||||
@import Intents; // Needed for NSUserActivity suggestedInvocationPhrase
|
||||
|
||||
@import JitsiMeetSDK;
|
||||
|
||||
#import "Types.h"
|
||||
#import "ViewController.h"
|
||||
|
||||
|
||||
@implementation ViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
JitsiMeetView *view = (JitsiMeetView *) self.view;
|
||||
view.delegate = self;
|
||||
|
||||
[view join:[[JitsiMeet sharedInstance] getInitialConferenceOptions]];
|
||||
}
|
||||
|
||||
// JitsiMeetViewDelegate
|
||||
|
||||
- (void)_onJitsiMeetViewDelegateEvent:(NSString *)name
|
||||
withData:(NSDictionary *)data {
|
||||
NSLog(
|
||||
@"[%s:%d] JitsiMeetViewDelegate %@ %@",
|
||||
__FILE__, __LINE__, name, data);
|
||||
|
||||
#if DEBUG
|
||||
NSAssert(
|
||||
[NSThread isMainThread],
|
||||
@"JitsiMeetViewDelegate %@ method invoked on a non-main thread",
|
||||
name);
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)conferenceJoined:(NSDictionary *)data {
|
||||
[self _onJitsiMeetViewDelegateEvent:@"CONFERENCE_JOINED" withData:data];
|
||||
|
||||
// Register a NSUserActivity for this conference so it can be invoked as a
|
||||
// Siri shortcut.
|
||||
NSUserActivity *userActivity
|
||||
= [[NSUserActivity alloc] initWithActivityType:JitsiMeetConferenceActivityType];
|
||||
|
||||
NSString *urlStr = data[@"url"];
|
||||
NSURL *url = [NSURL URLWithString:urlStr];
|
||||
NSString *conference = [url.pathComponents lastObject];
|
||||
|
||||
userActivity.title = [NSString stringWithFormat:@"Join %@", conference];
|
||||
userActivity.suggestedInvocationPhrase = @"Join my Jitsi meeting";
|
||||
userActivity.userInfo = @{@"url": urlStr};
|
||||
[userActivity setEligibleForSearch:YES];
|
||||
[userActivity setEligibleForPrediction:YES];
|
||||
[userActivity setPersistentIdentifier:urlStr];
|
||||
|
||||
// Subtitle
|
||||
CSSearchableItemAttributeSet *attributes
|
||||
= [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString *)kUTTypeItem];
|
||||
attributes.contentDescription = urlStr;
|
||||
userActivity.contentAttributeSet = attributes;
|
||||
|
||||
self.userActivity = userActivity;
|
||||
[userActivity becomeCurrent];
|
||||
}
|
||||
|
||||
- (void)conferenceTerminated:(NSDictionary *)data {
|
||||
[self _onJitsiMeetViewDelegateEvent:@"CONFERENCE_TERMINATED" withData:data];
|
||||
}
|
||||
|
||||
- (void)conferenceWillJoin:(NSDictionary *)data {
|
||||
[self _onJitsiMeetViewDelegateEvent:@"CONFERENCE_WILL_JOIN" withData:data];
|
||||
}
|
||||
|
||||
// - (void)customButtonPressed:(NSDictionary *)data {
|
||||
// [self _onJitsiMeetViewDelegateEvent:@"CUSTOM_BUTTON_PRESSED" withData:data];
|
||||
// }
|
||||
|
||||
#if 0
|
||||
- (void)enterPictureInPicture:(NSDictionary *)data {
|
||||
[self _onJitsiMeetViewDelegateEvent:@"ENTER_PICTURE_IN_PICTURE" withData:data];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)readyToClose:(NSDictionary *)data {
|
||||
[self _onJitsiMeetViewDelegateEvent:@"READY_TO_CLOSE" withData:data];
|
||||
}
|
||||
|
||||
// - (void)transcriptionChunkReceived:(NSDictionary *)data {
|
||||
// [self _onJitsiMeetViewDelegateEvent:@"TRANSCRIPTION_CHUNK_RECEIVED" withData:data];
|
||||
// }
|
||||
|
||||
- (void)participantJoined:(NSDictionary *)data {
|
||||
NSLog(@"%@%@", @"Participant joined: ", data[@"participantId"]);
|
||||
}
|
||||
|
||||
- (void)participantLeft:(NSDictionary *)data {
|
||||
NSLog(@"%@%@", @"Participant left: ", data[@"participantId"]);
|
||||
}
|
||||
|
||||
- (void)audioMutedChanged:(NSDictionary *)data {
|
||||
NSLog(@"%@%@", @"Audio muted changed: ", data[@"muted"]);
|
||||
}
|
||||
|
||||
- (void)endpointTextMessageReceived:(NSDictionary *)data {
|
||||
NSLog(@"%@%@", @"Endpoint text message received: ", data);
|
||||
}
|
||||
|
||||
- (void)screenShareToggled:(NSDictionary *)data {
|
||||
NSLog(@"%@%@", @"Screen share toggled: ", data);
|
||||
}
|
||||
|
||||
- (void)chatMessageReceived:(NSDictionary *)data {
|
||||
NSLog(@"%@%@", @"Chat message received: ", data);
|
||||
}
|
||||
|
||||
- (void)chatToggled:(NSDictionary *)data {
|
||||
NSLog(@"%@%@", @"Chat toggled: ", data);
|
||||
}
|
||||
|
||||
- (void)videoMutedChanged:(NSDictionary *)data {
|
||||
NSLog(@"%@%@", @"Video muted changed: ", data[@"muted"]);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Helpers
|
||||
|
||||
- (void)terminate {
|
||||
JitsiMeetView *view = (JitsiMeetView *) self.view;
|
||||
[view leave];
|
||||
}
|
||||
|
||||
@end
|
||||
94
ios/app/src/ViewController.swift
Normal file
94
ios/app/src/ViewController.swift
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright @ 2025-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import CoreSpotlight
|
||||
import Intents
|
||||
import MobileCoreServices
|
||||
import UIKit
|
||||
|
||||
import JitsiMeetSDK
|
||||
|
||||
@objcMembers
|
||||
class ViewController: UIViewController {
|
||||
|
||||
override func loadView() {
|
||||
let jitsiView = JitsiMeetView(frame: UIScreen.main.bounds)
|
||||
self.view = jitsiView
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
guard let view = self.view as? JitsiMeetView else { return }
|
||||
view.delegate = self
|
||||
view.join(JitsiMeet.sharedInstance().getInitialConferenceOptions())
|
||||
}
|
||||
|
||||
// MARK: - Helper Methods
|
||||
|
||||
func terminate() {
|
||||
guard let view = self.view as? JitsiMeetView else { return }
|
||||
view.leave()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension ViewController: @preconcurrency JitsiMeetViewDelegate {
|
||||
|
||||
// MARK: - Private Helper Methods
|
||||
|
||||
private func onJitsiMeetViewDelegateEvent(_ name: String, withData data: [AnyHashable: Any]?) {
|
||||
NSLog("[%@:%d] JitsiMeetViewDelegate %@ %@", #file, #line, name, data ?? [:])
|
||||
|
||||
#if DEBUG
|
||||
assert(Thread.isMainThread, "JitsiMeetViewDelegate \(name) method invoked on a non-main thread")
|
||||
#endif
|
||||
}
|
||||
|
||||
// MARK: - JitsiMeetViewDelegate
|
||||
|
||||
func conferenceJoined(_ data: [AnyHashable: Any]) {
|
||||
onJitsiMeetViewDelegateEvent("CONFERENCE_JOINED", withData: data)
|
||||
|
||||
// Register a NSUserActivity for this conference so it can be invoked as a Siri shortcut.
|
||||
// Must match the one defined in Info.plist
|
||||
let userActivity = NSUserActivity(activityType: "org.jitsi.JitsiMeet.ios.conference")
|
||||
|
||||
if let urlStr = data["url"] as? String,
|
||||
let url = URL(string: urlStr),
|
||||
let conference = url.pathComponents.last {
|
||||
|
||||
userActivity.title = "Join \(conference)"
|
||||
userActivity.suggestedInvocationPhrase = "Join my Jitsi meeting"
|
||||
userActivity.userInfo = ["url": urlStr]
|
||||
userActivity.isEligibleForSearch = true
|
||||
userActivity.isEligibleForPrediction = true
|
||||
userActivity.persistentIdentifier = urlStr
|
||||
|
||||
// Subtitle
|
||||
let attributes = CSSearchableItemAttributeSet(contentType: UTType.item)
|
||||
attributes.contentDescription = urlStr
|
||||
userActivity.contentAttributeSet = attributes
|
||||
|
||||
self.userActivity = userActivity
|
||||
userActivity.becomeCurrent()
|
||||
}
|
||||
}
|
||||
|
||||
func ready(toClose data: [AnyHashable: Any]) {
|
||||
onJitsiMeetViewDelegateEvent("READY_TO_CLOSE", withData: data)
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright @ 2017-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(
|
||||
argc, argv,
|
||||
nil,
|
||||
NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
}
|
||||
15
ios/patches/ws-tls13.diff
Normal file
15
ios/patches/ws-tls13.diff
Normal file
@@ -0,0 +1,15 @@
|
||||
diff --git a/SocketRocket/SRSecurityPolicy.m b/SocketRocket/SRSecurityPolicy.m
|
||||
index 3759d26e..271477e8 100644
|
||||
--- a/SocketRocket/SRSecurityPolicy.m
|
||||
+++ b/SocketRocket/SRSecurityPolicy.m
|
||||
@@ -56,8 +56,8 @@ - (instancetype)init
|
||||
|
||||
- (void)updateSecurityOptionsInStream:(NSStream *)stream
|
||||
{
|
||||
- // Enforce TLS 1.2
|
||||
- [stream setProperty:(__bridge id)CFSTR("kCFStreamSocketSecurityLevelTLSv1_2") forKey:(__bridge id)kCFStreamPropertySocketSecurityLevel];
|
||||
+ // Enforce TLS >= 1.2
|
||||
+ [stream setProperty:(__bridge id)kCFStreamSocketSecurityLevelNegotiatedSSL forKey:(__bridge id)kCFStreamPropertySocketSecurityLevel];
|
||||
|
||||
// Validate certificate chain for this stream if enabled.
|
||||
NSDictionary<NSString *, id> *sslOptions = @{ (__bridge NSString *)kCFStreamSSLValidatesCertificateChain : @(self.certificateChainValidationEnabled) };
|
||||
@@ -145,7 +145,6 @@
|
||||
4ED4FFF12721B9B90074E620 /* JitsiAudioSession.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiAudioSession.h; sourceTree = "<group>"; };
|
||||
4ED4FFF22721B9B90074E620 /* JitsiAudioSession.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JitsiAudioSession.m; sourceTree = "<group>"; };
|
||||
4ED4FFF52721BAE10074E620 /* JitsiAudioSession+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiAudioSession+Private.h"; sourceTree = "<group>"; };
|
||||
6132EF172BDFF13200BBE14D /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = ../PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
86389F55993FAAF6AEB3FA3E /* Pods-JitsiMeetSDKLite.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeetSDKLite.release.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeetSDKLite/Pods-JitsiMeetSDKLite.release.xcconfig"; sourceTree = "<group>"; };
|
||||
891FE43DAD30BC8976683100 /* Pods-JitsiMeetSDK.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeetSDK.release.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeetSDK/Pods-JitsiMeetSDK.release.xcconfig"; sourceTree = "<group>"; };
|
||||
8F48C340DE0D91D1012976C5 /* Pods-JitsiMeetSDKLite.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeetSDKLite.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-JitsiMeetSDKLite/Pods-JitsiMeetSDKLite.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
@@ -231,7 +230,6 @@
|
||||
0BD906E61EC0C00300C8C18E /* Products */,
|
||||
0BCA49681EC4BBE500B793EE /* Resources */,
|
||||
0BD906E71EC0C00300C8C18E /* src */,
|
||||
6132EF172BDFF13200BBE14D /* PrivacyInfo.xcprivacy */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -871,6 +869,7 @@
|
||||
baseConfigurationReference = 09A78016288AF50ACD28A10D /* Pods-JitsiMeetSDK.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
|
||||
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
@@ -894,8 +893,6 @@
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_INSTALL_OBJC_HEADER = NO;
|
||||
SWIFT_OBJC_INTERFACE_HEADER_NAME = "";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
@@ -907,6 +904,7 @@
|
||||
baseConfigurationReference = 891FE43DAD30BC8976683100 /* Pods-JitsiMeetSDK.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
|
||||
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
@@ -930,8 +928,6 @@
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_INSTALL_OBJC_HEADER = NO;
|
||||
SWIFT_OBJC_INTERFACE_HEADER_NAME = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -942,6 +938,7 @@
|
||||
baseConfigurationReference = 8F48C340DE0D91D1012976C5 /* Pods-JitsiMeetSDKLite.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
|
||||
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
@@ -970,8 +967,6 @@
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_INSTALL_OBJC_HEADER = NO;
|
||||
SWIFT_OBJC_INTERFACE_HEADER_NAME = "";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
@@ -983,6 +978,7 @@
|
||||
baseConfigurationReference = 86389F55993FAAF6AEB3FA3E /* Pods-JitsiMeetSDKLite.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
|
||||
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
@@ -1011,8 +1007,6 @@
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_INSTALL_OBJC_HEADER = NO;
|
||||
SWIFT_OBJC_INTERFACE_HEADER_NAME = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
|
||||
@@ -27,9 +27,15 @@ static NSString * const sendEventNotificationName = @"org.jitsi.meet.SendEvent";
|
||||
- (void)retrieveParticipantsInfo:(void (^)(NSArray*))completion;
|
||||
- (void)openChat:(NSString*)to;
|
||||
- (void)closeChat;
|
||||
- (void)sendChatMessage:(NSString*)message :(NSString*)to ;
|
||||
- (void)sendChatMessage:(NSString*)message :(NSString*)to;
|
||||
- (void)sendSetVideoMuted:(BOOL)muted;
|
||||
- (void)sendSetClosedCaptionsEnabled:(BOOL)enabled;
|
||||
- (void)toggleCamera;
|
||||
- (void)showNotification:(NSString*)appearance :(NSString*)description :(NSString*)timeout :(NSString*)title :(NSString*)uid;
|
||||
- (void)hideNotification:(NSString*)uid;
|
||||
- (void)startRecording:(NSString*)mode :(NSString*)dropboxToken :(BOOL)shouldShare :(NSString*)rtmpStreamKey :(NSString*)rtmpBroadcastID :(NSString*)youtubeStreamKey :(NSString*)youtubeBroadcastID :(NSDictionary*)extraMetadata :(BOOL)transcription;
|
||||
- (void)stopRecording:(NSString*)mode :(BOOL)transcription;
|
||||
- (void)overwriteConfig:(NSDictionary*)config;
|
||||
- (void)sendCameraFacingModeMessage:(NSString*)to :(NSString*)facingMode;
|
||||
|
||||
@end
|
||||
|
||||
@@ -28,13 +28,19 @@ static NSString * const sendChatMessageAction = @"org.jitsi.meet.SEND_CHAT_MESSA
|
||||
static NSString * const setVideoMutedAction = @"org.jitsi.meet.SET_VIDEO_MUTED";
|
||||
static NSString * const setClosedCaptionsEnabledAction = @"org.jitsi.meet.SET_CLOSED_CAPTIONS_ENABLED";
|
||||
static NSString * const toggleCameraAction = @"org.jitsi.meet.TOGGLE_CAMERA";
|
||||
static NSString * const showNotificationAction = @"org.jitsi.meet.SHOW_NOTIFICATION";
|
||||
static NSString * const hideNotificationAction = @"org.jitsi.meet.HIDE_NOTIFICATION";
|
||||
static NSString * const startRecordingAction = @"org.jitsi.meet.START_RECORDING";
|
||||
static NSString * const stopRecordingAction = @"org.jitsi.meet.STOP_RECORDING";
|
||||
static NSString * const overwriteConfigAction = @"org.jitsi.meet.OVERWRITE_CONFIG";
|
||||
static NSString * const sendCameraFacingModeMessageAction = @"org.jitsi.meet.SEND_CAMERA_FACING_MODE_MESSAGE";
|
||||
|
||||
@implementation ExternalAPI
|
||||
|
||||
static NSMapTable<NSString*, void (^)(NSArray* participantsInfo)> *participantInfoCompletionHandlers;
|
||||
|
||||
__attribute__((constructor))
|
||||
static void initializeViewsMap() {
|
||||
static void initializeViewsMap(void) {
|
||||
participantInfoCompletionHandlers = [NSMapTable strongToStrongObjectsMapTable];
|
||||
}
|
||||
|
||||
@@ -52,7 +58,13 @@ RCT_EXPORT_MODULE();
|
||||
@"SEND_CHAT_MESSAGE": sendChatMessageAction,
|
||||
@"SET_VIDEO_MUTED" : setVideoMutedAction,
|
||||
@"SET_CLOSED_CAPTIONS_ENABLED": setClosedCaptionsEnabledAction,
|
||||
@"TOGGLE_CAMERA": toggleCameraAction
|
||||
@"TOGGLE_CAMERA": toggleCameraAction,
|
||||
@"SHOW_NOTIFICATION": showNotificationAction,
|
||||
@"HIDE_NOTIFICATION": hideNotificationAction,
|
||||
@"START_RECORDING": startRecordingAction,
|
||||
@"STOP_RECORDING": stopRecordingAction,
|
||||
@"OVERWRITE_CONFIG": overwriteConfigAction,
|
||||
@"SEND_CAMERA_FACING_MODE_MESSAGE": sendCameraFacingModeMessageAction
|
||||
};
|
||||
};
|
||||
|
||||
@@ -78,7 +90,13 @@ RCT_EXPORT_MODULE();
|
||||
sendChatMessageAction,
|
||||
setVideoMutedAction,
|
||||
setClosedCaptionsEnabledAction,
|
||||
toggleCameraAction
|
||||
toggleCameraAction,
|
||||
showNotificationAction,
|
||||
hideNotificationAction,
|
||||
startRecordingAction,
|
||||
stopRecordingAction,
|
||||
overwriteConfigAction,
|
||||
sendCameraFacingModeMessageAction
|
||||
];
|
||||
}
|
||||
|
||||
@@ -180,4 +198,63 @@ RCT_EXPORT_METHOD(sendEvent:(NSString *)name
|
||||
[self sendEventWithName:toggleCameraAction body:nil];
|
||||
}
|
||||
|
||||
- (void)showNotification:(NSString*)appearance :(NSString*)description :(NSString*)timeout :(NSString*)title :(NSString*)uid {
|
||||
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
|
||||
data[@"appearance"] = appearance;
|
||||
data[@"description"] = description;
|
||||
data[@"timeout"] = timeout;
|
||||
data[@"title"] = title;
|
||||
data[@"uid"] = uid;
|
||||
|
||||
[self sendEventWithName:showNotificationAction body:data];
|
||||
}
|
||||
|
||||
- (void)hideNotification:(NSString*)uid {
|
||||
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
|
||||
data[@"uid"] = uid;
|
||||
|
||||
[self sendEventWithName:hideNotificationAction body:data];
|
||||
}
|
||||
|
||||
- (void)startRecording:(NSString*)mode :(NSString*)dropboxToken :(BOOL)shouldShare :(NSString*)rtmpStreamKey :(NSString*)rtmpBroadcastID :(NSString*)youtubeStreamKey :(NSString*)youtubeBroadcastID :(NSDictionary*)extraMetadata :(BOOL)transcription {
|
||||
NSDictionary *data = @{
|
||||
@"mode": mode,
|
||||
@"dropboxToken": dropboxToken,
|
||||
@"shouldShare": @(shouldShare),
|
||||
@"rtmpStreamKey": rtmpStreamKey,
|
||||
@"rtmpBroadcastID": rtmpBroadcastID,
|
||||
@"youtubeStreamKey": youtubeStreamKey,
|
||||
@"youtubeBroadcastID": youtubeBroadcastID,
|
||||
@"extraMetadata": extraMetadata,
|
||||
@"transcription": @(transcription)
|
||||
};
|
||||
|
||||
[self sendEventWithName:startRecordingAction body:data];
|
||||
}
|
||||
|
||||
- (void)stopRecording:(NSString*)mode :(BOOL)transcription {
|
||||
NSDictionary *data = @{
|
||||
@"mode": mode,
|
||||
@"transcription": @(transcription)
|
||||
};
|
||||
|
||||
[self sendEventWithName:stopRecordingAction body:data];
|
||||
}
|
||||
|
||||
- (void)overwriteConfig:(NSDictionary*)config {
|
||||
NSDictionary *data = @{
|
||||
@"config": config
|
||||
};
|
||||
|
||||
[self sendEventWithName:overwriteConfigAction body:data];
|
||||
}
|
||||
|
||||
- (void)sendCameraFacingModeMessage:(NSString*)to :(NSString*)facingMode {
|
||||
NSDictionary *data = @{
|
||||
@"to": to,
|
||||
@"facingMode": facingMode
|
||||
};
|
||||
|
||||
[self sendEventWithName:sendCameraFacingModeMessageAction body:data];
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -19,6 +19,15 @@
|
||||
|
||||
#import <JitsiMeetSDK/JitsiMeetConferenceOptions.h>
|
||||
|
||||
// Matches RTCLoggingSeverity from RTCLogging.h
|
||||
typedef NS_ENUM(NSInteger, WebRTCLoggingSeverity) {
|
||||
WebRTCLoggingSeverityVerbose,
|
||||
WebRTCLoggingSeverityInfo,
|
||||
WebRTCLoggingSeverityWarning,
|
||||
WebRTCLoggingSeverityError,
|
||||
WebRTCLoggingSeverityNone,
|
||||
};
|
||||
|
||||
@interface JitsiMeet : NSObject
|
||||
|
||||
/**
|
||||
@@ -26,20 +35,35 @@
|
||||
* SiriKit or Handoff, for example.
|
||||
*/
|
||||
@property (copy, nonatomic, nullable) NSString *conferenceActivityType;
|
||||
|
||||
/**
|
||||
* Custom URL scheme used for deep-linking.
|
||||
*/
|
||||
@property (copy, nonatomic, nullable) NSString *customUrlScheme;
|
||||
|
||||
/**
|
||||
* List of domains used for universal linking.
|
||||
*/
|
||||
@property (copy, nonatomic, nullable) NSArray<NSString *> *universalLinkDomains;
|
||||
|
||||
/**
|
||||
* Default conference options used for all conferences. These options will be merged
|
||||
* with those passed to JitsiMeetView.join when joining a conference.
|
||||
*/
|
||||
@property (nonatomic, nullable) JitsiMeetConferenceOptions *defaultConferenceOptions;
|
||||
|
||||
/**
|
||||
* Custom RTCAudioDevice implementation.
|
||||
* https://github.com/jitsi/webrtc/blob/M124/sdk/objc/components/audio/RTCAudioDevice.h
|
||||
* https://github.com/mstyura/RTCAudioDevice
|
||||
*/
|
||||
@property (nonatomic, strong, nullable) id rtcAudioDevice;
|
||||
|
||||
/**
|
||||
* Specify WebRTC logging severity.
|
||||
*/
|
||||
@property (nonatomic, assign) WebRTCLoggingSeverity webRtcLoggingSeverity;
|
||||
|
||||
#pragma mark - This class is a singleton
|
||||
|
||||
+ (instancetype _Nonnull)sharedInstance;
|
||||
@@ -58,7 +82,7 @@
|
||||
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *_Nonnull)options;
|
||||
|
||||
- (UIInterfaceOrientationMask)application:(UIApplication *_Nonnull)application
|
||||
supportedInterfaceOrientationsForWindow:(UIWindow *_Nonnull)window;
|
||||
supportedInterfaceOrientationsForWindow:(UIWindow *_Nullable)window;
|
||||
|
||||
#pragma mark - Utility methods
|
||||
|
||||
|
||||
@@ -54,14 +54,9 @@
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
#if 0
|
||||
// Initialize WebRTC options.
|
||||
WebRTCModuleOptions *options = [WebRTCModuleOptions sharedInstance];
|
||||
options.loggingSeverity = RTCLoggingSeverityInfo;
|
||||
#endif
|
||||
|
||||
// Initialize the one and only bridge for interfacing with React Native.
|
||||
_bridgeWrapper = [[RCTBridgeWrapper alloc] init];
|
||||
self.rtcAudioDevice = nil;
|
||||
self.webRtcLoggingSeverity = WebRTCLoggingSeverityNone;
|
||||
|
||||
// Initialize the listener for handling start/stop screensharing notifications.
|
||||
_screenshareEventEmiter = [[ScheenshareEventEmiter alloc] init];
|
||||
@@ -142,6 +137,12 @@
|
||||
return;
|
||||
};
|
||||
|
||||
// Initialize WebRTC options.
|
||||
WebRTCModuleOptions *options = [WebRTCModuleOptions sharedInstance];
|
||||
options.audioDevice = _rtcAudioDevice;
|
||||
options.loggingSeverity = (RTCLoggingSeverity)_webRtcLoggingSeverity;
|
||||
|
||||
// Initialize the one and only bridge for interfacing with React Native.
|
||||
_bridgeWrapper = [[RCTBridgeWrapper alloc] init];
|
||||
}
|
||||
|
||||
@@ -249,6 +250,8 @@
|
||||
}
|
||||
|
||||
- (RCTBridge *)getReactBridge {
|
||||
// Initialize bridge lazily.
|
||||
[self instantiateReactNativeBridge];
|
||||
return _bridgeWrapper.bridge;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
#import "JitsiMeetConferenceOptions.h"
|
||||
#import "JitsiMeetViewDelegate.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, RecordingMode) {
|
||||
RecordingModeFile,
|
||||
RecordingModeStream
|
||||
};
|
||||
|
||||
@interface JitsiMeetView : UIView
|
||||
|
||||
@property (nonatomic, nullable, weak) id<JitsiMeetViewDelegate> delegate;
|
||||
@@ -47,5 +52,10 @@
|
||||
- (void)setVideoMuted:(BOOL)muted;
|
||||
- (void)setClosedCaptionsEnabled:(BOOL)enabled;
|
||||
- (void)toggleCamera;
|
||||
|
||||
- (void)showNotification:(NSString * _Nonnull)appearance :(NSString * _Nullable)description :(NSString * _Nullable)timeout :(NSString * _Nullable)title :(NSString * _Nullable)uid;
|
||||
- (void)hideNotification:(NSString * _Nullable)uid;
|
||||
- (void)startRecording:(RecordingMode)mode :(NSString * _Nullable)dropboxToken :(BOOL)shouldShare :(NSString * _Nullable)rtmpStreamKey :(NSString * _Nullable)rtmpBroadcastID :(NSString * _Nullable)youtubeStreamKey :(NSString * _Nullable)youtubeBroadcastID :(NSDictionary * _Nullable)extraMetadata :(BOOL)transcription;
|
||||
- (void)stopRecording:(RecordingMode)mode :(BOOL)transcription;
|
||||
- (void)overwriteConfig:(NSDictionary * _Nonnull)config;
|
||||
- (void)sendCameraFacingModeMessage:(NSString * _Nonnull)to :(NSString * _Nullable)facingMode;
|
||||
@end
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "ExternalAPI.h"
|
||||
#import "JitsiMeet+Private.h"
|
||||
#import "JitsiMeetConferenceOptions+Private.h"
|
||||
@@ -25,11 +27,43 @@
|
||||
#import "RNRootView.h"
|
||||
|
||||
|
||||
#pragma mark UIColor helpers
|
||||
|
||||
@interface UIColor (Hex)
|
||||
|
||||
+ (UIColor *)colorWithHex:(uint32_t)hex;
|
||||
+ (UIColor *)colorWithHex:(uint32_t)hex alpha:(CGFloat)alpha;
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIColor (Hex)
|
||||
|
||||
+ (UIColor *)colorWithHex:(uint32_t)hex {
|
||||
return [self colorWithHex:hex alpha:1.0];
|
||||
}
|
||||
|
||||
+ (UIColor *)colorWithHex:(uint32_t)hex alpha:(CGFloat)alpha {
|
||||
CGFloat red = ((hex >> 16) & 0xFF) / 255.0;
|
||||
CGFloat green = ((hex >> 8) & 0xFF) / 255.0;
|
||||
CGFloat blue = (hex & 0xFF) / 255.0;
|
||||
|
||||
return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark UIColor helpers end
|
||||
|
||||
/**
|
||||
* Backwards compatibility: turn the boolean prop into a feature flag.
|
||||
*/
|
||||
static NSString *const PiPEnabledFeatureFlag = @"pip.enabled";
|
||||
|
||||
/**
|
||||
* Forward declarations.
|
||||
*/
|
||||
static NSString *recordingModeToString(RecordingMode mode);
|
||||
|
||||
|
||||
@implementation JitsiMeetView {
|
||||
/**
|
||||
@@ -65,11 +99,8 @@ static NSString *const PiPEnabledFeatureFlag = @"pip.enabled";
|
||||
* - registers necessary observers
|
||||
*/
|
||||
- (void)doInitialize {
|
||||
// Set a background color which is in accord with the JavaScript and Android
|
||||
// parts of the application and causes less perceived visual flicker than
|
||||
// the default background color.
|
||||
self.backgroundColor
|
||||
= [UIColor colorWithRed:.07f green:.07f blue:.07f alpha:1];
|
||||
// Set a background color which matches the one used in JS.
|
||||
self.backgroundColor = [UIColor colorWithHex:0x040404 alpha:1];
|
||||
|
||||
[self registerObservers];
|
||||
}
|
||||
@@ -143,6 +174,36 @@ static NSString *const PiPEnabledFeatureFlag = @"pip.enabled";
|
||||
[externalAPI toggleCamera];
|
||||
}
|
||||
|
||||
- (void)showNotification:(NSString *)appearance :(NSString *)description :(NSString *)timeout :(NSString *)title :(NSString *)uid {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI showNotification:appearance :description :timeout :title :uid];
|
||||
}
|
||||
|
||||
-(void)hideNotification:(NSString *)uid {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI hideNotification:uid];
|
||||
}
|
||||
|
||||
- (void)startRecording:(RecordingMode)mode :(NSString * _Nullable)dropboxToken :(BOOL)shouldShare :(NSString * _Nullable)rtmpStreamKey :(NSString * _Nullable)rtmpBroadcastID :(NSString * _Nullable)youtubeStreamKey :(NSString * _Nullable)youtubeBroadcastID :(NSDictionary * _Nullable)extraMetadata :(BOOL)transcription {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI startRecording:recordingModeToString(mode) :dropboxToken :shouldShare :rtmpStreamKey :rtmpBroadcastID :youtubeStreamKey :youtubeBroadcastID :extraMetadata :transcription];
|
||||
}
|
||||
|
||||
- (void)stopRecording:(RecordingMode)mode :(BOOL)transcription {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI stopRecording:recordingModeToString(mode) :transcription];
|
||||
}
|
||||
|
||||
- (void)overwriteConfig:(NSDictionary * _Nonnull)config {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI overwriteConfig:config];
|
||||
}
|
||||
|
||||
- (void)sendCameraFacingModeMessage:(NSString * _Nonnull)to :(NSString * _Nullable)facingMode {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI sendCameraFacingModeMessage:to :facingMode];
|
||||
}
|
||||
|
||||
#pragma mark Private methods
|
||||
|
||||
- (void)registerObservers {
|
||||
@@ -237,3 +298,14 @@ static NSString *const PiPEnabledFeatureFlag = @"pip.enabled";
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static NSString *recordingModeToString(RecordingMode mode) {
|
||||
switch (mode) {
|
||||
case RecordingModeFile:
|
||||
return @"file";
|
||||
case RecordingModeStream:
|
||||
return @"stream";
|
||||
default:
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,4 +130,18 @@
|
||||
*/
|
||||
- (void)customButtonPressed:(NSDictionary *)data;
|
||||
|
||||
/**
|
||||
* Called when the unique identifier for conference has been set.
|
||||
*
|
||||
* The `data` dictionary contains a `sessionId` key.
|
||||
*/
|
||||
- (void)conferenceUniqueIdSet:(NSDictionary *)data;
|
||||
|
||||
/**
|
||||
* Called when the recording status has changed.
|
||||
*
|
||||
* The `data` dictionary contains a `sessionData` key.
|
||||
*/
|
||||
- (void)recordingStatusChanged:(NSDictionary *)data;
|
||||
|
||||
@end
|
||||
|
||||
@@ -37,7 +37,9 @@
|
||||
"ml": "മലയാളം",
|
||||
"mn": "Монгол",
|
||||
"mr": "मराठी",
|
||||
"nb": "Norsk bokmål",
|
||||
"nl": "Nederlands",
|
||||
"no": "Norsk",
|
||||
"oc": "Occitan",
|
||||
"pl": "Polski",
|
||||
"pt": "Português",
|
||||
|
||||
@@ -944,6 +944,7 @@
|
||||
"title": "خيارات الأمان"
|
||||
},
|
||||
"settings": {
|
||||
"audio": "الصوت",
|
||||
"buttonLabel": "إعدادات",
|
||||
"calendar": {
|
||||
"about": "تُستعمَل الرزنامة {{appName}} المدمجة للوصل بأمان إلى رزنامتك، لذا بالإمكان معرفة الأحداث القادمة.",
|
||||
@@ -967,6 +968,7 @@
|
||||
"more": "المزيد",
|
||||
"name": "الاسم",
|
||||
"noDevice": "لا يوجد",
|
||||
"notifications": "الإشعارات",
|
||||
"participantJoined": "انضم مشارك",
|
||||
"participantKnocking": "دخل المشارك في الردهة",
|
||||
"participantLeft": "غادر المشارك",
|
||||
@@ -977,13 +979,15 @@
|
||||
"selectCamera": "الكاميرا",
|
||||
"selectMic": "المايكروفون",
|
||||
"selfView": "عرض ذاتي",
|
||||
"shortcuts": "اختصارات لوحة المفاتيح",
|
||||
"sounds": "اصوات",
|
||||
"speakers": "المذياع (مكبر الصوت)",
|
||||
"startAudioMuted": "بدء الجميع مكتومي الصوت",
|
||||
"startReactionsMuted": "كتم رد فعل الصوت للجميع",
|
||||
"startVideoMuted": "بدء الجميع دون فيديو",
|
||||
"talkWhileMuted": "تحدث أثناء كتم الصوت",
|
||||
"title": "الإعدادات"
|
||||
"title": "الإعدادات",
|
||||
"video": "الفيديو"
|
||||
},
|
||||
"settingsView": {
|
||||
"advanced": "إعدادات متقدمة",
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"failedToAdd": "Fehler beim Hinzufügen von Personen",
|
||||
"googleEmail": "Google-E-Mail",
|
||||
"inviteMoreHeader": "Sie sind alleine in der Sitzung",
|
||||
"inviteMoreMailSubject": "An {{appName}} Meeting teilnehmen",
|
||||
"inviteMoreMailSubject": "An {{appName}} Konferenz teilnehmen",
|
||||
"inviteMorePrompt": "Mehr Leute einladen",
|
||||
"linkCopied": "Link in die Zwischenablage kopiert",
|
||||
"noResults": "Keine passenden Ergebnisse",
|
||||
@@ -70,14 +70,14 @@
|
||||
"breakoutList": "Breakout-Liste",
|
||||
"buttonLabel": "Breakout-Räume",
|
||||
"defaultName": "Breakout-Raum #{{index}}",
|
||||
"hideParticipantList": "Teilnehmerliste ausblenden",
|
||||
"hideParticipantList": "Personenliste ausblenden",
|
||||
"mainRoom": "Hauptraum",
|
||||
"notifications": {
|
||||
"joined": "Breakout-Raum \"{{name}}\" betreten",
|
||||
"joinedMainRoom": "Hauptraum betreten",
|
||||
"joinedTitle": "Breakout-Räume"
|
||||
},
|
||||
"showParticipantList": "Teilnehmerliste anzeigen",
|
||||
"showParticipantList": "Personenliste anzeigen",
|
||||
"title": "Breakout-Räume"
|
||||
},
|
||||
"calendarSync": {
|
||||
@@ -89,10 +89,10 @@
|
||||
"notSignedIn": "Ein Fehler ist während der Authentifizierung zur Anzeige von Kalenderterminen aufgetreten. Prüfen Sie Ihre Kalendereinstellungen oder versuchen Sie, sich erneut anzumelden."
|
||||
},
|
||||
"join": "Teilnehmen",
|
||||
"joinTooltip": "Am Meeting teilnehmen",
|
||||
"joinTooltip": "An Konferenz teilnehmen",
|
||||
"nextMeeting": "Nächste Konferenz",
|
||||
"noEvents": "Es gibt keine bevorstehenden Termine.",
|
||||
"ongoingMeeting": "Laufendes Meeting",
|
||||
"ongoingMeeting": "Laufende Konferenz",
|
||||
"permissionButton": "Einstellungen öffnen",
|
||||
"permissionMessage": "Die App benötigt Zugriff auf den Kalender, um Termine und Konferenzen anzuzeigen.",
|
||||
"refresh": "Kalender aktualisieren",
|
||||
@@ -145,7 +145,7 @@
|
||||
"installExtensionText": "Installieren Sie die Erweiterung für die Integration von Google Calendar und Office 365"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
"joiningRoom": "Eine Verbindung zu Ihrem Meeting wird hergestellt…"
|
||||
"joiningRoom": "Eine Verbindung zu Ihrer Konferenz wird hergestellt…"
|
||||
},
|
||||
"connection": {
|
||||
"ATTACHED": "Angehängt",
|
||||
@@ -215,7 +215,7 @@
|
||||
"downloadMobileApp": "Aus dem App Store herunterladen",
|
||||
"ifDoNotHaveApp": "Wenn Sie die App noch nicht haben:",
|
||||
"ifHaveApp": "Wenn Sie die App bereits haben:",
|
||||
"joinInApp": "Mit der App am Meeting teilnehmen",
|
||||
"joinInApp": "Mit der App an der Konferenz teilnehmen",
|
||||
"joinInAppNew": "Mit der App",
|
||||
"joinInBrowser": "Im Browser",
|
||||
"launchMeetingLabel": "Wie möchten Sie an der Konferenz teilnehmen?",
|
||||
@@ -258,7 +258,7 @@
|
||||
"dialog": {
|
||||
"Back": "Zurück",
|
||||
"Cancel": "Abbrechen",
|
||||
"IamHost": "Ich leite das Meeting",
|
||||
"IamHost": "Ich leite die Konferenz",
|
||||
"Ok": "OK",
|
||||
"Remove": "Entfernen",
|
||||
"Share": "Teilen",
|
||||
@@ -317,7 +317,7 @@
|
||||
"e2eeLabel": "Ende-zu-Ende-Verschlüsselung aktivieren",
|
||||
"e2eeWarning": "WARNUNG: Nicht alle Personen dieser Konferenz scheinen Ende-zu-Ende-Verschlüsselung zu unterstützen. Wenn Sie diese aktivieren, können die entsprechenden Personen nichts mehr sehen oder hören.",
|
||||
"e2eeWillDisableDueToMaxModeDescription": "WARNUNG: Ende-zu-Ende-Verschlüsselung wird automatisch deaktiviert, wenn weitere Anwesende an der Konferenz teilnehmen.",
|
||||
"embedMeeting": "Besprechung einbetten",
|
||||
"embedMeeting": "Konferenz einbetten",
|
||||
"enterDisplayName": "Bitte geben Sie hier Ihren Namen ein",
|
||||
"error": "Fehler",
|
||||
"errorRoomCreationRestriction": "Sie haben versucht, zu schnell beizutreten, bitte versuchen Sie es gleich noch einmal.",
|
||||
@@ -334,7 +334,8 @@
|
||||
"kickParticipantButton": "Entfernen",
|
||||
"kickParticipantDialog": "Wollen Sie diese Person wirklich entfernen?",
|
||||
"kickParticipantTitle": "Person entfernen?",
|
||||
"kickTitle": "Autsch! {{participantDisplayName}} hat Sie aus dem Meeting geworfen",
|
||||
"kickSystemTitle": "Autsch! Sie wurden aus der Konferenz geworfen",
|
||||
"kickTitle": "Autsch! {{participantDisplayName}} hat Sie aus der Konferenz geworfen",
|
||||
"linkMeeting": "Konferenz verlinken",
|
||||
"linkMeetingTitle": "Konferenz mit Salesforce verlinken",
|
||||
"liveStreaming": "Livestreaming",
|
||||
@@ -362,18 +363,18 @@
|
||||
"muteEveryoneDialogModerationOn": "Die Anwesenden können eine Anfrage zum Sprechen jederzeit senden.",
|
||||
"muteEveryoneElseDialog": "Einmal stummgeschaltet, können Sie deren Stummschaltung nicht mehr beenden, aber sie können ihre Stummschaltung jederzeit selbst beenden.",
|
||||
"muteEveryoneElseTitle": "Alle außer {{whom}} stummschalten?",
|
||||
"muteEveryoneElsesVideoDialog": "Sobald die Kamera deaktiviert ist, können Sie sie nicht wieder aktivieren, die Teilnehmer können dies aber jederzeit wieder ändern.",
|
||||
"muteEveryoneElsesVideoDialog": "Sobald die Kamera für alle anderen Personen deaktiviert ist, können Sie diese nicht wieder für alle einschalten, die anderen Personen können ihre Kamera aber jederzeit wieder einschalten.",
|
||||
"muteEveryoneElsesVideoTitle": "Die Kamera von allen außer {{whom}} ausschalten?",
|
||||
"muteEveryoneSelf": "sich selbst",
|
||||
"muteEveryoneStartMuted": "Alle beginnen von jetzt an stummgeschaltet",
|
||||
"muteEveryoneTitle": "Alle stummschalten?",
|
||||
"muteEveryonesVideoDialog": "Sind Sie sicher, dass Sie die Kamera von allen Teilnehmern deaktivieren möchten? Sie können sie nicht wieder aktivieren, die Teilnehmer können dies aber jederzeit wieder ändern.",
|
||||
"muteEveryonesVideoDialog": "Sind Sie sicher, dass Sie die Kamera von allen Personen deaktivieren möchten? Sie können dies nicht wieder rückgängig machen, jede Personen kann ihre Kamera aber jederzeit wieder einschalten.",
|
||||
"muteEveryonesVideoDialogModerationOn": "Die Anwesenden können jederzeit eine Anfrage senden, um ihre Kamera einzuschalten.",
|
||||
"muteEveryonesVideoDialogOk": "deaktivieren",
|
||||
"muteEveryonesVideoTitle": "Die Kamera von allen anderen ausschalten?",
|
||||
"muteParticipantBody": "Sie können die Stummschaltung anderer Personen nicht aufheben, aber eine Person kann ihre eigene Stummschaltung jederzeit beenden.",
|
||||
"muteParticipantButton": "Stummschalten",
|
||||
"muteParticipantsVideoBody": "Sie können die Kamera nicht wieder aktivieren, die Teilnehmer können dies aber jederzeit wieder ändern.",
|
||||
"muteParticipantsVideoBody": "Sie können die Kamera nicht wieder einschalten, die Person kann ihre Kamera aber jederzeit wieder einschalten.",
|
||||
"muteParticipantsVideoBodyModerationOn": "Sie können die Kamera nicht wieder aktivieren und die Person selbst auch nicht.",
|
||||
"muteParticipantsVideoButton": "Kamera ausschalten",
|
||||
"muteParticipantsVideoDialog": "Wollen Sie die Kamera dieser Person wirklich deaktivieren? Sie können die Kamera nicht wieder aktivieren, die Person kann dies aber jederzeit selbst tun.",
|
||||
@@ -381,7 +382,7 @@
|
||||
"muteParticipantsVideoTitle": "Die Kamera von dieser Person ausschalten?",
|
||||
"noDropboxToken": "Kein gültiges Dropbox-Token",
|
||||
"password": "Passwort",
|
||||
"passwordLabel": "Dieses Meeting wurde gesichert. Bitte geben Sie das $t(lockRoomPasswordUppercase) ein, um dem Meeting beizutreten.",
|
||||
"passwordLabel": "Diese Konferenz wurde gesichert. Bitte geben Sie das $t(lockRoomPasswordUppercase) ein, um der Konferenz beizutreten.",
|
||||
"passwordNotSupported": "Das Festlegen eines Konferenzpassworts wird nicht unterstützt.",
|
||||
"passwordNotSupportedTitle": "$t(lockRoomPasswordUppercase) nicht unterstützt",
|
||||
"passwordRequired": "$t(lockRoomPasswordUppercase) erforderlich",
|
||||
@@ -555,13 +556,13 @@
|
||||
"invitePhone": "Wenn Sie stattdessen per Telefon beitreten möchten, wählen sie: {{number}},,{{conferenceID}}#\n",
|
||||
"invitePhoneAlternatives": "Suchen Sie nach einer anderen Einwahlnummer ?\nEinwahlnummern der Konferenz anzeigen: {{url}}\n\n\nWenn Sie sich auch über ein Raumtelefon einwählen, nehmen Sie teil, ohne sich mit dem Ton zu verbinden: {{silentUrl}}",
|
||||
"inviteSipEndpoint": "Um mit SIP teilzunehmen, folgende Adresse nutzen: {{sipUri}}",
|
||||
"inviteTextiOSInviteUrl": "Am Meeting teilnehmen: {{inviteUrl}}.",
|
||||
"inviteTextiOSInviteUrl": "An Konferenz teilnehmen: {{inviteUrl}}.",
|
||||
"inviteTextiOSJoinSilent": "Wenn Sie über ein Konferenztelefon teilnehmen, können Sie diesen Link nutzen um ohne Ton an der Konferenz teilzunehmen: {{silentUrl}}.",
|
||||
"inviteTextiOSPersonal": "{{name}} lädt Sie zu einem Meeting ein.",
|
||||
"inviteTextiOSPersonal": "{{name}} lädt Sie zu einer Konferenz ein.",
|
||||
"inviteTextiOSPhone": "Nutzen Sie folgende Nummer um via Telefon teilzunehmen: {{number}},,{{conferenceID}}#. Wenn Sie nach einer anderen Einwahlnummer suchen, finden Sie die vollständige Liste hier: {{didUrl}}.",
|
||||
"inviteURLFirstPartGeneral": "Sie wurden zur Teilnahme an einem Meeting eingeladen.",
|
||||
"inviteURLFirstPartPersonal": "{{name}} lädt Sie zu einem Meeting ein.\n",
|
||||
"inviteURLSecondPart": "\nAm Meeting teilnehmen:\n{{url}}\n",
|
||||
"inviteURLFirstPartGeneral": "Sie wurden zur Teilnahme an einer Konferenz eingeladen.",
|
||||
"inviteURLFirstPartPersonal": "{{name}} lädt Sie zu einer Konferenz ein.\n",
|
||||
"inviteURLSecondPart": "\nAn Konferenz teilnehmen:\n{{url}}\n",
|
||||
"label": "Einwahlinformationen",
|
||||
"liveStreamURL": "Livestream:",
|
||||
"moreNumbers": "Weitere Telefonnummern",
|
||||
@@ -575,7 +576,7 @@
|
||||
"sip": "SIP-Adresse",
|
||||
"sipAudioOnly": "SIP-Adresse (nur Ton)",
|
||||
"title": "Teilen",
|
||||
"tooltip": "Freigabe-Link und Einwahlinformationen für dieses Meeting",
|
||||
"tooltip": "Freigabe-Link und Einwahlinformationen für diese Konferenz",
|
||||
"upgradeOptions": "Bitte prüfen Sie Ihre Upgrade-Optionen auf",
|
||||
"whiteboardError": "Whiteboard konnte nicht geladen werden. Bitte versuchen Sie es später erneut."
|
||||
},
|
||||
@@ -627,7 +628,7 @@
|
||||
"errorAPI": "Beim Abrufen der YouTube-Livestreams ist ein Fehler aufgetreten. Bitte versuchen Sie, sich erneut anzumelden.",
|
||||
"errorLiveStreamNotEnabled": "Livestreaming ist für {{email}} nicht aktiviert. Aktivieren Sie das Livestreaming oder melden Sie sich bei einem Konto mit aktiviertem Livestreaming an.",
|
||||
"expandedOff": "Livestream wurde angehalten",
|
||||
"expandedOn": "Das Meeting wird momentan an YouTube gestreamt.",
|
||||
"expandedOn": "Die Konferenz wird momentan an YouTube gestreamt.",
|
||||
"expandedPending": "Livestream wird gestartet …",
|
||||
"failedToStart": "Livestream konnte nicht gestartet werden",
|
||||
"getStreamKeyManually": "Wir waren nicht in der Lage, Livestreams abzurufen. Versuchen Sie, Ihren Livestream-Schlüssel von YouTube zu erhalten.",
|
||||
@@ -641,6 +642,7 @@
|
||||
"on": "Livestream",
|
||||
"onBy": "{{name}} startete den Livestream",
|
||||
"pending": "Livestream wird gestartet …",
|
||||
"policyError": "Sie haben den Livestream zu schnell gestartet. Bitte versuchen Sie es später noch einmal!",
|
||||
"serviceName": "Livestreaming-Dienst",
|
||||
"sessionAlreadyActive": "Diese Konferenz wird bereits als Livestream übertragen.",
|
||||
"signIn": "Mit Google anmelden",
|
||||
@@ -731,14 +733,17 @@
|
||||
"me": "ich",
|
||||
"notify": {
|
||||
"OldElectronAPPTitle": "Sicherheitslücke!",
|
||||
"allowAction": "Erlauben",
|
||||
"allowAudio": "Mikrofon einschalten",
|
||||
"allowBoth": "Beides",
|
||||
"allowVideo": "Kamera einschalten",
|
||||
"allowedUnmute": "Sie können die Stummschaltung aufheben, Ihre Kamera einschalten oder Ihren Bildschirm teilen.",
|
||||
"audioUnmuteBlockedDescription": "Díe Stummschaltung kann aus Überlastungsschutzgründen temporär nicht aufgehoben werden.",
|
||||
"audioUnmuteBlockedTitle": "Stummschaltung kann nicht aufgehoben werden!",
|
||||
"chatMessages": "Chatnachrichten",
|
||||
"connectedOneMember": "{{name}} nimmt am Meeting teil",
|
||||
"connectedThreePlusMembers": "{{name}} und {{count}} andere Personen nehmen am Meeting teil",
|
||||
"connectedTwoMembers": "{{first}} und {{second}} nehmen am Meeting teil",
|
||||
"connectedOneMember": "{{name}} nimmt an der Konferenz teil",
|
||||
"connectedThreePlusMembers": "{{name}} und {{count}} andere Personen nehmen an der Konferenz teil",
|
||||
"connectedTwoMembers": "{{first}} und {{second}} nehmen an der Konferenz teil",
|
||||
"connectionFailed": "Verbindung fehlgeschlagen. Bitte versuchen Sie es später noch einmal!",
|
||||
"dataChannelClosed": "Schlechte Videoqualität",
|
||||
"dataChannelClosedDescription": "Die Steuerungsverbindung (Bridge Channel) wurde unterbrochen, daher ist die Videoqulität auf die schlechteste Stufe limitiert.",
|
||||
"dataChannelClosedDescriptionWithAudio": "Die Steuerungsverbindung (Bridge Channel) wurde unterbrochen, daher können Video- und Tonprobleme auftreten.",
|
||||
@@ -753,6 +758,9 @@
|
||||
"gifsMenu": "GIPHY",
|
||||
"groupTitle": "Benachrichtigungen",
|
||||
"hostAskedUnmute": "Die Moderation bittet Sie, das Mikrofon zu aktivieren",
|
||||
"invalidTenant": "Ungültiger Mandant",
|
||||
"invalidTenantHyphenDescription": "Der gewählte Mandantenname ist ungültig (beginnt oder endet mit '-').",
|
||||
"invalidTenantLengthDescription": "Der gewählte Mandantenname ist zu lang.",
|
||||
"invitedOneMember": "{{name}} wurde eingeladen",
|
||||
"invitedThreePlusMembers": "{{name}} und {{count}} andere wurden eingeladen",
|
||||
"invitedTwoMembers": "{{first}} und {{second}} wurden eingeladen",
|
||||
@@ -783,7 +791,7 @@
|
||||
"moderationToggleDescription": "von {{participantDisplayName}}",
|
||||
"moderator": "Moderationsrechte vergeben!",
|
||||
"muted": "Der Konferenz wurde stumm beigetreten.",
|
||||
"mutedRemotelyDescription": "Sie können jederzeit die Stummschaltung aufheben, wenn Sie bereit sind zu sprechen. Wenn Sie fertig sind, können Sie sich wieder stummschalten, um Geräusche vom Meeting fernzuhalten.",
|
||||
"mutedRemotelyDescription": "Sie können jederzeit die Stummschaltung aufheben, wenn Sie bereit sind zu sprechen. Wenn Sie fertig sind, können Sie sich wieder stummschalten, um Geräusche von der Konferenz fernzuhalten.",
|
||||
"mutedRemotelyTitle": "Sie wurden von {{participantDisplayName}} stummgeschaltet!",
|
||||
"mutedTitle": "Stummschaltung aktiv!",
|
||||
"newDeviceAction": "Verwenden",
|
||||
@@ -811,7 +819,7 @@
|
||||
"screenSharingAudioOnlyTitle": "Modus \"Beste Leistung\"",
|
||||
"selfViewTitle": "Sie können die eigene Ansicht immer in den Einstellungen reaktivieren",
|
||||
"somebody": "Jemand",
|
||||
"startSilentDescription": "Treten Sie dem Meeting noch einmal bei, um Ihr Audio zu aktivieren",
|
||||
"startSilentDescription": "Treten Sie der Konferenz noch einmal bei, um Ihr Audio zu aktivieren",
|
||||
"startSilentTitle": "Sie sind ohne Audioausgabe beigetreten!",
|
||||
"suboptimalBrowserWarning": "Tut uns leid, aber die Konferenz wird mit {{appName}} kein großartiges Erlebnis. Wir versuchen immer die Situation zu verbessern, bis dahin empfehlen wir aber die Verwendung einer der <a href=\"{{recommendedBrowserPageLink}}\" target=\"_blank\">vollständig unterstützen Browser</a>.",
|
||||
"suboptimalExperienceTitle": "Browserwarnung",
|
||||
@@ -819,6 +827,7 @@
|
||||
"suggestRecordingDescription": "Möchten Sie eine Aufzeichnung starten?",
|
||||
"suggestRecordingTitle": "Konferenz aufzeichnen",
|
||||
"unmute": "Stummschaltung aufheben",
|
||||
"unmuteVideo": "Kamera einschalten",
|
||||
"videoMutedRemotelyDescription": "Sie können sie jederzeit wieder einschalten.",
|
||||
"videoMutedRemotelyTitle": "Ihre Kamera wurde von {{participantDisplayName}} ausgeschaltet!",
|
||||
"videoUnmuteBlockedDescription": "Die Kamera und Bildschirmfreigabe kann aus Überlastungsschutzgründen temporär nicht eingeschaltet werden.",
|
||||
@@ -1022,7 +1031,7 @@
|
||||
"error": "Die Aufzeichnung ist fehlgeschlagen. Bitte versuchen Sie es erneut.",
|
||||
"errorFetchingLink": "Der Link zur Aufzeichnung konnte nicht geladen werden.",
|
||||
"expandedOff": "Aufzeichnung wurde gestoppt",
|
||||
"expandedOn": "Das Meeting wird momentan aufgezeichnet.",
|
||||
"expandedOn": "Die Konferenz wird momentan aufgezeichnet.",
|
||||
"expandedPending": "Aufzeichnung wird gestartet…",
|
||||
"failedToStart": "Die Aufnahme konnte nicht gestartet werden",
|
||||
"fileSharingdescription": "Aufzeichnung mit den Personen der Konferenz teilen",
|
||||
@@ -1030,7 +1039,7 @@
|
||||
"highlightMoment": "Moment als Highlight festhalten",
|
||||
"highlightMomentDisabled": "Sie können Momente als Highlights festhalten, sobald die Aufnahme startet",
|
||||
"highlightMomentSuccess": "Highlight festgehalten",
|
||||
"highlightMomentSucessDescription": "Ihr festgehaltener Moment wird zur Zusammenfassung des Meeting hinzugefügt.",
|
||||
"highlightMomentSucessDescription": "Ihr festgehaltener Moment wird zur Zusammenfassung der Konferenz hinzugefügt.",
|
||||
"inProgress": "Aufzeichnung gestartet",
|
||||
"limitNotificationDescriptionNative": "Wegen hoher Nachfrage ist Ihre Aufnahme auf {{limit}} Min. begrenzt. Für unlimitierte Aufnahmen nutzen Sie bitte <3>{{app}}</3>.",
|
||||
"limitNotificationDescriptionWeb": "Wegen hoher Nachfrage ist Ihre Aufnahme auf {{limit}} Min. begrenzt. Für unlimitierte Aufnahmen nutzen Sie bitte <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
@@ -1050,7 +1059,8 @@
|
||||
"on": "Aufnahme",
|
||||
"onBy": "{{name}} startete die Aufnahme",
|
||||
"onlyRecordSelf": "Nur eigenes Kamerabild und Ton aufzeichnen",
|
||||
"pending": "Aufzeichnung des Meetings wird vorbereitet…",
|
||||
"pending": "Aufzeichnung der Konferenz wird vorbereitet…",
|
||||
"policyError": "Sie haben die Aufzeichnung zu schnell gestartet. Bitte versuchen Sie es später noch einmal.",
|
||||
"recordAudioAndVideo": "Kamera und Ton aufzeichnen",
|
||||
"recordTranscription": "Transkription aufzeichnen",
|
||||
"saveLocalRecording": "Aufzeichnung lokal abspeichern",
|
||||
@@ -1073,10 +1083,10 @@
|
||||
"pullToRefresh": "Ziehen, um zu aktualisieren"
|
||||
},
|
||||
"security": {
|
||||
"about": "Sie können Ihre Konferenz mit einem Passwort sichern. Teilnehmer müssen dieses eingeben, bevor sie an der Sitzung teilnehmen dürfen.",
|
||||
"about": "Sie können Ihre Konferenz mit einem Passwort sichern. Personen müssen dieses eingeben, bevor sie an der Sitzung teilnehmen dürfen.",
|
||||
"aboutReadOnly": "Mit Moderationsrechten kann die Konferenz mit einem Passwort gesichert werden. Personen müssen dieses eingeben, bevor sie an der Sitzung teilnehmen dürfen.",
|
||||
"insecureRoomNameWarningNative": "Der Raumname ist unsicher. Unerwünschte Teilnehmer könnten Ihrer Konferenz beitreten. {{recommendAction}} Lernen Sie mehr über die Absicherung Ihrer Konferenz ",
|
||||
"insecureRoomNameWarningWeb": "Der Raumname ist unsicher. Unerwünschte Teilnehmer könnten Ihrer Konferenz beitreten {{recommendAction}} Lernen Sie <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">hier</a> mehr über die Absicherung Ihrer Konferenz.",
|
||||
"insecureRoomNameWarningNative": "Der Raumname ist unsicher. Unerwünschte Personen könnten Ihrer Konferenz beitreten. {{recommendAction}} Lernen Sie mehr über die Absicherung Ihrer Konferenz ",
|
||||
"insecureRoomNameWarningWeb": "Der Raumname ist unsicher. Unerwünschte Personen könnten Ihrer Konferenz beitreten {{recommendAction}} Lernen Sie <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">hier</a> mehr über die Absicherung Ihrer Konferenz.",
|
||||
"title": "Sicherheitsoptionen",
|
||||
"unsafeRoomActions": {
|
||||
"meeting": "Erwägen Sie die Absicherung Ihrer Konferenz über den Sicherheits-Button.",
|
||||
@@ -1165,8 +1175,8 @@
|
||||
"version": "Version"
|
||||
},
|
||||
"share": {
|
||||
"dialInfoText": "\n\n=====\n\nWollen Sie sich nur auf Ihrem Telefon einwählen?\n\n{{defaultDialInNumber}}Klicken Sie auf diesen Link, um die eingewählten Telefonnummern für dieses Meeting zu sehen\n{{dialInfoPageUrl}}",
|
||||
"mainText": "Klicken Sie auf den folgenden Link, um dem Meeting beizutreten:\n{{roomUrl}}"
|
||||
"dialInfoText": "\n\n=====\n\nWollen Sie sich nur auf Ihrem Telefon einwählen?\n\n{{defaultDialInNumber}}Klicken Sie auf diesen Link, um die eingewählten Telefonnummern für diese Konferenz zu sehen\n{{dialInfoPageUrl}}",
|
||||
"mainText": "Klicken Sie auf den folgenden Link, um der Konferenz beizutreten:\n{{roomUrl}}"
|
||||
},
|
||||
"speaker": "Sprecher/-in",
|
||||
"speakerStats": {
|
||||
@@ -1176,6 +1186,7 @@
|
||||
"fearful": "Ängstlich",
|
||||
"happy": "Fröhlich",
|
||||
"hours": "{{count}} Std. ",
|
||||
"labelTooltip": "Anzahl der Personen: {{count}}",
|
||||
"minutes": "{{count}} Min. ",
|
||||
"name": "Name",
|
||||
"neutral": "Neutral",
|
||||
@@ -1397,7 +1408,7 @@
|
||||
"ccButtonTooltip": "Untertitel ein-/ausschalten",
|
||||
"expandedLabel": "Transkribieren ist derzeit eingeschaltet",
|
||||
"failed": "Transkribieren fehlgeschlagen",
|
||||
"labelToolTip": "Das Meeting wird transkribiert",
|
||||
"labelToolTip": "Die Konferenz wird transkribiert",
|
||||
"sourceLanguageDesc": "Aktuell ist die Sprache der Konferenz auf <b>{{sourceLanguage}}</b> eingestellt. <br/> Sie könne dies hier ",
|
||||
"sourceLanguageHere": "ändern",
|
||||
"start": "Anzeige der Untertitel starten",
|
||||
@@ -1528,15 +1539,15 @@
|
||||
},
|
||||
"calendar": "Kalender",
|
||||
"connectCalendarButton": "Kalender verbinden",
|
||||
"connectCalendarText": "Verbinden Sie Ihren Kalender, um all Ihre Meetings in {{app}} anzuzeigen. Fügen Sie zudem {{provider}}-Meetings in Ihren Kalender ein und starten Sie sie mit nur einem Klick.",
|
||||
"enterRoomTitle": "Neues Meeting starten",
|
||||
"connectCalendarText": "Verbinden Sie Ihren Kalender, um all Ihre Konferenzen in {{app}} anzuzeigen. Fügen Sie zudem {{provider}}-Konferenzen in Ihren Kalender ein und starten Sie sie mit nur einem Klick.",
|
||||
"enterRoomTitle": "Neue Konferenz starten",
|
||||
"getHelp": "Hilfe",
|
||||
"go": "Los",
|
||||
"goSmall": "Los",
|
||||
"headerSubtitle": "Sichere und hochqualitative Meetings",
|
||||
"headerSubtitle": "Sichere und hochqualitative Konferenzen",
|
||||
"headerTitle": "Jitsi Meet",
|
||||
"info": "Einwahlinformationen",
|
||||
"jitsiOnMobile": "Jitsi unterwegs – einfach unsere Apps herunterladen und Meetings von überall starten",
|
||||
"jitsiOnMobile": "Jitsi unterwegs – einfach unsere Apps herunterladen und Konferenzen von überall starten",
|
||||
"join": "ERSTELLEN / BEITRETEN",
|
||||
"logo": {
|
||||
"calendar": "Kalender Logo",
|
||||
@@ -1562,7 +1573,7 @@
|
||||
"roomnameHint": "Name oder URL der Konferenz, der Sie beitreten möchten. Sie können einen Namen erfinden, er muss nur den anderen Personen übermittelt werden, damit diese der gleichen Konferenz beitreten.",
|
||||
"sendFeedback": "Feedback senden",
|
||||
"settings": "Einstellungen",
|
||||
"startMeeting": "Meeting starten",
|
||||
"startMeeting": "Konferenz starten",
|
||||
"terms": "AGB",
|
||||
"title": "Sichere, voll funktionale und komplett kostenlose Videokonferenzen",
|
||||
"upcomingMeetings": "Ihre zukünftigen Konferenzen"
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
"alreadySharedVideoTitle": "एक समय में केवल एक साझा वीडियो की अनुमति है",
|
||||
"applicationWindow": "एप्लिकेशन विंडो",
|
||||
"authenticationRequired": "प्रमाणीकरण आवश्यक है",
|
||||
"cameraConstraintFailedError": "Your camera does not satisfy some of the required constraints.",
|
||||
"cameraConstraintFailedError": "आपका कैमरा आवश्यक बाधाओं में से कुछ को पूरा नहीं करता है।",
|
||||
"cameraNotFoundError": "कैमरा नहीं मिला।",
|
||||
"cameraNotSendingData": "हम आपके कैमरे का उपयोग करने में असमर्थ हैं। कृपया जांचें कि क्या कोई अन्य एप्लिकेशन इस डिवाइस का उपयोग तो नहीं कर रहा है, सेटिंग मेनू से किसी अन्य डिवाइस का चयन करें या एप्लिकेशन को फिर से लोड करने का प्रयास करें।",
|
||||
"cameraNotSendingDataTitle": "कैमरा उपयोग करने में असमर्थ",
|
||||
@@ -222,7 +222,7 @@
|
||||
"e2eeWarning": "चेतावनी: इस मीटिंग में सभी प्रतिभागियों के पास एंड-टू-एंड एन्क्रिप्शन के लिए समक्षता नहीं है। यदि आप इसे सक्षम करते हैं तो वे आपको देखने और सुनने में सक्षम नहीं होंगे।",
|
||||
"enterDisplayName": "कृपया यहाँ अपना नाम लिखें",
|
||||
"error": "त्रुटि",
|
||||
"gracefulShutdown": "Our service is currently down for maintenance. Please try again later.",
|
||||
"gracefulShutdown": "हमारी सेवा वर्तमान में रखरखाव के लिए बंद है। कृपया बाद में पुनः प्रयास करें।",
|
||||
"grantModeratorDialog": "क्या आप वाकई इस प्रतिभागी को एक मध्यस्थ बनाना चाहते हैं?",
|
||||
"grantModeratorTitle": "मध्यस्थ स्वीकृती दे ",
|
||||
"incorrectPassword": "गलत उपयोगकर्ता नाम या पासवर्ड",
|
||||
@@ -230,7 +230,7 @@
|
||||
"internalError": "उफ़! कुछ गड़बड़ हो गई। निम्नलिखित त्रुटि हुई: {{error}}",
|
||||
"internalErrorTitle": "आंतरिक त्रुटि",
|
||||
"kickMessage": "आप अधिक जानकारी के लिए {{participantDisplayName}} से संपर्क कर सकते हैं।",
|
||||
"kickParticipantButton": "Kick",
|
||||
"kickParticipantButton": "निकालें",
|
||||
"kickParticipantDialog": "क्या आप वाकई इस प्रतिभागी को निकलना चाहते हैं?",
|
||||
"kickParticipantTitle": "इस प्रतिभागी को निकाले?",
|
||||
"kickTitle": "अरे! {{participantDisplayName}} ने आपको मीटिंग से बाहर कर दिया",
|
||||
@@ -245,7 +245,7 @@
|
||||
"logoutTitle": "लॉग आउट ",
|
||||
"maxUsersLimitReached": "अधिकतम प्रतिभागियों की सीमा पूरी हो चुकी है. कृपया बैठक के मालिक से संपर्क करें या बाद में पुनः प्रयास करें!!",
|
||||
"maxUsersLimitReachedTitle": "अधिकतम प्रतिभागियों सीमा पार हो गई",
|
||||
"micConstraintFailedError": "Your microphone does not satisfy some of the required constraints.",
|
||||
"micConstraintFailedError": "आपका माइक्रोफ़ोन आवश्यक प्रतिबंधों को पूरा नहीं करता।",
|
||||
"micNotFoundError": "माइक्रोफोन नहीं मिला।",
|
||||
"micNotSendingData": "अपने माइक को अनम्यूट करने और इसके स्तर को समायोजित करने के लिए अपने कंप्यूटर की सेटिंग पर जाएं",
|
||||
"micNotSendingDataTitle": "आपका माइक आपकी सिस्टम सेटिंग्स द्वारा मौन है",
|
||||
@@ -285,18 +285,18 @@
|
||||
"remoteControlDeniedMessage": "{{user}} ने आपका रिमोट कंट्रोल अनुरोध अस्वीकार कर दिया!",
|
||||
"remoteControlErrorMessage": "{{user}}से रिमोट कंट्रोल की अनुमति का अनुरोध करते समय एक त्रुटि हुई!",
|
||||
"remoteControlRequestMessage": "क्या आप {{user}} को दूर से अपने डेस्कटॉप को नियंत्रित करने की अनुमति देंगे?",
|
||||
"remoteControlShareScreenWarning": "Note that if you press \"Allow\" you will share your screen!",
|
||||
"remoteControlShareScreenWarning": "ध्यान दें कि यदि आप \"अनुमति दें\" दबाते हैं, तो आप अपनी स्क्रीन साझा करेंगे!",
|
||||
"remoteControlStopMessage": "रिमोट कंट्रोल सत्र समाप्त हो गया!",
|
||||
"remoteControlTitle": "रिमोट डेस्कटॉप कंट्रोल",
|
||||
"removePassword": "निकालें $t(lockRoomPassword)",
|
||||
"removeSharedVideoMsg": "क्या आप वाकई अपने साझा किए गए वीडियो को निकालना चाहते हैं?",
|
||||
"removeSharedVideoTitle": "साझा किया गया वीडियो निकालें",
|
||||
"reservationError": "Reservation system error",
|
||||
"reservationError": "आरक्षण प्रणाली में त्रुटि",
|
||||
"reservationErrorMsg": "Error code: {{code}}, message: {{msg}}",
|
||||
"retry": "पुनः प्रयास करें",
|
||||
"screenSharingAudio": "Share audio",
|
||||
"screenSharingAudio": "ऑडियो साझा करें",
|
||||
"screenSharingFailed": "उफ़! कुछ गड़बड़ हो गई, हम स्क्रीन शेयरिंग शुरू करने में सक्षम नहीं थे!",
|
||||
"screenSharingFailedTitle": "Screen sharing failed!",
|
||||
"screenSharingFailedTitle": "स्क्रीन साझा करना विफल हुआ!",
|
||||
"screenSharingPermissionDeniedError": "उफ़! आपकी स्क्रीन शेयरिंग अनुमतियों में कुछ गड़बड़ हो गई है। कृपया पुनः लोड करें और पुनः प्रयास करें।",
|
||||
"sendPrivateMessage": "आपने हाल ही में एक निजी संदेश प्राप्त किया है। क्या आप उसका निजी रूप से जवाब देने का इरादा रखते हैं? या आप अपना संदेश समूह को भेजना चाहते हैं?",
|
||||
"sendPrivateMessageCancel": "समूह को भेजें",
|
||||
@@ -304,7 +304,7 @@
|
||||
"sendPrivateMessageTitle": "निजी तौर पर भेजें?",
|
||||
"serviceUnavailable": "सेवा अनुपलब्ध",
|
||||
"sessTerminated": "कॉल समाप्त",
|
||||
"sessionRestarted": "Call restarted because of a connection issue",
|
||||
"sessionRestarted": "कनेक्शन समस्या के कारण कॉल पुनः प्रारंभ की गई",
|
||||
"shareVideoLinkError": "कृपया एक सही यूट्यूब लिंक प्रदान करें।.",
|
||||
"shareVideoTitle": "एक वीडियो साझा करें",
|
||||
"shareYourScreen": "अपनी स्क्रीन साझा करें",
|
||||
@@ -313,10 +313,10 @@
|
||||
"startRecording": "रिकॉर्डिंग प्रारंभ करें",
|
||||
"startRemoteControlErrorMessage": "रिमोट कंट्रोल सत्र शुरू करने की कोशिश करते समय एक त्रुटि हुई!",
|
||||
"stopLiveStreaming": "लाइव स्ट्रीम बंद करें",
|
||||
"stopRecording": "Stop recording",
|
||||
"stopRecording": "रिकॉर्डिंग बंद करें",
|
||||
"stopRecordingWarning": "क्या आप वाकई रिकॉर्डिंग को रोकना चाहते हैं?",
|
||||
"stopStreamingWarning": "क्या आप वाकई लाइव स्ट्रीमिंग को रोकना चाहते हैं?",
|
||||
"streamKey": "Live stream key",
|
||||
"streamKey": "लाइव स्ट्रीम कुंजी",
|
||||
"thankYou": " {{appName}} का उपयोग करने के लिए धन्यवाद!",
|
||||
"token": "टोकन",
|
||||
"tokenAuthFailed": "क्षमा करें, आपको इस कॉल में शामिल होने की अनुमति नहीं है।",
|
||||
@@ -336,7 +336,7 @@
|
||||
"labelToolTip": "इस कॉल पर ऑडियो और वीडियो संचार एंड-टू-एंड एन्क्रिप्टेड है"
|
||||
},
|
||||
"embedMeeting": {
|
||||
"title": "Embed this meeting"
|
||||
"title": "इस बैठक को एम्बेड करें"
|
||||
},
|
||||
"feedback": {
|
||||
"average": "औसत",
|
||||
@@ -381,7 +381,7 @@
|
||||
"moreNumbers": "अधिक संख्या",
|
||||
"noNumbers": "कोई डायल-इन नंबर नहीं।",
|
||||
"noPassword": "कोई नहीं",
|
||||
"noRoom": "No room was specified to dial-in into.",
|
||||
"noRoom": "डायल-इन करने के लिए कोई कक्ष निर्दिष्ट नहीं किया गया।",
|
||||
"numbers": "डायल-इन नंबर",
|
||||
"password": "$t(lockRoomPasswordUppercase):",
|
||||
"title": "साझा करें",
|
||||
@@ -404,11 +404,11 @@
|
||||
"keyboardShortcuts": {
|
||||
"focusLocal": "अपने वीडियो पर केंद्रित करें",
|
||||
"focusRemote": "किसी अन्य व्यक्ति के वीडियो पर केंद्रित करें",
|
||||
"fullScreen": "View or exit full screen",
|
||||
"fullScreen": "पूर्ण स्क्रीन देखें या बाहर निकलें",
|
||||
"keyboardShortcuts": "कीबोर्ड शॉर्टकट्स",
|
||||
"localRecording": "स्थानीय रिकॉर्डिंग नियंत्रण दिखाएं या छिपाएँ",
|
||||
"mute": "अपने माइक्रोफ़ोन को म्यूट या अनम्यूट करें",
|
||||
"pushToTalk": "Push to talk",
|
||||
"pushToTalk": "बोलने के लिए दबाएं",
|
||||
"raiseHand": "अपना हाथ उठाएँ या नीचे करें",
|
||||
"showSpeakerStats": "स्पीकर आंकड़े दिखाएं",
|
||||
"toggleChat": "चैट खोलें या बंद करें",
|
||||
@@ -418,39 +418,39 @@
|
||||
"videoMute": "अपना कैमरा प्रारंभ या बंद करें"
|
||||
},
|
||||
"liveStreaming": {
|
||||
"busy": "We're working on freeing streaming resources. Please try again in a few minutes.",
|
||||
"busyTitle": "All streamers are currently busy",
|
||||
"changeSignIn": "Switch accounts.",
|
||||
"choose": "Choose a live stream",
|
||||
"chooseCTA": "Choose a streaming option. You're currently logged in as {{email}}.",
|
||||
"enterStreamKey": "Enter your YouTube live stream key here.",
|
||||
"error": "Live Streaming failed. Please try again.",
|
||||
"errorAPI": "An error occurred while accessing your YouTube broadcasts. Please try logging in again.",
|
||||
"errorLiveStreamNotEnabled": "Live Streaming is not enabled on {{email}}. Please enable live streaming or log into an account with live streaming enabled.",
|
||||
"expandedOff": "The live streaming has stopped",
|
||||
"expandedOn": "The meeting is currently being streamed to YouTube.",
|
||||
"expandedPending": "The live streaming is being started…",
|
||||
"failedToStart": "Live Streaming failed to start",
|
||||
"getStreamKeyManually": "We weren’t able to fetch any live streams. Try getting your live stream key from YouTube.",
|
||||
"googlePrivacyPolicy": "Google Privacy Policy",
|
||||
"invalidStreamKey": "Live stream key may be incorrect.",
|
||||
"limitNotificationDescriptionNative": "Your streaming will be limited to {{limit}} min. For unlimited streaming try {{app}}.",
|
||||
"limitNotificationDescriptionWeb": "Due to high demand your streaming will be limited to {{limit}} min. For unlimited streaming try <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"off": "Live Streaming stopped",
|
||||
"offBy": "{{name}} stopped the live streaming",
|
||||
"on": "Live Streaming started",
|
||||
"onBy": "{{name}} started the live streaming",
|
||||
"pending": "Starting Live Stream…",
|
||||
"serviceName": "Live Streaming service",
|
||||
"signIn": "Sign in with Google",
|
||||
"signInCTA": "Sign in or enter your live stream key from YouTube.",
|
||||
"signOut": "Sign out",
|
||||
"signedInAs": "You are currently signed in as:",
|
||||
"start": "Start a live stream",
|
||||
"streamIdHelp": "What's this?",
|
||||
"title": "सीधा प्रसारण",
|
||||
"unavailableTitle": "Live Streaming unavailable",
|
||||
"youtubeTerms": "YouTube terms of services"
|
||||
"busy": "हम स्ट्रीमिंग संसाधनों को मुक्त करने पर काम कर रहे हैं। कृपया कुछ मिनटों में पुनः प्रयास करें।",
|
||||
"busyTitle": "सभी स्ट्रीमर वर्तमान में व्यस्त हैं",
|
||||
"changeSignIn": "खाता बदलें।",
|
||||
"choose": "एक लाइव स्ट्रीम चुनें",
|
||||
"chooseCTA": "स्ट्रीमिंग विकल्प चुनें। आप वर्तमान में {{email}} के रूप में लॉग इन हैं।",
|
||||
"enterStreamKey": "अपनी YouTube लाइव स्ट्रीम कुंजी यहाँ दर्ज करें।",
|
||||
"error": "लाइव स्ट्रीमिंग विफल रही। कृपया पुनः प्रयास करें।",
|
||||
"errorAPI": "आपके YouTube प्रसारण तक पहुँचने में त्रुटि हुई। कृपया पुनः लॉगिन करें।",
|
||||
"errorLiveStreamNotEnabled": "{{email}} पर लाइव स्ट्रीमिंग सक्षम नहीं है। कृपया लाइव स्ट्रीमिंग सक्षम करें या ऐसे खाते में लॉग इन करें जिसमें लाइव स्ट्रीमिंग सक्षम हो।",
|
||||
"expandedOff": "लाइव स्ट्रीमिंग बंद हो गई है",
|
||||
"expandedOn": "बैठक वर्तमान में YouTube पर स्ट्रीम की जा रही है।",
|
||||
"expandedPending": "लाइव स्ट्रीमिंग शुरू की जा रही है…",
|
||||
"failedToStart": "लाइव स्ट्रीमिंग शुरू करने में विफल रहा",
|
||||
"getStreamKeyManually": "हम कोई लाइव स्ट्रीम प्राप्त नहीं कर सके। कृपया YouTube से अपनी लाइव स्ट्रीम कुंजी प्राप्त करने का प्रयास करें।",
|
||||
"googlePrivacyPolicy": "Google गोपनीयता नीति",
|
||||
"invalidStreamKey": "लाइव स्ट्रीम कुंजी गलत हो सकती है।",
|
||||
"limitNotificationDescriptionNative": "आपकी स्ट्रीमिंग {{limit}} मिनट तक सीमित होगी। असीमित स्ट्रीमिंग के लिए {{app}} आज़माएँ।",
|
||||
"limitNotificationDescriptionWeb": "अधिक मांग के कारण आपकी स्ट्रीमिंग {{limit}} मिनट तक सीमित होगी। असीमित स्ट्रीमिंग के लिए <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a> आज़माएँ।",
|
||||
"off": "लाइव स्ट्रीमिंग बंद हो गई",
|
||||
"offBy": "{{name}} ने लाइव स्ट्रीमिंग बंद कर दी",
|
||||
"on": "लाइव स्ट्रीमिंग शुरू हो गई",
|
||||
"onBy": "{{name}} ने लाइव स्ट्रीमिंग शुरू की",
|
||||
"pending": "लाइव स्ट्रीम शुरू हो रही है…",
|
||||
"serviceName": "लाइव स्ट्रीमिंग सेवा",
|
||||
"signIn": "Google से साइन इन करें",
|
||||
"signInCTA": "साइन इन करें या YouTube से अपनी लाइव स्ट्रीम कुंजी दर्ज करें।",
|
||||
"signOut": "साइन आउट करें",
|
||||
"signedInAs": "आप वर्तमान में इस रूप में साइन इन हैं:",
|
||||
"start": "एक लाइव स्ट्रीम शुरू करें",
|
||||
"streamIdHelp": "यह क्या है?",
|
||||
"title": "लाइव स्ट्रीमिंग",
|
||||
"unavailableTitle": "लाइव स्ट्रीमिंग उपलब्ध नहीं है",
|
||||
"youtubeTerms": "YouTube सेवा की शर्तें"
|
||||
},
|
||||
"lobby": {
|
||||
"allow": "अनुमति दें",
|
||||
@@ -481,38 +481,38 @@
|
||||
"notificationLobbyEnabled": "लॉबी को {{originParticipantName}}द्वारा सक्षम किया गया",
|
||||
"notificationTitle": "लॉबी",
|
||||
"passwordField": "मीटिंग पासवर्ड दर्ज करें",
|
||||
"passwordJoinButton": "Join",
|
||||
"passwordJoinButton": "शामिल हों",
|
||||
"title": "लॉबी",
|
||||
"toggleLabel": "लॉबी सक्षम करें"
|
||||
},
|
||||
"localRecording": {
|
||||
"clientState": {
|
||||
"off": "Off",
|
||||
"on": "On",
|
||||
"unknown": "Unknown"
|
||||
"off": "बंद",
|
||||
"on": "चालू",
|
||||
"unknown": "अज्ञात"
|
||||
},
|
||||
"dialogTitle": "Local Recording Controls",
|
||||
"duration": "Duration",
|
||||
"durationNA": "N/A",
|
||||
"encoding": "Encoding",
|
||||
"label": "LOR",
|
||||
"labelToolTip": "Local recording is engaged",
|
||||
"localRecording": "Local Recording",
|
||||
"me": "Me",
|
||||
"dialogTitle": "स्थानीय रिकॉर्डिंग नियंत्रण",
|
||||
"duration": "अवधि",
|
||||
"durationNA": "उपलब्ध नहीं",
|
||||
"encoding": "एन्कोडिंग",
|
||||
"label": "स्थानीय रिकॉर्डिंग",
|
||||
"labelToolTip": "स्थानीय रिकॉर्डिंग सक्रिय है",
|
||||
"localRecording": "स्थानीय रिकॉर्डिंग",
|
||||
"me": "मैं",
|
||||
"messages": {
|
||||
"engaged": "Local recording engaged.",
|
||||
"finished": "Recording session {{token}} finished. Please send the recorded file to the moderator.",
|
||||
"finishedModerator": "Recording session {{token}} finished. The recording of the local track has been saved. Please ask the other participants to submit their recordings.",
|
||||
"notModerator": "You are not the moderator. You cannot start or stop local recording."
|
||||
"engaged": "स्थानीय रिकॉर्डिंग सक्रिय हो गई।",
|
||||
"finished": "रिकॉर्डिंग सत्र {{token}} समाप्त हो गया। कृपया रिकॉर्ड की गई फ़ाइल मॉडरेटर को भेजें।",
|
||||
"finishedModerator": "रिकॉर्डिंग सत्र {{token}} समाप्त हो गया। स्थानीय ट्रैक की रिकॉर्डिंग सहेज ली गई है। कृपया अन्य प्रतिभागियों से उनकी रिकॉर्डिंग जमा करने के लिए कहें।",
|
||||
"notModerator": "आप मॉडरेटर नहीं हैं। आप स्थानीय रिकॉर्डिंग प्रारंभ या बंद नहीं कर सकते।"
|
||||
},
|
||||
"moderator": "Moderator",
|
||||
"no": "No",
|
||||
"participant": "Participant",
|
||||
"participantStats": "Participant Stats",
|
||||
"sessionToken": "Session Token",
|
||||
"start": "Start Recording",
|
||||
"stop": "Stop Recording",
|
||||
"yes": "Yes"
|
||||
"moderator": "मॉडरेटर",
|
||||
"no": "नहीं",
|
||||
"participant": "प्रतिभागी",
|
||||
"participantStats": "प्रतिभागी आँकड़े",
|
||||
"sessionToken": "सत्र टोकन",
|
||||
"start": "रिकॉर्डिंग प्रारंभ करें",
|
||||
"stop": "रिकॉर्डिंग बंद करें",
|
||||
"yes": "हाँ"
|
||||
},
|
||||
"lockRoomPassword": "पासवर्ड",
|
||||
"lockRoomPasswordUppercase": "पासवर्ड",
|
||||
@@ -536,8 +536,8 @@
|
||||
"kickParticipant": "{{kicked}} को {{kicker}} द्वारा किक किया गया",
|
||||
"me": "मैं",
|
||||
"moderator": "मॉडरेटर के अधिकार दिए गए!",
|
||||
"muted": "You have started the conversation muted.",
|
||||
"mutedRemotelyDescription": "You can always unmute when you're ready to speak. Mute back when you're done to keep noise away from the meeting.",
|
||||
"muted": "आपने वार्तालाप को म्यूट करके शुरू किया है।",
|
||||
"mutedRemotelyDescription": "जब आप बोलने के लिए तैयार हों, तो आप हमेशा अनम्यूट कर सकते हैं। बैठक में शोर कम रखने के लिए बोलने के बाद म्यूट कर दें।",
|
||||
"mutedRemotelyTitle": "आपको {{participantDisplayName}} द्वारा म्यूट कर दिया गया है!",
|
||||
"mutedTitle": "आप मौन हैं!",
|
||||
"newDeviceAction": "उपयोग करें",
|
||||
@@ -563,7 +563,7 @@
|
||||
"reject": "अस्वीकार"
|
||||
}
|
||||
},
|
||||
"passwordDigitsOnly": "Up to {{number}} digits",
|
||||
"passwordDigitsOnly": "अधिकतम {{number}} अंक",
|
||||
"passwordSetRemotely": "दूसरे प्रतिभागी द्वारा निर्धारित",
|
||||
"polls": {
|
||||
"errors": {
|
||||
@@ -580,25 +580,25 @@
|
||||
"callMeAtNumber": "मुझे इस नंबर पर कॉल करें:",
|
||||
"calling": "कॉलिंग",
|
||||
"configuringDevices": "डिवाइस कॉन्फ़िगर कर रहा है…",
|
||||
"connectedWithAudioQ": "You’re connected with audio?",
|
||||
"connectedWithAudioQ": "क्या आप ऑडियो से जुड़े हैं?",
|
||||
"connection": {
|
||||
"good": "Your internet connection looks good!",
|
||||
"nonOptimal": "Your internet connection is not optimal",
|
||||
"poor": "आपके पास एक खराब इंटरनेट कनेक्शन है"
|
||||
"good": "आपका इंटरनेट कनेक्शन अच्छा है!",
|
||||
"nonOptimal": "आपका इंटरनेट कनेक्शन आदर्श नहीं है",
|
||||
"poor": "आपका इंटरनेट कनेक्शन खराब है"
|
||||
},
|
||||
"connectionDetails": {
|
||||
"audioClipping": "We expect your audio to be clipped.",
|
||||
"audioHighQuality": "We expect your audio to have excellent quality.",
|
||||
"audioLowNoVideo": "We expect your audio quality to be low and no video.",
|
||||
"goodQuality": "Awesome! Your media quality is going to be great.",
|
||||
"noMediaConnectivity": "We could not find a way to establish media connectivity for this test. This is typically caused by a firewall or NAT.",
|
||||
"noVideo": "We expect that your video will be terrible.",
|
||||
"undetectable": "If you still can not make calls in browser, we recommend that you make sure your speakers, microphone and camera are properly set up, that you have granted your browser rights to use your microphone and camera, and that your browser version is up-to-date. If you still have trouble calling, you should contact the web application developer.",
|
||||
"veryPoorConnection": "We expect your call quality to be really terrible.",
|
||||
"videoFreezing": "We expect your video to freeze, turn black, and be pixelated.",
|
||||
"videoHighQuality": "We expect your video to have good quality.",
|
||||
"videoLowQuality": "We expect your video to have low quality in terms of frame rate and resolution.",
|
||||
"videoTearing": "We expect your video to be pixelated or have visual artefacts."
|
||||
"audioClipping": "हमें उम्मीद है कि आपका ऑडियो कट सकता है।",
|
||||
"audioHighQuality": "हमें उम्मीद है कि आपका ऑडियो बेहतरीन गुणवत्ता का होगा।",
|
||||
"audioLowNoVideo": "हमें उम्मीद है कि आपकी ऑडियो गुणवत्ता कम होगी और वीडियो उपलब्ध नहीं होगा।",
|
||||
"goodQuality": "बहुत बढ़िया! आपकी मीडिया गुणवत्ता शानदार होगी।",
|
||||
"noMediaConnectivity": "हम इस परीक्षण के लिए मीडिया कनेक्टिविटी स्थापित करने में असमर्थ हैं। यह आमतौर पर फ़ायरवॉल या NAT के कारण होता है।",
|
||||
"noVideo": "हमें उम्मीद है कि आपका वीडियो बहुत खराब होगा।",
|
||||
"undetectable": "यदि आप अभी भी ब्राउज़र में कॉल नहीं कर पा रहे हैं, तो हम अनुशंसा करते हैं कि आप सुनिश्चित करें कि आपके स्पीकर, माइक्रोफ़ोन और कैमरा सही तरीके से सेट किए गए हैं, कि आपने अपने ब्राउज़र को माइक्रोफ़ोन और कैमरा उपयोग की अनुमति दी है, और आपका ब्राउज़र संस्करण अपडेट है। यदि समस्या बनी रहती है, तो आपको वेब एप्लिकेशन डेवलपर से संपर्क करना चाहिए।",
|
||||
"veryPoorConnection": "हमें उम्मीद है कि आपकी कॉल गुणवत्ता बहुत खराब होगी।",
|
||||
"videoFreezing": "हमें उम्मीद है कि आपका वीडियो फ्रीज़ होगा, काला हो जाएगा और धुंधला दिखेगा।",
|
||||
"videoHighQuality": "हमें उम्मीद है कि आपका वीडियो अच्छी गुणवत्ता का होगा।",
|
||||
"videoLowQuality": "हमें उम्मीद है कि आपका वीडियो फ्रेम दर और रिज़ॉल्यूशन के मामले में निम्न गुणवत्ता का होगा।",
|
||||
"videoTearing": "हमें उम्मीद है कि आपका वीडियो धुंधला होगा या इसमें दृश्य गड़बड़ियां हो सकती हैं।"
|
||||
},
|
||||
"copyAndShare": "मीटिंग लिंक कॉपी और साझा करे ",
|
||||
"dialInMeeting": "मीटिंग में डायल करें",
|
||||
@@ -637,7 +637,7 @@
|
||||
"disconnected": "डिस्कनेक्ट किया गया",
|
||||
"expired": "एक्सपायर्ड",
|
||||
"ignored": "Ignored",
|
||||
"initializingCall": "Initializing Call…",
|
||||
"initializingCall": "कॉल प्रारंभ की जा रही है…",
|
||||
"invited": "आमंत्रित",
|
||||
"rejected": "अस्वीकृत",
|
||||
"ringing": "Ringing…"
|
||||
@@ -650,38 +650,38 @@
|
||||
},
|
||||
"raisedHand": "बोलना चाहेंगे",
|
||||
"recording": {
|
||||
"authDropboxText": "Upload to Dropbox",
|
||||
"availableSpace": "Available space: {{spaceLeft}} MB (approximately {{duration}} minutes of recording)",
|
||||
"beta": "BETA",
|
||||
"busy": "We're working on freeing recording resources. Please try again in a few minutes.",
|
||||
"authDropboxText": "ड्रॉपबॉक्स पर अपलोड करें",
|
||||
"availableSpace": "उपलब्ध स्थान: {{spaceLeft}} MB (लगभग {{duration}} मिनट की रिकॉर्डिंग)",
|
||||
"beta": "बीटा",
|
||||
"busy": "हम रिकॉर्डिंग संसाधनों को मुक्त करने पर काम कर रहे हैं। कृपया कुछ मिनटों में पुनः प्रयास करें।",
|
||||
"busyTitle": "सभी रिकॉर्डर अभी व्यस्त हैं",
|
||||
"error": "रिकॉर्डिंग विफल हुई। कृपया पुन: प्रयास करें।",
|
||||
"error": "रिकॉर्डिंग विफल हुई। कृपया पुनः प्रयास करें।",
|
||||
"expandedOff": "रिकॉर्डिंग बंद हो गई है",
|
||||
"expandedOn": "The meeting is currently being recorded.",
|
||||
"expandedOn": "बैठक की रिकॉर्डिंग की जा रही है।",
|
||||
"expandedPending": "रिकॉर्डिंग शुरू की जा रही है…",
|
||||
"failedToStart": "रिकॉर्डिंग शुरू करने में विफलता हुई।",
|
||||
"fileSharingdescription": "Share recording with meeting participants",
|
||||
"limitNotificationDescriptionNative": "Due to high demand your recording will be limited to {{limit}} min. For unlimited recordings try <3>{{app}}</3>.",
|
||||
"limitNotificationDescriptionWeb": "Due to high demand your recording will be limited to {{limit}} min. For unlimited recordings try <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"live": "LIVE",
|
||||
"loggedIn": "Logged in as {{userName}}",
|
||||
"off": "Recording stopped",
|
||||
"offBy": "{{name}} stopped the recording",
|
||||
"on": "Recording started",
|
||||
"onBy": "{{name}} started the recording",
|
||||
"pending": "Preparing to record the meeting…",
|
||||
"rec": "REC",
|
||||
"serviceDescription": "Your recording will be saved by the recording service",
|
||||
"serviceDescriptionCloud": "Cloud recording",
|
||||
"serviceName": "Recording service",
|
||||
"signIn": "Sign in",
|
||||
"signOut": "Sign out",
|
||||
"fileSharingdescription": "रिकॉर्डिंग को बैठक प्रतिभागियों के साथ साझा करें",
|
||||
"limitNotificationDescriptionNative": "उच्च मांग के कारण आपकी रिकॉर्डिंग {{limit}} मिनट तक सीमित रहेगी। असीमित रिकॉर्डिंग के लिए <3>{{app}}</3> आज़माएँ।",
|
||||
"limitNotificationDescriptionWeb": "उच्च मांग के कारण आपकी रिकॉर्डिंग {{limit}} मिनट तक सीमित रहेगी। असीमित रिकॉर्डिंग के लिए <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a> आज़माएँ।",
|
||||
"live": "लाइव",
|
||||
"loggedIn": "{{userName}} के रूप में लॉग इन किया गया",
|
||||
"off": "रिकॉर्डिंग बंद हो गई",
|
||||
"offBy": "{{name}} ने रिकॉर्डिंग बंद की",
|
||||
"on": "रिकॉर्डिंग शुरू हो गई",
|
||||
"onBy": "{{name}} ने रिकॉर्डिंग शुरू की",
|
||||
"pending": "बैठक की रिकॉर्डिंग की तैयारी हो रही है…",
|
||||
"rec": "रिकॉर्डिंग",
|
||||
"serviceDescription": "आपकी रिकॉर्डिंग को रिकॉर्डिंग सेवा द्वारा सहेजा जाएगा",
|
||||
"serviceDescriptionCloud": "क्लाउड रिकॉर्डिंग",
|
||||
"serviceName": "रिकॉर्डिंग सेवा",
|
||||
"signIn": "साइन इन करें",
|
||||
"signOut": "साइन आउट करें",
|
||||
"title": "रिकॉर्डिंग",
|
||||
"unavailable": "ओह! {{serviceName}} वर्तमान में अनुपलब्ध है। हम समस्या को हल करने पर काम कर रहे हैं। कृपया बाद में पुनः प्रयास करें।",
|
||||
"unavailable": "ओह! {{serviceName}} वर्तमान में अनुपलब्ध है। हम इस समस्या को हल करने पर काम कर रहे हैं। कृपया बाद में पुनः प्रयास करें।",
|
||||
"unavailableTitle": "रिकॉर्डिंग उपलब्ध नहीं है"
|
||||
},
|
||||
"sectionList": {
|
||||
"pullToRefresh": "Pull to refresh"
|
||||
"pullToRefresh": "रीफ़्रेश करने के लिए नीचे खींचें"
|
||||
},
|
||||
"security": {
|
||||
"about": "आप अपनी मीटिंग में $t(lockRoomPassword) जोड़ सकते हैं। सहभागियों को मीटिंग में शामिल होने से पहले $t(lockRoomPassword) प्रदान करना होगा।",
|
||||
@@ -691,16 +691,16 @@
|
||||
},
|
||||
"settings": {
|
||||
"calendar": {
|
||||
"about": "The {{appName}} calendar integration is used to securely access your calendar so it can read upcoming events.",
|
||||
"disconnect": "Disconnect",
|
||||
"microsoftSignIn": "Sign in with Microsoft",
|
||||
"signedIn": "Currently accessing calendar events for {{email}}. Click the Disconnect button below to stop accessing calendar events.",
|
||||
"title": "Calendar"
|
||||
"about": "{{appName}} कैलेंडर एकीकरण आपके कैलेंडर तक सुरक्षित रूप से पहुंचने के लिए उपयोग किया जाता है ताकि यह आगामी कार्यक्रम पढ़ सके।",
|
||||
"disconnect": "डिस्कनेक्ट करें",
|
||||
"microsoftSignIn": "Microsoft से साइन इन करें",
|
||||
"signedIn": "वर्तमान में {{email}} के कैलेंडर कार्यक्रमों तक पहुंच रही है। कैलेंडर कार्यक्रमों की पहुंच बंद करने के लिए नीचे दिए गए डिस्कनेक्ट बटन पर क्लिक करें।",
|
||||
"title": "कैलेंडर"
|
||||
},
|
||||
"devices": "डिवाइस",
|
||||
"followMe": "Everyone follows me",
|
||||
"followMe": "हर कोई मेरा अनुसरण करेगा",
|
||||
"language": "भाषा",
|
||||
"loggedIn": "Logged in as {{name}}",
|
||||
"loggedIn": "{{name}} के रूप में लॉग इन किया",
|
||||
"microphones": "माइक्रोफोन",
|
||||
"moderator": "Moderator",
|
||||
"more": "More",
|
||||
@@ -710,8 +710,8 @@
|
||||
"selectCamera": "कैमरा",
|
||||
"selectMic": "माइक्रोफोन",
|
||||
"speakers": "Speakers",
|
||||
"startAudioMuted": "Everyone starts muted",
|
||||
"startVideoMuted": "Everyone starts hidden",
|
||||
"startAudioMuted": "सभी लोग म्यूट से शुरू करेंगे",
|
||||
"startVideoMuted": "सभी लोग छिपे हुए शुरू करेंगे",
|
||||
"title": "सेटिंग"
|
||||
},
|
||||
"settingsView": {
|
||||
@@ -720,9 +720,9 @@
|
||||
"alertOk": "ओके",
|
||||
"alertTitle": "चेतावनी",
|
||||
"alertURLText": "दर्ज किया गया सर्वर URL अमान्य है",
|
||||
"buildInfoSection": "Build Information",
|
||||
"buildInfoSection": "बिल्ड जानकारी",
|
||||
"conferenceSection": "सम्मेलन",
|
||||
"disableCallIntegration": "Disable native call integration",
|
||||
"disableCallIntegration": "मूल कॉल एकीकरण अक्षम करें",
|
||||
"disableCrashReporting": "क्रैश रिपोर्टिंग अक्षम करें",
|
||||
"disableCrashReportingWarning": "क्या आप वाकई क्रैश रिपोर्टिंग को अक्षम करना चाहते हैं? एप्लिकेशन को पुनरारंभ करने के बाद सेटिंग लागू की जाएगी",
|
||||
"disableP2P": "पीयर-टू-पीयर मोड को अक्षम करें",
|
||||
@@ -731,16 +731,16 @@
|
||||
"header": "सेटिंग",
|
||||
"profileSection": "प्रोफाइल",
|
||||
"serverURL": "सर्वर URL",
|
||||
"showAdvanced": "Show advanced settings",
|
||||
"startWithAudioMuted": "Start with audio muted",
|
||||
"startWithVideoMuted": "Start with video muted",
|
||||
"showAdvanced": "उन्नत सेटिंग्स दिखाएं",
|
||||
"startWithAudioMuted": "ऑडियो म्यूट के साथ शुरू करें",
|
||||
"startWithVideoMuted": "वीडियो म्यूट के साथ शुरू करें",
|
||||
"version": "संस्करण"
|
||||
},
|
||||
"share": {
|
||||
"dialInfoText": "\n\n=====\n\nJust want to dial in on your phone?\n\n{{defaultDialInNumber}}Click this link to see the dial in phone numbers for this meeting\n{{dialInfoPageUrl}}",
|
||||
"mainText": "मीटिंग में शामिल होने के लिए निम्न लिंक पर क्लिक करें:\n{{roomUrl}}"
|
||||
},
|
||||
"speaker": "Speaker",
|
||||
"speaker": "स्पीकर",
|
||||
"speakerStats": {
|
||||
"hours": "{{count}}h",
|
||||
"minutes": "{{count}}m",
|
||||
@@ -748,8 +748,8 @@
|
||||
"search": "खोजें",
|
||||
"searchHint": "प्रतिभागियों को खोजें",
|
||||
"seconds": "{{count}}s",
|
||||
"speakerStats": "Speaker Stats",
|
||||
"speakerTime": "Speaker Time"
|
||||
"speakerStats": "स्पीकर आंकड़े",
|
||||
"speakerTime": "स्पीकर समय"
|
||||
},
|
||||
"startupoverlay": {
|
||||
"genericTitle": "मीटिंग को आपके माइक्रोफ़ोन और कैमरे का उपयोग करने की आवश्यकता है।",
|
||||
@@ -825,10 +825,10 @@
|
||||
"download": "हमारे एप्लिकेशन डाउनलोड करें",
|
||||
"e2ee": "एंड-टू-एंड एन्क्रिप्शन",
|
||||
"embedMeeting": "Embed meeting",
|
||||
"enterFullScreen": "View full screen",
|
||||
"enterTileView": "Enter tile view",
|
||||
"exitFullScreen": "Exit full screen",
|
||||
"exitTileView": "Exit tile view",
|
||||
"enterFullScreen": "पूर्ण स्क्रीन में देखें",
|
||||
"enterTileView": "टाइल दृश्य में प्रवेश करें",
|
||||
"exitFullScreen": "पूर्ण स्क्रीन से बाहर निकलें",
|
||||
"exitTileView": "टाइल दृश्य से बाहर निकलें",
|
||||
"feedback": "प्रतिक्रिया छोड़ें",
|
||||
"hangup": "छोड़ें",
|
||||
"help": "Help",
|
||||
@@ -837,7 +837,7 @@
|
||||
"lobbyButtonEnable": "लॉबी मोड सक्षम करें",
|
||||
"login": "लॉग इन",
|
||||
"logout": "लॉगआउट",
|
||||
"lowerYourHand": "Lower your hand",
|
||||
"lowerYourHand": "अपना हाथ नीचे करें",
|
||||
"moreActions": "More actions",
|
||||
"moreOptions": "अधिक विकल्प",
|
||||
"mute": "म्यूट / अनम्यूट",
|
||||
@@ -866,7 +866,7 @@
|
||||
"startSubtitles": "Start subtitles",
|
||||
"stopScreenSharing": "स्क्रीन शेयरिंग बंद करो",
|
||||
"stopSharedVideo": "YouTube वीडियो बंद करें",
|
||||
"stopSubtitles": "Stop subtitles",
|
||||
"stopSubtitles": "उपशीर्षक बंद करें",
|
||||
"talkWhileMutedPopup": "बोलने की कोशिश कर रहा है? आप मौन हैं",
|
||||
"tileViewToggle": "टॉगल टाइल दृश्य",
|
||||
"toggleCamera": "कैमरा टॉगल करें",
|
||||
@@ -874,13 +874,13 @@
|
||||
"videomute": "स्टार्ट / स्टॉप कैमरा"
|
||||
},
|
||||
"transcribing": {
|
||||
"ccButtonTooltip": "Start / Stop subtitles",
|
||||
"ccButtonTooltip": "सबटाइटल शुरू / बंद करें",
|
||||
"error": "ट्रांसक्रिप्शनिंग विफल रही। कृपया पुन: प्रयास करें",
|
||||
"expandedLabel": "वर्तमान में ट्रांसक्रिप्शनिंग चालू है",
|
||||
"failedToStart": "ट्रांसक्रिप्शनिंग प्रारंभ करने में विफल",
|
||||
"labelToolTip": "The meeting is being transcribed",
|
||||
"labelToolTip": "बैठक का लिप्यंतरण किया जा रहा है",
|
||||
"off": "ट्रांसक्रिप्शनिंग बंद कर दिया",
|
||||
"pending": "Preparing to transcribe the meeting…",
|
||||
"pending": "बैठक के ट्रांसक्रिप्शन की तैयारी हो रही है…",
|
||||
"start": "उपशीर्षक दिखाना शुरू करें",
|
||||
"stop": "उपशीर्षक दिखाना बंद करें",
|
||||
"tr": "TR"
|
||||
@@ -899,20 +899,20 @@
|
||||
"pending": "{{displayName}} को आमंत्रित किया गया है"
|
||||
},
|
||||
"videoStatus": {
|
||||
"audioOnly": "AUD",
|
||||
"audioOnlyExpanded": "You are in low bandwidth mode. In this mode you will receive only audio and screen sharing.",
|
||||
"callQuality": "Video Quality",
|
||||
"hd": "HD",
|
||||
"hdTooltip": "Viewing high definition video",
|
||||
"highDefinition": "High definition",
|
||||
"labelTooiltipNoVideo": "No video",
|
||||
"labelTooltipAudioOnly": "Low bandwidth mode enabled",
|
||||
"ld": "LD",
|
||||
"ldTooltip": "Viewing low definition video",
|
||||
"lowDefinition": "Low definition",
|
||||
"sd": "SD",
|
||||
"sdTooltip": "Viewing standard definition video",
|
||||
"standardDefinition": "Standard definition"
|
||||
"audioOnly": "केवल ऑडियो",
|
||||
"audioOnlyExpanded": "आप कम बैंडविड्थ मोड में हैं। इस मोड में आपको केवल ऑडियो और स्क्रीन शेयरिंग प्राप्त होगी।",
|
||||
"callQuality": "वीडियो गुणवत्ता",
|
||||
"hd": "एचडी",
|
||||
"hdTooltip": "हाई डेफिनिशन वीडियो देख रहे हैं",
|
||||
"highDefinition": "हाई डेफिनिशन",
|
||||
"labelTooiltipNoVideo": "कोई वीडियो नहीं",
|
||||
"labelTooltipAudioOnly": "कम बैंडविड्थ मोड सक्षम",
|
||||
"ld": "एलडी",
|
||||
"ldTooltip": "लो डेफिनिशन वीडियो देख रहे हैं",
|
||||
"lowDefinition": "लो डेफिनिशन",
|
||||
"sd": "एसडी",
|
||||
"sdTooltip": "स्टैंडर्ड डेफिनिशन वीडियो देख रहे हैं",
|
||||
"standardDefinition": "स्टैंडर्ड डेफिनिशन"
|
||||
},
|
||||
"videothumbnail": {
|
||||
"connectionInfo": "कनेक्शन जानकारी",
|
||||
|
||||
@@ -371,6 +371,7 @@
|
||||
"sendPrivateMessageTitle": "Invio privatamente?",
|
||||
"serviceUnavailable": "Servizio non disponibile",
|
||||
"sessTerminated": "Chiamata terminata",
|
||||
"sessTerminatedReason": "La chiamata è stata terminata",
|
||||
"sessionRestarted": "Chiamata riavviata automaticamente",
|
||||
"shareAudio": "Continue",
|
||||
"shareAudioTitle": "Come condividere l'audio",
|
||||
|
||||
1584
lang/main-nb.json
Normal file
1584
lang/main-nb.json
Normal file
File diff suppressed because it is too large
Load Diff
1584
lang/main-no.json
Normal file
1584
lang/main-no.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -263,6 +263,7 @@
|
||||
"Remove": "Remove",
|
||||
"Share": "Share",
|
||||
"Submit": "Submit",
|
||||
"Understand": "I understand",
|
||||
"WaitForHostMsg": "The conference has not yet started because no moderators have yet arrived. If you'd like to become a moderator please log-in. Otherwise, please wait.",
|
||||
"WaitForHostNoAuthMsg": "The conference has not yet started because no moderators have yet arrived. Please wait.",
|
||||
"WaitingForHostButton": "Wait for moderator",
|
||||
@@ -358,7 +359,7 @@
|
||||
"micTimeoutError": "Could not start audio source. Timeout occurred!",
|
||||
"micUnknownError": "Cannot use microphone for an unknown reason.",
|
||||
"moderationAudioLabel": "Allow attendees to unmute themselves",
|
||||
"moderationVideoLabel": "Allow attendees to start their video",
|
||||
"moderationVideoLabel": "Allow non-moderators to start their video",
|
||||
"muteEveryoneDialog": "The participants can unmute themselves at any time.",
|
||||
"muteEveryoneDialogModerationOn": "The participants can send a request to speak at any time.",
|
||||
"muteEveryoneElseDialog": "Once muted, you won't be able to unmute them, but they can unmute themselves at any time.",
|
||||
@@ -393,6 +394,8 @@
|
||||
"recentlyUsedObjects": "Your recently used objects",
|
||||
"recording": "Recording",
|
||||
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Not possible while a live stream is active",
|
||||
"recordingInProgressDescription": "This meeting is being recorded. Your audio and video have been muted. If you choose to unmute, you consent to being recorded.",
|
||||
"recordingInProgressTitle": "Recording in progress",
|
||||
"rejoinNow": "Rejoin now",
|
||||
"remoteControlAllowedMessage": "{{user}} accepted your remote control request!",
|
||||
"remoteControlDeniedMessage": "{{user}} rejected your remote control request!",
|
||||
@@ -733,7 +736,9 @@
|
||||
"me": "me",
|
||||
"notify": {
|
||||
"OldElectronAPPTitle": "Security vulnerability!",
|
||||
"allowAction": "Allow",
|
||||
"allowAudio": "Allow Audio",
|
||||
"allowBoth": "Both",
|
||||
"allowVideo": "Allow Video",
|
||||
"allowedUnmute": "You can unmute your microphone, start your camera or share your screen.",
|
||||
"audioUnmuteBlockedDescription": "Mic unmute operation has been temporarily blocked because of system limits.",
|
||||
"audioUnmuteBlockedTitle": "Mic unmute blocked!",
|
||||
@@ -755,7 +760,7 @@
|
||||
"focusFail": "{{component}} not available - retry in {{ms}} sec",
|
||||
"gifsMenu": "GIPHY",
|
||||
"groupTitle": "Notifications",
|
||||
"hostAskedUnmute": "The moderator would like you to speak",
|
||||
"hostAskedUnmute": "The moderator would like you to participate.",
|
||||
"invalidTenant": "Invalid tenant",
|
||||
"invalidTenantHyphenDescription": "The tenant you are using is invalid (starts or ends with '-').",
|
||||
"invalidTenantLengthDescription": "The tenant you are using is too long.",
|
||||
@@ -807,7 +812,7 @@
|
||||
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) removed by another participant",
|
||||
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) set by another participant",
|
||||
"raiseHandAction": "Raise hand",
|
||||
"raisedHand": "Would like to speak.",
|
||||
"raisedHand": "Would like to participate.",
|
||||
"raisedHands": "{{participantName}} and {{raisedHands}} more people",
|
||||
"reactionSounds": "Disable sounds",
|
||||
"reactionSoundsForAll": "Disable sounds for all",
|
||||
@@ -824,7 +829,8 @@
|
||||
"suggestRecordingAction": "Start",
|
||||
"suggestRecordingDescription": "Would you like to start a recording?",
|
||||
"suggestRecordingTitle": "Record this meeting",
|
||||
"unmute": "Unmute",
|
||||
"unmute": "Unmute Audio",
|
||||
"unmuteVideo": "Unmute Video",
|
||||
"videoMutedRemotelyDescription": "You can always turn it on again.",
|
||||
"videoMutedRemotelyTitle": "Your video has been turned off by {{participantDisplayName}}",
|
||||
"videoUnmuteBlockedDescription": "Camera unmute and desktop sharing operation have been temporarily blocked because of system limits.",
|
||||
@@ -842,7 +848,7 @@
|
||||
"actions": {
|
||||
"admit": "Admit",
|
||||
"admitAll": "Admit all",
|
||||
"allow": "Allow attendees to:",
|
||||
"allow": "Allow non-moderators to:",
|
||||
"allowVideo": "Allow video",
|
||||
"askUnmute": "Ask to unmute",
|
||||
"audioModeration": "Unmute themselves",
|
||||
@@ -1405,7 +1411,8 @@
|
||||
"ccButtonTooltip": "Start / Stop subtitles",
|
||||
"expandedLabel": "Transcribing is currently on",
|
||||
"failed": "Transcribing failed",
|
||||
"labelToolTip": "The meeting is being transcribed",
|
||||
"labelTooltip": "This meeting is being transcribed.",
|
||||
"labelTooltipExtra": "In addition, a transcript will be available later.",
|
||||
"sourceLanguageDesc": "Currently the meeting language is set to <b>{{sourceLanguage}}</b>. <br/> You can change it from ",
|
||||
"sourceLanguageHere": "here",
|
||||
"start": "Start showing subtitles",
|
||||
@@ -1444,7 +1451,7 @@
|
||||
"ldTooltip": "Viewing low definition video",
|
||||
"lowDefinition": "Low definition",
|
||||
"performanceSettings": "Performance settings",
|
||||
"recording": "Recording in progress",
|
||||
"recording": "This meeting is being recorded.",
|
||||
"sd": "SD",
|
||||
"sdTooltip": "Viewing standard definition video",
|
||||
"standardDefinition": "Standard definition",
|
||||
|
||||
54
modules/API/API.js
Normal file → Executable file
54
modules/API/API.js
Normal file → Executable file
@@ -75,6 +75,7 @@ import {
|
||||
toggleChat
|
||||
} from '../../react/features/chat/actions';
|
||||
import { openChat } from '../../react/features/chat/actions.web';
|
||||
import { showDesktopPicker } from '../../react/features/desktop-picker/actions';
|
||||
import {
|
||||
processExternalDeviceRequest
|
||||
} from '../../react/features/device-selection/functions';
|
||||
@@ -491,7 +492,8 @@ function initCommands() {
|
||||
APP.store.dispatch(toggleRequestingSubtitles());
|
||||
},
|
||||
'set-subtitles': (enabled, displaySubtitles, language) => {
|
||||
APP.store.dispatch(setRequestingSubtitles(enabled, displaySubtitles, language));
|
||||
APP.store.dispatch(setRequestingSubtitles(
|
||||
enabled, displaySubtitles, language ? `translation-languages:${language}` : null));
|
||||
},
|
||||
'toggle-tile-view': () => {
|
||||
sendAnalytics(createApiEvent('tile-view.toggled'));
|
||||
@@ -594,9 +596,13 @@ function initCommands() {
|
||||
* Defaults to "normal" if not provided.
|
||||
* @param { string } arg.timeout - Timeout type, either `short`, `medium`, `long` or `sticky`.
|
||||
* Defaults to "short" if not provided.
|
||||
* @param { Array<Object> } arg.customActions - An array of custom actions to be displayed in the notification.
|
||||
* Each object should have a `label` and a `uuid` property. It should be used along a listener
|
||||
* for the `customNotificationActionTriggered` event to handle the custom action.
|
||||
* @returns {void}
|
||||
*/
|
||||
'show-notification': ({
|
||||
customActions = [],
|
||||
title,
|
||||
description,
|
||||
uid,
|
||||
@@ -618,7 +624,15 @@ function initCommands() {
|
||||
return;
|
||||
}
|
||||
|
||||
const handlers = customActions.map(({ uuid }) => () => {
|
||||
APP.API.notifyCustomNotificationActionTriggered(uuid);
|
||||
});
|
||||
|
||||
const keys = customActions.map(({ label }) => label);
|
||||
|
||||
APP.store.dispatch(showNotification({
|
||||
customActionHandler: handlers,
|
||||
customActionNameKey: keys,
|
||||
uid,
|
||||
title,
|
||||
description,
|
||||
@@ -1036,6 +1050,12 @@ function initCommands() {
|
||||
callback(getRoomsInfo(APP.store.getState()));
|
||||
break;
|
||||
}
|
||||
case 'get-shared-document-url': {
|
||||
const { etherpad } = APP.store.getState()['features/etherpad'];
|
||||
|
||||
callback(etherpad?.documentUrl || '');
|
||||
break;
|
||||
}
|
||||
case 'get-p2p-status': {
|
||||
callback(isP2pActive(APP.store.getState()));
|
||||
break;
|
||||
@@ -1048,6 +1068,23 @@ function initCommands() {
|
||||
}
|
||||
case '_new_electron_screensharing_supported': {
|
||||
callback(true);
|
||||
|
||||
break;
|
||||
}
|
||||
case 'open-desktop-picker': {
|
||||
const { desktopSharingSources } = APP.store.getState()['features/base/config'];
|
||||
const options = {
|
||||
desktopSharingSources: desktopSharingSources ?? [ 'screen', 'window' ]
|
||||
};
|
||||
const onSourceChoose = (_streamId, _type, screenShareAudio, source) => {
|
||||
callback({
|
||||
screenShareAudio,
|
||||
source
|
||||
});
|
||||
};
|
||||
|
||||
dispatch(showDesktopPicker(options, onSourceChoose));
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1482,6 +1519,21 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that a custom notification action has been triggered.
|
||||
*
|
||||
* @param {string} actionUuid - The UUID of the action that has been triggered.
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyCustomNotificationActionTriggered(actionUuid) {
|
||||
this._sendEvent({
|
||||
name: 'custom-notification-action-triggered',
|
||||
data: {
|
||||
id: actionUuid
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that the list of sharing participants changed.
|
||||
*
|
||||
|
||||
27
modules/API/external/external_api.js
vendored
27
modules/API/external/external_api.js
vendored
@@ -114,6 +114,7 @@ const events = {
|
||||
'compute-pressure-changed': 'computePressureChanged',
|
||||
'conference-created-timestamp': 'conferenceCreatedTimestamp',
|
||||
'content-sharing-participants-changed': 'contentSharingParticipantsChanged',
|
||||
'custom-notification-action-triggered': 'customNotificationActionTriggered',
|
||||
'data-channel-closed': 'dataChannelClosed',
|
||||
'data-channel-opened': 'dataChannelOpened',
|
||||
'device-list-changed': 'deviceListChanged',
|
||||
@@ -675,12 +676,23 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
*
|
||||
* @returns {Object} Rooms info.
|
||||
*/
|
||||
async getRoomsInfo() {
|
||||
getRoomsInfo() {
|
||||
return this._transport.sendRequest({
|
||||
name: 'rooms-info'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Shared Document Url of the conference.
|
||||
*
|
||||
* @returns {Object} Rooms info.
|
||||
*/
|
||||
getSharedDocumentUrl() {
|
||||
return this._transport.sendRequest({
|
||||
name: 'get-shared-document-url'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the conference is P2P.
|
||||
*
|
||||
@@ -1243,7 +1255,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
* @returns {Promise}
|
||||
*
|
||||
* TODO: should be removed after we make sure that all Electron clients use only versions
|
||||
* after with the legacy SS suport was removed from the electron SDK. If we remove it now the SS for Electron
|
||||
* after with the legacy SS support was removed from the electron SDK. If we remove it now the SS for Electron
|
||||
* clients with older versions wont work.
|
||||
*/
|
||||
_isNewElectronScreensharingSupported() {
|
||||
@@ -1455,4 +1467,15 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
setVirtualBackground(enabled, backgroundImage) {
|
||||
this.executeCommand('setVirtualBackground', enabled, backgroundImage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the desktop picker. This is invoked by the Electron SDK when gDM is used.
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_openDesktopPicker() {
|
||||
return this._transport.sendRequest({
|
||||
name: 'open-desktop-picker'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export default from './API';
|
||||
export { default } from './API';
|
||||
export * from './constants';
|
||||
|
||||
@@ -120,7 +120,9 @@ UI.unbindEvents = () => {
|
||||
* @param {string} name etherpad id
|
||||
*/
|
||||
UI.initEtherpad = name => {
|
||||
const etherpadBaseUrl = sanitizeUrl(config.etherpad_base);
|
||||
const { getState, dispatch } = APP.store;
|
||||
const configState = getState()['features/base/config'];
|
||||
const etherpadBaseUrl = sanitizeUrl(configState.etherpad_base);
|
||||
|
||||
if (etherpadManager || !etherpadBaseUrl || !name) {
|
||||
return;
|
||||
@@ -131,9 +133,9 @@ UI.initEtherpad = name => {
|
||||
|
||||
const url = new URL(name, etherpadBaseUrl);
|
||||
|
||||
APP.store.dispatch(setDocumentUrl(url.toString()));
|
||||
dispatch(setDocumentUrl(url.toString()));
|
||||
|
||||
if (config.openSharedDocumentOnJoin) {
|
||||
if (configState.openSharedDocumentOnJoin) {
|
||||
etherpadManager.toggleEtherpad();
|
||||
}
|
||||
};
|
||||
|
||||
973
package-lock.json
generated
973
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
26
package.json
26
package.json
@@ -26,7 +26,7 @@
|
||||
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.19/jitsi-excalidraw-0.0.19.tgz",
|
||||
"@jitsi/js-utils": "2.2.1",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
"@jitsi/rnnoise-wasm": "0.2.0",
|
||||
"@jitsi/rnnoise-wasm": "0.2.1",
|
||||
"@jitsi/rtcstats": "9.5.1",
|
||||
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
|
||||
"@microsoft/microsoft-graph-client": "3.0.1",
|
||||
@@ -68,14 +68,13 @@
|
||||
"js-md5": "0.6.1",
|
||||
"js-sha512": "0.8.0",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1908.0.0+2a5d7fcc/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1928.0.0+763b2c8f/lib-jitsi-meet.tgz",
|
||||
"lodash-es": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
"null-loader": "4.0.1",
|
||||
"optional-require": "1.0.3",
|
||||
"pixelmatch": "5.3.0",
|
||||
"promise.allsettled": "1.0.4",
|
||||
"promise.withresolvers": "1.0.3",
|
||||
"punycode": "2.3.0",
|
||||
"react": "18.2.0",
|
||||
@@ -84,7 +83,7 @@
|
||||
"react-focus-on": "3.8.1",
|
||||
"react-i18next": "10.11.4",
|
||||
"react-linkify": "1.0.0-alpha",
|
||||
"react-native": "0.75.4",
|
||||
"react-native": "0.75.5",
|
||||
"react-native-background-timer": "2.4.1",
|
||||
"react-native-calendar-events": "2.2.0",
|
||||
"react-native-default-preference": "1.4.4",
|
||||
@@ -130,14 +129,11 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.25.9",
|
||||
"@babel/eslint-parser": "7.25.9",
|
||||
"@babel/plugin-proposal-export-default-from": "7.25.9",
|
||||
"@babel/plugin-transform-private-methods": "7.25.9",
|
||||
"@babel/preset-env": "7.25.9",
|
||||
"@babel/preset-react": "7.25.9",
|
||||
"@jitsi/eslint-config": "5.0.9",
|
||||
"@react-native/metro-config": "0.75.4",
|
||||
"@stylistic/eslint-plugin": "2.12.1",
|
||||
"@jitsi/eslint-config": "6.0.1",
|
||||
"@react-native/metro-config": "0.75.5",
|
||||
"@types/amplitude-js": "8.16.5",
|
||||
"@types/audioworklet": "0.0.29",
|
||||
"@types/dom-screen-wake-lock": "1.0.1",
|
||||
@@ -163,8 +159,6 @@
|
||||
"@types/w3c-image-capture": "1.0.6",
|
||||
"@types/w3c-web-hid": "1.0.3",
|
||||
"@types/zxcvbn": "4.4.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.19.1",
|
||||
"@typescript-eslint/parser": "8.19.1",
|
||||
"@wdio/allure-reporter": "9.4.3",
|
||||
"@wdio/cli": "9.4.3",
|
||||
"@wdio/globals": "9.4.3",
|
||||
@@ -175,6 +169,7 @@
|
||||
"babel-plugin-optional-require": "0.3.1",
|
||||
"circular-dependency-plugin": "5.2.0",
|
||||
"clean-css-cli": "4.3.0",
|
||||
"core-js": "3.40.0",
|
||||
"css-loader": "6.8.1",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-plugin-import": "2.31.0",
|
||||
@@ -200,9 +195,6 @@
|
||||
"webpack-cli": "5.1.4",
|
||||
"webpack-dev-server": "5.1.0"
|
||||
},
|
||||
"overrides": {
|
||||
"@xmldom/xmldom": "0.8.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.0.0",
|
||||
"npm": ">=10.0.0"
|
||||
@@ -224,10 +216,14 @@
|
||||
"start": "make dev",
|
||||
"test": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.conf.ts",
|
||||
"test-single": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.conf.ts --spec",
|
||||
"test-ff-single": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.firefox.conf.ts --spec",
|
||||
"test-ff": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.firefox.conf.ts",
|
||||
"test-dev": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.dev.conf.ts",
|
||||
"test-dev-single": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.dev.conf.ts --spec",
|
||||
"test-grid": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.grid.conf.ts",
|
||||
"test-grid-single": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.grid.conf.ts --spec"
|
||||
"test-grid-single": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.grid.conf.ts --spec",
|
||||
"test-grid-ff": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.grid.firefox.conf.ts",
|
||||
"test-grid-ff-single": "DOTENV_CONFIG_PATH=tests/.env wdio run tests/wdio.grid.firefox.conf.ts --spec"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "17.0.14",
|
||||
|
||||
@@ -87,9 +87,6 @@
|
||||
"react-native-webrtc": "0.0.0",
|
||||
"react-native-webview": "0.0.0"
|
||||
},
|
||||
"overrides": {
|
||||
"@xmldom/xmldom": "0.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "node sdk_instructions.js",
|
||||
"prepare": "node prepare_sdk.js"
|
||||
|
||||
2
react-native-sdk/update_dependencies.js
vendored
2
react-native-sdk/update_dependencies.js
vendored
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable guard-for-in, no-continue */
|
||||
/* eslint-disable guard-for-in */
|
||||
/* global __dirname */
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
module.exports = {
|
||||
'plugins': [
|
||||
plugins: [
|
||||
'react-native'
|
||||
],
|
||||
'rules': {
|
||||
rules: {
|
||||
'react-native/no-color-literals': 2,
|
||||
'react-native/no-inline-styles': 2,
|
||||
'react-native/no-unused-styles': 2,
|
||||
'react-native/split-platform-components': 2
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
module.exports = {
|
||||
'extends': [
|
||||
extends: [
|
||||
'../.eslintrc.js',
|
||||
'@jitsi/eslint-config/jsdoc',
|
||||
'@jitsi/eslint-config/react',
|
||||
'.eslintrc-react-native.js'
|
||||
],
|
||||
'overrides': [
|
||||
overrides: [
|
||||
{
|
||||
'files': [ '*.ts', '*.tsx' ],
|
||||
files: [ '*.ts', '*.tsx' ],
|
||||
extends: [ '@jitsi/eslint-config/typescript' ],
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
project: [ './tsconfig.web.json', './tsconfig.native.json' ]
|
||||
},
|
||||
rules: {
|
||||
// TODO: Remove these and fix the warnings
|
||||
'@typescript-eslint/no-unsafe-function-type': 0,
|
||||
'@typescript-eslint/no-wrapper-object-types': 0,
|
||||
|
||||
'@typescript-eslint/no-require-imports': 0
|
||||
}
|
||||
}
|
||||
],
|
||||
'settings': {
|
||||
'react': {
|
||||
settings: {
|
||||
react: {
|
||||
'version': 'detect'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ export default class AlwaysOnTop extends Component<any, IState> {
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
override componentDidMount() {
|
||||
api.on('avatarChanged', this._avatarChangedListener);
|
||||
api.on('displayNameChange', this._displayNameChangedListener);
|
||||
api.on('largeVideoChanged', this._videoChangedListener);
|
||||
@@ -231,7 +231,7 @@ export default class AlwaysOnTop extends Component<any, IState> {
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentDidUpdate(_prevProps: any, prevState: IState) {
|
||||
override componentDidUpdate(_prevProps: any, prevState: IState) {
|
||||
if (!prevState.visible && this.state.visible) {
|
||||
this._hideToolbarAfterTimeout();
|
||||
}
|
||||
@@ -243,7 +243,7 @@ export default class AlwaysOnTop extends Component<any, IState> {
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
override componentWillUnmount() {
|
||||
api.removeListener('avatarChanged', this._avatarChangedListener);
|
||||
api.removeListener(
|
||||
'displayNameChange',
|
||||
@@ -267,7 +267,7 @@ export default class AlwaysOnTop extends Component<any, IState> {
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
override render() {
|
||||
return (
|
||||
<div id = 'alwaysOnTop'>
|
||||
<Toolbar
|
||||
|
||||
@@ -63,7 +63,7 @@ export default class AudioMuteButton extends Component<Props, IState> {
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
override componentDidMount() {
|
||||
api.on('audioAvailabilityChanged', this._audioAvailabilityListener);
|
||||
api.on('audioMuteStatusChanged', this._audioMutedListener);
|
||||
|
||||
@@ -86,7 +86,7 @@ export default class AudioMuteButton extends Component<Props, IState> {
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
override componentWillUnmount() {
|
||||
api.removeListener(
|
||||
'audioAvailabilityChanged',
|
||||
this._audioAvailabilityListener);
|
||||
@@ -165,7 +165,7 @@ export default class AudioMuteButton extends Component<Props, IState> {
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
override render() {
|
||||
const toggled = this._isAudioMuted();
|
||||
|
||||
return (
|
||||
|
||||
@@ -48,7 +48,7 @@ export default class HangupButton extends Component<Props> {
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
override render() {
|
||||
return (
|
||||
<ToolbarButton
|
||||
accessibilityLabel = { this.accessibilityLabel }
|
||||
|
||||
@@ -73,7 +73,7 @@ export default class Toolbar extends Component<Props, IState> {
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
override componentDidMount() {
|
||||
api.on('videoConferenceJoined', this._videoConferenceJoinedListener);
|
||||
|
||||
this._videoConferenceJoinedListener();
|
||||
@@ -106,7 +106,7 @@ export default class Toolbar extends Component<Props, IState> {
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
override componentWillUnmount() {
|
||||
api.removeListener('videoConferenceJoined', this._videoConferenceJoinedListener);
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ export default class Toolbar extends Component<Props, IState> {
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
override render() {
|
||||
const {
|
||||
className = '',
|
||||
onMouseOut,
|
||||
|
||||
@@ -63,7 +63,7 @@ export default class VideoMuteButton extends Component<Props, State> {
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
override componentDidMount() {
|
||||
api.on('videoAvailabilityChanged', this._videoAvailabilityListener);
|
||||
api.on('videoMuteStatusChanged', this._videoMutedListener);
|
||||
|
||||
@@ -85,7 +85,7 @@ export default class VideoMuteButton extends Component<Props, State> {
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
override componentWillUnmount() {
|
||||
api.removeListener(
|
||||
'videoAvailabilityChanged',
|
||||
this._videoAvailabilityListener);
|
||||
@@ -165,7 +165,7 @@ export default class VideoMuteButton extends Component<Props, State> {
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
override render() {
|
||||
const toggled = this._isVideoMuted();
|
||||
|
||||
return (
|
||||
|
||||
@@ -87,7 +87,6 @@ export async function createHandlers({ getState }: IStore) {
|
||||
amplitudeIncludeUTM,
|
||||
blackListedEvents,
|
||||
scriptURLs,
|
||||
googleAnalyticsTrackingId,
|
||||
matomoEndpoint,
|
||||
matomoSiteID,
|
||||
whiteListedEvents
|
||||
@@ -98,7 +97,6 @@ export async function createHandlers({ getState }: IStore) {
|
||||
amplitudeIncludeUTM,
|
||||
blackListedEvents,
|
||||
envType: deploymentInfo?.envType || 'dev',
|
||||
googleAnalyticsTrackingId,
|
||||
matomoEndpoint,
|
||||
matomoSiteID,
|
||||
group,
|
||||
@@ -154,30 +152,6 @@ export async function createHandlers({ getState }: IStore) {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a url is a data URL or not.
|
||||
*
|
||||
* @param {string} url - The URL to be checked.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isDataURL(url?: string): boolean {
|
||||
if (typeof url !== 'string') { // The icon will be ignored
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const urlObject = new URL(url);
|
||||
|
||||
if (urlObject.protocol === 'data:') {
|
||||
return false;
|
||||
}
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inits JitsiMeetJS.analytics by setting permanent properties and setting the handlers from the loaded scripts.
|
||||
* NOTE: Has to be used after JitsiMeetJS.init. Otherwise analytics will be null.
|
||||
@@ -210,20 +184,11 @@ export function initAnalytics(store: IStore, handlers: Array<Object>): boolean {
|
||||
isPromotedFromVisitor?: boolean;
|
||||
isVisitor?: boolean;
|
||||
overwritesCustomButtonsWithURL?: boolean;
|
||||
overwritesCustomParticipantButtonsWithURL?: boolean;
|
||||
overwritesDefaultLogoUrl?: boolean;
|
||||
overwritesDeploymentUrls?: boolean;
|
||||
overwritesEtherpadBase?: boolean;
|
||||
overwritesHosts?: boolean;
|
||||
overwritesIceServers?: boolean;
|
||||
overwritesLiveStreamingUrls?: boolean;
|
||||
overwritesPeopleSearchUrl?: boolean;
|
||||
overwritesPrejoinConfigICEUrl?: boolean;
|
||||
overwritesSalesforceUrl?: boolean;
|
||||
overwritesSupportUrl?: boolean;
|
||||
overwritesWatchRTCConfigParams?: boolean;
|
||||
overwritesWatchRTCProxyUrl?: boolean;
|
||||
overwritesWatchRTCWSUrl?: boolean;
|
||||
server?: string;
|
||||
tenant?: string;
|
||||
wasLobbyVisible?: boolean;
|
||||
@@ -265,27 +230,8 @@ export function initAnalytics(store: IStore, handlers: Array<Object>): boolean {
|
||||
// TODO: Temporary metric. To be removed once we don't need it.
|
||||
permanentProperties.overwritesSupportUrl = 'interfaceConfig.SUPPORT_URL' in params;
|
||||
permanentProperties.overwritesSalesforceUrl = 'config.salesforceUrl' in params;
|
||||
permanentProperties.overwritesPeopleSearchUrl = 'config.peopleSearchUrl' in params;
|
||||
permanentProperties.overwritesDefaultLogoUrl = 'config.defaultLogoUrl' in params;
|
||||
permanentProperties.overwritesEtherpadBase = 'config.etherpad_base' in params;
|
||||
const hosts = params['config.hosts'] ?? {};
|
||||
const hostsProps = [ 'anonymousdomain', 'authdomain', 'domain', 'focus', 'muc', 'visitorFocus' ];
|
||||
|
||||
permanentProperties.overwritesHosts = 'config.hosts' in params
|
||||
|| Boolean(hostsProps.find(p => `config.hosts.${p}` in params || (typeof hosts === 'object' && p in hosts)));
|
||||
|
||||
permanentProperties.overwritesWatchRTCConfigParams = 'config.watchRTCConfigParams' in params;
|
||||
const watchRTCConfigParams = params['config.watchRTCConfigParams'] ?? {};
|
||||
|
||||
permanentProperties.overwritesWatchRTCProxyUrl = ('config.watchRTCConfigParams.proxyUrl' in params)
|
||||
|| (typeof watchRTCConfigParams === 'object' && 'proxyUrl' in watchRTCConfigParams);
|
||||
permanentProperties.overwritesWatchRTCWSUrl = ('config.watchRTCConfigParams.wsUrl' in params)
|
||||
|| (typeof watchRTCConfigParams === 'object' && 'wsUrl' in watchRTCConfigParams);
|
||||
|
||||
const prejoinConfig = params['config.prejoinConfig'] ?? {};
|
||||
|
||||
permanentProperties.overwritesPrejoinConfigICEUrl = ('config.prejoinConfig.preCallTestICEUrl' in params)
|
||||
|| (typeof prejoinConfig === 'object' && 'preCallTestICEUrl' in prejoinConfig);
|
||||
const deploymentUrlsConfig = params['config.deploymentUrls'] ?? {};
|
||||
|
||||
permanentProperties.overwritesDeploymentUrls
|
||||
@@ -307,17 +253,7 @@ export function initAnalytics(store: IStore, handlers: Array<Object>): boolean {
|
||||
)
|
||||
);
|
||||
|
||||
permanentProperties.overwritesIceServers = Boolean(Object.keys(params).find(k => k.startsWith('iceServers')));
|
||||
|
||||
const customToolbarButtons = params['config.customToolbarButtons'] ?? [];
|
||||
|
||||
permanentProperties.overwritesCustomButtonsWithURL = Boolean(
|
||||
customToolbarButtons.find(({ icon }: { icon: string; }) => isDataURL(icon)));
|
||||
|
||||
const customParticipantMenuButtons = params['config.customParticipantMenuButtons'] ?? [];
|
||||
|
||||
permanentProperties.overwritesCustomParticipantButtonsWithURL = Boolean(
|
||||
customParticipantMenuButtons.find(({ icon }: { icon: string; }) => isDataURL(icon)));
|
||||
permanentProperties.overwritesCustomButtonsWithURL = 'config.customToolbarButtons' in params;
|
||||
|
||||
// Optionally, include local deployment information based on the
|
||||
// contents of window.config.deploymentInfo.
|
||||
|
||||
@@ -14,7 +14,6 @@ interface IOptions {
|
||||
amplitudeIncludeUTM?: boolean;
|
||||
blackListedEvents?: string[];
|
||||
envType?: string;
|
||||
googleAnalyticsTrackingId?: string;
|
||||
group?: string;
|
||||
host?: string;
|
||||
matomoEndpoint?: string;
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
/* global ga */
|
||||
|
||||
import { getJitsiMeetGlobalNS } from '../../base/util/helpers';
|
||||
|
||||
import AbstractHandler, { IEvent } from './AbstractHandler';
|
||||
|
||||
/**
|
||||
* Analytics handler for Google Analytics.
|
||||
*/
|
||||
class GoogleAnalyticsHandler extends AbstractHandler {
|
||||
_userProperties: Object;
|
||||
_userPropertiesString: string;
|
||||
|
||||
/**
|
||||
* Creates new instance of the GA analytics handler.
|
||||
*
|
||||
* @param {Object} options - The Google Analytics options.
|
||||
* @param {string} options.googleAnalyticsTrackingId - The GA track id
|
||||
* required by the GA API.
|
||||
*/
|
||||
constructor(options: any) {
|
||||
super(options);
|
||||
|
||||
this._userProperties = {};
|
||||
|
||||
if (!options.googleAnalyticsTrackingId) {
|
||||
throw new Error('Failed to initialize Google Analytics handler, no tracking ID');
|
||||
}
|
||||
|
||||
this._enabled = true;
|
||||
this._initGoogleAnalytics(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the ga object.
|
||||
*
|
||||
* @param {Object} options - The Google Analytics options.
|
||||
* @param {string} options.googleAnalyticsTrackingId - The GA track id
|
||||
* required by the GA API.
|
||||
* @returns {void}
|
||||
*/
|
||||
_initGoogleAnalytics(options: any) {
|
||||
/**
|
||||
* TODO: Keep this local, there's no need to add it to window.
|
||||
*/
|
||||
/* eslint-disable */ // @ts-ignore
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
// @ts-ignore
|
||||
(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');
|
||||
/* eslint-enable */
|
||||
// @ts-ignore
|
||||
ga('create', options.googleAnalyticsTrackingId, 'auto');
|
||||
|
||||
// @ts-ignore
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {number} - 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
|
||||
*/
|
||||
_extractValue(event: IEvent) {
|
||||
let value: string | number | undefined = 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
|
||||
*/
|
||||
_extractLabel(event: IEvent) {
|
||||
const { attributes = {} } = event;
|
||||
const labelsArray
|
||||
= Object.keys(attributes).map(key => `${key}=${attributes[key]}`);
|
||||
|
||||
labelsArray.push(this._userPropertiesString);
|
||||
|
||||
return labelsArray.join('&');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the permanent properties for the current session.
|
||||
*
|
||||
* @param {Object} userProps - The permanent portperties.
|
||||
* @returns {void}
|
||||
*/
|
||||
setUserProperties(userProps: any = {}) {
|
||||
if (!this._enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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.
|
||||
const filter = [ 'user_agent', 'callstats_name' ];
|
||||
|
||||
this._userPropertiesString
|
||||
= Object.keys(userProps)
|
||||
.filter(key => filter.indexOf(key) === -1)
|
||||
.map(key => `permanent_${key}=${userProps[key]}`)
|
||||
.join('&');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @returns {void}
|
||||
*/
|
||||
sendEvent(event: IEvent) {
|
||||
if (this._shouldIgnore(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const gaEvent: {
|
||||
eventAction?: string;
|
||||
eventCategory: string;
|
||||
eventLabel: string;
|
||||
eventValue?: number;
|
||||
} = {
|
||||
'eventCategory': 'jitsi-meet',
|
||||
'eventAction': this._extractName(event),
|
||||
'eventLabel': this._extractLabel(event)
|
||||
};
|
||||
const value = this._extractValue(event);
|
||||
|
||||
if (!isNaN(value)) {
|
||||
gaEvent.eventValue = value;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
ga('send', 'event', gaEvent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const globalNS = getJitsiMeetGlobalNS();
|
||||
|
||||
globalNS.analyticsHandlers = globalNS.analyticsHandlers || [];
|
||||
globalNS.analyticsHandlers.push(GoogleAnalyticsHandler);
|
||||
@@ -26,17 +26,12 @@ export interface IProps {
|
||||
* @abstract
|
||||
*/
|
||||
export class AbstractApp<P extends IProps = IProps> extends BaseApp<P> {
|
||||
/**
|
||||
* The deferred for the initialization {{promise, resolve, reject}}.
|
||||
*/
|
||||
_init: PromiseWithResolvers<any>;
|
||||
|
||||
/**
|
||||
* Initializes the app.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
async componentDidMount() {
|
||||
override async componentDidMount() {
|
||||
await super.componentDidMount();
|
||||
|
||||
// If a URL was explicitly specified to this React Component, then
|
||||
@@ -49,7 +44,7 @@ export class AbstractApp<P extends IProps = IProps> extends BaseApp<P> {
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
async componentDidUpdate(prevProps: IProps) {
|
||||
override async componentDidUpdate(prevProps: IProps) {
|
||||
const previousUrl = toURLString(prevProps.url);
|
||||
const currentUrl = toURLString(this.props.url);
|
||||
const previousTimestamp = prevProps.timestamp;
|
||||
|
||||
@@ -80,7 +80,7 @@ export class App extends AbstractApp<IProps> {
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
async componentDidMount() {
|
||||
override async componentDidMount() {
|
||||
await super.componentDidMount();
|
||||
|
||||
SplashScreen.hide();
|
||||
@@ -96,7 +96,7 @@ export class App extends AbstractApp<IProps> {
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
override render() {
|
||||
return (
|
||||
<JitsiThemePaperProvider>
|
||||
{ super.render() }
|
||||
|
||||
@@ -28,7 +28,7 @@ export class App extends AbstractApp {
|
||||
* @protected
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_createExtraElement() {
|
||||
override _createExtraElement() {
|
||||
return (
|
||||
<JitsiThemeProvider>
|
||||
<OverlayContainer />
|
||||
@@ -42,7 +42,7 @@ export class App extends AbstractApp {
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_createMainElement(component: React.ComponentType, props?: Object) {
|
||||
override _createMainElement(component: React.ComponentType, props?: Object) {
|
||||
return (
|
||||
<JitsiThemeProvider>
|
||||
<GlobalStyles />
|
||||
@@ -57,7 +57,7 @@ export class App extends AbstractApp {
|
||||
*
|
||||
* @returns {React$Element}
|
||||
*/
|
||||
_renderDialogContainer() {
|
||||
override _renderDialogContainer() {
|
||||
return (
|
||||
<JitsiThemeProvider>
|
||||
<DialogContainer />
|
||||
|
||||
@@ -13,6 +13,7 @@ import '../mobile/react-native-sdk/middleware';
|
||||
import '../mobile/watchos/middleware';
|
||||
import '../share-room/middleware';
|
||||
import '../shared-video/middleware';
|
||||
import '../toolbox/middleware.native';
|
||||
import '../whiteboard/middleware.native';
|
||||
|
||||
import './middlewares.any';
|
||||
|
||||
@@ -36,7 +36,7 @@ class AudioLevelIndicator extends Component<IProps> {
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
override render() {
|
||||
const { audioLevel: passedAudioLevel } = this.props;
|
||||
|
||||
// First make sure we are sensitive enough.
|
||||
|
||||
@@ -132,7 +132,7 @@ class LoginDialog extends Component<IProps, IState> {
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
override render() {
|
||||
const {
|
||||
_connecting: connecting,
|
||||
t
|
||||
|
||||
@@ -60,7 +60,7 @@ class WaitForOwnerDialog extends Component<IProps> {
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
override render() {
|
||||
const { _isConfirmHidden } = this.props;
|
||||
|
||||
return (
|
||||
|
||||
@@ -220,7 +220,7 @@ class LoginDialog extends Component<IProps, IState> {
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
override render() {
|
||||
const {
|
||||
_connecting: connecting,
|
||||
t
|
||||
|
||||
@@ -74,7 +74,7 @@ class WaitForOwnerDialog extends PureComponent<IProps> {
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
override render() {
|
||||
const {
|
||||
t
|
||||
} = this.props;
|
||||
|
||||
@@ -75,7 +75,7 @@ export const _getTokenAuthState = (
|
||||
const params = parseURLParams(locationURL);
|
||||
|
||||
for (const key of Object.keys(params)) {
|
||||
// we allow only config and interfaceConfig overrides in the state
|
||||
// we allow only config, interfaceConfig and iceServers overrides in the state
|
||||
if (key.startsWith('config.') || key.startsWith('interfaceConfig.') || key.startsWith('iceServers.')) {
|
||||
// @ts-ignore
|
||||
state[key] = params[key];
|
||||
|
||||
@@ -4,6 +4,7 @@ import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes';
|
||||
import { getConferenceState } from '../base/conference/functions';
|
||||
import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
|
||||
import { MEDIA_TYPE, MediaType } from '../base/media/constants';
|
||||
import { isAudioMuted, isVideoMuted } from '../base/media/functions';
|
||||
import { PARTICIPANT_UPDATED } from '../base/participants/actionTypes';
|
||||
import { raiseHand } from '../base/participants/actions';
|
||||
import {
|
||||
@@ -208,24 +209,46 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
state => state['features/base/conference'].conference,
|
||||
(conference, { dispatch }, previousConference) => {
|
||||
(conference, { dispatch, getState }, previousConference) => {
|
||||
if (conference && !previousConference) {
|
||||
// local participant is allowed to unmute
|
||||
conference.on(JitsiConferenceEvents.AV_MODERATION_APPROVED, ({ mediaType }: { mediaType: MediaType; }) => {
|
||||
dispatch(localParticipantApproved(mediaType));
|
||||
|
||||
// Audio & video moderation are both enabled at the same time.
|
||||
// Avoid displaying 2 different notifications.
|
||||
if (mediaType === MEDIA_TYPE.AUDIO) {
|
||||
dispatch(showNotification({
|
||||
titleKey: 'notify.hostAskedUnmute',
|
||||
sticky: true,
|
||||
customActionNameKey: [ 'notify.unmute' ],
|
||||
customActionHandler: [ () => dispatch(muteLocal(false, MEDIA_TYPE.AUDIO)) ],
|
||||
uid: ASKED_TO_UNMUTE_NOTIFICATION_ID
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
|
||||
dispatch(playSound(ASKED_TO_UNMUTE_SOUND_ID));
|
||||
const customActionNameKey = [];
|
||||
const customActionHandler = [];
|
||||
|
||||
if ((mediaType === MEDIA_TYPE.AUDIO || getState()['features/av-moderation'].audioUnmuteApproved)
|
||||
&& isAudioMuted(getState())) {
|
||||
customActionNameKey.push('notify.unmute');
|
||||
customActionHandler.push(() => {
|
||||
dispatch(muteLocal(false, MEDIA_TYPE.AUDIO));
|
||||
dispatch(hideNotification(ASKED_TO_UNMUTE_NOTIFICATION_ID));
|
||||
});
|
||||
}
|
||||
|
||||
if ((mediaType === MEDIA_TYPE.VIDEO || getState()['features/av-moderation'].videoUnmuteApproved)
|
||||
&& isVideoMuted(getState())) {
|
||||
customActionNameKey.push('notify.unmuteVideo');
|
||||
customActionHandler.push(() => {
|
||||
dispatch(muteLocal(false, MEDIA_TYPE.VIDEO));
|
||||
dispatch(hideNotification(ASKED_TO_UNMUTE_NOTIFICATION_ID));
|
||||
|
||||
// lower hand as there will be no audio and change in dominant speaker to clear it
|
||||
dispatch(raiseHand(false));
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
dispatch(showNotification({
|
||||
titleKey: 'notify.hostAskedUnmute',
|
||||
sticky: true,
|
||||
customActionNameKey,
|
||||
customActionHandler,
|
||||
uid: ASKED_TO_UNMUTE_NOTIFICATION_ID
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
|
||||
|
||||
dispatch(playSound(ASKED_TO_UNMUTE_SOUND_ID));
|
||||
});
|
||||
|
||||
conference.on(JitsiConferenceEvents.AV_MODERATION_REJECTED, ({ mediaType }: { mediaType: MediaType; }) => {
|
||||
|
||||
@@ -67,7 +67,7 @@ export default class BaseApp<P> extends Component<P, IState> {
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
async componentDidMount() {
|
||||
override async componentDidMount() {
|
||||
/**
|
||||
* Make the mobile {@code BaseApp} wait until the {@code AsyncStorage}
|
||||
* implementation of {@code Storage} initializes fully.
|
||||
@@ -107,7 +107,7 @@ export default class BaseApp<P> extends Component<P, IState> {
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
override componentWillUnmount() {
|
||||
this.state.store?.dispatch(appWillUnmount(this));
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ export default class BaseApp<P> extends Component<P, IState> {
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
componentDidCatch(error: Error, info: Object) {
|
||||
override componentDidCatch(error: Error, info: Object) {
|
||||
logger.error(error, info);
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ export default class BaseApp<P> extends Component<P, IState> {
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
override render() {
|
||||
const { route: { component, props }, store } = this.state;
|
||||
|
||||
if (store) {
|
||||
|
||||
@@ -148,7 +148,7 @@ class Avatar<P extends IProps> extends PureComponent<P, IState> {
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidUpdate(prevProps: P) {
|
||||
override componentDidUpdate(prevProps: P) {
|
||||
const { _corsAvatarURLs, url } = this.props;
|
||||
|
||||
if (prevProps.url !== url) {
|
||||
@@ -170,7 +170,7 @@ class Avatar<P extends IProps> extends PureComponent<P, IState> {
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
override render() {
|
||||
const {
|
||||
_customAvatarBackgrounds,
|
||||
_initialsBase,
|
||||
|
||||
@@ -51,7 +51,7 @@ export default class StatelessAvatar extends Component<IProps> {
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
override render() {
|
||||
const { initials, size, style, url } = this.props;
|
||||
|
||||
let avatar;
|
||||
|
||||
@@ -237,7 +237,6 @@ export function getConferenceOptions(stateful: IStateful) {
|
||||
if (options.disableThirdPartyRequests) {
|
||||
delete config.analytics?.scriptURLs;
|
||||
delete config.analytics?.amplitudeAPPKey;
|
||||
delete config.analytics?.googleAnalyticsTrackingId;
|
||||
}
|
||||
|
||||
return options;
|
||||
|
||||
@@ -177,7 +177,7 @@ function _conferenceFailed({ dispatch, getState }: IStore, next: Function, actio
|
||||
dispatch(showErrorNotification({
|
||||
description: 'Restart initiated because of a bridge failure',
|
||||
titleKey: 'dialog.sessionRestarted'
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
|
||||
}));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -190,7 +190,7 @@ function _conferenceFailed({ dispatch, getState }: IStore, next: Function, actio
|
||||
descriptionArguments: { msg },
|
||||
descriptionKey: msg ? 'dialog.connectErrorWithMsg' : 'dialog.connectError',
|
||||
titleKey: 'connection.CONNFAIL'
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
|
||||
}));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -199,7 +199,7 @@ function _conferenceFailed({ dispatch, getState }: IStore, next: Function, actio
|
||||
hideErrorSupportLink: true,
|
||||
descriptionKey: 'dialog.maxUsersLimitReached',
|
||||
titleKey: 'dialog.maxUsersLimitReachedTitle'
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
|
||||
}));
|
||||
|
||||
// In case of max users(it can be from a visitor node), let's restore
|
||||
// oldConfig if any as we will be back to the main prosody.
|
||||
@@ -236,7 +236,7 @@ function _conferenceFailed({ dispatch, getState }: IStore, next: Function, actio
|
||||
descriptionKey,
|
||||
hideErrorSupportLink: true,
|
||||
titleKey
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
|
||||
}));
|
||||
|
||||
sendAnalytics(createNotAllowedErrorEvent(type, msg));
|
||||
|
||||
@@ -416,7 +416,7 @@ function _connectionFailed({ dispatch, getState }: IStore, next: Function, actio
|
||||
descriptionKey: errors ? 'dialog.tokenAuthFailedWithReasons' : 'dialog.tokenAuthFailed',
|
||||
descriptionArguments: { reason: errors },
|
||||
titleKey: 'dialog.tokenAuthFailedTitle'
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { JitsiConferenceErrors } from '../lib-jitsi-meet';
|
||||
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
|
||||
import { CONFERENCE_FAILED } from './actionTypes';
|
||||
import { conferenceLeft } from './actions';
|
||||
import { conferenceLeft } from './actions.native';
|
||||
import { TRIGGER_READY_TO_CLOSE_REASONS } from './constants';
|
||||
|
||||
import './middleware.any';
|
||||
@@ -15,10 +15,20 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
|
||||
switch (action.type) {
|
||||
case CONFERENCE_FAILED: {
|
||||
const { getState } = store;
|
||||
const state = getState();
|
||||
const { notifyOnConferenceDestruction = true } = state['features/base/config'];
|
||||
|
||||
if (error?.name !== JitsiConferenceErrors.CONFERENCE_DESTROYED) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!notifyOnConferenceDestruction) {
|
||||
dispatch(conferenceLeft(action.conference));
|
||||
dispatch(appNavigate(undefined));
|
||||
break;
|
||||
}
|
||||
|
||||
const [ reason ] = error.params;
|
||||
|
||||
const reasonKey = Object.keys(TRIGGER_READY_TO_CLOSE_REASONS)[
|
||||
|
||||
@@ -122,12 +122,14 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
}
|
||||
|
||||
if (errorName === JitsiConferenceErrors.CONFERENCE_DESTROYED) {
|
||||
const state = getState();
|
||||
const { notifyOnConferenceDestruction = true } = state['features/base/config'];
|
||||
const [ reason ] = action.error.params;
|
||||
const titlekey = Object.keys(TRIGGER_READY_TO_CLOSE_REASONS)[
|
||||
Object.values(TRIGGER_READY_TO_CLOSE_REASONS).indexOf(reason)
|
||||
];
|
||||
|
||||
dispatch(hangup(true, i18next.t(titlekey) || reason));
|
||||
dispatch(hangup(true, i18next.t(titlekey) || reason, notifyOnConferenceDestruction));
|
||||
}
|
||||
|
||||
releaseScreenLock();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user