mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-02-08 23:10:20 +00:00
Compare commits
126 Commits
7579
...
fix_analyt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a403a221ae | ||
|
|
3a836eba63 | ||
|
|
55a16f31c2 | ||
|
|
7de88f4e47 | ||
|
|
d71b827d1a | ||
|
|
3811caa8a0 | ||
|
|
32f6bc376b | ||
|
|
8b4ebe4fa3 | ||
|
|
45415ef8da | ||
|
|
99bba14628 | ||
|
|
8b8b2568e2 | ||
|
|
ca144e127c | ||
|
|
965760df41 | ||
|
|
6ab25f7bc0 | ||
|
|
701ae5b2b1 | ||
|
|
b2d6ee06df | ||
|
|
18f5bdeaf8 | ||
|
|
dd6ce33296 | ||
|
|
5a7a6bf59c | ||
|
|
20d8a403f3 | ||
|
|
0bce8e185d | ||
|
|
7f21075613 | ||
|
|
e833860fcb | ||
|
|
376b17e011 | ||
|
|
87541a63d3 | ||
|
|
109b83d6f1 | ||
|
|
3a1fc363ed | ||
|
|
71658a5de6 | ||
|
|
40ac57a5d4 | ||
|
|
a20bf845ea | ||
|
|
95943b725c | ||
|
|
0813ae0f3c | ||
|
|
a33e34c309 | ||
|
|
821cc11364 | ||
|
|
caf7df4a82 | ||
|
|
bda39ef876 | ||
|
|
9e2ed855eb | ||
|
|
3be453e76a | ||
|
|
dec54692c1 | ||
|
|
e77d19b128 | ||
|
|
a83bf98625 | ||
|
|
3307365885 | ||
|
|
341fc774a6 | ||
|
|
56673f14b5 | ||
|
|
ab08eb2f99 | ||
|
|
000458697d | ||
|
|
b0c56d8963 | ||
|
|
0ecd65777e | ||
|
|
6d02f50d09 | ||
|
|
a71143891e | ||
|
|
6fda5924a3 | ||
|
|
b09574f62f | ||
|
|
8cdde88049 | ||
|
|
9cd42b988d | ||
|
|
8b559ad4f2 | ||
|
|
192fce8740 | ||
|
|
235016d7cf | ||
|
|
27792b0be4 | ||
|
|
765fd7d766 | ||
|
|
d49a5097f0 | ||
|
|
cfcc3fdbbe | ||
|
|
fdbceb0e42 | ||
|
|
89197cbdb2 | ||
|
|
f067f07d64 | ||
|
|
4594a978e0 | ||
|
|
fcddccf018 | ||
|
|
7a9285b326 | ||
|
|
11f0ab9226 | ||
|
|
0b6705610c | ||
|
|
9d9199ba3b | ||
|
|
ff656a0625 | ||
|
|
148fc103e3 | ||
|
|
77abbee308 | ||
|
|
83c4ce98b4 | ||
|
|
898741e40d | ||
|
|
0c3e7395e7 | ||
|
|
c530bdd107 | ||
|
|
29dbcb309d | ||
|
|
8a4990d9ae | ||
|
|
0e55cbbda6 | ||
|
|
6da94aecf2 | ||
|
|
2a3c962e88 | ||
|
|
34f1eb60f4 | ||
|
|
4115ebe856 | ||
|
|
d7dadfc157 | ||
|
|
2851eeeab3 | ||
|
|
84d75f2ae8 | ||
|
|
73b3309adf | ||
|
|
e2de06f60d | ||
|
|
cdc7962d11 | ||
|
|
59242e1217 | ||
|
|
631e39d4fd | ||
|
|
4290cdf53d | ||
|
|
84c1e20216 | ||
|
|
e6caeb86b0 | ||
|
|
5854e38a09 | ||
|
|
3e9ee9451f | ||
|
|
29d02f0a2b | ||
|
|
c780f9bbba | ||
|
|
d5a0bac0a3 | ||
|
|
f0187cc0f8 | ||
|
|
4708d894cc | ||
|
|
f38d120406 | ||
|
|
53960baf76 | ||
|
|
a0f061aa6f | ||
|
|
f2fb525d0a | ||
|
|
5a59bee597 | ||
|
|
07b903d887 | ||
|
|
1a39315001 | ||
|
|
97e5f00dae | ||
|
|
bae77f21f8 | ||
|
|
24d788f333 | ||
|
|
c4d553c605 | ||
|
|
fa64e2e67c | ||
|
|
94c29180e4 | ||
|
|
b864d91572 | ||
|
|
2006182a2a | ||
|
|
8fc3de416c | ||
|
|
4c5787511e | ||
|
|
8a2e4bc628 | ||
|
|
f78ebbb9a9 | ||
|
|
4cc4c25691 | ||
|
|
d02c7dc3a7 | ||
|
|
8741ee771e | ||
|
|
006e8463cd | ||
|
|
86e295e9bc |
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
@@ -74,3 +74,17 @@ 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
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -99,6 +99,10 @@ tsconfig.json
|
||||
#
|
||||
react-native-sdk/*.tgz
|
||||
react-native-sdk/android/src
|
||||
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/JitsiMeetOngoingConferenceService.java
|
||||
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/JitsiMeetReactNativePackage.java
|
||||
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/JMOngoingConferenceModule.java
|
||||
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/RNOngoingNotification.java
|
||||
react-native-sdk/images
|
||||
react-native-sdk/ios
|
||||
react-native-sdk/lang
|
||||
|
||||
4
Makefile
4
Makefile
@@ -55,6 +55,8 @@ deploy-appbundle:
|
||||
$(BUILD_DIR)/face-landmarks-worker.min.js.map \
|
||||
$(BUILD_DIR)/noise-suppressor-worklet.min.js \
|
||||
$(BUILD_DIR)/noise-suppressor-worklet.min.js.map \
|
||||
$(BUILD_DIR)/screenshot-capture-worker.min.js \
|
||||
$(BUILD_DIR)/screenshot-capture-worker.min.js.map \
|
||||
$(DEPLOY_DIR)
|
||||
cp \
|
||||
$(BUILD_DIR)/close3.min.js \
|
||||
@@ -123,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 favicon.ico fonts images libs static sounds LICENSE lang source_package/jitsi-meet && \
|
||||
cp -r *.js *.html resources/*.txt 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
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<?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>
|
||||
<?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>
|
||||
|
||||
6
app.js
6
app.js
@@ -31,12 +31,6 @@ if (window.Olm) {
|
||||
window.APP = {
|
||||
API,
|
||||
conference,
|
||||
|
||||
// Used for automated performance tests.
|
||||
connectionTimes: {
|
||||
'index.loaded': window.indexLoadedTime
|
||||
},
|
||||
|
||||
translation,
|
||||
UI
|
||||
};
|
||||
|
||||
126
conference.js
126
conference.js
@@ -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, makePrecallTest } from './react/features/prejoin/actions';
|
||||
import { initPrejoin } 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,8 +718,6 @@ export default {
|
||||
};
|
||||
|
||||
if (isPrejoinPageVisible(state)) {
|
||||
APP.store.dispatch(makePrecallTest(this._getConferenceOptions()));
|
||||
|
||||
const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(initialOptions);
|
||||
const localTracks = await tryCreateLocalTracks;
|
||||
|
||||
@@ -1039,17 +1037,6 @@ 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.
|
||||
*
|
||||
@@ -1061,13 +1048,6 @@ export default {
|
||||
return room.getSpeakerStats();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the connection times stored in the library.
|
||||
*/
|
||||
getConnectionTimes() {
|
||||
return room.getConnectionTimes();
|
||||
},
|
||||
|
||||
// used by torture currently
|
||||
isJoined() {
|
||||
return room && room.isJoined();
|
||||
@@ -2049,10 +2029,6 @@ export default {
|
||||
|
||||
return this.useVideoStream(stream);
|
||||
})
|
||||
.then(() => {
|
||||
logger.info(`Switched local video device to ${cameraDeviceId}.`);
|
||||
this._updateVideoDeviceId();
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error(`Failed to switch to selected camera:${cameraDeviceId}, error:${error}`);
|
||||
|
||||
@@ -2107,8 +2083,6 @@ export default {
|
||||
// above mentioned chrome bug.
|
||||
localAudio._realDeviceId = localAudio.deviceId = 'default';
|
||||
}
|
||||
logger.info(`switched local audio input device to: ${selectedDeviceId}`);
|
||||
this._updateAudioDeviceId();
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error(`Failed to switch to selected audio input device ${selectedDeviceId}, error=${err}`);
|
||||
@@ -2193,13 +2167,6 @@ export default {
|
||||
|
||||
return dispatch(getAvailableDevices())
|
||||
.then(devices => {
|
||||
// Ugly way to synchronize real device IDs with local
|
||||
// storage and settings menu. This is a workaround until
|
||||
// getConstraints() method will be implemented in browsers.
|
||||
this._updateAudioDeviceId();
|
||||
|
||||
this._updateVideoDeviceId();
|
||||
|
||||
APP.UI.onAvailableDevicesChanged(devices);
|
||||
});
|
||||
}
|
||||
@@ -2207,36 +2174,6 @@ export default {
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the settings for the currently used video device, extracting
|
||||
* the device id from the used track.
|
||||
* @private
|
||||
*/
|
||||
_updateVideoDeviceId() {
|
||||
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
|
||||
|
||||
if (localVideo && localVideo.videoType === 'camera') {
|
||||
APP.store.dispatch(updateSettings({
|
||||
cameraDeviceId: localVideo.getDeviceId()
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the settings for the currently used audio device, extracting
|
||||
* the device id from the used track.
|
||||
* @private
|
||||
*/
|
||||
_updateAudioDeviceId() {
|
||||
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
|
||||
|
||||
if (localAudio) {
|
||||
APP.store.dispatch(updateSettings({
|
||||
micDeviceId: localAudio.getDeviceId()
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Event listener for JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED to
|
||||
* handle change of available media devices.
|
||||
@@ -2385,14 +2322,10 @@ export default {
|
||||
this.useAudioStream(track)
|
||||
.then(() => {
|
||||
hasDefaultMicChanged && (track._realDeviceId = track.deviceId = 'default');
|
||||
this._updateAudioDeviceId();
|
||||
}));
|
||||
} else {
|
||||
promises.push(
|
||||
this.useVideoStream(track)
|
||||
.then(() => {
|
||||
this._updateVideoDeviceId();
|
||||
}));
|
||||
this.useVideoStream(track));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2445,7 +2378,7 @@ export default {
|
||||
* @param {string} [hangupReason] the reason for leaving the meeting
|
||||
* requested
|
||||
*/
|
||||
async hangup(requestFeedback = false, hangupReason) {
|
||||
hangup(requestFeedback = false, hangupReason) {
|
||||
APP.store.dispatch(disableReceiver());
|
||||
|
||||
this._stopProxyConnection();
|
||||
@@ -2462,33 +2395,42 @@ export default {
|
||||
|
||||
APP.UI.removeAllListeners();
|
||||
|
||||
let feedbackResult = {};
|
||||
let feedbackResultPromise = Promise.resolve({});
|
||||
|
||||
if (requestFeedback) {
|
||||
try {
|
||||
feedbackResult = await APP.store.dispatch(maybeOpenFeedbackDialog(room, hangupReason));
|
||||
} catch (err) { // eslint-disable-line no-empty
|
||||
const feedbackDialogClosed = (feedbackResult = {}) => {
|
||||
if (!feedbackResult.wasDialogShown && hangupReason) {
|
||||
return APP.store.dispatch(
|
||||
openLeaveReasonDialog(hangupReason)).then(() => feedbackResult);
|
||||
}
|
||||
|
||||
return Promise.resolve(feedbackResult);
|
||||
};
|
||||
|
||||
feedbackResultPromise
|
||||
= APP.store.dispatch(maybeOpenFeedbackDialog(room, hangupReason))
|
||||
.then(feedbackDialogClosed, feedbackDialogClosed);
|
||||
}
|
||||
|
||||
const leavePromise = this.leaveRoom().catch(() => Promise.resolve());
|
||||
|
||||
Promise.allSettled([ feedbackResultPromise, leavePromise ]).then(([ feedback, _ ]) => {
|
||||
this._room = undefined;
|
||||
room = undefined;
|
||||
|
||||
/**
|
||||
* Don't call {@code notifyReadyToClose} if the promotional page flag is set
|
||||
* and let the page take care of sending the message, since there will be
|
||||
* a redirect to the page anyway.
|
||||
*/
|
||||
if (!interfaceConfig.SHOW_PROMOTIONAL_CLOSE_PAGE) {
|
||||
APP.API.notifyReadyToClose();
|
||||
}
|
||||
}
|
||||
|
||||
if (!feedbackResult.wasDialogShown && hangupReason) {
|
||||
await APP.store.dispatch(openLeaveReasonDialog(hangupReason));
|
||||
}
|
||||
APP.store.dispatch(maybeRedirectToWelcomePage(feedback.value ?? {}));
|
||||
});
|
||||
|
||||
await this.leaveRoom();
|
||||
|
||||
this._room = undefined;
|
||||
room = undefined;
|
||||
|
||||
/**
|
||||
* Don't call {@code notifyReadyToClose} if the promotional page flag is set
|
||||
* and let the page take care of sending the message, since there will be
|
||||
* a redirect to the page anyway.
|
||||
*/
|
||||
if (!interfaceConfig.SHOW_PROMOTIONAL_CLOSE_PAGE) {
|
||||
APP.API.notifyReadyToClose();
|
||||
}
|
||||
APP.store.dispatch(maybeRedirectToWelcomePage(feedbackResult));
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -2498,7 +2440,7 @@ export default {
|
||||
* @param {string} reason - reason for leaving the room.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async leaveRoom(doDisconnect = true, reason = '') {
|
||||
leaveRoom(doDisconnect = true, reason = '') {
|
||||
APP.store.dispatch(conferenceWillLeave(room));
|
||||
|
||||
const maybeDisconnect = () => {
|
||||
|
||||
121
config.js
121
config.js
@@ -51,6 +51,9 @@ var config = {
|
||||
// Websocket URL (XMPP)
|
||||
// websocket: 'wss://jitsi-meet.example.com/' + subdir + 'xmpp-websocket',
|
||||
|
||||
// Whether BOSH should be preferred over WebSocket if both are configured.
|
||||
// preferBosh: false,
|
||||
|
||||
// The real JID of focus participant - can be overridden here
|
||||
// Do not change username - FIXME: Make focus username configurable
|
||||
// https://github.com/jitsi/jitsi-meet/issues/7376
|
||||
@@ -94,11 +97,6 @@ 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.
|
||||
@@ -215,6 +213,9 @@ var config = {
|
||||
|
||||
// Video
|
||||
|
||||
// Sets the default camera facing mode.
|
||||
// cameraFacingMode: 'user',
|
||||
|
||||
// Sets the preferred resolution (height) for local video. Defaults to 720.
|
||||
// resolution: 720,
|
||||
|
||||
@@ -288,12 +289,19 @@ var config = {
|
||||
// max: 5,
|
||||
// },
|
||||
|
||||
// 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,
|
||||
// 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'
|
||||
// },
|
||||
|
||||
// Recording
|
||||
|
||||
@@ -431,6 +439,49 @@ 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
|
||||
@@ -632,6 +683,7 @@ var config = {
|
||||
// hideDominantSpeakerBadge: false,
|
||||
|
||||
// Default language for the user interface. Cannot be overwritten.
|
||||
// DEPRECATED! Use the `lang` iframe option directly instead.
|
||||
// defaultLanguage: 'en',
|
||||
|
||||
// Disables profile and the edit of all fields from the profile settings (display name and email)
|
||||
@@ -886,38 +938,10 @@ var config = {
|
||||
// The interval at which PeerConnection.getStats() is called. Defaults to 10000
|
||||
// pcStatsInterval: 10000,
|
||||
|
||||
// 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
|
||||
// Enables sending participants' display names to stats
|
||||
// enableDisplayNameInStats: false,
|
||||
|
||||
// Enables sending participants' emails (if available) to callstats and other analytics
|
||||
// Enables sending participants' emails (if available) to stats and other analytics
|
||||
// enableEmailInStats: false,
|
||||
|
||||
// faceLandmarks: {
|
||||
@@ -940,7 +964,7 @@ var config = {
|
||||
// captureInterval: 1000,
|
||||
// },
|
||||
|
||||
// Controls the percentage of automatic feedback shown to participants when callstats is enabled.
|
||||
// Controls the percentage of automatic feedback shown to participants.
|
||||
// The default value is 100%. If set to 0, no automatic feedback will be requested
|
||||
// feedbackPercentage: 100,
|
||||
|
||||
@@ -948,7 +972,7 @@ var config = {
|
||||
//
|
||||
|
||||
// If third party requests are disabled, no other server will be contacted.
|
||||
// This means avatars will be locally generated and callstats integration
|
||||
// This means avatars will be locally generated and external stats integration
|
||||
// will not function.
|
||||
// disableThirdPartyRequests: false,
|
||||
|
||||
@@ -1499,8 +1523,6 @@ var config = {
|
||||
_peerConnStatusOutOfLastNTimeout
|
||||
_peerConnStatusRtcMuteTimeout
|
||||
avgRtpStatsN
|
||||
callStatsConfIDNamespace
|
||||
callStatsCustomScriptUrl
|
||||
desktopSharingSources
|
||||
disableAEC
|
||||
disableAGC
|
||||
@@ -1509,7 +1531,6 @@ var config = {
|
||||
disableLocalStats
|
||||
disableNS
|
||||
enableTalkWhileMuted
|
||||
forceJVB121Ratio
|
||||
forceTurnRelay
|
||||
hiddenDomain
|
||||
hiddenFromRecorderFeatureEnabled
|
||||
@@ -1675,13 +1696,12 @@ var config = {
|
||||
// logging: {
|
||||
// // Default log level for the app and lib-jitsi-meet.
|
||||
// defaultLogLevel: 'trace',
|
||||
// // Option to disable LogCollector (which stores the logs on CallStats).
|
||||
// // Option to disable LogCollector.
|
||||
// //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',
|
||||
// },
|
||||
|
||||
@@ -1695,6 +1715,11 @@ var config = {
|
||||
// // The server used to support whiteboard collaboration.
|
||||
// // https://github.com/jitsi/excalidraw-backend
|
||||
// collabServerBaseUrl: 'https://excalidraw-backend.example.com',
|
||||
// // The user access limit to the whiteboard, introduced as a means
|
||||
// // to control the performance.
|
||||
// userLimit: 25,
|
||||
// // The url for more info about the whiteboard and its usage limitations.
|
||||
// limitUrl: 'https://example.com/blog/whiteboard-limits,
|
||||
// },
|
||||
|
||||
// The watchRTC initialize config params as described :
|
||||
|
||||
@@ -115,17 +115,18 @@ form {
|
||||
}
|
||||
|
||||
.leftwatermark {
|
||||
max-width: 140px;
|
||||
max-height:70px;
|
||||
left: 32px;
|
||||
top: 32px;
|
||||
background-position: center left;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.leftwatermarknomargin {
|
||||
background-position: center left;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
&.no-margin {
|
||||
left:0;
|
||||
top:0;
|
||||
}
|
||||
}
|
||||
|
||||
.rightwatermark {
|
||||
|
||||
@@ -61,6 +61,35 @@ body.welcome-page {
|
||||
|
||||
}
|
||||
|
||||
.not-allow-title-character-div {
|
||||
color: #f03e3e;
|
||||
background-color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
margin: 10px 0px 5px 0px;
|
||||
text-align: $welcomePageHeaderTextAlign;
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
.not-allow-title-character-text {
|
||||
float: right;
|
||||
line-height: 1.9;
|
||||
};
|
||||
.jitsi-icon {
|
||||
margin-right: 9px;
|
||||
float: left;
|
||||
|
||||
|
||||
svg {
|
||||
fill:#f03e3e;
|
||||
|
||||
& > *:first-child {
|
||||
fill: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.insecure-room-name-warning {
|
||||
align-items: center;
|
||||
color: rgb(215, 121, 118);
|
||||
@@ -231,11 +260,6 @@ body.welcome-page {
|
||||
width: $welcomePageWatermarkWidth;
|
||||
height: $welcomePageWatermarkHeight;
|
||||
}
|
||||
|
||||
.watermark.leftwatermarknomargin {
|
||||
width: $welcomePageWatermarkWidth;
|
||||
height: $welcomePageWatermarkHeight;
|
||||
}
|
||||
}
|
||||
|
||||
&.without-content {
|
||||
|
||||
1
debian/jitsi-meet-web.install
vendored
1
debian/jitsi-meet-web.install
vendored
@@ -1,6 +1,5 @@
|
||||
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
BIN
favicon.ico
Binary file not shown.
|
Before Width: | Height: | Size: 3.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
13
images/favicon.svg
Normal file
13
images/favicon.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 8.5 KiB |
13
ios/Podfile
13
ios/Podfile
@@ -6,8 +6,6 @@ workspace 'jitsi-meet'
|
||||
|
||||
install! 'cocoapods', :deterministic_uuids => false
|
||||
|
||||
production = ENV["PRODUCTION"] == "1"
|
||||
|
||||
target 'JitsiMeet' do
|
||||
project 'app/app.xcodeproj'
|
||||
|
||||
@@ -26,7 +24,6 @@ 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.
|
||||
@@ -56,24 +53,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)
|
||||
react_native_post_install(installer, :mac_catalyst_enabled => false)
|
||||
__apply_Xcode_12_5_M1_post_install_workaround(installer)
|
||||
installer.pods_project.targets.each do |target|
|
||||
# https://github.com/CocoaPods/CocoaPods/issues/11402
|
||||
|
||||
582
ios/Podfile.lock
582
ios/Podfile.lock
@@ -14,14 +14,14 @@ PODS:
|
||||
- CocoaLumberjack/Core (= 3.7.2)
|
||||
- CocoaLumberjack/Core (3.7.2)
|
||||
- DoubleConversion (1.1.6)
|
||||
- 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)
|
||||
- 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)
|
||||
- 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.2.5):
|
||||
- GoogleDataTransport (9.3.0):
|
||||
- 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.11.5):
|
||||
- GoogleUtilities/AppDelegateSwizzler (7.12.0):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Environment (7.11.5):
|
||||
- GoogleUtilities/Environment (7.12.0):
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- GoogleUtilities/Logger (7.11.5):
|
||||
- GoogleUtilities/Logger (7.12.0):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/MethodSwizzler (7.11.5):
|
||||
- GoogleUtilities/MethodSwizzler (7.12.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network (7.11.5):
|
||||
- GoogleUtilities/Network (7.12.0):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (7.11.5)"
|
||||
- GoogleUtilities/Reachability (7.11.5):
|
||||
- "GoogleUtilities/NSData+zlib (7.12.0)"
|
||||
- GoogleUtilities/Reachability (7.12.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/UserDefaults (7.11.5):
|
||||
- GoogleUtilities/UserDefaults (7.12.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GTMAppAuth (2.0.0):
|
||||
- AppAuth/Core (~> 1.6)
|
||||
- GTMSessionFetcher/Core (< 4.0, >= 1.5)
|
||||
- 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):
|
||||
- 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):
|
||||
- libwebp/webp
|
||||
- libwebp/mux (1.3.1):
|
||||
- libwebp/mux (1.3.2):
|
||||
- libwebp/demux
|
||||
- libwebp/sharpyuv (1.3.1)
|
||||
- libwebp/webp (1.3.1):
|
||||
- libwebp/sharpyuv (1.3.2)
|
||||
- libwebp/webp (1.3.2):
|
||||
- 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.06.28.00-v2):
|
||||
- RCT-Folly (2021.07.22.00):
|
||||
- boost
|
||||
- DoubleConversion
|
||||
- fmt (~> 6.2.1)
|
||||
- glog
|
||||
- RCT-Folly/Default (= 2021.06.28.00-v2)
|
||||
- RCT-Folly/Default (2021.06.28.00-v2):
|
||||
- RCT-Folly/Default (= 2021.07.22.00)
|
||||
- RCT-Folly/Default (2021.07.22.00):
|
||||
- boost
|
||||
- DoubleConversion
|
||||
- fmt (~> 6.2.1)
|
||||
- glog
|
||||
- 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):
|
||||
- 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):
|
||||
- glog
|
||||
- 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)
|
||||
- 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)
|
||||
- Yoga
|
||||
- React-Core/CoreModulesHeaders (0.69.12):
|
||||
- React-Core/CoreModulesHeaders (0.70.14):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.69.12)
|
||||
- React-jsi (= 0.69.12)
|
||||
- React-jsiexecutor (= 0.69.12)
|
||||
- React-perflogger (= 0.69.12)
|
||||
- React-cxxreact (= 0.70.14)
|
||||
- React-jsi (= 0.70.14)
|
||||
- React-jsiexecutor (= 0.70.14)
|
||||
- React-perflogger (= 0.70.14)
|
||||
- Yoga
|
||||
- React-Core/Default (0.69.12):
|
||||
- React-Core/Default (0.70.14):
|
||||
- glog
|
||||
- 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)
|
||||
- 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)
|
||||
- Yoga
|
||||
- React-Core/DevSupport (0.69.12):
|
||||
- React-Core/DevSupport (0.70.14):
|
||||
- glog
|
||||
- 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)
|
||||
- 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)
|
||||
- Yoga
|
||||
- React-Core/RCTActionSheetHeaders (0.69.12):
|
||||
- React-Core/RCTActionSheetHeaders (0.70.14):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.69.12)
|
||||
- React-jsi (= 0.69.12)
|
||||
- React-jsiexecutor (= 0.69.12)
|
||||
- React-perflogger (= 0.69.12)
|
||||
- React-cxxreact (= 0.70.14)
|
||||
- React-jsi (= 0.70.14)
|
||||
- React-jsiexecutor (= 0.70.14)
|
||||
- React-perflogger (= 0.70.14)
|
||||
- Yoga
|
||||
- React-Core/RCTAnimationHeaders (0.69.12):
|
||||
- React-Core/RCTAnimationHeaders (0.70.14):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.69.12)
|
||||
- React-jsi (= 0.69.12)
|
||||
- React-jsiexecutor (= 0.69.12)
|
||||
- React-perflogger (= 0.69.12)
|
||||
- React-cxxreact (= 0.70.14)
|
||||
- React-jsi (= 0.70.14)
|
||||
- React-jsiexecutor (= 0.70.14)
|
||||
- React-perflogger (= 0.70.14)
|
||||
- Yoga
|
||||
- React-Core/RCTBlobHeaders (0.69.12):
|
||||
- React-Core/RCTBlobHeaders (0.70.14):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.69.12)
|
||||
- React-jsi (= 0.69.12)
|
||||
- React-jsiexecutor (= 0.69.12)
|
||||
- React-perflogger (= 0.69.12)
|
||||
- React-cxxreact (= 0.70.14)
|
||||
- React-jsi (= 0.70.14)
|
||||
- React-jsiexecutor (= 0.70.14)
|
||||
- React-perflogger (= 0.70.14)
|
||||
- Yoga
|
||||
- React-Core/RCTImageHeaders (0.69.12):
|
||||
- React-Core/RCTImageHeaders (0.70.14):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.69.12)
|
||||
- React-jsi (= 0.69.12)
|
||||
- React-jsiexecutor (= 0.69.12)
|
||||
- React-perflogger (= 0.69.12)
|
||||
- React-cxxreact (= 0.70.14)
|
||||
- React-jsi (= 0.70.14)
|
||||
- React-jsiexecutor (= 0.70.14)
|
||||
- React-perflogger (= 0.70.14)
|
||||
- Yoga
|
||||
- React-Core/RCTLinkingHeaders (0.69.12):
|
||||
- React-Core/RCTLinkingHeaders (0.70.14):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.69.12)
|
||||
- React-jsi (= 0.69.12)
|
||||
- React-jsiexecutor (= 0.69.12)
|
||||
- React-perflogger (= 0.69.12)
|
||||
- React-cxxreact (= 0.70.14)
|
||||
- React-jsi (= 0.70.14)
|
||||
- React-jsiexecutor (= 0.70.14)
|
||||
- React-perflogger (= 0.70.14)
|
||||
- Yoga
|
||||
- React-Core/RCTNetworkHeaders (0.69.12):
|
||||
- React-Core/RCTNetworkHeaders (0.70.14):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.69.12)
|
||||
- React-jsi (= 0.69.12)
|
||||
- React-jsiexecutor (= 0.69.12)
|
||||
- React-perflogger (= 0.69.12)
|
||||
- React-cxxreact (= 0.70.14)
|
||||
- React-jsi (= 0.70.14)
|
||||
- React-jsiexecutor (= 0.70.14)
|
||||
- React-perflogger (= 0.70.14)
|
||||
- Yoga
|
||||
- React-Core/RCTSettingsHeaders (0.69.12):
|
||||
- React-Core/RCTSettingsHeaders (0.70.14):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.69.12)
|
||||
- React-jsi (= 0.69.12)
|
||||
- React-jsiexecutor (= 0.69.12)
|
||||
- React-perflogger (= 0.69.12)
|
||||
- React-cxxreact (= 0.70.14)
|
||||
- React-jsi (= 0.70.14)
|
||||
- React-jsiexecutor (= 0.70.14)
|
||||
- React-perflogger (= 0.70.14)
|
||||
- Yoga
|
||||
- React-Core/RCTTextHeaders (0.69.12):
|
||||
- React-Core/RCTTextHeaders (0.70.14):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.69.12)
|
||||
- React-jsi (= 0.69.12)
|
||||
- React-jsiexecutor (= 0.69.12)
|
||||
- React-perflogger (= 0.69.12)
|
||||
- React-cxxreact (= 0.70.14)
|
||||
- React-jsi (= 0.70.14)
|
||||
- React-jsiexecutor (= 0.70.14)
|
||||
- React-perflogger (= 0.70.14)
|
||||
- Yoga
|
||||
- React-Core/RCTVibrationHeaders (0.69.12):
|
||||
- React-Core/RCTVibrationHeaders (0.70.14):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.69.12)
|
||||
- React-jsi (= 0.69.12)
|
||||
- React-jsiexecutor (= 0.69.12)
|
||||
- React-perflogger (= 0.69.12)
|
||||
- React-cxxreact (= 0.70.14)
|
||||
- React-jsi (= 0.70.14)
|
||||
- React-jsiexecutor (= 0.70.14)
|
||||
- React-perflogger (= 0.70.14)
|
||||
- Yoga
|
||||
- React-Core/RCTWebSocket (0.69.12):
|
||||
- React-Core/RCTWebSocket (0.70.14):
|
||||
- glog
|
||||
- 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)
|
||||
- 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)
|
||||
- Yoga
|
||||
- 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):
|
||||
- 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):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- 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):
|
||||
- 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):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-jsi/Default (= 0.69.12)
|
||||
- React-jsi/Default (0.69.12):
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-jsi/Default (= 0.70.14)
|
||||
- React-jsi/Default (0.70.14):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-jsiexecutor (0.69.12):
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-jsiexecutor (0.70.14):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- 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):
|
||||
- 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):
|
||||
- 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 (9.4.1):
|
||||
- react-native-netinfo (11.1.0):
|
||||
- React-Core
|
||||
- react-native-orientation-locker (1.5.0):
|
||||
- react-native-orientation-locker (1.6.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 (111.0.3):
|
||||
- JitsiWebRTC (~> 111.0.0)
|
||||
- react-native-webrtc (118.0.0):
|
||||
- JitsiWebRTC (~> 118.0.0)
|
||||
- React-Core
|
||||
- react-native-webview (13.5.1):
|
||||
- React-Core
|
||||
- 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):
|
||||
- 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):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- 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)
|
||||
- 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)
|
||||
- RNCalendarEvents (2.2.0):
|
||||
- React
|
||||
- RNCAsyncStorage (1.19.3):
|
||||
- RNCAsyncStorage (1.19.4):
|
||||
- React-Core
|
||||
- RNCClipboard (1.5.1):
|
||||
- React-Core
|
||||
@@ -474,7 +474,7 @@ PODS:
|
||||
- React-Core
|
||||
- RNGestureHandler (2.9.0):
|
||||
- React-Core
|
||||
- RNGoogleSignin (10.0.1):
|
||||
- RNGoogleSignin (10.1.0):
|
||||
- GoogleSignIn (~> 7.0)
|
||||
- React-Core
|
||||
- RNScreens (3.24.0):
|
||||
@@ -709,8 +709,8 @@ SPEC CHECKSUMS:
|
||||
boost: a7c83b31436843459a1961bfd74b96033dc77234
|
||||
CocoaLumberjack: b7e05132ff94f6ae4dfa9d5bce9141893a21d9da
|
||||
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
|
||||
FBLazyVector: 6fab494fa11340bd4206edaebed07279a6bafad4
|
||||
FBReactNativeSpec: 76d7b03876b0ad0b86bc5c84d23af8e64db8e096
|
||||
FBLazyVector: efad4471d02263013cfcb7a2f75de6ac7565692f
|
||||
FBReactNativeSpec: 9cd9542bfdcc64e07bc649f809dd621876f78619
|
||||
Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d
|
||||
FirebaseAnalytics: 7761cbadb00a717d8d0939363eb46041526474fa
|
||||
FirebaseCore: 5743c5785c074a794d35f2fff7ecc254a91e08b1
|
||||
@@ -721,71 +721,71 @@ SPEC CHECKSUMS:
|
||||
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
|
||||
Giphy: 6b5f6986c8df4f71e01a8ef86595f426b3439fb5
|
||||
giphy-react-native-sdk: fcda9639f8ca2cc47e0517b6ef11c19359db5f5a
|
||||
glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a
|
||||
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
|
||||
GoogleAppMeasurement: 4c19f031220c72464d460c9daa1fb5d1acce958e
|
||||
GoogleDataTransport: 54dee9d48d14580407f8f5fbf2f496e92437a2f2
|
||||
GoogleDataTransport: 57c22343ab29bc686febbf7cbb13bad167c2d8fe
|
||||
GoogleSignIn: b232380cf495a429b8095d3178a8d5855b42e842
|
||||
GoogleUtilities: 13e2c67ede716b8741c7989e26893d151b2b2084
|
||||
GoogleUtilities: 0759d1a57ebb953965c2dfe0ba4c82e95ccc2e34
|
||||
GTMAppAuth: 99fb010047ba3973b7026e45393f51f27ab965ae
|
||||
GTMSessionFetcher: e8647203b65cee28c5f73d0f473d096653945e72
|
||||
JitsiWebRTC: 80f62908fcf2a1160e0d14b584323fb6e6be630b
|
||||
libwebp: 33dc822fbbf4503668d09f7885bbfedc76c45e96
|
||||
GTMSessionFetcher: 41b9ef0b4c08a6db4b7eb51a21ae5183ec99a2c8
|
||||
JitsiWebRTC: 3a41671ef65a51d7204323814b055a2690b921c7
|
||||
libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009
|
||||
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
|
||||
ObjectiveDropboxOfficial: fe206ce8c0bc49976c249d472db7fdbc53ebbd53
|
||||
PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
|
||||
PromisesSwift: 28dca69a9c40779916ac2d6985a0192a5cb4a265
|
||||
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
|
||||
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
|
||||
react-native-background-timer: 17ea5e06803401a379ebf1f20505b793ac44d0fe
|
||||
react-native-get-random-values: dee677497c6a740b71e5612e8dbd83e7539ed5bb
|
||||
react-native-keep-awake: afad8a51dfef9fe9655a6344771be32c8596d774
|
||||
react-native-netinfo: fefd4e98d75cbdd6e85fc530f7111a8afdf2b0c5
|
||||
react-native-orientation-locker: 851f6510d8046ea2f14aa169b1e01fcd309a94ba
|
||||
react-native-netinfo: 3aa5637c18834966e0c932de8ae1ae56fea20a97
|
||||
react-native-orientation-locker: 4409c5b12b65f942e75449872b4f078b6f27af81
|
||||
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: 4d1669c2ed29767fe70b0169428b4466589ecf8b
|
||||
react-native-webrtc: c8d9ad3c152105b2720ca2851d04b49659551992
|
||||
react-native-webview: 8baa0f5c6d336d6ba488e942bcadea5bf51f050a
|
||||
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
|
||||
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
|
||||
RNCalendarEvents: 7e65eb4a94f53c1744d1e275f7fafcfaa619f7a3
|
||||
RNCAsyncStorage: c913ede1fa163a71cea118ed4670bbaaa4b511bb
|
||||
RNCAsyncStorage: 3a8f7145d17cdd9f88e7b77666c94a09e4f759c8
|
||||
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
|
||||
RNDefaultPreference: 08bdb06cfa9188d5da97d4642dac745218d7fb31
|
||||
RNDeviceInfo: 02ea8b23e2280fa18e00a06d7e62804d74028579
|
||||
RNGestureHandler: 071d7a9ad81e8b83fe7663b303d132406a7d8f39
|
||||
RNGoogleSignin: ccaa4a81582cf713eea562c5dd9dc1961a715fd0
|
||||
RNGoogleSignin: a6a612cce56a45ab701c5c5c6e36f5390522d100
|
||||
RNScreens: b21dc57dfa2b710c30ec600786a3fc223b1b92e7
|
||||
RNSound: 6c156f925295bdc83e8e422e7d8b38d33bc71852
|
||||
RNSVG: ed492aaf3af9ca01bc945f7a149d76d62e73ec82
|
||||
RNWatch: fd30ca40a5b5ef58dcbc195638e68219bc455236
|
||||
Yoga: 8a90b50af67eaa9fe94fd03e550bfeab06096873
|
||||
Yoga: 56413d530d1808044600320ced5baa883acedc44
|
||||
|
||||
PODFILE CHECKSUM: 90720aee51cf2cab2e12611a28dbf55a688e969c
|
||||
PODFILE CHECKSUM: c5053669414ca81c03ca4548249b11fe53a13060
|
||||
|
||||
COCOAPODS: 1.12.1
|
||||
COCOAPODS: 1.14.3
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 52;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -862,7 +862,6 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -892,7 +891,6 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -978,7 +976,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -1013,6 +1011,7 @@
|
||||
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;
|
||||
@@ -1028,6 +1027,10 @@
|
||||
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";
|
||||
@@ -1039,7 +1042,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -1069,6 +1072,10 @@
|
||||
"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;
|
||||
@@ -1081,6 +1088,10 @@
|
||||
);
|
||||
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;
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
[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];
|
||||
@@ -126,7 +125,7 @@
|
||||
|
||||
- (UIInterfaceOrientationMask)application:(UIApplication *)application
|
||||
supportedInterfaceOrientationsForWindow:(UIWindow *)window {
|
||||
return [[JitsiMeet sharedInstance] application:application
|
||||
return [[JitsiMeet sharedInstance] application:application
|
||||
supportedInterfaceOrientationsForWindow:window];
|
||||
}
|
||||
|
||||
|
||||
@@ -728,7 +728,7 @@
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -766,6 +766,7 @@
|
||||
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;
|
||||
@@ -776,6 +777,10 @@
|
||||
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";
|
||||
@@ -791,7 +796,7 @@
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -824,6 +829,10 @@
|
||||
"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;
|
||||
@@ -832,6 +841,10 @@
|
||||
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;
|
||||
|
||||
@@ -419,6 +419,7 @@
|
||||
"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.",
|
||||
|
||||
@@ -778,7 +778,7 @@
|
||||
"moreModerationControls": "Más controles de moderación",
|
||||
"moreParticipantOptions": "Más opciones de participantes",
|
||||
"mute": "Silenciar",
|
||||
"muteAll": "Silenciar a todos los demás",
|
||||
"muteAll": "Silenciar a todos",
|
||||
"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",
|
||||
"domuteOthers": "Silenciar a todos los demás",
|
||||
"domuteVideo": "Desactivar la cámara",
|
||||
"domuteVideoOfOthers": "Desactivar la cámara de todos los demás",
|
||||
"flip": "Voltear",
|
||||
|
||||
1226
lang/main-lv.json
1226
lang/main-lv.json
File diff suppressed because it is too large
Load Diff
@@ -67,13 +67,18 @@
|
||||
"renameBreakoutRoom": "Renomear sala",
|
||||
"sendToBreakoutRoom": "Enviar participante para:"
|
||||
},
|
||||
"breakoutList": "lista de salas",
|
||||
"buttonLabel": "Salas simultâneas",
|
||||
"defaultName": "Sala #{{index}}",
|
||||
"hideParticipantList": "Ocultar lista de participantes",
|
||||
"mainRoom": "Sala principal",
|
||||
"notifications": {
|
||||
"joined": "Entrada na sala \"{{name}}\"",
|
||||
"joinedMainRoom": "Entrada na sala principal",
|
||||
"joinedTitle": "Salas simultâneas"
|
||||
}
|
||||
},
|
||||
"showParticipantList": "Mostrar lista de participantes",
|
||||
"title": "Salas simultâneas"
|
||||
},
|
||||
"calendarSync": {
|
||||
"addMeetingURL": "Adicionar um link da reunião",
|
||||
@@ -477,6 +482,10 @@
|
||||
"viewUpgradeOptions": "Ver opções de actualização",
|
||||
"viewUpgradeOptionsContent": "Para obter acesso ilimitado a funcionalidades premium como gravação, transcrições, RTMP Streaming & mais, terá de actualizar o seu plano.",
|
||||
"viewUpgradeOptionsTitle": "Descobriu uma característica premium!",
|
||||
"whiteboardLimitContent": "Lamentamos, mas o limite de utilizadores do quadro branco foi atingido.",
|
||||
"whiteboardLimitReference": "Para mais informações consultar",
|
||||
"whiteboardLimitReferenceUrl": "o nosso sítio Web",
|
||||
"whiteboardLimitTitle": "Restrição da utilização do quadro branco",
|
||||
"yourEntireScreen": "O seu ecrã inteiro"
|
||||
},
|
||||
"documentSharing": {
|
||||
@@ -724,6 +733,7 @@
|
||||
"dataChannelClosed": "Deficiência na qualidade do vídeo",
|
||||
"dataChannelClosedDescription": "O canal de ponte foi desconectado e, portanto, a qualidade do vídeo está limitada à sua configuração mais baixa.",
|
||||
"disabledIframe": "A incorporação destina-se apenas a fins de demonstração, pelo que esta chamada será desligada em {{timeout}} minutos.",
|
||||
"disabledIframeSecondary": "A incorporação de {{domain}} destina-se apenas a fins de demonstração, pelo que esta chamada será desligada em {{timeout}} minutos. Por favor, use <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi as a Service</a> para incorporação em produção!",
|
||||
"disconnected": "desconectado",
|
||||
"displayNotifications": "Mostrar notificações para",
|
||||
"dontRemindMe": "Não me lembre",
|
||||
@@ -799,7 +809,9 @@
|
||||
"videoUnmuteBlockedDescription": "A operação de ligar a câmara e partilhar o ambiente de trabalho foi temporariamente bloqueada devido aos limites do sistema.",
|
||||
"videoUnmuteBlockedTitle": "Está bloqueado ligar a câmara e partilhar o ambiente de trabalho!",
|
||||
"viewLobby": "Ver sala de espera",
|
||||
"waitingParticipants": "{{waitingParticipants}} pessoas"
|
||||
"waitingParticipants": "{{waitingParticipants}} pessoas",
|
||||
"whiteboardLimitDescription": "Guarde o seu progresso, pois o limite de utilizadores será atingido em breve e o quadro branco será encerrado.",
|
||||
"whiteboardLimitTitle": "Utilização do quadro branco"
|
||||
},
|
||||
"participantsPane": {
|
||||
"actions": {
|
||||
@@ -808,6 +820,7 @@
|
||||
"askUnmute": "Pedir para ligar o som",
|
||||
"audioModeration": "Ligar o microfone deles",
|
||||
"blockEveryoneMicCamera": "Bloquear o microfone e a câmara de todos",
|
||||
"breakoutRooms": "Salas simultâneas",
|
||||
"invite": "Convidar alguém",
|
||||
"moreModerationActions": "Mais opções de moderação",
|
||||
"moreModerationControls": "Mais controlos de moderação",
|
||||
@@ -1154,7 +1167,7 @@
|
||||
"audioOnly": "Mudar para apenas áudio",
|
||||
"audioRoute": "Selecionar o dispositivo de som",
|
||||
"boo": "Vaia",
|
||||
"breakoutRoom": "Entrar/Sair da sala",
|
||||
"breakoutRooms": "Salas simultâneas",
|
||||
"callQuality": "Gerir a qualidade do vídeo",
|
||||
"carmode": "Modo de condução",
|
||||
"cc": "Mudar legendas",
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"addPeople": {
|
||||
"accessibilityLabel": {
|
||||
"meetingLink": "Link da reunião: {{url}}"
|
||||
},
|
||||
"add": "Convidar",
|
||||
"addContacts": "Convide seus contatos",
|
||||
"contacts": "contatos",
|
||||
@@ -39,6 +42,18 @@
|
||||
"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",
|
||||
@@ -48,15 +63,22 @@
|
||||
"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",
|
||||
@@ -239,9 +261,12 @@
|
||||
"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"
|
||||
@@ -250,6 +275,8 @@
|
||||
"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",
|
||||
@@ -310,6 +337,7 @@
|
||||
"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!",
|
||||
@@ -353,8 +381,6 @@
|
||||
"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",
|
||||
@@ -371,6 +397,8 @@
|
||||
"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",
|
||||
@@ -389,9 +417,11 @@
|
||||
"sendPrivateMessageOk": "Enviar em privado",
|
||||
"sendPrivateMessageTitle": "Enviar em privado?",
|
||||
"serviceUnavailable": "Serviço indisponível",
|
||||
"sessTerminated": "Chamada terminada",
|
||||
"sessionRestarted": "Chamada reiniciada pelo bridge",
|
||||
"sessTerminated": "Chamada encerrada",
|
||||
"sessTerminatedReason": "A chamada foi encerrada",
|
||||
"sessionRestarted": "Chamada reiniciada devido a um erro de conexão.",
|
||||
"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\".",
|
||||
@@ -421,7 +451,25 @@
|
||||
"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",
|
||||
@@ -435,6 +483,10 @@
|
||||
"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": {
|
||||
@@ -447,6 +499,9 @@
|
||||
"title": "Reunião em formato compacto"
|
||||
},
|
||||
"feedback": {
|
||||
"accessibilityLabel": {
|
||||
"yourChoice": "Sua escolha: {{rating}}"
|
||||
},
|
||||
"average": "Média",
|
||||
"bad": "Ruim",
|
||||
"detailsLabel": "Nos conte mais sobre isso.",
|
||||
@@ -507,6 +562,7 @@
|
||||
"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"
|
||||
@@ -613,13 +669,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",
|
||||
@@ -651,9 +707,11 @@
|
||||
"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",
|
||||
"stop": "Parar a gravação",
|
||||
"stopping": "Parando a gravação",
|
||||
"wait": "Por favor aguarde enquanto salvamos sua gravação",
|
||||
"yes": "Sim"
|
||||
},
|
||||
"lockRoomPassword": "senha",
|
||||
@@ -676,6 +734,7 @@
|
||||
"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",
|
||||
@@ -722,7 +781,6 @@
|
||||
"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",
|
||||
@@ -752,7 +810,9 @@
|
||||
"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"
|
||||
"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"
|
||||
},
|
||||
"participantsPane": {
|
||||
"actions": {
|
||||
@@ -761,6 +821,7 @@
|
||||
"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",
|
||||
@@ -937,7 +998,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": "AOVIVO",
|
||||
"live": "AO VIVO",
|
||||
"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.",
|
||||
@@ -1037,6 +1098,7 @@
|
||||
"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",
|
||||
@@ -1047,12 +1109,14 @@
|
||||
"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",
|
||||
@@ -1104,7 +1168,7 @@
|
||||
"audioOnly": "Alternar para apenas áudio",
|
||||
"audioRoute": "Selecionar o dispositivo de som",
|
||||
"boo": "Vaia",
|
||||
"breakoutRoom": "Entrar/sair da sala de apoio",
|
||||
"breakoutRooms": "Entrar/sair da sala de apoio",
|
||||
"callQuality": "Gerenciar qualidade do vídeo",
|
||||
"carmode": "Modo carro",
|
||||
"cc": "Alternar legendas",
|
||||
@@ -1132,7 +1196,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",
|
||||
@@ -1173,7 +1237,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",
|
||||
@@ -1218,7 +1282,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",
|
||||
@@ -1266,7 +1330,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",
|
||||
@@ -1371,6 +1435,10 @@
|
||||
"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.",
|
||||
@@ -1457,7 +1525,7 @@
|
||||
},
|
||||
"whiteboard": {
|
||||
"accessibilityLabel": {
|
||||
"heading": "Quadro branco"
|
||||
"heading": "Quadro-branco"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,7 +391,7 @@
|
||||
"serviceUnavailable": "Tjänsten otillgänglig",
|
||||
"sessTerminated": "Konferensen avslutades",
|
||||
"sessionRestarted": "Samtal återstartat av bryggan",
|
||||
"shareAudio": "Forstätt",
|
||||
"shareAudio": "Fortsätt",
|
||||
"shareAudioTitle": "Hur man delar ljud",
|
||||
"shareAudioWarningD1": "Du måste avsluta din skärmdelning innan du kan dela ditt ljud",
|
||||
"shareAudioWarningD2": "Du måste starta om din skärmdelning och därefter klicka på \"ljuddelning\"",
|
||||
@@ -427,13 +427,13 @@
|
||||
"user": "Användare",
|
||||
"userIdentifier": "Användar-ID",
|
||||
"userPassword": "Lösenord",
|
||||
"verifyParticipantConfirm": "Dem matchar",
|
||||
"verifyParticipantDismiss": "Dem matchar inte",
|
||||
"verifyParticipantConfirm": "De matchar",
|
||||
"verifyParticipantDismiss": "De matchar inte",
|
||||
"verifyParticipantQuestion": "EXPERIMENTELLT: Fråga deltagaren; {{participantName}} om han/hon kan se samma innehåll, i samma ordning.",
|
||||
"verifyParticipantTitle": "Användarverifikation",
|
||||
"videoLink": "Videolänk",
|
||||
"viewUpgradeOptions": "Se uppgraderings alternativ",
|
||||
"viewUpgradeOptionsContent": "För att få obegränsad tillgång till premiumfunktioner som inspelning, transkriptioner, RTMP -streaming och mer måste du uppgradera din plan.",
|
||||
"viewUpgradeOptionsContent": "För att få obegränsad tillgång till premiumfunktioner som inspelning, transkriptioner, RTMP-streaming och mer måste du uppgradera din plan.",
|
||||
"viewUpgradeOptionsTitle": "Du upptäckte en premiumfunktion!",
|
||||
"yourEntireScreen": "Helskärm"
|
||||
},
|
||||
@@ -458,7 +458,7 @@
|
||||
},
|
||||
"filmstrip": {
|
||||
"accessibilityLabel": {
|
||||
"heading": "Videomineatyrer"
|
||||
"heading": "Videominiatyrer"
|
||||
}
|
||||
},
|
||||
"giphy": {
|
||||
@@ -1278,7 +1278,7 @@
|
||||
"tileViewToggle": "Öppna eller stäng panelvyn",
|
||||
"toggleCamera": "Byta kamera",
|
||||
"unmute": "Slå på ljud",
|
||||
"videoSettings": "Video inställningar",
|
||||
"videoSettings": "Videoinställningar",
|
||||
"videomute": "Inaktivera kameran",
|
||||
"videounmute": "Aktivera kameran"
|
||||
},
|
||||
@@ -1346,9 +1346,9 @@
|
||||
"videothumbnail": {
|
||||
"connectionInfo": "Anslutningsinformation",
|
||||
"domute": "Tysta",
|
||||
"domuteOthers": "Inkativerad ljud för alla andra",
|
||||
"domuteOthers": "Inaktivera ljud för alla andra",
|
||||
"domuteVideo": "Inaktivera kamera",
|
||||
"domuteVideoOfOthers": "Inkativera kamera för alla andra",
|
||||
"domuteVideoOfOthers": "Inaktivera kamera för alla andra",
|
||||
"flip": "Vänd",
|
||||
"grantModerator": "Godkänn moderator",
|
||||
"hideSelfView": "Dölj självvyn",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"addPeople": {
|
||||
"accessibilityLabel": {
|
||||
"meetingLink": "會議連結: {{url}}"
|
||||
"meetingLink": "會議連結:{{url}}"
|
||||
},
|
||||
"add": "邀請",
|
||||
"addContacts": "邀請您的聯絡人",
|
||||
@@ -16,7 +16,7 @@
|
||||
"failedToAdd": "加入與會者失敗",
|
||||
"googleEmail": "Google Email",
|
||||
"inviteMoreHeader": "目前只有您一個人在會議中",
|
||||
"inviteMoreMailSubject": "加入{{appName}}會議",
|
||||
"inviteMoreMailSubject": "加入 {{appName}} 會議",
|
||||
"inviteMorePrompt": "邀請更多人",
|
||||
"linkCopied": "已將連結複製至剪貼簿",
|
||||
"noResults": "沒有符合的搜尋結果",
|
||||
@@ -29,7 +29,7 @@
|
||||
"sipAddresses": "SIP 位址",
|
||||
"telephone": "電話號碼:{{number}}",
|
||||
"title": "邀請他人至會議",
|
||||
"yahooEmail": "Yahoo! Email"
|
||||
"yahooEmail": "Yahoo Email"
|
||||
},
|
||||
"audioDevices": {
|
||||
"bluetooth": "藍牙",
|
||||
@@ -56,24 +56,29 @@
|
||||
},
|
||||
"breakoutRooms": {
|
||||
"actions": {
|
||||
"add": "新增討論室",
|
||||
"autoAssign": "自動分配至討論室",
|
||||
"add": "新增分組討論室",
|
||||
"autoAssign": "自動分配至分組討論室",
|
||||
"close": "關閉",
|
||||
"join": "加入",
|
||||
"leaveBreakoutRoom": "離開討論室",
|
||||
"leaveBreakoutRoom": "離開分組討論室",
|
||||
"more": "更多",
|
||||
"remove": "移除",
|
||||
"rename": "重新命名",
|
||||
"renameBreakoutRoom": "重新命名討論室",
|
||||
"renameBreakoutRoom": "重新命名分組討論室",
|
||||
"sendToBreakoutRoom": "將與會者移至:"
|
||||
},
|
||||
"breakoutList": "分組討論室列表",
|
||||
"buttonLabel": "分組討論室",
|
||||
"defaultName": "分組討論室 #{{index}}",
|
||||
"hideParticipantList": "隱藏與會者列表",
|
||||
"mainRoom": "主會議室",
|
||||
"notifications": {
|
||||
"joined": "正在加入「{{name}}」分組討論室",
|
||||
"joinedMainRoom": "正在加入主會議室",
|
||||
"joinedTitle": "分組討論室"
|
||||
}
|
||||
},
|
||||
"showParticipantList": "顯示與會者列表",
|
||||
"title": "分組討論室"
|
||||
},
|
||||
"calendarSync": {
|
||||
"addMeetingURL": "增加會議連結",
|
||||
@@ -107,11 +112,11 @@
|
||||
"enter": "加入聊天室",
|
||||
"error": "錯誤:您的訊息未被傳送。原因:{{error}}",
|
||||
"fieldPlaceHolder": "在此輸入您的訊息",
|
||||
"lobbyChatMessageTo": "大廳聊天訊息傳送至{{recipient}}",
|
||||
"lobbyChatMessageTo": "大廳聊天訊息傳送至 {{recipient}}",
|
||||
"message": "訊息",
|
||||
"messageAccessibleTitle": "{{user}}:",
|
||||
"messageAccessibleTitleMe": "說:",
|
||||
"messageTo": "傳送私人訊息至{{recipient}}",
|
||||
"messageAccessibleTitleMe": "我:",
|
||||
"messageTo": "傳送私人訊息至 {{recipient}}",
|
||||
"messagebox": "輸入訊息",
|
||||
"newMessages": "新訊息",
|
||||
"nickname": {
|
||||
@@ -120,7 +125,7 @@
|
||||
"titleWithPolls": "輸入名稱來使用聊天與投票"
|
||||
},
|
||||
"noMessagesMessage": "此會議尚無訊息,在此開始對話聊天!",
|
||||
"privateNotice": "傳送私人訊息至{{recipient}}",
|
||||
"privateNotice": "傳送私人訊息至 {{recipient}}",
|
||||
"sendButton": "傳送",
|
||||
"smileysPanel": "Emoji 面板",
|
||||
"tabs": {
|
||||
@@ -133,7 +138,7 @@
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
"buttonText": "安裝 Chrome 擴充功能",
|
||||
"buttonTextEdge": "安裝 Edge 外掛程式",
|
||||
"buttonTextEdge": "安裝 Edge 擴充功能",
|
||||
"close": "關閉",
|
||||
"dontShowAgain": "不要再問了",
|
||||
"installExtensionText": "安裝適用於 Google 行事曆及 Office 365 整合的擴充功能"
|
||||
@@ -151,14 +156,14 @@
|
||||
"DISCONNECTED": "已斷線",
|
||||
"DISCONNECTING": "中斷連接中",
|
||||
"ERROR": "錯誤",
|
||||
"FETCH_SESSION_ID": "正在取得工作階段ID...",
|
||||
"GET_SESSION_ID_ERROR": "取得工作階段ID時發生錯誤:{{code}}",
|
||||
"GOT_SESSION_ID": "正在取得工作階段ID...完成",
|
||||
"LOW_BANDWIDTH": "已關閉{{displayName}}的視訊以節省流量"
|
||||
"FETCH_SESSION_ID": "正在取得工作階段 ID...",
|
||||
"GET_SESSION_ID_ERROR": "取得工作階段 ID 時發生錯誤:{{code}}",
|
||||
"GOT_SESSION_ID": "正在取得工作階段 ID... 完成",
|
||||
"LOW_BANDWIDTH": "已關閉 {{displayName}} 的視訊以節省頻寬"
|
||||
},
|
||||
"connectionindicator": {
|
||||
"address": "位址:",
|
||||
"audio_ssrc": "音訊SSRC:",
|
||||
"audio_ssrc": "音訊 SSRC:",
|
||||
"bandwidth": "預估頻寬:",
|
||||
"bitrate": "連線速率:",
|
||||
"bridgeCount": "伺服器數量:",
|
||||
@@ -175,7 +180,7 @@
|
||||
"more": "顯示更多",
|
||||
"no": "否",
|
||||
"packetloss": "封包遺失率:",
|
||||
"participant_id": "與會者ID:",
|
||||
"participant_id": "與會者 ID:",
|
||||
"quality": {
|
||||
"good": "良好",
|
||||
"inactive": "閒置",
|
||||
@@ -192,7 +197,7 @@
|
||||
"status": "連線狀態:",
|
||||
"transport": "傳輸協定:",
|
||||
"transport_plural": "傳輸:",
|
||||
"video_ssrc": "視訊SSRC:",
|
||||
"video_ssrc": "視訊 SSRC:",
|
||||
"yes": "是"
|
||||
},
|
||||
"dateUtils": {
|
||||
@@ -201,33 +206,33 @@
|
||||
"yesterday": "昨天"
|
||||
},
|
||||
"deepLinking": {
|
||||
"appNotInstalled": "您需要在手機上安裝{{app}}行動應用程式才能加入這場會議。",
|
||||
"description": "什麼事情都沒發生?我們已嘗試在您的{{app}}桌面應用程式開啟會議。請再試一次,或是在{{app}}網路應用程式開啟會議。",
|
||||
"descriptionNew": "什麼事情都沒發生?我們已嘗試在您的{{app}}桌面應用程式開啟會議。<br /><br />您可以再試一次,或在網頁上啟動。",
|
||||
"descriptionWithoutWeb": "什麼事情都沒發生?我們已試著將您的會議在桌面應用程式{{app}}中啟動。",
|
||||
"downloadApp": "下載App",
|
||||
"downloadMobileApp": "從App Store下載",
|
||||
"ifDoNotHaveApp": "如果您尚未安裝App:",
|
||||
"ifHaveApp": "如果您已經安裝此App:",
|
||||
"joinInApp": "使用App加入會議",
|
||||
"joinInAppNew": "在APP中加入",
|
||||
"appNotInstalled": "您需要在手機上安裝 {{app}} 應用程式才能加入這場會議。",
|
||||
"description": "什麼事情都沒發生?我們已嘗試在您的 {{app}} 桌面應用程式開啟會議。請再試一次,或是在 {{app}} 網頁應用程式開啟會議。",
|
||||
"descriptionNew": "什麼事情都沒發生?我們已嘗試在您的 {{app}} 桌面應用程式開啟會議。<br /><br />您可以再試一次,或在網頁上啟動。",
|
||||
"descriptionWithoutWeb": "什麼事情都沒發生?我們已試著將您的會議在桌面應用程式 {{app}} 中啟動。",
|
||||
"downloadApp": "下載應用程式",
|
||||
"downloadMobileApp": "從 App Store 下載",
|
||||
"ifDoNotHaveApp": "如果您尚未安裝應用程式:",
|
||||
"ifHaveApp": "如果您已經安裝應用程式:",
|
||||
"joinInApp": "使用應用程式加入會議",
|
||||
"joinInAppNew": "在應用程式中加入",
|
||||
"joinInBrowser": "在瀏覽器中加入",
|
||||
"launchMeetingLabel": "您想如何加入此會議?",
|
||||
"launchWebButton": "在瀏覽器開啟",
|
||||
"noMobileApp": "您尚未安裝該APP?",
|
||||
"noMobileApp": "您尚未安裝該應用程式?",
|
||||
"termsAndConditions": "繼續操作即表示您同意我們的<a href='{{termsAndConditionsLink}}' rel='noopener noreferrer' target='_blank'>條款與條件。</a>",
|
||||
"title": "正在{{app}}發起您的會議...",
|
||||
"titleNew": "正在啟動您的會議...",
|
||||
"title": "正在 {{app}} 開啟您的會議...",
|
||||
"titleNew": "正在開啟您的會議...",
|
||||
"tryAgainButton": "在桌面上再試一次",
|
||||
"unsupportedBrowser": "您似乎正在使用我們不支援的瀏覽器"
|
||||
"unsupportedBrowser": "您似乎正在使用我們不支援的瀏覽器。"
|
||||
},
|
||||
"defaultLink": "例如{{url}}",
|
||||
"defaultNickname": "例如:Jane Pink",
|
||||
"defaultLink": "例如 {{url}}",
|
||||
"defaultNickname": "例如:王小明",
|
||||
"deviceError": {
|
||||
"cameraError": "無法存取您的網路攝影機",
|
||||
"cameraPermission": "獲取網路攝影機權限時發生錯誤",
|
||||
"cameraPermission": "取得網路攝影機權限時發生錯誤",
|
||||
"microphoneError": "無法存取您的麥克風",
|
||||
"microphonePermission": "獲取麥克風權限時發生錯誤"
|
||||
"microphonePermission": "取得麥克風權限時發生錯誤"
|
||||
},
|
||||
"deviceSelection": {
|
||||
"hid": {
|
||||
@@ -239,13 +244,13 @@
|
||||
"noPermission": "未取得權限",
|
||||
"previewUnavailable": "無法預覽",
|
||||
"selectADevice": "選擇裝置",
|
||||
"testAudio": "播放測試聲音"
|
||||
"testAudio": "測試"
|
||||
},
|
||||
"dialIn": {
|
||||
"screenTitle": "通話記錄"
|
||||
},
|
||||
"dialOut": {
|
||||
"statusMessage": "現在狀態為{{status}}"
|
||||
"statusMessage": "現在狀態為 {{status}}"
|
||||
},
|
||||
"dialog": {
|
||||
"Back": "返回",
|
||||
@@ -256,6 +261,7 @@
|
||||
"Share": "分享",
|
||||
"Submit": "送出",
|
||||
"WaitForHostMsg": "此會議尚未開始,如果您是會議主持人,請進行認證並以主持人身分開始會議。",
|
||||
"WaitingForHostButton": "等待主持人",
|
||||
"WaitingForHostTitle": "正在等候主持人加入...",
|
||||
"Yes": "是",
|
||||
"accessibilityLabel": {
|
||||
@@ -269,6 +275,8 @@
|
||||
"addMeetingNote": "新增此會議的備註",
|
||||
"addOptionalNote": "新增備註(選填):",
|
||||
"allow": "允許",
|
||||
"allowToggleCameraDialog": "您要允許 {{initiatorName}} 切換您的鏡頭朝向嗎?",
|
||||
"allowToggleCameraTitle": "要允許切換鏡頭嗎?",
|
||||
"alreadySharedVideoMsg": "其他與會者正在分享影像,同一時間只有一個與會者可以分享影像螢幕。",
|
||||
"alreadySharedVideoTitle": "同一時間只允許一位影像分享",
|
||||
"applicationWindow": "應用程式視窗",
|
||||
@@ -277,14 +285,14 @@
|
||||
"cameraNotFoundError": "找不到網路攝影機。",
|
||||
"cameraNotSendingData": "我們無法存取您的網路攝影機,請檢查是否有其他應用程式正在使用這個裝置,並從裝置選單裡選擇其他設備或者重新載入。",
|
||||
"cameraNotSendingDataTitle": "無法存取網路攝影機",
|
||||
"cameraPermissionDeniedError": "未取得網路攝影機的存取權,您仍可參加會議,但其他人無法看到你。按一下網址列中的「攝影機」圖示 ,然後選取「一律允許」選項。",
|
||||
"cameraPermissionDeniedError": "未取得網路攝影機的存取權,您仍可參加會議,但其他人無法看到您。按一下網址列中的「攝影機」圖示 ,然後選取「一律允許」選項。",
|
||||
"cameraTimeoutError": "無法啟動視訊裝置,連線逾時!",
|
||||
"cameraUnknownError": "由於不明原因,無法存取網路攝影機。",
|
||||
"cameraUnsupportedResolutionError": "您的網路攝影機不支援所需的影像解析度。",
|
||||
"close": "關閉",
|
||||
"conferenceDisconnectMsg": "請檢查一下網路連線,將在{{seconds}}秒後重新連接...",
|
||||
"conferenceDisconnectMsg": "請檢查一下網路連線,將在 {{seconds}} 秒後重新連接...",
|
||||
"conferenceDisconnectTitle": "您已經被中斷連接。",
|
||||
"conferenceReloadMsg": "我們正試著修復狀況,將在{{seconds}}秒後重新連接...",
|
||||
"conferenceReloadMsg": "我們正試著修復狀況,將在 {{seconds}} 秒後重新連接...",
|
||||
"conferenceReloadTitle": "喔哦!好像有東西壞掉囉。",
|
||||
"confirm": "確認",
|
||||
"confirmNo": "否",
|
||||
@@ -298,7 +306,7 @@
|
||||
"dismiss": "取消",
|
||||
"displayNameRequired": "嗨!請問大名?",
|
||||
"done": "完成",
|
||||
"e2eeDescription": "請注意,端對端加密目前是實驗性功能,啟用端對端加密將停用部分伺服器端提供的服務,例如:透過電話加入會議。另外,透過網頁版加入會議還需要使用支援Insertable Streams的瀏覽器。",
|
||||
"e2eeDescription": "請注意,端對端加密目前是實驗性功能,啟用端對端加密將停用部分伺服器端提供的服務,例如:透過電話加入會議。另外,透過網頁版加入會議還需要使用支援 Insertable Streams 的瀏覽器。",
|
||||
"e2eeDisabledDueToMaxModeDescription": "由於會議中的人數過多,故無法啟用端對端加密。",
|
||||
"e2eeLabel": "啟用端對端加密",
|
||||
"e2eeWarning": "警告:看來此會議中不是每位與會者都啟用了端對端加密,如果您啟用了,他們可能無法看或聽到您。",
|
||||
@@ -307,7 +315,7 @@
|
||||
"enterDisplayName": "請在此輸入您自己的名字",
|
||||
"error": "錯誤",
|
||||
"gracefulShutdown": "服務目前正在維護中,請稍後再試。",
|
||||
"grantModeratorDialog": "您確定要授予{{participantName}}主持人權限嗎?",
|
||||
"grantModeratorDialog": "您確定要授予 {{participantName}} 主持人權限嗎?",
|
||||
"grantModeratorTitle": "授予主持人權限",
|
||||
"hide": "隱藏",
|
||||
"hideShareAudioHelper": "不再顯示",
|
||||
@@ -315,16 +323,16 @@
|
||||
"incorrectRoomLockPassword": "密碼不符",
|
||||
"internalError": "喔哦!出現了點問題,發生錯誤:{{error}}",
|
||||
"internalErrorTitle": "內部錯誤",
|
||||
"kickMessage": "您可以聯絡{{participantDisplayName}}取得更詳細資訊。",
|
||||
"kickMessage": "您可以聯絡 {{participantDisplayName}} 取得更詳細資訊。",
|
||||
"kickParticipantButton": "移除",
|
||||
"kickParticipantDialog": "您確定要將這位與會者移除嗎?",
|
||||
"kickParticipantTitle": "移除這位與會者?",
|
||||
"kickTitle": "噢!{{participantDisplayName}}將您從會議中移除",
|
||||
"kickTitle": "噢!{{participantDisplayName}} 將您從會議中移除",
|
||||
"linkMeeting": "連結會議",
|
||||
"linkMeetingTitle": "將會議連結至 Salesforce",
|
||||
"liveStreaming": "直播串流中",
|
||||
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "正在錄製,無法使用",
|
||||
"localUserControls": "本地使用者控制",
|
||||
"localUserControls": "本機使用者控制",
|
||||
"lockMessage": "無法鎖定會議。",
|
||||
"lockRoom": "新增會議 $t(lockRoomPasswordUppercase)",
|
||||
"lockTitle": "鎖定失敗",
|
||||
@@ -346,9 +354,9 @@
|
||||
"muteEveryoneDialog": "與會者可以隨時解除自己的靜音狀態。",
|
||||
"muteEveryoneDialogModerationOn": "與會者可以隨時請求發言。",
|
||||
"muteEveryoneElseDialog": "靜音後,您就不能再解除對方的靜音,但對方可以隨時解除自己的靜音狀態。",
|
||||
"muteEveryoneElseTitle": "是否要讓除了{{whom}}以外的人靜音?",
|
||||
"muteEveryoneElseTitle": "是否要讓除了 {{whom}} 以外的人靜音?",
|
||||
"muteEveryoneElsesVideoDialog": "一旦停用,您就不能再重新開啟對方的網路攝影機,但對方隨時能重新開啟自己的網路攝影機。",
|
||||
"muteEveryoneElsesVideoTitle": "是否要關閉除了{{whom}}以外的人的網路攝影機?",
|
||||
"muteEveryoneElsesVideoTitle": "是否要關閉除了 {{whom}} 以外的人的網路攝影機?",
|
||||
"muteEveryoneSelf": "您自己",
|
||||
"muteEveryoneStartMuted": "現在所有人皆已靜音",
|
||||
"muteEveryoneTitle": "要將所有人靜音嗎?",
|
||||
@@ -364,12 +372,12 @@
|
||||
"muteParticipantsVideoDialog": "確定要停用這位與會者的網路攝影機?您不能再重新開啟對方的網路攝影機,但他們隨時能重新開啟。",
|
||||
"muteParticipantsVideoDialogModerationOn": "您確定要關閉此與會者的網路攝影機嗎?您和他都無法再將視訊重新開啟。",
|
||||
"muteParticipantsVideoTitle": "要關閉此與會者的網路攝影機嗎?",
|
||||
"noDropboxToken": "沒有有效的 Dropbox token",
|
||||
"noDropboxToken": "沒有有效的 Dropbox 權杖",
|
||||
"password": "密碼",
|
||||
"passwordLabel": "會議已被一位與會者鎖定,請輸入$t(lockRoomPassword)以加入。",
|
||||
"passwordNotSupported": "尚未支援設定會議$t(lockRoomPassword)。",
|
||||
"passwordNotSupportedTitle": "尚未支援$t(lockRoomPasswordUppercase)",
|
||||
"passwordRequired": "需要$t(lockRoomPasswordUppercase)",
|
||||
"passwordLabel": "會議已被一位與會者鎖定,請輸入 $t(lockRoomPassword) 以加入。",
|
||||
"passwordNotSupported": "尚未支援設定會議 $t(lockRoomPassword)。",
|
||||
"passwordNotSupportedTitle": "尚未支援 $t(lockRoomPasswordUppercase)",
|
||||
"passwordRequired": "需要 $t(lockRoomPasswordUppercase)",
|
||||
"permissionCameraRequiredError": "參與視訊會議需要存取網路攝影機,請在設定中啟用權限",
|
||||
"permissionErrorTitle": "需要權限",
|
||||
"permissionMicRequiredError": "參與音訊會議需要存取麥克風,請在設定中啟用權限",
|
||||
@@ -378,19 +386,19 @@
|
||||
"recording": "錄製中",
|
||||
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "正在直播時無法使用",
|
||||
"rejoinNow": "立即重新加入",
|
||||
"remoteControlAllowedMessage": "{{user}}接受您進行遠端控制的請求!",
|
||||
"remoteControlDeniedMessage": "{{user}}拒絕您進行遠端控制的請求!",
|
||||
"remoteControlErrorMessage": "在嘗試向{{user}}請求遠端控制權限時發生錯誤!",
|
||||
"remoteControlRequestMessage": "您要允許{{user}}遠端控制您的桌面嗎?",
|
||||
"remoteControlAllowedMessage": "{{user}} 接受您進行遠端控制的請求!",
|
||||
"remoteControlDeniedMessage": "{{user}} 拒絕您進行遠端控制的請求!",
|
||||
"remoteControlErrorMessage": "在嘗試向 {{user}} 請求遠端控制權限時發生錯誤!",
|
||||
"remoteControlRequestMessage": "您要允許 {{user}} 遠端控制您的桌面嗎?",
|
||||
"remoteControlShareScreenWarning": "請注意:如果按下「允許」您將會分享自己的螢幕!",
|
||||
"remoteControlStopMessage": "遠端控制會話已結束!",
|
||||
"remoteControlTitle": "遠端桌面控制",
|
||||
"remoteUserControls": "{{username}}的遠端使用者控制",
|
||||
"remoteUserControls": "{{username}} 的遠端使用者控制",
|
||||
"removePassword": "移除 $t(lockRoomPassword)",
|
||||
"removeSharedVideoMsg": "您確定要移除您分享的影像嗎?",
|
||||
"removeSharedVideoTitle": "移除分享的影像",
|
||||
"renameBreakoutRoomLabel": "討論室名稱",
|
||||
"renameBreakoutRoomTitle": "重新命名討論室",
|
||||
"renameBreakoutRoomLabel": "分組討論室名稱",
|
||||
"renameBreakoutRoomTitle": "重新命名分組討論室",
|
||||
"reservationError": "預約系統錯誤",
|
||||
"reservationErrorMsg": "錯誤代碼:{{code}},訊息:{{msg}}",
|
||||
"retry": "重試",
|
||||
@@ -410,6 +418,7 @@
|
||||
"sendPrivateMessageTitle": "私人回覆?",
|
||||
"serviceUnavailable": "服務無法使用",
|
||||
"sessTerminated": "通話已經終止",
|
||||
"sessTerminatedReason": "會議已經終止",
|
||||
"sessionRestarted": "通話因連線問題重新啟動。",
|
||||
"shareAudio": "繼續",
|
||||
"shareAudioTitle": "如何分享音訊",
|
||||
@@ -438,7 +447,7 @@
|
||||
"stopRecordingWarning": "確定要停用錄製嗎?",
|
||||
"stopStreamingWarning": "確定要停止直播串流嗎?",
|
||||
"streamKey": "直播串流金鑰",
|
||||
"thankYou": "感謝您使用{{appName}}!",
|
||||
"thankYou": "感謝您使用 {{appName}}!",
|
||||
"token": "token",
|
||||
"tokenAuthFailed": "抱歉,您未被允許加入這個通話。",
|
||||
"tokenAuthFailedReason": {
|
||||
@@ -450,29 +459,33 @@
|
||||
"featuresNotFound": "`context` 未在負載中找到。",
|
||||
"headerNotFound": "標頭缺失。",
|
||||
"issInvalid": "無效的`iss`值,應為`chat`。",
|
||||
"kidMismatch": "金鑰ID(kid)與子項不符。",
|
||||
"kidNotFound": "缺少金鑰ID(kid)。",
|
||||
"kidMismatch": "金鑰 ID(kid)與子項不符。",
|
||||
"kidNotFound": "缺少金鑰 ID(kid)。",
|
||||
"nbfFuture": "`nbf`值在未來。",
|
||||
"nbfInvalid": "無效的`nbf`值。",
|
||||
"payloadNotFound": "未找到負載。",
|
||||
"tokenExpired": "Token已過期。"
|
||||
"payloadNotFound": "負載缺失。",
|
||||
"tokenExpired": "權杖已過期。"
|
||||
},
|
||||
"tokenAuthFailedTitle": "驗證失敗",
|
||||
"tokenAuthFailedWithReasons": "抱歉,您無法參加這個通話,可能原因:{{reason}}",
|
||||
"tokenAuthUnsupported": "不支援的令牌位址。",
|
||||
"tokenAuthUnsupported": "不支援權杖網址。",
|
||||
"transcribing": "轉錄中",
|
||||
"unlockRoom": "移除會議 $t(lockRoomPassword)",
|
||||
"user": "使用者",
|
||||
"userIdentifier": "使用者ID",
|
||||
"userIdentifier": "使用者 ID",
|
||||
"userPassword": "使用者密碼",
|
||||
"verifyParticipantConfirm": "符合",
|
||||
"verifyParticipantDismiss": "不符合",
|
||||
"verifyParticipantQuestion": "實驗性功能:詢問與會者{{participantName}}是否以相同順序看到相同內容。",
|
||||
"verifyParticipantQuestion": "實驗性功能:詢問與會者 {{participantName}} 是否以相同順序看到相同內容。",
|
||||
"verifyParticipantTitle": "使用者驗證",
|
||||
"videoLink": "影片連結",
|
||||
"viewUpgradeOptions": "查看升級方案",
|
||||
"viewUpgradeOptionsContent": "若要不受限制地使用錄製、逐字稿、RTMP 串流等進階版功能,您需要升級您的方案。",
|
||||
"viewUpgradeOptionsTitle": "您找到了進階版功能!",
|
||||
"whiteboardLimitContent": "抱歉,已達到白板使用者限制。",
|
||||
"whiteboardLimitReference": "若要了解詳情,請前往",
|
||||
"whiteboardLimitReferenceUrl": "我們的網站",
|
||||
"whiteboardLimitTitle": "白板使用受限",
|
||||
"yourEntireScreen": "您的整個螢幕"
|
||||
},
|
||||
"documentSharing": {
|
||||
@@ -521,7 +534,7 @@
|
||||
"copyNumber": "複製號碼",
|
||||
"country": "國家",
|
||||
"dialANumber": "若要參加您的會議,請撥打以下其中一支號碼,然後輸入 PIN 碼。",
|
||||
"dialInConferenceID": "PIN碼:",
|
||||
"dialInConferenceID": "PIN 碼:",
|
||||
"dialInNotSupported": "抱歉,目前不支援電話撥入。",
|
||||
"dialInNumber": "撥入:",
|
||||
"dialInSummaryError": "目前解析撥入資訊錯誤,請稍後再試一次。",
|
||||
@@ -536,7 +549,7 @@
|
||||
"inviteTextiOSPersonal": "{{name}}邀請您加入會議。",
|
||||
"inviteTextiOSPhone": "若要透過電話加入,請使用此號碼:{{number}},,{{conferenceID}}#。如果您需要其他號碼,點擊此連結以檢視完整列表:{{didUrl}}。",
|
||||
"inviteURLFirstPartGeneral": "您受邀參加會議。",
|
||||
"inviteURLFirstPartPersonal": "{{name}}正在邀請您加入會議。\n",
|
||||
"inviteURLFirstPartPersonal": "{{name}} 正在邀請您加入會議。\n",
|
||||
"inviteURLSecondPart": "\n加入會議:\n{{url}}\n",
|
||||
"label": "撥入資訊",
|
||||
"liveStreamURL": "直播串流:",
|
||||
@@ -547,7 +560,8 @@
|
||||
"numbers": "撥入號碼",
|
||||
"password": "$t(lockRoomPasswordUppercase):",
|
||||
"reachedLimit": "您已達到您的方案上限",
|
||||
"sip": "SIP位址",
|
||||
"sip": "SIP 位址",
|
||||
"sipAudioOnly": "SIP 僅音訊位址",
|
||||
"title": "分享",
|
||||
"tooltip": "顯示此會議的連結及電話撥入號碼",
|
||||
"upgradeOptions": "請查看升級選項於"
|
||||
@@ -566,7 +580,7 @@
|
||||
"searchPlaceholder": "與會者或電話號碼",
|
||||
"send": "傳送"
|
||||
},
|
||||
"jitsiHome": "{{logo}}商標,首頁連結",
|
||||
"jitsiHome": "{{logo}} 商標,首頁連結",
|
||||
"keyboardShortcuts": {
|
||||
"focusLocal": "聚焦於自己的影像",
|
||||
"focusRemote": "聚焦於另一人的影像",
|
||||
@@ -594,11 +608,11 @@
|
||||
"busyTitle": "全部直播設備正在忙碌",
|
||||
"changeSignIn": "切換帳號",
|
||||
"choose": "選擇直播串流",
|
||||
"chooseCTA": "請選擇直播串流選項,您目前是以{{email}}身份登入。",
|
||||
"chooseCTA": "請選擇直播串流選項,您目前是以 {{email}} 身份登入。",
|
||||
"enterStreamKey": "在此輸入您的 YouTube 直播串流金鑰。",
|
||||
"error": "直播串流失敗,請重試。",
|
||||
"errorAPI": "在存取您的 YouTube 直播時發生問題,請重新登入。",
|
||||
"errorLiveStreamNotEnabled": "直播在{{email}}尚未啟用,請開啟直播串流或登入有啟用直播串流的帳號。",
|
||||
"errorLiveStreamNotEnabled": "直播在 {{email}} 尚未啟用,請開啟直播串流或登入有啟用直播串流的帳號。",
|
||||
"expandedOff": "直播已停用",
|
||||
"expandedOn": "會議目前正在 YouTube 上直播。",
|
||||
"expandedPending": "直播串流正被啟動...",
|
||||
@@ -607,12 +621,12 @@
|
||||
"googlePrivacyPolicy": "Google 隱私權政策",
|
||||
"inProgress": "正在錄製或直播",
|
||||
"invalidStreamKey": "直播串流金鑰可能不正確。",
|
||||
"limitNotificationDescriptionNative": "您的最大直播長度將被限制在{{limit}}分鐘,若要不受限的直播,請使用{{app}}。",
|
||||
"limitNotificationDescriptionWeb": "由於目前流量過大,您的最大直播長度將被限制在{{limit}}分鐘。若要不受限的直播,請使用<a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>。",
|
||||
"limitNotificationDescriptionNative": "您的最大直播長度將被限制在 {{limit}} 分鐘,若要不受限的直播,請使用 {{app}}。",
|
||||
"limitNotificationDescriptionWeb": "由於目前流量過大,您的最大直播長度將被限制在 {{limit}} 分鐘。若要不受限的直播,請使用 <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>。",
|
||||
"off": "直播串流已停用",
|
||||
"offBy": "{{name}}停用了直播串流",
|
||||
"offBy": "{{name}} 停用了直播串流",
|
||||
"on": "直播串流已啟動",
|
||||
"onBy": "{{name}}啟動了直播串流",
|
||||
"onBy": "{{name}} 啟動了直播串流",
|
||||
"pending": "啟動直播串流...",
|
||||
"serviceName": "直播串流服務",
|
||||
"sessionAlreadyActive": "已在錄製或直播此工作階段。",
|
||||
@@ -652,13 +666,13 @@
|
||||
"knockButton": "請求加入",
|
||||
"knockTitle": "有人想要加入會議",
|
||||
"knockingParticipantList": "請求加入的與會者名單",
|
||||
"lobbyChatStartedNotification": "{{moderator}}與{{attendee}}開始在大廳中聊天",
|
||||
"lobbyChatStartedTitle": "{{moderator}}與您開始在大廳中聊天。",
|
||||
"lobbyChatStartedNotification": "{{moderator}} 與 {{attendee}} 開始在大廳中聊天",
|
||||
"lobbyChatStartedTitle": "{{moderator}} 與您開始在大廳中聊天。",
|
||||
"nameField": "輸入您的名字",
|
||||
"notificationLobbyAccessDenied": "{{originParticipantName}}拒絕了{{targetParticipantName}}的加入請求",
|
||||
"notificationLobbyAccessGranted": "{{originParticipantName}}同意了{{targetParticipantName}}的加入請求",
|
||||
"notificationLobbyDisabled": "{{originParticipantName}}已停用大廳模式",
|
||||
"notificationLobbyEnabled": "{{originParticipantName}}已啟用大廳模式",
|
||||
"notificationLobbyAccessDenied": "{{originParticipantName}} 拒絕了 {{targetParticipantName}} 的加入請求",
|
||||
"notificationLobbyAccessGranted": "{{originParticipantName}} 同意了 {{targetParticipantName}} 的加入請求",
|
||||
"notificationLobbyDisabled": "{{originParticipantName}} 已停用大廳模式",
|
||||
"notificationLobbyEnabled": "{{originParticipantName}} 已啟用大廳模式",
|
||||
"notificationTitle": "大廳",
|
||||
"passwordField": "輸入會議密碼",
|
||||
"passwordJoinButton": "加入",
|
||||
@@ -673,19 +687,19 @@
|
||||
"on": "開啟",
|
||||
"unknown": "未知"
|
||||
},
|
||||
"dialogTitle": "本地錄製控制",
|
||||
"dialogTitle": "本機錄製控制",
|
||||
"duration": "時長",
|
||||
"durationNA": "不適用",
|
||||
"encoding": "編碼中",
|
||||
"label": "本地錄製",
|
||||
"labelToolTip": "本地錄製已啟用",
|
||||
"localRecording": "本地錄製中",
|
||||
"label": "本機錄製",
|
||||
"labelToolTip": "本機錄製已啟用",
|
||||
"localRecording": "本機錄製中",
|
||||
"me": "我",
|
||||
"messages": {
|
||||
"engaged": "已啟用本地錄製。",
|
||||
"engaged": "已啟用本機錄製。",
|
||||
"finished": "錄製會話 {{token}} 已結束,請將傳送錄製檔案至主持人。",
|
||||
"finishedModerator": "錄製階段{{token}}已完成,本地錄製追蹤已存檔,請要求各與會者提供其錄製檔案。",
|
||||
"notModerator": "您不是主持人,無法開始或停止本地錄製。"
|
||||
"finishedModerator": "錄製階段{{token}} 已完成,本機錄製追蹤已存檔,請要求各與會者提供其錄製檔案。",
|
||||
"notModerator": "您不是主持人,無法開始或停止本機錄製。"
|
||||
},
|
||||
"moderator": "主持人",
|
||||
"no": "否",
|
||||
@@ -713,36 +727,37 @@
|
||||
"audioUnmuteBlockedDescription": "麥克風解除靜音操作由於系統限制而被暫時封鎖。",
|
||||
"audioUnmuteBlockedTitle": "麥克風解除靜音遭封鎖!",
|
||||
"chatMessages": "聊天訊息",
|
||||
"connectedOneMember": "{{name}}加入了會議",
|
||||
"connectedThreePlusMembers": "{{name}}與其他人加入了會議",
|
||||
"connectedTwoMembers": "{{first}}與{{second}}加入了會議",
|
||||
"connectedOneMember": "{{name}} 加入了會議",
|
||||
"connectedThreePlusMembers": "{{name}} 與其他人加入了會議",
|
||||
"connectedTwoMembers": "{{first}} 與{{second}} 加入了會議",
|
||||
"dataChannelClosed": "視訊品質受限",
|
||||
"dataChannelClosedDescription": "橋接通道已斷開,視訊品質降至最低設定。",
|
||||
"disabledIframe": "嵌入僅供示範使用,此通話將於 {{timeout}} 分鐘後中斷連線。",
|
||||
"disabledIframeSecondary": "內嵌 {{domain}} 僅為展示用途,此通話將在 {{timeout}} 分鐘後中斷連線。請使用在正式環境使用 <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi 服務</a>來內嵌!",
|
||||
"disconnected": "已經中斷連接",
|
||||
"displayNotifications": "顯示通知給",
|
||||
"dontRemindMe": "不要再提醒我",
|
||||
"focus": "會議焦點",
|
||||
"focusFail": "{{component}}無法使用 - {{ms}}秒後重試",
|
||||
"focusFail": "{{component}} 無法使用 - {{ms}} 秒後重試",
|
||||
"gifsMenu": "GIPHY",
|
||||
"groupTitle": "通知",
|
||||
"hostAskedUnmute": "主持人希望你發言",
|
||||
"invitedOneMember": "{{name}}已受邀請",
|
||||
"invitedThreePlusMembers": "{{name}}與{{count}}位人員已受邀請",
|
||||
"invitedTwoMembers": "{{first}}與{{second}}已受邀請",
|
||||
"hostAskedUnmute": "主持人希望您發言",
|
||||
"invitedOneMember": "{{name}} 已受邀請",
|
||||
"invitedThreePlusMembers": "{{name}} 與 {{count}} 位人員已受邀請",
|
||||
"invitedTwoMembers": "{{first}} 與 {{second}} 已受邀請",
|
||||
"joinMeeting": "加入",
|
||||
"kickParticipant": "{{kicked}}已被{{kicker}}移除會議",
|
||||
"leftOneMember": "{{name}}已離開會議",
|
||||
"leftThreePlusMembers": "{{name}}與其他人已離開會議",
|
||||
"leftTwoMembers": "{{first}}與{{second}}已離開會議",
|
||||
"kickParticipant": "{{kicked}} 已被 {{kicker}} 移除會議",
|
||||
"leftOneMember": "{{name}} 已離開會議",
|
||||
"leftThreePlusMembers": "{{name}} 與其他人已離開會議",
|
||||
"leftTwoMembers": "{{first}} 與 {{second}} 已離開會議",
|
||||
"linkToSalesforce": "連結至 Salesforce",
|
||||
"linkToSalesforceDescription": "您可以將會議摘要連結至 Salesforce 物件。",
|
||||
"linkToSalesforceError": "無法將會議連結至 Salesforce",
|
||||
"linkToSalesforceKey": "連結此會議",
|
||||
"linkToSalesforceProgress": "正在將會議連結至 Salesforce...",
|
||||
"linkToSalesforceSuccess": "會議已連結至 Salesforce",
|
||||
"localRecordingStarted": "{{name}}已啟用本地錄製",
|
||||
"localRecordingStopped": "{{name}}已停用本地錄製",
|
||||
"localRecordingStarted": "{{name}} 已啟用本機錄製",
|
||||
"localRecordingStopped": "{{name}} 已停用本機錄製",
|
||||
"me": "我",
|
||||
"moderationInEffectCSDescription": "若要分享您的螢幕,請舉手",
|
||||
"moderationInEffectCSTitle": "分享螢幕已被主持人停用",
|
||||
@@ -754,11 +769,11 @@
|
||||
"moderationRequestFromParticipant": "想要發言",
|
||||
"moderationStartedTitle": "開始主持",
|
||||
"moderationStoppedTitle": "停止主持",
|
||||
"moderationToggleDescription": "由{{participantDisplayName}}",
|
||||
"moderationToggleDescription": "由 {{participantDisplayName}}",
|
||||
"moderator": "主持人權限已經取得!",
|
||||
"muted": "您已經啟動通話,處於靜音。",
|
||||
"mutedRemotelyDescription": "當您準備好要發言,隨時可以取消靜音。當您結束之後再回復成靜音,保持會議安靜。",
|
||||
"mutedRemotelyTitle": "您已經被{{participantDisplayName}}設為靜音!",
|
||||
"mutedRemotelyTitle": "您已經被 {{participantDisplayName}} 設為靜音!",
|
||||
"mutedTitle": "您目前處於靜音!",
|
||||
"newDeviceAction": "使用",
|
||||
"newDeviceAudioTitle": "偵測到新的音效裝置",
|
||||
@@ -771,11 +786,11 @@
|
||||
"oldElectronClientDescription3": "!",
|
||||
"participantWantsToJoin": "希望加入會議",
|
||||
"participantsWantToJoin": "希望加入會議",
|
||||
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase)已被其他與會者移除",
|
||||
"passwordSetRemotely": "$t(lockRoomPasswordUppercase)由其他與會者設定",
|
||||
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) 已被其他與會者移除",
|
||||
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) 由其他與會者設定",
|
||||
"raiseHandAction": "舉手發言",
|
||||
"raisedHand": "{{name}}想要發言。",
|
||||
"raisedHands": "{{participantName}}與其他{{raisedHands}}人",
|
||||
"raisedHands": "{{participantName}} 與其他 {{raisedHands}} 人",
|
||||
"reactionSounds": "停用音效",
|
||||
"reactionSoundsForAll": "停用所有音效",
|
||||
"screenShareNoAudio": "您未在選擇視窗時勾選分享音訊",
|
||||
@@ -790,11 +805,13 @@
|
||||
"suboptimalExperienceTitle": "瀏覽器警告",
|
||||
"unmute": "取消靜音",
|
||||
"videoMutedRemotelyDescription": "您隨時可以再次啟用。",
|
||||
"videoMutedRemotelyTitle": "您的視訊已被{{participantDisplayName}}停用",
|
||||
"videoMutedRemotelyTitle": "您的視訊已被 {{participantDisplayName}} 停用",
|
||||
"videoUnmuteBlockedDescription": "啟用網路攝影機與分享螢幕由於系統限制而被暫時封鎖。",
|
||||
"videoUnmuteBlockedTitle": "啟用網路攝影機與分享螢幕遭封鎖!",
|
||||
"viewLobby": "檢視大廳",
|
||||
"waitingParticipants": "{{waitingParticipants}}人"
|
||||
"waitingParticipants": "{{waitingParticipants}} 人",
|
||||
"whiteboardLimitDescription": "由於即將超出使用者限制,白板將關閉,請儲存您的進度。",
|
||||
"whiteboardLimitTitle": "白板使用情況"
|
||||
},
|
||||
"participantsPane": {
|
||||
"actions": {
|
||||
@@ -803,6 +820,7 @@
|
||||
"askUnmute": "要求解除靜音",
|
||||
"audioModeration": "自我解除靜音",
|
||||
"blockEveryoneMicCamera": "停用所有人的麥克風和網路攝影機",
|
||||
"breakoutRooms": "分組討論室",
|
||||
"invite": "邀請他人",
|
||||
"moreModerationActions": "更多主持人選項",
|
||||
"moreModerationControls": "更多主持人操作",
|
||||
@@ -817,15 +835,15 @@
|
||||
},
|
||||
"close": "關閉",
|
||||
"headings": {
|
||||
"lobby": "大廳({{count}}人)",
|
||||
"participantsList": "會議與會者({{count}}人)",
|
||||
"visitors": "訪客({{count}}人)",
|
||||
"waitingLobby": "於大廳等候({{count}}人)"
|
||||
"lobby": "大廳({{count}} 人)",
|
||||
"participantsList": "會議與會者({{count}} 人)",
|
||||
"visitors": "訪客({{count}} 人)",
|
||||
"waitingLobby": "於大廳等候({{count}} 人)"
|
||||
},
|
||||
"search": "搜尋與會者",
|
||||
"title": "與會者"
|
||||
},
|
||||
"passwordDigitsOnly": "上限為{{number}}位數",
|
||||
"passwordDigitsOnly": "上限為 {{number}} 位數",
|
||||
"passwordSetRemotely": "由其他與會者設定",
|
||||
"pinParticipant": "{{participantName}} - 釘選",
|
||||
"pinnedParticipant": "與會者被釘選",
|
||||
@@ -834,13 +852,13 @@
|
||||
"skip": "跳過",
|
||||
"submit": "送出"
|
||||
},
|
||||
"by": "由{{ name }}",
|
||||
"by": "由 {{ name }}",
|
||||
"create": {
|
||||
"addOption": "新增選項",
|
||||
"answerPlaceholder": "選項{{index}}",
|
||||
"answerPlaceholder": "選項 {{index}}",
|
||||
"cancel": "取消",
|
||||
"create": "建立投票",
|
||||
"pollOption": "選項{{index}}",
|
||||
"pollOption": "選項 {{index}}",
|
||||
"pollQuestion": "投票問題",
|
||||
"questionPlaceholder": "詢問問題",
|
||||
"removeOption": "移除選項",
|
||||
@@ -879,7 +897,7 @@
|
||||
"audioHighQuality": "您的音訊品質極佳。",
|
||||
"audioLowNoVideo": "您的音訊品質較差,且無視訊功能。",
|
||||
"goodQuality": "太好了!您的媒體品質良好。",
|
||||
"noMediaConnectivity": "我們無法為此測試建立媒體連線,通常是防火牆或NAT的問題。",
|
||||
"noMediaConnectivity": "我們無法為此測試建立媒體連線,通常是防火牆或 NAT 的問題。",
|
||||
"noVideo": "您的視訊畫質將會很糟糕。",
|
||||
"undetectable": "如果您仍無法在瀏覽器中進行通話,我們建議您檢查喇叭、麥克風、及網路攝影機的設置,確認是否允許瀏覽器存取麥克風及網路攝影機,並將瀏覽器更新到最新版本。如果以上步驟無法解決問題,請聯絡網頁程式的開發者。",
|
||||
"veryPoorConnection": "您的通話品質將會非常糟糕。",
|
||||
@@ -958,8 +976,8 @@
|
||||
},
|
||||
"recording": {
|
||||
"authDropboxText": "上傳至 Dropbox",
|
||||
"availableSpace": "可用空間:{{spaceLeft}}MB(錄製時間大約{{duration}}分鐘)",
|
||||
"beta": "BETA",
|
||||
"availableSpace": "可用空間:{{spaceLeft}} MB(錄製時間大約 {{duration}} 分鐘)",
|
||||
"beta": "測試版",
|
||||
"busy": "我們正在釋放錄製資源,請過幾分鐘後再試。",
|
||||
"busyTitle": "全部錄製目前忙碌",
|
||||
"copyLink": "複製連結",
|
||||
@@ -976,15 +994,15 @@
|
||||
"highlightMomentSuccess": "已精選的時刻",
|
||||
"highlightMomentSucessDescription": "您的精選時刻將新增至會議摘要。",
|
||||
"inProgress": "正在錄製或直播",
|
||||
"limitNotificationDescriptionNative": "由於目前流量過大,您的錄製時間被限制在{{limit}}分鐘。若要無限制的錄製,請試試 <3>{{app}}</3>。",
|
||||
"limitNotificationDescriptionWeb": "由於目前流量過大,您的錄製時間被限制在{{limit}}分鐘。若要無限制的錄製,請試試 <a href={{url}}rel='noopener noreferrer' target='_blank'>{{app}}</a>。",
|
||||
"limitNotificationDescriptionNative": "由於目前流量過大,您的錄製時間被限制在 {{limit}} 分鐘。若要無限制的錄製,請試試 <3>{{app}}</3>。",
|
||||
"limitNotificationDescriptionWeb": "由於目前流量過大,您的錄製時間被限制在 {{limit}} 分鐘。若要無限制的錄製,請試試 <a href={{url}}rel='noopener noreferrer' target='_blank'>{{app}}</a>。",
|
||||
"linkGenerated": "我們建立了您的錄製檔案的連結。",
|
||||
"live": "直播",
|
||||
"localRecordingNoNotificationWarning": "系統不會主動知會與會者錄製已開啟,主持人需另行通知。",
|
||||
"localRecordingNoVideo": "沒有錄製的視訊",
|
||||
"localRecordingStartWarning": "請確保在退出會議之前停用錄製以便保存。",
|
||||
"localRecordingStartWarningTitle": "停用錄製以保存",
|
||||
"localRecordingVideoStop": "關閉您的視訊也將停止本地錄製,確定繼續嗎?",
|
||||
"localRecordingVideoStop": "關閉您的視訊也將停止本機錄製,確定繼續嗎?",
|
||||
"localRecordingVideoWarning": "錄製視訊必須在開始時啟用",
|
||||
"localRecordingWarning": "確保選擇目前的分頁以錄製正確的視訊和音訊。錄製目前限制為1GB,約可錄製100分鐘。",
|
||||
"loggedIn": "以 {{userName}} 登入",
|
||||
@@ -997,7 +1015,7 @@
|
||||
"onlyRecordSelf": "僅錄製我的音訊和影片串流",
|
||||
"pending": "正在準備錄製會議...",
|
||||
"rec": "錄製中",
|
||||
"saveLocalRecording": "將錄製檔案保存在本地(BETA)",
|
||||
"saveLocalRecording": "將錄製檔案保存在本機(測試版)",
|
||||
"serviceDescription": "您的錄製會由錄製服務儲存",
|
||||
"serviceDescriptionCloud": "雲端錄製",
|
||||
"serviceDescriptionCloudInfo": "已錄製的會議將在 24 小時後自動清除。",
|
||||
@@ -1007,19 +1025,19 @@
|
||||
"signOut": "登出",
|
||||
"surfaceError": "請選擇目前分頁",
|
||||
"title": "錄製中",
|
||||
"unavailable": "喔哦!{{serviceName}}目前無法使用,我們正在解決此問題,請稍後再試。",
|
||||
"unavailable": "喔哦!{{serviceName}} 目前無法使用,我們正在解決此問題,請稍後再試。",
|
||||
"unavailableTitle": "錄製無法使用",
|
||||
"uploadToCloud": "上傳至雲端"
|
||||
},
|
||||
"screenshareDisplayName": "{{name}}的螢幕",
|
||||
"screenshareDisplayName": "{{name}} 的螢幕",
|
||||
"sectionList": {
|
||||
"pullToRefresh": "下拉以重新整理"
|
||||
},
|
||||
"security": {
|
||||
"about": "您可以新增$t(lockRoomPassword)至您的會議,與會者在加入會議前必須先輸入$t(lockRoomPassword)。",
|
||||
"aboutReadOnly": "主持人可以新增$t(lockRoomPassword)至會議,與會者在加入會議前必須先輸入$t(lockRoomPassword)。",
|
||||
"insecureRoomNameWarningNative": "房間名稱不安全,任何人都可能會加入您的會議。{{recommendAction}} 了解有關保護您的會議的更多信息。",
|
||||
"insecureRoomNameWarningWeb": "房間名稱不安全,任何人都可能會加入您的會議。{{recommendAction}} 在此處了解有關保護您的會議的更多信息 <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">這裡</a>。",
|
||||
"about": "您可以新增 $t(lockRoomPassword) 至您的會議,與會者在加入會議前必須先輸入$t(lockRoomPassword)。",
|
||||
"aboutReadOnly": "主持人可以新增 $t(lockRoomPassword) 至會議,與會者在加入會議前必須先輸入$t(lockRoomPassword)。",
|
||||
"insecureRoomNameWarningNative": "房間名稱不安全,任何人都可能會加入您的會議。{{recommendAction}} 了解有關保護您的會議的更多資訊。",
|
||||
"insecureRoomNameWarningWeb": "房間名稱不安全,任何人都可能會加入您的會議。{{recommendAction}} 在此處了解有關保護您的會議的更多資訊 <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">這裡</a>。",
|
||||
"title": "安全性選項",
|
||||
"unsafeRoomActions": {
|
||||
"meeting": "請考慮使用安全按鈕保護您的會議。",
|
||||
@@ -1031,10 +1049,10 @@
|
||||
"audio": "音訊",
|
||||
"buttonLabel": "設定",
|
||||
"calendar": {
|
||||
"about": "{{appName}}行事曆整合功能可安全地存取您行事曆中即將舉行的活動。",
|
||||
"about": "{{appName}} 行事曆整合功能可安全地存取您行事曆中即將舉行的活動。",
|
||||
"disconnect": "中斷連接",
|
||||
"microsoftSignIn": "使用Microsoft帳號登入",
|
||||
"signedIn": "目前正在存取{{email}}的行事曆事件,點按下方中斷連接可以停用存取行事曆事件。",
|
||||
"microsoftSignIn": "使用 Microsoft 帳號登入",
|
||||
"signedIn": "目前正在存取 {{email}} 的行事曆事件,點按下方中斷連接可以停用存取行事曆事件。",
|
||||
"title": "行事曆"
|
||||
},
|
||||
"desktopShareFramerate": "桌面螢幕分享影格率",
|
||||
@@ -1079,6 +1097,7 @@
|
||||
"alertOk": "確定",
|
||||
"alertTitle": "警告",
|
||||
"alertURLText": "輸入的伺服器網址無效",
|
||||
"apply": "套用",
|
||||
"buildInfoSection": "組建資訊",
|
||||
"conferenceSection": "會議",
|
||||
"disableCallIntegration": "停用原生通話整合",
|
||||
@@ -1086,23 +1105,24 @@
|
||||
"disableCrashReportingWarning": "您確定要停用錯誤回報功能嗎?變更將在重啟應用程式後生效。",
|
||||
"disableP2P": "停用點對點模式",
|
||||
"displayName": "顯示名稱",
|
||||
"displayNamePlaceholderText": "例如:John Doe",
|
||||
"displayNamePlaceholderText": "例如:王小明",
|
||||
"email": "電子郵件",
|
||||
"emailPlaceholderText": "email@example.com",
|
||||
"gavatarMessage": "如果您的電子郵件地址與 Gravatar 帳號相關聯,我們會使用 Gravatar 上的個人檔案大頭貼。",
|
||||
"goTo": "前往",
|
||||
"header": "設定",
|
||||
"help": "協助",
|
||||
"links": "連結",
|
||||
"privacy": "隱私權",
|
||||
"profileSection": "簡介",
|
||||
"sdkVersion": "SDK版本",
|
||||
"sdkVersion": "SDK 版本",
|
||||
"serverURL": "伺服器網址",
|
||||
"showAdvanced": "顯示進階設定",
|
||||
"startCarModeInLowBandwidthMode": "同時啟用行車模式與低頻寬模式",
|
||||
"startWithAudioMuted": "啟動並靜音",
|
||||
"startWithVideoMuted": "啟動並關閉影像",
|
||||
"terms": "條款",
|
||||
"version": "APP版本"
|
||||
"version": "應用程式版本"
|
||||
},
|
||||
"share": {
|
||||
"dialInfoText": "\n\n=====\n\n只想要透過手機撥打加入嗎?\n\n撥打{{defaultDialInNumber}}或點此連結來查看此會議的電話撥入號碼\n{{dialInfoPageUrl}}",
|
||||
@@ -1146,7 +1166,7 @@
|
||||
"Settings": "切換設定",
|
||||
"audioOnly": "切換僅音訊",
|
||||
"audioRoute": "選擇音訊裝置",
|
||||
"boo": "喝倒彩",
|
||||
"boo": "倒喝彩",
|
||||
"breakoutRoom": "進入/離開分組討論室",
|
||||
"callQuality": "管理視訊品質",
|
||||
"carmode": "行車模式",
|
||||
@@ -1160,7 +1180,7 @@
|
||||
"document": "切換檔案分享",
|
||||
"documentClose": "關閉檔案分享",
|
||||
"documentOpen": "打開檔案分享",
|
||||
"download": "下載我們的APP",
|
||||
"download": "下載我們的應用程式",
|
||||
"embedMeeting": "嵌入會議",
|
||||
"endConference": "結束會議(所有人)",
|
||||
"enterFullScreen": "進入全螢幕",
|
||||
@@ -1183,7 +1203,7 @@
|
||||
"like": "比讚",
|
||||
"linkToSalesforce": "連結至 Salesforce",
|
||||
"lobbyButton": "啟用/停用大廳模式",
|
||||
"localRecording": "切換本地錄製控制",
|
||||
"localRecording": "切換本機錄製控制",
|
||||
"lockRoom": "切換會議密碼",
|
||||
"lowerHand": "放下手",
|
||||
"moreActions": "更多動作",
|
||||
@@ -1199,7 +1219,7 @@
|
||||
"openChat": "打開聊天",
|
||||
"participants": "打開與會者窗格",
|
||||
"pip": "切換子母螢幕模式",
|
||||
"privateMessage": "發送私人訊息",
|
||||
"privateMessage": "傳送私人訊息",
|
||||
"profile": "編輯您的個人檔案",
|
||||
"raiseHand": "舉手",
|
||||
"reactions": "反應",
|
||||
@@ -1237,7 +1257,7 @@
|
||||
"audioRoute": "選擇音訊裝置",
|
||||
"audioSettings": "音訊設定",
|
||||
"authenticate": "驗證",
|
||||
"boo": "喝倒彩",
|
||||
"boo": "倒喝彩",
|
||||
"callQuality": "管理影像品質",
|
||||
"chat": "開啟/關閉聊天欄",
|
||||
"clap": "鼓掌",
|
||||
@@ -1248,7 +1268,7 @@
|
||||
"disableReactionSounds": "您可以停用此會議的反應音效",
|
||||
"documentClose": "關閉分享檔案欄",
|
||||
"documentOpen": "開啟分享檔案欄",
|
||||
"download": "下載我們的APP",
|
||||
"download": "下載我們的應用程式",
|
||||
"e2ee": "端對端加密",
|
||||
"embedMeeting": "嵌入會議",
|
||||
"enableNoiseSuppression": "開啟雜訊抑制",
|
||||
@@ -1273,7 +1293,7 @@
|
||||
"lobbyButtonEnable": "啟用大廳模式",
|
||||
"login": "登入",
|
||||
"logout": "登出",
|
||||
"lowerYourHand": "放下你的手",
|
||||
"lowerYourHand": "放下您的手",
|
||||
"moreActions": "更多動作",
|
||||
"moreOptions": "更多選項",
|
||||
"mute": "靜音/解除靜音",
|
||||
@@ -1294,9 +1314,9 @@
|
||||
"pip": "進入子母螢幕模式",
|
||||
"privateMessage": "傳送私人訊息",
|
||||
"profile": "編輯您的個人資料",
|
||||
"raiseHand": "舉起/放下你的手",
|
||||
"raiseHand": "舉起/放下您的手",
|
||||
"raiseYourHand": "舉手",
|
||||
"reactionBoo": "傳送喝倒彩反應",
|
||||
"reactionBoo": "傳送倒喝彩反應",
|
||||
"reactionClap": "傳送鼓掌反應",
|
||||
"reactionLaugh": "傳送大笑反應",
|
||||
"reactionLike": "傳送比讚反應",
|
||||
@@ -1336,7 +1356,7 @@
|
||||
"labelToolTip": "此會議正在轉錄",
|
||||
"off": "轉錄已停用",
|
||||
"pending": "準備轉錄會議...",
|
||||
"sourceLanguageDesc": "會議語言目前設定為<b>{{sourceLanguage}}</b><br/>您可以在這裡",
|
||||
"sourceLanguageDesc": "會議語言目前設定為 <b>{{sourceLanguage}}</b><br/> 您可以在這裡",
|
||||
"sourceLanguageHere": "修改",
|
||||
"start": "開始顯示字幕",
|
||||
"stop": "停用顯示字幕",
|
||||
@@ -1360,12 +1380,12 @@
|
||||
"videoSIPGW": {
|
||||
"busy": "我們正在釋放資源,請過幾分鐘後再試。",
|
||||
"busyTitle": "會議室服務目前忙碌中",
|
||||
"errorAlreadyInvited": "{{displayName}}已經受邀",
|
||||
"errorAlreadyInvited": "{{displayName}} 已經受邀",
|
||||
"errorInvite": "會議尚未開始,請稍候再試。",
|
||||
"errorInviteFailed": "我們正在努力解決這個問題,請稍後再試。",
|
||||
"errorInviteFailedTitle": "邀請{{displayName}}失敗",
|
||||
"errorInviteFailedTitle": "邀請 {{displayName}} 失敗",
|
||||
"errorInviteTitle": "會議室邀請錯誤",
|
||||
"pending": "已向{{displayName}}發送邀請"
|
||||
"pending": "已向 {{displayName}} 傳送邀請"
|
||||
},
|
||||
"videoStatus": {
|
||||
"adjustFor": "調整為:",
|
||||
@@ -1415,7 +1435,7 @@
|
||||
},
|
||||
"virtualBackground": {
|
||||
"accessibilityLabel": {
|
||||
"currentBackground": "當前背景:{{background}}",
|
||||
"currentBackground": "目前背景:{{background}}",
|
||||
"selectBackground": "選擇背景"
|
||||
},
|
||||
"addBackground": "新增背景",
|
||||
@@ -1438,8 +1458,8 @@
|
||||
"slightBlur": "輕微模糊",
|
||||
"title": "虛擬背景",
|
||||
"uploadedImage": "已上傳的圖片 {{index}}",
|
||||
"webAssemblyWarning": "不支援WebAssembly",
|
||||
"webAssemblyWarningDescription": "WebAssembly已停用或不受此瀏覽器支援"
|
||||
"webAssemblyWarning": "不支援 WebAssembly",
|
||||
"webAssemblyWarningDescription": "WebAssembly 已停用或不受此瀏覽器支援"
|
||||
},
|
||||
"visitors": {
|
||||
"chatIndicator": "(訪客)",
|
||||
@@ -1456,14 +1476,14 @@
|
||||
"roomname": "輸入會議室名稱"
|
||||
},
|
||||
"addMeetingName": "新增會議名稱",
|
||||
"appDescription": "來吧,和您的整個團隊進行視訊會議。不,邀請所有您認識的人進行視訊會議。{{app}}是一套完全加密、100% 開放源始碼的視訊會議解決方案。無需註冊帳號,無時無刻不分日夜均可免費使用。",
|
||||
"appDescription": "來吧,和您的整個團隊進行視訊會議。不,邀請所有您認識的人進行視訊會議。{{app}} 是一套完全加密、100% 開放原始碼的視訊會議解決方案。無需註冊帳號,無時無刻不分日夜均可免費使用。",
|
||||
"audioVideoSwitch": {
|
||||
"audio": "音訊",
|
||||
"video": "視訊"
|
||||
},
|
||||
"calendar": "行事曆",
|
||||
"connectCalendarButton": "連接您的行事曆",
|
||||
"connectCalendarText": "連接您的行事曆來查看在{{app}}中的會議。此外,增加{{provider}}的會議至自己的行事曆,只要點按一下即可啟動。",
|
||||
"connectCalendarText": "連接您的行事曆來查看在 {{app}} 中的會議。此外,增加 {{provider}} 的會議至自己的行事曆,只要點按一下即可啟動。",
|
||||
"enterRoomTitle": "啟動新的會議",
|
||||
"getHelp": "取得協助",
|
||||
"go": "開始",
|
||||
@@ -1482,25 +1502,25 @@
|
||||
"policyLogo": "政策圖示"
|
||||
},
|
||||
"meetingsAccessibilityLabel": "會議",
|
||||
"mobileDownLoadLinkAndroid": "下載 Android 版本的手機應用程式",
|
||||
"mobileDownLoadLinkFDroid": "前往 F-Droid 下載 Android 版本的手機應用程式",
|
||||
"mobileDownLoadLinkIos": "下載 iOS 版本的手機應用程式",
|
||||
"mobileDownLoadLinkAndroid": "下載 Android 版本的應用程式",
|
||||
"mobileDownLoadLinkFDroid": "前往 F-Droid 下載 Android 版本的應用程式",
|
||||
"mobileDownLoadLinkIos": "下載 iOS 版本的應用程式",
|
||||
"moderatedMessage": "或以主持人身份<a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">預先建立會議</a>。",
|
||||
"privacy": "隱私權",
|
||||
"recentList": "最近使用",
|
||||
"recentList": "近期",
|
||||
"recentListDelete": "刪除",
|
||||
"recentListEmpty": "目前最近使用是空白的,與您的團隊成員聊天,即會在此處找到最近使用過的會議。",
|
||||
"recentMeetings": "您的最近會議",
|
||||
"recentListEmpty": "您的近期列表目前是空白的,與您的團隊成員聊天,即可在此處找到最近參與過的會議。",
|
||||
"recentMeetings": "您近期的會議",
|
||||
"reducedUIText": "歡迎使用{{app}}!",
|
||||
"roomNameAllowedChars": "會議室名稱不應包含以下字元:? & : ' \" % #",
|
||||
"roomNameAllowedChars": "會議室名稱不應包含以下字元:?、&、:、'、\"、%、#。",
|
||||
"roomname": "輸入會議室名稱",
|
||||
"roomnameHint": "請輸入您想加入的會議室名稱或網址,您可以用一個名稱來建立會議室,只要其他人輸入相同的名稱就能加入會議室喔。",
|
||||
"roomnameHint": "請輸入您想加入的會議室名稱或網址,您可以用一個名稱來建立會議室,只要其他人輸入相同的名稱就能加入會議室。",
|
||||
"sendFeedback": "傳送回饋",
|
||||
"settings": "設定",
|
||||
"startMeeting": "開始會議",
|
||||
"terms": "條款",
|
||||
"title": "安全、功能齊全、完全免費的視訊會議",
|
||||
"upcomingMeetings": "您即將的會議"
|
||||
"upcomingMeetings": "您即將開始的會議"
|
||||
},
|
||||
"whiteboard": {
|
||||
"accessibilityLabel": {
|
||||
|
||||
@@ -421,6 +421,7 @@
|
||||
"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.",
|
||||
@@ -482,6 +483,10 @@
|
||||
"viewUpgradeOptions": "View upgrade options",
|
||||
"viewUpgradeOptionsContent": "To get unlimited access to premium features like recording, transcriptions, RTMP Streaming & more, you'll need to upgrade your plan.",
|
||||
"viewUpgradeOptionsTitle": "You discovered a premium feature!",
|
||||
"whiteboardLimitContent": "Sorry, the limit of conccurent whiteboard users has been reached.",
|
||||
"whiteboardLimitReference": "For more information please visit",
|
||||
"whiteboardLimitReferenceUrl": "our website",
|
||||
"whiteboardLimitTitle": "Whiteboard usage restricted",
|
||||
"yourEntireScreen": "Your entire screen"
|
||||
},
|
||||
"documentSharing": {
|
||||
@@ -729,6 +734,7 @@
|
||||
"dataChannelClosed": "Video quality impaired",
|
||||
"dataChannelClosedDescription": "The bridge channel has been disconnected and thus video quality is limited to its lowest setting.",
|
||||
"disabledIframe": "Embedding is only meant for demo purposes, so this call will disconnect in {{timeout}} minutes.",
|
||||
"disabledIframeSecondary": "Embedding {{domain}} is only meant for demo purposes, so this call will disconnect in {{timeout}} minutes. Please use <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi as a Service</a> for production embedding!",
|
||||
"disconnected": "disconnected",
|
||||
"displayNotifications": "Display notifications for",
|
||||
"dontRemindMe": "Do not remind me",
|
||||
@@ -804,7 +810,9 @@
|
||||
"videoUnmuteBlockedDescription": "Camera unmute and desktop sharing operation have been temporarily blocked because of system limits.",
|
||||
"videoUnmuteBlockedTitle": "Camera unmute and desktop sharing blocked!",
|
||||
"viewLobby": "View lobby",
|
||||
"waitingParticipants": "{{waitingParticipants}} people"
|
||||
"waitingParticipants": "{{waitingParticipants}} people",
|
||||
"whiteboardLimitDescription": "Please save your progress, as the user limit will soon be reached and the whiteboard will close.",
|
||||
"whiteboardLimitTitle": "Whiteboard usage"
|
||||
},
|
||||
"participantsPane": {
|
||||
"actions": {
|
||||
|
||||
@@ -244,8 +244,6 @@ function initCommands() {
|
||||
}
|
||||
},
|
||||
'pin-participant': (id, videoType) => {
|
||||
logger.debug('Pin participant command received');
|
||||
|
||||
const state = APP.store.getState();
|
||||
|
||||
// if id not provided, unpin everybody.
|
||||
@@ -303,7 +301,6 @@ 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));
|
||||
},
|
||||
@@ -324,7 +321,6 @@ 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'));
|
||||
@@ -335,7 +331,6 @@ 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) {
|
||||
@@ -373,12 +368,10 @@ 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': () => {
|
||||
@@ -497,7 +490,6 @@ 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);
|
||||
|
||||
@@ -515,7 +507,6 @@ 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,
|
||||
@@ -538,25 +529,19 @@ 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);
|
||||
|
||||
@@ -564,9 +549,7 @@ 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());
|
||||
},
|
||||
@@ -641,6 +624,7 @@ 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': ({
|
||||
@@ -651,7 +635,8 @@ function initCommands() {
|
||||
rtmpStreamKey,
|
||||
rtmpBroadcastID,
|
||||
youtubeStreamKey,
|
||||
youtubeBroadcastID
|
||||
youtubeBroadcastID,
|
||||
extraMetadata = {}
|
||||
}) => {
|
||||
const state = APP.store.getState();
|
||||
const conference = getCurrentConference(state);
|
||||
@@ -701,6 +686,7 @@ function initCommands() {
|
||||
mode: JitsiRecordingConstants.mode.FILE,
|
||||
appData: JSON.stringify({
|
||||
'file_recording_metadata': {
|
||||
...extraMetadata,
|
||||
'upload_credentials': {
|
||||
'service_name': RECORDING_TYPES.DROPBOX,
|
||||
'token': dropboxToken
|
||||
@@ -713,6 +699,7 @@ function initCommands() {
|
||||
mode: JitsiRecordingConstants.mode.FILE,
|
||||
appData: JSON.stringify({
|
||||
'file_recording_metadata': {
|
||||
...extraMetadata,
|
||||
'share': shouldShare
|
||||
}
|
||||
})
|
||||
@@ -842,11 +829,14 @@ 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) => {
|
||||
@@ -993,7 +983,13 @@ function initCommands() {
|
||||
callback(isP2pActive(APP.store.getState()));
|
||||
break;
|
||||
}
|
||||
case '_new_electron_screensharing_supported': {
|
||||
callback(true);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
callback({ error: new Error('UnknownRequestError') });
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1101,7 +1097,11 @@ class API {
|
||||
this._enabled = true;
|
||||
|
||||
initCommands();
|
||||
|
||||
this.notifyBrowserSupport(isSupportedBrowser());
|
||||
|
||||
// Let the embedder know we are ready.
|
||||
this._sendEvent({ name: 'ready' });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1279,6 +1279,19 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify request desktop sources.
|
||||
*
|
||||
* @param {Object} options - Object with the options for desktop sources.
|
||||
* @returns {void}
|
||||
*/
|
||||
requestDesktopSources(options) {
|
||||
return transport.sendRequest({
|
||||
name: '_request-desktop-sources',
|
||||
options
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application that the video quality setting has changed.
|
||||
*
|
||||
@@ -1964,6 +1977,20 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that the user received
|
||||
* a transcription chunk.
|
||||
*
|
||||
* @param {Object} data - The event data.
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyTranscriptionChunkReceived(data) {
|
||||
this._sendEvent({
|
||||
name: 'transcription-chunk-received',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) whether the used browser is supported or not.
|
||||
*
|
||||
|
||||
59
modules/API/external/external_api.js
vendored
59
modules/API/external/external_api.js
vendored
@@ -145,6 +145,7 @@ const events = {
|
||||
'prejoin-screen-loaded': 'prejoinScreenLoaded',
|
||||
'proxy-connection-event': 'proxyConnectionEvent',
|
||||
'raise-hand-updated': 'raiseHandUpdated',
|
||||
'ready': 'ready',
|
||||
'recording-link-available': 'recordingLinkAvailable',
|
||||
'recording-status-changed': 'recordingStatusChanged',
|
||||
'participant-menu-button-clicked': 'participantMenuButtonClick',
|
||||
@@ -159,9 +160,14 @@ const events = {
|
||||
'suspend-detected': 'suspendDetected',
|
||||
'tile-view-changed': 'tileViewChanged',
|
||||
'toolbar-button-clicked': 'toolbarButtonClicked',
|
||||
'transcription-chunk-received': 'transcriptionChunkReceived',
|
||||
'whiteboard-status-changed': 'whiteboardStatusChanged'
|
||||
};
|
||||
|
||||
const requests = {
|
||||
'_request-desktop-sources': '_requestDesktopSources'
|
||||
};
|
||||
|
||||
/**
|
||||
* Last id of api object.
|
||||
*
|
||||
@@ -269,10 +275,10 @@ function parseArguments(args) {
|
||||
function parseSizeParam(value) {
|
||||
let parsedValue;
|
||||
|
||||
// This regex parses values of the form 100px, 100em, 100pt or 100%.
|
||||
// This regex parses values of the form 100px, 100em, 100pt, 100vh, 100vw or 100%.
|
||||
// Values like 100 or 100px are handled outside of the regex, and
|
||||
// invalid values will be ignored and the minimum will be used.
|
||||
const re = /([0-9]*\.?[0-9]+)(em|pt|px|%)$/;
|
||||
const re = /([0-9]*\.?[0-9]+)(em|pt|px|((d|l|s)?v)(h|w)|%)$/;
|
||||
|
||||
if (typeof value === 'string' && String(value).match(re) !== null) {
|
||||
parsedValue = value;
|
||||
@@ -361,7 +367,9 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
},
|
||||
release
|
||||
});
|
||||
this._createIFrame(height, width, onload, sandbox);
|
||||
|
||||
this._createIFrame(height, width, sandbox);
|
||||
|
||||
this._transport = new Transport({
|
||||
backend: new PostMessageTransportBackend({
|
||||
postisOptions: {
|
||||
@@ -371,9 +379,12 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if (Array.isArray(invitees) && invitees.length > 0) {
|
||||
this.invite(invitees);
|
||||
}
|
||||
|
||||
this._onload = onload;
|
||||
this._tmpE2EEKey = e2eeKey;
|
||||
this._isLargeVideoVisible = false;
|
||||
this._isPrejoinVideoVisible = false;
|
||||
@@ -392,14 +403,12 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
* parseSizeParam for format details.
|
||||
* @param {number|string} width - The with of the iframe. Check
|
||||
* parseSizeParam for format details.
|
||||
* @param {Function} onload - The function that will listen
|
||||
* for onload event.
|
||||
* @param {string} sandbox - Sandbox directive for the created iframe, if desired.
|
||||
* @returns {void}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_createIFrame(height, width, onload, sandbox) {
|
||||
_createIFrame(height, width, sandbox) {
|
||||
const frameName = `jitsiConferenceFrame${id}`;
|
||||
|
||||
this._frame = document.createElement('iframe');
|
||||
@@ -411,7 +420,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
'display-capture',
|
||||
'hid',
|
||||
'microphone',
|
||||
'screen-wake-lock'
|
||||
'screen-wake-lock',
|
||||
'speaker-selection'
|
||||
].join('; ');
|
||||
this._frame.name = frameName;
|
||||
this._frame.id = frameName;
|
||||
@@ -423,11 +433,6 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
this._frame.sandbox = sandbox;
|
||||
}
|
||||
|
||||
if (onload) {
|
||||
// waits for iframe resources to load
|
||||
// and fires event when it is done
|
||||
this._frame.onload = onload;
|
||||
}
|
||||
this._frame.src = this._url;
|
||||
|
||||
this._frame = this._parentNode.appendChild(this._frame);
|
||||
@@ -576,6 +581,12 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
const userID = data.id;
|
||||
|
||||
switch (name) {
|
||||
case 'ready': {
|
||||
// Fake the iframe onload event because it's not reliable.
|
||||
this._onload?.();
|
||||
|
||||
break;
|
||||
}
|
||||
case 'video-conference-joined': {
|
||||
if (typeof this._tmpE2EEKey !== 'undefined') {
|
||||
|
||||
@@ -687,6 +698,18 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
this._transport.on('request', (request, callback) => {
|
||||
const requestName = requests[request.name];
|
||||
const data = {
|
||||
...request,
|
||||
name: requestName
|
||||
};
|
||||
|
||||
if (requestName) {
|
||||
this.emit(requestName, data, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1258,6 +1281,17 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the state of availability electron share screen via external api.
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_isNewElectronScreensharingSupported() {
|
||||
return this._transport.sendRequest({
|
||||
name: '_new_electron_screensharing_supported'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Pins a participant's video on to the stage view.
|
||||
*
|
||||
@@ -1398,6 +1432,7 @@ 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) {
|
||||
|
||||
4597
package-lock.json
generated
4597
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
22
package.json
22
package.json
@@ -22,7 +22,7 @@
|
||||
"@giphy/js-fetch-api": "4.7.1",
|
||||
"@giphy/react-components": "6.8.1",
|
||||
"@giphy/react-native-sdk": "2.3.0",
|
||||
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.14/jitsi-excalidraw-0.0.14.tgz",
|
||||
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.16/jitsi-excalidraw-0.0.16.tgz",
|
||||
"@jitsi/js-utils": "2.2.1",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
"@jitsi/rnnoise-wasm": "0.1.0",
|
||||
@@ -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.3",
|
||||
"@react-native-async-storage/async-storage": "1.19.4",
|
||||
"@react-native-community/clipboard": "1.5.1",
|
||||
"@react-native-community/netinfo": "9.4.1",
|
||||
"@react-native-community/netinfo": "11.1.0",
|
||||
"@react-native-community/slider": "4.4.3",
|
||||
"@react-native-google-signin/google-signin": "10.0.1",
|
||||
"@react-native-google-signin/google-signin": "10.1.0",
|
||||
"@react-navigation/bottom-tabs": "6.5.8",
|
||||
"@react-navigation/elements": "1.3.18",
|
||||
"@react-navigation/material-top-tabs": "6.6.3",
|
||||
@@ -65,12 +65,13 @@
|
||||
"js-md5": "0.6.1",
|
||||
"js-sha512": "0.8.0",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1698.0.0+03cb3ce8/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1734.0.0+34ceebd2/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
"null-loader": "4.0.1",
|
||||
"optional-require": "1.0.3",
|
||||
"pixelmatch": "5.3.0",
|
||||
"promise.allsettled": "1.0.4",
|
||||
"punycode": "2.3.0",
|
||||
"react": "18.2.0",
|
||||
@@ -79,10 +80,9 @@
|
||||
"react-focus-on": "3.8.1",
|
||||
"react-i18next": "10.11.4",
|
||||
"react-linkify": "1.0.0-alpha",
|
||||
"react-native": "0.69.12",
|
||||
"react-native": "0.70.14",
|
||||
"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 +90,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.5.0",
|
||||
"react-native-orientation-locker": "1.6.0",
|
||||
"react-native-pager-view": "6.2.0",
|
||||
"react-native-paper": "5.10.3",
|
||||
"react-native-performance": "5.0.0",
|
||||
@@ -104,7 +104,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": "111.0.3",
|
||||
"react-native-webrtc": "118.0.0",
|
||||
"react-native-webview": "13.5.1",
|
||||
"react-native-youtube-iframe": "2.3.0",
|
||||
"react-redux": "7.2.9",
|
||||
@@ -113,7 +113,6 @@
|
||||
"react-youtube": "10.1.0",
|
||||
"redux": "4.0.4",
|
||||
"redux-thunk": "2.4.1",
|
||||
"resemblejs": "4.0.0",
|
||||
"seamless-scroll-polyfill": "2.1.8",
|
||||
"semver": "7.5.4",
|
||||
"tss-react": "4.4.4",
|
||||
@@ -136,6 +135,8 @@
|
||||
"@types/dom-screen-wake-lock": "1.0.1",
|
||||
"@types/js-md5": "0.4.3",
|
||||
"@types/lodash": "4.14.182",
|
||||
"@types/offscreencanvas": "2019.7.2",
|
||||
"@types/pixelmatch": "5.2.5",
|
||||
"@types/punycode": "2.1.0",
|
||||
"@types/react": "17.0.14",
|
||||
"@types/react-dom": "17.0.14",
|
||||
@@ -145,7 +146,6 @@
|
||||
"@types/react-native-video": "5.0.14",
|
||||
"@types/react-redux": "7.1.24",
|
||||
"@types/react-window": "1.8.5",
|
||||
"@types/resemblejs": "^4.1.0",
|
||||
"@types/unorm": "1.3.28",
|
||||
"@types/uuid": "8.3.4",
|
||||
"@types/w3c-image-capture": "1.0.6",
|
||||
|
||||
@@ -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 @@ - (void)setup
|
||||
@@ -127,7 +127,15 @@ RCT_EXPORT_MODULE()
|
||||
{
|
||||
_paused = YES;
|
||||
_timers = [NSMutableDictionary new];
|
||||
@@ -19,7 +19,7 @@ index 13d0d57..00e5d4c 100644
|
||||
|
||||
for (NSString *name in @[
|
||||
UIApplicationWillResignActiveNotification,
|
||||
@@ -146,6 +154,11 @@ - (void)setup
|
||||
@@ -146,6 +154,11 @@ RCT_EXPORT_MODULE()
|
||||
name:name
|
||||
object:nil];
|
||||
}
|
||||
@@ -31,7 +31,7 @@ index 13d0d57..00e5d4c 100644
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
@@ -182,6 +195,16 @@ - (void)appDidMoveToForeground
|
||||
@@ -182,6 +195,16 @@ RCT_EXPORT_MODULE()
|
||||
[self startTimers];
|
||||
}
|
||||
|
||||
@@ -73,6 +73,13 @@ cd ios && pod install && cd ..
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
```
|
||||
- In `android/app/src/main/AndroidManifest.xml`, under the `</application>` tag, include
|
||||
```xml
|
||||
<service
|
||||
android:name="org.jitsi.meet.sdk.JitsiMeetOngoingConferenceService"
|
||||
android:foregroundServiceType="mediaProjection" />
|
||||
```
|
||||
This will take care of the screen share feature.
|
||||
|
||||
If you want to test all the steps before applying them to your app, you can check our React Native SDK sample app here:
|
||||
https://github.com/jitsi/jitsi-meet-sdk-samples/tree/master/react-native
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
|
||||
|
||||
@ReactModule(name = JMOngoingConferenceModule.NAME)
|
||||
class JMOngoingConferenceModule
|
||||
extends ReactContextBaseJavaModule {
|
||||
|
||||
public static final String NAME = "JMOngoingConference";
|
||||
|
||||
public JMOngoingConferenceModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void launch() {
|
||||
Context context = getReactApplicationContext();
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
|
||||
JitsiMeetOngoingConferenceService.launch(context, currentActivity);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void abort() {
|
||||
Context context = getReactApplicationContext();
|
||||
|
||||
JitsiMeetOngoingConferenceService.abort(context);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* This class implements an Android {@link Service}, a foreground one specifically, and it's
|
||||
* responsible for presenting an ongoing notification when a conference is in progress.
|
||||
* The service will help keep the app running while in the background.
|
||||
*
|
||||
* See: https://developer.android.com/guide/components/services
|
||||
*/
|
||||
public class JitsiMeetOngoingConferenceService extends Service {
|
||||
private static final String TAG = JitsiMeetOngoingConferenceService.class.getSimpleName();
|
||||
|
||||
public static void launch(Context context, Activity currentActivity) {
|
||||
|
||||
RNOngoingNotification.createOngoingConferenceNotificationChannel(currentActivity);
|
||||
|
||||
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
|
||||
|
||||
ComponentName componentName;
|
||||
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
componentName = context.startForegroundService(intent);
|
||||
} else {
|
||||
componentName = context.startService(intent);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
// Avoid crashing due to ForegroundServiceStartNotAllowedException (API level 31).
|
||||
// See: https://developer.android.com/guide/components/foreground-services#background-start-restrictions
|
||||
JitsiMeetLogger.w(TAG + " Ongoing conference service not started", e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (componentName == null) {
|
||||
JitsiMeetLogger.w(TAG + " Ongoing conference service not started");
|
||||
}
|
||||
}
|
||||
|
||||
public static void abort(Context context) {
|
||||
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
|
||||
context.stopService(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
Notification notification = RNOngoingNotification.buildOngoingConferenceNotification(this);
|
||||
|
||||
if (notification == null) {
|
||||
stopSelf();
|
||||
JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null");
|
||||
} else {
|
||||
startForeground(RNOngoingNotification.NOTIFICATION_ID, notification);
|
||||
JitsiMeetLogger.i(TAG + " Service started");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ public class JitsiMeetReactNativePackage implements ReactPackage {
|
||||
new AndroidSettingsModule(reactContext),
|
||||
new AppInfoModule(reactContext),
|
||||
new AudioModeModule(reactContext),
|
||||
new JMOngoingConferenceModule(reactContext),
|
||||
new JavaScriptSandboxModule(reactContext),
|
||||
new LocaleDetector(reactContext),
|
||||
new LogBridgeModule(reactContext),
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Helper class for creating the ongoing notification which is used with
|
||||
* {@link JitsiMeetOngoingConferenceService}. It allows the user to easily get back to the app
|
||||
* and to hangup from within the notification itself.
|
||||
*/
|
||||
class RNOngoingNotification {
|
||||
private static final String TAG = RNOngoingNotification.class.getSimpleName();
|
||||
|
||||
static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
|
||||
|
||||
static void createOngoingConferenceNotificationChannel(Activity currentActivity) {
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentActivity == null) {
|
||||
JitsiMeetLogger.w(TAG + " Cannot create notification channel: no current context");
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationManager notificationManager
|
||||
= (NotificationManager) currentActivity.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
NotificationChannel channel
|
||||
= notificationManager.getNotificationChannel("JitsiOngoingConferenceChannel");
|
||||
if (channel != null) {
|
||||
// The channel was already created, no need to do it again.
|
||||
return;
|
||||
}
|
||||
|
||||
channel = new NotificationChannel("JitsiOngoingConferenceChannel", currentActivity.getString(R.string.ongoing_notification_channel_name), NotificationManager.IMPORTANCE_DEFAULT);
|
||||
channel.enableLights(false);
|
||||
channel.enableVibration(false);
|
||||
channel.setShowBadge(false);
|
||||
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
static Notification buildOngoingConferenceNotification(Context context) {
|
||||
|
||||
if (context == null) {
|
||||
JitsiMeetLogger.w(TAG + " Cannot create notification: no current context");
|
||||
return null;
|
||||
}
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "JitsiOngoingConferenceChannel");
|
||||
|
||||
builder
|
||||
.setCategory(NotificationCompat.CATEGORY_CALL)
|
||||
.setContentTitle(context.getString(R.string.ongoing_notification_title))
|
||||
.setContentText(context.getString(R.string.ongoing_notification_text))
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.setOngoing(true)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setUsesChronometer(true)
|
||||
.setAutoCancel(false)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setSmallIcon(context.getResources().getIdentifier("ic_notification", "drawable", context.getPackageName()));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ import { setAudioMuted, setVideoMuted } from './react/features/base/media/action
|
||||
|
||||
|
||||
interface IEventListeners {
|
||||
onAudioMutedChanged?: Function;
|
||||
onVideoMutedChanged?: Function;
|
||||
onConferenceBlurred?: Function;
|
||||
onConferenceFocused?: Function;
|
||||
onConferenceJoined?: Function;
|
||||
@@ -107,6 +109,8 @@ 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,
|
||||
|
||||
120
react-native-sdk/package-lock.json
generated
120
react-native-sdk/package-lock.json
generated
@@ -154,11 +154,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz",
|
||||
"integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==",
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
|
||||
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.15",
|
||||
"@babel/types": "^7.23.0",
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
"@jridgewell/trace-mapping": "^0.3.17",
|
||||
"jsesc": "^2.5.1"
|
||||
@@ -191,20 +191,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-environment-visitor": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
|
||||
"integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==",
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
|
||||
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-function-name": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
|
||||
"integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
|
||||
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.22.5",
|
||||
"@babel/types": "^7.22.5"
|
||||
"@babel/template": "^7.22.15",
|
||||
"@babel/types": "^7.23.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -281,9 +281,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz",
|
||||
"integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==",
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@@ -323,9 +323,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.15.tgz",
|
||||
"integrity": "sha512-RWmQ/sklUN9BvGGpCDgSubhHWfAx24XDTDObup4ffvxaYsptOg2P3KG0j+1eWKLxpkX0j0uHxmpq2Z1SP/VhxA==",
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
|
||||
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
@@ -358,18 +358,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.15.tgz",
|
||||
"integrity": "sha512-DdHPwvJY0sEeN4xJU5uRLmZjgMMDIvMPniLuYzUVXj/GGzysPl0/fwt44JBkyUIzGJPV8QgHMcQdQ34XFuKTYQ==",
|
||||
"version": "7.23.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
|
||||
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.22.13",
|
||||
"@babel/generator": "^7.22.15",
|
||||
"@babel/helper-environment-visitor": "^7.22.5",
|
||||
"@babel/helper-function-name": "^7.22.5",
|
||||
"@babel/generator": "^7.23.0",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/parser": "^7.22.15",
|
||||
"@babel/types": "^7.22.15",
|
||||
"@babel/parser": "^7.23.0",
|
||||
"@babel/types": "^7.23.0",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
@@ -378,12 +378,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.15.tgz",
|
||||
"integrity": "sha512-X+NLXr0N8XXmN5ZsaQdm9U2SSC3UbIYq/doL++sueHOTisgZHoKaQtZxGuV2cUPQHMfjKEfg/g6oy7Hm6SKFtA==",
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
|
||||
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.22.5",
|
||||
"@babel/helper-validator-identifier": "^7.22.15",
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -3866,11 +3866,11 @@
|
||||
}
|
||||
},
|
||||
"@babel/generator": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz",
|
||||
"integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==",
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
|
||||
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.22.15",
|
||||
"@babel/types": "^7.23.0",
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
"@jridgewell/trace-mapping": "^0.3.17",
|
||||
"jsesc": "^2.5.1"
|
||||
@@ -3896,17 +3896,17 @@
|
||||
}
|
||||
},
|
||||
"@babel/helper-environment-visitor": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
|
||||
"integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q=="
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
|
||||
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA=="
|
||||
},
|
||||
"@babel/helper-function-name": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
|
||||
"integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
|
||||
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
|
||||
"requires": {
|
||||
"@babel/template": "^7.22.5",
|
||||
"@babel/types": "^7.22.5"
|
||||
"@babel/template": "^7.22.15",
|
||||
"@babel/types": "^7.23.0"
|
||||
}
|
||||
},
|
||||
"@babel/helper-hoist-variables": {
|
||||
@@ -3959,9 +3959,9 @@
|
||||
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw=="
|
||||
},
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz",
|
||||
"integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ=="
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A=="
|
||||
},
|
||||
"@babel/helper-validator-option": {
|
||||
"version": "7.22.15",
|
||||
@@ -3989,9 +3989,9 @@
|
||||
}
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.15.tgz",
|
||||
"integrity": "sha512-RWmQ/sklUN9BvGGpCDgSubhHWfAx24XDTDObup4ffvxaYsptOg2P3KG0j+1eWKLxpkX0j0uHxmpq2Z1SP/VhxA=="
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
|
||||
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw=="
|
||||
},
|
||||
"@babel/runtime": {
|
||||
"version": "7.22.5",
|
||||
@@ -4012,29 +4012,29 @@
|
||||
}
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.15.tgz",
|
||||
"integrity": "sha512-DdHPwvJY0sEeN4xJU5uRLmZjgMMDIvMPniLuYzUVXj/GGzysPl0/fwt44JBkyUIzGJPV8QgHMcQdQ34XFuKTYQ==",
|
||||
"version": "7.23.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
|
||||
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.22.13",
|
||||
"@babel/generator": "^7.22.15",
|
||||
"@babel/helper-environment-visitor": "^7.22.5",
|
||||
"@babel/helper-function-name": "^7.22.5",
|
||||
"@babel/generator": "^7.23.0",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/parser": "^7.22.15",
|
||||
"@babel/types": "^7.22.15",
|
||||
"@babel/parser": "^7.23.0",
|
||||
"@babel/types": "^7.23.0",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.15.tgz",
|
||||
"integrity": "sha512-X+NLXr0N8XXmN5ZsaQdm9U2SSC3UbIYq/doL++sueHOTisgZHoKaQtZxGuV2cUPQHMfjKEfg/g6oy7Hm6SKFtA==",
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
|
||||
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
|
||||
"requires": {
|
||||
"@babel/helper-string-parser": "^7.22.5",
|
||||
"@babel/helper-validator-identifier": "^7.22.15",
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
"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",
|
||||
|
||||
26
react-native-sdk/prepare_sdk.js
vendored
26
react-native-sdk/prepare_sdk.js
vendored
@@ -6,7 +6,9 @@ const packageJSON = require('../package.json');
|
||||
const SDKPackageJSON = require('./package.json');
|
||||
|
||||
const androidSourcePath = '../android/sdk/src/main/java/org/jitsi/meet/sdk';
|
||||
const androidMainSourcePath = '../android/sdk/src/main/res';
|
||||
const androidTargetPath = './android/src/main/java/org/jitsi/meet/sdk';
|
||||
const androidMainTargetPath = './android/src/main/res';
|
||||
const iosSrcPath = '../ios/sdk/src';
|
||||
const iosDestPath = './ios/src';
|
||||
|
||||
@@ -169,6 +171,30 @@ copyFolderRecursiveSync(
|
||||
`${androidSourcePath}/log`,
|
||||
`${androidTargetPath}/log`
|
||||
);
|
||||
copyFolderRecursiveSync(
|
||||
`${androidMainSourcePath}/values`,
|
||||
`${androidMainTargetPath}`
|
||||
);
|
||||
copyFolderRecursiveSync(
|
||||
`${androidMainSourcePath}/drawable-hdpi`,
|
||||
`${androidMainTargetPath}`
|
||||
);
|
||||
copyFolderRecursiveSync(
|
||||
`${androidMainSourcePath}/drawable-mdpi`,
|
||||
`${androidMainTargetPath}`
|
||||
);
|
||||
copyFolderRecursiveSync(
|
||||
`${androidMainSourcePath}/drawable-xhdpi`,
|
||||
`${androidMainTargetPath}`
|
||||
);
|
||||
copyFolderRecursiveSync(
|
||||
`${androidMainSourcePath}/drawable-xxhdpi`,
|
||||
`${androidMainTargetPath}`
|
||||
);
|
||||
copyFolderRecursiveSync(
|
||||
`${androidMainSourcePath}/drawable-xxxhdpi`,
|
||||
`${androidMainTargetPath}`
|
||||
);
|
||||
copyFolderRecursiveSync(
|
||||
`${androidSourcePath}/net`,
|
||||
`${androidTargetPath}/log`
|
||||
|
||||
15
react-native-sdk/update_dependencies.js
vendored
15
react-native-sdk/update_dependencies.js
vendored
@@ -25,7 +25,8 @@ function updateDependencies() {
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (!semver.valid(packageJSON.dependencies[key])) {
|
||||
if (!semver.valid(packageJSON.dependencies[key])
|
||||
&& packageJSON.dependencies[key] !== RNSDKpackageJSON.peerDependencies[key]) {
|
||||
packageJSON.dependencies[key] = RNSDKpackageJSON.peerDependencies[key];
|
||||
updated = true;
|
||||
|
||||
@@ -46,6 +47,18 @@ 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 || {};
|
||||
|
||||
@@ -934,3 +934,27 @@ export function createGifSentEvent() {
|
||||
action: 'gif.sent'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event which indicates the whiteboard was opened.
|
||||
*
|
||||
* @returns {Object} The event in a format suitable for sending via
|
||||
* sendAnalytics.
|
||||
*/
|
||||
export function createOpenWhiteboardEvent() {
|
||||
return {
|
||||
action: 'whiteboard.open'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event which indicates the whiteboard limit was enforced.
|
||||
*
|
||||
* @returns {Object} The event in a format suitable for sending via
|
||||
* sendAnalytics.
|
||||
*/
|
||||
export function createRestrictWhiteboardEvent() {
|
||||
return {
|
||||
action: 'whiteboard.restrict'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ 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';
|
||||
@@ -158,9 +159,10 @@ 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>) {
|
||||
export function initAnalytics(store: IStore, handlers: Array<Object>, willShowPrejoin?: boolean) {
|
||||
const { getState, dispatch } = store;
|
||||
|
||||
if (!isAnalyticsEnabled(getState) || handlers.length === 0) {
|
||||
@@ -180,8 +182,12 @@ export function initAnalytics(store: IStore, handlers: Array<Object>) {
|
||||
externalApi?: boolean;
|
||||
group?: string;
|
||||
inIframe?: boolean;
|
||||
isPromotedFromVisitor?: boolean;
|
||||
isVisitor?: boolean;
|
||||
server?: string;
|
||||
tenant?: string;
|
||||
wasLobbyVisible?: boolean;
|
||||
wasPrejoinDisplayed?: boolean;
|
||||
websocket?: boolean;
|
||||
} & typeof deploymentInfo = {};
|
||||
|
||||
@@ -207,6 +213,15 @@ export function initAnalytics(store: IStore, handlers: Array<Object>) {
|
||||
// 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) {
|
||||
|
||||
@@ -5,6 +5,7 @@ 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 {
|
||||
@@ -16,6 +17,10 @@ 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';
|
||||
@@ -81,6 +86,18 @@ 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
|
||||
@@ -97,7 +114,7 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
const result = next(action);
|
||||
|
||||
createHandlersPromise.then(handlers => {
|
||||
initAnalytics(store, handlers);
|
||||
initAnalytics(store, handlers, action.willShowPrejoin);
|
||||
});
|
||||
|
||||
return result;
|
||||
@@ -144,6 +161,14 @@ 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({
|
||||
|
||||
@@ -5,12 +5,15 @@ 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.
|
||||
@@ -104,7 +107,11 @@ 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;
|
||||
@@ -120,7 +127,18 @@ export function maybeRedirectToTokenAuthUrl(
|
||||
const room = state['features/base/conference'].room;
|
||||
const { tenant } = parseURIString(locationURL.href) || {};
|
||||
|
||||
getTokenAuthUrl(config, room, tenant, true, locationURL)
|
||||
getTokenAuthUrl(
|
||||
config,
|
||||
locationURL,
|
||||
{
|
||||
audioMuted,
|
||||
audioOnlyEnabled: audioOnlyEnabled || startAudioOnly,
|
||||
skipPrejoin: true,
|
||||
videoMuted
|
||||
},
|
||||
room,
|
||||
tenant
|
||||
)
|
||||
.then((tokenAuthServiceUrl: string | undefined) => {
|
||||
if (!tokenAuthServiceUrl) {
|
||||
logger.warn('Cannot handle login, token service URL is not set');
|
||||
|
||||
@@ -150,9 +150,20 @@ 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));
|
||||
dispatch(setRoom(room, willShowPrejoin));
|
||||
|
||||
if (!room) {
|
||||
goBackToRoot(getState(), dispatch);
|
||||
@@ -163,12 +174,10 @@ export function appNavigate(uri?: string, options: IReloadNowOptions = {}) {
|
||||
dispatch(createDesiredLocalTracks());
|
||||
dispatch(clearNotifications());
|
||||
|
||||
if (!options.hidePrejoin && isPrejoinPageEnabled(getState())) {
|
||||
if (isUnsafeRoomWarningEnabled(getState()) && isInsecureRoomName(room)) {
|
||||
navigateRoot(screen.unsafeRoomWarning);
|
||||
} else {
|
||||
navigateRoot(screen.preJoin);
|
||||
}
|
||||
if (willShowUnsafeRoomWarning) {
|
||||
navigateRoot(screen.unsafeRoomWarning);
|
||||
} else if (willShowPrejoin) {
|
||||
navigateRoot(screen.preJoin);
|
||||
} else {
|
||||
dispatch(connect());
|
||||
navigateRoot(screen.conference.root);
|
||||
|
||||
@@ -7,8 +7,7 @@ import SplashScreen from 'react-native-splash-screen';
|
||||
import BottomSheetContainer from '../../base/dialog/components/native/BottomSheetContainer';
|
||||
import DialogContainer from '../../base/dialog/components/native/DialogContainer';
|
||||
import { updateFlags } from '../../base/flags/actions';
|
||||
import { CALL_INTEGRATION_ENABLED, SERVER_URL_CHANGE_ENABLED } from '../../base/flags/constants';
|
||||
import { getFeatureFlag } from '../../base/flags/functions';
|
||||
import { CALL_INTEGRATION_ENABLED } from '../../base/flags/constants';
|
||||
import { clientResized, setSafeAreaInsets } from '../../base/responsive-ui/actions';
|
||||
import DimensionsDetector from '../../base/responsive-ui/components/DimensionsDetector.native';
|
||||
import { updateSettings } from '../../base/settings/actions';
|
||||
@@ -22,6 +21,7 @@ import { AbstractApp, IProps as AbstractAppProps } from './AbstractApp';
|
||||
import '../middlewares.native';
|
||||
import '../reducers.native';
|
||||
|
||||
|
||||
declare let __DEV__: any;
|
||||
|
||||
const { AppInfo } = NativeModules;
|
||||
@@ -111,7 +111,7 @@ export class App extends AbstractApp<IProps> {
|
||||
*/
|
||||
async _extraInit() {
|
||||
const { dispatch, getState } = this.state.store ?? {};
|
||||
const { flags = {} } = this.props;
|
||||
const { flags = {}, url, userInfo } = this.props;
|
||||
let callIntegrationEnabled = flags[CALL_INTEGRATION_ENABLED as keyof typeof flags];
|
||||
|
||||
// CallKit does not work on the simulator, make sure we disable it.
|
||||
@@ -153,22 +153,19 @@ export class App extends AbstractApp<IProps> {
|
||||
|
||||
await rootNavigationReady;
|
||||
|
||||
// Check if serverURL is configured externally and not allowed to change.
|
||||
const serverURLChangeEnabled = getState && getFeatureFlag(getState(), SERVER_URL_CHANGE_ENABLED, true);
|
||||
// Update specified server URL.
|
||||
if (typeof url !== 'undefined') {
|
||||
|
||||
if (!serverURLChangeEnabled) {
|
||||
// As serverURL is provided externally, so we push it to settings.
|
||||
if (typeof this.props.url !== 'undefined') {
|
||||
// @ts-ignore
|
||||
const { serverURL } = this.props.url;
|
||||
// @ts-ignore
|
||||
const { serverURL } = url;
|
||||
|
||||
if (typeof serverURL !== 'undefined') {
|
||||
dispatch?.(updateSettings({ serverURL }));
|
||||
}
|
||||
if (typeof serverURL !== 'undefined') {
|
||||
dispatch?.(updateSettings({ serverURL }));
|
||||
}
|
||||
}
|
||||
|
||||
dispatch?.(updateSettings(this.props.userInfo || {}));
|
||||
// @ts-ignore
|
||||
dispatch?.(updateSettings(userInfo || {}));
|
||||
|
||||
// Update settings with feature-flag.
|
||||
if (typeof callIntegrationEnabled !== 'undefined') {
|
||||
|
||||
@@ -55,8 +55,20 @@ 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, room, tenant, false, locationURL)
|
||||
return getTokenAuthUrl(
|
||||
config,
|
||||
locationURL,
|
||||
{
|
||||
audioMuted: false,
|
||||
audioOnlyEnabled: startAudioOnly,
|
||||
skipPrejoin: false,
|
||||
videoMuted: false
|
||||
},
|
||||
room,
|
||||
tenant
|
||||
)
|
||||
.then((url: string | undefined) => {
|
||||
route.href = url;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import '../analytics/middleware';
|
||||
import '../authentication/middleware';
|
||||
import '../av-moderation/middleware';
|
||||
import '../base/app/middleware';
|
||||
import '../base/conference/middleware';
|
||||
import '../base/config/middleware';
|
||||
import '../base/jwt/middleware';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import '../base/app/middleware';
|
||||
import '../base/connection/middleware';
|
||||
import '../base/i18n/middleware';
|
||||
import '../base/devices/middleware';
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -13,29 +13,65 @@ 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,
|
||||
skipPrejoin: boolean | undefined = false,
|
||||
locationURL: URL): object => {
|
||||
tenant: string | undefined): 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) {
|
||||
|
||||
@@ -14,10 +14,15 @@ 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
|
||||
@@ -25,11 +30,23 @@ 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
|
||||
locationURL: URL): Promise<string | undefined> => {
|
||||
tenant: string | undefined): Promise<string | undefined> => {
|
||||
|
||||
const {
|
||||
audioMuted = false,
|
||||
audioOnlyEnabled = false,
|
||||
skipPrejoin = false,
|
||||
videoMuted = false
|
||||
} = options;
|
||||
|
||||
let url = config.tokenAuthUrl;
|
||||
|
||||
@@ -38,7 +55,17 @@ export const getTokenAuthUrl = (
|
||||
}
|
||||
|
||||
if (url.indexOf('{state}')) {
|
||||
const state = _getTokenAuthState(roomName, tenant, skipPrejoin, locationURL);
|
||||
const state = _getTokenAuthState(
|
||||
locationURL,
|
||||
{
|
||||
audioMuted,
|
||||
audioOnlyEnabled,
|
||||
skipPrejoin,
|
||||
videoMuted
|
||||
},
|
||||
roomName,
|
||||
tenant
|
||||
);
|
||||
|
||||
// Append ios=true or android=true to the token URL.
|
||||
// @ts-ignore
|
||||
|
||||
@@ -32,10 +32,15 @@ function _cryptoRandom() {
|
||||
* 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 current location URL.
|
||||
* @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
|
||||
@@ -43,11 +48,23 @@ 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
|
||||
locationURL: URL): Promise<string | undefined> => {
|
||||
tenant: string | undefined): Promise<string | undefined> => {
|
||||
|
||||
const {
|
||||
audioMuted = false,
|
||||
audioOnlyEnabled = false,
|
||||
skipPrejoin = false,
|
||||
videoMuted = false
|
||||
} = options;
|
||||
|
||||
let url = config.tokenAuthUrl;
|
||||
|
||||
@@ -56,7 +73,17 @@ export const getTokenAuthUrl = (
|
||||
}
|
||||
|
||||
if (url.indexOf('{state}')) {
|
||||
const state = _getTokenAuthState(roomName, tenant, skipPrejoin, locationURL);
|
||||
const state = _getTokenAuthState(
|
||||
locationURL,
|
||||
{
|
||||
audioMuted,
|
||||
audioOnlyEnabled,
|
||||
skipPrejoin,
|
||||
videoMuted
|
||||
},
|
||||
roomName,
|
||||
tenant
|
||||
);
|
||||
|
||||
if (browser.isElectron()) {
|
||||
// @ts-ignore
|
||||
|
||||
@@ -13,7 +13,9 @@ 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';
|
||||
|
||||
@@ -257,6 +259,9 @@ 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!');
|
||||
@@ -270,7 +275,18 @@ function _handleLogin({ dispatch, getState }: IStore) {
|
||||
return;
|
||||
}
|
||||
|
||||
getTokenAuthUrl(config, room, tenant, true, locationURL)
|
||||
getTokenAuthUrl(
|
||||
config,
|
||||
locationURL,
|
||||
{
|
||||
audioMuted,
|
||||
audioOnlyEnabled,
|
||||
skipPrejoin: true,
|
||||
videoMuted
|
||||
},
|
||||
room,
|
||||
tenant
|
||||
)
|
||||
.then((tokenAuthServiceUrl: string | undefined) => {
|
||||
if (!tokenAuthServiceUrl) {
|
||||
logger.warn('Cannot handle login, token service URL is not set');
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { AnyAction } from 'redux';
|
||||
|
||||
import MiddlewareRegistry from '../../base/redux/MiddlewareRegistry';
|
||||
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
import { inIframe } from '../util/iframeUtils';
|
||||
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
|
||||
import logger from './logger';
|
||||
@@ -21,7 +22,9 @@ MiddlewareRegistry.register(() => (next: Function) => async (action: AnyAction)
|
||||
|
||||
switch (action.type) {
|
||||
case APP_WILL_MOUNT: {
|
||||
if ('PressureObserver' in globalThis) {
|
||||
// Disable it inside an iframe until Google fixes the origin trial for 3rd party sources:
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=1504167
|
||||
if (!inIframe() && 'PressureObserver' in globalThis) {
|
||||
pressureObserver = new window.PressureObserver(
|
||||
(records: typeof window.PressureRecord) => {
|
||||
logger.info('Compute pressure state changed:', JSON.stringify(records));
|
||||
@@ -9,7 +9,7 @@ const AVATAR_COLORS = [
|
||||
'#B23683',
|
||||
'#F96E57',
|
||||
'#4380E2',
|
||||
'#2AA076',
|
||||
'#238561',
|
||||
'#00A8B3'
|
||||
];
|
||||
const wordSplitRegex = (/\s+|\.+|_+|;+|-+|,+|\|+|\/+|\\+|"+|'+|\(+|\)+|#+|&+/);
|
||||
|
||||
@@ -510,15 +510,18 @@ 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
|
||||
* conference: JitsiConference,
|
||||
* isRedirect: boolean
|
||||
* }}
|
||||
*/
|
||||
export function conferenceWillLeave(conference?: IJitsiConference) {
|
||||
export function conferenceWillLeave(conference?: IJitsiConference, isRedirect?: boolean) {
|
||||
return {
|
||||
type: CONFERENCE_WILL_LEAVE,
|
||||
conference
|
||||
conference,
|
||||
isRedirect
|
||||
};
|
||||
}
|
||||
|
||||
@@ -897,15 +900,20 @@ 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
|
||||
* room: string,
|
||||
* willShowPrejoin: boolean
|
||||
* }}
|
||||
*/
|
||||
export function setRoom(room?: string) {
|
||||
export function setRoom(room?: string, willShowPrejoin?: boolean) {
|
||||
return {
|
||||
type: SET_ROOM,
|
||||
room
|
||||
room,
|
||||
willShowPrejoin
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1008,7 +1016,7 @@ export function redirect(vnode: string, focusJid: string, username: string) {
|
||||
}
|
||||
|
||||
dispatch(overwriteConfig(newConfig)) // @ts-ignore
|
||||
.then(() => dispatch(conferenceWillLeave(conference || joining)))
|
||||
.then(() => dispatch(conferenceWillLeave(conference || joining, true)))
|
||||
.then(() => dispatch(disconnect()))
|
||||
.then(() => dispatch(setIAmVisitor(Boolean(vnode))))
|
||||
|
||||
|
||||
@@ -246,8 +246,6 @@ 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;
|
||||
|
||||
@@ -14,6 +14,7 @@ import { reloadNow } from '../../app/actions';
|
||||
import { IStore } from '../../app/types';
|
||||
import { removeLobbyChatParticipant } from '../../chat/actions.any';
|
||||
import { openDisplayNamePrompt } from '../../display-name/actions';
|
||||
import { isVpaasMeeting } from '../../jaas/functions';
|
||||
import { showErrorNotification } from '../../notifications/actions';
|
||||
import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants';
|
||||
import { hasDisplayName } from '../../prejoin/utils';
|
||||
@@ -306,7 +307,7 @@ async function _connectionEstablished({ dispatch, getState }: IStore, next: Func
|
||||
|
||||
// if there is token auth URL defined and local participant is using jwt
|
||||
// this means it is logged in when connection is established, so we can change the state
|
||||
if (tokenAuthUrl) {
|
||||
if (tokenAuthUrl && !isVpaasMeeting(getState())) {
|
||||
let email;
|
||||
|
||||
if (getState()['features/base/jwt'].jwt) {
|
||||
|
||||
@@ -73,7 +73,6 @@ export interface IJitsiConference {
|
||||
getSsrcByTrack: Function;
|
||||
grantOwner: Function;
|
||||
isAVModerationSupported: Function;
|
||||
isCallstatsEnabled: Function;
|
||||
isE2EEEnabled: Function;
|
||||
isE2EESupported: Function;
|
||||
isEndConferenceSupported: Function;
|
||||
|
||||
@@ -157,6 +157,13 @@ export interface INoiseSuppressionConfig {
|
||||
};
|
||||
}
|
||||
|
||||
export interface IWhiteboardConfig {
|
||||
collabServerBaseUrl?: string;
|
||||
enabled?: boolean;
|
||||
limitUrl?: string;
|
||||
userLimit?: number;
|
||||
}
|
||||
|
||||
export interface IWatchRTCConfiguration {
|
||||
allowBrowserLogCollection?: boolean;
|
||||
collectionInterval?: number;
|
||||
@@ -224,28 +231,8 @@ 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;
|
||||
chromeExtensionBanner?: {
|
||||
chromeExtensionsInfo?: Array<{ id: string; path: string; }>;
|
||||
@@ -452,6 +439,7 @@ export interface IConfig {
|
||||
inviteServiceCallFlowsUrl?: string;
|
||||
inviteServiceUrl?: string;
|
||||
jaasActuatorUrl?: string;
|
||||
jaasConferenceCreatorUrl?: string;
|
||||
jaasFeedbackMetadataURL?: string;
|
||||
jaasTokenUrl?: string;
|
||||
legalUrls?: {
|
||||
@@ -513,6 +501,7 @@ export interface IConfig {
|
||||
pcStatsInterval?: number;
|
||||
peopleSearchQueryTypes?: string[];
|
||||
peopleSearchUrl?: string;
|
||||
preferBosh?: boolean;
|
||||
preferredTranscribeLanguage?: string;
|
||||
prejoinConfig?: {
|
||||
enabled?: boolean;
|
||||
@@ -571,7 +560,6 @@ export interface IConfig {
|
||||
subject?: string;
|
||||
testing?: {
|
||||
assumeBandwidth?: boolean;
|
||||
callStatsThreshold?: number;
|
||||
disableE2EE?: boolean;
|
||||
mobileXmppWsThreshold?: number;
|
||||
noAutoPlayVideo?: boolean;
|
||||
@@ -630,8 +618,5 @@ export interface IConfig {
|
||||
customUrl?: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
whiteboard?: {
|
||||
collabServerBaseUrl?: string;
|
||||
enabled?: boolean;
|
||||
};
|
||||
whiteboard?: IWhiteboardConfig;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ export default [
|
||||
'avgRtpStatsN',
|
||||
'backgroundAlpha',
|
||||
'breakoutRooms',
|
||||
'bridgeChannel',
|
||||
'buttonsWithNotifyClick',
|
||||
|
||||
/**
|
||||
@@ -54,10 +55,6 @@ export default [
|
||||
* @type string
|
||||
*/
|
||||
'callHandle',
|
||||
'callStatsConfIDNamespace',
|
||||
'callStatsConfigParams',
|
||||
'callStatsID',
|
||||
'callStatsSecret',
|
||||
|
||||
/**
|
||||
* The UUID of the CallKit call representing the conference/meeting
|
||||
@@ -74,6 +71,7 @@ export default [
|
||||
*/
|
||||
'callUUID',
|
||||
|
||||
'cameraFacingMode',
|
||||
'conferenceInfo',
|
||||
'channelLastN',
|
||||
'connectionIndicators',
|
||||
@@ -158,7 +156,6 @@ export default [
|
||||
'filmstrip',
|
||||
'firefox_fake_device',
|
||||
'flags',
|
||||
'forceJVB121Ratio',
|
||||
'forceTurnRelay',
|
||||
'gatherStats',
|
||||
'giphy',
|
||||
@@ -197,6 +194,7 @@ export default [
|
||||
'participantMenuButtonsWithNotifyClick',
|
||||
'participantsPane',
|
||||
'pcStatsInterval',
|
||||
'preferBosh',
|
||||
'prejoinConfig',
|
||||
'prejoinPageEnabled',
|
||||
'recordingService',
|
||||
|
||||
@@ -28,8 +28,6 @@ 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 };
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import { ConnectionFailedError, IIceServers } from './types';
|
||||
*/
|
||||
interface IOptions extends IConfigState {
|
||||
iceServersOverride?: IIceServers;
|
||||
preferVisitor?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +113,7 @@ export function constructOptions(state: IReduxState) {
|
||||
// redux store.
|
||||
const options: IOptions = _.cloneDeep(state['features/base/config']);
|
||||
|
||||
const { locationURL } = state['features/base/connection'];
|
||||
const { locationURL, preferVisitor } = state['features/base/connection'];
|
||||
const params = parseURLParams(locationURL || '');
|
||||
const iceServersOverride = params['iceServers.replace'];
|
||||
|
||||
@@ -120,7 +121,7 @@ export function constructOptions(state: IReduxState) {
|
||||
options.iceServersOverride = iceServersOverride;
|
||||
}
|
||||
|
||||
const { bosh } = options;
|
||||
const { bosh, preferBosh } = options;
|
||||
let { websocket } = options;
|
||||
|
||||
// TESTING: Only enable WebSocket for some percentage of users.
|
||||
@@ -130,6 +131,10 @@ export function constructOptions(state: IReduxState) {
|
||||
}
|
||||
}
|
||||
|
||||
if (preferBosh) {
|
||||
websocket = undefined;
|
||||
}
|
||||
|
||||
// WebSocket is preferred over BOSH.
|
||||
const serviceUrl = websocket || bosh;
|
||||
|
||||
@@ -151,6 +156,10 @@ export function constructOptions(state: IReduxState) {
|
||||
}
|
||||
}
|
||||
|
||||
if (preferVisitor) {
|
||||
options.preferVisitor = true;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { SET_ROOM } from '../conference/actionTypes';
|
||||
import { SET_JWT } from '../jwt/actionTypes';
|
||||
import { JitsiConnectionErrors } from '../lib-jitsi-meet';
|
||||
import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
import { assign, set } from '../redux/functions';
|
||||
@@ -26,6 +27,7 @@ export interface IConnectionState {
|
||||
error?: ConnectionFailedError;
|
||||
locationURL?: URL;
|
||||
passwordRequired?: Object;
|
||||
preferVisitor?: boolean;
|
||||
showConnectionInfo?: boolean;
|
||||
timeEstablished?: number;
|
||||
}
|
||||
@@ -49,6 +51,9 @@ ReducerRegistry.register<IConnectionState>(
|
||||
case CONNECTION_WILL_CONNECT:
|
||||
return _connectionWillConnect(state, action);
|
||||
|
||||
case SET_JWT:
|
||||
return _setJWT(state, action);
|
||||
|
||||
case SET_LOCATION_URL:
|
||||
return _setLocationURL(state, action);
|
||||
|
||||
@@ -84,6 +89,7 @@ function _connectionDisconnected(
|
||||
return assign(state, {
|
||||
connecting: undefined,
|
||||
connection: undefined,
|
||||
preferVisitor: undefined,
|
||||
timeEstablished: undefined
|
||||
});
|
||||
}
|
||||
@@ -141,7 +147,8 @@ function _connectionFailed(
|
||||
error,
|
||||
passwordRequired:
|
||||
error.name === JitsiConnectionErrors.PASSWORD_REQUIRED
|
||||
? connection : undefined
|
||||
? connection : undefined,
|
||||
preferVisitor: undefined
|
||||
});
|
||||
}
|
||||
|
||||
@@ -184,6 +191,22 @@ function _getCurrentConnection(baseConnectionState: IConnectionState): IConnecti
|
||||
return baseConnectionState.connection || baseConnectionState.connecting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces a specific redux action {@link SET_JWT} of the feature
|
||||
* base/connection.
|
||||
*
|
||||
* @param {IConnectionState} state - The redux state of the feature base/connection.
|
||||
* @param {Action} action - The Redux action SET_JWT to reduce.
|
||||
* @private
|
||||
* @returns {Object} The new state of the feature base/connection after the
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _setJWT(state: IConnectionState, { preferVisitor }: { preferVisitor: boolean; }) {
|
||||
return assign(state, {
|
||||
preferVisitor
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces a specific redux action {@link SET_LOCATION_URL} of the feature
|
||||
* base/connection.
|
||||
|
||||
@@ -43,7 +43,7 @@ const DEVICE_TYPE_TO_SETTINGS_KEYS = {
|
||||
userSelectedDeviceLabel: 'userSelectedAudioOutputDeviceLabel'
|
||||
},
|
||||
videoInput: {
|
||||
currentDeviceId: 'audioOutputDeviceId',
|
||||
currentDeviceId: 'cameraDeviceId',
|
||||
userSelectedDeviceId: 'userSelectedCameraDeviceId',
|
||||
userSelectedDeviceLabel: 'userSelectedCameraDeviceLabel'
|
||||
}
|
||||
|
||||
@@ -65,9 +65,15 @@ export const DEFAULT_LANGUAGE = 'en';
|
||||
*/
|
||||
const options: i18next.InitOptions = {
|
||||
backend: <HttpBackendOptions>{
|
||||
loadPath: (lng: string[], ns: string[]) =>
|
||||
// eslint-disable-next-line no-extra-parens
|
||||
(ns[0] === 'main' ? 'lang/{{ns}}-{{lng}}.json' : 'lang/{{ns}}.json')
|
||||
loadPath: (lng: string[], ns: string[]) => {
|
||||
switch (ns[0]) {
|
||||
case 'countries':
|
||||
case 'main':
|
||||
return 'lang/{{ns}}-{{lng}}.json';
|
||||
default:
|
||||
return 'lang/{{ns}}.json';
|
||||
}
|
||||
}
|
||||
},
|
||||
defaultNS: 'main',
|
||||
fallbackLng: DEFAULT_LANGUAGE,
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
export const MEET_FEATURES = {
|
||||
BRANDING: 'branding',
|
||||
CALENDAR: 'calendar',
|
||||
CALLSTATS: 'callstats',
|
||||
FLIP: 'flip',
|
||||
INBOUND_CALL: 'inbound-call',
|
||||
LIVESTREAMING: 'livestreaming',
|
||||
|
||||
@@ -153,6 +153,11 @@ function _setJWT(store: IStore, next: Function, action: AnyAction) {
|
||||
_overwriteLocalParticipant(
|
||||
store, { ...newUser,
|
||||
features: context.features });
|
||||
|
||||
// eslint-disable-next-line max-depth
|
||||
if (context.user && context.user.role === 'visitor') {
|
||||
action.preferVisitor = true;
|
||||
}
|
||||
} else if (jwtPayload.name || jwtPayload.picture || jwtPayload.email) {
|
||||
// there are some tokens (firebase) having picture and name on the main level.
|
||||
_overwriteLocalParticipant(store, {
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
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. Captured
|
||||
* logs are sent to CallStats.
|
||||
* Implements log storage interface from the @jitsi/logger lib.
|
||||
*/
|
||||
export default class JitsiMeetLogStorage {
|
||||
counter: number;
|
||||
@@ -33,8 +31,7 @@ export default class JitsiMeetLogStorage {
|
||||
}
|
||||
|
||||
/**
|
||||
* The JitsiMeetLogStorage is ready when the CallStats are started and
|
||||
* before refactoring the code it was after the conference has been joined.
|
||||
* The JitsiMeetLogStorage is ready when the conference has been joined.
|
||||
* A conference is considered joined when the 'conference' field is defined
|
||||
* in the base/conference state.
|
||||
*
|
||||
@@ -73,54 +70,8 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* The type of redux action which stores the log collector that will be
|
||||
* submitting the logs to CallStats.
|
||||
* submitting the logs to a service
|
||||
*
|
||||
* {
|
||||
* type: SET_LOG_COLLECTOR,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { SET_LOGGING_CONFIG, SET_LOG_COLLECTOR } from './actionTypes';
|
||||
|
||||
/**
|
||||
* Stores a {@code Logger.LogCollector} instance which will be uploading logs
|
||||
* to CallStats.
|
||||
* Stores a {@code Logger.LogCollector} instance which will be uploading logs.
|
||||
*
|
||||
* @param {Logger.LogCollector} logCollector - The log collector instance to be
|
||||
* stored in the Redux state of base/logging feature.
|
||||
|
||||
@@ -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
|
||||
// (CallStats) is stopped.
|
||||
// is stopped.
|
||||
//
|
||||
// NOTE The LogCollector is not stopped, because this event can be
|
||||
// triggered multiple times during single conference (whenever
|
||||
|
||||
@@ -10,14 +10,13 @@ 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 on CallStats)
|
||||
// Option to disable LogCollector (which stores the logs)
|
||||
// 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
|
||||
}
|
||||
};
|
||||
|
||||
@@ -23,7 +23,12 @@ import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
import { getPropertyValue } from '../settings/functions.any';
|
||||
import { TRACK_ADDED } from '../tracks/actionTypes';
|
||||
import { destroyLocalTracks } from '../tracks/actions.any';
|
||||
import { isLocalTrackMuted, isLocalVideoTrackDesktop, setTrackMuted } from '../tracks/functions.any';
|
||||
import {
|
||||
getCameraFacingMode,
|
||||
isLocalTrackMuted,
|
||||
isLocalVideoTrackDesktop,
|
||||
setTrackMuted
|
||||
} from '../tracks/functions.any';
|
||||
import { ITrack } from '../tracks/types';
|
||||
|
||||
import {
|
||||
@@ -40,7 +45,6 @@ import {
|
||||
setVideoMuted
|
||||
} from './actions';
|
||||
import {
|
||||
CAMERA_FACING_MODE,
|
||||
MEDIA_TYPE,
|
||||
SCREENSHARE_MUTISM_AUTHORITY,
|
||||
VIDEO_MUTISM_AUTHORITY
|
||||
@@ -233,7 +237,7 @@ function _setRoom({ dispatch, getState }: IStore, next: Function, action: AnyAct
|
||||
// the user i.e. the state of base/media. Eventually, practice/reality i.e.
|
||||
// the state of base/tracks will or will not agree with the desires.
|
||||
dispatch(setAudioMuted(audioMuted));
|
||||
dispatch(setCameraFacingMode(CAMERA_FACING_MODE.USER));
|
||||
dispatch(setCameraFacingMode(getCameraFacingMode(state)));
|
||||
dispatch(setVideoMuted(videoMuted));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@ import {
|
||||
Keyboard,
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
StatusBar
|
||||
StatusBar,
|
||||
ViewStyle
|
||||
} from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
|
||||
@@ -38,9 +39,9 @@ interface IProps {
|
||||
hasBottomTextInput: boolean;
|
||||
|
||||
/**
|
||||
* Is the screen rendering a tab navigator?
|
||||
* Is the screen header having an extra height?
|
||||
*/
|
||||
hasTabNavigator: boolean;
|
||||
hasExtraHeaderHeight?: boolean;
|
||||
|
||||
/**
|
||||
* Additional style to be appended to the KeyboardAvoidingView.
|
||||
@@ -54,8 +55,8 @@ const JitsiKeyboardAvoidingView = (
|
||||
children,
|
||||
contentContainerStyle,
|
||||
disableForcedKeyboardDismiss,
|
||||
hasTabNavigator,
|
||||
hasBottomTextInput,
|
||||
hasExtraHeaderHeight,
|
||||
style
|
||||
}: IProps) => {
|
||||
const headerHeight = useHeaderHeight();
|
||||
@@ -69,13 +70,13 @@ const JitsiKeyboardAvoidingView = (
|
||||
}, [ insets.bottom ]);
|
||||
|
||||
|
||||
const tabNavigatorPadding
|
||||
= hasTabNavigator ? headerHeight : 0;
|
||||
const extraHeaderHeight
|
||||
= hasExtraHeaderHeight ? headerHeight : 0;
|
||||
const extraBottomPadding
|
||||
= addBottomPadding ? bottomPadding : 0;
|
||||
const noNotchDevicePadding = extraBottomPadding || 10;
|
||||
const iosVerticalOffset
|
||||
= headerHeight + noNotchDevicePadding + tabNavigatorPadding;
|
||||
= headerHeight + noNotchDevicePadding + extraHeaderHeight;
|
||||
const androidVerticalOffset = hasBottomTextInput
|
||||
? headerHeight + Number(StatusBar.currentHeight) : headerHeight;
|
||||
|
||||
@@ -86,7 +87,7 @@ const JitsiKeyboardAvoidingView = (
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
behavior = { Platform.OS === 'ios' ? 'padding' : 'height' }
|
||||
contentContainerStyle = { contentContainerStyle }
|
||||
contentContainerStyle = { contentContainerStyle as ViewStyle }
|
||||
enabled = { true }
|
||||
keyboardVerticalOffset = {
|
||||
Platform.OS === 'ios'
|
||||
@@ -95,7 +96,7 @@ const JitsiKeyboardAvoidingView = (
|
||||
}
|
||||
onResponderRelease = { onRelease }
|
||||
onStartShouldSetResponder = { shouldSetResponse }
|
||||
style = { style }>
|
||||
style = { style as ViewStyle }>
|
||||
{ children }
|
||||
</KeyboardAvoidingView>
|
||||
);
|
||||
|
||||
@@ -40,9 +40,9 @@ interface IProps {
|
||||
hasBottomTextInput?: boolean;
|
||||
|
||||
/**
|
||||
* Is the screen rendering a tab navigator?
|
||||
* Is the screen header having an extra height?
|
||||
*/
|
||||
hasTabNavigator?: boolean;
|
||||
hasExtraHeaderHeight?: boolean;
|
||||
|
||||
/**
|
||||
* Insets for the SafeAreaView.
|
||||
@@ -61,8 +61,8 @@ const JitsiScreen = ({
|
||||
children,
|
||||
disableForcedKeyboardDismiss = false,
|
||||
footerComponent,
|
||||
hasTabNavigator = false,
|
||||
hasBottomTextInput = false,
|
||||
hasExtraHeaderHeight = false,
|
||||
safeAreaInsets = [ 'left', 'right' ],
|
||||
style
|
||||
}: IProps) => {
|
||||
@@ -72,7 +72,7 @@ const JitsiScreen = ({
|
||||
contentContainerStyle = { contentContainerStyle }
|
||||
disableForcedKeyboardDismiss = { disableForcedKeyboardDismiss }
|
||||
hasBottomTextInput = { hasBottomTextInput }
|
||||
hasTabNavigator = { hasTabNavigator }
|
||||
hasExtraHeaderHeight = { hasExtraHeaderHeight }
|
||||
style = { style }>
|
||||
<SafeAreaView
|
||||
edges = { safeAreaInsets }
|
||||
|
||||
@@ -203,6 +203,14 @@ export const SET_LOADABLE_AVATAR_URL = 'SET_LOADABLE_AVATAR_URL';
|
||||
*/
|
||||
export const LOCAL_PARTICIPANT_RAISE_HAND = 'LOCAL_PARTICIPANT_RAISE_HAND';
|
||||
|
||||
/**
|
||||
* Clear the raise hand queue.
|
||||
* {
|
||||
* type: RAISE_HAND_CLEAR
|
||||
* }
|
||||
*/
|
||||
export const RAISE_HAND_CLEAR = 'RAISE_HAND_CLEAR';
|
||||
|
||||
/**
|
||||
* Updates participant in raise hand queue.
|
||||
* {
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
PARTICIPANT_SOURCES_UPDATED,
|
||||
PARTICIPANT_UPDATED,
|
||||
PIN_PARTICIPANT,
|
||||
RAISE_HAND_CLEAR,
|
||||
RAISE_HAND_UPDATED,
|
||||
SCREENSHARE_PARTICIPANT_NAME_CHANGED,
|
||||
SET_LOADABLE_AVATAR_URL,
|
||||
@@ -629,6 +630,19 @@ export function raiseHand(enabled: boolean) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the raise hand queue.
|
||||
*
|
||||
* @returns {{
|
||||
* type: RAISE_HAND_CLEAR
|
||||
* }}
|
||||
*/
|
||||
export function raiseHandClear() {
|
||||
return {
|
||||
type: RAISE_HAND_CLEAR
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update raise hand queue of participants.
|
||||
*
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
PARTICIPANT_SOURCES_UPDATED,
|
||||
PARTICIPANT_UPDATED,
|
||||
PIN_PARTICIPANT,
|
||||
RAISE_HAND_CLEAR,
|
||||
RAISE_HAND_UPDATED,
|
||||
SCREENSHARE_PARTICIPANT_NAME_CHANGED,
|
||||
SET_LOADABLE_AVATAR_URL
|
||||
@@ -465,6 +466,12 @@ ReducerRegistry.register<IParticipantsState>('features/base/participants',
|
||||
|
||||
return { ...state };
|
||||
}
|
||||
case RAISE_HAND_CLEAR: {
|
||||
return {
|
||||
...state,
|
||||
raisedHandsQueue: []
|
||||
};
|
||||
}
|
||||
case RAISE_HAND_UPDATED: {
|
||||
return {
|
||||
...state,
|
||||
|
||||
@@ -3,7 +3,6 @@ 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';
|
||||
@@ -217,8 +216,8 @@ function ConnectionStatus({ connectionDetails, t, connectionType }: IProps) {
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function mapStateToProps(state: IReduxState) {
|
||||
const { connectionDetails, connectionType } = getConnectionData(state);
|
||||
function mapStateToProps() {
|
||||
const { connectionDetails, connectionType } = getConnectionData();
|
||||
|
||||
return {
|
||||
connectionDetails,
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
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.
|
||||
@@ -79,132 +70,15 @@ export function calculateAvatarDimensions(height: number) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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[]
|
||||
* }}
|
||||
*/
|
||||
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' ]
|
||||
};
|
||||
}
|
||||
|
||||
export function getConnectionData() {
|
||||
return {
|
||||
connectionType: CONNECTION_TYPE.NONE,
|
||||
connectionDetails: []
|
||||
|
||||
@@ -158,15 +158,13 @@ class Watermarks extends Component<IProps, State> {
|
||||
_showJitsiWatermark
|
||||
} = this.props;
|
||||
const { noMargins, t } = this.props;
|
||||
const className = `watermark ${noMargins ? 'leftwatermarknomargin' : 'leftwatermark'}`;
|
||||
const className = `watermark leftwatermark ${noMargins ? 'no-margin' : ''}`;
|
||||
|
||||
let reactElement = null;
|
||||
|
||||
if (_showJitsiWatermark) {
|
||||
const style = {
|
||||
backgroundImage: `url(${_logoUrl})`,
|
||||
maxWidth: 140,
|
||||
maxHeight: 70,
|
||||
position: _logoLink ? 'static' : 'absolute'
|
||||
} as const;
|
||||
|
||||
|
||||
@@ -3,9 +3,14 @@ import { PREJOIN_INITIALIZED } from '../../prejoin/actionTypes';
|
||||
import { setPrejoinPageVisibility } from '../../prejoin/actions';
|
||||
import { APP_WILL_MOUNT } from '../app/actionTypes';
|
||||
import { getJwtName } from '../jwt/functions';
|
||||
import { MEDIA_TYPE } from '../media/constants';
|
||||
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
import { TRACK_ADDED } from '../tracks/actionTypes';
|
||||
import { ITrack } from '../tracks/types';
|
||||
|
||||
import { updateSettings } from './actions';
|
||||
import logger from './logger';
|
||||
|
||||
|
||||
import './middleware.any';
|
||||
|
||||
@@ -27,6 +32,9 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
case PREJOIN_INITIALIZED:
|
||||
_maybeUpdateDisplayName(store);
|
||||
break;
|
||||
case TRACK_ADDED:
|
||||
_maybeUpdateDeviceId(store, action.track);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -68,3 +76,30 @@ function _maybeUpdateDisplayName({ dispatch, getState }: IStore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe update the camera or mic device id when local track is added or updated.
|
||||
*
|
||||
* @param {Store} store - The redux store.
|
||||
* @param {ITrack} track - The potential local track.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
function _maybeUpdateDeviceId({ dispatch, getState }: IStore, track: ITrack) {
|
||||
if (track.local) {
|
||||
const { cameraDeviceId, micDeviceId } = getState()['features/base/settings'];
|
||||
const deviceId = track.jitsiTrack.getDeviceId();
|
||||
|
||||
if (track.mediaType === MEDIA_TYPE.VIDEO && track.videoType === 'camera' && cameraDeviceId !== deviceId) {
|
||||
dispatch(updateSettings({
|
||||
cameraDeviceId: track.jitsiTrack.getDeviceId()
|
||||
}));
|
||||
logger.info(`switched local video device to: ${deviceId}`);
|
||||
} else if (track.mediaType === MEDIA_TYPE.AUDIO && micDeviceId !== deviceId) {
|
||||
dispatch(updateSettings({
|
||||
micDeviceId: track.jitsiTrack.getDeviceId()
|
||||
}));
|
||||
logger.info(`switched local audio input device to: ${deviceId}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,11 @@ export interface IProps extends WithTranslation {
|
||||
*/
|
||||
handleClick?: Function;
|
||||
|
||||
/**
|
||||
* Whether the button open a menu or not.
|
||||
*/
|
||||
isMenuButton?: boolean;
|
||||
|
||||
/**
|
||||
* Notify mode for `toolbarButtonClicked` event -
|
||||
* whether to only notify or to also prevent button click routine.
|
||||
@@ -102,7 +107,7 @@ export const defaultDisabledButtonStyles = {
|
||||
/**
|
||||
* An abstract implementation of a button.
|
||||
*/
|
||||
export default class AbstractButton<P extends IProps, S=any> extends Component<P, S> {
|
||||
export default class AbstractButton<P extends IProps, S = any> extends Component<P, S> {
|
||||
static defaultProps = {
|
||||
afterClick: undefined,
|
||||
disabledStyles: defaultDisabledButtonStyles,
|
||||
@@ -354,7 +359,7 @@ export default class AbstractButton<P extends IProps, S=any> extends Component<P
|
||||
|
||||
if (typeof APP !== 'undefined' && notifyMode) {
|
||||
APP.API.notifyToolbarButtonClicked(
|
||||
buttonKey, notifyMode === NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY
|
||||
buttonKey, notifyMode === NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,11 @@ interface IProps extends AbstractToolboxItemProps {
|
||||
*/
|
||||
contextMenu?: boolean;
|
||||
|
||||
/**
|
||||
* Whether the button open a menu or not.
|
||||
*/
|
||||
isMenuButton?: boolean;
|
||||
|
||||
/**
|
||||
* On key down handler.
|
||||
*/
|
||||
@@ -67,6 +72,7 @@ export default class ToolboxItem extends AbstractToolboxItem<IProps> {
|
||||
const {
|
||||
backgroundColor,
|
||||
contextMenu,
|
||||
isMenuButton,
|
||||
disabled,
|
||||
elementAfter,
|
||||
icon,
|
||||
@@ -77,8 +83,9 @@ export default class ToolboxItem extends AbstractToolboxItem<IProps> {
|
||||
toggled
|
||||
} = this.props;
|
||||
const className = showLabel ? 'overflow-menu-item' : 'toolbox-button';
|
||||
const buttonAttribute = isMenuButton ? 'aria-expanded' : 'aria-pressed';
|
||||
const props = {
|
||||
'aria-pressed': toggled,
|
||||
[buttonAttribute]: toggled,
|
||||
'aria-disabled': disabled,
|
||||
'aria-label': this.accessibilityLabel,
|
||||
className: className + (disabled ? ' disabled' : ''),
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
} from './actionTypes';
|
||||
import {
|
||||
createLocalTracksF,
|
||||
getCameraFacingMode,
|
||||
getLocalTrack,
|
||||
getLocalTracks,
|
||||
getLocalVideoTrack,
|
||||
@@ -140,6 +141,7 @@ export function createLocalTracksA(options: ITrackOptions = {}) {
|
||||
getState
|
||||
};
|
||||
const promises = [];
|
||||
const state = getState();
|
||||
|
||||
// The following executes on React Native only at the time of this
|
||||
// writing. The effort to port Web's createInitialLocalTracks
|
||||
@@ -153,7 +155,7 @@ export function createLocalTracksA(options: ITrackOptions = {}) {
|
||||
// device separately.
|
||||
for (const device of devices) {
|
||||
if (getLocalTrack(
|
||||
getState()['features/base/tracks'],
|
||||
state['features/base/tracks'],
|
||||
device as MediaType,
|
||||
/* includePending */ true)) {
|
||||
throw new Error(`Local track for ${device} already exists`);
|
||||
@@ -165,7 +167,7 @@ export function createLocalTracksA(options: ITrackOptions = {}) {
|
||||
cameraDeviceId: options.cameraDeviceId,
|
||||
devices: [ device ],
|
||||
facingMode:
|
||||
options.facingMode || CAMERA_FACING_MODE.USER,
|
||||
options.facingMode || getCameraFacingMode(state),
|
||||
micDeviceId: options.micDeviceId
|
||||
},
|
||||
store)
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
} from '../config/functions.any';
|
||||
import { JitsiTrackErrors, browser } from '../lib-jitsi-meet';
|
||||
import { gumPending } from '../media/actions';
|
||||
import { MEDIA_TYPE, MediaType, VIDEO_TYPE } from '../media/constants';
|
||||
import { CAMERA_FACING_MODE, MEDIA_TYPE, MediaType, VIDEO_TYPE } from '../media/constants';
|
||||
import { IMediaState } from '../media/reducer';
|
||||
import { IGUMPendingState } from '../media/types';
|
||||
import {
|
||||
@@ -447,3 +447,13 @@ export function logTracksForParticipant(tracksState: ITrack[], participantId: st
|
||||
|
||||
logger.debug(`${logStringPrefix}${reason ? `(reason: ${reason})` : ''}:${tracksLogMsg}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default camera facing mode.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {string} - The camera facing mode.
|
||||
*/
|
||||
export function getCameraFacingMode(state: IReduxState) {
|
||||
return state['features/base/config'].cameraFacingMode ?? CAMERA_FACING_MODE.USER;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { IStore } from '../../app/types';
|
||||
import JitsiMeetJS from '../lib-jitsi-meet';
|
||||
|
||||
import { getCameraFacingMode } from './functions.any';
|
||||
import { ITrackOptions } from './types';
|
||||
|
||||
export * from './functions.any';
|
||||
@@ -39,6 +40,7 @@ export function createLocalTracksF(options: ITrackOptions = {}, store: IStore) {
|
||||
|
||||
// Copy array to avoid mutations inside library.
|
||||
devices: options.devices?.slice(0),
|
||||
facingMode: options.facingMode || getCameraFacingMode(state),
|
||||
micDeviceId,
|
||||
resolution
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
getUserSelectedMicDeviceId
|
||||
} from '../settings/functions.web';
|
||||
|
||||
import { getCameraFacingMode } from './functions.any';
|
||||
import loadEffects from './loadEffects';
|
||||
import logger from './logger';
|
||||
import { ITrackOptions } from './types';
|
||||
@@ -82,6 +83,7 @@ export function createLocalTracksF(options: ITrackOptions = {}, store?: IStore)
|
||||
// Copy array to avoid mutations inside library.
|
||||
devices: options.devices?.slice(0),
|
||||
effects,
|
||||
facingMode: options.facingMode || getCameraFacingMode(state),
|
||||
firefox_fake_device, // eslint-disable-line camelcase
|
||||
firePermissionPromptIsShownEvent,
|
||||
micDeviceId,
|
||||
|
||||
@@ -11,7 +11,6 @@ const button = {
|
||||
|
||||
const buttonLabel = {
|
||||
...BaseTheme.typography.bodyShortBold,
|
||||
lineHeight: 14,
|
||||
textTransform: 'capitalize'
|
||||
};
|
||||
|
||||
|
||||
@@ -344,7 +344,6 @@ const ContextMenu = ({
|
||||
|
||||
if (event.key === 'Escape') {
|
||||
// Close the menu
|
||||
event.preventDefault();
|
||||
setIsHidden(true);
|
||||
|
||||
} else if (event.key === 'ArrowUp') {
|
||||
|
||||
@@ -59,13 +59,17 @@ class Chat extends Component<IProps> {
|
||||
return (
|
||||
<JitsiScreen
|
||||
disableForcedKeyboardDismiss = { true }
|
||||
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
footerComponent = { () =>
|
||||
<ChatInputBar onSend = { this._onSendMessage } />
|
||||
}
|
||||
hasBottomTextInput = { true }
|
||||
hasTabNavigator = { true }
|
||||
hasExtraHeaderHeight = { true }
|
||||
style = { styles.chatContainer }>
|
||||
{/* @ts-ignore */}
|
||||
<MessageContainer messages = { _messages } />
|
||||
<MessageRecipient privateMessageRecipient = { privateMessageRecipient } />
|
||||
<ChatInputBar onSend = { this._onSendMessage } />
|
||||
</JitsiScreen>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
import React, { Component } from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { Platform, ViewStyle } from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { Platform, View, ViewStyle } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import { IconSend } from '../../../base/icons/svg';
|
||||
import { ASPECT_RATIO_WIDE } from '../../../base/responsive-ui/constants';
|
||||
import IconButton from '../../../base/ui/components/native/IconButton';
|
||||
import Input from '../../../base/ui/components/native/Input';
|
||||
import { BUTTON_TYPES } from '../../../base/ui/constants.native';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
interface IProps extends WithTranslation {
|
||||
|
||||
/**
|
||||
* Application's aspect ratio.
|
||||
*/
|
||||
aspectRatio: Symbol;
|
||||
|
||||
/**
|
||||
* Callback to invoke on message send.
|
||||
*/
|
||||
@@ -66,11 +74,18 @@ class ChatInputBar extends Component<IProps, IState> {
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
let inputBarStyles;
|
||||
|
||||
if (this.props.aspectRatio === ASPECT_RATIO_WIDE) {
|
||||
inputBarStyles = styles.inputBarWide;
|
||||
} else {
|
||||
inputBarStyles = styles.inputBarNarrow;
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
edges = { [ 'bottom' ] }
|
||||
<View
|
||||
style = { [
|
||||
styles.inputBar,
|
||||
inputBarStyles,
|
||||
this.state.addPadding ? styles.extraBarPadding : null
|
||||
] as ViewStyle[] }>
|
||||
<Input
|
||||
@@ -88,9 +103,8 @@ class ChatInputBar extends Component<IProps, IState> {
|
||||
disabled = { !this.state.message }
|
||||
onPress = { this._onSubmit }
|
||||
src = { IconSend }
|
||||
style = { styles.sendButton }
|
||||
type = { BUTTON_TYPES.PRIMARY } />
|
||||
</SafeAreaView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -137,4 +151,19 @@ class ChatInputBar extends Component<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(ChatInputBar);
|
||||
/**
|
||||
* Maps part of the Redux state to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @private
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
const { aspectRatio } = state['features/base/responsive-ui'];
|
||||
|
||||
return {
|
||||
aspectRatio
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(ChatInputBar));
|
||||
|
||||
@@ -14,6 +14,12 @@ const recipientContainer = {
|
||||
padding: BaseTheme.spacing[2]
|
||||
};
|
||||
|
||||
const inputBar = {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between'
|
||||
};
|
||||
|
||||
/**
|
||||
* The styles of the feature chat.
|
||||
*
|
||||
@@ -116,12 +122,16 @@ export default {
|
||||
paddingBottom: 30
|
||||
},
|
||||
|
||||
inputBar: {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
marginLeft: BaseTheme.spacing[3],
|
||||
width: '100%'
|
||||
inputBarNarrow: {
|
||||
...inputBar,
|
||||
height: 112,
|
||||
marginHorizontal: BaseTheme.spacing[3]
|
||||
},
|
||||
|
||||
inputBarWide: {
|
||||
...inputBar,
|
||||
height: 88,
|
||||
marginHorizontal: BaseTheme.spacing[9]
|
||||
},
|
||||
|
||||
customInputContainer: {
|
||||
@@ -157,10 +167,6 @@ export default {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
|
||||
sendButton: {
|
||||
marginRight: BaseTheme.spacing[5]
|
||||
},
|
||||
|
||||
/**
|
||||
* Style modifier for system (error) messages.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { IStore } from '../app/types';
|
||||
import { configureInitialDevices } from '../base/devices/actions.web';
|
||||
import { configureInitialDevices, getAvailableDevices } from '../base/devices/actions.web';
|
||||
import { openDialog } from '../base/dialog/actions';
|
||||
import { getBackendSafeRoomName } from '../base/util/uri';
|
||||
|
||||
@@ -34,6 +34,18 @@ export function dismissCalendarNotification() {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Setups initial devices. Makes sure we populate availableDevices list before configuring.
|
||||
*
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
export function setupInitialDevices() {
|
||||
return async (dispatch: IStore['dispatch']) => {
|
||||
await dispatch(getAvailableDevices());
|
||||
await dispatch(configureInitialDevices());
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Init.
|
||||
*
|
||||
@@ -45,7 +57,7 @@ export function init() {
|
||||
|
||||
// XXX For web based version we use conference initialization logic
|
||||
// from the old app (at the moment of writing).
|
||||
return dispatch(configureInitialDevices()).then(
|
||||
return dispatch(setupInitialDevices()).then(
|
||||
() => APP.conference.init({
|
||||
roomName: room
|
||||
}).catch((error: Error) => {
|
||||
|
||||
@@ -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';
|
||||
import { appNavigate } from '../../../app/actions.native';
|
||||
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';
|
||||
import { setToolboxVisible } from '../../../toolbox/actions.native';
|
||||
import Toolbox from '../../../toolbox/components/native/Toolbox';
|
||||
import { isToolboxVisible } from '../../../toolbox/functions';
|
||||
import { isToolboxVisible } from '../../../toolbox/functions.native';
|
||||
import {
|
||||
AbstractConference,
|
||||
abstractMapStateToProps
|
||||
} from '../AbstractConference';
|
||||
import type { AbstractProps } from '../AbstractConference';
|
||||
import { isConnecting } from '../functions';
|
||||
import { isConnecting } from '../functions.native';
|
||||
|
||||
import AlwaysOnLabels from './AlwaysOnLabels';
|
||||
import ExpandedLabelPopup from './ExpandedLabelPopup';
|
||||
@@ -230,7 +230,9 @@ class Conference extends AbstractConference<IProps, State> {
|
||||
*/
|
||||
componentDidUpdate(prevProps: IProps) {
|
||||
const {
|
||||
_showLobby
|
||||
_audioOnlyEnabled,
|
||||
_showLobby,
|
||||
_startCarMode
|
||||
} = this.props;
|
||||
|
||||
if (!prevProps._showLobby && _showLobby) {
|
||||
@@ -238,6 +240,10 @@ class Conference extends AbstractConference<IProps, State> {
|
||||
}
|
||||
|
||||
if (prevProps._showLobby && !_showLobby) {
|
||||
if (_audioOnlyEnabled && _startCarMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
navigate(screen.conference.main);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import { getLocalizedDateFormatter } from '../base/i18n/dateUtil';
|
||||
import { translateToHTML } from '../base/i18n/functions';
|
||||
import i18next from '../base/i18n/i18next';
|
||||
import { browser } from '../base/lib-jitsi-meet';
|
||||
import { pinParticipant } from '../base/participants/actions';
|
||||
import { pinParticipant, raiseHandClear } from '../base/participants/actions';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import StateListenerRegistry from '../base/redux/StateListenerRegistry';
|
||||
import { SET_REDUCED_UI } from '../base/responsive-ui/actionTypes';
|
||||
@@ -90,6 +90,9 @@ StateListenerRegistry.register(
|
||||
// remaining pinned, since it's not destroyed across runs.
|
||||
dispatch(pinParticipant(null));
|
||||
|
||||
// Clear raised hands.
|
||||
dispatch(raiseHandClear());
|
||||
|
||||
// XXX I wonder if there is a better way to do this. At this stage
|
||||
// we do know what dialogs we want to keep but the list of those
|
||||
// we want to hide is a lot longer. Thus we take a bit of a shortcut
|
||||
@@ -174,11 +177,30 @@ function _checkIframe(state: IReduxState, dispatch: IStore['dispatch']) {
|
||||
if (inIframe() && state['features/base/config'].disableIframeAPI && !browser.isElectron()
|
||||
&& !isVpaasMeeting(state) && !allowIframe) {
|
||||
// show sticky notification and redirect in 5 minutes
|
||||
const { locationURL } = state['features/base/connection'];
|
||||
let translationKey = 'notify.disabledIframe';
|
||||
const hostname = locationURL?.hostname ?? '';
|
||||
let domain = '';
|
||||
|
||||
const mapping: Record<string, string> = {
|
||||
'8x8.vc': 'https://jaas.8x8.vc',
|
||||
'meet.jit.si': 'https://jitsi.org/jaas'
|
||||
};
|
||||
|
||||
const jaasDomain = mapping[hostname];
|
||||
|
||||
if (jaasDomain) {
|
||||
translationKey = 'notify.disabledIframeSecondary';
|
||||
domain = hostname;
|
||||
}
|
||||
|
||||
dispatch(showWarningNotification({
|
||||
description: translateToHTML(
|
||||
i18next.t.bind(i18next),
|
||||
'notify.disabledIframe',
|
||||
translationKey,
|
||||
{
|
||||
domain,
|
||||
jaasDomain,
|
||||
timeout: IFRAME_DISABLED_TIMEOUT_MINUTES
|
||||
}
|
||||
)
|
||||
|
||||
@@ -7,20 +7,12 @@ import { hideDialog } from '../../base/dialog/actions';
|
||||
import { translate } from '../../base/i18n/functions';
|
||||
import Dialog from '../../base/ui/components/web/Dialog';
|
||||
import Tabs from '../../base/ui/components/web/Tabs';
|
||||
import { THUMBNAIL_SIZE } from '../constants';
|
||||
import { obtainDesktopSources } from '../functions';
|
||||
import logger from '../logger';
|
||||
|
||||
import DesktopPickerPane from './DesktopPickerPane';
|
||||
|
||||
/**
|
||||
* The size of the requested thumbnails.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const THUMBNAIL_SIZE = {
|
||||
height: 300,
|
||||
width: 300
|
||||
};
|
||||
|
||||
/**
|
||||
* The sources polling interval in ms.
|
||||
*
|
||||
@@ -135,13 +127,6 @@ class DesktopPicker extends PureComponent<IProps, IState> {
|
||||
types: []
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores the type of the selected tab.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
_selectedTabType = DEFAULT_TAB_TYPE;
|
||||
|
||||
/**
|
||||
* Initializes a new DesktopPicker instance.
|
||||
*
|
||||
@@ -182,6 +167,7 @@ class DesktopPicker extends PureComponent<IProps, IState> {
|
||||
this._stopPolling();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
@@ -230,17 +216,20 @@ class DesktopPicker extends PureComponent<IProps, IState> {
|
||||
* Computes the selected source.
|
||||
*
|
||||
* @param {Object} sources - The available sources.
|
||||
* @param {string} selectedTab - The selected tab.
|
||||
* @returns {Object} The selectedSource value.
|
||||
*/
|
||||
_getSelectedSource(sources: any = {}) {
|
||||
_getSelectedSource(sources: any = {}, selectedTab?: string) {
|
||||
const { selectedSource } = this.state;
|
||||
|
||||
const currentSelectedTab = selectedTab ?? this.state.selectedTab;
|
||||
|
||||
/**
|
||||
* If there are no sources for this type (or no sources for any type)
|
||||
* we can't select anything.
|
||||
*/
|
||||
if (!Array.isArray(sources[this._selectedTabType as keyof typeof sources])
|
||||
|| sources[this._selectedTabType as keyof typeof sources].length <= 0) {
|
||||
if (!Array.isArray(sources[currentSelectedTab as keyof typeof sources])
|
||||
|| sources[currentSelectedTab as keyof typeof sources].length <= 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -252,12 +241,12 @@ class DesktopPicker extends PureComponent<IProps, IState> {
|
||||
* 3) The selected source is no longer available.
|
||||
*/
|
||||
if (!selectedSource // scenario 1)
|
||||
|| selectedSource.type !== this._selectedTabType // scenario 2)
|
||||
|| !sources[this._selectedTabType].some( // scenario 3)
|
||||
|| selectedSource.type !== currentSelectedTab // scenario 2)
|
||||
|| !sources[currentSelectedTab].some( // scenario 3)
|
||||
(source: any) => source.id === selectedSource.id)) {
|
||||
return {
|
||||
id: sources[this._selectedTabType][0].id,
|
||||
type: this._selectedTabType
|
||||
id: sources[currentSelectedTab][0].id,
|
||||
type: currentSelectedTab
|
||||
};
|
||||
}
|
||||
|
||||
@@ -322,13 +311,13 @@ class DesktopPicker extends PureComponent<IProps, IState> {
|
||||
_onTabSelected(id: string) {
|
||||
const { sources } = this.state;
|
||||
|
||||
this._selectedTabType = id;
|
||||
|
||||
// When we change tabs also reset the screenShareAudio state so we don't
|
||||
// use the option from one tab when sharing from another.
|
||||
this.setState({
|
||||
screenShareAudio: false,
|
||||
selectedSource: this._getSelectedSource(sources),
|
||||
selectedSource: this._getSelectedSource(sources, id),
|
||||
|
||||
// select type `window` or `screen` from id
|
||||
selectedTab: id
|
||||
});
|
||||
}
|
||||
@@ -405,23 +394,23 @@ class DesktopPicker extends PureComponent<IProps, IState> {
|
||||
*/
|
||||
_updateSources() {
|
||||
const { types } = this.state;
|
||||
const options = {
|
||||
types,
|
||||
thumbnailSize: THUMBNAIL_SIZE
|
||||
};
|
||||
|
||||
|
||||
if (types.length > 0) {
|
||||
obtainDesktopSources(
|
||||
this.state.types,
|
||||
{ thumbnailSize: THUMBNAIL_SIZE }
|
||||
)
|
||||
.then((sources: any) => {
|
||||
const selectedSource = this._getSelectedSource(sources);
|
||||
obtainDesktopSources(options)
|
||||
.then((sources: any) => {
|
||||
const selectedSource = this._getSelectedSource(sources);
|
||||
|
||||
// TODO: Maybe check if we have stopped the timer and unmounted
|
||||
// the component.
|
||||
this.setState({
|
||||
sources,
|
||||
selectedSource
|
||||
});
|
||||
})
|
||||
.catch(() => { /* ignore */ });
|
||||
this.setState({
|
||||
selectedSource,
|
||||
sources
|
||||
});
|
||||
})
|
||||
.catch((error: any) => logger.log(error));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user