Compare commits

..

22 Commits

Author SHA1 Message Date
Дамян Минков
66db657170 Updates ljm to use release branch directly. 2023-12-07 10:52:59 -06:00
Gabriel Borlea
6f6c6108e3 fix(LJM): change the reference to point to the head of the release branch 2023-12-07 12:00:34 +02:00
Дамян Минков
15b07548c5 fix(auth): Skip authStatusChanged for jaas meetings. (#14128)
It is showing Login/Logout buttons which does nothing in this case.
2023-12-05 11:30:38 -06:00
Andrei Gavrilescu
08d72666a6 feat(rtcstats): fetch conference creator id and send to rtcstats (#14060)
* fetch conference creator id and send to rtcstats

* fix lint

* fix lint again
2023-11-27 21:49:38 +02:00
Andrei Gavrilescu
bbeceb4fdb chore(deps): Update lib-jitsi-meet, send identity 2023-11-27 21:48:44 +02:00
Gabriel Borlea
6f35514c53 fix(devices): device type to settings key mapping for video 2023-11-27 17:04:47 +02:00
Horatiu Muresan
ec10df3b57 fix(media-devices) Fix configuring media devices on init (#14097)
- on 3rd party prejoin, we did not setup the initial devices, resulting in always creating tracks for default device for camera and mic regardless of settings, and for both meeting and 3rd party prejoin to not set the audio output device at all
2023-11-27 17:04:38 +02:00
Gabriel Borlea
3aa37e06ca fix(devices): return user selected device id if there is no device id 2023-11-27 17:04:26 +02:00
Saúl Ibarra Corretgé
cd93a2025e fix(compute-pressure) disable when in an iframe
Permission delegation doesn't work for 3rd party iframes on this origin
trial, wait until Google solves it: https://bugs.chromium.org/p/chromium/issues/detail?id=1504167
2023-11-27 17:04:13 +02:00
Gabriel Borlea
2b1cb3c7b9 ref(settings): listen to TRACK_ADDED to set the input devices id (#14093)
This fixes the issue when starting the conference with video muted, after unmuting it the cameraDeviceId would stay undefined.
2023-11-27 17:04:04 +02:00
Gabriel Borlea
86b8c427eb fix(electron-screensharing): get the right current selected source 2023-11-21 12:15:28 -06:00
Jaya Allamsetty
ba7d1dd964 chore(deps): Update lib-jitsi-meet, fixes screenshare quality on older versions of Chrome. 2023-11-21 11:58:04 -05:00
damencho
1b8d43d7a7 fix(browser-detection): ipad detection in safari 2023-11-20 14:41:38 -06:00
Jaya Allamsetty
0b364e7004 chore(deps): update lib-jitsi-meet.
bd98ecd05d - fixes the encodings config on codec switch.
2023-11-17 23:02:27 -05:00
Jaya Allamsetty
4a21c6d5b8 chore(deps) - update lib-jitsi-meet.
1f098c7bf8 - Fix support for Firefox ESR 102
e8beab03a0 - read deprecated video bitrate settings correctly.
2023-11-17 12:23:14 -05:00
Gabriel Borlea
63892a39b1 fix(screenshot-captue): get the right worker url 2023-11-16 17:46:24 +02:00
Hristo Terezov
ef249145c9 fix(pr-test): For LJM 2023-11-14 18:41:08 +02:00
Gabriel Borlea
15648b4071 ref(screenshot-capture): move screenshot processing on a web worker (#14015)
Improvement for the screenshot capture feature by using a web worker to process the differences between the screenshots, and some code adjustments.
2023-11-14 18:24:57 +02:00
Mihaela Dumitru
6a54ff2c1a chore(deps) update excalidraw with disabled image pasting (#14046) 2023-11-14 17:08:44 +02:00
Hristo Terezov
42d343b48a chore(deps): Update LJM. 2023-11-13 16:04:30 -06:00
Hristo Terezov
fbc66d379d fix(FeedbackButoon): display for JaaS meetings. 2023-11-13 15:47:44 -06:00
Hristo Terezov
f52ca265ae feat(feedback): show even if callstats is disabled 2023-11-13 15:47:30 -06:00
90 changed files with 4353 additions and 2721 deletions

View File

@@ -74,17 +74,3 @@ jobs:
cache: 'npm'
- run: npm install
- run: npx react-native bundle --entry-file react/index.native.js --platform ios --bundle-output /tmp/ios.bundle --reset-cache
debian-build:
name: Test Debian packages build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
cache: 'npm'
- run: npm install
- run: make
- run: sudo apt-get install -y debhelper
- run: dpkg-buildpackage -A -rfakeroot -us -uc -d
- run: make source-package

View File

@@ -125,7 +125,7 @@ dev: deploy-init deploy-css deploy-rnnoise-binary deploy-tflite deploy-meet-mode
source-package:
mkdir -p source_package/jitsi-meet/css && \
cp -r *.js *.html resources/*.txt fonts images libs static sounds LICENSE lang source_package/jitsi-meet && \
cp -r *.js *.html resources/*.txt favicon.ico fonts images libs static sounds LICENSE lang source_package/jitsi-meet && \
cp css/all.css source_package/jitsi-meet/css && \
(cd source_package ; tar cjf ../jitsi-meet.tar.bz2 jitsi-meet) && \
rm -rf source_package

View File

@@ -1,10 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Server URL configuration -->
<restriction
android:description="@string/restriction_server_url_description"
android:key="SERVER_URL"
android:restrictionType="string"
android:title="@string/restriction_server_url_title"/>
</restrictions>
<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Server URL configuration -->
<restriction
android:defaultValue="https://meet.jit.si"
android:description="@string/restriction_server_url_description"
android:key="SERVER_URL"
android:restrictionType="string"
android:title="@string/restriction_server_url_title"/>
</restrictions>

6
app.js
View File

@@ -31,6 +31,12 @@ if (window.Olm) {
window.APP = {
API,
conference,
// Used for automated performance tests.
connectionTimes: {
'index.loaded': window.indexLoadedTime
},
translation,
UI
};

View File

@@ -154,7 +154,7 @@ import {
import { isModerationNotificationDisplayed } from './react/features/notifications/functions';
import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay/actions';
import { suspendDetected } from './react/features/power-monitor/actions';
import { initPrejoin } from './react/features/prejoin/actions';
import { initPrejoin, makePrecallTest } from './react/features/prejoin/actions';
import { isPrejoinPageVisible } from './react/features/prejoin/functions';
import { disableReceiver, stopReceiver } from './react/features/remote-control/actions';
import { setScreenAudioShareState } from './react/features/screen-share/actions.web';
@@ -718,6 +718,8 @@ export default {
};
if (isPrejoinPageVisible(state)) {
APP.store.dispatch(makePrecallTest(this._getConferenceOptions()));
const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(initialOptions);
const localTracks = await tryCreateLocalTracks;
@@ -1037,6 +1039,17 @@ export default {
.filter(p => !p.isHidden() || !(config.iAmRecorder && p.isHiddenFromRecorder())).length + 1;
},
/**
* Returns true if the callstats integration is enabled, otherwise returns
* false.
*
* @returns true if the callstats integration is enabled, otherwise returns
* false.
*/
isCallstatsEnabled() {
return room && room.isCallstatsEnabled();
},
/**
* Get speaker stats that track total dominant speaker time.
*

108
config.js
View File

@@ -97,6 +97,11 @@ var config = {
// Disables the auto-play behavior of *all* newly created video element.
// This is useful when the client runs on a host with limited resources.
// noAutoPlayVideo: false,
// Enable callstats only for a percentage of users.
// This takes a value between 0 and 100 which determines the probability for
// the callstats to be enabled.
// callStatsThreshold: 5, // enable callstats for 5% of the users.
},
// Disables moderator indicators.
@@ -289,19 +294,12 @@ var config = {
// max: 5,
// },
// Optional screenshare settings that give more control over screen capture in the browser.
// screenShareSettings: {
// // Show users the current tab is the preferred capture source, default: false.
// desktopPreferCurrentTab: false,
// // Allow users to select system audio, default: include.
// desktopSystemAudio: 'include',
// // Allow users to seamlessly switch which tab they are sharing without having to select the tab again.
// desktopSurfaceSwitching: 'include',
// // Allow a user to be shown a preference for what screen is to be captured, default: unset.
// desktopDisplaySurface: undefined,
// // Allow users to select the current tab as a capture source, default: exclude.
// desktopSelfBrowserSurface: 'exclude'
// },
// This option has been deprecated since it is no longer supported as per the w3c spec.
// https://w3c.github.io/mediacapture-screen-share/#dom-mediadevices-getdisplaymedia. If the user has not
// interacted with the webpage before the getDisplayMedia call, the promise will be rejected by the browser. This
// has already been implemented in Firefox and Safari and will be implemented in Chrome soon.
// https://bugs.chromium.org/p/chromium/issues/detail?id=1198918
// startScreenSharing: false,
// Recording
@@ -439,49 +437,6 @@ var config = {
// // Provides a way to set the codec preference on desktop based endpoints.
// codecPreferenceOrder: [ 'VP9', 'VP8', 'H264' ],
//
// // Codec specific settings for scalability modes and max bitrates.
// av1: {
// maxBitratesVideo: {
// low: 100000,
// standard: 300000,
// high: 1000000,
// ssHigh: 2500000
// },
// scalabilityModeEnabled: true,
// useSimulcast: false,
// useKSVC: true
// },
// h264: {
// maxBitratesVideo: {
// low: 200000,
// standard: 500000,
// high: 1500000,
// ssHigh: 2500000
// },
// scalabilityModeEnabled: true
// },
// vp8: {
// maxBitratesVideo: {
// low: 200000,
// standard: 500000,
// high: 1500000,
// ssHigh: 2500000
// },
// scalabilityModeEnabled: false
// },
// vp9: {
// maxBitratesVideo: {
// low: 100000,
// standard: 300000,
// high: 1200000,
// ssHigh: 2500000
// },
// scalabilityModeEnabled: true,
// useSimulcast: false,
// useKSVC: true
// }
//
// DEPRECATED! Use `codec specific settings` instead.
// // Provides a way to configure the maximum bitrates that will be enforced on the simulcast streams for
// // video tracks. The keys in the object represent the type of the stream (LD, SD or HD) and the values
// // are the max.bitrates to be set on that particular type of stream. The actual send may vary based on
@@ -938,10 +893,38 @@ var config = {
// The interval at which PeerConnection.getStats() is called. Defaults to 10000
// pcStatsInterval: 10000,
// Enables sending participants' display names to stats
// To enable sending statistics to callstats.io you must provide the
// Application ID and Secret.
// callStatsID: '',
// callStatsSecret: '',
// callStatsApplicationLogsDisabled: false,
// The callstats initialize config params as described in the API:
// https://docs.callstats.io/docs/javascript#callstatsinitialize-with-app-secret
// callStatsConfigParams: {
// disableBeforeUnloadHandler: true, // disables callstats.js's window.onbeforeunload parameter.
// applicationVersion: "app_version", // Application version specified by the developer.
// disablePrecalltest: true, // disables the pre-call test, it is enabled by default.
// siteID: "siteID", // The name/ID of the site/campus from where the call/pre-call test is made.
// additionalIDs: { // additionalIDs object, contains application related IDs.
// customerID: "Customer Identifier. Example, walmart.",
// tenantID: "Tenant Identifier. Example, monster.",
// productName: "Product Name. Example, Jitsi.",
// meetingsName: "Meeting Name. Example, Jitsi loves callstats.",
// serverName: "Server/MiddleBox Name. Example, jvb-prod-us-east-mlkncws12.",
// pbxID: "PBX Identifier. Example, walmart.",
// pbxExtensionID: "PBX Extension Identifier. Example, 5625.",
// fqExtensionID: "Fully qualified Extension Identifier. Example, +71 (US) +5625.",
// sessionID: "Session Identifier. Example, session-12-34",
// },
// collectLegacyStats: true, //enables the collection of legacy stats in chrome browser
// collectIP: true, //enables the collection localIP address
// },
// Enables sending participants' display names to callstats
// enableDisplayNameInStats: false,
// Enables sending participants' emails (if available) to stats and other analytics
// Enables sending participants' emails (if available) to callstats and other analytics
// enableEmailInStats: false,
// faceLandmarks: {
@@ -964,7 +947,7 @@ var config = {
// captureInterval: 1000,
// },
// Controls the percentage of automatic feedback shown to participants.
// Controls the percentage of automatic feedback shown to participants when callstats is enabled.
// The default value is 100%. If set to 0, no automatic feedback will be requested
// feedbackPercentage: 100,
@@ -972,7 +955,7 @@ var config = {
//
// If third party requests are disabled, no other server will be contacted.
// This means avatars will be locally generated and external stats integration
// This means avatars will be locally generated and callstats integration
// will not function.
// disableThirdPartyRequests: false,
@@ -1523,6 +1506,8 @@ var config = {
_peerConnStatusOutOfLastNTimeout
_peerConnStatusRtcMuteTimeout
avgRtpStatsN
callStatsConfIDNamespace
callStatsCustomScriptUrl
desktopSharingSources
disableAEC
disableAGC
@@ -1696,12 +1681,13 @@ var config = {
// logging: {
// // Default log level for the app and lib-jitsi-meet.
// defaultLogLevel: 'trace',
// // Option to disable LogCollector.
// // Option to disable LogCollector (which stores the logs on CallStats).
// //disableLogCollector: true,
// // Individual loggers are customizable.
// loggers: {
// // The following are too verbose in their logging with the default level.
// 'modules/RTC/TraceablePeerConnection.js': 'info',
// 'modules/statistics/CallStats.js': 'info',
// 'modules/xmpp/strophe.util.js': 'log',
// },

View File

@@ -115,18 +115,17 @@ form {
}
.leftwatermark {
max-width: 140px;
max-height:70px;
left: 32px;
top: 32px;
background-position: center left;
background-repeat: no-repeat;
background-size: contain;
}
&.no-margin {
left:0;
top:0;
}
.leftwatermarknomargin {
background-position: center left;
background-repeat: no-repeat;
background-size: contain;
}
.rightwatermark {

View File

@@ -260,6 +260,11 @@ body.welcome-page {
width: $welcomePageWatermarkWidth;
height: $welcomePageWatermarkHeight;
}
.watermark.leftwatermarknomargin {
width: $welcomePageWatermarkWidth;
height: $welcomePageWatermarkHeight;
}
}
&.without-content {

View File

@@ -1,5 +1,6 @@
interface_config.js /usr/share/jitsi-meet/
*.html /usr/share/jitsi-meet/
*.ico /usr/share/jitsi-meet/
libs /usr/share/jitsi-meet/
static /usr/share/jitsi-meet/
css/all.css /usr/share/jitsi-meet/css/

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
images/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -6,6 +6,8 @@ workspace 'jitsi-meet'
install! 'cocoapods', :deterministic_uuids => false
production = ENV["PRODUCTION"] == "1"
target 'JitsiMeet' do
project 'app/app.xcodeproj'
@@ -24,6 +26,7 @@ target 'JitsiMeetSDK' do
flags = get_default_flags()
use_react_native!(
:path => config[:reactNativePath],
:production => production,
:hermes_enabled => false,
:fabric_enabled => false,
# An absolute path to your application root.
@@ -53,24 +56,24 @@ target 'JitsiMeetSDKLite' do
# React Native and its dependencies
#
config = use_native_modules!
use_react_native!(
:path => config[:reactNativePath],
:path => config["reactNativePath"],
:hermes_enabled => false,
:fabric_enabled => false,
# An absolute path to your application root.
:app_path => "#{Pod::Config.instance.installation_root}/.."
)
# Native pod dependencies
#
pod 'CocoaLumberjack', '3.7.2'
end
post_install do |installer|
react_native_post_install(installer, :mac_catalyst_enabled => false)
react_native_post_install(installer)
__apply_Xcode_12_5_M1_post_install_workaround(installer)
installer.pods_project.targets.each do |target|
# https://github.com/CocoaPods/CocoaPods/issues/11402

View File

@@ -14,14 +14,14 @@ PODS:
- CocoaLumberjack/Core (= 3.7.2)
- CocoaLumberjack/Core (3.7.2)
- DoubleConversion (1.1.6)
- FBLazyVector (0.70.14)
- FBReactNativeSpec (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- RCTRequired (= 0.70.14)
- RCTTypeSafety (= 0.70.14)
- React-Core (= 0.70.14)
- React-jsi (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- FBLazyVector (0.69.12)
- FBReactNativeSpec (0.69.12):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.69.12)
- RCTTypeSafety (= 0.69.12)
- React-Core (= 0.69.12)
- React-jsi (= 0.69.12)
- ReactCommon/turbomodule/core (= 0.69.12)
- Firebase/Analytics (8.15.0):
- Firebase/Core
- Firebase/Core (8.15.0):
@@ -103,7 +103,7 @@ PODS:
- GoogleUtilities/Network (~> 7.7)
- "GoogleUtilities/NSData+zlib (~> 7.7)"
- nanopb (~> 2.30908.0)
- GoogleDataTransport (9.3.0):
- GoogleDataTransport (9.2.5):
- GoogleUtilities/Environment (~> 7.7)
- nanopb (< 2.30910.0, >= 2.30908.0)
- PromisesObjC (< 3.0, >= 1.2)
@@ -111,41 +111,41 @@ PODS:
- AppAuth (~> 1.5)
- GTMAppAuth (< 3.0, >= 1.3)
- GTMSessionFetcher/Core (< 4.0, >= 1.1)
- GoogleUtilities/AppDelegateSwizzler (7.12.0):
- GoogleUtilities/AppDelegateSwizzler (7.11.5):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- GoogleUtilities/Environment (7.12.0):
- GoogleUtilities/Environment (7.11.5):
- PromisesObjC (< 3.0, >= 1.2)
- GoogleUtilities/Logger (7.12.0):
- GoogleUtilities/Logger (7.11.5):
- GoogleUtilities/Environment
- GoogleUtilities/MethodSwizzler (7.12.0):
- GoogleUtilities/MethodSwizzler (7.11.5):
- GoogleUtilities/Logger
- GoogleUtilities/Network (7.12.0):
- GoogleUtilities/Network (7.11.5):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (7.12.0)"
- GoogleUtilities/Reachability (7.12.0):
- "GoogleUtilities/NSData+zlib (7.11.5)"
- GoogleUtilities/Reachability (7.11.5):
- GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (7.12.0):
- GoogleUtilities/UserDefaults (7.11.5):
- GoogleUtilities/Logger
- GTMAppAuth (2.0.0):
- AppAuth/Core (~> 1.6)
- GTMSessionFetcher/Core (< 4.0, >= 1.5)
- GTMSessionFetcher/Core (3.2.0)
- JitsiWebRTC (118.0.0)
- libwebp (1.3.2):
- libwebp/demux (= 1.3.2)
- libwebp/mux (= 1.3.2)
- libwebp/sharpyuv (= 1.3.2)
- libwebp/webp (= 1.3.2)
- libwebp/demux (1.3.2):
- GTMSessionFetcher/Core (3.1.1)
- JitsiWebRTC (111.0.2)
- libwebp (1.3.1):
- libwebp/demux (= 1.3.1)
- libwebp/mux (= 1.3.1)
- libwebp/sharpyuv (= 1.3.1)
- libwebp/webp (= 1.3.1)
- libwebp/demux (1.3.1):
- libwebp/webp
- libwebp/mux (1.3.2):
- libwebp/mux (1.3.1):
- libwebp/demux
- libwebp/sharpyuv (1.3.2)
- libwebp/webp (1.3.2):
- libwebp/sharpyuv (1.3.1)
- libwebp/webp (1.3.1):
- libwebp/sharpyuv
- nanopb (2.30908.0):
- nanopb/decode (= 2.30908.0)
@@ -156,214 +156,214 @@ PODS:
- PromisesObjC (2.3.1)
- PromisesSwift (2.3.1):
- PromisesObjC (= 2.3.1)
- RCT-Folly (2021.07.22.00):
- RCT-Folly (2021.06.28.00-v2):
- boost
- DoubleConversion
- fmt (~> 6.2.1)
- glog
- RCT-Folly/Default (= 2021.07.22.00)
- RCT-Folly/Default (2021.07.22.00):
- RCT-Folly/Default (= 2021.06.28.00-v2)
- RCT-Folly/Default (2021.06.28.00-v2):
- boost
- DoubleConversion
- fmt (~> 6.2.1)
- glog
- RCTRequired (0.70.14)
- RCTTypeSafety (0.70.14):
- FBLazyVector (= 0.70.14)
- RCTRequired (= 0.70.14)
- React-Core (= 0.70.14)
- React (0.70.14):
- React-Core (= 0.70.14)
- React-Core/DevSupport (= 0.70.14)
- React-Core/RCTWebSocket (= 0.70.14)
- React-RCTActionSheet (= 0.70.14)
- React-RCTAnimation (= 0.70.14)
- React-RCTBlob (= 0.70.14)
- React-RCTImage (= 0.70.14)
- React-RCTLinking (= 0.70.14)
- React-RCTNetwork (= 0.70.14)
- React-RCTSettings (= 0.70.14)
- React-RCTText (= 0.70.14)
- React-RCTVibration (= 0.70.14)
- React-bridging (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- React-jsi (= 0.70.14)
- React-callinvoker (0.70.14)
- React-Codegen (0.70.14):
- FBReactNativeSpec (= 0.70.14)
- RCT-Folly (= 2021.07.22.00)
- RCTRequired (= 0.70.14)
- RCTTypeSafety (= 0.70.14)
- React-Core (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-Core (0.70.14):
- RCTRequired (0.69.12)
- RCTTypeSafety (0.69.12):
- FBLazyVector (= 0.69.12)
- RCTRequired (= 0.69.12)
- React-Core (= 0.69.12)
- React (0.69.12):
- React-Core (= 0.69.12)
- React-Core/DevSupport (= 0.69.12)
- React-Core/RCTWebSocket (= 0.69.12)
- React-RCTActionSheet (= 0.69.12)
- React-RCTAnimation (= 0.69.12)
- React-RCTBlob (= 0.69.12)
- React-RCTImage (= 0.69.12)
- React-RCTLinking (= 0.69.12)
- React-RCTNetwork (= 0.69.12)
- React-RCTSettings (= 0.69.12)
- React-RCTText (= 0.69.12)
- React-RCTVibration (= 0.69.12)
- React-bridging (0.69.12):
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsi (= 0.69.12)
- React-callinvoker (0.69.12)
- React-Codegen (0.69.12):
- FBReactNativeSpec (= 0.69.12)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.69.12)
- RCTTypeSafety (= 0.69.12)
- React-Core (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsiexecutor (= 0.69.12)
- ReactCommon/turbomodule/core (= 0.69.12)
- React-Core (0.69.12):
- glog
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default (= 0.70.14)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.69.12)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsiexecutor (= 0.69.12)
- React-perflogger (= 0.69.12)
- Yoga
- React-Core/CoreModulesHeaders (0.70.14):
- React-Core/CoreModulesHeaders (0.69.12):
- glog
- RCT-Folly (= 2021.07.22.00)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsiexecutor (= 0.69.12)
- React-perflogger (= 0.69.12)
- Yoga
- React-Core/Default (0.70.14):
- React-Core/Default (0.69.12):
- glog
- RCT-Folly (= 2021.07.22.00)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- RCT-Folly (= 2021.06.28.00-v2)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsiexecutor (= 0.69.12)
- React-perflogger (= 0.69.12)
- Yoga
- React-Core/DevSupport (0.70.14):
- React-Core/DevSupport (0.69.12):
- glog
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default (= 0.70.14)
- React-Core/RCTWebSocket (= 0.70.14)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-jsinspector (= 0.70.14)
- React-perflogger (= 0.70.14)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.69.12)
- React-Core/RCTWebSocket (= 0.69.12)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsiexecutor (= 0.69.12)
- React-jsinspector (= 0.69.12)
- React-perflogger (= 0.69.12)
- Yoga
- React-Core/RCTActionSheetHeaders (0.70.14):
- React-Core/RCTActionSheetHeaders (0.69.12):
- glog
- RCT-Folly (= 2021.07.22.00)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsiexecutor (= 0.69.12)
- React-perflogger (= 0.69.12)
- Yoga
- React-Core/RCTAnimationHeaders (0.70.14):
- React-Core/RCTAnimationHeaders (0.69.12):
- glog
- RCT-Folly (= 2021.07.22.00)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsiexecutor (= 0.69.12)
- React-perflogger (= 0.69.12)
- Yoga
- React-Core/RCTBlobHeaders (0.70.14):
- React-Core/RCTBlobHeaders (0.69.12):
- glog
- RCT-Folly (= 2021.07.22.00)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsiexecutor (= 0.69.12)
- React-perflogger (= 0.69.12)
- Yoga
- React-Core/RCTImageHeaders (0.70.14):
- React-Core/RCTImageHeaders (0.69.12):
- glog
- RCT-Folly (= 2021.07.22.00)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsiexecutor (= 0.69.12)
- React-perflogger (= 0.69.12)
- Yoga
- React-Core/RCTLinkingHeaders (0.70.14):
- React-Core/RCTLinkingHeaders (0.69.12):
- glog
- RCT-Folly (= 2021.07.22.00)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsiexecutor (= 0.69.12)
- React-perflogger (= 0.69.12)
- Yoga
- React-Core/RCTNetworkHeaders (0.70.14):
- React-Core/RCTNetworkHeaders (0.69.12):
- glog
- RCT-Folly (= 2021.07.22.00)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsiexecutor (= 0.69.12)
- React-perflogger (= 0.69.12)
- Yoga
- React-Core/RCTSettingsHeaders (0.70.14):
- React-Core/RCTSettingsHeaders (0.69.12):
- glog
- RCT-Folly (= 2021.07.22.00)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsiexecutor (= 0.69.12)
- React-perflogger (= 0.69.12)
- Yoga
- React-Core/RCTTextHeaders (0.70.14):
- React-Core/RCTTextHeaders (0.69.12):
- glog
- RCT-Folly (= 2021.07.22.00)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsiexecutor (= 0.69.12)
- React-perflogger (= 0.69.12)
- Yoga
- React-Core/RCTVibrationHeaders (0.70.14):
- React-Core/RCTVibrationHeaders (0.69.12):
- glog
- RCT-Folly (= 2021.07.22.00)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsiexecutor (= 0.69.12)
- React-perflogger (= 0.69.12)
- Yoga
- React-Core/RCTWebSocket (0.70.14):
- React-Core/RCTWebSocket (0.69.12):
- glog
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default (= 0.70.14)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.69.12)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsiexecutor (= 0.69.12)
- React-perflogger (= 0.69.12)
- Yoga
- React-CoreModules (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.70.14)
- React-Codegen (= 0.70.14)
- React-Core/CoreModulesHeaders (= 0.70.14)
- React-jsi (= 0.70.14)
- React-RCTImage (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-cxxreact (0.70.14):
- React-CoreModules (0.69.12):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.12)
- React-Codegen (= 0.69.12)
- React-Core/CoreModulesHeaders (= 0.69.12)
- React-jsi (= 0.69.12)
- React-RCTImage (= 0.69.12)
- ReactCommon/turbomodule/core (= 0.69.12)
- React-cxxreact (0.69.12):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.07.22.00)
- React-callinvoker (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsinspector (= 0.70.14)
- React-logger (= 0.70.14)
- React-perflogger (= 0.70.14)
- React-runtimeexecutor (= 0.70.14)
- React-jsi (0.70.14):
- RCT-Folly (= 2021.06.28.00-v2)
- React-callinvoker (= 0.69.12)
- React-jsi (= 0.69.12)
- React-jsinspector (= 0.69.12)
- React-logger (= 0.69.12)
- React-perflogger (= 0.69.12)
- React-runtimeexecutor (= 0.69.12)
- React-jsi (0.69.12):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.07.22.00)
- React-jsi/Default (= 0.70.14)
- React-jsi/Default (0.70.14):
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsi/Default (= 0.69.12)
- React-jsi/Default (0.69.12):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.07.22.00)
- React-jsiexecutor (0.70.14):
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsiexecutor (0.69.12):
- DoubleConversion
- glog
- RCT-Folly (= 2021.07.22.00)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-perflogger (= 0.70.14)
- React-jsinspector (0.70.14)
- React-logger (0.70.14):
- RCT-Folly (= 2021.06.28.00-v2)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-perflogger (= 0.69.12)
- React-jsinspector (0.69.12)
- React-logger (0.69.12):
- glog
- react-native-background-timer (2.4.1):
- React-Core
@@ -371,9 +371,9 @@ PODS:
- React-Core
- react-native-keep-awake (4.0.0):
- React
- react-native-netinfo (11.1.0):
- react-native-netinfo (9.4.1):
- React-Core
- react-native-orientation-locker (1.6.0):
- react-native-orientation-locker (1.5.0):
- React-Core
- react-native-pager-view (6.2.0):
- React-Core
@@ -391,80 +391,80 @@ PODS:
- react-native-video/Video (6.0.0-alpha.7):
- PromisesSwift
- React-Core
- react-native-webrtc (118.0.0):
- JitsiWebRTC (~> 118.0.0)
- react-native-webrtc (111.0.6):
- JitsiWebRTC (~> 111.0.0)
- React-Core
- react-native-webview (13.5.1):
- React-Core
- React-perflogger (0.70.14)
- React-RCTActionSheet (0.70.14):
- React-Core/RCTActionSheetHeaders (= 0.70.14)
- React-RCTAnimation (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.70.14)
- React-Codegen (= 0.70.14)
- React-Core/RCTAnimationHeaders (= 0.70.14)
- React-jsi (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-RCTBlob (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- React-Codegen (= 0.70.14)
- React-Core/RCTBlobHeaders (= 0.70.14)
- React-Core/RCTWebSocket (= 0.70.14)
- React-jsi (= 0.70.14)
- React-RCTNetwork (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-RCTImage (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.70.14)
- React-Codegen (= 0.70.14)
- React-Core/RCTImageHeaders (= 0.70.14)
- React-jsi (= 0.70.14)
- React-RCTNetwork (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-RCTLinking (0.70.14):
- React-Codegen (= 0.70.14)
- React-Core/RCTLinkingHeaders (= 0.70.14)
- React-jsi (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-RCTNetwork (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.70.14)
- React-Codegen (= 0.70.14)
- React-Core/RCTNetworkHeaders (= 0.70.14)
- React-jsi (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-RCTSettings (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.70.14)
- React-Codegen (= 0.70.14)
- React-Core/RCTSettingsHeaders (= 0.70.14)
- React-jsi (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-RCTText (0.70.14):
- React-Core/RCTTextHeaders (= 0.70.14)
- React-RCTVibration (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- React-Codegen (= 0.70.14)
- React-Core/RCTVibrationHeaders (= 0.70.14)
- React-jsi (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-runtimeexecutor (0.70.14):
- React-jsi (= 0.70.14)
- ReactCommon/turbomodule/core (0.70.14):
- React-perflogger (0.69.12)
- React-RCTActionSheet (0.69.12):
- React-Core/RCTActionSheetHeaders (= 0.69.12)
- React-RCTAnimation (0.69.12):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.12)
- React-Codegen (= 0.69.12)
- React-Core/RCTAnimationHeaders (= 0.69.12)
- React-jsi (= 0.69.12)
- ReactCommon/turbomodule/core (= 0.69.12)
- React-RCTBlob (0.69.12):
- RCT-Folly (= 2021.06.28.00-v2)
- React-Codegen (= 0.69.12)
- React-Core/RCTBlobHeaders (= 0.69.12)
- React-Core/RCTWebSocket (= 0.69.12)
- React-jsi (= 0.69.12)
- React-RCTNetwork (= 0.69.12)
- ReactCommon/turbomodule/core (= 0.69.12)
- React-RCTImage (0.69.12):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.12)
- React-Codegen (= 0.69.12)
- React-Core/RCTImageHeaders (= 0.69.12)
- React-jsi (= 0.69.12)
- React-RCTNetwork (= 0.69.12)
- ReactCommon/turbomodule/core (= 0.69.12)
- React-RCTLinking (0.69.12):
- React-Codegen (= 0.69.12)
- React-Core/RCTLinkingHeaders (= 0.69.12)
- React-jsi (= 0.69.12)
- ReactCommon/turbomodule/core (= 0.69.12)
- React-RCTNetwork (0.69.12):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.12)
- React-Codegen (= 0.69.12)
- React-Core/RCTNetworkHeaders (= 0.69.12)
- React-jsi (= 0.69.12)
- ReactCommon/turbomodule/core (= 0.69.12)
- React-RCTSettings (0.69.12):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.12)
- React-Codegen (= 0.69.12)
- React-Core/RCTSettingsHeaders (= 0.69.12)
- React-jsi (= 0.69.12)
- ReactCommon/turbomodule/core (= 0.69.12)
- React-RCTText (0.69.12):
- React-Core/RCTTextHeaders (= 0.69.12)
- React-RCTVibration (0.69.12):
- RCT-Folly (= 2021.06.28.00-v2)
- React-Codegen (= 0.69.12)
- React-Core/RCTVibrationHeaders (= 0.69.12)
- React-jsi (= 0.69.12)
- ReactCommon/turbomodule/core (= 0.69.12)
- React-runtimeexecutor (0.69.12):
- React-jsi (= 0.69.12)
- ReactCommon/turbomodule/core (0.69.12):
- DoubleConversion
- glog
- RCT-Folly (= 2021.07.22.00)
- React-bridging (= 0.70.14)
- React-callinvoker (= 0.70.14)
- React-Core (= 0.70.14)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-logger (= 0.70.14)
- React-perflogger (= 0.70.14)
- RCT-Folly (= 2021.06.28.00-v2)
- React-bridging (= 0.69.12)
- React-callinvoker (= 0.69.12)
- React-Core (= 0.69.12)
- React-cxxreact (= 0.69.12)
- React-jsi (= 0.69.12)
- React-logger (= 0.69.12)
- React-perflogger (= 0.69.12)
- RNCalendarEvents (2.2.0):
- React
- RNCAsyncStorage (1.19.4):
- RNCAsyncStorage (1.19.3):
- React-Core
- RNCClipboard (1.5.1):
- React-Core
@@ -474,7 +474,7 @@ PODS:
- React-Core
- RNGestureHandler (2.9.0):
- React-Core
- RNGoogleSignin (10.1.0):
- RNGoogleSignin (10.0.1):
- GoogleSignIn (~> 7.0)
- React-Core
- RNScreens (3.24.0):
@@ -709,8 +709,8 @@ SPEC CHECKSUMS:
boost: a7c83b31436843459a1961bfd74b96033dc77234
CocoaLumberjack: b7e05132ff94f6ae4dfa9d5bce9141893a21d9da
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
FBLazyVector: efad4471d02263013cfcb7a2f75de6ac7565692f
FBReactNativeSpec: 9cd9542bfdcc64e07bc649f809dd621876f78619
FBLazyVector: 6fab494fa11340bd4206edaebed07279a6bafad4
FBReactNativeSpec: 76d7b03876b0ad0b86bc5c84d23af8e64db8e096
Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d
FirebaseAnalytics: 7761cbadb00a717d8d0939363eb46041526474fa
FirebaseCore: 5743c5785c074a794d35f2fff7ecc254a91e08b1
@@ -721,71 +721,71 @@ SPEC CHECKSUMS:
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
Giphy: 6b5f6986c8df4f71e01a8ef86595f426b3439fb5
giphy-react-native-sdk: fcda9639f8ca2cc47e0517b6ef11c19359db5f5a
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a
GoogleAppMeasurement: 4c19f031220c72464d460c9daa1fb5d1acce958e
GoogleDataTransport: 57c22343ab29bc686febbf7cbb13bad167c2d8fe
GoogleDataTransport: 54dee9d48d14580407f8f5fbf2f496e92437a2f2
GoogleSignIn: b232380cf495a429b8095d3178a8d5855b42e842
GoogleUtilities: 0759d1a57ebb953965c2dfe0ba4c82e95ccc2e34
GoogleUtilities: 13e2c67ede716b8741c7989e26893d151b2b2084
GTMAppAuth: 99fb010047ba3973b7026e45393f51f27ab965ae
GTMSessionFetcher: 41b9ef0b4c08a6db4b7eb51a21ae5183ec99a2c8
JitsiWebRTC: 3a41671ef65a51d7204323814b055a2690b921c7
libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009
GTMSessionFetcher: e8647203b65cee28c5f73d0f473d096653945e72
JitsiWebRTC: 80f62908fcf2a1160e0d14b584323fb6e6be630b
libwebp: 33dc822fbbf4503668d09f7885bbfedc76c45e96
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
ObjectiveDropboxOfficial: fe206ce8c0bc49976c249d472db7fdbc53ebbd53
PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
PromisesSwift: 28dca69a9c40779916ac2d6985a0192a5cb4a265
RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda
RCTRequired: 6f42727926c2ef4836fc23169586f3d8d7f5a6e4
RCTTypeSafety: de9b538a8f20ae8c780bf38935f37f303b083fc8
React: 6604c02c25295898e9332c5dbe5d6f140be1e246
React-bridging: 55de000607b776d7c9b1333f38d1991ef25bf915
React-callinvoker: aa42aaefd72dbe9218c112fd503eff7ab782bd11
React-Codegen: 9e13e901ac4d4c46349c2db28b8774fa4274ec18
React-Core: b046bbaddd981014eaac20cef83de953a0405c1b
React-CoreModules: 4f0b29e5924b06a868983952265f77fed219f349
React-cxxreact: 818c9b06607f7972e95eeacb326389429c6a2d38
React-jsi: 0bf359879bc4c2c908204b1cd789b0a727a7a568
React-jsiexecutor: 03144eeee729e6a6cb8d7ff2d5653b67315f8f31
React-jsinspector: 6538dfb58970d1fb9d89c9c34e87713ece6c3cf0
React-logger: 4e9c3f888b4b5bb72a3ac7f1be7929e776181016
RCT-Folly: b9d9fe1fc70114b751c076104e52f3b1b5e5a95a
RCTRequired: b9e53f0512019150020156fa0dacd6583ab838be
RCTTypeSafety: 04b72202bef8302802610dee70bb9407a245b64c
React: 59288a7ca8104eb8002f01378606fe42eeabf4b5
React-bridging: b042b8c217f04e568409786de5f221793be49c31
React-callinvoker: c7b83d582112e2d5a049dc46abf4c64d871b5c45
React-Codegen: 5747238d0446e3ab1deb967e749a2bfde6a5c866
React-Core: d8e1250039d47112513757038d9d9f9b638565c6
React-CoreModules: 63cceb0040ec2b43a258113193be91f934b37f1b
React-cxxreact: 429404aac55d8bffca77328002452fc7fa8b29e8
React-jsi: a8f60feb519ac00085eb9a39d20eaa65c96b51ea
React-jsiexecutor: ce0b9aa647bdf94126eb2ee1f235d329eb8c0aec
React-jsinspector: f275698149311abc8c32ebb97797d6b97c44adde
React-logger: da69d7f1c9501c78cd60776d52a60d7fa5e4d9c2
react-native-background-timer: 17ea5e06803401a379ebf1f20505b793ac44d0fe
react-native-get-random-values: dee677497c6a740b71e5612e8dbd83e7539ed5bb
react-native-keep-awake: afad8a51dfef9fe9655a6344771be32c8596d774
react-native-netinfo: 3aa5637c18834966e0c932de8ae1ae56fea20a97
react-native-orientation-locker: 4409c5b12b65f942e75449872b4f078b6f27af81
react-native-netinfo: fefd4e98d75cbdd6e85fc530f7111a8afdf2b0c5
react-native-orientation-locker: 851f6510d8046ea2f14aa169b1e01fcd309a94ba
react-native-pager-view: 0ccb8bf60e2ebd38b1f3669fa3650ecce81db2df
react-native-performance: 47ac22ebf2aa24f324a96a5825581f6ce18c09e8
react-native-safe-area-context: 9697629f7b2cda43cf52169bb7e0767d330648c2
react-native-slider: 1cdd6ba29675df21f30544253bf7351d3c2d68c4
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
react-native-video: 967eead48aaa42c25a9e1d65c3b1ab30762a88df
react-native-webrtc: c8d9ad3c152105b2720ca2851d04b49659551992
react-native-webrtc: 255a1172fd31525b952b36aef7b8e9a41de325e5
react-native-webview: 8baa0f5c6d336d6ba488e942bcadea5bf51f050a
React-perflogger: 74b2d33200b8c26440c2c39b87a4177d8404655f
React-RCTActionSheet: 3fdf6b3a85f2ea4b365b267efd9c82aaeb20fe33
React-RCTAnimation: 9659d5ed57ccbd129516486b2cce38e536841337
React-RCTBlob: 49ac98cfd9476af046814a2c9126fca1bf0cbe75
React-RCTImage: b4d2d7d14ad9389bd645bc2daa706ccaead3fc44
React-RCTLinking: ebf051ed2532652e5290e4fb7c017c42e4e1f0d2
React-RCTNetwork: 1636df1f91d4c5ad8815ef93f695931af1c0a842
React-RCTSettings: f6306171fd5d3cd8c5fa0b1803da599784ead5c5
React-RCTText: 53c106b5fb9e263c2f1e5d6b0733049989d6c428
React-RCTVibration: d293c50100c0927379e6a80fab86a219e08792ae
React-runtimeexecutor: 0d01d03375f996484fcc231ccca3fe604a4a5652
ReactCommon: dce64235f8548b6e4758647310145f5356c8d0cb
React-perflogger: 5ade0a1627352f1647d283e78331819bb46cceae
React-RCTActionSheet: 8e94f1e46e09c7035b81fe56c0ed8d78f3ccd340
React-RCTAnimation: bf2af72f03cf16528db9a830be69fa04b341a1b7
React-RCTBlob: 4d076b8bb55e631ad1280280ecba674fb1e46d16
React-RCTImage: 073dcc1689466851fe120c7f8a3cfe3db0196c9f
React-RCTLinking: 8872818dc894a17bf17cb4b120f76917bf2e9f0a
React-RCTNetwork: 1e9c873f4a210784a4fb752194cb595502112464
React-RCTSettings: 1475a717c54f4a9ed627dffffad2470c4b15a419
React-RCTText: ed34088172126f84130eea859d62fedca0dd7975
React-RCTVibration: c9cd9f21bbcb3b9c6deedbb66f13e373f57dd795
React-runtimeexecutor: ea78653fbc68bd6f2d3f5e7e311bc5a9dc8bfeca
ReactCommon: f4bb9e5209ea5c3c6ab25e100895119e58d6e50a
RNCalendarEvents: 7e65eb4a94f53c1744d1e275f7fafcfaa619f7a3
RNCAsyncStorage: 3a8f7145d17cdd9f88e7b77666c94a09e4f759c8
RNCAsyncStorage: c913ede1fa163a71cea118ed4670bbaaa4b511bb
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
RNDefaultPreference: 08bdb06cfa9188d5da97d4642dac745218d7fb31
RNDeviceInfo: 02ea8b23e2280fa18e00a06d7e62804d74028579
RNGestureHandler: 071d7a9ad81e8b83fe7663b303d132406a7d8f39
RNGoogleSignin: a6a612cce56a45ab701c5c5c6e36f5390522d100
RNGoogleSignin: ccaa4a81582cf713eea562c5dd9dc1961a715fd0
RNScreens: b21dc57dfa2b710c30ec600786a3fc223b1b92e7
RNSound: 6c156f925295bdc83e8e422e7d8b38d33bc71852
RNSVG: ed492aaf3af9ca01bc945f7a149d76d62e73ec82
RNWatch: fd30ca40a5b5ef58dcbc195638e68219bc455236
Yoga: 56413d530d1808044600320ced5baa883acedc44
Yoga: 8a90b50af67eaa9fe94fd03e550bfeab06096873
PODFILE CHECKSUM: c5053669414ca81c03ca4548249b11fe53a13060
PODFILE CHECKSUM: 90720aee51cf2cab2e12611a28dbf55a688e969c
COCOAPODS: 1.14.3
COCOAPODS: 1.12.1

View File

@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objectVersion = 52;
objects = {
/* Begin PBXBuildFile section */
@@ -862,6 +862,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -891,6 +892,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -976,7 +978,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@@ -1011,7 +1013,6 @@
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@@ -1027,10 +1028,6 @@
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -1042,7 +1039,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@@ -1072,10 +1069,6 @@
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -1088,10 +1081,6 @@
);
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;

View File

@@ -38,6 +38,7 @@
[builder setFeatureFlag:@"resolution" withValue:@(360)];
[builder setFeatureFlag:@"ios.screensharing.enabled" withBoolean:YES];
[builder setFeatureFlag:@"ios.recording.enabled" withBoolean:YES];
builder.serverURL = [NSURL URLWithString:@"https://meet.jit.si"];
}];
[jitsiMeet application:application didFinishLaunchingWithOptions:launchOptions];
@@ -125,7 +126,7 @@
- (UIInterfaceOrientationMask)application:(UIApplication *)application
supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return [[JitsiMeet sharedInstance] application:application
return [[JitsiMeet sharedInstance] application:application
supportedInterfaceOrientationsForWindow:window];
}

View File

@@ -728,7 +728,7 @@
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@@ -766,7 +766,6 @@
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
@@ -777,10 +776,6 @@
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -796,7 +791,7 @@
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@@ -829,10 +824,6 @@
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -841,10 +832,6 @@
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;

View File

@@ -419,7 +419,6 @@
"sessTerminatedReason": "Die Konferenz wurde beendet",
"sessionRestarted": "Konferenz neugestartet",
"shareAudio": "Fortfahren",
"shareAudioAltText": "Um den gewünschten Inhalt zu teilen: Navigiere zu \"Browser tab\", wähle den Inhalt, aktiviere \"Audio teilen\" Kästchen Und klicke den “Teilen” schaltfläche",
"shareAudioTitle": "Wie kann Audio geteilt werden",
"shareAudioWarningD1": "müssen Sie Ihre Bildschirmfreigabe stoppen, bevor Sie Audio teilen können.",
"shareAudioWarningD2": "müssen Sie Ihre Bildschirmfreigabe neustarten und die Option \"Audio freigeben\" auswählen.",

View File

@@ -778,7 +778,7 @@
"moreModerationControls": "Más controles de moderación",
"moreParticipantOptions": "Más opciones de participantes",
"mute": "Silenciar",
"muteAll": "Silenciar a todos",
"muteAll": "Silenciar a todos los demás",
"muteEveryoneElse": "Silenciar al resto",
"stopEveryonesVideo": "Detener el vídeo de todos",
"stopVideo": "Detener el vídeo",
@@ -1361,7 +1361,7 @@
"videothumbnail": {
"connectionInfo": "Información de conexión",
"domute": "Silenciar",
"domuteOthers": "Silenciar a todos los demás",
"domuteOthers": "Silenciar a todos",
"domuteVideo": "Desactivar la cámara",
"domuteVideoOfOthers": "Desactivar la cámara de todos los demás",
"flip": "Voltear",

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,5 @@
{
"addPeople": {
"accessibilityLabel": {
"meetingLink": "Link da reunião: {{url}}"
},
"add": "Convidar",
"addContacts": "Convide seus contatos",
"contacts": "contatos",
@@ -42,18 +39,6 @@
"audioOnly": {
"audioOnly": "Largura de banda baixa"
},
"bandwidthSettings": {
"assumedBandwidthBps": "Ex. 10000000 para 10 Mbps",
"assumedBandwidthBpsWarning": "Valores mais altos podem causar erros de rede.",
"customValue": "valor personalizado",
"customValueEffect": "para definir o valor de bps real",
"leaveEmpty": "deixar vazio",
"leaveEmptyEffect": "para permitir que estimativas assumam",
"possibleValues": "Valores possíveis",
"setAssumedBandwidthBps": "Banda presumida (bps)",
"title": "Configurações de banda",
"zeroEffect": "para desabilitar o vídeo"
},
"breakoutRooms": {
"actions": {
"add": "Adicionar sala de apoio",
@@ -63,22 +48,15 @@
"leaveBreakoutRoom": "Sair da sala de apoio",
"more": "Mais",
"remove": "Remover",
"rename": "Renomear",
"renameBreakoutRoom": "Renomear sala de apoio",
"sendToBreakoutRoom": "Enviar participante para:"
},
"breakoutList": "Lista de apoio",
"buttonLabel": "Salas de apoio",
"defaultName": "Sala de apoio #{{index}}",
"hideParticipantList": "Ocultar lista de participantes",
"mainRoom": "Sala principal",
"notifications": {
"joined": "Entrando na sala de apoio \"{{name}}\"",
"joinedMainRoom": "Entrando na sala principal",
"joinedTitle": "Salas de apoio"
},
"showParticipantList": "Exibir lista de participantes",
"title": "Salas de apoio"
}
},
"calendarSync": {
"addMeetingURL": "Adicionar um link da reunião",
@@ -261,12 +239,9 @@
"Share": "Compartilhar",
"Submit": "Enviar",
"WaitForHostMsg": "A conferência ainda não começou. Se você é o anfitrião, faça a autenticação. Do contrário, aguarde a chegada do anfitrião.",
"WaitingForHostButton": "Aguardar por anfitrião",
"WaitingForHostTitle": "Esperando o anfitrião...",
"Yes": "Sim",
"accessibilityLabel": {
"Cancel": "Cancelar (fechar janela)",
"Ok": "OK (salvar e fechar janela)",
"close": "Fechar janela",
"liveStreaming": "Transmissão ao vivo",
"sharingTabs": "Opções de compartilhamento"
@@ -275,8 +250,6 @@
"addMeetingNote": "Adicionar uma anotação para esta reunião",
"addOptionalNote": "Adicionar uma anotação (opcional):",
"allow": "Permitir",
"allowToggleCameraDialog": "Você permite que {{initiatorName}} possa alternar entre suas câmeras?",
"allowToggleCameraTitle": "Permitir alternar câmera?",
"alreadySharedVideoMsg": "Outro participante já está compartilhando um vídeo. Esta conferência permite apenas um vídeo compartilhado por vez.",
"alreadySharedVideoTitle": "Somente um vídeo compartilhado é permitido por vez",
"applicationWindow": "Janela de aplicativo",
@@ -337,7 +310,6 @@
"lockRoom": "Adicionar reunião $t(lockRoomPasswordUppercase)",
"lockTitle": "Bloqueio falhou",
"login": "Entrar",
"loginQuestion": "Deseja iniciar a sessão e finalizar a conferência?",
"logoutQuestion": "Deseja encerrar a sessão e finalizar a conferência?",
"logoutTitle": "Encerrar sessão",
"maxUsersLimitReached": "O limite para o número máximo de participantes foi atingido. A conferência está cheia. Entre em contato com o proprietário da reunião ou tente novamente mais tarde!",
@@ -381,6 +353,8 @@
"permissionCameraRequiredError": "É necessário permitir acesso à câmera para participar de reuniões com vídeo. Ative a permissão nas configurações",
"permissionErrorTitle": "Permissão necessária",
"permissionMicRequiredError": "É necessário permitir acesso ao microfone para participar de reuniões com áudio. Ative a permissão nas configurações",
"popupError": "Seu navegador está bloqueando janelas popup deste site. Habilite os popups nas configurações de segurança no seu navegador e tente novamente.",
"popupErrorTitle": "Popup bloqueado",
"readMore": "mais...",
"recentlyUsedObjects": "Seus objetos usados recentemente",
"recording": "Gravando",
@@ -397,8 +371,6 @@
"removePassword": "Remover $t(lockRoomPassword)",
"removeSharedVideoMsg": "Deseja remover seu vídeo compartilhado?",
"removeSharedVideoTitle": "Remover vídeo compartilhado",
"renameBreakoutRoomLabel": "Nome da sala",
"renameBreakoutRoomTitle": "Renomear sala de apoio",
"reservationError": "Erro de sistema de reserva",
"reservationErrorMsg": "Código do erro: {{code}}, mensagem: {{msg}}",
"retry": "Tentar novamente",
@@ -417,11 +389,9 @@
"sendPrivateMessageOk": "Enviar em privado",
"sendPrivateMessageTitle": "Enviar em privado?",
"serviceUnavailable": "Serviço indisponível",
"sessTerminated": "Chamada encerrada",
"sessTerminatedReason": "A chamada foi encerrada",
"sessionRestarted": "Chamada reiniciada devido a um erro de conexão.",
"sessTerminated": "Chamada terminada",
"sessionRestarted": "Chamada reiniciada pelo bridge",
"shareAudio": "Continuar",
"shareAudioAltText": "para compartilhar o conteúdo desejado, acesse \"Aba de navegador\", selecione o conteúdo, ative a caixa de \"compartilhar áudio\" e então clique no botão \"compartilhar\"",
"shareAudioTitle": "Como compartilhar áudio",
"shareAudioWarningD1": "você precisa parar o compartilhamento de tela antes de compartilhar seu áudio.",
"shareAudioWarningD2": "você precisa reiniciar o compartilhamento de tela e selecionar a opção \"compartilhar áudio\".",
@@ -451,25 +421,7 @@
"thankYou": "Obrigado por usar o {{appName}}!",
"token": "token",
"tokenAuthFailed": "Desculpe, você não está autorizado a entrar nesta chamada.",
"tokenAuthFailedReason": {
"audInvalid": "Valor `aud` inválido. Deveria ser `jitsi`.",
"contextNotFound": "O objeto `context` está faltando na carga.",
"expInvalid": "Valor `exp`inválido.",
"featureInvalid": "Recurso inválido: {{feature}}, possivelmente ainda não implementado.",
"featureValueInvalid": "Valor inválido para recurso: {{feature}}.",
"featuresNotFound": "O objeto `features` está faltando na carga.",
"headerNotFound": "Cabeçalho está faltando.",
"issInvalid": "Valor `iss` inválido. Deveria ser `chat`.",
"kidMismatch": "Key ID (kid) não coincide com o sub.",
"kidNotFound": "Key ID (kid) faltando.",
"nbfFuture": "O valor `nbf` está no futuro.",
"nbfInvalid": "Valor `nbf` inválido.",
"payloadNotFound": "Carga faltando.",
"tokenExpired": "O token está expirado."
},
"tokenAuthFailedTitle": "Falha de autenticação",
"tokenAuthFailedWithReasons": "Desculpe, você não pode ingressar nesta chamada. Razões possíveis: {{reason}}",
"tokenAuthUnsupported": "Token da URL não é suportada.",
"transcribing": "Transcrevendo",
"unlockRoom": "Remove a reunião $t(lockRoomPassword)",
"user": "Usuário",
@@ -483,10 +435,6 @@
"viewUpgradeOptions": "Ver opções de atualização",
"viewUpgradeOptionsContent": "Para obter acesso ilimitado a recursos premium tais como gravação, transcrição, streaming RTMP e muito mais, você precisa atualizar seu plano.",
"viewUpgradeOptionsTitle": "Você descobriu um recurso premium!",
"whiteboardLimitContent": "Desculpe, o limite de usuários de quadro-branco simultâneos foi atingido.",
"whiteboardLimitReference": "Para mais informações por favor visite",
"whiteboardLimitReferenceUrl": "nosso website",
"whiteboardLimitTitle": "Restrição no uso do quadro-branco",
"yourEntireScreen": "Toda sua tela"
},
"documentSharing": {
@@ -499,9 +447,6 @@
"title": "Reunião em formato compacto"
},
"feedback": {
"accessibilityLabel": {
"yourChoice": "Sua escolha: {{rating}}"
},
"average": "Média",
"bad": "Ruim",
"detailsLabel": "Nos conte mais sobre isso.",
@@ -562,7 +507,6 @@
"password": "$t(lockRoomPasswordUppercase):",
"reachedLimit": "Você atingiu o limite do seu plano.",
"sip": "endereço SIP",
"sipAudioOnly": "Endereço apenas para áudio SIP",
"title": "Compartilhar",
"tooltip": "Compartilhar link e discagem para esta reunião",
"upgradeOptions": "Por favor, verifique as opções de upgrade em"
@@ -669,13 +613,13 @@
"knockingParticipantList": "Remover lista de participantes",
"lobbyChatStartedNotification": "{{moderator}} iniciou uma conversa na sala de espera com {{attendee}}",
"lobbyChatStartedTitle": "{{moderator}} iniciou uma conversa na sala de espera com você.",
"lobbyClosed": "A sala de espera foi fechada.",
"nameField": "Informe seu nome",
"notificationLobbyAccessDenied": "{{targetParticipantName}} foi rejeitado por {{originParticipantName}}",
"notificationLobbyAccessGranted": "{{targetParticipantName}} foi aceito por {{originParticipantName}}",
"notificationLobbyDisabled": "Sala de espera foi desabilitada por {{originParticipantName}}",
"notificationLobbyEnabled": "Sala de espera foi habilitada por {{originParticipantName}}",
"notificationTitle": "Sala de espera",
"passwordField": "Informe a senha da conferência",
"passwordJoinButton": "Solicitar",
"reject": "Rejeitar",
"rejectAll": "Rejeitar todos",
@@ -707,11 +651,9 @@
"participant": "Participante",
"participantStats": "Estatísticas dos Participantes",
"selectTabTitle": "🎥 Por favor selecione esta aba para gravar",
"sessionToken": "Token de sessão",
"sessionToken": "Token de Sessão",
"start": "Iniciar gravação",
"stop": "Parar a gravação",
"stopping": "Parando a gravação",
"wait": "Por favor aguarde enquanto salvamos sua gravação",
"stop": "Parar a Gravação",
"yes": "Sim"
},
"lockRoomPassword": "senha",
@@ -734,7 +676,6 @@
"dataChannelClosed": "Qualidade do vídeo prejudicada",
"dataChannelClosedDescription": "O canal da ponte foi desconectado, assim a qualidade do vídeo foi limitada a sua configuração mais baixa.",
"disabledIframe": "Incorporação destina-se apenas a fins de demonstração, assim esta chamada será desconectada em {{timeout}} minutos.",
"disabledIframeSecondary": "Incorporação de {{domain}} é apenas destinado para fins de demonstração, então esta chamada será desconectada em {{timeout}} minutos. Por favor use o <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi as a Service</a> para incorporação em produção!",
"disconnected": "desconectado",
"displayNotifications": "Exibir notificações para",
"dontRemindMe": "Não me lembrar",
@@ -781,6 +722,7 @@
"newDeviceCameraTitle": "Nova câmera detectada",
"noiseSuppressionDesktopAudioDescription": "A supressão de ruído não pode ser habilitada enquanto compartilha o áudio da área de trabalho. Por favor desabilite e tente novamente.",
"noiseSuppressionFailedTitle": "Falha ao iniciar a supressão de ruído",
"noiseSuppressionNoTrackDescription": "Por favor ative o microfone antes.",
"noiseSuppressionStereoDescription": "Supressão de ruído de áudio estéreo não é suportado no momento.",
"oldElectronClientDescription1": "Você está usando um versão antiga do cliente Jitsi Meet que possui uma conhecida vulnerabilidade de segurança. Por favor tenha certeza de atulizar para a nossa ",
"oldElectronClientDescription2": "última versão",
@@ -810,9 +752,7 @@
"videoUnmuteBlockedDescription": "A liberação da câmera e compartilhamento de tela foram temporariamente bloqueados devido a limites do sistema.",
"videoUnmuteBlockedTitle": "Câmera e compartilhamento de tela bloqueados!",
"viewLobby": "Ver sala de espera",
"waitingParticipants": "{{waitingParticipants}} pessoas",
"whiteboardLimitDescription": "Por favor, salve seu progresso pois o limite de usuários logo será atingido e o quadro-branco será fechado.",
"whiteboardLimitTitle": "Uso do quadro-branco"
"waitingParticipants": "{{waitingParticipants}} pessoas"
},
"participantsPane": {
"actions": {
@@ -821,7 +761,6 @@
"askUnmute": "Pedir para ativar som",
"audioModeration": "Reativarem seus sons",
"blockEveryoneMicCamera": "Bloquear microfone e câmera de todos",
"breakoutRooms": "Salas de apoio",
"invite": "Convidar alguém",
"moreModerationActions": "Mais opções de moderação",
"moreModerationControls": "Mais controles de moderação",
@@ -998,7 +937,7 @@
"limitNotificationDescriptionNative": "Devido a demanda, sua gravação ficará limitada a {{limit}} minutos. Para gravação ilimitada tente <3>{{app}}</3>.",
"limitNotificationDescriptionWeb": "Devido a demanda, sua gravação ficará limitada a {{limit}} minutos. Para gravação ilimitada tente <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
"linkGenerated": "Geramos um link para sua gravação.",
"live": "AO VIVO",
"live": "AOVIVO",
"localRecordingNoNotificationWarning": "A gravação não será anunciada aos outros participantes. Você precisará avisá-los que a reunião está sendo gravada.",
"localRecordingNoVideo": "O vídeo não está sendo gravado",
"localRecordingStartWarning": "Por favor, certifique-se de ter parado a gravação antes de sair da reunião para garantir que será salva.",
@@ -1098,7 +1037,6 @@
"alertOk": "OK",
"alertTitle": "Atenção",
"alertURLText": "A URL digitada do servidor é inválida",
"apply": "Aplicar",
"buildInfoSection": "Informações de compilação",
"conferenceSection": "Conferência",
"disableCallIntegration": "Desativar integração de chamada nativa",
@@ -1109,14 +1047,12 @@
"displayNamePlaceholderText": "Ex: João Silva",
"email": "Email",
"emailPlaceholderText": "email@exemplo.com.br",
"gavatarMessage": "Se seu email está associado com uma conta Gravatar, o usaremos para exibir sua foto de perfil.",
"goTo": "Ir para",
"header": "Configurações",
"help": "Ajuda",
"links": "Links",
"privacy": "Privacidade",
"profileSection": "Perfil",
"sdkVersion": "Versão do SDK",
"serverURL": "URL do servidor",
"showAdvanced": "Mostrar configurações avançadas",
"startCarModeInLowBandwidthMode": "Iniciar modo carro em modo de banda baixa",
@@ -1168,7 +1104,7 @@
"audioOnly": "Alternar para apenas áudio",
"audioRoute": "Selecionar o dispositivo de som",
"boo": "Vaia",
"breakoutRooms": "Entrar/sair da sala de apoio",
"breakoutRoom": "Entrar/sair da sala de apoio",
"callQuality": "Gerenciar qualidade do vídeo",
"carmode": "Modo carro",
"cc": "Alternar legendas",
@@ -1196,7 +1132,7 @@
"hangup": "Sair da chamada",
"heading": "Barra de ferramentas",
"help": "Ajuda",
"hideWhiteboard": "Ocultar quadro-branco",
"hideWhiteboard": "Ocultar quadro branco",
"invite": "Convidar pessoas",
"kick": "Remover participante",
"laugh": "Risada",
@@ -1237,7 +1173,7 @@
"sharedvideo": "Alternar compartilhamento de vídeo",
"shortcuts": "Alternar atalhos",
"show": "Mostrar no palco",
"showWhiteboard": "Exibir quadro-branco",
"showWhiteboard": "Exibir quadro branco",
"silence": "Silenciar",
"speakerStats": "Alternar estatísticas do apresentador",
"stopScreenSharing": "Parar de compartilhar sua tela",
@@ -1282,7 +1218,7 @@
"giphy": "Alternar menu do GIPHY",
"hangup": "Sair",
"help": "Ajuda",
"hideWhiteboard": "Ocultar quadro-branco",
"hideWhiteboard": "Ocultar quadro branco",
"invite": "Convidar pessoas",
"joinBreakoutRoom": "Ingressar na sala de apoio",
"laugh": "Risada",
@@ -1330,7 +1266,7 @@
"shareaudio": "Compartilhar áudio",
"sharedvideo": "Compartilhar um vídeo",
"shortcuts": "Ver atalhos",
"showWhiteboard": "Exibir quadro-branco",
"showWhiteboard": "Exibir quadro branco",
"silence": "Silêncio",
"speakerStats": "Estatísticas do Apresentador",
"startScreenSharing": "Iniciar compart. de tela",
@@ -1435,10 +1371,6 @@
"videomute": "O participante parou a câmera"
},
"virtualBackground": {
"accessibilityLabel": {
"currentBackground": "Fundo atual: {{background}}",
"selectBackground": "Selecionar um fundo"
},
"addBackground": "Adicionar novo fundo",
"apply": "Aplicar",
"backgroundEffectError": "Falha ao aplicar efeito de fundo.",
@@ -1525,7 +1457,7 @@
},
"whiteboard": {
"accessibilityLabel": {
"heading": "Quadro-branco"
"heading": "Quadro branco"
}
}
}

View File

@@ -421,7 +421,6 @@
"sessTerminatedReason": "The meeting has been terminated",
"sessionRestarted": "Call restarted because of a connection issue.",
"shareAudio": "Continue",
"shareAudioAltText": "to share the desired content, navigate to \"Browser Tab\", select the content, activate the \"share audio\" check mark and then click \"share\" button",
"shareAudioTitle": "How to share audio",
"shareAudioWarningD1": "you need to stop screen sharing before sharing your audio.",
"shareAudioWarningD2": "you need to restart your screen sharing and check the \"share audio\" option.",

View File

@@ -244,6 +244,8 @@ function initCommands() {
}
},
'pin-participant': (id, videoType) => {
logger.debug('Pin participant command received');
const state = APP.store.getState();
// if id not provided, unpin everybody.
@@ -301,6 +303,7 @@ function initCommands() {
APP.store.dispatch(removeBreakoutRoom(breakoutRoomJid));
},
'resize-large-video': (width, height) => {
logger.debug('Resize large video command received');
sendAnalytics(createApiEvent('largevideo.resized'));
APP.store.dispatch(resizeLargeVideo(width, height));
},
@@ -321,6 +324,7 @@ function initCommands() {
APP.store.dispatch(setAssumedBandwidthBps(value));
},
'set-follow-me': value => {
logger.debug('Set follow me command received');
if (value) {
sendAnalytics(createApiEvent('follow.me.set'));
@@ -331,6 +335,7 @@ function initCommands() {
APP.store.dispatch(setFollowMe(value));
},
'set-large-video-participant': (participantId, videoType) => {
logger.debug('Set large video participant command received');
const { getState, dispatch } = APP.store;
if (!participantId) {
@@ -368,10 +373,12 @@ function initCommands() {
},
'toggle-audio': () => {
sendAnalytics(createApiEvent('toggle-audio'));
logger.log('Audio toggle: API command received');
APP.conference.toggleAudioMuted(false /* no UI */);
},
'toggle-video': () => {
sendAnalytics(createApiEvent('toggle-video'));
logger.log('Video toggle: API command received');
APP.conference.toggleVideoMuted(false /* no UI */, true /* ensure track */);
},
'toggle-film-strip': () => {
@@ -490,6 +497,7 @@ function initCommands() {
APP.conference.changeLocalAvatarUrl(avatarUrl);
},
'send-chat-message': (message, to, ignorePrivacy = false) => {
logger.debug('Send chat message command received');
if (to) {
const participant = getParticipantById(APP.store.getState(), to);
@@ -507,6 +515,7 @@ function initCommands() {
APP.store.dispatch(sendMessage(message, ignorePrivacy));
},
'send-endpoint-text-message': (to, text) => {
logger.debug('Send endpoint message command received');
try {
APP.conference.sendEndpointMessage(to, {
name: ENDPOINT_TEXT_MESSAGE_NAME,
@@ -529,19 +538,25 @@ function initCommands() {
});
},
'overwrite-names': participantList => {
logger.debug('Overwrite names command received');
APP.store.dispatch(overwriteParticipantsNames(participantList));
},
'toggle-e2ee': enabled => {
logger.debug('Toggle E2EE key command received');
APP.store.dispatch(toggleE2EE(enabled));
},
'set-media-encryption-key': keyInfo => {
APP.store.dispatch(setMediaEncryptionKey(JSON.parse(keyInfo)));
},
'set-video-quality': frameHeight => {
logger.debug('Set video quality command received');
sendAnalytics(createApiEvent('set.video.quality'));
APP.store.dispatch(setVideoQuality(frameHeight));
},
'start-share-video': url => {
logger.debug('Share video command received');
sendAnalytics(createApiEvent('share.video.start'));
const id = extractYoutubeIdOrURL(url);
@@ -549,7 +564,9 @@ function initCommands() {
APP.store.dispatch(playSharedVideo(id));
}
},
'stop-share-video': () => {
logger.debug('Share video command received');
sendAnalytics(createApiEvent('share.video.stop'));
APP.store.dispatch(stopSharedVideo());
},
@@ -624,7 +641,6 @@ function initCommands() {
* Only applies to certain jitsi meet deploys.
* @param { string } arg.youtubeStreamKey - The youtube stream key.
* @param { string } arg.youtubeBroadcastID - The youtube broadcast ID.
* @param { Object } arg.extraMetadata - Any extra metadata params for file recording.
* @returns {void}
*/
'start-recording': ({
@@ -635,8 +651,7 @@ function initCommands() {
rtmpStreamKey,
rtmpBroadcastID,
youtubeStreamKey,
youtubeBroadcastID,
extraMetadata = {}
youtubeBroadcastID
}) => {
const state = APP.store.getState();
const conference = getCurrentConference(state);
@@ -686,7 +701,6 @@ function initCommands() {
mode: JitsiRecordingConstants.mode.FILE,
appData: JSON.stringify({
'file_recording_metadata': {
...extraMetadata,
'upload_credentials': {
'service_name': RECORDING_TYPES.DROPBOX,
'token': dropboxToken
@@ -699,7 +713,6 @@ function initCommands() {
mode: JitsiRecordingConstants.mode.FILE,
appData: JSON.stringify({
'file_recording_metadata': {
...extraMetadata,
'share': shouldShare
}
})
@@ -829,14 +842,11 @@ function initCommands() {
};
transport.on('event', ({ data, name }) => {
if (name && commands[name]) {
logger.info(`API command received: ${name}`);
commands[name](...data);
return true;
}
logger.warn(`Unknown API command received: ${name}`);
return false;
});
transport.on('request', (request, callback) => {

View File

@@ -420,8 +420,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
'display-capture',
'hid',
'microphone',
'screen-wake-lock',
'speaker-selection'
'screen-wake-lock'
].join('; ');
this._frame.name = frameName;
this._frame.id = frameName;
@@ -1432,7 +1431,6 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
* @param { string } options.rtmpBroadcastID - The RTMP broadcast ID.
* @param { string } options.youtubeStreamKey - The youtube stream key.
* @param { string } options.youtubeBroadcastID - The youtube broadcast ID.
* @param {Object } options.extraMetadata - Any extra metadata params for file recording.
* @returns {void}
*/
startRecording(options) {

3762
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -31,11 +31,11 @@
"@microsoft/microsoft-graph-client": "3.0.1",
"@mui/material": "5.12.1",
"@mui/styles": "5.12.0",
"@react-native-async-storage/async-storage": "1.19.4",
"@react-native-async-storage/async-storage": "1.19.3",
"@react-native-community/clipboard": "1.5.1",
"@react-native-community/netinfo": "11.1.0",
"@react-native-community/netinfo": "9.4.1",
"@react-native-community/slider": "4.4.3",
"@react-native-google-signin/google-signin": "10.1.0",
"@react-native-google-signin/google-signin": "10.0.1",
"@react-navigation/bottom-tabs": "6.5.8",
"@react-navigation/elements": "1.3.18",
"@react-navigation/material-top-tabs": "6.6.3",
@@ -65,7 +65,7 @@
"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/v1734.0.0+34ceebd2/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "git+https://github.com/jitsi/lib-jitsi-meet#release-7629",
"lodash": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",
@@ -80,9 +80,10 @@
"react-focus-on": "3.8.1",
"react-i18next": "10.11.4",
"react-linkify": "1.0.0-alpha",
"react-native": "0.70.14",
"react-native": "0.69.12",
"react-native-background-timer": "2.4.1",
"react-native-calendar-events": "2.2.0",
"react-native-callstats": "3.73.22",
"react-native-default-preference": "1.4.4",
"react-native-device-info": "10.9.0",
"react-native-dialog": "https://github.com/jitsi/react-native-dialog/releases/download/v9.2.2-jitsi.1/react-native-dialog-9.2.2.tgz",
@@ -90,7 +91,7 @@
"react-native-get-random-values": "1.9.0",
"react-native-immersive-mode": "2.0.1",
"react-native-keep-awake": "4.0.0",
"react-native-orientation-locker": "1.6.0",
"react-native-orientation-locker": "https://github.com/jitsi/react-native-orientation-locker/releases/download/v1.5.0-jitsi1/react-native-orientation-locker-1.5.0.tgz",
"react-native-pager-view": "6.2.0",
"react-native-paper": "5.10.3",
"react-native-performance": "5.0.0",
@@ -104,7 +105,7 @@
"react-native-url-polyfill": "2.0.0",
"react-native-video": "6.0.0-alpha.7",
"react-native-watch-connectivity": "1.1.0",
"react-native-webrtc": "118.0.0",
"react-native-webrtc": "111.0.6",
"react-native-webview": "13.5.1",
"react-native-youtube-iframe": "2.3.0",
"react-redux": "7.2.9",

View File

@@ -2,7 +2,7 @@ diff --git a/node_modules/react-native/React/CoreModules/RCTTiming.mm b/node_mod
index 13d0d57..00e5d4c 100644
--- a/node_modules/react-native/React/CoreModules/RCTTiming.mm
+++ b/node_modules/react-native/React/CoreModules/RCTTiming.mm
@@ -127,7 +127,15 @@ RCT_EXPORT_MODULE()
@@ -127,7 +127,15 @@ - (void)setup
{
_paused = YES;
_timers = [NSMutableDictionary new];
@@ -19,7 +19,7 @@ index 13d0d57..00e5d4c 100644
for (NSString *name in @[
UIApplicationWillResignActiveNotification,
@@ -146,6 +154,11 @@ RCT_EXPORT_MODULE()
@@ -146,6 +154,11 @@ - (void)setup
name:name
object:nil];
}
@@ -31,7 +31,7 @@ index 13d0d57..00e5d4c 100644
}
- (void)dealloc
@@ -182,6 +195,16 @@ RCT_EXPORT_MODULE()
@@ -182,6 +195,16 @@ - (void)appDidMoveToForeground
[self startTimers];
}

View File

@@ -1,6 +1,6 @@
package org.jitsi.meet.sdk;
import android.app.Activity;
import android.app.Notification;
import android.content.Context;
import androidx.annotation.NonNull;
@@ -24,9 +24,9 @@ class JMOngoingConferenceModule
@ReactMethod
public void launch() {
Context context = getReactApplicationContext();
Activity currentActivity = getCurrentActivity();
Context activityContext = context.getCurrentActivity();
JitsiMeetOngoingConferenceService.launch(context, currentActivity);
JitsiMeetOngoingConferenceService.launch(context, activityContext);
}
@ReactMethod

View File

@@ -16,7 +16,6 @@
package org.jitsi.meet.sdk;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
@@ -42,9 +41,9 @@ import java.util.HashMap;
public class JitsiMeetOngoingConferenceService extends Service {
private static final String TAG = JitsiMeetOngoingConferenceService.class.getSimpleName();
public static void launch(Context context, Activity currentActivity) {
public static void launch(Context context, Context activityContext) {
RNOngoingNotification.createOngoingConferenceNotificationChannel(currentActivity);
RNOngoingNotification.createOngoingConferenceNotificationChannel(activityContext);
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);

View File

@@ -16,7 +16,6 @@
package org.jitsi.meet.sdk;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -42,19 +41,19 @@ class RNOngoingNotification {
static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
static void createOngoingConferenceNotificationChannel(Activity currentActivity) {
static void createOngoingConferenceNotificationChannel(Context activityContext) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return;
}
if (currentActivity == null) {
if (activityContext == null) {
JitsiMeetLogger.w(TAG + " Cannot create notification channel: no current context");
return;
}
NotificationManager notificationManager
= (NotificationManager) currentActivity.getSystemService(Context.NOTIFICATION_SERVICE);
= (NotificationManager) activityContext.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel
= notificationManager.getNotificationChannel("JitsiOngoingConferenceChannel");
@@ -63,7 +62,7 @@ class RNOngoingNotification {
return;
}
channel = new NotificationChannel("JitsiOngoingConferenceChannel", currentActivity.getString(R.string.ongoing_notification_channel_name), NotificationManager.IMPORTANCE_DEFAULT);
channel = new NotificationChannel("JitsiOngoingConferenceChannel", activityContext.getString(R.string.ongoing_notification_channel_name), NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(false);
channel.enableVibration(false);
channel.setShowBadge(false);

View File

@@ -19,8 +19,6 @@ import { setAudioMuted, setVideoMuted } from './react/features/base/media/action
interface IEventListeners {
onAudioMutedChanged?: Function;
onVideoMutedChanged?: Function;
onConferenceBlurred?: Function;
onConferenceFocused?: Function;
onConferenceJoined?: Function;
@@ -109,8 +107,6 @@ export const JitsiMeeting = forwardRef((props: IAppProps, ref) => {
setAppProps({
'flags': flags,
'rnSdkHandlers': {
onAudioMutedChanged: eventListeners?.onAudioMutedChanged,
onVideoMutedChanged: eventListeners?.onVideoMutedChanged,
onConferenceBlurred: eventListeners?.onConferenceBlurred,
onConferenceFocused: eventListeners?.onConferenceFocused,
onConferenceJoined: eventListeners?.onConferenceJoined,

View File

@@ -38,6 +38,7 @@
"react-emoji-render": "1.2.4",
"react-i18next": "10.11.4",
"react-linkify": "1.0.0-alpha",
"react-native-callstats": "3.73.22",
"react-native-dialog": "https://github.com/jitsi/react-native-dialog/releases/download/v9.2.2-jitsi.1/react-native-dialog-9.2.2.tgz",
"react-native-svg-transformer": "1.1.0",
"react-native-tab-view": "3.5.2",

View File

@@ -25,8 +25,7 @@ function updateDependencies() {
updated = true;
}
if (!semver.valid(packageJSON.dependencies[key])
&& packageJSON.dependencies[key] !== RNSDKpackageJSON.peerDependencies[key]) {
if (!semver.valid(packageJSON.dependencies[key])) {
packageJSON.dependencies[key] = RNSDKpackageJSON.peerDependencies[key];
updated = true;
@@ -47,18 +46,6 @@ function updateDependencies() {
console.log(`${key} is now set to ${RNSDKpackageJSON.peerDependencies[key]}`);
}
if (!semver.valid(RNSDKpackageJSON.peerDependencies[key])
&& RNSDKpackageJSON.peerDependencies[key].includes('github')
&& packageJSON.dependencies[key] !== RNSDKpackageJSON.peerDependencies[key]) {
packageJSON.dependencies[key] = RNSDKpackageJSON.peerDependencies[key];
updated = true;
console.log(
`A fix for ${key} is available on ${RNSDKpackageJSON.peerDependencies[key]}.
This is now set on your end.`
);
}
}
packageJSON.overrides = packageJSON.overrides || {};

View File

@@ -16,7 +16,6 @@ import { getJitsiMeetGlobalNS } from '../base/util/helpers';
import { inIframe } from '../base/util/iframeUtils';
import { loadScript } from '../base/util/loadScript';
import { parseURIString } from '../base/util/uri';
import { isPrejoinPageVisible } from '../prejoin/functions';
import AmplitudeHandler from './handlers/AmplitudeHandler';
import MatomoHandler from './handlers/MatomoHandler';
@@ -159,10 +158,9 @@ export async function createHandlers({ getState }: IStore) {
*
* @param {Store} store - The redux store in which the specified {@code action} is being dispatched.
* @param {Array<Object>} handlers - The analytics handlers.
* @param {boolean|undefined} willShowPrejoin -
* @returns {void}
*/
export function initAnalytics(store: IStore, handlers: Array<Object>, willShowPrejoin?: boolean) {
export function initAnalytics(store: IStore, handlers: Array<Object>) {
const { getState, dispatch } = store;
if (!isAnalyticsEnabled(getState) || handlers.length === 0) {
@@ -182,12 +180,8 @@ export function initAnalytics(store: IStore, handlers: Array<Object>, willShowPr
externalApi?: boolean;
group?: string;
inIframe?: boolean;
isPromotedFromVisitor?: boolean;
isVisitor?: boolean;
server?: string;
tenant?: string;
wasLobbyVisible?: boolean;
wasPrejoinDisplayed?: boolean;
websocket?: boolean;
} & typeof deploymentInfo = {};
@@ -213,15 +207,6 @@ export function initAnalytics(store: IStore, handlers: Array<Object>, willShowPr
// Report the tenant from the URL.
permanentProperties.tenant = tenant || '/';
permanentProperties.wasPrejoinDisplayed = willShowPrejoin ?? isPrejoinPageVisible(state);
// Currently we don't know if there will be lobby. We will update it to true if we go through lobby.
permanentProperties.wasLobbyVisible = false;
// Setting visitor properties to false by default. We will update them later if it turns out we are visitor.
permanentProperties.isVisitor = false;
permanentProperties.isPromotedFromVisitor = false;
// Optionally, include local deployment information based on the
// contents of window.config.deploymentInfo.
if (deploymentInfo) {

View File

@@ -5,7 +5,6 @@ import {
SET_ROOM
} from '../base/conference/actionTypes';
import { SET_CONFIG } from '../base/config/actionTypes';
import { analytics } from '../base/lib-jitsi-meet';
import { SET_NETWORK_INFO } from '../base/net-info/actionTypes';
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import {
@@ -17,10 +16,6 @@ import {
getLocalAudioTrack,
getLocalVideoTrack
} from '../base/tracks/functions';
import { SET_LOBBY_VISIBILITY } from '../lobby/actionTypes';
import { getIsLobbyVisible } from '../lobby/functions';
import { I_AM_VISITOR_MODE } from '../visitors/actionTypes';
import { iAmVisitor } from '../visitors/functions';
import { createLocalTracksDurationEvent, createNetworkInfoEvent } from './AnalyticsEvents';
import { UPDATE_LOCAL_TRACKS_DURATION } from './actionTypes';
@@ -86,18 +81,6 @@ function calculateLocalTrackDuration(state: IReduxState) {
*/
MiddlewareRegistry.register(store => next => action => {
switch (action.type) {
case I_AM_VISITOR_MODE: {
const oldIAmVisitor = iAmVisitor(store.getState());
const result = next(action);
const newIAmVisitor = iAmVisitor(store.getState());
analytics.addPermanentProperties({
isVisitor: newIAmVisitor,
isPromotedFromVisitor: oldIAmVisitor && !newIAmVisitor
});
return result;
}
case SET_CONFIG:
if (navigator.product === 'ReactNative') {
// Resetting the analytics is currently not needed for web because
@@ -114,7 +97,7 @@ MiddlewareRegistry.register(store => next => action => {
const result = next(action);
createHandlersPromise.then(handlers => {
initAnalytics(store, handlers, action.willShowPrejoin);
initAnalytics(store, handlers);
});
return result;
@@ -161,14 +144,6 @@ MiddlewareRegistry.register(store => next => action => {
});
break;
}
case SET_LOBBY_VISIBILITY:
if (getIsLobbyVisible(store.getState())) {
analytics.addPermanentProperties({
wasLobbyVisible: true
});
}
break;
case SET_NETWORK_INFO:
sendAnalytics(
createNetworkInfoEvent({

View File

@@ -5,15 +5,12 @@ import { openTokenAuthUrl } from '../authentication/actions';
// @ts-ignore
import { getTokenAuthUrl, isTokenAuthEnabled } from '../authentication/functions';
import { getJwtExpirationDate } from '../base/jwt/functions';
import { MEDIA_TYPE } from '../base/media/constants';
import { isLocalTrackMuted } from '../base/tracks/functions.any';
import { getLocationContextRoot, parseURIString } from '../base/util/uri';
import { addTrackStateToURL } from './functions.any';
import logger from './logger';
import { IStore } from './types';
/**
* Redirects to another page generated by replacing the path in the original URL
* with the given path.
@@ -107,11 +104,7 @@ export function maybeRedirectToTokenAuthUrl(
dispatch: IStore['dispatch'], getState: IStore['getState'], failureCallback: Function) {
const state = getState();
const config = state['features/base/config'];
const { enabled: audioOnlyEnabled } = state['features/base/audio-only'];
const { startAudioOnly } = config;
const { locationURL = { href: '' } as URL } = state['features/base/connection'];
const audioMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.AUDIO);
const videoMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.VIDEO);
if (!isTokenAuthEnabled(config)) {
return false;
@@ -127,18 +120,7 @@ export function maybeRedirectToTokenAuthUrl(
const room = state['features/base/conference'].room;
const { tenant } = parseURIString(locationURL.href) || {};
getTokenAuthUrl(
config,
locationURL,
{
audioMuted,
audioOnlyEnabled: audioOnlyEnabled || startAudioOnly,
skipPrejoin: true,
videoMuted
},
room,
tenant
)
getTokenAuthUrl(config, room, tenant, true, locationURL)
.then((tokenAuthServiceUrl: string | undefined) => {
if (!tokenAuthServiceUrl) {
logger.warn('Cannot handle login, token service URL is not set');

View File

@@ -150,20 +150,9 @@ export function appNavigate(uri?: string, options: IReloadNowOptions = {}) {
return;
}
let willShowPrejoin = false;
let willShowUnsafeRoomWarning = false;
if (!options.hidePrejoin && isPrejoinPageEnabled(getState()) && room) {
if (isUnsafeRoomWarningEnabled(getState()) && isInsecureRoomName(room)) {
willShowUnsafeRoomWarning = true;
} else {
willShowPrejoin = true;
}
}
dispatch(setLocationURL(locationURL));
dispatch(setConfig(config));
dispatch(setRoom(room, willShowPrejoin));
dispatch(setRoom(room));
if (!room) {
goBackToRoot(getState(), dispatch);
@@ -174,10 +163,12 @@ export function appNavigate(uri?: string, options: IReloadNowOptions = {}) {
dispatch(createDesiredLocalTracks());
dispatch(clearNotifications());
if (willShowUnsafeRoomWarning) {
navigateRoot(screen.unsafeRoomWarning);
} else if (willShowPrejoin) {
navigateRoot(screen.preJoin);
if (!options.hidePrejoin && isPrejoinPageEnabled(getState())) {
if (isUnsafeRoomWarningEnabled(getState()) && isInsecureRoomName(room)) {
navigateRoot(screen.unsafeRoomWarning);
} else {
navigateRoot(screen.preJoin);
}
} else {
dispatch(connect());
navigateRoot(screen.conference.root);

View File

@@ -21,7 +21,6 @@ import { AbstractApp, IProps as AbstractAppProps } from './AbstractApp';
import '../middlewares.native';
import '../reducers.native';
declare let __DEV__: any;
const { AppInfo } = NativeModules;
@@ -111,7 +110,7 @@ export class App extends AbstractApp<IProps> {
*/
async _extraInit() {
const { dispatch, getState } = this.state.store ?? {};
const { flags = {}, url, userInfo } = this.props;
const { flags = {} } = this.props;
let callIntegrationEnabled = flags[CALL_INTEGRATION_ENABLED as keyof typeof flags];
// CallKit does not work on the simulator, make sure we disable it.
@@ -154,18 +153,16 @@ export class App extends AbstractApp<IProps> {
await rootNavigationReady;
// Update specified server URL.
if (typeof url !== 'undefined') {
if (typeof this.props.url !== 'undefined') {
// @ts-ignore
const { serverURL } = url;
const { serverURL } = this.props.url;
if (typeof serverURL !== 'undefined') {
dispatch?.(updateSettings({ serverURL }));
}
}
// @ts-ignore
dispatch?.(updateSettings(userInfo || {}));
dispatch?.(updateSettings(this.props.userInfo || {}));
// Update settings with feature-flag.
if (typeof callIntegrationEnabled !== 'undefined') {

View File

@@ -55,20 +55,8 @@ function _getWebConferenceRoute(state: IReduxState) {
&& !state['features/base/jwt'].jwt && room) {
const { locationURL = { href: '' } as URL } = state['features/base/connection'];
const { tenant } = parseURIString(locationURL.href) || {};
const { startAudioOnly } = config;
return getTokenAuthUrl(
config,
locationURL,
{
audioMuted: false,
audioOnlyEnabled: startAudioOnly,
skipPrejoin: false,
videoMuted: false
},
room,
tenant
)
return getTokenAuthUrl(config, room, tenant, false, locationURL)
.then((url: string | undefined) => {
route.href = url;

View File

@@ -68,7 +68,7 @@ export function openTokenAuthUrl(tokenAuthServiceUrl: string): any {
dispatch(openDialog(LoginQuestionDialog, {
handler: () => {
// Give time for the dialog to close.
setTimeout(() => redirect(), 500);
setTimeout(() => redirect, 500);
}
}));
} else {

View File

@@ -13,65 +13,29 @@ export const isTokenAuthEnabled = (config: IConfig): boolean =>
/**
* Returns the state that we can add as a parameter to the tokenAuthUrl.
*
* @param {URL} locationURL - The location URL.
* @param {Object} options: - Config options {
* audioMuted: boolean | undefined
* audioOnlyEnabled: boolean | undefined,
* skipPrejoin: boolean | undefined,
* videoMuted: boolean | undefined
* }.
* @param {string?} roomName - The room name.
* @param {string?} tenant - The tenant name if any.
*
* @param {boolean} skipPrejoin - Whether to skip pre-join page.
* @param {URL} locationURL - The location URL.
* @returns {Object} The state object.
*/
export const _getTokenAuthState = (
locationURL: URL,
options: {
audioMuted: boolean | undefined;
audioOnlyEnabled: boolean | undefined;
skipPrejoin: boolean | undefined;
videoMuted: boolean | undefined;
},
roomName: string | undefined,
tenant: string | undefined): object => {
tenant: string | undefined,
skipPrejoin: boolean | undefined = false,
locationURL: URL): object => {
const state = {
room: roomName,
roomSafe: getBackendSafeRoomName(roomName),
tenant
};
const {
audioMuted = false,
audioOnlyEnabled = false,
skipPrejoin = false,
videoMuted = false
} = options;
if (audioMuted) {
// @ts-ignore
state['config.startWithAudioMuted'] = true;
}
if (audioOnlyEnabled) {
// @ts-ignore
state['config.startAudioOnly'] = true;
}
if (skipPrejoin) {
// We have already shown the prejoin screen, no need to show it again after obtaining the token.
// @ts-ignore
state['config.prejoinConfig.enabled'] = false;
}
if (videoMuted) {
// @ts-ignore
state['config.startWithVideoMuted'] = true;
}
const params = new URLSearchParams(locationURL.hash);
for (const [ key, value ] of params) {

View File

@@ -14,15 +14,10 @@ export * from './functions.any';
* argument to this method.
*
* @param {Object} config - Configuration state object from store. A URL pattern pointing to the login service.
* @param {string} roomName - The name of the conference room for which the user will be authenticated.
* @param {string} tenant - The name of the conference tenant.
* @param {string} skipPrejoin - The name of the conference room for which the user will be authenticated.
* @param {URL} locationURL - The location URL.
* @param {Object} options: - Config options {
* audioMuted: boolean | undefined
* audioOnlyEnabled: boolean | undefined,
* skipPrejoin: boolean | undefined,
* videoMuted: boolean | undefined
* }.
* @param {string?} roomName - The room name.
* @param {string?} tenant - The tenant name if any.
*
* @returns {Promise<string|undefined>} - The URL pointing to JWT login service or
* <tt>undefined</tt> if the pattern stored in config is not a string and the URL can not be
@@ -30,23 +25,11 @@ export * from './functions.any';
*/
export const getTokenAuthUrl = (
config: IConfig,
locationURL: URL,
options: {
audioMuted: boolean | undefined;
audioOnlyEnabled: boolean | undefined;
skipPrejoin: boolean | undefined;
videoMuted: boolean | undefined;
},
roomName: string | undefined,
tenant: string | undefined,
skipPrejoin: boolean | undefined = false,
// eslint-disable-next-line max-params
tenant: string | undefined): Promise<string | undefined> => {
const {
audioMuted = false,
audioOnlyEnabled = false,
skipPrejoin = false,
videoMuted = false
} = options;
locationURL: URL): Promise<string | undefined> => {
let url = config.tokenAuthUrl;
@@ -55,17 +38,7 @@ export const getTokenAuthUrl = (
}
if (url.indexOf('{state}')) {
const state = _getTokenAuthState(
locationURL,
{
audioMuted,
audioOnlyEnabled,
skipPrejoin,
videoMuted
},
roomName,
tenant
);
const state = _getTokenAuthState(roomName, tenant, skipPrejoin, locationURL);
// Append ios=true or android=true to the token URL.
// @ts-ignore

View File

@@ -32,15 +32,10 @@ function _cryptoRandom() {
* argument to this method.
*
* @param {Object} config - Configuration state object from store. A URL pattern pointing to the login service.
* @param {URL} locationURL - The location URL.
* @param {Object} options: - Config options {
* audioMuted: boolean | undefined
* audioOnlyEnabled: boolean | undefined,
* skipPrejoin: boolean | undefined,
* videoMuted: boolean | undefined
* }.
* @param {string?} roomName - The room name.
* @param {string?} tenant - The tenant name if any.
* @param {string} roomName - The name of the conference room for which the user will be authenticated.
* @param {string} tenant - The name of the conference tenant.
* @param {string} skipPrejoin - The name of the conference room for which the user will be authenticated.
* @param {URL} locationURL - The current location URL.
*
* @returns {Promise<string|undefined>} - The URL pointing to JWT login service or
* <tt>undefined</tt> if the pattern stored in config is not a string and the URL can not be
@@ -48,23 +43,11 @@ function _cryptoRandom() {
*/
export const getTokenAuthUrl = (
config: IConfig,
locationURL: URL,
options: {
audioMuted: boolean | undefined;
audioOnlyEnabled: boolean | undefined;
skipPrejoin: boolean | undefined;
videoMuted: boolean | undefined;
},
roomName: string | undefined,
tenant: string | undefined,
skipPrejoin: boolean | undefined = false,
// eslint-disable-next-line max-params
tenant: string | undefined): Promise<string | undefined> => {
const {
audioMuted = false,
audioOnlyEnabled = false,
skipPrejoin = false,
videoMuted = false
} = options;
locationURL: URL): Promise<string | undefined> => {
let url = config.tokenAuthUrl;
@@ -73,17 +56,7 @@ export const getTokenAuthUrl = (
}
if (url.indexOf('{state}')) {
const state = _getTokenAuthState(
locationURL,
{
audioMuted,
audioOnlyEnabled,
skipPrejoin,
videoMuted
},
roomName,
tenant
);
const state = _getTokenAuthState(roomName, tenant, skipPrejoin, locationURL);
if (browser.isElectron()) {
// @ts-ignore

View File

@@ -13,9 +13,7 @@ import {
JitsiConferenceErrors,
JitsiConnectionErrors
} from '../base/lib-jitsi-meet';
import { MEDIA_TYPE } from '../base/media/constants';
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import { isLocalTrackMuted } from '../base/tracks/functions.any';
import { parseURIString } from '../base/util/uri';
import { openLogoutDialog } from '../settings/actions';
@@ -259,9 +257,6 @@ function _handleLogin({ dispatch, getState }: IStore) {
const room = state['features/base/conference'].room;
const { locationURL = { href: '' } as URL } = state['features/base/connection'];
const { tenant } = parseURIString(locationURL.href) || {};
const { enabled: audioOnlyEnabled } = state['features/base/audio-only'];
const audioMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.AUDIO);
const videoMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.VIDEO);
if (!room) {
logger.warn('Cannot handle login, room is undefined!');
@@ -275,18 +270,7 @@ function _handleLogin({ dispatch, getState }: IStore) {
return;
}
getTokenAuthUrl(
config,
locationURL,
{
audioMuted,
audioOnlyEnabled,
skipPrejoin: true,
videoMuted
},
room,
tenant
)
getTokenAuthUrl(config, room, tenant, true, locationURL)
.then((tokenAuthServiceUrl: string | undefined) => {
if (!tokenAuthServiceUrl) {
logger.warn('Cannot handle login, token service URL is not set');

View File

@@ -9,7 +9,7 @@ const AVATAR_COLORS = [
'#B23683',
'#F96E57',
'#4380E2',
'#238561',
'#2AA076',
'#00A8B3'
];
const wordSplitRegex = (/\s+|\.+|_+|;+|-+|,+|\|+|\/+|\\+|"+|'+|\(+|\)+|#+|&+/);

View File

@@ -510,18 +510,15 @@ export function conferenceWillJoin(conference?: IJitsiConference) {
*
* @param {JitsiConference} conference - The JitsiConference instance which will
* be left by the local participant.
* @param {boolean} isRedirect - Indicates if the action has been dispatched as part of visitor promotion.
* @returns {{
* type: CONFERENCE_LEFT,
* conference: JitsiConference,
* isRedirect: boolean
* conference: JitsiConference
* }}
*/
export function conferenceWillLeave(conference?: IJitsiConference, isRedirect?: boolean) {
export function conferenceWillLeave(conference?: IJitsiConference) {
return {
type: CONFERENCE_WILL_LEAVE,
conference,
isRedirect
conference
};
}
@@ -900,20 +897,15 @@ export function setObfuscatedRoom(obfuscatedRoom: string, obfuscatedRoomSource:
*
* @param {(string|undefined)} room - The name of the room of the conference to
* be joined.
* @param {boolean|undefined} willShowPrejoin - Whether the prejoin should be hidden or not.
* NOTE: This argument is used only for mobile currently!
*
* @returns {{
* type: SET_ROOM,
* room: string,
* willShowPrejoin: boolean
* room: string
* }}
*/
export function setRoom(room?: string, willShowPrejoin?: boolean) {
export function setRoom(room?: string) {
return {
type: SET_ROOM,
room,
willShowPrejoin
room
};
}
@@ -1016,7 +1008,7 @@ export function redirect(vnode: string, focusJid: string, username: string) {
}
dispatch(overwriteConfig(newConfig)) // @ts-ignore
.then(() => dispatch(conferenceWillLeave(conference || joining, true)))
.then(() => dispatch(conferenceWillLeave(conference || joining)))
.then(() => dispatch(disconnect()))
.then(() => dispatch(setIAmVisitor(Boolean(vnode))))

View File

@@ -246,6 +246,8 @@ export function getConferenceOptions(stateful: IStateful) {
delete config.analytics?.scriptURLs;
delete config.analytics?.amplitudeAPPKey;
delete config.analytics?.googleAnalyticsTrackingId;
delete options.callStatsID;
delete options.callStatsSecret;
}
return options;

View File

@@ -73,6 +73,7 @@ export interface IJitsiConference {
getSsrcByTrack: Function;
grantOwner: Function;
isAVModerationSupported: Function;
isCallstatsEnabled: Function;
isE2EEEnabled: Function;
isE2EESupported: Function;
isEndConferenceSupported: Function;

View File

@@ -231,6 +231,27 @@ export interface IConfig {
callDisplayName?: string;
callFlowsEnabled?: boolean;
callHandle?: string;
callStatsConfigParams?: {
additionalIDs?: {
customerID?: string;
fqExtensionID?: string;
meetingsName?: string;
pbxExtensionID?: string;
pbxID?: string;
productName?: string;
serverName?: string;
sessionID?: string;
tenantID?: string;
};
applicationVersion?: string;
collectIP?: boolean;
collectLegacyStats?: boolean;
disableBeforeUnloadHandler?: boolean;
disablePrecalltest?: boolean;
siteID?: string;
};
callStatsID?: string;
callStatsSecret?: string;
callUUID?: string;
cameraFacingMode?: string;
channelLastN?: number;
@@ -560,6 +581,7 @@ export interface IConfig {
subject?: string;
testing?: {
assumeBandwidth?: boolean;
callStatsThreshold?: number;
disableE2EE?: boolean;
mobileXmppWsThreshold?: number;
noAutoPlayVideo?: boolean;

View File

@@ -23,7 +23,6 @@ export default [
'avgRtpStatsN',
'backgroundAlpha',
'breakoutRooms',
'bridgeChannel',
'buttonsWithNotifyClick',
/**
@@ -55,6 +54,10 @@ export default [
* @type string
*/
'callHandle',
'callStatsConfIDNamespace',
'callStatsConfigParams',
'callStatsID',
'callStatsSecret',
/**
* The UUID of the CallKit call representing the conference/meeting

View File

@@ -28,6 +28,8 @@ export function _cleanupConfig(config: IConfig) {
delete config.analytics?.rtcstatsUseLegacy;
delete config.analytics?.obfuscateRoomName;
delete config.analytics?.watchRTCEnabled;
delete config.callStatsID;
delete config.callStatsSecret;
delete config.watchRTCConfigParams;
config.giphy = { enabled: false };
}

View File

@@ -65,15 +65,9 @@ export const DEFAULT_LANGUAGE = 'en';
*/
const options: i18next.InitOptions = {
backend: <HttpBackendOptions>{
loadPath: (lng: string[], ns: string[]) => {
switch (ns[0]) {
case 'countries':
case 'main':
return 'lang/{{ns}}-{{lng}}.json';
default:
return 'lang/{{ns}}.json';
}
}
loadPath: (lng: string[], ns: string[]) =>
// eslint-disable-next-line no-extra-parens
(ns[0] === 'main' ? 'lang/{{ns}}-{{lng}}.json' : 'lang/{{ns}}.json')
},
defaultNS: 'main',
fallbackLng: DEFAULT_LANGUAGE,

View File

@@ -4,6 +4,7 @@
export const MEET_FEATURES = {
BRANDING: 'branding',
CALENDAR: 'calendar',
CALLSTATS: 'callstats',
FLIP: 'flip',
INBOUND_CALL: 'inbound-call',
LIVESTREAMING: 'livestreaming',

View File

@@ -1,9 +1,11 @@
import { IStore } from '../../app/types';
import RTCStats from '../../rtcstats/RTCStats';
import { isRTCStatsEnabled } from '../../rtcstats/functions';
import { getCurrentConference } from '../conference/functions';
/**
* Implements log storage interface from the @jitsi/logger lib.
* Implements log storage interface from the @jitsi/logger lib. Captured
* logs are sent to CallStats.
*/
export default class JitsiMeetLogStorage {
counter: number;
@@ -31,7 +33,8 @@ export default class JitsiMeetLogStorage {
}
/**
* The JitsiMeetLogStorage is ready when the conference has been joined.
* The JitsiMeetLogStorage is ready when the CallStats are started and
* before refactoring the code it was after the conference has been joined.
* A conference is considered joined when the 'conference' field is defined
* in the base/conference state.
*
@@ -70,8 +73,54 @@ export default class JitsiMeetLogStorage {
*/
storeLogs(logEntries: Array<string | any>) {
// XXX the config.callStatsApplicationLogsDisabled controls whether or not the logs will be sent to callstats.
// this is done in LJM
this.storeLogsCallstats(logEntries);
if (this.canStoreLogsRtcstats()) {
RTCStats.sendLogs(logEntries);
}
}
/**
* Store the console logs in callstats (if callstats is enabled).
*
* @param {Array<string|any>} logEntries - The log entries to send to the rtcstats server.
* @returns {void}
*/
storeLogsCallstats(logEntries: Array<string | any>) {
const conference = getCurrentConference(this.getState());
if (!conference?.isCallstatsEnabled()) {
// Discard the logs if CallStats is not enabled.
return;
}
let logMessage = `{"log${this.counter}":"\n`;
for (let i = 0, len = logEntries.length; i < len; i++) {
const logEntry = logEntries[i];
if (logEntry.timestamp) {
logMessage += `${logEntry.timestamp} `;
}
if (logEntry.count > 1) {
logMessage += `(${logEntry.count}) `;
}
logMessage += `${logEntry.text}\n`;
}
logMessage += '"}';
this.counter += 1;
// Try catch was used, because there are many variables
// on the way that could be uninitialized if the storeLogs
// attempt would be made very early (which is unlikely)
try {
conference.sendApplicationLog(logMessage);
} catch (error) {
// NOTE console is intentional here
console.error(`Failed to store the logs, msg length: ${logMessage.length} error:`, error);
}
}
}

View File

@@ -1,6 +1,6 @@
/**
* The type of redux action which stores the log collector that will be
* submitting the logs to a service
* submitting the logs to CallStats.
*
* {
* type: SET_LOG_COLLECTOR,

View File

@@ -1,7 +1,8 @@
import { SET_LOGGING_CONFIG, SET_LOG_COLLECTOR } from './actionTypes';
/**
* Stores a {@code Logger.LogCollector} instance which will be uploading logs.
* Stores a {@code Logger.LogCollector} instance which will be uploading logs
* to CallStats.
*
* @param {Logger.LogCollector} logCollector - The log collector instance to be
* stored in the Redux state of base/logging feature.

View File

@@ -106,7 +106,7 @@ function _conferenceJoined({ getState }: IStore, next: Function, action: AnyActi
logCollector.flush();
// This event listener will flush the logs, before the statistics module
// is stopped.
// (CallStats) is stopped.
//
// NOTE The LogCollector is not stopped, because this event can be
// triggered multiple times during single conference (whenever

View File

@@ -10,13 +10,14 @@ const DEFAULT_LOGGING_CONFIG = {
// default log level for the app and lib-jitsi-meet
defaultLogLevel: 'trace' as LogLevel,
// Option to disable LogCollector (which stores the logs)
// Option to disable LogCollector (which stores the logs on CallStats)
// disableLogCollector: true,
loggers: {
// The following are too verbose in their logging with the
// {@link #defaultLogLevel}:
'modules/RTC/TraceablePeerConnection.js': 'info' as LogLevel,
'modules/statistics/CallStats.js': 'info' as LogLevel,
'modules/xmpp/strophe.util.js': 'log' as LogLevel
}
};

View File

@@ -3,6 +3,7 @@ import { WithTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { makeStyles } from 'tss-react/mui';
import { IReduxState } from '../../../../app/types';
import { translate } from '../../../i18n/functions';
import Icon from '../../../icons/components/Icon';
import { IconArrowDown, IconWifi1Bar, IconWifi2Bars, IconWifi3Bars } from '../../../icons/svg';
@@ -216,8 +217,8 @@ function ConnectionStatus({ connectionDetails, t, connectionType }: IProps) {
* @param {Object} state - The redux state.
* @returns {Object}
*/
function mapStateToProps() {
const { connectionDetails, connectionType } = getConnectionData();
function mapStateToProps(state: IReduxState) {
const { connectionDetails, connectionType } = getConnectionData(state);
return {
connectionDetails,

View File

@@ -1,5 +1,14 @@
import { findIndex } from 'lodash';
import { IReduxState } from '../../app/types';
import { CONNECTION_TYPE } from './constants';
const LOSS_AUDIO_THRESHOLDS = [ 0.33, 0.05 ];
const LOSS_VIDEO_THRESHOLDS = [ 0.33, 0.1, 0.05 ];
const THROUGHPUT_AUDIO_THRESHOLDS = [ 8, 20 ];
const THROUGHPUT_VIDEO_THRESHOLDS = [ 60, 750 ];
/**
* The avatar size to container size ration.
@@ -71,14 +80,131 @@ export function calculateAvatarDimensions(height: number) {
}
/**
* Selector for determining the connection type & details.
* Returns the level based on a list of thresholds.
*
* @param {number[]} thresholds - The thresholds array.
* @param {number} value - The value against which the level is calculated.
* @param {boolean} descending - The order based on which the level is calculated.
*
* @returns {number}
*/
function _getLevel(thresholds: number[], value: number, descending = true) {
let predicate;
if (descending) {
predicate = function(threshold: number) {
return value > threshold;
};
} else {
predicate = function(threshold: number) {
return value < threshold;
};
}
const i = findIndex(thresholds, predicate);
if (i === -1) {
return thresholds.length;
}
return i;
}
/**
* Returns the connection details from the test results.
*
* @param {number} testResults.fractionalLoss - Factional loss.
* @param {number} testResults.throughput - Throughput.
*
* @returns {{
* connectionType: string,
* connectionDetails: string[]
* }}
*/
export function getConnectionData() {
function _getConnectionDataFromTestResults({ fractionalLoss: l, throughput: t }:
{ fractionalLoss: number; throughput: number; }) {
const loss = {
audioQuality: _getLevel(LOSS_AUDIO_THRESHOLDS, l),
videoQuality: _getLevel(LOSS_VIDEO_THRESHOLDS, l)
};
const throughput = {
audioQuality: _getLevel(THROUGHPUT_AUDIO_THRESHOLDS, t, false),
videoQuality: _getLevel(THROUGHPUT_VIDEO_THRESHOLDS, t, false)
};
let connectionType = CONNECTION_TYPE.NONE;
const connectionDetails = [];
if (throughput.audioQuality === 0 || loss.audioQuality === 0) {
// Calls are impossible.
connectionType = CONNECTION_TYPE.POOR;
connectionDetails.push('prejoin.connectionDetails.veryPoorConnection');
} else if (
throughput.audioQuality === 2
&& throughput.videoQuality === 2
&& loss.audioQuality === 2
&& loss.videoQuality === 3
) {
// Ideal conditions for both audio and video. Show only one message.
connectionType = CONNECTION_TYPE.GOOD;
connectionDetails.push('prejoin.connectionDetails.goodQuality');
} else {
connectionType = CONNECTION_TYPE.NON_OPTIMAL;
if (throughput.audioQuality === 1) {
// Minimum requirements for a call are met.
connectionDetails.push('prejoin.connectionDetails.audioLowNoVideo');
} else {
// There are two paragraphs: one saying something about audio and the other about video.
if (loss.audioQuality === 1) {
connectionDetails.push('prejoin.connectionDetails.audioClipping');
} else {
connectionDetails.push('prejoin.connectionDetails.audioHighQuality');
}
if (throughput.videoQuality === 0 || loss.videoQuality === 0) {
connectionDetails.push('prejoin.connectionDetails.noVideo');
} else if (throughput.videoQuality === 1) {
connectionDetails.push('prejoin.connectionDetails.videoLowQuality');
} else if (loss.videoQuality === 1) {
connectionDetails.push('prejoin.connectionDetails.videoFreezing');
} else if (loss.videoQuality === 2) {
connectionDetails.push('prejoin.connectionDetails.videoTearing');
} else {
connectionDetails.push('prejoin.connectionDetails.videoHighQuality');
}
}
connectionDetails.push('prejoin.connectionDetails.undetectable');
}
return {
connectionType,
connectionDetails
};
}
/**
* Selector for determining the connection type & details.
*
* @param {Object} state - The state of the app.
* @returns {{
* connectionType: string,
* connectionDetails: string[]
* }}
*/
export function getConnectionData(state: IReduxState) {
const { precallTestResults } = state['features/prejoin'];
if (precallTestResults) {
if (precallTestResults.mediaConnectivity) {
return _getConnectionDataFromTestResults(precallTestResults);
}
return {
connectionType: CONNECTION_TYPE.POOR,
connectionDetails: [ 'prejoin.connectionDetails.noMediaConnectivity' ]
};
}
return {
connectionType: CONNECTION_TYPE.NONE,
connectionDetails: []

View File

@@ -158,13 +158,15 @@ class Watermarks extends Component<IProps, State> {
_showJitsiWatermark
} = this.props;
const { noMargins, t } = this.props;
const className = `watermark leftwatermark ${noMargins ? 'no-margin' : ''}`;
const className = `watermark ${noMargins ? 'leftwatermarknomargin' : 'leftwatermark'}`;
let reactElement = null;
if (_showJitsiWatermark) {
const style = {
backgroundImage: `url(${_logoUrl})`,
maxWidth: 140,
maxHeight: 70,
position: _logoLink ? 'static' : 'absolute'
} as const;

View File

@@ -11,6 +11,7 @@ const button = {
const buttonLabel = {
...BaseTheme.typography.bodyShortBold,
lineHeight: 14,
textTransform: 'capitalize'
};

View File

@@ -344,6 +344,7 @@ const ContextMenu = ({
if (event.key === 'Escape') {
// Close the menu
event.preventDefault();
setIsHidden(true);
} else if (event.key === 'ArrowUp') {

View File

@@ -12,7 +12,7 @@ import {
import { EdgeInsets, withSafeAreaInsets } from 'react-native-safe-area-context';
import { connect, useDispatch } from 'react-redux';
import { appNavigate } from '../../../app/actions.native';
import { appNavigate } from '../../../app/actions';
import { IReduxState, IStore } from '../../../app/types';
import { CONFERENCE_BLURRED, CONFERENCE_FOCUSED } from '../../../base/conference/actionTypes';
import { FULLSCREEN_ENABLED, PIP_ENABLED } from '../../../base/flags/constants';
@@ -41,15 +41,15 @@ import { navigate } from '../../../mobile/navigation/components/conference/Confe
import { screen } from '../../../mobile/navigation/routes';
import { setPictureInPictureEnabled } from '../../../mobile/picture-in-picture/functions';
import Captions from '../../../subtitles/components/native/Captions';
import { setToolboxVisible } from '../../../toolbox/actions.native';
import { setToolboxVisible } from '../../../toolbox/actions';
import Toolbox from '../../../toolbox/components/native/Toolbox';
import { isToolboxVisible } from '../../../toolbox/functions.native';
import { isToolboxVisible } from '../../../toolbox/functions';
import {
AbstractConference,
abstractMapStateToProps
} from '../AbstractConference';
import type { AbstractProps } from '../AbstractConference';
import { isConnecting } from '../functions.native';
import { isConnecting } from '../functions';
import AlwaysOnLabels from './AlwaysOnLabels';
import ExpandedLabelPopup from './ExpandedLabelPopup';
@@ -230,9 +230,7 @@ class Conference extends AbstractConference<IProps, State> {
*/
componentDidUpdate(prevProps: IProps) {
const {
_audioOnlyEnabled,
_showLobby,
_startCarMode
_showLobby
} = this.props;
if (!prevProps._showLobby && _showLobby) {
@@ -240,10 +238,6 @@ class Conference extends AbstractConference<IProps, State> {
}
if (prevProps._showLobby && !_showLobby) {
if (_audioOnlyEnabled && _startCarMode) {
return;
}
navigate(screen.conference.main);
}
}

View File

@@ -71,7 +71,8 @@ export function maybeOpenFeedbackDialog(conference: IJitsiConference, title?: st
showThankYou: true,
wasDialogShown: false
});
} else if (shouldSendJaaSFeedbackMetadata(state)
} else if (
(conference.isCallstatsEnabled() || shouldSendJaaSFeedbackMetadata(state))
&& feedbackPercentage > Math.random() * 100) {
return new Promise(resolve => {
dispatch(openFeedbackDialog(conference, title, () => {
@@ -167,6 +168,10 @@ export function submitFeedback(
const state = getState();
const promises = [];
if (conference.isCallstatsEnabled()) {
promises.push(conference.sendFeedback(score, message));
}
if (shouldSendJaaSFeedbackMetadata(state)) {
promises.push(dispatch(sendJaasFeedbackMetadata(conference, {
score,

View File

@@ -50,7 +50,7 @@ const mapStateToProps = (state: IReduxState) => {
return {
_conference: conference,
visible: shouldSendJaaSFeedbackMetadata(state)
visible: conference?.isCallstatsEnabled() || shouldSendJaaSFeedbackMetadata(state)
};
};

View File

@@ -154,10 +154,11 @@ function _conferenceFailed({ getState }: IStore, next: Function, action: AnyActi
// prevented the user from joining a specific conference but the app may be
// able to eventually join the conference.
if (!action.error.recoverable) {
const { callUUID } = action.conference;
if (action?.conference?.callUUID) {
if (callUUID) {
delete action.conference.callUUID;
CallIntegration.reportCallFailed(action.conference.callUUIDID);
CallIntegration.reportCallFailed(callUUID);
}
}
@@ -184,9 +185,9 @@ function _conferenceJoined({ getState }: IStore, next: Function, action: AnyActi
return result;
}
if (action?.conference?.callUUID) {
const { callUUID } = action.conference;
const { callUUID } = action.conference;
if (callUUID) {
CallIntegration.reportConnectedOutgoingCall(callUUID)
.then(() => {
// iOS 13 doesn't like the mute state to be false before the call is started
@@ -229,9 +230,11 @@ function _conferenceLeft({ getState }: IStore, next: Function, action: AnyAction
return result;
}
if (action?.conference?.callUUID) {
const { callUUID } = action.conference;
if (callUUID) {
delete action.conference.callUUID;
CallIntegration.endCall(action.conference.callUUID);
CallIntegration.endCall(callUUID);
}
return result;

View File

@@ -30,7 +30,7 @@ interface IProps {
/**
* Is the navigator part of Welcome page?
*/
isInWelcomePage?: boolean | undefined;
isInWelcomePage?: boolean;
}

View File

@@ -288,6 +288,13 @@ function _visitNode(node, callback) {
global.performance.now = performanceNow;
global.PerformanceObserver = perf.PerformanceObserver;
// CallStats
//
// Required by:
// - lib-jitsi-meet
require('react-native-callstats/csio-polyfill');
global.callstats = require('react-native-callstats/callstats');
// Timers
//
// React Native's timers won't run while the app is in the background, this

View File

@@ -1,4 +1,4 @@
import { NativeModules, Platform } from 'react-native';
import { NativeModules } from 'react-native';
import { getAppProp } from '../../base/app/functions';
import {
@@ -8,7 +8,6 @@ import {
CONFERENCE_LEFT,
CONFERENCE_WILL_JOIN
} from '../../base/conference/actionTypes';
import { SET_AUDIO_MUTED, SET_VIDEO_MUTED } from '../../base/media/actionTypes';
import { PARTICIPANT_JOINED } from '../../base/participants/actionTypes';
import MiddlewareRegistry from '../../base/redux/MiddlewareRegistry';
import StateListenerRegistry from '../../base/redux/StateListenerRegistry';
@@ -32,12 +31,6 @@ const { JMOngoingConference } = NativeModules;
const rnSdkHandlers = getAppProp(store, 'rnSdkHandlers');
switch (type) {
case SET_AUDIO_MUTED:
rnSdkHandlers?.onAudioMutedChanged && rnSdkHandlers?.onAudioMutedChanged(action.muted);
break;
case SET_VIDEO_MUTED:
rnSdkHandlers?.onVideoMutedChanged && rnSdkHandlers?.onVideoMutedChanged(Boolean(action.muted));
break;
case CONFERENCE_BLURRED:
rnSdkHandlers?.onConferenceBlurred && rnSdkHandlers?.onConferenceBlurred();
break;
@@ -72,10 +65,9 @@ const { JMOngoingConference } = NativeModules;
});
/**
* Before enabling media projection service control on Android,
* we need to check if native modules are being used or not.
* Check if native modules are being used or not.
*/
Platform.OS === 'android' && !externalAPIEnabled && StateListenerRegistry.register(
!externalAPIEnabled && StateListenerRegistry.register(
state => state['features/base/conference'].conference,
(conference, previousConference) => {
if (!conference) {

View File

@@ -152,6 +152,9 @@ export default class AbstractPageReloadOverlay<P extends IProps>
* @returns {void}
*/
componentDidMount() {
// FIXME (CallStats - issue) This event will not make it to CallStats
// because the log queue is not flushed before "fabric terminated" is
// sent to the backed.
// FIXME: We should dispatch action for this.
if (typeof APP !== 'undefined' && APP.conference?._room) {
APP.conference._room.sendApplicationLog(JSON.stringify({

View File

@@ -1,6 +1,8 @@
import React, { useCallback } from 'react';
import { FlatList, Text, TextStyle, View, ViewStyle } from 'react-native';
import { useSelector } from 'react-redux';
import { getLocalParticipant } from '../../../base/participants/functions';
import Button from '../../../base/ui/components/native/Button';
import { BUTTON_TYPES } from '../../../base/ui/constants.native';
import AbstractPollResults from '../AbstractPollResults';
@@ -18,7 +20,6 @@ const PollResults = (props: AbstractProps) => {
const {
answers,
changeVote,
creatorName,
haveVoted,
question,
showDetails,
@@ -87,6 +88,7 @@ const PollResults = (props: AbstractProps) => {
);
}, [ showDetails ]);
const localParticipant = useSelector(getLocalParticipant);
/* eslint-disable react/jsx-no-bind */
@@ -94,7 +96,7 @@ const PollResults = (props: AbstractProps) => {
<View>
<Text style = { dialogStyles.questionText as TextStyle } >{ question }</Text>
<Text style = { dialogStyles.questionOwnerText as TextStyle } >
{ t('polls.by', { name: creatorName }) }
{ t('polls.by', { name: localParticipant?.name }) }
</Text>
<FlatList
data = { answers }

View File

@@ -39,6 +39,11 @@ export const SET_DIALOUT_STATUS = 'SET_DIALOUT_STATUS';
*/
export const SET_JOIN_BY_PHONE_DIALOG_VISIBLITY = 'SET_JOIN_BY_PHONE_DIALOG_VISIBLITY';
/**
* Action type to set the precall test data.
*/
export const SET_PRECALL_TEST_RESULTS = 'SET_PRECALL_TEST_RESULTS';
/**
* Action type to disable the audio while on prejoin page.
*/

View File

@@ -30,6 +30,7 @@ import {
SET_DIALOUT_NUMBER,
SET_DIALOUT_STATUS,
SET_JOIN_BY_PHONE_DIALOG_VISIBLITY,
SET_PRECALL_TEST_RESULTS,
SET_PREJOIN_DEVICE_ERRORS,
SET_PREJOIN_PAGE_VISIBILITY,
SET_SKIP_PREJOIN_RELOAD
@@ -312,6 +313,25 @@ export function joinConferenceWithoutAudio() {
};
}
/**
* Initializes the 'precallTest' and executes one test, storing the results.
*
* @param {Object} conferenceOptions - The conference options.
* @returns {Function}
*/
export function makePrecallTest(conferenceOptions: Object) {
return async function(dispatch: IStore['dispatch']) {
try {
await JitsiMeetJS.precallTest.init(conferenceOptions);
const results = await JitsiMeetJS.precallTest.execute();
dispatch(setPrecallTestResults(results));
} catch (error) {
logger.debug('Failed to execute pre call test - ', error);
}
};
}
/**
* Opens an external page with all the dial in numbers.
*
@@ -495,6 +515,19 @@ export function setJoinByPhoneDialogVisiblity(value: boolean) {
};
}
/**
* Action used to set data from precall test.
*
* @param {Object} value - The precall test results.
* @returns {Object}
*/
export function setPrecallTestResults(value: Object) {
return {
type: SET_PRECALL_TEST_RESULTS,
value
};
}
/**
* Action used to set the initial errors after creating the tracks.
*

View File

@@ -2,13 +2,14 @@ import React, { ComponentType } from 'react';
import { batch } from 'react-redux';
import BaseApp from '../../../base/app/components/BaseApp';
import { getConferenceOptions } from '../../../base/conference/functions';
import { setConfig } from '../../../base/config/actions';
import { createPrejoinTracks } from '../../../base/tracks/functions.web';
import GlobalStyles from '../../../base/ui/components/GlobalStyles.web';
import JitsiThemeProvider from '../../../base/ui/components/JitsiThemeProvider.web';
import DialogContainer from '../../../base/ui/components/web/DialogContainer';
import { setupInitialDevices } from '../../../conference/actions.web';
import { initPrejoin } from '../../actions.web';
import { initPrejoin, makePrecallTest } from '../../actions.web';
import PrejoinThirdParty from './PrejoinThirdParty';
@@ -66,6 +67,7 @@ export default class PrejoinApp extends BaseApp<Props> {
batch(() => {
dispatch?.(initPrejoin(tracks, errors));
store && dispatch?.(makePrecallTest(getConferenceOptions(store.getState())));
});
}

View File

@@ -8,6 +8,7 @@ import {
SET_DIALOUT_NUMBER,
SET_DIALOUT_STATUS,
SET_JOIN_BY_PHONE_DIALOG_VISIBLITY,
SET_PRECALL_TEST_RESULTS,
SET_PREJOIN_DEVICE_ERRORS,
SET_PREJOIN_PAGE_VISIBILITY,
SET_SKIP_PREJOIN_RELOAD
@@ -44,6 +45,11 @@ export interface IPrejoinState {
dialOutStatus: string;
joiningInProgress?: boolean;
name: string;
precallTestResults?: {
fractionalLoss: number;
mediaConnectivity: boolean;
throughput: number;
};
rawError: string;
showJoinByPhoneDialog: boolean;
showPrejoin: boolean;
@@ -75,6 +81,12 @@ ReducerRegistry.register<IPrejoinState>(
};
}
case SET_PRECALL_TEST_RESULTS:
return {
...state,
precallTestResults: action.value
};
case SET_PREJOIN_PAGE_VISIBILITY:
return {
...state,

View File

@@ -31,6 +31,6 @@ export function showSalesforceNotification() {
dispatch(openDialog(SalesforceLinkDialog));
} ],
appearance: NOTIFICATION_TYPE.NORMAL
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
};
}

View File

@@ -83,10 +83,9 @@ class ShareAudioDialog extends Component<IProps> {
titleKey = { t('dialog.shareAudioTitle') }>
<div className = 'share-audio-dialog'>
<img
alt = { t('dialog.shareAudioAltText') }
alt = ''
className = 'share-audio-animation'
src = 'images/share-audio.gif'
tabIndex = { 0 } />
src = 'images/share-audio.gif' />
<Checkbox
checked = { this.props._shouldHideShareAudioHelper }
label = { t('dialog.hideShareAudioHelper') }

View File

@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import React, { useCallback, useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
@@ -7,7 +7,7 @@ import { IReduxState } from '../../../app/types';
import { updateSettings } from '../../../base/settings/actions';
import Input from '../../../base/ui/components/native/Input';
import Switch from '../../../base/ui/components/native/Switch';
import { isServerURLChangeEnabled, normalizeUserInputURL } from '../../functions.native';
import { isServerURLChangeEnabled, normalizeUserInputURL } from '../../functions.any';
import FormRow from './FormRow';
import FormSection from './FormSection';
@@ -17,6 +17,7 @@ import styles from './styles';
const ConferenceSection = () => {
const { t } = useTranslation();
const dispatch = useDispatch();
const defaultServerURL = useSelector((state: IReduxState) => getDefaultURL(state));
const {
serverURL,
startCarMode,
@@ -24,10 +25,7 @@ const ConferenceSection = () => {
startWithVideoMuted
} = useSelector((state: IReduxState) => state['features/base/settings']);
const defaultServerURL = useSelector((state: IReduxState) => getDefaultURL(state));
const [ newServerURL, setNewServerURL ] = useState(serverURL ?? '');
const serverURLChangeEnabled = useSelector((state: IReduxState) => isServerURLChangeEnabled(state));
const { serverURLChangeEnabled } = useSelector((state: IReduxState) => isServerURLChangeEnabled(state));
const switches = useMemo(() => [
{
@@ -47,27 +45,21 @@ const ConferenceSection = () => {
}
], [ startCarMode, startWithAudioMuted, startWithVideoMuted ]);
const onChangeServerURL = useCallback(value => {
setNewServerURL(value);
dispatch(updateSettings({
serverURL: value
}));
}, [ dispatch, newServerURL ]);
const onChangeServerURL = useCallback(newServerURL => {
dispatch(updateSettings({ serverURL: newServerURL }));
}, [ updateSettings ]);
const processServerURL = useCallback(() => {
const normalizedURL = normalizeUserInputURL(newServerURL);
const normalizedURL = normalizeUserInputURL(serverURL ?? '');
onChangeServerURL(normalizedURL);
}, [ newServerURL ]);
}, [ serverURL ]);
useEffect(() => () => processServerURL(), []);
const onSwitchToggled = useCallback((name: string) => (enabled?: boolean) => {
// @ts-ignore
dispatch(updateSettings({ [name]: enabled }));
}, [ dispatch ]);
}, [ dispatch, updateSettings ]);
return (
<FormSection
@@ -82,7 +74,7 @@ const ConferenceSection = () => {
onChange = { onChangeServerURL }
placeholder = { defaultServerURL }
textContentType = { 'URL' } // iOS only
value = { newServerURL } />
value = { serverURL ?? '' } />
{
switches.map(({ label, state, name }) => (
<FormRow

View File

@@ -2,7 +2,6 @@ import { useNavigation } from '@react-navigation/native';
import React, { useCallback, useLayoutEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ScrollView, Text, View, ViewStyle } from 'react-native';
import { Edge } from 'react-native-safe-area-context';
import { useDispatch, useSelector } from 'react-redux';
import { IReduxState } from '../../../app/types';
@@ -40,7 +39,6 @@ const ProfileView = ({ isInWelcomePage }: {
(state: IReduxState) => state['features/base/settings']
);
const participant = useSelector((state: IReduxState) => getLocalParticipant(state));
const { locationURL } = useSelector((state: IReduxState) => state['features/base/connection']);
const [ displayName, setDisplayName ] = useState(reduxDisplayName);
const [ email, setEmail ] = useState(reduxEmail);
@@ -105,9 +103,7 @@ const ProfileView = ({ isInWelcomePage }: {
useLayoutEffect(() => {
navigation.setOptions({
headerLeft,
headerRight: !isInWelcomePage
&& !locationURL?.hostname?.includes('8x8.vc')
&& headerRight
headerRight: !isInWelcomePage && headerRight
});
}, [ navigation ]);
@@ -116,7 +112,7 @@ const ProfileView = ({ isInWelcomePage }: {
disableForcedKeyboardDismiss = { true }
// @ts-ignore
safeAreaInsets = { [ !isInWelcomePage && 'bottom', 'left', 'right' ].filter(Boolean) as Edge[] }
safeAreaInsets = { [ !isInWelcomePage && 'bottom', 'left', 'right' ].filter(Boolean) }
style = { styles.settingsViewContainer }>
<ScrollView
bounces = { isInWelcomePage }

View File

@@ -1,18 +1,18 @@
import React from 'react';
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import {
ScrollView,
Text,
TextStyle,
TouchableHighlight,
View,
ViewStyle
} from 'react-native';
import { Divider } from 'react-native-paper';
import { Edge } from 'react-native-safe-area-context';
import { useSelector } from 'react-redux';
import { connect } from 'react-redux';
import { IReduxState } from '../../../app/types';
import { IReduxState, IStore } from '../../../app/types';
import Avatar from '../../../base/avatar/components/Avatar';
import { translate } from '../../../base/i18n/functions';
import Icon from '../../../base/icons/components/Icon';
import { IconArrowRight } from '../../../base/icons/svg';
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
@@ -30,72 +30,148 @@ import NotificationsSection from './NotificationsSection';
import { AVATAR_SIZE } from './constants';
import styles from './styles';
/**
* The type of the React {@code Component} props of
* {@link SettingsView}.
*/
interface IProps extends WithTranslation {
interface IProps {
_displayName?: string;
isInWelcomePage?: boolean | undefined;
/**
* The ID of the local participant.
*/
_localParticipantId?: string;
/**
* Flag indicating whether the moderator settings are available.
*/
_showModeratorSettings: boolean;
/**
* Whether {@link SettingsView} is visible.
*
* @protected
*/
_visible?: boolean;
/**
* Redux store dispatch function.
*/
dispatch: IStore['dispatch'];
/**
* Flag indicating whether the settings is launched inside welcome page.
*/
isInWelcomePage?: boolean;
/**
* Default prop for navigating between screen components(React Navigation).
*/
navigation?: Object;
}
const SettingsView = ({ isInWelcomePage }: IProps) => {
const { displayName } = useSelector((state: IReduxState) => state['features/base/settings']);
const localParticipant = useSelector((state: IReduxState) => getLocalParticipant(state));
const showModeratorSettings = useSelector((state: IReduxState) => shouldShowModeratorSettings(state));
const { visible } = useSelector((state: IReduxState) => state['features/settings']);
/**
* The native container rendering the app settings page.
*/
class SettingsView extends Component<IProps> {
const addBottomInset = !isInWelcomePage;
const localParticipantId = localParticipant?.id;
const scrollBounces = Boolean(isInWelcomePage);
if (visible !== undefined && !visible) {
return null;
/**
* Opens the profile settings screen.
*
* @returns {void}
*/
_onPressProfile() {
navigate(screen.settings.profile);
}
return (
<JitsiScreen
disableForcedKeyboardDismiss = { true }
safeAreaInsets = { [ addBottomInset && 'bottom', 'left', 'right' ].filter(Boolean) as Edge[] }
style = { styles.settingsViewContainer }>
<ScrollView bounces = { scrollBounces }>
<View style = { styles.profileContainerWrapper as ViewStyle }>
<TouchableHighlight
/**
* Implements React's {@link Component#render()}, renders the settings page.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const {
_displayName
} = this.props;
/* eslint-disable react/jsx-no-bind */
onPress = { () => navigate(screen.settings.profile) }>
<View
style = { styles.profileContainer as ViewStyle }>
<Avatar
participantId = { localParticipantId }
size = { AVATAR_SIZE } />
<Text style = { styles.displayName as TextStyle }>
{ displayName }
</Text>
<Icon
size = { 24 }
src = { IconArrowRight }
style = { styles.profileViewArrow } />
</View>
</TouchableHighlight>
</View>
<GeneralSection />
{ isInWelcomePage && <>
<Divider style = { styles.fieldSeparator as ViewStyle } />
<ConferenceSection />
</> }
<Divider style = { styles.fieldSeparator as ViewStyle } />
<NotificationsSection />
const {
isInWelcomePage,
_showModeratorSettings
} = this.props;
{ showModeratorSettings
&& <>
<Divider style = { styles.fieldSeparator as ViewStyle } />
<ModeratorSection />
const addBottomInset = !isInWelcomePage;
const scrollBounces = Boolean(isInWelcomePage);
return (
<JitsiScreen
disableForcedKeyboardDismiss = { true }
// @ts-ignore
safeAreaInsets = { [ addBottomInset && 'bottom', 'left', 'right' ].filter(Boolean) }
style = { styles.settingsViewContainer }>
<ScrollView bounces = { scrollBounces }>
<View style = { styles.profileContainerWrapper }>
<TouchableHighlight onPress = { this._onPressProfile }>
<View
style = { styles.profileContainer as ViewStyle }>
<Avatar
participantId = { this.props._localParticipantId }
size = { AVATAR_SIZE } />
<Text style = { styles.displayName }>
{ _displayName }
</Text>
<Icon
size = { 24 }
src = { IconArrowRight }
style = { styles.profileViewArrow } />
</View>
</TouchableHighlight>
</View>
<GeneralSection />
{ isInWelcomePage && <>
{/* @ts-ignore */}
<Divider style = { styles.fieldSeparator } />
<ConferenceSection />
</> }
<Divider style = { styles.fieldSeparator as ViewStyle } />
<AdvancedSection />
<Divider style = { styles.fieldSeparator as ViewStyle } />
<LinksSection />
</ScrollView>
</JitsiScreen>
);
};
{/* @ts-ignore */}
<Divider style = { styles.fieldSeparator } />
<NotificationsSection />
export default SettingsView;
{ _showModeratorSettings
&& <>
{/* @ts-ignore */}
<Divider style = { styles.fieldSeparator } />
<ModeratorSection />
</> }
{/* @ts-ignore */}
<Divider style = { styles.fieldSeparator } />
<AdvancedSection />
{/* @ts-ignore */}
<Divider style = { styles.fieldSeparator } />
<LinksSection />
</ScrollView>
</JitsiScreen>
);
}
}
/**
* Maps part of the Redux state to the props of this component.
*
* @param {Object} state - The Redux state.
* @returns {IProps}
*/
function _mapStateToProps(state: IReduxState) {
const localParticipant = getLocalParticipant(state);
return {
_localParticipantId: localParticipant?.id,
_displayName: state['features/base/settings'].displayName,
_visible: state['features/settings'].visible,
_showModeratorSettings: shouldShowModeratorSettings(state)
};
}
export default translate(connect(_mapStateToProps)(SettingsView));

View File

@@ -1,12 +1,14 @@
import { IReduxState } from '../app/types';
import { IStateful } from '../base/app/types';
import { isNameReadOnly } from '../base/config/functions.any';
import { isNameReadOnly } from '../base/config/functions';
import { SERVER_URL_CHANGE_ENABLED } from '../base/flags/constants';
import { getFeatureFlag } from '../base/flags/functions';
import i18next, { DEFAULT_LANGUAGE, LANGUAGES } from '../base/i18n/i18next';
import { getLocalParticipant } from '../base/participants/functions';
import {
getLocalParticipant
} from '../base/participants/functions';
import { toState } from '../base/redux/functions';
import { getHideSelfView } from '../base/settings/functions.any';
import { getHideSelfView } from '../base/settings/functions';
import { parseStandardURIString } from '../base/util/uri';
import { isStageFilmstripEnabled } from '../filmstrip/functions';
import { isFollowMeActive } from '../follow-me/functions';
@@ -24,8 +26,9 @@ import { shouldShowModeratorSettings } from './functions';
*/
export function isServerURLChangeEnabled(stateful: IStateful) {
const state = toState(stateful);
const flag = getFeatureFlag(state, SERVER_URL_CHANGE_ENABLED, true);
return getFeatureFlag(state, SERVER_URL_CHANGE_ENABLED, true);
return flag;
}
/**

View File

@@ -79,7 +79,7 @@ const useStyles = makeStyles()(theme => {
width: 6
},
track: {
background: theme.palette.text03,
background: theme.palette.ui02,
borderRadius: Number(theme.shape.borderRadius) / 2,
height
},

View File

@@ -18,12 +18,7 @@ ReducerRegistry.register<IVisitorsState>('features/visitors', (state = DEFAULT_S
case CONFERENCE_WILL_LEAVE: {
return {
...state,
...DEFAULT_STATE,
// If the action was called because a visitor was promoted don't clear the iAmVisitor field. It will be set
// to false with the I_AM_VISITOR_MODE action and we will be able to distinguish leaving the conference use
// case and promoting a visitor use case.
iAmVisitor: action.isRedirect ? state.iAmVisitor : DEFAULT_STATE.iAmVisitor
...DEFAULT_STATE
};
}
case UPDATE_VISITORS_COUNT: {

View File

@@ -1,3 +1,5 @@
/* global APP */
import React from 'react';
import ReactDOM from 'react-dom';
@@ -11,6 +13,16 @@ import PrejoinApp from './features/prejoin/components/web/PrejoinApp';
const logger = getLogger('index.web');
const OS = Platform.OS;
/**
* Renders the app when the DOM tree has been loaded.
*/
document.addEventListener('DOMContentLoaded', () => {
const now = window.performance.now();
APP.connectionTimes['document.ready'] = now;
logger.log('(TIME) document ready:\t', now);
});
// Workaround for the issue when returning to a page with the back button and
// the page is loaded from the 'back-forward' cache on iOS which causes nothing
// to be rendered.
@@ -30,18 +42,6 @@ if (OS === 'ios') {
const globalNS = getJitsiMeetGlobalNS();
// Used for automated performance tests.
globalNS.connectionTimes = {
'index.loaded': window.indexLoadedTime
};
document.addEventListener('DOMContentLoaded', () => {
const now = window.performance.now();
globalNS.connectionTimes['document.ready'] = now;
logger.log('(TIME) document ready:\t', now);
});
globalNS.entryPoints = {
APP: App,
PREJOIN: PrejoinApp,

View File

@@ -246,25 +246,8 @@ function process_set_affiliation(event)
end
end
function process_main_muc_loaded(main_muc, host_module)
module:log('debug', 'Main muc loaded');
main_muc_service = main_muc;
module:log("info", "Hook to muc events on %s", main_muc_component_host);
host_module:hook("muc-pre-set-affiliation", process_set_affiliation);
end
process_host_module(main_muc_component_host, function(host_module, host)
local muc_module = prosody.hosts[host].modules.muc;
main_muc_service = prosody.hosts[host].modules.muc;
if muc_module then
process_main_muc_loaded(muc_module, host_module);
else
module:log('debug', 'Will wait for muc to be available');
prosody.hosts[host].events.add_handler('module-loaded', function(event)
if (event.module == 'muc') then
process_main_muc_loaded(prosody.hosts[host].modules.muc, host_module);
end
end);
end
host_module:hook("muc-pre-set-affiliation", process_set_affiliation);
end);

View File

@@ -15,9 +15,6 @@
-- muc_room_locking = false
-- muc_room_default_public_jids = true
--
module:depends('room_destroy');
-- we use async to detect Prosody 0.10 and earlier
local have_async = pcall(require, 'util.async');
@@ -430,39 +427,14 @@ function on_occupant_left(event)
-- and we will have the old instance
local main_room, main_room_jid = get_main_room(room_jid);
if main_room and main_room.close_timer then
prosody.events.fire_event("maybe-destroy-room", {
room = main_room;
reason = 'All occupants left.';
caller = module:get_name();
});
module:log('info', 'Closing conference %s as all left for good.', main_room_jid);
main_room:set_persistent(false);
main_room:destroy(nil, 'All occupants left.');
end
end);
end
end
-- Stop other modules from destroying room if breakout rooms not empty
function handle_maybe_destroy_main_room(event)
local main_room = event.room;
local caller = event.caller;
if caller == module:get_name() then
-- we were the one that requested the deletion. Do not override.
return nil; -- stop room destruction
end
-- deletion was requested by another module. Check for break room occupants.
for breakout_room_jid, _ in pairs(main_room._data.breakout_rooms or {}) do
local breakout_room = breakout_rooms_muc_service.get_room_from_jid(breakout_room_jid);
if breakout_room and breakout_room:has_occupant() then
module:log('info', 'Suppressing room destroy. Breakout room still occupied %s', breakout_room_jid);
return true; -- stop room destruction
end
end
end
module:hook_global("maybe-destroy-room", handle_maybe_destroy_main_room)
function on_main_room_destroyed(event)
local main_room = event.room;

View File

@@ -8,7 +8,6 @@
-- To trigger creation of lobby room:
-- prosody.events.fire_event("create-persistent-lobby-room", { room = room; });
--
module:depends('room_destroy');
local util = module:require "util";
local is_healthcheck_room = util.is_healthcheck_room;
@@ -87,11 +86,8 @@ end
-- Helper method to trigger main room destroy
local function trigger_room_destroy(room)
prosody.events.fire_event("maybe-destroy-room", {
room = room;
reason = 'main room and lobby now empty';
caller = module:get_name();
});
room:set_persistent(false);
room:destroy(nil, 'main room and lobby now empty');
end
@@ -174,26 +170,3 @@ end
module:hook_global('create-persistent-lobby-room', handle_create_persistent_lobby);
-- Stop other modules from destroying room if persistent lobby not empty
function handle_maybe_destroy_main_room(event)
local main_room = event.room;
local caller = event.caller;
if caller == module:get_name() then
-- we were the one that requested the deletion. Do not override.
return nil;
end
-- deletion was requested by another module. Check for lobby occupants.
if has_persistent_lobby(main_room) and main_room._data.lobbyroom then
local lobby_room_jid = main_room._data.lobbyroom;
local lobby_room = lobby_muc_service.get_room_from_jid(lobby_room_jid);
if lobby_room and lobby_room:has_occupant() then
module:log('info', 'Suppressing room destroy. Persistent lobby still occupied %s', lobby_room_jid);
return true; -- stop room destruction
end
end
end
module:hook_global("maybe-destroy-room", handle_maybe_destroy_main_room);

View File

@@ -1,15 +0,0 @@
-- Handle room destroy requests it such a way that it can be suppressed by other
-- modules that handle room lifecycle and wish to keep the room alive.
function handle_room_destroy(event)
local room = event.room;
local reason = event.reason;
local caller = event.caller;
module:log('info', 'Destroying room %s (requested by %s)', room.jid, caller);
room:set_persistent(false);
room:destroy(nil, reason);
end
module:hook_global("maybe-destroy-room", handle_room_destroy, -1);
module:log('info', 'loaded');

View File

@@ -6,4 +6,4 @@
<meta itemprop="name" content="Jitsi Meet"/>
<meta itemprop="description" content="Join a WebRTC video conference powered by the Jitsi Videobridge"/>
<meta itemprop="image" content="images/jitsilogo.png?v=1"/>
<link rel="icon" href="images/favicon.svg?v=1">
<link rel="icon" type="image/png" href="images/favicon.ico?v=1"/>