Compare commits
201 Commits
7517
...
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 | ||
|
|
07bade2557 | ||
|
|
0becc890d8 | ||
|
|
a1ce6f1ce5 | ||
|
|
43a7d00c63 | ||
|
|
9c04ba767c | ||
|
|
7e1d10fb4d | ||
|
|
4ce2280e31 | ||
|
|
2918a89d35 | ||
|
|
8f1c83edfd | ||
|
|
106452d857 | ||
|
|
a4d3fb6c70 | ||
|
|
a7af01b9e3 | ||
|
|
f7f434ab55 | ||
|
|
09c0854779 | ||
|
|
b4d12d74f7 | ||
|
|
50b064907a | ||
|
|
b9d6a0f269 | ||
|
|
2414e57260 | ||
|
|
6c41ddb622 | ||
|
|
55e75d56fd | ||
|
|
32ac299422 | ||
|
|
cb7146f954 | ||
|
|
144c1ce4f4 | ||
|
|
2102d6eda1 | ||
|
|
1f8e3fe26f | ||
|
|
8b0285a9d7 | ||
|
|
b546d01c2d | ||
|
|
7bf3e7df1d | ||
|
|
f9ac965e18 | ||
|
|
d70412166c | ||
|
|
a843406cb0 | ||
|
|
58115477a2 | ||
|
|
e1dc573c3c | ||
|
|
c025102511 | ||
|
|
54d052de73 | ||
|
|
7e633f0136 | ||
|
|
4b4bc1c823 | ||
|
|
767e23f34c | ||
|
|
b003d28cc5 | ||
|
|
91c8e9bd86 | ||
|
|
1f52c0b49f | ||
|
|
16fd4d4411 | ||
|
|
b8a669ad21 | ||
|
|
f0cb33a627 | ||
|
|
b5b7019325 | ||
|
|
7ccd68eb18 | ||
|
|
44b0ac57eb | ||
|
|
a411b7c969 | ||
|
|
fc8ce532f6 | ||
|
|
ef56b3c5b6 | ||
|
|
37e13804a5 | ||
|
|
8b209b3c6e | ||
|
|
cb26042d08 | ||
|
|
2952d1cde8 | ||
|
|
8a7f456560 | ||
|
|
f74b6cd82f | ||
|
|
d04515c35a | ||
|
|
2aca0ce110 | ||
|
|
d0e49b27a1 | ||
|
|
d97c365aed | ||
|
|
8304e77a04 | ||
|
|
b1db315582 | ||
|
|
4e785dd982 | ||
|
|
40f5afcf43 | ||
|
|
de2688bb33 | ||
|
|
76db09303b | ||
|
|
ea4e20f9a7 | ||
|
|
01a74856a3 | ||
|
|
36045100bf | ||
|
|
cc344cb548 | ||
|
|
a2624952a0 | ||
|
|
b8259e00dc | ||
|
|
463c823d3b | ||
|
|
5a6f3ead5a | ||
|
|
1b4d666af3 |
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
@@ -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
@@ -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
|
||||
|
||||
@@ -82,14 +82,14 @@ dependencies {
|
||||
|
||||
if (!rootProject.ext.libreBuild) {
|
||||
// Sync with react-native-google-signin
|
||||
implementation 'com.google.android.gms:play-services-auth:19.2.0'
|
||||
implementation 'com.google.android.gms:play-services-auth:20.5.0'
|
||||
|
||||
// Firebase
|
||||
// - Crashlytics
|
||||
// - Dynamic Links
|
||||
implementation 'com.google.firebase:firebase-analytics:17.5.0'
|
||||
implementation 'com.google.firebase:firebase-crashlytics:17.2.1'
|
||||
implementation 'com.google.firebase:firebase-dynamic-links:19.1.0'
|
||||
implementation 'com.google.firebase:firebase-analytics:21.3.0'
|
||||
implementation 'com.google.firebase:firebase-crashlytics:18.4.3'
|
||||
implementation 'com.google.firebase:firebase-dynamic-links:21.1.0'
|
||||
}
|
||||
|
||||
implementation project(':sdk')
|
||||
|
||||
@@ -152,7 +152,6 @@ public class MainActivity extends JitsiMeetActivity {
|
||||
= new JitsiMeetConferenceOptions.Builder()
|
||||
.setServerURL(buildURL(defaultURL))
|
||||
.setFeatureFlag("welcomepage.enabled", true)
|
||||
.setFeatureFlag("call-integration.enabled", false)
|
||||
.setFeatureFlag("resolution", 360)
|
||||
.setFeatureFlag("server-url-change.enabled", !configurationByRestrictions)
|
||||
.build();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -11,8 +11,8 @@ buildscript {
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.3.1'
|
||||
classpath 'com.google.gms:google-services:4.3.14'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2'
|
||||
classpath 'com.google.gms:google-services:4.4.0'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.9'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
168
conference.js
@@ -65,7 +65,11 @@ import {
|
||||
updateDeviceList
|
||||
} from './react/features/base/devices/actions.web';
|
||||
import {
|
||||
areDevicesDifferent,
|
||||
filterIgnoredDevices,
|
||||
flattenAvailableDevices,
|
||||
getDefaultDeviceId,
|
||||
logDevices,
|
||||
setAudioOutputDeviceId
|
||||
} from './react/features/base/devices/functions.web';
|
||||
import {
|
||||
@@ -150,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';
|
||||
@@ -632,7 +636,7 @@ export default {
|
||||
// so that the user can try unmute later on and add audio/video
|
||||
// to the conference
|
||||
if (!tracks.find(t => t.isAudioTrack())) {
|
||||
this.setAudioMuteStatus(true);
|
||||
this.updateAudioIconEnabled();
|
||||
}
|
||||
|
||||
if (!tracks.find(t => t.isVideoTrack())) {
|
||||
@@ -714,8 +718,6 @@ export default {
|
||||
};
|
||||
|
||||
if (isPrejoinPageVisible(state)) {
|
||||
APP.store.dispatch(makePrecallTest(this._getConferenceOptions()));
|
||||
|
||||
const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(initialOptions);
|
||||
const localTracks = await tryCreateLocalTracks;
|
||||
|
||||
@@ -841,7 +843,7 @@ export default {
|
||||
// This will only modify base/media.audio.muted which is then synced
|
||||
// up with the track at the end of local tracks initialization.
|
||||
muteLocalAudio(mute);
|
||||
this.setAudioMuteStatus(mute);
|
||||
this.updateAudioIconEnabled();
|
||||
|
||||
return;
|
||||
} else if (this.isLocalAudioMuted() === mute) {
|
||||
@@ -1035,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.
|
||||
*
|
||||
@@ -1057,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();
|
||||
@@ -1390,7 +1374,7 @@ export default {
|
||||
APP.store.dispatch(
|
||||
replaceLocalTrack(oldTrack, newTrack, room))
|
||||
.then(() => {
|
||||
this.setAudioMuteStatus(this.isLocalAudioMuted());
|
||||
this.updateAudioIconEnabled();
|
||||
})
|
||||
.then(resolve)
|
||||
.catch(reject)
|
||||
@@ -2045,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}`);
|
||||
|
||||
@@ -2103,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}`);
|
||||
@@ -2189,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);
|
||||
});
|
||||
}
|
||||
@@ -2203,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.
|
||||
@@ -2241,19 +2182,28 @@ export default {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async _onDeviceListChanged(devices) {
|
||||
const oldDevices = APP.store.getState()['features/base/devices'].availableDevices;
|
||||
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
|
||||
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
|
||||
const state = APP.store.getState();
|
||||
const { filteredDevices, ignoredDevices } = filterIgnoredDevices(devices);
|
||||
const oldDevices = state['features/base/devices'].availableDevices;
|
||||
|
||||
APP.store.dispatch(updateDeviceList(devices));
|
||||
if (!areDevicesDifferent(flattenAvailableDevices(oldDevices), filteredDevices)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
logDevices(ignoredDevices, 'Ignored devices on device list changed:');
|
||||
|
||||
const localAudio = getLocalJitsiAudioTrack(state);
|
||||
const localVideo = getLocalJitsiVideoTrack(state);
|
||||
|
||||
APP.store.dispatch(updateDeviceList(filteredDevices));
|
||||
|
||||
// Firefox users can choose their preferred device in the gUM prompt. In that case
|
||||
// we should respect that and not attempt to switch to the preferred device from
|
||||
// our settings.
|
||||
const newLabelsOnly = mediaDeviceHelper.newDeviceListAddedLabelsOnly(oldDevices, devices);
|
||||
const newLabelsOnly = mediaDeviceHelper.newDeviceListAddedLabelsOnly(oldDevices, filteredDevices);
|
||||
const newDevices
|
||||
= mediaDeviceHelper.getNewMediaDevicesAfterDeviceListChanged(
|
||||
devices,
|
||||
filteredDevices,
|
||||
localVideo,
|
||||
localAudio,
|
||||
newLabelsOnly);
|
||||
@@ -2372,21 +2322,17 @@ 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises)
|
||||
.then(() => {
|
||||
APP.UI.onAvailableDevicesChanged(devices);
|
||||
APP.UI.onAvailableDevicesChanged(filteredDevices);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -2432,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();
|
||||
@@ -2449,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));
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -2485,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 = () => {
|
||||
@@ -2662,15 +2617,6 @@ export default {
|
||||
APP.UI.setVideoMuted(this.getMyUserId());
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the audio muted status.
|
||||
*
|
||||
* @param {boolean} muted - New muted status.
|
||||
*/
|
||||
setAudioMuteStatus(muted) {
|
||||
APP.UI.setAudioMuted(this.getMyUserId(), muted);
|
||||
},
|
||||
|
||||
/**
|
||||
* Dispatches the passed in feedback for submission. The submitted score
|
||||
* should be a number inclusively between 1 through 5, or -1 for no score.
|
||||
|
||||
189
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
|
||||
@@ -588,7 +639,7 @@ var config = {
|
||||
// },
|
||||
|
||||
// Configs for the lobby screen.
|
||||
// lobby {
|
||||
// lobby: {
|
||||
// // If Lobby is enabled, it starts knocking automatically. Replaces `autoKnockLobby`.
|
||||
// autoKnock: false,
|
||||
// // Enables the lobby chat. Replaces `enableLobbyChat`.
|
||||
@@ -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,
|
||||
|
||||
@@ -1298,6 +1322,16 @@ var config = {
|
||||
// A list of images that can be used as video backgrounds.
|
||||
// When this field is present, the default images will be replaced with those provided.
|
||||
virtualBackgrounds: ['https://example.com/img.jpg'],
|
||||
// Object containing customized icons that should replace the default ones.
|
||||
// The keys need to be the exact same icon names used in here:
|
||||
// https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/icons/svg/index.ts
|
||||
// To avoid having the icons trimmed or displayed in an unexpected way, please provide svg
|
||||
// files containing svg xml icons in the size that the default icons come in.
|
||||
customIcons: {
|
||||
IconArrowUp: 'https://example.com/arrow-up.svg',
|
||||
IconDownload: 'https://example.com/download.svg',
|
||||
IconRemoteControlStart: 'https://example.com/remote-start.svg',
|
||||
},
|
||||
// Object containing a theme's properties. It also supports partial overwrites of the main theme.
|
||||
// For a list of all possible theme tokens and their current defaults, please check:
|
||||
// https://github.com/jitsi/jitsi-meet/tree/master/resources/custom-theme/custom-theme.json
|
||||
@@ -1431,6 +1465,31 @@ var config = {
|
||||
// dialInConfCodeUrl is the conference mapper converting a meeting id to a PIN used for dial-in
|
||||
// or the other way around (more info in resources/cloud-api.swagger)
|
||||
|
||||
// You can use external service for authentication that will redirect back passing a jwt token
|
||||
// You can use tokenAuthUrl config to point to a URL of such service.
|
||||
// The URL for the service supports few params which will be filled in by the code.
|
||||
// tokenAuthUrl:
|
||||
// 'https://myservice.com/auth/{room}?code_challenge_method=S256&code_challenge={code_challenge}&state={state}'
|
||||
// Supported parameters in tokenAuthUrl:
|
||||
// {room} - will be replaced with the room name
|
||||
// {code_challenge} - (A web only). A oauth 2.0 code challenge that will be sent to the service. See:
|
||||
// https://datatracker.ietf.org/doc/html/rfc7636. The code verifier will be saved in the sessionStorage
|
||||
// under key: 'code_verifier'.
|
||||
// {state} - A json with the current state before redirecting. Keys that are included in the state:
|
||||
// - room (The current room name as shown in the address bar)
|
||||
// - roomSafe (the backend safe room name to use (lowercase), that is passed to the backend)
|
||||
// - tenant (The tenant if any)
|
||||
// - config.xxx (all config overrides)
|
||||
// - interfaceConfig.xxx (all interfaceConfig overrides)
|
||||
// - ios=true (in case ios mobile app is used)
|
||||
// - android=true (in case android mobile app is used)
|
||||
// - electron=true (when web is loaded in electron app)
|
||||
// If there is a logout service you can specify its URL with:
|
||||
// tokenLogoutUrl: 'https://myservice.com/logout'
|
||||
// You can enable tokenAuthUrlAutoRedirect which will detect that you have logged in successfully before
|
||||
// and will automatically redirect to the token service to get the token for the meeting.
|
||||
// tokenAuthUrlAutoRedirect: false
|
||||
|
||||
// List of undocumented settings used in jitsi-meet
|
||||
/**
|
||||
_immediateReloadThreshold
|
||||
@@ -1450,9 +1509,6 @@ var config = {
|
||||
peopleSearchQueryTypes
|
||||
peopleSearchUrl
|
||||
requireDisplayName
|
||||
tokenAuthUrl
|
||||
tokenAuthUrlAutoRedirect
|
||||
tokenLogoutUrl
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -1467,8 +1523,6 @@ var config = {
|
||||
_peerConnStatusOutOfLastNTimeout
|
||||
_peerConnStatusRtcMuteTimeout
|
||||
avgRtpStatsN
|
||||
callStatsConfIDNamespace
|
||||
callStatsCustomScriptUrl
|
||||
desktopSharingSources
|
||||
disableAEC
|
||||
disableAGC
|
||||
@@ -1477,7 +1531,6 @@ var config = {
|
||||
disableLocalStats
|
||||
disableNS
|
||||
enableTalkWhileMuted
|
||||
forceJVB121Ratio
|
||||
forceTurnRelay
|
||||
hiddenDomain
|
||||
hiddenFromRecorderFeatureEnabled
|
||||
@@ -1501,6 +1554,7 @@ var config = {
|
||||
*/
|
||||
// notifications: [
|
||||
// 'connection.CONNFAIL', // shown when the connection fails,
|
||||
// 'dialog.cameraConstraintFailedError', // shown when the camera failed
|
||||
// 'dialog.cameraNotSendingData', // shown when there's no feed from user's camera
|
||||
// 'dialog.kickTitle', // shown when user has been kicked
|
||||
// 'dialog.liveStreaming', // livestreaming notifications (pending, on, off, limits)
|
||||
@@ -1511,6 +1565,7 @@ var config = {
|
||||
// 'dialog.recording', // recording notifications (pending, on, off, limits)
|
||||
// 'dialog.remoteControlTitle', // remote control notifications (allowed, denied, start, stop, error)
|
||||
// 'dialog.reservationError',
|
||||
// 'dialog.screenSharingFailedTitle', // shown when the screen sharing failed
|
||||
// 'dialog.serviceUnavailable', // shown when server is not reachable
|
||||
// 'dialog.sessTerminated', // shown when there is a failed conference session
|
||||
// 'dialog.sessionRestarted', // show when a client reload is initiated because of bridge migration
|
||||
@@ -1523,37 +1578,45 @@ var config = {
|
||||
// 'liveStreaming.unavailableTitle', // shown when livestreaming service is not reachable
|
||||
// 'lobby.joinRejectedMessage', // shown when while in a lobby, user's request to join is rejected
|
||||
// 'lobby.notificationTitle', // shown when lobby is toggled and when join requests are allowed / denied
|
||||
// 'notify.audioUnmuteBlockedTitle', // shown when mic unmute blocked
|
||||
// 'notify.chatMessages', // shown when receiving chat messages while the chat window is closed
|
||||
// 'notify.disconnected', // shown when a participant has left
|
||||
// 'notify.connectedOneMember', // show when a participant joined
|
||||
// 'notify.connectedTwoMembers', // show when two participants joined simultaneously
|
||||
// 'notify.connectedThreePlusMembers', // show when more than 2 participants joined simultaneously
|
||||
// 'notify.leftOneMember', // show when a participant left
|
||||
// 'notify.leftTwoMembers', // show when two participants left simultaneously
|
||||
// 'notify.leftThreePlusMembers', // show when more than 2 participants left simultaneously
|
||||
// 'notify.grantedTo', // shown when moderator rights were granted to a participant
|
||||
// 'notify.connectedTwoMembers', // show when two participants joined simultaneously
|
||||
// 'notify.dataChannelClosed', // shown when the bridge channel has been disconnected
|
||||
// 'notify.hostAskedUnmute', // shown to participant when host asks them to unmute
|
||||
// 'notify.invitedOneMember', // shown when 1 participant has been invited
|
||||
// 'notify.invitedThreePlusMembers', // shown when 3+ participants have been invited
|
||||
// 'notify.invitedTwoMembers', // shown when 2 participants have been invited
|
||||
// 'notify.kickParticipant', // shown when a participant is kicked
|
||||
// 'notify.leftOneMember', // show when a participant left
|
||||
// 'notify.leftThreePlusMembers', // show when more than 2 participants left simultaneously
|
||||
// 'notify.leftTwoMembers', // show when two participants left simultaneously
|
||||
// 'notify.linkToSalesforce', // shown when joining a meeting with salesforce integration
|
||||
// 'notify.moderationStartedTitle', // shown when AV moderation is activated
|
||||
// 'notify.moderationStoppedTitle', // shown when AV moderation is deactivated
|
||||
// 'notify.localRecordingStarted', // shown when the local recording has been started
|
||||
// 'notify.localRecordingStopped', // shown when the local recording has been stopped
|
||||
// 'notify.moderationInEffectCSTitle', // shown when user attempts to share content during AV moderation
|
||||
// 'notify.moderationInEffectTitle', // shown when user attempts to unmute audio during AV moderation
|
||||
// 'notify.moderationInEffectVideoTitle', // shown when user attempts to enable video during AV moderation
|
||||
// 'notify.moderationInEffectCSTitle', // shown when user attempts to share content during AV moderation
|
||||
// 'notify.moderator', // shown when user gets moderator privilege
|
||||
// 'notify.mutedRemotelyTitle', // shown when user is muted by a remote party
|
||||
// 'notify.mutedTitle', // shown when user has been muted upon joining,
|
||||
// 'notify.newDeviceAudioTitle', // prompts the user to use a newly detected audio device
|
||||
// 'notify.newDeviceCameraTitle', // prompts the user to use a newly detected camera
|
||||
// 'notify.noiseSuppressionFailedTitle', // shown when failed to start noise suppression
|
||||
// 'notify.participantWantsToJoin', // shown when lobby is enabled and participant requests to join meeting
|
||||
// 'notify.participantsWantToJoin', // shown when lobby is enabled and participants request to join meeting
|
||||
// 'notify.passwordRemovedRemotely', // shown when a password has been removed remotely
|
||||
// 'notify.passwordSetRemotely', // shown when a password has been set remotely
|
||||
// 'notify.raisedHand', // shown when a partcipant used raise hand,
|
||||
// 'notify.screenShareNoAudio', // shown when the audio could not be shared for the selected screen
|
||||
// 'notify.screenSharingAudioOnlyTitle', // shown when the best performance has been affected by screen sharing
|
||||
// 'notify.selfViewTitle', // show "You can always un-hide the self-view from settings"
|
||||
// 'notify.startSilentTitle', // shown when user joined with no audio
|
||||
// 'notify.suboptimalExperienceTitle', // show the browser warning
|
||||
// 'notify.unmute', // shown to moderator when user raises hand during AV moderation
|
||||
// 'notify.videoMutedRemotelyTitle', // shown when user's video is muted by a remote party,
|
||||
// 'notify.videoUnmuteBlockedTitle', // shown when camera unmute and desktop sharing are blocked
|
||||
// 'prejoin.errorDialOut',
|
||||
// 'prejoin.errorDialOutDisconnected',
|
||||
// 'prejoin.errorDialOutFailed',
|
||||
@@ -1633,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',
|
||||
// },
|
||||
|
||||
@@ -1653,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 {
|
||||
|
||||
@@ -154,17 +154,17 @@ $reactionCount: 20;
|
||||
}
|
||||
|
||||
70% {
|
||||
transform: translate(40px, -70vh) scale(1.5);
|
||||
transform: translate(40px, -70dvh) scale(1.5);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: translate(40px, -70vh) scale(1.5);
|
||||
transform: translate(40px, -70dvh) scale(1.5);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translate(140px, -50vh) scale(1);
|
||||
transform: translate(140px, -50dvh) scale(1);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@@ -187,17 +187,17 @@ $reactionCount: 20;
|
||||
}
|
||||
|
||||
70% {
|
||||
transform: translate(#{$topX}px, -#{$topY}vh) scale(1.5);
|
||||
transform: translate(#{$topX}px, -#{$topY}dvh) scale(1.5);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: translate(#{$topX}px, -#{$topY}vh) scale(1.5);
|
||||
transform: translate(#{$topX}px, -#{$topY}dvh) scale(1.5);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translate(#{$bottomX}px, -#{$bottomY}vh) scale(1);
|
||||
transform: translate(#{$bottomX}px, -#{$bottomY}dvh) scale(1);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,10 +266,10 @@
|
||||
#avatarContainer {
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
height: 50vh;
|
||||
margin-top: 25vh;
|
||||
height: 50dvh;
|
||||
margin-top: 25dvh;
|
||||
overflow: hidden;
|
||||
width: 50vh;
|
||||
width: 50dvh;
|
||||
|
||||
#avatar {
|
||||
height: 100%;
|
||||
|
||||
@@ -10,7 +10,7 @@ body.welcome-page {
|
||||
flex-direction: column;
|
||||
font-family: $welcomePageFontFamily;
|
||||
justify-content: space-between;
|
||||
min-height: 100vh;
|
||||
min-height: 100dvh;
|
||||
position: relative;
|
||||
|
||||
.header {
|
||||
@@ -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,6 +1,6 @@
|
||||
.deep-linking-mobile {
|
||||
background-color: #fff;
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
width: 100vw;
|
||||
|
||||
2
debian/jitsi-meet-tokens.postinst
vendored
@@ -39,7 +39,7 @@ case "$1" in
|
||||
echo "Application secret is mandatory"
|
||||
fi
|
||||
# Not allowed unix special characters in secret: /, \, ", ', `
|
||||
if echo "$RET" | grep -q '[/\\\"\`]' ; then
|
||||
if echo "$RET" | grep -q "[/\\\"\`\']" ; then
|
||||
echo "Application secret contains invalid characters: /, \\, \", ', \`"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
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/
|
||||
|
||||
@@ -43,8 +43,8 @@ server {
|
||||
}
|
||||
}
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name jitsi-meet.example.com;
|
||||
|
||||
# Mozilla Guideline v5.4, nginx 1.17.7, OpenSSL 1.1.1d, intermediate configuration
|
||||
|
||||
BIN
favicon.ico
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
13
images/favicon.svg
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
@@ -107,8 +107,8 @@ var interfaceConfig = {
|
||||
// Names of browsers which should show a warning stating the current browser
|
||||
// has a suboptimal experience. Browsers which are not listed as optimal or
|
||||
// unsupported are considered suboptimal. Valid values are:
|
||||
// chrome, chromium, edge, electron, firefox, nwjs, opera, safari
|
||||
OPTIMAL_BROWSERS: [ 'chrome', 'chromium', 'firefox', 'nwjs', 'electron', 'safari' ],
|
||||
// chrome, chromium, electron, firefox , safari, webkit
|
||||
OPTIMAL_BROWSERS: [ 'chrome', 'chromium', 'firefox', 'electron', 'safari', 'webkit' ],
|
||||
|
||||
POLICY_LOGO: null,
|
||||
PROVIDER_NAME: 'Jitsi',
|
||||
|
||||
15
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.
|
||||
@@ -46,7 +43,6 @@ target 'JitsiMeetSDK' do
|
||||
|
||||
pod 'CocoaLumberjack', '3.7.2'
|
||||
pod 'ObjectiveDropboxOfficial', '6.2.3'
|
||||
pod 'JitsiWebRTC', '~> 111.0.0'
|
||||
end
|
||||
|
||||
target 'JitsiMeetSDKLite' do
|
||||
@@ -57,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
|
||||
@@ -86,6 +82,7 @@ post_install do |installer|
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['SUPPORTS_MACCATALYST'] = 'NO'
|
||||
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.4'
|
||||
config.build_settings['OTHER_SWIFT_FLAGS'] = '$(inherited) -no-verify-emitted-module-interface'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
583
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.11)
|
||||
- FBReactNativeSpec (0.69.11):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTRequired (= 0.69.11)
|
||||
- RCTTypeSafety (= 0.69.11)
|
||||
- React-Core (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- ReactCommon/turbomodule/core (= 0.69.11)
|
||||
- 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.11)
|
||||
- RCTTypeSafety (0.69.11):
|
||||
- FBLazyVector (= 0.69.11)
|
||||
- RCTRequired (= 0.69.11)
|
||||
- React-Core (= 0.69.11)
|
||||
- React (0.69.11):
|
||||
- React-Core (= 0.69.11)
|
||||
- React-Core/DevSupport (= 0.69.11)
|
||||
- React-Core/RCTWebSocket (= 0.69.11)
|
||||
- React-RCTActionSheet (= 0.69.11)
|
||||
- React-RCTAnimation (= 0.69.11)
|
||||
- React-RCTBlob (= 0.69.11)
|
||||
- React-RCTImage (= 0.69.11)
|
||||
- React-RCTLinking (= 0.69.11)
|
||||
- React-RCTNetwork (= 0.69.11)
|
||||
- React-RCTSettings (= 0.69.11)
|
||||
- React-RCTText (= 0.69.11)
|
||||
- React-RCTVibration (= 0.69.11)
|
||||
- React-bridging (0.69.11):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-callinvoker (0.69.11)
|
||||
- React-Codegen (0.69.11):
|
||||
- FBReactNativeSpec (= 0.69.11)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTRequired (= 0.69.11)
|
||||
- RCTTypeSafety (= 0.69.11)
|
||||
- React-Core (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsiexecutor (= 0.69.11)
|
||||
- ReactCommon/turbomodule/core (= 0.69.11)
|
||||
- React-Core (0.69.11):
|
||||
- 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.11)
|
||||
- React-cxxreact (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsiexecutor (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- 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.11):
|
||||
- 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.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsiexecutor (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- 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.11):
|
||||
- React-Core/Default (0.70.14):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-cxxreact (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsiexecutor (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- 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.11):
|
||||
- React-Core/DevSupport (0.70.14):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default (= 0.69.11)
|
||||
- React-Core/RCTWebSocket (= 0.69.11)
|
||||
- React-cxxreact (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsiexecutor (= 0.69.11)
|
||||
- React-jsinspector (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- 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.11):
|
||||
- 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.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsiexecutor (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- 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.11):
|
||||
- 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.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsiexecutor (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- 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.11):
|
||||
- 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.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsiexecutor (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- 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.11):
|
||||
- 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.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsiexecutor (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- 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.11):
|
||||
- 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.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsiexecutor (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- 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.11):
|
||||
- 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.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsiexecutor (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- 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.11):
|
||||
- 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.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsiexecutor (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- 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.11):
|
||||
- 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.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsiexecutor (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- 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.11):
|
||||
- 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.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsiexecutor (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- 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.11):
|
||||
- React-Core/RCTWebSocket (0.70.14):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default (= 0.69.11)
|
||||
- React-cxxreact (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsiexecutor (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- 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.11):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.69.11)
|
||||
- React-Codegen (= 0.69.11)
|
||||
- React-Core/CoreModulesHeaders (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-RCTImage (= 0.69.11)
|
||||
- ReactCommon/turbomodule/core (= 0.69.11)
|
||||
- React-cxxreact (0.69.11):
|
||||
- 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.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-jsinspector (= 0.69.11)
|
||||
- React-logger (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- React-runtimeexecutor (= 0.69.11)
|
||||
- React-jsi (0.69.11):
|
||||
- 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.11)
|
||||
- React-jsi/Default (0.69.11):
|
||||
- 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.11):
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-jsiexecutor (0.70.14):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-cxxreact (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- React-jsinspector (0.69.11)
|
||||
- React-logger (0.69.11):
|
||||
- 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.11)
|
||||
- React-RCTActionSheet (0.69.11):
|
||||
- React-Core/RCTActionSheetHeaders (= 0.69.11)
|
||||
- React-RCTAnimation (0.69.11):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.69.11)
|
||||
- React-Codegen (= 0.69.11)
|
||||
- React-Core/RCTAnimationHeaders (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- ReactCommon/turbomodule/core (= 0.69.11)
|
||||
- React-RCTBlob (0.69.11):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Codegen (= 0.69.11)
|
||||
- React-Core/RCTBlobHeaders (= 0.69.11)
|
||||
- React-Core/RCTWebSocket (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-RCTNetwork (= 0.69.11)
|
||||
- ReactCommon/turbomodule/core (= 0.69.11)
|
||||
- React-RCTImage (0.69.11):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.69.11)
|
||||
- React-Codegen (= 0.69.11)
|
||||
- React-Core/RCTImageHeaders (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-RCTNetwork (= 0.69.11)
|
||||
- ReactCommon/turbomodule/core (= 0.69.11)
|
||||
- React-RCTLinking (0.69.11):
|
||||
- React-Codegen (= 0.69.11)
|
||||
- React-Core/RCTLinkingHeaders (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- ReactCommon/turbomodule/core (= 0.69.11)
|
||||
- React-RCTNetwork (0.69.11):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.69.11)
|
||||
- React-Codegen (= 0.69.11)
|
||||
- React-Core/RCTNetworkHeaders (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- ReactCommon/turbomodule/core (= 0.69.11)
|
||||
- React-RCTSettings (0.69.11):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.69.11)
|
||||
- React-Codegen (= 0.69.11)
|
||||
- React-Core/RCTSettingsHeaders (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- ReactCommon/turbomodule/core (= 0.69.11)
|
||||
- React-RCTText (0.69.11):
|
||||
- React-Core/RCTTextHeaders (= 0.69.11)
|
||||
- React-RCTVibration (0.69.11):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Codegen (= 0.69.11)
|
||||
- React-Core/RCTVibrationHeaders (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- ReactCommon/turbomodule/core (= 0.69.11)
|
||||
- React-runtimeexecutor (0.69.11):
|
||||
- React-jsi (= 0.69.11)
|
||||
- ReactCommon/turbomodule/core (0.69.11):
|
||||
- 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.11)
|
||||
- React-callinvoker (= 0.69.11)
|
||||
- React-Core (= 0.69.11)
|
||||
- React-cxxreact (= 0.69.11)
|
||||
- React-jsi (= 0.69.11)
|
||||
- React-logger (= 0.69.11)
|
||||
- React-perflogger (= 0.69.11)
|
||||
- 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):
|
||||
@@ -503,7 +503,6 @@ DEPENDENCIES:
|
||||
- Firebase/DynamicLinks (~> 8.0)
|
||||
- "giphy-react-native-sdk (from `../node_modules/@giphy/react-native-sdk`)"
|
||||
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
||||
- JitsiWebRTC (~> 111.0.0)
|
||||
- ObjectiveDropboxOfficial (= 6.2.3)
|
||||
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
|
||||
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
|
||||
@@ -710,8 +709,8 @@ SPEC CHECKSUMS:
|
||||
boost: a7c83b31436843459a1961bfd74b96033dc77234
|
||||
CocoaLumberjack: b7e05132ff94f6ae4dfa9d5bce9141893a21d9da
|
||||
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
|
||||
FBLazyVector: 5c0975e66853436589eae7542f4b956c7e2ef465
|
||||
FBReactNativeSpec: bb062293e84c33200005312d1807d8cb94a0d66a
|
||||
FBLazyVector: efad4471d02263013cfcb7a2f75de6ac7565692f
|
||||
FBReactNativeSpec: 9cd9542bfdcc64e07bc649f809dd621876f78619
|
||||
Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d
|
||||
FirebaseAnalytics: 7761cbadb00a717d8d0939363eb46041526474fa
|
||||
FirebaseCore: 5743c5785c074a794d35f2fff7ecc254a91e08b1
|
||||
@@ -722,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: 8e9a57dddc8f8e9e816c67c2d2537271a997137a
|
||||
RCTTypeSafety: 2b19e268e2036a2c2f6db6deb1ac03e28b1d607a
|
||||
React: f9478e6390f177ee6b67b87a3c6afea42b39523e
|
||||
React-bridging: d405ecd3ff80e1d0a4059a11063eaa9ed7a00c58
|
||||
React-callinvoker: c8ffa61f3f06f486ba6647769fc98f19e25d165a
|
||||
React-Codegen: 73acfdac1495b91ad5efdd3ab005568263c5def6
|
||||
React-Core: 7b7c75af4b73fe0ed4e5c3cdb7d79979e81148dc
|
||||
React-CoreModules: cd6e7efb38162884f08c7afa16fffaf15ff28ae4
|
||||
React-cxxreact: 51157cc600c9f436a7e623913a03b775305ef86c
|
||||
React-jsi: 3eeb345c4828d7b132fd38064a305f31b46d4ec3
|
||||
React-jsiexecutor: 5813455a4a908fb7284aa13307a9e0386e93b0bb
|
||||
React-jsinspector: 9ca5bf73ed0a195397e45fdbcd507cf7d503c428
|
||||
React-logger: 700340e325f21ba2a2d6413a61ef14268c7360aa
|
||||
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: fdee2a0c512167ae4c19c4e230ccf6aa66a6aff0
|
||||
React-RCTActionSheet: 1cf5fef4e372f1c877969710a51bea4bb25e78fe
|
||||
React-RCTAnimation: 73816e3acd1f5e3f00166fc7eedb34f6b112f734
|
||||
React-RCTBlob: 6976c838fb14a1daf75d7c8bb23bae9cbbf726bb
|
||||
React-RCTImage: ab8a7498f215117f32271698591e4bd932dcf812
|
||||
React-RCTLinking: e8e78aed2744ab9946cc8ba5716b4938c2efb1e0
|
||||
React-RCTNetwork: 796f5aed4d932655d292bdc6b40f9502dcdb9542
|
||||
React-RCTSettings: 7e1cd2a384b45c90caf67464572abe3833b9da3b
|
||||
React-RCTText: fd6162890828f0761e03c59058fa23c3a21b2e10
|
||||
React-RCTVibration: 302cfd5cc33669d7abdb7ec6790123baba66e62e
|
||||
React-runtimeexecutor: 59407514818b2afbb1d7507e4e1ac834d24b0fbd
|
||||
ReactCommon: b8487da74723562d7368dab27135fd182f00a91c
|
||||
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: 7f5ad94937ba3fc58c151ad1b7bbada2c275b28e
|
||||
Yoga: 56413d530d1808044600320ced5baa883acedc44
|
||||
|
||||
PODFILE CHECKSUM: e3579df5272b8b697c9fdc0e55aa0845b189c4dd
|
||||
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;
|
||||
|
||||
@@ -67,13 +67,16 @@
|
||||
"renameBreakoutRoom": "Breakout-Raum umbenennen",
|
||||
"sendToBreakoutRoom": "Anwesende in Breakout-Raum verschieben:"
|
||||
},
|
||||
"breakoutList": "Breakout-Liste",
|
||||
"defaultName": "Breakout-Raum #{{index}}",
|
||||
"hideParticipantList": "Teilnehmerliste ausblenden",
|
||||
"mainRoom": "Hauptraum",
|
||||
"notifications": {
|
||||
"joined": "Breakout-Raum \"{{name}}\" betreten",
|
||||
"joinedMainRoom": "Hauptraum betreten",
|
||||
"joinedTitle": "Breakout-Räume"
|
||||
}
|
||||
},
|
||||
"showParticipantList": "Teilnehmerliste anzeigen"
|
||||
},
|
||||
"calendarSync": {
|
||||
"addMeetingURL": "Konferenzlink hinzufügen",
|
||||
@@ -256,6 +259,7 @@
|
||||
"Share": "Teilen",
|
||||
"Submit": "OK",
|
||||
"WaitForHostMsg": "Die Konferenz wurde noch nicht gestartet. Falls Sie die Konferenz leiten, authentifizieren Sie sich bitte. Warten Sie andernfalls, bis die Konferenz gestartet wird.",
|
||||
"WaitingForHostButton": "Auf Moderation warten",
|
||||
"WaitingForHostTitle": "Warten auf den Beginn der Konferenz …",
|
||||
"Yes": "Ja",
|
||||
"accessibilityLabel": {
|
||||
@@ -269,6 +273,8 @@
|
||||
"addMeetingNote": "Notiz zu dieser Konferenz hinzufügen",
|
||||
"addOptionalNote": "Notiz hinzufügen (optional):",
|
||||
"allow": "Erlauben",
|
||||
"allowToggleCameraDialog": "Wollen Sie {{initiatorName}} erlauben, Ihre Kameraauswahl zu ändern?",
|
||||
"allowToggleCameraTitle": "Änderung der Kamera zulassen?",
|
||||
"alreadySharedVideoMsg": "Eine andere Person gibt bereits ein Video weiter. Bei dieser Konferenz ist jeweils nur ein geteiltes Video möglich.",
|
||||
"alreadySharedVideoTitle": "Nur ein geteiltes Video gleichzeitig",
|
||||
"applicationWindow": "Anwendungsfenster",
|
||||
@@ -329,6 +335,7 @@
|
||||
"lockRoom": "Konferenz$t(lockRoomPassword) hinzufügen",
|
||||
"lockTitle": "Sperren fehlgeschlagen",
|
||||
"login": "Anmelden",
|
||||
"loginQuestion": "Sind Sie sicher, dass sie sich anmelden und die Konferenz verlassen möchten?",
|
||||
"logoutQuestion": "Sind Sie sicher, dass Sie sich abmelden und die Konferenz verlassen möchten?",
|
||||
"logoutTitle": "Abmelden",
|
||||
"maxUsersLimitReached": "Das Limit für die maximale Personenzahl ist erreicht. Die Konferenz ist voll. Bitte wenden Sie sich an die Konferenzleitung oder versuchen Sie es später noch einmal!",
|
||||
@@ -409,8 +416,10 @@
|
||||
"sendPrivateMessageTitle": "Privat antworten?",
|
||||
"serviceUnavailable": "Dienst nicht verfügbar",
|
||||
"sessTerminated": "Konferenz beendet",
|
||||
"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.",
|
||||
@@ -440,7 +449,24 @@
|
||||
"thankYou": "Danke für die Verwendung von {{appName}}!",
|
||||
"token": "Token",
|
||||
"tokenAuthFailed": "Sie sind nicht berechtigt, dieser Konferenz beizutreten.",
|
||||
"tokenAuthFailedReason": {
|
||||
"audInvalid": "Ungültiger `aud`-Wert. Erwartet wird `jitsi`.",
|
||||
"contextNotFound": "Das `context`-Objekt fehlt.",
|
||||
"expInvalid": "Ungültiger `exp`-Wert.",
|
||||
"featureInvalid": "Ungültiges Feature: {{feature}}, noch nicht implementiert.",
|
||||
"featureValueInvalid": "Ungültiger Wert für Feature: {{feature}}.",
|
||||
"featuresNotFound": "Das `features`-Objekt fehlt.",
|
||||
"headerNotFound": "Header fehlt.",
|
||||
"issInvalid": "Ungültiger `iss`-Wert. Erwartet wird `chat`.",
|
||||
"kidMismatch": "Die Key-ID (kid) passt nicht zum sub.",
|
||||
"kidNotFound": "Fehlende Key-ID (kid).",
|
||||
"nbfFuture": "Der `nbf`-Wert liegt in der Zukunft.",
|
||||
"nbfInvalid": "Ungültiger `nbf`-Wert.",
|
||||
"payloadNotFound": "Fehlende Payload.",
|
||||
"tokenExpired": "Das Token ist abgelaufen."
|
||||
},
|
||||
"tokenAuthFailedTitle": "Authentifizierung fehlgeschlagen",
|
||||
"tokenAuthFailedWithReasons": "Teilnahme an der Konferenz fehlgeschlagen. Möglicher Grund: {{reason}}",
|
||||
"tokenAuthUnsupported": "Token-Authentifizierung wird nicht unterstützt.",
|
||||
"transcribing": "Wird transkribiert",
|
||||
"unlockRoom": "Konferenz$t(lockRoomPassword) entfernen",
|
||||
@@ -530,6 +556,7 @@
|
||||
"password": "$t(lockRoomPasswordUppercase):",
|
||||
"reachedLimit": "Sie haben die Grenzen Ihres Tarifs erreicht.",
|
||||
"sip": "SIP-Adresse",
|
||||
"sipAudioOnly": "SIP-Adresse (nur Ton)",
|
||||
"title": "Teilen",
|
||||
"tooltip": "Freigabe-Link und Einwahlinformationen für dieses Meeting",
|
||||
"upgradeOptions": "Bitte prüfen Sie Ihre Upgrade-Optionen auf"
|
||||
@@ -636,13 +663,13 @@
|
||||
"knockingParticipantList": "Liste anklopfender Personen",
|
||||
"lobbyChatStartedNotification": "{{moderator}} hat einen Lobby-Chat mit {{attendee}} gestartet",
|
||||
"lobbyChatStartedTitle": "{{moderator}} hat einen Lobby-Chat mit Ihnen gestartet.",
|
||||
"lobbyClosed": "Die Lobby wurde geschlossen.",
|
||||
"nameField": "Geben Sie Ihren Namen ein",
|
||||
"notificationLobbyAccessDenied": "{{targetParticipantName}} wurde von {{originParticipantName}} der Zutritt verwehrt",
|
||||
"notificationLobbyAccessGranted": "{{targetParticipantName}} wurde von {{originParticipantName}} der Zutritt gestattet",
|
||||
"notificationLobbyDisabled": "{{originParticipantName}} hat die Lobby deaktiviert",
|
||||
"notificationLobbyEnabled": "{{originParticipantName}} hat die Lobby aktiviert",
|
||||
"notificationTitle": "Lobby",
|
||||
"passwordField": "Konferenzpasswort eingeben",
|
||||
"passwordJoinButton": "Beitreten",
|
||||
"reject": "Ablehnen",
|
||||
"rejectAll": "Alle ablehnen",
|
||||
@@ -677,6 +704,8 @@
|
||||
"sessionToken": "Sitzungs-Token",
|
||||
"start": "Aufnahme starten",
|
||||
"stop": "Aufnahme stoppen",
|
||||
"stopping": "Aufnahme wird gestoppt",
|
||||
"wait": "Bitte warten Sie während wir Ihre Aufnahme speichern",
|
||||
"yes": "Ja"
|
||||
},
|
||||
"lockRoomPassword": "Passwort",
|
||||
@@ -1059,6 +1088,7 @@
|
||||
"alertOk": "OK",
|
||||
"alertTitle": "Warnung",
|
||||
"alertURLText": "Die angegebene Server-URL ist ungültig",
|
||||
"apply": "Übernehmen",
|
||||
"buildInfoSection": "Build-Informationen",
|
||||
"conferenceSection": "Konferenz",
|
||||
"disableCallIntegration": "Native Anrufintegration deaktivieren",
|
||||
@@ -1069,6 +1099,7 @@
|
||||
"displayNamePlaceholderText": "z.B. Erika Musterfrau",
|
||||
"email": "E-Mail",
|
||||
"emailPlaceholderText": "email@beispiel.de",
|
||||
"gavatarMessage": "Wenn Sie ein Gravatar-Konto mit Ihrer Emailadresse haben, wird dieses als Ihr Profilfoto verwendet.",
|
||||
"goTo": "Gehe zu",
|
||||
"header": "Einstellungen",
|
||||
"help": "Hilfe",
|
||||
|
||||
@@ -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
@@ -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",
|
||||
@@ -250,13 +255,14 @@
|
||||
"dialog": {
|
||||
"Back": "Voltar",
|
||||
"Cancel": "Cancelar",
|
||||
"IamHost": "Eu sou o anfitrião",
|
||||
"IamHost": "Iniciar sessão",
|
||||
"Ok": "OK",
|
||||
"Remove": "Remover",
|
||||
"Share": "Partilhar",
|
||||
"Submit": "Submeter",
|
||||
"WaitForHostMsg": "A conferência ainda não começou. Se for o anfitrião, por favor autentique. Caso contrário, por favor aguarde que o anfitrião chegue.",
|
||||
"WaitingForHostTitle": "À espera do anfitrião ...",
|
||||
"WaitForHostMsg": "A conferência ainda não começou porque ainda não chegaram moderadores. Se quiser ser um moderador, inicie a sessão. Caso contrário, aguarde.",
|
||||
"WaitingForHostButton": "Esperar pelo moderador",
|
||||
"WaitingForHostTitle": "À espera de um moderador...",
|
||||
"Yes": "Sim",
|
||||
"accessibilityLabel": {
|
||||
"Cancel": "Cancelar (sair da caixa de diálogo)",
|
||||
@@ -269,6 +275,8 @@
|
||||
"addMeetingNote": "Acrescentar uma nota sobre esta reunião",
|
||||
"addOptionalNote": "Adicionar uma nota (opcional):",
|
||||
"allow": "Permitir",
|
||||
"allowToggleCameraDialog": "Permite que {{initiatorName}} alterne o modo de visualização da câmara?",
|
||||
"allowToggleCameraTitle": "Permitir alternar a câmara?",
|
||||
"alreadySharedVideoMsg": "Outro participante já está a partilhar um vídeo. Esta conferência permite apenas um vídeo partilhado de cada vez.",
|
||||
"alreadySharedVideoTitle": "Só é permitido um vídeo partilhado de cada vez",
|
||||
"applicationWindow": "Janela de aplicação",
|
||||
@@ -329,6 +337,7 @@
|
||||
"lockRoom": "Adicionar reunião $t(lockRoomPassword)",
|
||||
"lockTitle": "Bloqueio falhado",
|
||||
"login": "Entrar",
|
||||
"loginQuestion": "Tem a certeza de que pretende iniciar sessão e abandonar a conferência?",
|
||||
"logoutQuestion": "Tem a certeza de que quer terminar a sessão e sair da conferência?",
|
||||
"logoutTitle": "Sair",
|
||||
"maxUsersLimitReached": "O limite para o número máximo de participantes foi atingido. A conferência está cheia. Por favor contacte o proprietário da reunião ou tente novamente mais tarde!",
|
||||
@@ -409,6 +418,7 @@
|
||||
"sendPrivateMessageTitle": "Enviar em privado?",
|
||||
"serviceUnavailable": "Serviço indisponível",
|
||||
"sessTerminated": "Chamada terminada",
|
||||
"sessTerminatedReason": "A reunião foi encerrada",
|
||||
"sessionRestarted": "Chamada reiniciada devido a um problema de ligação.",
|
||||
"shareAudio": "Continuar",
|
||||
"shareAudioTitle": "Como partilhar áudio",
|
||||
@@ -440,7 +450,24 @@
|
||||
"thankYou": "Obrigado por utilizar {{appName}}!",
|
||||
"token": "token",
|
||||
"tokenAuthFailed": "Desculpe, não está autorizado a juntar-se a esta chamada.",
|
||||
"tokenAuthFailedReason": {
|
||||
"audInvalid": "Valor `aud` inválido. Deveria ser `jitsi`.",
|
||||
"contextNotFound": "O objeto `context` está em falta na carga útil.",
|
||||
"expInvalid": "Valor `exp` inválido.",
|
||||
"featureInvalid": "Funcionalidade inválida: {{feature}}, muito provavelmente ainda não implementada.",
|
||||
"featureValueInvalid": "Valor inválido para a caraterística: {{feature}}.",
|
||||
"featuresNotFound": "O objeto `features` está em falta na carga útil.",
|
||||
"headerNotFound": "Falta o cabeçalho.",
|
||||
"issInvalid": "Valor `iss` inválido. Deveria ser `chat`.",
|
||||
"kidMismatch": "O ID da chave (kid) não corresponde ao sub.",
|
||||
"kidNotFound": "Falta o ID da chave (kid)",
|
||||
"nbfFuture": "O valor `nbf` está no futuro.",
|
||||
"nbfInvalid": "Valor `nbf` inválido.",
|
||||
"payloadNotFound": "Falta a carga útil.",
|
||||
"tokenExpired": "O token expirou."
|
||||
},
|
||||
"tokenAuthFailedTitle": "A autenticação falhou",
|
||||
"tokenAuthFailedWithReasons": "Lamentamos, mas não está autorizado a participar nesta chamada. Razões possíveis: {{reason}}",
|
||||
"tokenAuthUnsupported": "O URL de token não é suportado.",
|
||||
"transcribing": "Transcrição",
|
||||
"unlockRoom": "Retirar reunião $t(lockRoomPassword)",
|
||||
@@ -455,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": {
|
||||
@@ -529,7 +560,8 @@
|
||||
"numbers": "Números para entrar por chamada telefónica",
|
||||
"password": "$t(lockRoomPasswordUppercase): ",
|
||||
"reachedLimit": "atingiu o limite do seu plano.",
|
||||
"sip": "Endereços SIP",
|
||||
"sip": "Endereço SIP",
|
||||
"sipAudioOnly": "Endereço SIP só de áudio",
|
||||
"title": "Partilhar",
|
||||
"tooltip": "Partilhar link e acesso telefónico para esta reunião",
|
||||
"upgradeOptions": "Por favor, verifique as opções de atualização em"
|
||||
@@ -593,15 +625,15 @@
|
||||
"limitNotificationDescriptionWeb": "Devido à grande procura, a sua transmissão será limitada a {{limit}} min. Para uma tentativa de streaming ilimitada tente <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"off": "Transmissão em direto encerrada",
|
||||
"offBy": "{{name}} parou a transmissão em direto",
|
||||
"on": "Transmissão em Direto",
|
||||
"on": "Iniciada a transmissão em direto",
|
||||
"onBy": "{{name}} iniciou a transmissão em direto",
|
||||
"pending": "Iniciando Transmissão em Direto...",
|
||||
"pending": "Início da transmissão em direto...",
|
||||
"serviceName": "Serviço de Transmissão em Direto",
|
||||
"sessionAlreadyActive": "Esta sessão já está a ser gravada ou transmitida em direto.",
|
||||
"signIn": "Faça login no Google",
|
||||
"signInCTA": "Faça login ou insira sua chave de transmissão em Direto do YouTube.",
|
||||
"signIn": "Iniciar sessão com o Google",
|
||||
"signInCTA": "Inicie sessão ou introduza a sua chave de transmissão em direto do YouTube.",
|
||||
"signOut": "Sair",
|
||||
"signedInAs": "Está conectado como:",
|
||||
"signedInAs": "Atualmente, tem sessão iniciada como:",
|
||||
"start": "Iniciar uma transmissão em direto",
|
||||
"streamIdHelp": "O que é isso?",
|
||||
"title": "Transmissão em direto",
|
||||
@@ -636,13 +668,13 @@
|
||||
"knockingParticipantList": "Lista de participantes a expulsar",
|
||||
"lobbyChatStartedNotification": "{{moderator}} iniciou com {{attendee}} uma conversa na sala de espera",
|
||||
"lobbyChatStartedTitle": "{{moderator}} iniciou consigo uma conversa na sala de espera.",
|
||||
"lobbyClosed": "A sala de espera foi encerrada.",
|
||||
"nameField": "Introduza o seu nome",
|
||||
"notificationLobbyAccessDenied": "{{targetParticipantName}} foi recusada a adesão por {{originParticipantName}}",
|
||||
"notificationLobbyAccessGranted": "{{targetParticipantName}} foi autorizado a aderir por {{originParticipantName}}",
|
||||
"notificationLobbyDisabled": "A sala de espera foi desactivada por {{originParticipantName}}",
|
||||
"notificationLobbyEnabled": "A sala de espera foi activada por {{originParticipantName}}",
|
||||
"notificationTitle": "Sala de espera",
|
||||
"passwordField": "Introduza a senha da reunião",
|
||||
"passwordJoinButton": "Solicitar",
|
||||
"reject": "Rejeitar",
|
||||
"rejectAll": "Rejeitar todos",
|
||||
@@ -701,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",
|
||||
@@ -776,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": {
|
||||
@@ -785,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",
|
||||
@@ -1061,6 +1097,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": "Desactivar a integração de chamadas nativas",
|
||||
@@ -1071,6 +1108,7 @@
|
||||
"displayNamePlaceholderText": "Ex: João Dias",
|
||||
"email": "Email",
|
||||
"emailPlaceholderText": "email@example.com",
|
||||
"gavatarMessage": "Se o seu e-mail estiver associado a uma conta Gravatar, utilizá-la-emos para apresentar a sua imagem de perfil.",
|
||||
"goTo": "Ir para",
|
||||
"header": "Configurações",
|
||||
"help": "Ajuda",
|
||||
@@ -1129,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",
|
||||
@@ -1254,7 +1292,7 @@
|
||||
"lobbyButtonDisable": "Desativar sala de espera",
|
||||
"lobbyButtonEnable": "Ativar sala de espera",
|
||||
"login": "Iniciar sessão",
|
||||
"logout": "Encerrar sessão",
|
||||
"logout": "Terminar sessão",
|
||||
"lowerYourHand": "Baixar a mão",
|
||||
"moreActions": "Mais ações",
|
||||
"moreOptions": "Mais opções",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -1251,7 +1251,7 @@
|
||||
"pending": "{{displayName}} davet edildi"
|
||||
},
|
||||
"videoStatus": {
|
||||
"adjustFor": "Ayala:",
|
||||
"adjustFor": "Ayarla:",
|
||||
"audioOnly": "SES",
|
||||
"audioOnlyExpanded": "Yalnızca ses modundasınız. Bu mod bant genişliğinden tasarruf sağlar, ancak başkalarının videolarını göremezsiniz.",
|
||||
"bestPerformance": "En iyi performans",
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -67,13 +67,18 @@
|
||||
"renameBreakoutRoom": "Rename breakout room",
|
||||
"sendToBreakoutRoom": "Send participant to:"
|
||||
},
|
||||
"breakoutList": "Breakout list",
|
||||
"buttonLabel": "Breakout rooms",
|
||||
"defaultName": "Breakout room #{{index}}",
|
||||
"hideParticipantList": "Hide participant list",
|
||||
"mainRoom": "Main room",
|
||||
"notifications": {
|
||||
"joined": "Joining the \"{{name}}\" breakout room",
|
||||
"joinedMainRoom": "Joining the main room",
|
||||
"joinedTitle": "Breakout Rooms"
|
||||
}
|
||||
},
|
||||
"showParticipantList": "Show participant list",
|
||||
"title": "Breakout Rooms"
|
||||
},
|
||||
"calendarSync": {
|
||||
"addMeetingURL": "Add a meeting link",
|
||||
@@ -416,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.",
|
||||
@@ -477,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": {
|
||||
@@ -724,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",
|
||||
@@ -799,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": {
|
||||
@@ -808,6 +821,7 @@
|
||||
"askUnmute": "Ask to unmute",
|
||||
"audioModeration": "Unmute themselves",
|
||||
"blockEveryoneMicCamera": "Block everyone's mic and camera",
|
||||
"breakoutRooms": "Breakout rooms",
|
||||
"invite": "Invite Someone",
|
||||
"moreModerationActions": "More moderation options",
|
||||
"moreModerationControls": "More moderation controls",
|
||||
@@ -1154,7 +1168,7 @@
|
||||
"audioOnly": "Toggle audio only",
|
||||
"audioRoute": "Select the sound device",
|
||||
"boo": "Boo",
|
||||
"breakoutRoom": "Join/leave breakout room",
|
||||
"breakoutRooms": "Breakout rooms",
|
||||
"callQuality": "Manage video quality",
|
||||
"carmode": "Car Mode",
|
||||
"cc": "Toggle subtitles",
|
||||
|
||||
10
metadata/en-US/full_description.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Jitsi Meet lets you stay in touch with all your teams, be they family, friends, or colleagues. Instant video conferences, efficiently adapting to your scale.
|
||||
|
||||
* Unlimited users: There are no artificial restrictions on the number of users or conference participants. Server power and bandwidth are the only limiting factors.
|
||||
* No account needed.
|
||||
* Lock-protected rooms: Control the access to your conferences with a password.
|
||||
* Encrypted by default.
|
||||
* High quality: Audio and video are delivered with the clarity and richness of Opus and VP8.
|
||||
* Web browser ready: No downloads are required of your friends to join the conversation. Jitsi Meet works directly within their browsers as well. Simply share your conference URL with others to get started.
|
||||
* 100% open source: Powered by awesome communities from all over the world. And your friends at 8x8.
|
||||
* Invite by pretty URLs: You can meet at the easy to remember https://MySite.com/OurConf of your choice instead of joining the hard to remember rooms with seemingly random sequences of numbers and letters in their names.
|
||||
BIN
metadata/en-US/images/icon.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
metadata/en-US/images/phoneScreenshots/01.png
Normal file
|
After Width: | Height: | Size: 302 KiB |
BIN
metadata/en-US/images/phoneScreenshots/02.png
Normal file
|
After Width: | Height: | Size: 168 KiB |
BIN
metadata/en-US/images/phoneScreenshots/03.png
Normal file
|
After Width: | Height: | Size: 243 KiB |
BIN
metadata/en-US/images/sevenInchScreenshots/01.png
Normal file
|
After Width: | Height: | Size: 928 KiB |
BIN
metadata/en-US/images/sevenInchScreenshots/02.png
Normal file
|
After Width: | Height: | Size: 534 KiB |
1
metadata/en-US/short_description.txt
Normal file
@@ -0,0 +1 @@
|
||||
Secure, Simple and Scalable Video Conferences with state-of-the-art video quality
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
91
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;
|
||||
@@ -305,6 +311,9 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
* configuration options defined in config.js to be overridden.
|
||||
* @param {Object} [options.interfaceConfigOverwrite] - Object containing
|
||||
* configuration options defined in interface_config.js to be overridden.
|
||||
* @param {IIceServers} [options.iceServers] - Object with rules that will be used to modify/remove the existing
|
||||
* ice server configuration.
|
||||
* NOTE: This property is currently experimental and may be removed in the future!
|
||||
* @param {string} [options.jwt] - The JWT token if needed by jitsi-meet for
|
||||
* authentication.
|
||||
* @param {string} [options.lang] - The meeting's default language.
|
||||
@@ -334,6 +343,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
lang = undefined,
|
||||
onload = undefined,
|
||||
invitees,
|
||||
iceServers,
|
||||
devices,
|
||||
userInfo,
|
||||
e2eeKey,
|
||||
@@ -345,6 +355,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
this._parentNode = parentNode;
|
||||
this._url = generateURL(domain, {
|
||||
configOverwrite,
|
||||
iceServers,
|
||||
interfaceConfigOverwrite,
|
||||
jwt,
|
||||
lang,
|
||||
@@ -356,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: {
|
||||
@@ -366,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;
|
||||
@@ -387,18 +403,26 @@ 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');
|
||||
this._frame.allow = 'camera; microphone; display-capture; autoplay; clipboard-write; hid; screen-wake-lock';
|
||||
this._frame.allow = [
|
||||
'autoplay',
|
||||
'camera',
|
||||
'clipboard-write',
|
||||
'compute-pressure',
|
||||
'display-capture',
|
||||
'hid',
|
||||
'microphone',
|
||||
'screen-wake-lock',
|
||||
'speaker-selection'
|
||||
].join('; ');
|
||||
this._frame.name = frameName;
|
||||
this._frame.id = frameName;
|
||||
this._setSize(height, width);
|
||||
@@ -409,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);
|
||||
@@ -562,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') {
|
||||
|
||||
@@ -673,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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1191,6 +1228,24 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
return this._numberOfParticipants;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of commands supported by executeCommand().
|
||||
*
|
||||
* @returns {Array<string>} Array of commands.
|
||||
*/
|
||||
getSupportedCommands() {
|
||||
return Object.keys(commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of events supported by addEventListener().
|
||||
*
|
||||
* @returns {Array<string>} Array of events.
|
||||
*/
|
||||
getSupportedEvents() {
|
||||
return Object.values(events);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the video is available.
|
||||
*
|
||||
@@ -1226,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.
|
||||
*
|
||||
@@ -1366,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) {
|
||||
|
||||
@@ -203,16 +203,6 @@ UI.toggleFilmstrip = function() {
|
||||
APP.store.dispatch(setFilmstripVisible(!visible));
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets muted audio state for participant
|
||||
*/
|
||||
UI.setAudioMuted = function(id) {
|
||||
// FIXME: Maybe this can be removed!
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
APP.conference.updateAudioIconEnabled();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets muted video state for participant
|
||||
*/
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
notifyMicError
|
||||
} from '../../react/features/base/devices/actions.web';
|
||||
import {
|
||||
flattenAvailableDevices,
|
||||
getAudioOutputDeviceId
|
||||
} from '../../react/features/base/devices/functions.web';
|
||||
import { updateSettings } from '../../react/features/base/settings/actions';
|
||||
@@ -186,7 +187,7 @@ export default {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
newDeviceListAddedLabelsOnly(oldDevices, newDevices) {
|
||||
const oldDevicesFlattend = oldDevices.audioInput.concat(oldDevices.audioOutput).concat(oldDevices.videoInput);
|
||||
const oldDevicesFlattend = flattenAvailableDevices(oldDevices);
|
||||
|
||||
if (oldDevicesFlattend.length !== newDevices.length) {
|
||||
return false;
|
||||
|
||||
6280
package-lock.json
generated
31
package.json
@@ -22,8 +22,8 @@
|
||||
"@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/js-utils": "2.1.3",
|
||||
"@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",
|
||||
"@jitsi/rtcstats": "9.5.1",
|
||||
@@ -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",
|
||||
@@ -48,7 +48,7 @@
|
||||
"@vladmandic/human-models": "2.5.9",
|
||||
"@xmldom/xmldom": "0.8.7",
|
||||
"amplitude-js": "8.2.1",
|
||||
"base64-js": "1.3.1",
|
||||
"base64-js": "1.5.1",
|
||||
"bc-css-flags": "3.0.0",
|
||||
"clipboard-copy": "4.0.1",
|
||||
"clsx": "1.1.1",
|
||||
@@ -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/v1681.0.0+6cd397fa/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.11",
|
||||
"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,8 +113,8 @@
|
||||
"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",
|
||||
"util": "0.12.1",
|
||||
"uuid": "8.3.2",
|
||||
@@ -135,16 +135,17 @@
|
||||
"@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",
|
||||
"@types/react-linkify": "1.0.1",
|
||||
"@types/react-native": "0.69.20",
|
||||
"@types/react-native": "0.69.22",
|
||||
"@types/react-native-keep-awake": "2.0.3",
|
||||
"@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",
|
||||
@@ -156,7 +157,7 @@
|
||||
"babel-plugin-optional-require": "0.3.1",
|
||||
"circular-dependency-plugin": "5.2.0",
|
||||
"clean-css-cli": "4.3.0",
|
||||
"css-loader": "3.6.0",
|
||||
"css-loader": "6.8.1",
|
||||
"eslint": "8.40.0",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-jsdoc": "37.0.3",
|
||||
|
||||
@@ -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
|
||||
@@ -87,3 +94,6 @@ https://github.com/jitsi/jitsi-meet-sdk-samples/tree/master/react-native
|
||||
serverURL={'https://meet.jit.si/'}
|
||||
token={'dkhalhfajhflahlfaahalhfahfsl'} />
|
||||
```
|
||||
|
||||
For more details on how you can use React Native SDK with React Native app, you can follow this link:
|
||||
https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-react-native-sdk
|
||||
|
||||
@@ -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,
|
||||
|
||||
232
react-native-sdk/package-lock.json
generated
@@ -23,10 +23,11 @@
|
||||
"grapheme-splitter": "1.0.4",
|
||||
"i18n-iso-countries": "6.8.0",
|
||||
"i18next": "17.0.6",
|
||||
"i18next-http-backend": "^2.2.1",
|
||||
"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/v1681.0.0+6cd397fa/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1687.0.0+cafe30d7/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -153,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"
|
||||
@@ -190,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"
|
||||
@@ -280,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"
|
||||
}
|
||||
@@ -322,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"
|
||||
},
|
||||
@@ -357,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"
|
||||
},
|
||||
@@ -377,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": {
|
||||
@@ -1275,6 +1276,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/cross-fetch": {
|
||||
"version": "3.1.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz",
|
||||
"integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==",
|
||||
"dependencies": {
|
||||
"node-fetch": "^2.6.11"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
|
||||
@@ -1962,6 +1971,14 @@
|
||||
"@babel/runtime": "^7.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/i18next-http-backend": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.2.2.tgz",
|
||||
"integrity": "sha512-mJu4ZqzDtBiU3O4GV9AbK5ekEqoDMdMnCl3pkdXmb5b8yoIH//u8FsmIe6C5qXb3teZu+j6VMi20tjUgzeABiw==",
|
||||
"dependencies": {
|
||||
"cross-fetch": "3.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
@@ -2464,13 +2481,14 @@
|
||||
},
|
||||
"node_modules/lib-jitsi-meet": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1681.0.0+6cd397fa/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-IUjwOod8/HX785klIwINfmnxjrE4iwaMZCEmng9SQoCdAtZDqo8XsAI0+pLyBpttJ/fhUkBI/ox8Vw2Ic4TB9w==",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1687.0.0+cafe30d7/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-ky3q5gLeLDHFtenXe7+QlxAh33opz0a3bqEp8svA9urR1AICUi0QthOwmUerTdfSRFU3wfVObF9axlX1fbHZ3A==",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "2.1.3",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
"@jitsi/rtcstats": "9.5.1",
|
||||
"@jitsi/sdp-interop": "git+https://github.com/jitsi/sdp-interop#3d49eb4aa26863a3f8d32d7581cdb4321244266b",
|
||||
"@jitsi/sdp-simulcast": "0.4.0",
|
||||
"@testrtc/watchrtc-sdk": "1.36.3",
|
||||
@@ -2654,6 +2672,25 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "2.0.13",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
|
||||
@@ -3510,6 +3547,11 @@
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||
@@ -3653,6 +3695,15 @@
|
||||
"npm": ">=3.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/whatwg-url-without-unicode": {
|
||||
"version": "8.0.0-3",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url-without-unicode/-/whatwg-url-without-unicode-8.0.0-3.tgz",
|
||||
@@ -3666,6 +3717,11 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/whatwg-url/node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
||||
@@ -3810,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"
|
||||
@@ -3840,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": {
|
||||
@@ -3903,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",
|
||||
@@ -3933,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",
|
||||
@@ -3956,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"
|
||||
}
|
||||
},
|
||||
@@ -4568,6 +4624,14 @@
|
||||
"path-type": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"cross-fetch": {
|
||||
"version": "3.1.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz",
|
||||
"integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==",
|
||||
"requires": {
|
||||
"node-fetch": "^2.6.11"
|
||||
}
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
|
||||
@@ -5069,6 +5133,14 @@
|
||||
"@babel/runtime": "^7.3.1"
|
||||
}
|
||||
},
|
||||
"i18next-http-backend": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.2.2.tgz",
|
||||
"integrity": "sha512-mJu4ZqzDtBiU3O4GV9AbK5ekEqoDMdMnCl3pkdXmb5b8yoIH//u8FsmIe6C5qXb3teZu+j6VMi20tjUgzeABiw==",
|
||||
"requires": {
|
||||
"cross-fetch": "3.1.6"
|
||||
}
|
||||
},
|
||||
"ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
@@ -5404,11 +5476,12 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1681.0.0+6cd397fa/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-IUjwOod8/HX785klIwINfmnxjrE4iwaMZCEmng9SQoCdAtZDqo8XsAI0+pLyBpttJ/fhUkBI/ox8Vw2Ic4TB9w==",
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1687.0.0+cafe30d7/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-ky3q5gLeLDHFtenXe7+QlxAh33opz0a3bqEp8svA9urR1AICUi0QthOwmUerTdfSRFU3wfVObF9axlX1fbHZ3A==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "2.1.3",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
"@jitsi/rtcstats": "9.5.1",
|
||||
"@jitsi/sdp-interop": "git+https://github.com/jitsi/sdp-interop#3d49eb4aa26863a3f8d32d7581cdb4321244266b",
|
||||
"@jitsi/sdp-simulcast": "0.4.0",
|
||||
"@testrtc/watchrtc-sdk": "1.36.3",
|
||||
@@ -5564,6 +5637,14 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node-releases": {
|
||||
"version": "2.0.13",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
|
||||
@@ -6162,6 +6243,11 @@
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"tslib": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||
@@ -6257,6 +6343,22 @@
|
||||
"sdp": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"whatwg-url-without-unicode": {
|
||||
"version": "8.0.0-3",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url-without-unicode/-/whatwg-url-without-unicode-8.0.0-3.tgz",
|
||||
|
||||
@@ -25,9 +25,10 @@
|
||||
"i18n-iso-countries": "6.8.0",
|
||||
"i18next": "17.0.6",
|
||||
"js-md5": "0.6.1",
|
||||
"i18next-http-backend": "^2.2.1",
|
||||
"js-sha512": "0.8.0",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1681.0.0+6cd397fa/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1687.0.0+cafe30d7/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -37,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",
|
||||
@@ -96,4 +96,4 @@
|
||||
"keywords": [
|
||||
"react-native"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
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`
|
||||
|
||||
42
react-native-sdk/update_dependencies.js
vendored
@@ -1,8 +1,10 @@
|
||||
/* eslint-disable guard-for-in */
|
||||
/* eslint-disable guard-for-in, no-continue */
|
||||
/* global __dirname */
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const semver = require('semver');
|
||||
|
||||
|
||||
const pathToPackageJSON = path.resolve(__dirname, '../../../package.json');
|
||||
|
||||
@@ -10,6 +12,7 @@ const packageJSON = require(pathToPackageJSON);
|
||||
|
||||
const RNSDKpackageJSON = require(path.resolve(__dirname, './package.json'));
|
||||
|
||||
|
||||
/**
|
||||
* Updates dependencies from the app package.json with the peer dependencies of the RNSDK package.json.
|
||||
*/
|
||||
@@ -21,6 +24,41 @@ function updateDependencies() {
|
||||
packageJSON.dependencies[key] = RNSDKpackageJSON.peerDependencies[key];
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (!semver.valid(packageJSON.dependencies[key])
|
||||
&& packageJSON.dependencies[key] !== RNSDKpackageJSON.peerDependencies[key]) {
|
||||
packageJSON.dependencies[key] = RNSDKpackageJSON.peerDependencies[key];
|
||||
updated = true;
|
||||
|
||||
console.log(`
|
||||
⚠️We changed ${key} version number from ${packageJSON.dependencies[key]} to ${RNSDKpackageJSON.peerDependencies[key]}`
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (semver.satisfies(RNSDKpackageJSON.peerDependencies[key], `=${packageJSON.dependencies[key]}`)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (semver.satisfies(RNSDKpackageJSON.peerDependencies[key], `>${packageJSON.dependencies[key]}`)) {
|
||||
packageJSON.dependencies[key] = RNSDKpackageJSON.peerDependencies[key];
|
||||
updated = true;
|
||||
|
||||
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 || {};
|
||||
@@ -33,6 +71,8 @@ function updateDependencies() {
|
||||
}
|
||||
|
||||
if (!updated) {
|
||||
console.log('All your dependencies are up to date!');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import React, { Component } from 'react';
|
||||
// in this environment (e.g. JitsiMeetJS or interfaceConfig)
|
||||
import StatelessAvatar from '../base/avatar/components/web/StatelessAvatar';
|
||||
import { getAvatarColor, getInitials } from '../base/avatar/functions';
|
||||
import { DEFAULT_ICON } from '../base/icons/svg/constants';
|
||||
|
||||
import Toolbar from './Toolbar';
|
||||
|
||||
@@ -184,6 +185,7 @@ export default class AlwaysOnTop extends Component<any, IState> {
|
||||
<div id = 'avatarContainer'>
|
||||
<StatelessAvatar
|
||||
color = { getAvatarColor(displayName, customAvatarBackgrounds) }
|
||||
iconUser = { DEFAULT_ICON.IconUser }
|
||||
id = 'avatar'
|
||||
initials = { getInitials(displayName) }
|
||||
url = { avatarURL } />)
|
||||
|
||||
@@ -2,7 +2,8 @@ import React, { Component } from 'react';
|
||||
|
||||
// We need to reference these files directly to avoid loading things that are not available
|
||||
// in this environment (e.g. JitsiMeetJS or interfaceConfig)
|
||||
import { IconMic, IconMicSlash } from '../base/icons/svg';
|
||||
|
||||
import { DEFAULT_ICON } from '../base/icons/svg/constants';
|
||||
import { IProps } from '../base/toolbox/components/AbstractButton';
|
||||
|
||||
import ToolbarButton from './ToolbarButton';
|
||||
@@ -31,8 +32,8 @@ type Props = Partial<IProps>;
|
||||
* Stateless "mute/unmute audio" button for the Always-on-Top windows.
|
||||
*/
|
||||
export default class AudioMuteButton extends Component<Props, IState> {
|
||||
icon = IconMic;
|
||||
toggledIcon = IconMicSlash;
|
||||
icon = DEFAULT_ICON.IconMic;
|
||||
toggledIcon = DEFAULT_ICON.IconMicSlash;
|
||||
accessibilityLabel = 'Audio mute';
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
||||
|
||||
// We need to reference these files directly to avoid loading things that are not available
|
||||
// in this environment (e.g. JitsiMeetJS or interfaceConfig)
|
||||
import { IconHangup } from '../base/icons/svg';
|
||||
import { DEFAULT_ICON } from '../base/icons/svg/constants';
|
||||
import { IProps } from '../base/toolbox/components/AbstractButton';
|
||||
|
||||
import ToolbarButton from './ToolbarButton';
|
||||
@@ -17,7 +17,7 @@ type Props = Partial<IProps>;
|
||||
export default class HangupButton extends Component<Props> {
|
||||
|
||||
accessibilityLabel = 'Hangup';
|
||||
icon = IconHangup;
|
||||
icon = DEFAULT_ICON.IconHangup;
|
||||
|
||||
/**
|
||||
* Initializes a new {@code HangupButton} instance.
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
||||
|
||||
// We need to reference these files directly to avoid loading things that are not available
|
||||
// in this environment (e.g. JitsiMeetJS or interfaceConfig)
|
||||
import { IconVideo, IconVideoOff } from '../base/icons/svg';
|
||||
import { DEFAULT_ICON } from '../base/icons/svg/constants';
|
||||
import { IProps } from '../base/toolbox/components/AbstractButton';
|
||||
|
||||
import ToolbarButton from './ToolbarButton';
|
||||
@@ -32,8 +32,8 @@ type State = {
|
||||
*/
|
||||
export default class VideoMuteButton extends Component<Props, State> {
|
||||
|
||||
icon = IconVideo;
|
||||
toggledIcon = IconVideoOff;
|
||||
icon = DEFAULT_ICON.IconVideo;
|
||||
toggledIcon = DEFAULT_ICON.IconVideoOff;
|
||||
accessibilityLabel = 'Video mute';
|
||||
|
||||
/**
|
||||
|
||||
@@ -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) {
|
||||
@@ -224,7 +239,7 @@ export function initAnalytics(store: IStore, handlers: Array<Object>) {
|
||||
// Set the handlers last, since this triggers emptying of the cache
|
||||
analytics.setAnalyticsHandlers(handlers);
|
||||
|
||||
if (!isMobileBrowser() && browser.isChrome()) {
|
||||
if (!isMobileBrowser() && browser.isChromiumBased()) {
|
||||
const bannerCfg = state['features/base/config'].chromeExtensionBanner;
|
||||
|
||||
checkChromeExtensionsInstalled(bannerCfg).then(extensionsInstalled => {
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
import { getLocationContextRoot } from '../base/util/uri';
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line
|
||||
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.
|
||||
@@ -83,4 +94,68 @@ export function reloadWithStoredParams() {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether tokenAuthUrl is set, we have a jwt token that will expire soon
|
||||
* and redirect to the auth url to obtain new token if this is the case.
|
||||
*
|
||||
* @param {Dispatch} dispatch - The Redux dispatch function.
|
||||
* @param {Function} getState - The Redux state.
|
||||
* @param {Function} failureCallback - The callback on failure to obtain auth url.
|
||||
* @returns {boolean} Whether we will redirect or not.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
// if tokenAuthUrl check jwt if is about to expire go through the url to get new token
|
||||
const jwt = state['features/base/jwt'].jwt;
|
||||
const expirationDate = getJwtExpirationDate(jwt);
|
||||
|
||||
// if there is jwt and its expiration time is less than 3 minutes away
|
||||
// let's obtain new token
|
||||
if (expirationDate && expirationDate.getTime() - Date.now() < 3 * 60 * 1000) {
|
||||
const room = state['features/base/conference'].room;
|
||||
const { tenant } = parseURIString(locationURL.href) || {};
|
||||
|
||||
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');
|
||||
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
return dispatch(openTokenAuthUrl(tokenAuthServiceUrl));
|
||||
})
|
||||
.catch(() => {
|
||||
failureCallback();
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { setRoom } from '../base/conference/actions';
|
||||
import { getConferenceState } from '../base/conference/functions';
|
||||
import {
|
||||
configWillLoad,
|
||||
loadConfigError,
|
||||
@@ -10,6 +11,7 @@ import {
|
||||
restoreConfig
|
||||
} from '../base/config/functions.native';
|
||||
import { connect, disconnect, setLocationURL } from '../base/connection/actions.native';
|
||||
import { JITSI_CONNECTION_URL_KEY } from '../base/connection/constants';
|
||||
import { loadConfig } from '../base/lib-jitsi-meet/functions.native';
|
||||
import { createDesiredLocalTracks } from '../base/tracks/actions.native';
|
||||
import isInsecureRoomName from '../base/util/isInsecureRoomName';
|
||||
@@ -29,6 +31,7 @@ import { screen } from '../mobile/navigation/routes';
|
||||
import { clearNotifications } from '../notifications/actions';
|
||||
import { isUnsafeRoomWarningEnabled } from '../prejoin/functions';
|
||||
|
||||
import { maybeRedirectToTokenAuthUrl } from './actions.any';
|
||||
import { addTrackStateToURL, getDefaultURL } from './functions.native';
|
||||
import logger from './logger';
|
||||
import { IReloadNowOptions, IStore } from './types';
|
||||
@@ -72,11 +75,25 @@ export function appNavigate(uri?: string, options: IReloadNowOptions = {}) {
|
||||
}
|
||||
|
||||
location.protocol || (location.protocol = 'https:');
|
||||
const { contextRoot, host, room } = location;
|
||||
const { contextRoot, host, hostname, pathname, room } = location;
|
||||
const locationURL = new URL(location.toString());
|
||||
const { conference } = getConferenceState(getState());
|
||||
|
||||
if (room) {
|
||||
navigateRoot(screen.connecting);
|
||||
if (conference) {
|
||||
|
||||
// We need to check if the location is the same with the previous one.
|
||||
const currentLocationURL = conference?.getConnection()[JITSI_CONNECTION_URL_KEY];
|
||||
const { hostname: currentHostName, pathname: currentPathName } = currentLocationURL;
|
||||
|
||||
if (currentHostName === hostname && currentPathName === pathname) {
|
||||
logger.warn(`Joining same conference using URL: ${currentLocationURL}`);
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
navigateRoot(screen.connecting);
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(disconnect());
|
||||
@@ -133,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);
|
||||
@@ -146,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);
|
||||
@@ -188,10 +214,18 @@ export function reloadNow() {
|
||||
// @ts-ignore
|
||||
const newURL = addTrackStateToURL(locationURL, state);
|
||||
|
||||
logger.info(`Reloading the conference using URL: ${locationURL}`);
|
||||
const reloadAction = () => {
|
||||
logger.info(`Reloading the conference using URL: ${locationURL}`);
|
||||
|
||||
dispatch(appNavigate(toURLString(newURL), {
|
||||
hidePrejoin: true
|
||||
}));
|
||||
dispatch(appNavigate(toURLString(newURL), {
|
||||
hidePrejoin: true
|
||||
}));
|
||||
};
|
||||
|
||||
if (maybeRedirectToTokenAuthUrl(dispatch, getState, reloadAction)) {
|
||||
return;
|
||||
}
|
||||
|
||||
reloadAction();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
|
||||
import { isWelcomePageEnabled } from '../welcome/functions';
|
||||
|
||||
import {
|
||||
maybeRedirectToTokenAuthUrl,
|
||||
redirectToStaticPage,
|
||||
redirectWithStoredParams,
|
||||
reloadWithStoredParams
|
||||
@@ -170,8 +171,16 @@ export function reloadNow() {
|
||||
const state = getState();
|
||||
const { locationURL } = state['features/base/connection'];
|
||||
|
||||
logger.info(`Reloading the conference using URL: ${locationURL}`);
|
||||
const reloadAction = () => {
|
||||
logger.info(`Reloading the conference using URL: ${locationURL}`);
|
||||
|
||||
dispatch(reloadWithStoredParams());
|
||||
dispatch(reloadWithStoredParams());
|
||||
};
|
||||
|
||||
if (maybeRedirectToTokenAuthUrl(dispatch, getState, reloadAction)) {
|
||||
return;
|
||||
}
|
||||
|
||||
reloadAction();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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,14 +111,22 @@ 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.
|
||||
if (Platform.OS === 'ios' && DeviceInfo.isEmulatorSync()) {
|
||||
flags['call-integration.enabled'] = false;
|
||||
flags[CALL_INTEGRATION_ENABLED] = false;
|
||||
callIntegrationEnabled = false;
|
||||
logger.info('Disabling CallKit because this is a simulator');
|
||||
}
|
||||
|
||||
// Disable Android ConnectionService by default.
|
||||
if (Platform.OS === 'android' && typeof callIntegrationEnabled === 'undefined') {
|
||||
flags[CALL_INTEGRATION_ENABLED] = false;
|
||||
callIntegrationEnabled = false;
|
||||
}
|
||||
|
||||
// We set these early enough so then we avoid any unnecessary re-renders.
|
||||
dispatch?.(updateFlags(flags));
|
||||
|
||||
@@ -145,26 +153,21 @@ 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.
|
||||
const callIntegrationEnabled = flags[CALL_INTEGRATION_ENABLED as keyof typeof flags];
|
||||
|
||||
if (typeof callIntegrationEnabled !== 'undefined') {
|
||||
dispatch?.(updateSettings({ disableCallIntegration: !callIntegrationEnabled }));
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
// @ts-expect-error
|
||||
import { generateRoomWithoutSeparator } from '@jitsi/js-utils/random';
|
||||
|
||||
import { getTokenAuthUrl } from '../authentication/functions';
|
||||
import { getTokenAuthUrl } from '../authentication/functions.web';
|
||||
import { IStateful } from '../base/app/types';
|
||||
import { isRoomValid } from '../base/conference/functions';
|
||||
import { isSupportedBrowser } from '../base/environment/environment';
|
||||
import { browser } from '../base/lib-jitsi-meet';
|
||||
import { toState } from '../base/redux/functions';
|
||||
import { parseURIString } from '../base/util/uri';
|
||||
import Conference from '../conference/components/web/Conference';
|
||||
import { getDeepLinkingPage } from '../deep-linking/functions';
|
||||
import UnsupportedDesktopBrowser from '../unsupported-browser/components/UnsupportedDesktopBrowser';
|
||||
@@ -52,9 +53,28 @@ function _getWebConferenceRoute(state: IReduxState) {
|
||||
if (!browser.isElectron() && config.tokenAuthUrl && config.tokenAuthUrlAutoRedirect
|
||||
&& state['features/authentication'].tokenAuthUrlSuccessful
|
||||
&& !state['features/base/jwt'].jwt && room) {
|
||||
route.href = getTokenAuthUrl(config, room);
|
||||
const { locationURL = { href: '' } as URL } = state['features/base/connection'];
|
||||
const { tenant } = parseURIString(locationURL.href) || {};
|
||||
const { startAudioOnly } = config;
|
||||
|
||||
return Promise.resolve(route);
|
||||
return getTokenAuthUrl(
|
||||
config,
|
||||
locationURL,
|
||||
{
|
||||
audioMuted: false,
|
||||
audioOnlyEnabled: startAudioOnly,
|
||||
skipPrejoin: false,
|
||||
videoMuted: false
|
||||
},
|
||||
room,
|
||||
tenant
|
||||
)
|
||||
.then((url: string | undefined) => {
|
||||
route.href = url;
|
||||
|
||||
return route;
|
||||
})
|
||||
.catch(() => Promise.resolve(route));
|
||||
}
|
||||
|
||||
// Update the location if it doesn't match. This happens when a room is
|
||||
|
||||
@@ -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';
|
||||
@@ -27,6 +26,7 @@ import '../connection-indicator/middleware';
|
||||
import '../deep-linking/middleware';
|
||||
import '../device-selection/middleware';
|
||||
import '../display-name/middleware';
|
||||
import '../dynamic-branding/middleware';
|
||||
import '../etherpad/middleware';
|
||||
import '../filmstrip/middleware';
|
||||
import '../follow-me/middleware';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import '../base/app/middleware';
|
||||
import '../base/connection/middleware';
|
||||
import '../base/i18n/middleware';
|
||||
import '../base/devices/middleware';
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { Linking, Platform } from 'react-native';
|
||||
import { Linking } from 'react-native';
|
||||
|
||||
import { appNavigate } from '../app/actions.native';
|
||||
import { IStore } from '../app/types';
|
||||
import { conferenceLeft } from '../base/conference/actions';
|
||||
import { connectionFailed } from '../base/connection/actions.native';
|
||||
import { set } from '../base/redux/functions';
|
||||
import { appendURLHashParam } from '../base/util/uri';
|
||||
|
||||
import { CANCEL_LOGIN } from './actionTypes';
|
||||
import { stopWaitForOwner } from './actions.any';
|
||||
@@ -85,12 +84,7 @@ export function redirectToDefaultLocation() {
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function openTokenAuthUrl(tokenAuthServiceUrl: string) {
|
||||
let url = appendURLHashParam(tokenAuthServiceUrl, 'skipPrejoin', 'true');
|
||||
|
||||
// Append ios=true or android=true to the token URL.
|
||||
url = appendURLHashParam(url, Platform.OS, 'true');
|
||||
|
||||
return () => {
|
||||
Linking.openURL(url);
|
||||
Linking.openURL(tokenAuthServiceUrl);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { maybeRedirectToWelcomePage } from '../app/actions.web';
|
||||
import { IStore } from '../app/types';
|
||||
import { openDialog } from '../base/dialog/actions';
|
||||
import { browser } from '../base/lib-jitsi-meet';
|
||||
import { appendURLHashParam } from '../base/util/uri';
|
||||
|
||||
import { CANCEL_LOGIN } from './actionTypes';
|
||||
import LoginQuestionDialog from './components/web/LoginQuestionDialog';
|
||||
@@ -57,14 +56,10 @@ export function redirectToDefaultLocation() {
|
||||
export function openTokenAuthUrl(tokenAuthServiceUrl: string): any {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const redirect = () => {
|
||||
// We have already shown the prejoin screen, no need to show it again after obtaining the token.
|
||||
let url = appendURLHashParam(tokenAuthServiceUrl, 'skipPrejoin', 'true');
|
||||
|
||||
if (browser.isElectron()) {
|
||||
url = appendURLHashParam(url, 'electron', 'true');
|
||||
window.open(url, '_blank');
|
||||
window.open(tokenAuthServiceUrl, '_blank');
|
||||
} else {
|
||||
window.location.href = url;
|
||||
window.location.href = tokenAuthServiceUrl;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -73,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 {
|
||||
|
||||
@@ -17,6 +17,11 @@ interface IProps {
|
||||
*/
|
||||
_alternativeCancelText?: boolean;
|
||||
|
||||
/**
|
||||
* Is confirm button hidden?
|
||||
*/
|
||||
_isConfirmHidden?: boolean;
|
||||
|
||||
/**
|
||||
* Redux store dispatch function.
|
||||
*/
|
||||
@@ -56,11 +61,14 @@ class WaitForOwnerDialog extends Component<IProps> {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { _isConfirmHidden } = this.props;
|
||||
|
||||
return (
|
||||
<ConfirmDialog
|
||||
cancelLabel = { this.props._alternativeCancelText ? 'dialog.WaitingForHostButton' : 'dialog.Cancel' }
|
||||
confirmLabel = 'dialog.IamHost'
|
||||
descriptionKey = 'dialog.WaitForHostMsg'
|
||||
isConfirmHidden = { _isConfirmHidden }
|
||||
onCancel = { this._onCancel }
|
||||
onSubmit = { this._onLogin } />
|
||||
);
|
||||
@@ -97,9 +105,11 @@ class WaitForOwnerDialog extends Component<IProps> {
|
||||
*/
|
||||
function mapStateToProps(state: IReduxState) {
|
||||
const { membersOnly, lobbyWaitingForHost } = state['features/base/conference'];
|
||||
const { locationURL } = state['features/base/connection'];
|
||||
|
||||
return {
|
||||
_alternativeCancelText: membersOnly && lobbyWaitingForHost
|
||||
_alternativeCancelText: membersOnly && lobbyWaitingForHost,
|
||||
_isConfirmHidden: locationURL?.hostname?.includes('8x8.vc')
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
86
react/features/authentication/functions.any.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { IConfig } from '../base/config/configType';
|
||||
import { getBackendSafeRoomName } from '../base/util/uri';
|
||||
|
||||
/**
|
||||
* Checks if the token for authentication is available.
|
||||
*
|
||||
* @param {Object} config - Configuration state object from store.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isTokenAuthEnabled = (config: IConfig): boolean =>
|
||||
typeof config.tokenAuthUrl === 'string' && config.tokenAuthUrl.length > 0;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @returns {Object} The state object.
|
||||
*/
|
||||
export const _getTokenAuthState = (
|
||||
locationURL: URL,
|
||||
options: {
|
||||
audioMuted: boolean | undefined;
|
||||
audioOnlyEnabled: boolean | undefined;
|
||||
skipPrejoin: boolean | undefined;
|
||||
videoMuted: boolean | undefined;
|
||||
},
|
||||
roomName: string | undefined,
|
||||
tenant: string | undefined): object => {
|
||||
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) {
|
||||
// we allow only config and interfaceConfig overrides in the state
|
||||
if (key.startsWith('config.') || key.startsWith('interfaceConfig.')) {
|
||||
// @ts-ignore
|
||||
state[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
};
|
||||
78
react/features/authentication/functions.native.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
import { IConfig } from '../base/config/configType';
|
||||
|
||||
import { _getTokenAuthState } from './functions.any';
|
||||
|
||||
export * from './functions.any';
|
||||
|
||||
/**
|
||||
* Creates the URL pointing to JWT token authentication service. It is
|
||||
* formatted from the 'urlPattern' argument which can contain the following
|
||||
* constants:
|
||||
* '{room}' - name of the conference room passed as <tt>roomName</tt>
|
||||
* argument to this method.
|
||||
*
|
||||
* @param {Object} config - Configuration state object from store. A URL pattern pointing to the login service.
|
||||
* @param {URL} locationURL - The location URL.
|
||||
* @param {Object} options: - Config options {
|
||||
* audioMuted: boolean | undefined
|
||||
* audioOnlyEnabled: boolean | undefined,
|
||||
* skipPrejoin: boolean | undefined,
|
||||
* videoMuted: boolean | undefined
|
||||
* }.
|
||||
* @param {string?} roomName - The room name.
|
||||
* @param {string?} tenant - The tenant name if any.
|
||||
*
|
||||
* @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
|
||||
* constructed.
|
||||
*/
|
||||
export const getTokenAuthUrl = (
|
||||
config: IConfig,
|
||||
locationURL: URL,
|
||||
options: {
|
||||
audioMuted: boolean | undefined;
|
||||
audioOnlyEnabled: boolean | undefined;
|
||||
skipPrejoin: boolean | undefined;
|
||||
videoMuted: boolean | undefined;
|
||||
},
|
||||
roomName: string | undefined,
|
||||
// eslint-disable-next-line max-params
|
||||
tenant: string | undefined): Promise<string | undefined> => {
|
||||
|
||||
const {
|
||||
audioMuted = false,
|
||||
audioOnlyEnabled = false,
|
||||
skipPrejoin = false,
|
||||
videoMuted = false
|
||||
} = options;
|
||||
|
||||
let url = config.tokenAuthUrl;
|
||||
|
||||
if (!url || !roomName) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
if (url.indexOf('{state}')) {
|
||||
const state = _getTokenAuthState(
|
||||
locationURL,
|
||||
{
|
||||
audioMuted,
|
||||
audioOnlyEnabled,
|
||||
skipPrejoin,
|
||||
videoMuted
|
||||
},
|
||||
roomName,
|
||||
tenant
|
||||
);
|
||||
|
||||
// Append ios=true or android=true to the token URL.
|
||||
// @ts-ignore
|
||||
state[Platform.OS] = true;
|
||||
|
||||
url = url.replace('{state}', encodeURIComponent(JSON.stringify(state)));
|
||||
}
|
||||
|
||||
return Promise.resolve(url.replace('{room}', roomName));
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
import { IConfig } from '../base/config/configType';
|
||||
|
||||
/**
|
||||
* Checks if the token for authentication is available.
|
||||
*
|
||||
* @param {Object} config - Configuration state object from store.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isTokenAuthEnabled = (config: IConfig) =>
|
||||
typeof config.tokenAuthUrl === 'string'
|
||||
&& config.tokenAuthUrl.length;
|
||||
|
||||
/**
|
||||
* Creates the URL pointing to JWT token authentication service. It is
|
||||
* formatted from the 'urlPattern' argument which can contain the following
|
||||
* constants:
|
||||
* '{room}' - name of the conference room passed as <tt>roomName</tt>
|
||||
* argument to this method.
|
||||
* '{roleUpgrade}' - will contain 'true' if the URL will be used for
|
||||
* the role upgrade scenario, where user connects from anonymous domain and
|
||||
* then gets upgraded to the moderator by logging-in from the popup window.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @returns {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
|
||||
* constructed.
|
||||
*/
|
||||
export const getTokenAuthUrl = (config: IConfig, roomName: string | undefined) => {
|
||||
|
||||
const url = config.tokenAuthUrl;
|
||||
|
||||
if (typeof url !== 'string' || !roomName) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return url.replace('{room}', roomName);
|
||||
};
|
||||
122
react/features/authentication/functions.web.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import base64js from 'base64-js';
|
||||
|
||||
import { IConfig } from '../base/config/configType';
|
||||
import { browser } from '../base/lib-jitsi-meet';
|
||||
|
||||
import { _getTokenAuthState } from './functions.any';
|
||||
|
||||
export * from './functions.any';
|
||||
|
||||
/**
|
||||
* Based on rfc7636 we need a random string for a code verifier.
|
||||
*/
|
||||
const POSSIBLE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
|
||||
/**
|
||||
* Crypto random, alternative of Math.random.
|
||||
*
|
||||
* @returns {float} A random value.
|
||||
*/
|
||||
function _cryptoRandom() {
|
||||
const typedArray = new Uint8Array(1);
|
||||
const randomValue = crypto.getRandomValues(typedArray)[0];
|
||||
|
||||
return randomValue / Math.pow(2, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the URL pointing to JWT token authentication service. It is
|
||||
* formatted from the 'urlPattern' argument which can contain the following
|
||||
* constants:
|
||||
* '{room}' - name of the conference room passed as <tt>roomName</tt>
|
||||
* argument to this method.
|
||||
*
|
||||
* @param {Object} config - Configuration state object from store. A URL pattern pointing to the login service.
|
||||
* @param {URL} locationURL - The location URL.
|
||||
* @param {Object} options: - Config options {
|
||||
* audioMuted: boolean | undefined
|
||||
* audioOnlyEnabled: boolean | undefined,
|
||||
* skipPrejoin: boolean | undefined,
|
||||
* videoMuted: boolean | undefined
|
||||
* }.
|
||||
* @param {string?} roomName - The room name.
|
||||
* @param {string?} tenant - The tenant name if any.
|
||||
*
|
||||
* @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
|
||||
* constructed.
|
||||
*/
|
||||
export const getTokenAuthUrl = (
|
||||
config: IConfig,
|
||||
locationURL: URL,
|
||||
options: {
|
||||
audioMuted: boolean | undefined;
|
||||
audioOnlyEnabled: boolean | undefined;
|
||||
skipPrejoin: boolean | undefined;
|
||||
videoMuted: boolean | undefined;
|
||||
},
|
||||
roomName: string | undefined,
|
||||
// eslint-disable-next-line max-params
|
||||
tenant: string | undefined): Promise<string | undefined> => {
|
||||
|
||||
const {
|
||||
audioMuted = false,
|
||||
audioOnlyEnabled = false,
|
||||
skipPrejoin = false,
|
||||
videoMuted = false
|
||||
} = options;
|
||||
|
||||
let url = config.tokenAuthUrl;
|
||||
|
||||
if (!url || !roomName) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
if (url.indexOf('{state}')) {
|
||||
const state = _getTokenAuthState(
|
||||
locationURL,
|
||||
{
|
||||
audioMuted,
|
||||
audioOnlyEnabled,
|
||||
skipPrejoin,
|
||||
videoMuted
|
||||
},
|
||||
roomName,
|
||||
tenant
|
||||
);
|
||||
|
||||
if (browser.isElectron()) {
|
||||
// @ts-ignore
|
||||
state.electron = true;
|
||||
}
|
||||
|
||||
url = url.replace('{state}', encodeURIComponent(JSON.stringify(state)));
|
||||
}
|
||||
|
||||
url = url.replace('{room}', roomName);
|
||||
|
||||
if (url.indexOf('{code_challenge}')) {
|
||||
let codeVerifier = '';
|
||||
|
||||
// random string
|
||||
for (let i = 0; i < 64; i++) {
|
||||
codeVerifier += POSSIBLE_CHARS.charAt(Math.floor(_cryptoRandom() * POSSIBLE_CHARS.length));
|
||||
}
|
||||
|
||||
window.sessionStorage.setItem('code_verifier', codeVerifier);
|
||||
|
||||
return window.crypto.subtle.digest('SHA-256', new TextEncoder().encode(codeVerifier))
|
||||
.then(digest => {
|
||||
// prepare code challenge - base64 encoding without padding as described in:
|
||||
// https://datatracker.ietf.org/doc/html/rfc7636#appendix-A
|
||||
const codeChallenge = base64js.fromByteArray(new Uint8Array(digest))
|
||||
.replace(/=/g, '')
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_');
|
||||
|
||||
return url ? url.replace('{code_challenge}', codeChallenge) : undefined;
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve(url);
|
||||
};
|
||||
@@ -13,8 +13,10 @@ import {
|
||||
JitsiConferenceErrors,
|
||||
JitsiConnectionErrors
|
||||
} from '../base/lib-jitsi-meet';
|
||||
import { MEDIA_TYPE } from '../base/media/constants';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import { getBackendSafeRoomName } from '../base/util/uri';
|
||||
import { isLocalTrackMuted } from '../base/tracks/functions.any';
|
||||
import { parseURIString } from '../base/util/uri';
|
||||
import { openLogoutDialog } from '../settings/actions';
|
||||
|
||||
import {
|
||||
@@ -254,7 +256,12 @@ function _isWaitingForOwner({ getState }: IStore) {
|
||||
function _handleLogin({ dispatch, getState }: IStore) {
|
||||
const state = getState();
|
||||
const config = state['features/base/config'];
|
||||
const room = getBackendSafeRoomName(state['features/base/conference'].room);
|
||||
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!');
|
||||
@@ -268,16 +275,27 @@ function _handleLogin({ dispatch, getState }: IStore) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: This method will not preserve the other URL params that were originally passed.
|
||||
const tokenAuthServiceUrl = getTokenAuthUrl(config, room);
|
||||
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');
|
||||
|
||||
if (!tokenAuthServiceUrl) {
|
||||
logger.warn('Cannot handle login, token service URL is not set');
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(openTokenAuthUrl(tokenAuthServiceUrl));
|
||||
return dispatch(openTokenAuthUrl(tokenAuthServiceUrl));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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));
|
||||
@@ -2,6 +2,7 @@ import React, { PureComponent } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { IconUser } from '../../icons/svg';
|
||||
import { getParticipantById } from '../../participants/functions';
|
||||
import { IParticipant } from '../../participants/types';
|
||||
import { getAvatarColor, getInitials, isCORSAvatarURL } from '../functions';
|
||||
@@ -182,6 +183,7 @@ class Avatar<P extends IProps> extends PureComponent<P, IState> {
|
||||
|
||||
const avatarProps: AbstractProps & {
|
||||
className?: string;
|
||||
iconUser?: any;
|
||||
id?: string;
|
||||
status?: string;
|
||||
testId?: string;
|
||||
@@ -226,6 +228,10 @@ class Avatar<P extends IProps> extends PureComponent<P, IState> {
|
||||
avatarProps.initials = initials;
|
||||
}
|
||||
|
||||
if (navigator.product !== 'ReactNative') {
|
||||
avatarProps.iconUser = IconUser;
|
||||
}
|
||||
|
||||
return (
|
||||
<StatelessAvatar
|
||||
{ ...avatarProps } />
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { useCallback } from 'react';
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import Icon from '../../../icons/components/Icon';
|
||||
import { IconUser } from '../../../icons/svg';
|
||||
import { withPixelLineHeight } from '../../../styles/functions.web';
|
||||
import { isIcon } from '../../functions';
|
||||
import { IAvatarProps } from '../../types';
|
||||
@@ -122,6 +121,7 @@ const useStyles = makeStyles()(theme => {
|
||||
const StatelessAvatar = ({
|
||||
className,
|
||||
color,
|
||||
iconUser,
|
||||
id,
|
||||
initials,
|
||||
onAvatarLoadError,
|
||||
@@ -212,7 +212,7 @@ const StatelessAvatar = ({
|
||||
style = { _getAvatarStyle() }>
|
||||
<Icon
|
||||
size = { '50%' }
|
||||
src = { IconUser } />
|
||||
src = { iconUser } />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ const AVATAR_COLORS = [
|
||||
'#B23683',
|
||||
'#F96E57',
|
||||
'#4380E2',
|
||||
'#2AA076',
|
||||
'#238561',
|
||||
'#00A8B3'
|
||||
];
|
||||
const wordSplitRegex = (/\s+|\.+|_+|;+|-+|,+|\|+|\/+|\\+|"+|'+|\(+|\)+|#+|&+/);
|
||||
|
||||
@@ -5,6 +5,11 @@ export interface IAvatarProps {
|
||||
*/
|
||||
color?: string;
|
||||
|
||||
/**
|
||||
* The user icon(browser only).
|
||||
*/
|
||||
iconUser?: any;
|
||||
|
||||
/**
|
||||
* Initials to be used to render the initials based avatars.
|
||||
*/
|
||||
|
||||
@@ -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,8 +14,10 @@ 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';
|
||||
import { stopLocalVideoRecording } from '../../recording/actions.any';
|
||||
import LocalRecordingManager from '../../recording/components/Recording/LocalRecordingManager';
|
||||
import { iAmVisitor } from '../../visitors/functions';
|
||||
@@ -276,7 +278,9 @@ function _conferenceJoined({ dispatch, getState }: IStore, next: Function, actio
|
||||
if (requireDisplayName
|
||||
&& !getLocalParticipant(getState)?.name
|
||||
&& !conference.isHidden()) {
|
||||
dispatch(openDisplayNamePrompt(undefined));
|
||||
dispatch(openDisplayNamePrompt({
|
||||
validateInput: hasDisplayName
|
||||
}));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -303,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) {
|
||||
|
||||
@@ -59,6 +59,7 @@ export interface IJitsiConference {
|
||||
enableLobby: Function;
|
||||
end: Function;
|
||||
getBreakoutRooms: Function;
|
||||
getConnection: Function;
|
||||
getLocalParticipantProperty: Function;
|
||||
getLocalTracks: Function;
|
||||
getMeetingUniqueId: Function;
|
||||
@@ -72,7 +73,6 @@ export interface IJitsiConference {
|
||||
getSsrcByTrack: Function;
|
||||
grantOwner: Function;
|
||||
isAVModerationSupported: Function;
|
||||
isCallstatsEnabled: Function;
|
||||
isE2EEEnabled: Function;
|
||||
isE2EESupported: Function;
|
||||
isEndConferenceSupported: Function;
|
||||
@@ -156,11 +156,13 @@ export interface IConferenceState {
|
||||
|
||||
export interface IJitsiConferenceRoom {
|
||||
locked: boolean;
|
||||
moderator: {
|
||||
logout: Function;
|
||||
};
|
||||
myroomjid: string;
|
||||
roomjid: string;
|
||||
xmpp: {
|
||||
moderator: {
|
||||
logout: Function;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
interface IConferenceFailedError extends Error {
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ import _ from 'lodash';
|
||||
import { IReduxState, IStore } from '../../app/types';
|
||||
import { conferenceLeft, conferenceWillLeave, redirect } from '../conference/actions';
|
||||
import { getCurrentConference } from '../conference/functions';
|
||||
import { IConfigState } from '../config/reducer';
|
||||
import JitsiMeetJS, { JitsiConnectionEvents } from '../lib-jitsi-meet';
|
||||
import { parseURLParams } from '../util/parseURLParams';
|
||||
import {
|
||||
appendURLParam,
|
||||
getBackendSafeRoomName
|
||||
@@ -18,53 +20,15 @@ import {
|
||||
} from './actionTypes';
|
||||
import { JITSI_CONNECTION_URL_KEY } from './constants';
|
||||
import logger from './logger';
|
||||
import { ConnectionFailedError, IIceServers } from './types';
|
||||
|
||||
/**
|
||||
* The error structure passed to the {@link connectionFailed} action.
|
||||
*
|
||||
* Note there was an intention to make the error resemble an Error instance (to
|
||||
* the extent that jitsi-meet needs it).
|
||||
* The options that will be passed to the JitsiConnection instance.
|
||||
*/
|
||||
export type ConnectionFailedError = {
|
||||
|
||||
/**
|
||||
* The invalid credentials that were used to authenticate and the
|
||||
* authentication failed.
|
||||
*/
|
||||
credentials?: {
|
||||
|
||||
/**
|
||||
* The XMPP user's ID.
|
||||
*/
|
||||
jid: string;
|
||||
|
||||
/**
|
||||
* The XMPP user's password.
|
||||
*/
|
||||
password: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* The details about the connection failed event.
|
||||
*/
|
||||
details?: Object;
|
||||
|
||||
/**
|
||||
* Error message.
|
||||
*/
|
||||
message?: string;
|
||||
|
||||
/**
|
||||
* One of {@link JitsiConnectionError} constants (defined in
|
||||
* lib-jitsi-meet).
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Indicates whether this event is recoverable or not.
|
||||
*/
|
||||
recoverable?: boolean;
|
||||
};
|
||||
interface IOptions extends IConfigState {
|
||||
iceServersOverride?: IIceServers;
|
||||
preferVisitor?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an action for when the signaling connection has been lost.
|
||||
@@ -147,9 +111,17 @@ export function connectionFailed(
|
||||
export function constructOptions(state: IReduxState) {
|
||||
// Deep clone the options to make sure we don't modify the object in the
|
||||
// redux store.
|
||||
const options = _.cloneDeep(state['features/base/config']);
|
||||
const options: IOptions = _.cloneDeep(state['features/base/config']);
|
||||
|
||||
const { bosh } = options;
|
||||
const { locationURL, preferVisitor } = state['features/base/connection'];
|
||||
const params = parseURLParams(locationURL || '');
|
||||
const iceServersOverride = params['iceServers.replace'];
|
||||
|
||||
if (iceServersOverride) {
|
||||
options.iceServersOverride = iceServersOverride;
|
||||
}
|
||||
|
||||
const { bosh, preferBosh } = options;
|
||||
let { websocket } = options;
|
||||
|
||||
// TESTING: Only enable WebSocket for some percentage of users.
|
||||
@@ -159,6 +131,10 @@ export function constructOptions(state: IReduxState) {
|
||||
}
|
||||
}
|
||||
|
||||
if (preferBosh) {
|
||||
websocket = undefined;
|
||||
}
|
||||
|
||||
// WebSocket is preferred over BOSH.
|
||||
const serviceUrl = websocket || bosh;
|
||||
|
||||
@@ -180,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';
|
||||
@@ -11,7 +12,7 @@ import {
|
||||
SET_LOCATION_URL,
|
||||
SHOW_CONNECTION_INFO
|
||||
} from './actionTypes';
|
||||
import { ConnectionFailedError } from './actions.any';
|
||||
import { ConnectionFailedError } from './types';
|
||||
|
||||
export interface IConnectionState {
|
||||
connecting?: any;
|
||||
@@ -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.
|
||||
|
||||
113
react/features/base/connection/types.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* The error structure passed to the {@link connectionFailed} action.
|
||||
*
|
||||
* Note there was an intention to make the error resemble an Error instance (to
|
||||
* the extent that jitsi-meet needs it).
|
||||
*/
|
||||
export type ConnectionFailedError = {
|
||||
|
||||
/**
|
||||
* The invalid credentials that were used to authenticate and the
|
||||
* authentication failed.
|
||||
*/
|
||||
credentials?: {
|
||||
|
||||
/**
|
||||
* The XMPP user's ID.
|
||||
*/
|
||||
jid: string;
|
||||
|
||||
/**
|
||||
* The XMPP user's password.
|
||||
*/
|
||||
password: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* The details about the connection failed event.
|
||||
*/
|
||||
details?: Object;
|
||||
|
||||
/**
|
||||
* Error message.
|
||||
*/
|
||||
message?: string;
|
||||
|
||||
/**
|
||||
* One of {@link JitsiConnectionError} constants (defined in
|
||||
* lib-jitsi-meet).
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Indicates whether this event is recoverable or not.
|
||||
*/
|
||||
recoverable?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* The value for the username or credential property.
|
||||
*/
|
||||
type ReplaceIceServersField = string | null;
|
||||
|
||||
/**
|
||||
* The value for the urls property.
|
||||
*/
|
||||
type IceServerUrls = null | string | Array<string>;
|
||||
|
||||
/**
|
||||
* The types of ice servers.
|
||||
*/
|
||||
enum IceServerType {
|
||||
STUN = 'stun',
|
||||
TURN = 'turn',
|
||||
TURNS = 'turns'
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a single override rule.
|
||||
*/
|
||||
interface IReplaceIceServer {
|
||||
|
||||
/**
|
||||
* The value the credential prop will be replaced with.
|
||||
*
|
||||
* NOTE: If the value is null we will remove the credential property in entry that matches the target type. If the
|
||||
* value is undefined or missing we won't change the credential property in the entry that matches the target type.
|
||||
*/
|
||||
credential?: ReplaceIceServersField;
|
||||
|
||||
/**
|
||||
* Target type that will be used to match the already received ice server and modify/remove it based on the values
|
||||
* of credential, urls and username.
|
||||
*/
|
||||
targetType: IceServerType;
|
||||
|
||||
/**
|
||||
* The value the urls prop will be replaced with.
|
||||
*
|
||||
* NOTE: If the value is null we will remove the whole entry that matches the target type. If the value is undefined
|
||||
* or missing we won't change the urls property in the entry that matches the target type.
|
||||
*/
|
||||
urls?: IceServerUrls;
|
||||
|
||||
/**
|
||||
* The value the username prop will be replaced with.
|
||||
*
|
||||
* NOTE: If the value is null we will remove the username property in entry that matches the target type. If the
|
||||
* value is undefined or missing we won't change the username property in the entry that matches the target type.
|
||||
*/
|
||||
username?: ReplaceIceServersField;
|
||||
}
|
||||
|
||||
/**
|
||||
* An object with rules for changing the existing ice server configuration.
|
||||
*/
|
||||
export interface IIceServers {
|
||||
|
||||
/**
|
||||
* An array of rules for replacing parts from the existing ice server configuration.
|
||||
*/
|
||||
replace: Array<IReplaceIceServer>;
|
||||
}
|
||||
|
||||
@@ -16,9 +16,13 @@ import {
|
||||
} from './actionTypes';
|
||||
import {
|
||||
areDeviceLabelsInitialized,
|
||||
areDevicesDifferent,
|
||||
filterIgnoredDevices,
|
||||
flattenAvailableDevices,
|
||||
getDeviceIdByLabel,
|
||||
getDeviceLabelById,
|
||||
getDevicesFromURL,
|
||||
logDevices,
|
||||
setAudioOutputDeviceId
|
||||
} from './functions';
|
||||
import logger from './logger';
|
||||
@@ -39,7 +43,7 @@ const DEVICE_TYPE_TO_SETTINGS_KEYS = {
|
||||
userSelectedDeviceLabel: 'userSelectedAudioOutputDeviceLabel'
|
||||
},
|
||||
videoInput: {
|
||||
currentDeviceId: 'audioOutputDeviceId',
|
||||
currentDeviceId: 'cameraDeviceId',
|
||||
userSelectedDeviceId: 'userSelectedCameraDeviceId',
|
||||
userSelectedDeviceLabel: 'userSelectedCameraDeviceLabel'
|
||||
}
|
||||
@@ -137,15 +141,21 @@ export function configureInitialDevices() {
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function getAvailableDevices() {
|
||||
return (dispatch: IStore['dispatch']) => new Promise(resolve => {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => new Promise(resolve => {
|
||||
const { mediaDevices } = JitsiMeetJS;
|
||||
|
||||
if (mediaDevices.isDeviceListAvailable()
|
||||
&& mediaDevices.isDeviceChangeAvailable()) {
|
||||
mediaDevices.enumerateDevices((devices: MediaDeviceInfo[]) => {
|
||||
dispatch(updateDeviceList(devices));
|
||||
const { filteredDevices, ignoredDevices } = filterIgnoredDevices(devices);
|
||||
const oldDevices = flattenAvailableDevices(getState()['features/base/devices'].availableDevices);
|
||||
|
||||
resolve(devices);
|
||||
if (areDevicesDifferent(oldDevices, filteredDevices)) {
|
||||
logDevices(ignoredDevices, 'Ignored devices on device list changed:');
|
||||
dispatch(updateDeviceList(filteredDevices));
|
||||
}
|
||||
|
||||
resolve(filteredDevices);
|
||||
});
|
||||
} else {
|
||||
resolve([]);
|
||||
|
||||
8
react/features/base/devices/constants.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Prefixes of devices that will be filtered from the device list.
|
||||
*
|
||||
* NOTE: Currently we filter only 'Microsoft Teams Audio Device' virtual device. It seems that it can't be set
|
||||
* as default device on the OS level and this use case is not handled in the code. If we add more device prefixes that
|
||||
* can be default devices we should make sure to handle the default device use case.
|
||||
*/
|
||||
export const DEVICE_LABEL_PREFIXES_TO_IGNORE = [ 'Microsoft Teams Audio Device' ];
|
||||