mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-02-09 15:30:18 +00:00
Compare commits
194 Commits
5083
...
enable-deb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1433a1ee5d | ||
|
|
834ee22bc3 | ||
|
|
d6b5687828 | ||
|
|
6b496d4def | ||
|
|
22cc56ce8d | ||
|
|
0419c5a15b | ||
|
|
dda1f3c5ba | ||
|
|
6f41ef75d7 | ||
|
|
46cbc0ff49 | ||
|
|
53a695da90 | ||
|
|
8bbee7d1dc | ||
|
|
72d4aa7dd5 | ||
|
|
8161309e28 | ||
|
|
465e7f1458 | ||
|
|
4e43a31ec9 | ||
|
|
70c5ea04b1 | ||
|
|
ca25be7314 | ||
|
|
3c2ad24652 | ||
|
|
e421a119e1 | ||
|
|
619acaca24 | ||
|
|
bc9f5773fb | ||
|
|
d0be8dcf9d | ||
|
|
af9958ad66 | ||
|
|
efc5c9dabe | ||
|
|
d22fc88ae3 | ||
|
|
9ee75038b6 | ||
|
|
09af88088d | ||
|
|
2e539ba010 | ||
|
|
87b3ec2cc0 | ||
|
|
907b51925d | ||
|
|
643340c4a6 | ||
|
|
d6c821d524 | ||
|
|
eb16f93153 | ||
|
|
47576aebba | ||
|
|
bac0a55421 | ||
|
|
1c8103c444 | ||
|
|
4e83e93eb6 | ||
|
|
0f8fa4f059 | ||
|
|
becaf0806a | ||
|
|
5b77d722d7 | ||
|
|
f4cde2192e | ||
|
|
e91df47d1b | ||
|
|
2d04f3852c | ||
|
|
2209394d09 | ||
|
|
1e76dc0aa2 | ||
|
|
75edfc1fab | ||
|
|
8c20dd8e47 | ||
|
|
fefe451180 | ||
|
|
b268e01a42 | ||
|
|
d62e378528 | ||
|
|
e8ad2365b6 | ||
|
|
b7389e1c31 | ||
|
|
eeddf6b350 | ||
|
|
665b7730ee | ||
|
|
7854437e31 | ||
|
|
600af62945 | ||
|
|
88ddb8d9b4 | ||
|
|
5182a720f9 | ||
|
|
415562c315 | ||
|
|
53d0a892b5 | ||
|
|
9b220f3870 | ||
|
|
c6e50ad439 | ||
|
|
36cb896680 | ||
|
|
249515ac60 | ||
|
|
80b49266ab | ||
|
|
1afae50923 | ||
|
|
b332fb474b | ||
|
|
a12ad99ecf | ||
|
|
400f47963d | ||
|
|
65fbc6f256 | ||
|
|
e7a324185f | ||
|
|
14a5c45fa3 | ||
|
|
05e6dde341 | ||
|
|
e13473d42f | ||
|
|
4b72fefd7e | ||
|
|
ba9398a1e2 | ||
|
|
8d4cf7165e | ||
|
|
0b3991d9e1 | ||
|
|
47be509d17 | ||
|
|
ba64d3e0c8 | ||
|
|
cd05c34d19 | ||
|
|
24550777c6 | ||
|
|
ee101f8947 | ||
|
|
8ca85f9e1c | ||
|
|
34ccd56691 | ||
|
|
f49c05c666 | ||
|
|
e7280e5040 | ||
|
|
eb1add681f | ||
|
|
8419dc725c | ||
|
|
f984faef3f | ||
|
|
0c76d7532c | ||
|
|
cb0b68f840 | ||
|
|
08a4da22f3 | ||
|
|
bdd6638067 | ||
|
|
8b44e06f2c | ||
|
|
79edc1b358 | ||
|
|
6597bfc2aa | ||
|
|
e0a2320d75 | ||
|
|
81e9fca03b | ||
|
|
76f8302aeb | ||
|
|
7263829763 | ||
|
|
b7ab3ea052 | ||
|
|
c657f360e1 | ||
|
|
ae5edf5a62 | ||
|
|
2bac757ca6 | ||
|
|
c10805f81b | ||
|
|
251eec19cd | ||
|
|
4276f82c03 | ||
|
|
4c3aae1e28 | ||
|
|
12be14bd4b | ||
|
|
420a7d8110 | ||
|
|
17f77a4246 | ||
|
|
6f9944a2d0 | ||
|
|
73328810e4 | ||
|
|
bb8c30a6c9 | ||
|
|
c5438ecd0c | ||
|
|
e22a25b216 | ||
|
|
4075e5deb7 | ||
|
|
ea0d953d1c | ||
|
|
b3e03fe50c | ||
|
|
8f81a75a61 | ||
|
|
0ab905bf75 | ||
|
|
5a3607f63f | ||
|
|
d57e202d19 | ||
|
|
1223c63f69 | ||
|
|
25b4887f74 | ||
|
|
e8ee65db82 | ||
|
|
9956ca6551 | ||
|
|
03a96d0be2 | ||
|
|
3fa7c01f19 | ||
|
|
5cba6c7bc7 | ||
|
|
52ee9b5151 | ||
|
|
d5f379a97c | ||
|
|
84cdd31731 | ||
|
|
b7eba915af | ||
|
|
7d0722c031 | ||
|
|
7d3953de51 | ||
|
|
601ee219e7 | ||
|
|
8db3a341b3 | ||
|
|
8d562b9d59 | ||
|
|
80e2c05219 | ||
|
|
0bdc7d42c5 | ||
|
|
d87a40e77e | ||
|
|
bad58f6508 | ||
|
|
dc60418613 | ||
|
|
f2f545a57f | ||
|
|
d72b27d46d | ||
|
|
e1fef8d848 | ||
|
|
33f1199fc8 | ||
|
|
62c78950cd | ||
|
|
074a783bd9 | ||
|
|
da7358d564 | ||
|
|
58ef72dce5 | ||
|
|
7f44442b21 | ||
|
|
b995221a2b | ||
|
|
0507f8c2f9 | ||
|
|
df1561c198 | ||
|
|
ae9bea1a0c | ||
|
|
2174368d23 | ||
|
|
abc984f83b | ||
|
|
d9bfeecb5b | ||
|
|
24503c3bd3 | ||
|
|
d4c7fc8a72 | ||
|
|
5fcd5ff17b | ||
|
|
62bb259182 | ||
|
|
027e1ba978 | ||
|
|
a866be787f | ||
|
|
0381f714fc | ||
|
|
5d6e88b53a | ||
|
|
a8044c43e2 | ||
|
|
13f9299921 | ||
|
|
c356c2360c | ||
|
|
01867ed343 | ||
|
|
765fbe5e1d | ||
|
|
ea56010e09 | ||
|
|
38b14c5d62 | ||
|
|
74d65ff596 | ||
|
|
1d45edbb27 | ||
|
|
7945f14cee | ||
|
|
35c7f156db | ||
|
|
f82d46337b | ||
|
|
07a69ba040 | ||
|
|
2d319d18c3 | ||
|
|
16cfda3c7a | ||
|
|
64ae9c7953 | ||
|
|
3e8f725c62 | ||
|
|
2a9b3dc1b2 | ||
|
|
487da8f231 | ||
|
|
804d14e112 | ||
|
|
53cea31bb8 | ||
|
|
e6cdeb31ff | ||
|
|
60db81f31c | ||
|
|
0e6addbfad | ||
|
|
0a37ef7d46 |
@@ -25,5 +25,5 @@ android.enableDexingArtifactTransform.desugaring=false
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
appVersion=21.2.0
|
||||
sdkVersion=3.6.0
|
||||
appVersion=21.3.0
|
||||
sdkVersion=3.8.0
|
||||
|
||||
@@ -70,11 +70,13 @@ dependencies {
|
||||
implementation project(':react-native-default-preference')
|
||||
implementation project(':react-native-immersive')
|
||||
implementation project(':react-native-keep-awake')
|
||||
implementation project(':react-native-slider')
|
||||
implementation project(':react-native-sound')
|
||||
implementation project(':react-native-splash-screen')
|
||||
implementation project(':react-native-svg')
|
||||
implementation project(':react-native-video')
|
||||
implementation project(':react-native-webrtc')
|
||||
implementation project(':react-native-webview')
|
||||
implementation project(':react-native-splash-screen')
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
|
||||
<service
|
||||
android:name=".ConnectionService"
|
||||
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
|
||||
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.telecom.ConnectionService" />
|
||||
</intent-filter>
|
||||
|
||||
@@ -47,7 +47,7 @@ class LocaleDetector extends ReactContextBaseJavaModule {
|
||||
public Map<String, Object> getConstants() {
|
||||
Context context = getReactApplicationContext();
|
||||
HashMap<String,Object> constants = new HashMap<>();
|
||||
constants.put("locale", context.getResources().getConfiguration().locale.toString());
|
||||
constants.put("locale", context.getResources().getConfiguration().locale.toLanguageTag());
|
||||
return constants;
|
||||
}
|
||||
|
||||
@@ -55,4 +55,4 @@ class LocaleDetector extends ReactContextBaseJavaModule {
|
||||
public String getName() {
|
||||
return "LocaleDetector";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,9 +187,11 @@ class ReactInstanceManagerHolder {
|
||||
new com.ocetnik.timer.BackgroundTimerPackage(),
|
||||
new com.reactnativecommunity.asyncstorage.AsyncStoragePackage(),
|
||||
new com.reactnativecommunity.netinfo.NetInfoPackage(),
|
||||
new com.reactnativecommunity.slider.ReactSliderPackage(),
|
||||
new com.reactnativecommunity.webview.RNCWebViewPackage(),
|
||||
new com.rnimmersive.RNImmersivePackage(),
|
||||
new com.zmxv.RNSound.RNSoundPackage(),
|
||||
new com.brentvatne.react.ReactVideoPackage(),
|
||||
new ReactPackageAdapter() {
|
||||
@Override
|
||||
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
||||
|
||||
@@ -19,13 +19,17 @@ include ':react-native-immersive'
|
||||
project(':react-native-immersive').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-immersive/android')
|
||||
include ':react-native-keep-awake'
|
||||
project(':react-native-keep-awake').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keep-awake/android')
|
||||
include ':react-native-slider'
|
||||
project(':react-native-slider').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/slider/android')
|
||||
include ':react-native-sound'
|
||||
project(':react-native-sound').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sound/android')
|
||||
include ':react-native-splash-screen'
|
||||
project(':react-native-splash-screen').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-splash-screen/android')
|
||||
include ':react-native-svg'
|
||||
project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-svg/android')
|
||||
include ':react-native-video'
|
||||
project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android')
|
||||
include ':react-native-webrtc'
|
||||
project(':react-native-webrtc').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webrtc/android')
|
||||
include ':react-native-webview'
|
||||
project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android')
|
||||
project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android')
|
||||
|
||||
@@ -39,6 +39,7 @@ import {
|
||||
conferenceWillJoin,
|
||||
conferenceWillLeave,
|
||||
dataChannelOpened,
|
||||
getConferenceOptions,
|
||||
kickedOut,
|
||||
lockStateChanged,
|
||||
onStartMutedPolicyChanged,
|
||||
@@ -111,7 +112,6 @@ import {
|
||||
trackRemoved
|
||||
} from './react/features/base/tracks';
|
||||
import { downloadJSON } from './react/features/base/util/downloadJSON';
|
||||
import { getConferenceOptions } from './react/features/conference/functions';
|
||||
import { showDesktopPicker } from './react/features/desktop-picker';
|
||||
import { appendSuffix } from './react/features/display-name';
|
||||
import {
|
||||
@@ -132,6 +132,7 @@ import { setScreenAudioShareState, isScreenAudioShared } from './react/features/
|
||||
import { toggleScreenshotCaptureEffect } from './react/features/screenshot-capture';
|
||||
import { AudioMixerEffect } from './react/features/stream-effects/audio-mixer/AudioMixerEffect';
|
||||
import { createPresenterEffect } from './react/features/stream-effects/presenter';
|
||||
import { createRnnoiseProcessor } from './react/features/stream-effects/rnnoise';
|
||||
import { endpointMessageReceived } from './react/features/subtitles';
|
||||
import UIEvents from './service/UI/UIEvents';
|
||||
|
||||
@@ -1357,7 +1358,11 @@ export default {
|
||||
},
|
||||
|
||||
_getConferenceOptions() {
|
||||
return getConferenceOptions(APP.store.getState());
|
||||
const options = getConferenceOptions(APP.store.getState());
|
||||
|
||||
options.createVADProcessor = createRnnoiseProcessor;
|
||||
|
||||
return options;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -1867,7 +1872,6 @@ export default {
|
||||
await this.useVideoStream(desktopVideoStream);
|
||||
}
|
||||
|
||||
|
||||
if (this._desktopAudioStream) {
|
||||
// If there is a localAudio stream, mix in the desktop audio stream captured by the screen sharing
|
||||
// api.
|
||||
@@ -2186,6 +2190,10 @@ export default {
|
||||
id: localParticipant.id,
|
||||
isReplaced
|
||||
}));
|
||||
|
||||
// we send readyToClose when kicked participant is replace so that
|
||||
// embedding app can choose to dispose the iframe API on the handler.
|
||||
APP.API.notifyReadyToClose();
|
||||
}
|
||||
APP.store.dispatch(kickedOut(room, participant));
|
||||
});
|
||||
@@ -2459,8 +2467,8 @@ export default {
|
||||
});
|
||||
|
||||
APP.UI.addListener(
|
||||
UIEvents.TOGGLE_SCREENSHARING, audioOnly => {
|
||||
this.toggleScreenSharing(undefined, { audioOnly });
|
||||
UIEvents.TOGGLE_SCREENSHARING, ({ enabled, audioOnly }) => {
|
||||
this.toggleScreenSharing(enabled, { audioOnly });
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
66
config.js
66
config.js
@@ -70,6 +70,9 @@ var config = {
|
||||
// callStatsThreshold: 5 // enable callstats for 5% of the users.
|
||||
},
|
||||
|
||||
// Enables reactions feature.
|
||||
// enableReactions: false,
|
||||
|
||||
// Disables ICE/UDP by filtering out local and remote UDP candidates in
|
||||
// signalling.
|
||||
// webrtcIceUdpDisable: false,
|
||||
@@ -101,6 +104,10 @@ var config = {
|
||||
// about the call.
|
||||
// enableSaveLogs: false,
|
||||
|
||||
// Enabling this will hide the "Show More" link in the GSM popover that can be
|
||||
// used to display more statistics about the connection (IP, Port, protocol, etc).
|
||||
// disableShowMoreStats: true,
|
||||
|
||||
// Enabling this will run the lib-jitsi-meet noise detection module which will
|
||||
// notify the user if there is noise, other than voice, coming from the current
|
||||
// selected microphone. The purpose it to let the user know that the input could
|
||||
@@ -455,11 +462,38 @@ var config = {
|
||||
// - 'desktop' controls the "Share your screen" button
|
||||
// - if `toolbarButtons` is undefined, we fallback to enabling all buttons on the UI
|
||||
// toolbarButtons: [
|
||||
// 'microphone', 'camera', 'closedcaptions', 'desktop', 'embedmeeting', 'fullscreen',
|
||||
// 'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
|
||||
// 'livestreaming', 'etherpad', 'sharedvideo', 'shareaudio', 'settings', 'raisehand',
|
||||
// 'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
|
||||
// 'tileview', 'select-background', 'download', 'help', 'mute-everyone', 'mute-video-everyone', 'security'
|
||||
// 'camera',
|
||||
// 'chat',
|
||||
// 'closedcaptions',
|
||||
// 'desktop',
|
||||
// 'download',
|
||||
// 'embedmeeting',
|
||||
// 'etherpad',
|
||||
// 'feedback',
|
||||
// 'filmstrip',
|
||||
// 'fullscreen',
|
||||
// 'hangup',
|
||||
// 'help',
|
||||
// 'invite',
|
||||
// 'livestreaming',
|
||||
// 'microphone',
|
||||
// 'mute-everyone',
|
||||
// 'mute-video-everyone',
|
||||
// 'participants-pane',
|
||||
// 'profile',
|
||||
// 'raisehand',
|
||||
// 'recording',
|
||||
// 'security',
|
||||
// 'select-background',
|
||||
// 'settings',
|
||||
// 'shareaudio',
|
||||
// 'sharedvideo',
|
||||
// 'shortcuts',
|
||||
// 'stats',
|
||||
// 'tileview',
|
||||
// 'toggle-camera',
|
||||
// 'videoquality',
|
||||
// '__end'
|
||||
// ],
|
||||
|
||||
// Stats
|
||||
@@ -510,6 +544,9 @@ var config = {
|
||||
// connection.
|
||||
enabled: true,
|
||||
|
||||
// Enable unified plan implementation support on Chromium for p2p connection.
|
||||
// enableUnifiedOnChrome: false,
|
||||
|
||||
// Sets the ICE transport policy for the p2p connection. At the time
|
||||
// of this writing the list of possible values are 'all' and 'relay',
|
||||
// but that is subject to change in the future. The enum is defined in
|
||||
@@ -596,6 +633,9 @@ var config = {
|
||||
// conference (if set to true, these sounds will not be played).
|
||||
// disableJoinLeaveSounds: false,
|
||||
|
||||
// Disables the sounds that play when a chat message is received.
|
||||
// disableIncomingMessageSound: false,
|
||||
|
||||
// Information for the chrome extension banner
|
||||
// chromeExtensionBanner: {
|
||||
// // The chrome extension to be installed address
|
||||
@@ -725,6 +765,9 @@ var config = {
|
||||
// Hides the conference subject
|
||||
// hideConferenceSubject: true,
|
||||
|
||||
// Hides the recording label
|
||||
// hideRecordingLabel: false,
|
||||
|
||||
// Hides the conference timer.
|
||||
// hideConferenceTimer: true,
|
||||
|
||||
@@ -739,6 +782,18 @@ var config = {
|
||||
// is not persisting the local storage inside the iframe.
|
||||
// useHostPageLocalStorage: true,
|
||||
|
||||
// etherpad ("shared document") integration.
|
||||
//
|
||||
|
||||
// If set, add a "Open shared document" link to the bottom right menu that
|
||||
// will open an etherpad document.
|
||||
// etherpad_base: 'https://your-etherpad-installati.on/p/',
|
||||
|
||||
// If etherpad_base is set, and useRoomAsSharedDocumentName is set to true,
|
||||
// open a pad with the name of the room (lowercased) instead of a pad with a
|
||||
// random UUID.
|
||||
// useRoomAsSharedDocumentName: true,
|
||||
|
||||
// List of undocumented settings used in jitsi-meet
|
||||
/**
|
||||
_immediateReloadThreshold
|
||||
@@ -751,7 +806,6 @@ var config = {
|
||||
dialOutCodesUrl
|
||||
disableRemoteControl
|
||||
displayJids
|
||||
etherpad_base
|
||||
externalConnectUrl
|
||||
firefox_fake_device
|
||||
googleApiApplicationClientID
|
||||
|
||||
@@ -11,11 +11,13 @@ import {
|
||||
connectionFailed
|
||||
} from './react/features/base/connection/actions';
|
||||
import { openDialog } from './react/features/base/dialog/actions';
|
||||
import { setJWT } from './react/features/base/jwt';
|
||||
import {
|
||||
isFatalJitsiConnectionError,
|
||||
JitsiConnectionErrors,
|
||||
JitsiConnectionEvents
|
||||
} from './react/features/base/lib-jitsi-meet';
|
||||
import { isVpaasMeeting, getJaasJWT } from './react/features/jaas/functions';
|
||||
import { setPrejoinDisplayNameRequired } from './react/features/prejoin/actions';
|
||||
const logger = Logger.getLogger(__filename);
|
||||
|
||||
@@ -82,9 +84,16 @@ function checkForAttachParametersAndConnect(id, password, connection) {
|
||||
* @returns {Promise<JitsiConnection>} connection if
|
||||
* everything is ok, else error.
|
||||
*/
|
||||
export function connect(id, password, roomName) {
|
||||
export async function connect(id, password, roomName) {
|
||||
const connectionConfig = Object.assign({}, config);
|
||||
const { jwt } = APP.store.getState()['features/base/jwt'];
|
||||
const state = APP.store.getState();
|
||||
let { jwt } = state['features/base/jwt'];
|
||||
const { iAmRecorder, iAmSipGateway } = state['features/base/config'];
|
||||
|
||||
if (!iAmRecorder && !iAmSipGateway && !jwt && isVpaasMeeting(state)) {
|
||||
jwt = await getJaasJWT(state);
|
||||
APP.store.dispatch(setJWT(jwt));
|
||||
}
|
||||
|
||||
// Use Websocket URL for the web app if configured. Note that there is no 'isWeb' check, because there's assumption
|
||||
// that this code executes only on web browsers/electron. This needs to be changed when mobile and web are unified.
|
||||
|
||||
@@ -100,12 +100,18 @@
|
||||
}
|
||||
|
||||
.audio-preview > div:nth-child(2),
|
||||
.video-preview > div:nth-child(2) {
|
||||
.video-preview > div:nth-child(2),
|
||||
.reactions-menu-popup > div:nth-child(2) {
|
||||
margin-bottom: 4px;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.reactions-menu-popup > div:nth-child(2) {
|
||||
margin-bottom: 6px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* The following selectors keep the chat modal full-size anywhere between 100px
|
||||
* and 580px for desktop or 680px for mobile.
|
||||
|
||||
@@ -45,6 +45,10 @@
|
||||
@extend .connection-info__icon;
|
||||
}
|
||||
|
||||
&__mobile {
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.connection-actions {
|
||||
margin: 10px auto;
|
||||
text-align: center;
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
line-height: 13px;
|
||||
margin: 0 auto;
|
||||
width: 320px;
|
||||
|
||||
@include adjust-for-max-width(320px, 8px);
|
||||
}
|
||||
|
||||
&-header {
|
||||
|
||||
@@ -4,17 +4,28 @@
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: $drawerZ;
|
||||
border-radius: 16px 16px 0 0;
|
||||
}
|
||||
|
||||
.drawer-portal::after {
|
||||
content: '';
|
||||
background-color: $participantsPaneBgColor;
|
||||
margin-bottom: env(safe-area-inset-bottom, 0);
|
||||
}
|
||||
|
||||
.drawer-menu-container {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.drawer-menu {
|
||||
max-height: 50vh;
|
||||
max-height: calc(80vh - 64px);
|
||||
background: #242528;
|
||||
border-radius: 16px 16px 0 0;
|
||||
overflow-y: auto;
|
||||
|
||||
&.expanded {
|
||||
max-height: 80vh;
|
||||
}
|
||||
overflow-y: hidden;
|
||||
margin-bottom: env(safe-area-inset-bottom, 0);
|
||||
width: 100%;
|
||||
|
||||
.drawer-toggle {
|
||||
display: flex;
|
||||
@@ -42,6 +53,8 @@
|
||||
font-size: 1.2em;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
height: calc(80vh - 144px - 64px);
|
||||
overflow-y: auto;
|
||||
|
||||
.overflow-menu-item {
|
||||
box-sizing: border-box;
|
||||
|
||||
@@ -38,17 +38,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
#knocking-participant-list {
|
||||
#notification-participant-list {
|
||||
background-color: $newToolbarBackgroundColor;
|
||||
border: 1px solid rgba(255, 255, 255, .4);
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
left: 0;
|
||||
margin: 20px;
|
||||
max-height: 600px;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
position: fixed;
|
||||
top: 20;
|
||||
transition: top 1s ease;
|
||||
top: 30px;
|
||||
z-index: $toolbarZ + 1;
|
||||
|
||||
&.toolbox-visible {
|
||||
@@ -94,8 +94,6 @@
|
||||
|
||||
.knocking-participants-container {
|
||||
list-style-type: none;
|
||||
max-height: 600px;
|
||||
overflow-y: scroll;
|
||||
padding: 0 15px 15px 15px;
|
||||
}
|
||||
|
||||
|
||||
@@ -206,3 +206,13 @@
|
||||
bottom: 0;
|
||||
width: 35%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes elements width to fill the whole screen width with some margin
|
||||
*/
|
||||
@mixin adjust-for-max-width($width, $margin) {
|
||||
@media (max-width: $width) {
|
||||
margin: 0 $margin;
|
||||
width: $width - 2 * $margin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +113,8 @@
|
||||
&-dropdown-btns {
|
||||
width: 320px;
|
||||
padding: 8px 0;
|
||||
|
||||
@include adjust-for-max-width(320px, 8px);
|
||||
}
|
||||
|
||||
&-dropdown-btn {
|
||||
@@ -140,6 +142,8 @@
|
||||
}
|
||||
|
||||
&-dropdown-container {
|
||||
margin-top: 16px;
|
||||
|
||||
& > div:nth-child(2) {
|
||||
background: #fff;
|
||||
padding: 0;
|
||||
|
||||
@@ -30,16 +30,18 @@
|
||||
|
||||
.action-btn {
|
||||
border-radius: 3px;
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
margin-top: 16px;
|
||||
padding: 7px 16px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
width: 286px;
|
||||
width: 320px;
|
||||
|
||||
@include adjust-for-max-width(320px, 8px);
|
||||
|
||||
&.primary {
|
||||
background: #0376DA;
|
||||
@@ -175,6 +177,8 @@
|
||||
text-align: center;
|
||||
width: 320px;
|
||||
|
||||
@include adjust-for-max-width(320px, 8px);
|
||||
|
||||
&.error {
|
||||
box-shadow: 0px 0px 4px 3px rgba(225, 45, 45, 0.4);
|
||||
}
|
||||
@@ -246,6 +250,7 @@
|
||||
transition: background 0.16s ease-out;
|
||||
width: 320px;
|
||||
|
||||
@include adjust-for-max-width(320px, 8px);
|
||||
@include flex-centered();
|
||||
|
||||
svg {
|
||||
|
||||
189
css/_reactions-menu.scss
Normal file
189
css/_reactions-menu.scss
Normal file
@@ -0,0 +1,189 @@
|
||||
@use 'sass:math';
|
||||
|
||||
.reactions-menu {
|
||||
width: 280px;
|
||||
background: #292929;
|
||||
box-shadow: 0px 3px 16px rgba(0, 0, 0, 0.6), 0px 0px 4px 1px rgba(0, 0, 0, 0.25);
|
||||
border-radius: 3px;
|
||||
padding: 16px;
|
||||
|
||||
&.overflow {
|
||||
width: auto;
|
||||
padding-bottom: max(env(safe-area-inset-bottom, 0), 16px);
|
||||
background-color: #141414;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
position: relative;
|
||||
|
||||
.toolbox-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
|
||||
span.emoji {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.reactions-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
|
||||
.toolbox-button {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toolbox-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 6px;
|
||||
|
||||
span.emoji {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.reactions-row {
|
||||
.toolbox-button {
|
||||
margin-right: 8px;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
.toolbox-button:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.raise-hand-row {
|
||||
margin-top: 16px;
|
||||
|
||||
.toolbox-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.toolbox-icon {
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
span.text {
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reactions-animations-container {
|
||||
position: absolute;
|
||||
width: 20%;
|
||||
bottom: 0;
|
||||
left: 40%;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.reactions-menu-popup-container,
|
||||
.reactions-menu-popup {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
$reactionCount: 20;
|
||||
|
||||
@function random($min, $max) {
|
||||
@return math.random() * ($max - $min) + $min;
|
||||
}
|
||||
|
||||
.reaction-emoji {
|
||||
position: absolute;
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
top: 0;
|
||||
left: 20px;
|
||||
opacity: 0;
|
||||
z-index: 1;
|
||||
|
||||
&.reaction-0 {
|
||||
animation: flowToRight 5s forwards ease-in-out;
|
||||
}
|
||||
|
||||
@for $i from 1 through $reactionCount {
|
||||
&.reaction-#{$i} {
|
||||
animation: animation-#{$i} 5s forwards ease-in-out;
|
||||
top: #{random(-40, 10)}px;
|
||||
left: #{random(0, 30)}px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes flowToRight {
|
||||
0% {
|
||||
transform: translate(0px, 0px) scale(0.6);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
70% {
|
||||
transform: translate(40px, -70vh) scale(1.5);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: translate(40px, -70vh) scale(1.5);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translate(140px, -50vh) scale(1);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin animation-list {
|
||||
@for $i from 1 through $reactionCount {
|
||||
$topX: random(-100, 100);
|
||||
$topY: random(65, 75);
|
||||
$bottomX: random(150, 200);
|
||||
$bottomY: random(40, 50);
|
||||
|
||||
@if $topX < 0 {
|
||||
$bottomX: -$bottomX;
|
||||
}
|
||||
|
||||
@keyframes animation-#{$i} {
|
||||
0% {
|
||||
transform: translate(0, 0) scale(0.6);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
70% {
|
||||
transform: translate(#{$topX}px, -#{$topY}vh) scale(1.5);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: translate(#{$topX}px, -#{$topY}vh) scale(1.5);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translate(#{$bottomX}px, -#{$bottomY}vh) scale(1);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include animation-list;
|
||||
@@ -9,8 +9,31 @@
|
||||
z-index: $zindex3;
|
||||
|
||||
&.visible {
|
||||
top: 0px;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
&.recording {
|
||||
top: 0;
|
||||
|
||||
.subject-details-container {
|
||||
opacity: 0;
|
||||
transition: opacity .3s ease-in;
|
||||
}
|
||||
|
||||
.subject-info-container .show-always {
|
||||
transition: margin-left .3s ease-in;
|
||||
}
|
||||
|
||||
&.visible {
|
||||
.subject-details-container {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.subject-details-container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.subject-info-container {
|
||||
|
||||
@@ -105,16 +105,23 @@
|
||||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
pointer-events: all;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.toolbox-content-wrapper::after {
|
||||
content: '';
|
||||
background: $newToolbarBackgroundColor;
|
||||
padding-bottom: env(safe-area-inset-bottom, 0);
|
||||
}
|
||||
|
||||
.toolbox-content-items {
|
||||
background: $newToolbarBackgroundColor;
|
||||
box-shadow: 0px 2px 8px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.15);
|
||||
border-radius: 6px;
|
||||
margin: 0 auto;
|
||||
padding: 6px;
|
||||
text-align: center;
|
||||
pointer-events: all;
|
||||
box-shadow: 0px 2px 8px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.15);
|
||||
|
||||
>div {
|
||||
margin-left: 8px;
|
||||
@@ -278,6 +285,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.profile-button-avatar {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/**
|
||||
* START of fade in animation for main toolbar
|
||||
*/
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
z-index: $subtitlesZ;
|
||||
|
||||
&.lifted {
|
||||
// Lift subtitle above toolbar+invite box.
|
||||
bottom: $newToolbarSize + 112px + 40px;
|
||||
// Lift subtitle above toolbar+dominant speaker box.
|
||||
bottom: $newToolbarSize + 36px + 40px;
|
||||
}
|
||||
|
||||
span {
|
||||
|
||||
@@ -46,6 +46,7 @@ $menuBG:#242528;
|
||||
$newToolbarFontSize: 24px;
|
||||
$newToolbarHangupFontSize: 32px;
|
||||
$newToolbarSize: 48px;
|
||||
$newToolbarSizeMobile: 60px;
|
||||
$newToolbarSizeWithPadding: calc(#{$newToolbarSize} + 24px);
|
||||
$toolbarTitleFontSize: 19px;
|
||||
$overflowMenuItemColor: #fff;
|
||||
|
||||
@@ -122,11 +122,11 @@ body.welcome-page {
|
||||
#moderated-meetings {
|
||||
max-width: calc(100% - 40px);
|
||||
padding: 16px 0 39px 0;
|
||||
margin: $welcomePageEnterRoomMargin;
|
||||
width: $welcomePageEnterRoomWidth;
|
||||
|
||||
p {
|
||||
color: $welcomePageDescriptionColor;
|
||||
float: left;
|
||||
text-align: $welcomePageHeaderTextAlign;
|
||||
|
||||
a {
|
||||
|
||||
@@ -33,18 +33,18 @@
|
||||
}
|
||||
|
||||
&__videos {
|
||||
@extend %align-right;
|
||||
position:relative;
|
||||
padding: 0;
|
||||
/* The filmstrip should not be covered by the left toolbar. */
|
||||
bottom: 0;
|
||||
width:auto;
|
||||
overflow: visible !important;
|
||||
|
||||
&#remoteVideos {
|
||||
border: $thumbnailsBorder solid transparent;
|
||||
transition: bottom 2s;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
@include minHWAutoFix()
|
||||
}
|
||||
|
||||
@@ -60,41 +60,25 @@
|
||||
&.hidden {
|
||||
bottom: calc(-196px - #{$newToolbarSizeWithPadding});
|
||||
}
|
||||
|
||||
.remote-videos-container {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.remote-videos-container {
|
||||
transition: opacity 1s;
|
||||
.remote-videos {
|
||||
& > div {
|
||||
transition: opacity 1s;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
&.is-not-overflowing > div {
|
||||
right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
&.hide-videos {
|
||||
.remote-videos-container {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
#filmstripRemoteVideos {
|
||||
@include minHWAutoFix();
|
||||
|
||||
display: flex;
|
||||
flex: 1;
|
||||
width: auto;
|
||||
justify-content: flex-end;
|
||||
flex-direction: row;
|
||||
|
||||
#filmstripRemoteVideosContainer {
|
||||
flex-direction: row-reverse;
|
||||
/**
|
||||
* Add padding as a hack for Firefox not to show scrollbars when
|
||||
* unnecessary.
|
||||
*/
|
||||
padding: 1px 0;
|
||||
overflow-y: hidden;
|
||||
overflow-x: scroll;
|
||||
.remote-videos {
|
||||
& > div {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,25 +87,3 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Workarounds for Edge and Firefox not handling scrolling properly with
|
||||
* flex-direction: row-reverse.
|
||||
*/
|
||||
@mixin undoRowReverseVideos() {
|
||||
.horizontal-filmstrip {
|
||||
#remoteVideos #filmstripRemoteVideos #filmstripRemoteVideosContainer {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Firefox detection hack **/
|
||||
@-moz-document url-prefix() {
|
||||
@include undoRowReverseVideos();
|
||||
}
|
||||
|
||||
/** Edge detection hack **/
|
||||
@supports (-ms-ime-align:auto) {
|
||||
@include undoRowReverseVideos();
|
||||
}
|
||||
|
||||
@@ -10,13 +10,11 @@
|
||||
box-shadow: 0px 0px 1px 1.5px black, 0px 0px 1.3px 4px $videoThumbnailSelected;
|
||||
}
|
||||
|
||||
#filmstripRemoteVideos {
|
||||
.remote-videos {
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.filmstrip__videos .videocontainer {
|
||||
@@ -34,6 +32,10 @@
|
||||
*/
|
||||
height: 100% !important;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: margin-bottom .3s ease-in;
|
||||
}
|
||||
|
||||
.filmstrip {
|
||||
@@ -50,6 +52,22 @@
|
||||
&.shift-right {
|
||||
margin-left: $sidebarWidth;
|
||||
width: calc(100% - #{$sidebarWidth});
|
||||
|
||||
.remote-videos {
|
||||
width: calc(100vw - #{$sidebarWidth});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.collapse {
|
||||
#remoteVideos {
|
||||
height: calc(100% - #{$newToolbarSizeMobile}) !important;
|
||||
margin-bottom: $newToolbarSizeMobile;
|
||||
}
|
||||
|
||||
.remote-videos {
|
||||
// !important is needed here as overflow is set via element.style in a FixedSizeGrid.
|
||||
overflow: hidden auto !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,63 +80,49 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
#filmstripRemoteVideos {
|
||||
.remote-videos {
|
||||
box-sizing: border-box;
|
||||
|
||||
|
||||
/**
|
||||
* Allow vertical scrolling of the thumbnails.
|
||||
*/
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* The size of the thumbnails should be set with javascript, based on
|
||||
* desired column count and window width. The rows are created using flex
|
||||
* and allowing the thumbnails to wrap.
|
||||
*/
|
||||
#filmstripRemoteVideosContainer {
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-shrink: 0;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
justify-content: center;
|
||||
|
||||
.videocontainer {
|
||||
border: 0;
|
||||
* The size of the thumbnails should be set with javascript, based on
|
||||
* desired column count and window width. The rows are created using flex
|
||||
* and allowing the thumbnails to wrap.
|
||||
*/
|
||||
& > div {
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
margin: 2px;
|
||||
}
|
||||
display: flex;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
|
||||
video {
|
||||
object-fit: contain;
|
||||
}
|
||||
.videocontainer {
|
||||
border: 0;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Max-width corresponding to the ASPECT_RATIO_BREAKPOINT from features/filmstrip/constants.
|
||||
*/
|
||||
@media only screen and (max-width: 500px) {
|
||||
video {
|
||||
object-fit: cover;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Max-width corresponding to the ASPECT_RATIO_BREAKPOINT from features/filmstrip/constants.
|
||||
*/
|
||||
@media only screen and (max-width: 500px) {
|
||||
video {
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.has-overflow#filmstripRemoteVideosContainer {
|
||||
align-content: baseline;
|
||||
}
|
||||
|
||||
.has-overflow .videocontainer {
|
||||
align-self: baseline;
|
||||
}
|
||||
}
|
||||
|
||||
.shift-right #filmstripRemoteVideosContainer {
|
||||
.shift-right .remote-videos > div {
|
||||
/**
|
||||
* Max-width corresponding to the ASPECT_RATIO_BREAKPOINT from features/filmstrip/constants,
|
||||
* from which we subtract the chat size.
|
||||
@@ -129,3 +133,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.indicator-icon-container {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
.vertical-filmstrip .filmstrip {
|
||||
&.hide-videos {
|
||||
.remote-videos-container {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
.remote-videos {
|
||||
& > div {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +28,7 @@
|
||||
flex-direction: column-reverse;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: ($desktopAppDragBarHeight - 5px) 5px 10px;
|
||||
padding: ($desktopAppDragBarHeight - 5px) 5px calc(env(safe-area-inset-bottom, 0) + 10px);
|
||||
/**
|
||||
* fixed positioning is necessary for remote menus and tooltips to pop
|
||||
* out of the scrolling filmstrip. AtlasKit dialogs and tooltips use
|
||||
@@ -39,10 +41,6 @@
|
||||
right: 0;
|
||||
z-index: $filmstripVideosZ;
|
||||
|
||||
&.reduce-height {
|
||||
height: calc(100% - #{$newToolbarSizeWithPadding});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide videos by making them slight to the right.
|
||||
*/
|
||||
@@ -98,33 +96,10 @@
|
||||
* filmstrip from overlapping the left edge of the screen.
|
||||
*/
|
||||
#filmstripLocalVideo,
|
||||
#filmstripRemoteVideos {
|
||||
.remote-videos {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#filmstripRemoteVideos {
|
||||
@include minHWAutoFix();
|
||||
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column-reverse;
|
||||
height: auto;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
|
||||
#filmstripRemoteVideosContainer {
|
||||
@include minHWAutoFix();
|
||||
flex-direction: column-reverse;
|
||||
overflow: visible;
|
||||
width: calc(100% - 8px); // 8px for margin + border of the thumbnails
|
||||
|
||||
.videocontainer {
|
||||
height: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#remoteVideos {
|
||||
@include minHWAutoFix();
|
||||
|
||||
@@ -132,56 +107,21 @@
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.remote-videos-container {
|
||||
&.reduce-height {
|
||||
height: calc(100% - calc(#{$newToolbarSizeWithPadding} + #{$scrollHeight}));
|
||||
}
|
||||
|
||||
.remote-videos {
|
||||
display: flex;
|
||||
transition: opacity 1s;
|
||||
}
|
||||
transition: height .3s ease-in;
|
||||
|
||||
.hide-scrollbar#filmstripRemoteVideos {
|
||||
margin-right: 7px; // Scrollbar size
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
& > div {
|
||||
position: absolute;
|
||||
transition: opacity 1s;
|
||||
}
|
||||
|
||||
&.is-not-overflowing > div {
|
||||
bottom: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Workarounds for Edge and Firefox not handling scrolling properly with
|
||||
* flex-direction: column-reverse. The remove videos in filmstrip should
|
||||
* start scrolling from the bottom of the filmstrip, but in those browsers the
|
||||
* scrolling won't happen. Per W3C spec, scrolling should happen from the
|
||||
* bottom. As such, use css hacks to get around the css issue, with the intent
|
||||
* being to remove the hacks as the spec is supported.
|
||||
*/
|
||||
@mixin undoColumnReverseVideos() {
|
||||
.vertical-filmstrip {
|
||||
#remoteVideos #filmstripRemoteVideos #filmstripRemoteVideosContainer {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* FF does not include the scroll width when calculating the size of the content. That's why we need to include
|
||||
* ourselves the width of the scroll so that the remote videos are aligned with the local one.
|
||||
*/
|
||||
@mixin filmstripSizeWithoutScroll {
|
||||
.vertical-filmstrip {
|
||||
#remoteVideos #filmstripRemoteVideos {
|
||||
#filmstripRemoteVideosContainer {
|
||||
width: calc(100% - 15px) // 8 px - margins + border of the thumbnails; 7px - for the scroll
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Firefox detection hack **/
|
||||
@-moz-document url-prefix() {
|
||||
@include undoColumnReverseVideos();
|
||||
@include filmstripSizeWithoutScroll();
|
||||
}
|
||||
|
||||
/** Edge detection hack **/
|
||||
@supports (-ms-ime-align:auto) {
|
||||
@include undoColumnReverseVideos();
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ $flagsImagePath: "../images/";
|
||||
@import 'modals/feedback/feedback';
|
||||
@import 'modals/invite/info';
|
||||
@import 'modals/settings/settings';
|
||||
@import 'modals/screen-share/share-audio';
|
||||
@import 'modals/screen-share/share-screen-warning';
|
||||
@import 'modals/speaker_stats/speaker_stats';
|
||||
@import 'modals/video-quality/video-quality';
|
||||
@import 'modals/virtual-background/virtual-background';
|
||||
@@ -104,5 +106,7 @@ $flagsImagePath: "../images/";
|
||||
@import 'connection-status';
|
||||
@import 'drawer';
|
||||
@import 'participants-pane';
|
||||
@import 'reactions-menu';
|
||||
@import 'plan-limit';
|
||||
|
||||
/* Modules END */
|
||||
|
||||
22
css/modals/screen-share/_share-audio.scss
Normal file
22
css/modals/screen-share/_share-audio.scss
Normal file
@@ -0,0 +1,22 @@
|
||||
.share-audio-dialog {
|
||||
.share-audio-animation {
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
object-fit: contain;
|
||||
}
|
||||
input[type="checkbox"] + svg + span {
|
||||
color: #9FB0CC;
|
||||
}
|
||||
|
||||
.separator-line {
|
||||
margin: 24px 0 24px -20px;
|
||||
padding: 0 20px;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background: #5E6D7A;
|
||||
|
||||
&:last-child {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
css/modals/screen-share/_share-screen-warning.scss
Normal file
23
css/modals/screen-share/_share-screen-warning.scss
Normal file
@@ -0,0 +1,23 @@
|
||||
.share-screen-warn-dialog {
|
||||
font-size: 14px;
|
||||
|
||||
.separator-line {
|
||||
margin: 24px 0 24px -20px;
|
||||
padding: 0 20px;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background: #5E6D7A;
|
||||
|
||||
&:last-child {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,12 @@
|
||||
|
||||
.calendar-tab,
|
||||
.more-tab,
|
||||
.box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.profile-edit {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
@@ -45,18 +51,24 @@
|
||||
flex: 1;
|
||||
}
|
||||
.settings-sub-pane {
|
||||
flex-grow: 1;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.settings-sub-pane .right {
|
||||
flex: 1;
|
||||
}
|
||||
.settings-sub-pane .left {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.settings-sub-pane-element {
|
||||
text-align: left;
|
||||
flex: 1;
|
||||
}
|
||||
.profile-edit-field {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.language-settings {
|
||||
max-width: 50%;
|
||||
width: 35%;
|
||||
}
|
||||
|
||||
.calendar-tab {
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.virtual-background-dialog {
|
||||
margin-left:-10px;
|
||||
margin-left: -10px;
|
||||
position: relative;
|
||||
max-height: 300px;
|
||||
color: white;
|
||||
@@ -7,16 +7,16 @@
|
||||
grid-template-columns: auto auto auto auto auto;
|
||||
column-gap: 9px;
|
||||
cursor: pointer;
|
||||
.desktop-share:hover, .thumbnail:hover, .blur:hover, .slight-blur:hover, .virtual-background-none:hover{
|
||||
opacity: .5;
|
||||
.desktop-share:hover,
|
||||
.thumbnail:hover,
|
||||
.blur:hover,
|
||||
.slight-blur:hover,
|
||||
.virtual-background-none:hover {
|
||||
opacity: 0.5;
|
||||
border: 2px solid #99bbf3;
|
||||
@media (min-width: 432px) and (min-width: 432px) and (max-width: 632px) {
|
||||
height: 56px;
|
||||
width: 56px;
|
||||
}
|
||||
@media (max-width: 432px){
|
||||
height: 56px;
|
||||
width: 56px;
|
||||
@media (max-width: 632px) {
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
}
|
||||
}
|
||||
.background-option {
|
||||
@@ -40,28 +40,28 @@
|
||||
}
|
||||
.thumbnail-selected {
|
||||
object-fit: cover;
|
||||
border: 2px solid #246FE5;
|
||||
border: 2px solid #246fe5;
|
||||
}
|
||||
.blur{
|
||||
.blur {
|
||||
box-shadow: inset 0 0 12px #000000;
|
||||
background: #7E8287;
|
||||
background: #7e8287;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.blur-selected {
|
||||
box-shadow: inset 0 0 12px #000000;
|
||||
background: #7E8287;
|
||||
border: 2px solid #246FE5;
|
||||
background: #7e8287;
|
||||
border: 2px solid #246fe5;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.slight-blur{
|
||||
.slight-blur {
|
||||
box-shadow: inset 0 0 12px #000000;
|
||||
background: #A4A4A4;
|
||||
background: #a4a4a4;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.slight-blur-selected{
|
||||
.slight-blur-selected {
|
||||
box-shadow: inset 0 0 12px #000000;
|
||||
background: #A4A4A4;
|
||||
border: 2px solid #246FE5;
|
||||
background: #a4a4a4;
|
||||
border: 2px solid #246fe5;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.virtual-background-none {
|
||||
@@ -70,24 +70,40 @@
|
||||
}
|
||||
.none-selected {
|
||||
background: #525252;
|
||||
border: 2px solid #246FE5;
|
||||
border: 2px solid #246fe5;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.desktop-share{
|
||||
.desktop-share {
|
||||
background: #525252;
|
||||
}
|
||||
.desktop-share-selected{
|
||||
.desktop-share-selected {
|
||||
background: #525252;
|
||||
border: 2px solid #246FE5;
|
||||
border: 2px solid #246fe5;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
@media (min-width: 432px) and (max-width: 632px) {
|
||||
@media (max-width: 632px) {
|
||||
font-size: 1.5vw;
|
||||
.desktop-share,
|
||||
.virtual-background-none,
|
||||
.thumbnail,
|
||||
.blur,
|
||||
.slight-blur {
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
}
|
||||
.desktop-share-selected,
|
||||
.thumbnail-selected,
|
||||
.none-selected,
|
||||
.blur-selected,
|
||||
.slight-blur-selected {
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 432px){
|
||||
font-size: 1.5vw;
|
||||
@media (max-width: 360px) {
|
||||
grid-template-columns: auto auto auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,14 +120,14 @@
|
||||
.file-upload-btn {
|
||||
display: none;
|
||||
}
|
||||
.file-upload-label{
|
||||
.file-upload-label {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
margin-left: -10px;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 8px;
|
||||
color: #669AEC;
|
||||
color: #669aec;
|
||||
display: inline-flex;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -122,8 +138,8 @@
|
||||
display: none;
|
||||
left: 96;
|
||||
bottom: 51;
|
||||
@media (min-width: 432px) and (max-width: 632px) {
|
||||
left: 51px
|
||||
@media (max-width: 632px) {
|
||||
left: 51px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,57 +150,54 @@
|
||||
.thumbnail-container {
|
||||
position: relative;
|
||||
&:focus-within {
|
||||
.thumbnail ~ .delete-image-icon{
|
||||
display: block;
|
||||
}
|
||||
.thumbnail ~ .delete-image-icon {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-background{
|
||||
.add-background {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.apply-background-btn{
|
||||
.apply-background-btn {
|
||||
margin-top: 16px;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.video-background-preview-entry{
|
||||
.video-background-preview-entry {
|
||||
margin-left: -10px;
|
||||
height: 250px;
|
||||
width: 570px;
|
||||
margin-bottom: 8px;
|
||||
z-index: 2;
|
||||
@media (min-width: 432px) and (max-width: 632px) {
|
||||
@media (max-width: 632px) {
|
||||
max-width: 336;
|
||||
}
|
||||
@media (max-width: 432px){
|
||||
max-width: 336;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.virtual-background-preview-video{
|
||||
.virtual-background-preview-video {
|
||||
margin-left: -10;
|
||||
border-radius: 6px;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
}
|
||||
.video-preview-loader{
|
||||
border-radius: 6px;
|
||||
background-color: transparent;
|
||||
height: 250px;
|
||||
margin-bottom: 8px;
|
||||
width: 572px;
|
||||
position: fixed;
|
||||
z-index: 2;
|
||||
@media (min-width: 432px) and (max-width: 632px) {
|
||||
width: 340px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.video-preview-loader {
|
||||
border-radius: 6px;
|
||||
background-color: transparent;
|
||||
height: 250px;
|
||||
margin-bottom: 8px;
|
||||
width: 572px;
|
||||
position: fixed;
|
||||
z-index: 2;
|
||||
@media (min-width: 432px) and (max-width: 632px) {
|
||||
width: 340px;
|
||||
}
|
||||
}
|
||||
|
||||
.video-preview-loader svg{
|
||||
.video-preview-loader svg {
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 45%;
|
||||
}
|
||||
}
|
||||
|
||||
BIN
images/share-audio.gif
Normal file
BIN
images/share-audio.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 202 KiB |
@@ -174,7 +174,7 @@ var interfaceConfig = {
|
||||
RECENT_LIST_ENABLED: true,
|
||||
REMOTE_THUMBNAIL_RATIO: 1, // 1:1
|
||||
|
||||
SETTINGS_SECTIONS: [ 'devices', 'language', 'moderator', 'profile', 'calendar' ],
|
||||
SETTINGS_SECTIONS: [ 'devices', 'language', 'moderator', 'profile', 'calendar', 'sounds' ],
|
||||
|
||||
/**
|
||||
* Specify which sharing features should be displayed. If the value is not set
|
||||
@@ -208,13 +208,7 @@ var interfaceConfig = {
|
||||
* DEPRECATED!
|
||||
* This config was moved to config.js as `toolbarButtons`.
|
||||
*/
|
||||
// TOOLBAR_BUTTONS: [
|
||||
// 'microphone', 'camera', 'closedcaptions', 'desktop', 'embedmeeting', 'fullscreen',
|
||||
// 'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
|
||||
// 'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
|
||||
// 'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
|
||||
// 'tileview', 'select-background', 'download', 'help', 'mute-everyone', 'mute-video-everyone', 'security'
|
||||
// ],
|
||||
// TOOLBAR_BUTTONS: [],
|
||||
|
||||
TOOLBAR_TIMEOUT: 4000,
|
||||
|
||||
|
||||
@@ -58,7 +58,9 @@ target 'JitsiMeetSDK' do
|
||||
pod 'react-native-calendar-events', :path => '../node_modules/react-native-calendar-events'
|
||||
pod 'react-native-keep-awake', :path => '../node_modules/react-native-keep-awake'
|
||||
pod 'react-native-netinfo', :path => '../node_modules/@react-native-community/netinfo'
|
||||
pod 'react-native-slider', :path => '../node_modules/@react-native-community/slider'
|
||||
pod 'react-native-splash-screen', :path => '../node_modules/react-native-splash-screen'
|
||||
pod 'react-native-video', :path => '../node_modules/react-native-video/react-native-video.podspec'
|
||||
pod 'react-native-webview', :path => '../node_modules/react-native-webview'
|
||||
pod 'react-native-webrtc', :path => '../node_modules/react-native-webrtc'
|
||||
pod 'RNCAsyncStorage', :path => '../node_modules/@react-native-async-storage/async-storage'
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
PODS:
|
||||
- AppAuth (1.2.0):
|
||||
- AppAuth/Core (= 1.2.0)
|
||||
- AppAuth/ExternalUserAgent (= 1.2.0)
|
||||
- AppAuth/Core (1.2.0)
|
||||
- AppAuth/ExternalUserAgent (1.2.0)
|
||||
- AppAuth (1.4.0):
|
||||
- AppAuth/Core (= 1.4.0)
|
||||
- AppAuth/ExternalUserAgent (= 1.4.0)
|
||||
- AppAuth/Core (1.4.0)
|
||||
- AppAuth/ExternalUserAgent (1.4.0)
|
||||
- boost-for-react-native (1.63.0)
|
||||
- CocoaLumberjack (3.5.3):
|
||||
- CocoaLumberjack/Core (= 3.5.3)
|
||||
@@ -48,7 +48,7 @@ PODS:
|
||||
- GoogleUtilities/Environment (~> 6.7)
|
||||
- GoogleUtilities/Logger (~> 6.7)
|
||||
- nanopb (~> 1.30906.0)
|
||||
- FirebaseCrashlytics (4.6.1):
|
||||
- FirebaseCrashlytics (4.6.2):
|
||||
- FirebaseCore (~> 6.10)
|
||||
- FirebaseInstallations (~> 1.6)
|
||||
- GoogleDataTransport (~> 7.2)
|
||||
@@ -77,9 +77,9 @@ PODS:
|
||||
- GoogleUtilities/Network (~> 6.7)
|
||||
- "GoogleUtilities/NSData+zlib (~> 6.7)"
|
||||
- nanopb (~> 1.30906.0)
|
||||
- GoogleDataTransport (7.4.0):
|
||||
- GoogleDataTransport (7.5.1):
|
||||
- nanopb (~> 1.30906.0)
|
||||
- GoogleSignIn (5.0.1):
|
||||
- GoogleSignIn (5.0.2):
|
||||
- AppAuth (~> 1.2)
|
||||
- GTMAppAuth (~> 1.0)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
@@ -102,21 +102,17 @@ PODS:
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/UserDefaults (6.7.2):
|
||||
- GoogleUtilities/Logger
|
||||
- GTMAppAuth (1.0.0):
|
||||
- AppAuth/Core (~> 1.0)
|
||||
- GTMSessionFetcher (~> 1.1)
|
||||
- GTMSessionFetcher (1.2.2):
|
||||
- GTMSessionFetcher/Full (= 1.2.2)
|
||||
- GTMSessionFetcher/Core (1.2.2)
|
||||
- GTMSessionFetcher/Full (1.2.2):
|
||||
- GTMSessionFetcher/Core (= 1.2.2)
|
||||
- GTMAppAuth (1.2.2):
|
||||
- AppAuth/Core (~> 1.4)
|
||||
- GTMSessionFetcher/Core (~> 1.5)
|
||||
- GTMSessionFetcher/Core (1.6.1)
|
||||
- nanopb (1.30906.0):
|
||||
- nanopb/decode (= 1.30906.0)
|
||||
- nanopb/encode (= 1.30906.0)
|
||||
- nanopb/decode (1.30906.0)
|
||||
- nanopb/encode (1.30906.0)
|
||||
- ObjectiveDropboxOfficial (3.9.4)
|
||||
- PromisesObjC (1.2.10)
|
||||
- PromisesObjC (1.2.12)
|
||||
- RCTRequired (0.61.5-jitsi.2)
|
||||
- RCTTypeSafety (0.61.5-jitsi.2):
|
||||
- FBLazyVector (= 0.61.5-jitsi.2)
|
||||
@@ -288,9 +284,16 @@ PODS:
|
||||
- React
|
||||
- react-native-netinfo (4.1.5):
|
||||
- React
|
||||
- react-native-slider (3.0.3):
|
||||
- React
|
||||
- react-native-splash-screen (3.2.0):
|
||||
- React
|
||||
- react-native-webrtc (1.89.1):
|
||||
- react-native-video (5.1.1):
|
||||
- React-Core
|
||||
- react-native-video/Video (= 5.1.1)
|
||||
- react-native-video/Video (5.1.1):
|
||||
- React-Core
|
||||
- react-native-webrtc (1.92.0):
|
||||
- React-Core
|
||||
- react-native-webview (11.0.2):
|
||||
- React-Core
|
||||
@@ -348,8 +351,8 @@ PODS:
|
||||
- React-jsi (= 0.61.5-jitsi.2)
|
||||
- ReactCommon/jscallinvoker (= 0.61.5-jitsi.2)
|
||||
- ReactCommon/turbomodule/core (= 0.61.5-jitsi.2)
|
||||
- RNCAsyncStorage (1.13.2):
|
||||
- React
|
||||
- RNCAsyncStorage (1.15.5):
|
||||
- React-Core
|
||||
- RNDefaultPreference (1.4.2):
|
||||
- React
|
||||
- RNDeviceInfo (8.0.0):
|
||||
@@ -394,7 +397,9 @@ DEPENDENCIES:
|
||||
- react-native-calendar-events (from `../node_modules/react-native-calendar-events`)
|
||||
- react-native-keep-awake (from `../node_modules/react-native-keep-awake`)
|
||||
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
|
||||
- "react-native-slider (from `../node_modules/@react-native-community/slider`)"
|
||||
- react-native-splash-screen (from `../node_modules/react-native-splash-screen`)
|
||||
- react-native-video (from `../node_modules/react-native-video/react-native-video.podspec`)
|
||||
- react-native-webrtc (from `../node_modules/react-native-webrtc`)
|
||||
- react-native-webview (from `../node_modules/react-native-webview`)
|
||||
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
|
||||
@@ -475,8 +480,12 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native-keep-awake"
|
||||
react-native-netinfo:
|
||||
:path: "../node_modules/@react-native-community/netinfo"
|
||||
react-native-slider:
|
||||
:path: "../node_modules/@react-native-community/slider"
|
||||
react-native-splash-screen:
|
||||
:path: "../node_modules/react-native-splash-screen"
|
||||
react-native-video:
|
||||
:path: "../node_modules/react-native-video/react-native-video.podspec"
|
||||
react-native-webrtc:
|
||||
:path: "../node_modules/react-native-webrtc"
|
||||
react-native-webview:
|
||||
@@ -519,7 +528,7 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native/ReactCommon/yoga"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
AppAuth: bce82c76043657c99d91e7882e8a9e1a93650cd4
|
||||
AppAuth: 31bcec809a638d7bd2f86ea8a52bd45f6e81e7c7
|
||||
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
|
||||
CocoaLumberjack: 2f44e60eb91c176d471fdba43b9e3eae6a721947
|
||||
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
|
||||
@@ -529,20 +538,20 @@ SPEC CHECKSUMS:
|
||||
FirebaseAnalytics: 5dd088bd2e67bb9d13dbf792d1164ceaf3052193
|
||||
FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd
|
||||
FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1
|
||||
FirebaseCrashlytics: 5777d3462fb8c3ab9e80a2473bd7d667a2e8411c
|
||||
FirebaseCrashlytics: 1a747c9cc084a24dc6d9511c991db1cd078154eb
|
||||
FirebaseDynamicLinks: 6eac37d86910382eafb6315d952cc44c9e176094
|
||||
FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2
|
||||
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
|
||||
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
|
||||
GoogleAppMeasurement: 966e88df9d19c15715137bb2ddaf52373f111436
|
||||
GoogleDataTransport: b7f406340a291370045a270c599e53c6fa6ec20f
|
||||
GoogleSignIn: 3a51b9bb8e48b635fd7f4272cee06ca260345b86
|
||||
GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833
|
||||
GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213
|
||||
GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
|
||||
GTMAppAuth: 4deac854479704f348309e7b66189e604cf5e01e
|
||||
GTMSessionFetcher: 61bb0f61a4cb560030f1222021178008a5727a23
|
||||
GTMAppAuth: ad5c2b70b9a8689e1a04033c9369c4915bfcbe89
|
||||
GTMSessionFetcher: 36689134877faeb055b27dfa4ccc9ceaa42e029e
|
||||
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
|
||||
ObjectiveDropboxOfficial: a5afefc83f6467c42c45f2253f583f2ad1ffc701
|
||||
PromisesObjC: b14b1c6b68e306650688599de8a45e49fae81151
|
||||
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
|
||||
RCTRequired: a686731276578c125dff205f08b6ec9cee6ede32
|
||||
RCTTypeSafety: 88e5500e801c00d16a3d1895e3470d13beed6584
|
||||
React: 8b2bcf6a93846e47a7a365a54ec6edeb78b37701
|
||||
@@ -556,8 +565,10 @@ SPEC CHECKSUMS:
|
||||
react-native-calendar-events: 1442fad71a00388f933cfa25512588fec300fcf8
|
||||
react-native-keep-awake: eba3137546b10003361b37c761f6c429b59814ae
|
||||
react-native-netinfo: 8d8db463bcc5db66a8ac5c48a7d86beb3b92f61a
|
||||
react-native-slider: b733e17fdd31186707146debf1f04b5d94aa1a93
|
||||
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
|
||||
react-native-webrtc: ccb0c21eb4fb04326648fbdb4a5d49977e2cf274
|
||||
react-native-video: 1574074179ecaf6a9dd067116c8f31bf9fec15c8
|
||||
react-native-webrtc: bbb644859dcc37ccb7edaec860ca62ed47bf996c
|
||||
react-native-webview: b2542d6fd424bcc3e3b2ec5f854f0abb4ec86c87
|
||||
React-RCTActionSheet: bcbc311dc3b47bc8efb2737ff0940239a45789a9
|
||||
React-RCTAnimation: 65f61080ce632f6dea23d52e354ffac9948396c6
|
||||
@@ -569,7 +580,7 @@ SPEC CHECKSUMS:
|
||||
React-RCTText: 4f1b99f228278d2a5e9008eced8dc9c974c4a270
|
||||
React-RCTVibration: c1041024893fdfdb8371e7c720c437751b711676
|
||||
ReactCommon: 18014e1d98dbeb9141e935cfe35fc93bd511ffb6
|
||||
RNCAsyncStorage: bc2f81cc1df90c267ce9ed30bb2dbc93b945a8ee
|
||||
RNCAsyncStorage: 8324611026e8dc3706f829953aa6e3899f581589
|
||||
RNDefaultPreference: 56a405ce61033ac77b95004dccd7ac54c2eb50d1
|
||||
RNDeviceInfo: 72ded653ce636b3f03571e90bed99309a714944e
|
||||
RNGoogleSignin: 39336070b35fc4cea6a98cf111e00480317be0ae
|
||||
@@ -578,6 +589,6 @@ SPEC CHECKSUMS:
|
||||
RNWatch: a5320c959c75e72845c07985f3e935e58998f1d3
|
||||
Yoga: 96b469c5e81ff51b917b92e8c3390642d4ded30c
|
||||
|
||||
PODFILE CHECKSUM: d059cebf82da14a53940a16c24c3330752d4b0c8
|
||||
PODFILE CHECKSUM: f4db44d934caeae7212dbaa33abe62ed164363e8
|
||||
|
||||
COCOAPODS: 1.10.1
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>21.2.0</string>
|
||||
<string>21.3.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSExtension</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>21.2.0</string>
|
||||
<string>21.3.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>21.2.0</string>
|
||||
<string>21.3.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>21.2.0</string>
|
||||
<string>21.3.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>CLKComplicationPrincipalClass</key>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.6.0</string>
|
||||
<string>3.8.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -59,6 +59,16 @@
|
||||
|
||||
#pragma mark - Utility methods
|
||||
|
||||
/**
|
||||
* Once the react native bridge is destroyed you are responsible for reinstantiating it back. Use this method to do so.
|
||||
*/
|
||||
- (void)instantiateReactNativeBridge;
|
||||
|
||||
/**
|
||||
* Helper method to destroy the react native bridge, cleaning up resources in the process. Once the react native bridge is destroyed you are responsible for reinstantiating it back using `instantiateReactNativeBridge` method.
|
||||
*/
|
||||
- (void)destroyReactNativeBridge;
|
||||
|
||||
- (JitsiMeetConferenceOptions *_Nonnull)getInitialConferenceOptions;
|
||||
|
||||
- (BOOL)isCrashReportingDisabled;
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#import <RNGoogleSignin/RNGoogleSignin.h>
|
||||
#import <WebRTC/RTCLogging.h>
|
||||
|
||||
|
||||
@implementation JitsiMeet {
|
||||
RCTBridgeWrapper *_bridgeWrapper;
|
||||
NSDictionary *_launchOptions;
|
||||
@@ -50,7 +49,7 @@
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
// Initialize the on and only bridge for interfacing with React Native.
|
||||
// Initialize the one and only bridge for interfacing with React Native.
|
||||
_bridgeWrapper = [[RCTBridgeWrapper alloc] init];
|
||||
|
||||
// Initialize the listener for handling start/stop screensharing notifications.
|
||||
@@ -119,6 +118,18 @@
|
||||
|
||||
#pragma mark - Utility methods
|
||||
|
||||
- (void)instantiateReactNativeBridge {
|
||||
if (_bridgeWrapper != nil) {
|
||||
return;
|
||||
};
|
||||
|
||||
_bridgeWrapper = [[RCTBridgeWrapper alloc] init];
|
||||
}
|
||||
|
||||
- (void)destroyReactNativeBridge {
|
||||
_bridgeWrapper = nil;
|
||||
}
|
||||
|
||||
- (JitsiMeetConferenceOptions *)getInitialConferenceOptions {
|
||||
if (_launchOptions[UIApplicationLaunchOptionsURLKey]) {
|
||||
NSURL *url = _launchOptions[UIApplicationLaunchOptionsURLKey];
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"fr": "Francés",
|
||||
"frCA": "Francés (Canadian)",
|
||||
"he": "Ebrèu",
|
||||
"hi": "Indi",
|
||||
"mr":"Marathi",
|
||||
"hr": "Croat",
|
||||
"hu": "Ongrés",
|
||||
@@ -42,7 +43,9 @@
|
||||
"sk": "Eslovac",
|
||||
"sl": "Eslovèn",
|
||||
"sr": "Sèrbe",
|
||||
"sq": "Albanés",
|
||||
"sv": "Suedés",
|
||||
"te": "Telugu",
|
||||
"th": "Tai",
|
||||
"tr": "Turc",
|
||||
"uk": "Ucraïnian",
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"fr": "Frëngjisht",
|
||||
"frCA": "Frëngjisht (Kebek)",
|
||||
"he": "Hebraisht",
|
||||
"hi": "Hindi",
|
||||
"mr":"Maratisht",
|
||||
"hr": "Kroatisht",
|
||||
"hu": "Hungarisht",
|
||||
@@ -34,15 +35,17 @@
|
||||
"oc": "Oçitanisht",
|
||||
"fa": "Persisht",
|
||||
"pl": "Polonisht",
|
||||
"pt": "Portugalisht",
|
||||
"ptBR": "Portugalisht (Brazil)",
|
||||
"ru": "Rusisht",
|
||||
"ro": "Rumanisht",
|
||||
"sc": "Sardenjisht",
|
||||
"sk": "Sllovakisht",
|
||||
"sl": "Sllovenisht",
|
||||
"sq": "Shqip",
|
||||
"sr": "Serbisht",
|
||||
"sq": "Shqip",
|
||||
"sv": "Suedisht",
|
||||
"te": "Telugu",
|
||||
"th": "Tajlandisht",
|
||||
"tr": "Turqisht",
|
||||
"uk": "Ukrainisht",
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"shareInvite": "Einladung zur Versammlung teilen",
|
||||
"shareLink": "Teilen Sie den Konferenzlink, um andere einzuladen",
|
||||
"shareStream": "Den Livestreaminglink freigeben",
|
||||
"sip": "SIP: {{address}}",
|
||||
"sipAddresses": "SIP-Adressen",
|
||||
"telephone": "Telefon: {{number}}",
|
||||
"title": "Personen zu dieser Konferenz einladen",
|
||||
"yahooEmail": "Yahoo-E-Mail"
|
||||
@@ -215,6 +215,7 @@
|
||||
"gracefulShutdown": "Der Dienst steht momentan wegen Wartungsarbeiten nicht zur Verfügung. Bitte versuchen Sie es später noch einmal.",
|
||||
"grantModeratorDialog": "Möchten Sie wirklich Moderationsrechte an diese Person vergeben?",
|
||||
"grantModeratorTitle": "Moderationsrechte vergeben",
|
||||
"hideShareAudioHelper": "Diese Meldung nicht mehr anzeigen",
|
||||
"IamHost": "Ich leite das Meeting",
|
||||
"incorrectRoomLockPassword": "Falsches Passwort",
|
||||
"incorrectPassword": "Name oder Passwort ungültig",
|
||||
@@ -257,16 +258,21 @@
|
||||
"muteParticipantBody": "Sie können die Stummschaltung anderer Personen nicht aufheben, aber eine Person kann ihre eigene Stummschaltung jederzeit beenden.",
|
||||
"muteParticipantButton": "Stummschalten",
|
||||
"muteParticipantDialog": "Wollen Sie diese Person wirklich stummschalten? Sie können die Stummschaltung nicht wieder aufheben, die Person kann dies aber jederzeit selbst tun.",
|
||||
"muteParticipantsVideoDialog": "Wollen Sie die Kamera dieser Person wirklich deaktivieren? Sie können die Kamera nicht wieder aktivieren, die Person kann dies aber jederzeit selbst tun.",
|
||||
"muteParticipantTitle": "Person stummschalten?",
|
||||
"muteParticipantsVideoButton": "Kamera ausschalten",
|
||||
"muteParticipantsVideoTitle": "Die Kamera von dieser Person ausschalten?",
|
||||
"muteParticipantsVideoBody": "Sie können die Kamera nicht wieder aktivieren, die Teilnehmer können dies aber jederzeit wieder ändern.",
|
||||
"noDropboxToken": "Kein gültiges Dropbox-Token",
|
||||
"Ok": "OK",
|
||||
"password": "Passwort",
|
||||
"passwordLabel": "Dieses Meeting wurde gesichert. Bitte geben Sie das $t(lockRoomPasswordUppercase) ein, um dem Meeting beizutreten.",
|
||||
"passwordNotSupported": "Das Festlegen eines Konferenzpassworts wird nicht unterstützt.",
|
||||
"passwordNotSupportedTitle": "$t(lockRoomPasswordUppercase) nicht unterstützt",
|
||||
"passwordRequired": "$t(lockRoomPasswordUppercase) erforderlich",
|
||||
"permissionErrorTitle": "Berechtigung benötigt",
|
||||
"permissionCameraRequiredError": "Der Zugriff auf die Kamera wird benötigt, um in Videokonferenzen teilzunehmen. Bitte in den Einstellungen zulassen",
|
||||
"permissionMicRequiredError": "Der Zugriff auf das Mikrofon wird benötigt, um an Konferenzen mit Ton teilzunehmen. Bitte in den Einstellungen zulassen",
|
||||
"popupError": "Ihr Browser blockiert Pop-ups von dieser Website. Bitte aktivieren Sie Pop-ups in den Sicherheitseinstellungen des Browsers und versuchen Sie es erneut.",
|
||||
"popupErrorTitle": "Pop-up blockiert",
|
||||
"readMore": "mehr",
|
||||
@@ -300,6 +306,13 @@
|
||||
"sessTerminated": "Konferenz beendet",
|
||||
"sessionRestarted": "Konferenz neugestartet",
|
||||
"Share": "Teilen",
|
||||
"shareAudio": "Fortfahren",
|
||||
"shareAudioTitle" : "Wie kann Audio geteilt werden",
|
||||
"shareAudioWarningTitle": "Sie müssen die Bildschirmfreigabe ausschalten, bevor Sie Audio teilen können",
|
||||
"shareAudioWarningH1": "Wenn Sie Ihr Audio teilen wollen:",
|
||||
"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.",
|
||||
"shareMediaWarningGenericH2": "Wenn Sie Ihren Bildschirm und Audio teilen wollen",
|
||||
"shareVideoLinkError": "Bitte einen gültigen YouTube-Link angeben.",
|
||||
"shareVideoTitle": "Video teilen",
|
||||
"shareYourScreen": "Bildschirmfreigabe ein-/ausschalten",
|
||||
@@ -307,6 +320,10 @@
|
||||
"startLiveStreaming": "Livestream starten",
|
||||
"startRecording": "Aufnahme starten",
|
||||
"startRemoteControlErrorMessage": "Beim Versuch, die Fernsteuerung zu starten, ist ein Fehler aufgetreten!",
|
||||
"shareScreenWarningTitle": "Sie müssen die Audiofreigabe beenden, bevor Sie den Bildschirm freigeben können",
|
||||
"shareScreenWarningH1": "Wenn Sie Ihren Bildschirm freigeben wollen:",
|
||||
"shareScreenWarningD1": "müssen Sie Ihre Audiofreigabe stoppen, bevor Sie ihren Bildschirm freigeben.",
|
||||
"shareScreenWarningD2": "müssen Sie Ihre Audiofreigabe stoppen und dann die Bildschirmfreigabe mit der Option \"Audio freigeben\" starten.",
|
||||
"stopLiveStreaming": "Livestream stoppen",
|
||||
"stopRecording": "Aufnahme stoppen",
|
||||
"stopRecordingWarning": "Sind Sie sicher, dass Sie die Aufnahme stoppen möchten?",
|
||||
@@ -323,6 +340,9 @@
|
||||
"userIdentifier": "Benutzername",
|
||||
"userPassword": "Passwort",
|
||||
"videoLink": "Video-Link",
|
||||
"viewUpgradeOptions": "Upgradeoptionen anzeigen",
|
||||
"viewUpgradeOptionsContent": "Sie müssen Ihren Tarif erweitern, um Premium-Features wie Aufnahme, Transkription, RTMP-Streaming und mehr zu nutzen.",
|
||||
"viewUpgradeOptionsTitle": "Sie haben ein Premium-Feature entdeckt!",
|
||||
"WaitForHostMsg": "Die Konferenz <b>{{room}}</b> wurde noch nicht gestartet. Falls Sie die Konferenz leiten, authentifizieren Sie sich bitte. Warten Sie andernfalls, bis die Konferenz gestartet wird.",
|
||||
"WaitForHostMsgWOk": "Die Konferenz <b>{{room}}</b> wurde noch nicht gestartet. Falls Sie die Konferenz leiten, authentifizieren Sie sich bitte. Warten Sie andernfalls, bis die Konferenz gestartet wird.",
|
||||
"WaitingForHostTitle": "Warten auf den Beginn der Konferenz …",
|
||||
@@ -344,11 +364,11 @@
|
||||
"title": "Diese Konferenz einbetten"
|
||||
},
|
||||
"virtualBackground": {
|
||||
"apply": "Anwenden",
|
||||
"title": "Hintergründe",
|
||||
"blur": "Hintergrund unscharf",
|
||||
"slightBlur": "Hintergrund leicht unscharf",
|
||||
"removeBackground": "Hintergrund entfernen",
|
||||
"uploadImage": "Bild hochladen",
|
||||
"addBackground": "Hintergrund hinzufügen",
|
||||
"pleaseWait": "Bitte warten...",
|
||||
"none": "keiner",
|
||||
@@ -362,7 +382,8 @@
|
||||
"image6" : "Wald",
|
||||
"image7" : "Sonnenaufgang",
|
||||
"desktopShareError": "Desktop konnte nicht freigegeben werden",
|
||||
"desktopShare":"Desktopfreigabe"
|
||||
"desktopShare": "Desktopfreigabe",
|
||||
"webAssemblyWarning": "WebAssembly wird nicht unterstützt"
|
||||
},
|
||||
"feedback": {
|
||||
"average": "Durchschnittlich",
|
||||
@@ -399,6 +420,10 @@
|
||||
"invitePhone": "Wenn Sie stattdessen per Telefon beitreten möchten, wählen sie: {{number}},,{{conferenceID}}#\n",
|
||||
"invitePhoneAlternatives": "Suchen Sie nach einer anderen Einwahlnummer ?\nEinwahlnummern der Konferenz anzeigen: {{url}}\n\n\nWenn Sie sich auch über ein Raumtelefon einwählen, nehmen Sie teil, ohne sich mit dem Ton zu verbinden: {{silentUrl}}",
|
||||
"inviteSipEndpoint": "Um mit SIP teilzunehmen, folgende Adresse nutzen: {{sipUri}}",
|
||||
"inviteTextiOSPersonal": "{{name}} lädt Sie zu einem Meeting ein.",
|
||||
"inviteTextiOSJoinSilent": "Wenn Sie über ein Konferenztelefon teilnehmen, können Sie diesen Link nutzen um ohne Ton an der Konferenz teilzunehmen: {{silentUrl}}.",
|
||||
"inviteTextiOSInviteUrl": "Am Meeting teilnehmen: {{inviteUrl}}.",
|
||||
"inviteTextiOSPhone": "Nutzen Sie folgende Nummer um via Telefon teilzunehmen: {{number}},,{{conferenceID}}#. Wenn Sie nach einer anderen Einwahlnummer suchen, finden Sie die vollständige Liste hier: {{didUrl}}.",
|
||||
"inviteURLFirstPartGeneral": "Sie wurden zur Teilnahme an einem Meeting eingeladen.",
|
||||
"inviteURLFirstPartPersonal": "{{name}} lädt Sie zu einem Meeting ein.\n",
|
||||
"inviteURLSecondPart": "\nAm Meeting teilnehmen:\n{{url}}\n",
|
||||
@@ -409,6 +434,7 @@
|
||||
"noRoom": "Keine Konferenz für die Einwahlinformationen angegeben.",
|
||||
"numbers": "Einwahlnummern",
|
||||
"password": "$t(lockRoomPasswordUppercase):",
|
||||
"sip": "SIP-Adresse",
|
||||
"title": "Teilen",
|
||||
"tooltip": "Freigabe-Link und Einwahlinformationen für dieses Meeting",
|
||||
"label": "Einwahlinformationen"
|
||||
@@ -519,6 +545,7 @@
|
||||
"focus": "Konferenzleitung",
|
||||
"focusFail": "{{component}} ist im Moment nicht verfügbar – wiederholen in {{ms}} Sekunden",
|
||||
"grantedTo": "Moderationsrechte an {{to}} vergeben!",
|
||||
"hostAskedUnmute": "Die Moderation bittet Sie, das Mikrofon zu aktivieren",
|
||||
"invitedOneMember": "{{name}} wurde eingeladen",
|
||||
"invitedThreePlusMembers": "{{name}} und {{count}} andere wurden eingeladen",
|
||||
"invitedTwoMembers": "{{first}} und {{second}} wurden eingeladen",
|
||||
@@ -534,7 +561,7 @@
|
||||
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) von einer anderen Person entfernt",
|
||||
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) von einer anderen Person gesetzt",
|
||||
"raisedHand": "{{name}} möchte sprechen.",
|
||||
"screenShareNoAudio": " Share audio box was not checked in the window selection screen.",
|
||||
"screenShareNoAudio": "Die Option \"Audio freigeben\" wurde bei der Auswahl des Fensters nicht ausgewählt.",
|
||||
"screenShareNoAudioTitle": "Share audio was not checked",
|
||||
"somebody": "Jemand",
|
||||
"startSilentTitle": "Sie sind ohne Audioausgabe beigetreten!",
|
||||
@@ -549,28 +576,40 @@
|
||||
"oldElectronClientDescription1": "Sie scheinen eine alte Version des Jitsi-Meet-Clients zu nutzen. Diese hat bekannte Schwachstellen. Bitte aktualisieren Sie auf unsere ",
|
||||
"oldElectronClientDescription2": "aktuelle Version",
|
||||
"oldElectronClientDescription3": "!",
|
||||
"moderationInEffectDescription": "Bitte melden um zu sprechen",
|
||||
"moderationInEffectCSDescription": "Bitte melden um ein Video zu teilen",
|
||||
"moderationInEffectVideoDescription": "Bitte melden um die Kamera zu starten",
|
||||
"moderationInEffectTitle": "Das Mikrofon ist von der Moderation gesperrt",
|
||||
"moderationInEffectCSTitle": "Die Videofreigabe ist von der Moderation gesperrt",
|
||||
"moderationInEffectVideoTitle": "Die Kamera ist von der Moderation gesperrt",
|
||||
"moderationRequestFromModerator": "Die Moderation bittet Sie, das Mikrofon zu aktivieren",
|
||||
"moderationRequestFromParticipant": "möchte sprechen",
|
||||
"moderationStartedTitle": "Moderation gestartet",
|
||||
"moderationStoppedTitle": "Moderation gestoppt",
|
||||
"moderationToggleDescription": "von {{participantDisplayName}}",
|
||||
"raiseHandAction": "Melden",
|
||||
"groupTitle": "Benachrichtigungen"
|
||||
},
|
||||
"participantsPane": {
|
||||
"close": "Schließen",
|
||||
"header": "Anwesende",
|
||||
"headings": {
|
||||
"lobby": "Lobby ({{count}})",
|
||||
"participantsList": "Teilnehmer ({{count}})"
|
||||
},
|
||||
"actions": {
|
||||
"muteAll": "Alle stummschalten",
|
||||
"stopVideo": "Video stoppen"
|
||||
}
|
||||
},
|
||||
"participantsPane": {
|
||||
"headings": {
|
||||
"lobby": "Lobby ({{count}})",
|
||||
"participantsList": "Anwesende ({{count}})"
|
||||
"participantsList": "Anwesende ({{count}})",
|
||||
"waitingLobby": "In der Lobby ({{count}})"
|
||||
},
|
||||
"actions": {
|
||||
"allow": "Anwesenden erlauben:",
|
||||
"blockEveryoneMicCamera": "Kamera und Mikrofon von allen sperren",
|
||||
"invite": "Person einladen",
|
||||
"askUnmute": "Anfragen, Stummschaltung aufzuheben",
|
||||
"mute": "Stummschalten",
|
||||
"muteAll": "Alle stummschalten",
|
||||
"stopVideo": "Kamera ausschalten"
|
||||
"muteEveryoneElse": "Alle anderen stummschalten",
|
||||
"startModeration": "Stummschaltung aufheben oder Kamera aktivieren",
|
||||
"stopEveryonesVideo": "Alle Kameras ausschalten",
|
||||
"stopVideo": "Kamera ausschalten",
|
||||
"unblockEveryoneMicCamera": "Kamera und Mikrofon von allen entsperren"
|
||||
}
|
||||
},
|
||||
"passwordSetRemotely": "von einer anderen Person gesetzt",
|
||||
@@ -625,9 +664,9 @@
|
||||
"linkCopied": "Link in die Zwischenablage kopiert",
|
||||
"lookGood": "Ihr Mikrofon scheint zu funktionieren.",
|
||||
"or": "oder",
|
||||
"keyboardShortcuts" : "Tastaturkurzbefehle aktivieren",
|
||||
"premeeting": "Vorschau",
|
||||
"showScreen": "Konferenzvorschau aktivieren",
|
||||
"keyboardShortcuts" : "Tastaturkurzbefehle aktivieren",
|
||||
"startWithPhone": "Mit Telefonaudio starten",
|
||||
"screenSharingError": "Fehler bei Bildschirmfreigabe:",
|
||||
"videoOnlyError": "Videofehler:",
|
||||
@@ -664,12 +703,15 @@
|
||||
"beta": "BETA",
|
||||
"busy": "Es werden Ressourcen für eine Aufnahme bereitgestellt. Bitte in ein paar Minuten erneut versuchen.",
|
||||
"busyTitle": "Alle Aufnahme-Instanzen sind in Gebrauch",
|
||||
"copyLink": "Link kopieren",
|
||||
"error": "Die Aufzeichnung ist fehlgeschlagen. Bitte versuchen Sie es erneut.",
|
||||
"errorFetchingLink": "Der Link zur Aufzeichnung konnte nicht geladen werden.",
|
||||
"expandedOff": "Aufzeichnung wurde gestoppt",
|
||||
"expandedOn": "Das Meeting wird momentan aufgezeichnet.",
|
||||
"expandedPending": "Aufzeichnung wird gestartet…",
|
||||
"failedToStart": "Die Aufnahme konnte nicht gestartet werden",
|
||||
"fileSharingdescription": "Aufzeichnung mit den Personen der Konferenz teilen",
|
||||
"linkGenerated": "Link zur Aufzeichnung wurde generiert.",
|
||||
"live": "LIVE",
|
||||
"loggedIn": "Als {{userName}} angemeldet",
|
||||
"off": "Aufnahme gestoppt",
|
||||
@@ -684,7 +726,8 @@
|
||||
"signIn": "Anmelden",
|
||||
"signOut": "Abmelden",
|
||||
"unavailable": "Oh! Der {{serviceName}} ist aktuell nicht verfügbar. Wir arbeiten an der Behebung des Problems. Bitte versuchen Sie es später noch einmal.",
|
||||
"unavailableTitle": "Aufnahme nicht verfügbar"
|
||||
"unavailableTitle": "Aufnahme nicht verfügbar",
|
||||
"uploadToCloud": "In die Cloud hochladen"
|
||||
},
|
||||
"sectionList": {
|
||||
"pullToRefresh": "Ziehen, um zu aktualisieren"
|
||||
@@ -703,8 +746,13 @@
|
||||
"signedIn": "Momentan wird auf Kalendertermine von {{email}} zugegriffen. Klicken Sie auf die folgende Schaltfläche „Trennen“, um den Zugriff auf die Kalendertermine zu stoppen.",
|
||||
"title": "Kalender"
|
||||
},
|
||||
"desktopShareFramerate": "Framerate für Bildschirmfreigabe",
|
||||
"desktopShareWarning": "Sie müssen die Bildschirmfreigabe neustarten, damit die Einstellung übernommen wird.",
|
||||
"desktopShareHighFpsWarning": "Eine höhere Framerate könnte sich auf Ihre Datenrate auswirken. Sie müssen die Bildschirmfreigabe neustarten, damit die Einstellung übernommen wird.",
|
||||
"devices": "Geräte",
|
||||
"followMe": "Follow-me für alle Personen",
|
||||
"framesPerSecond": "FPS",
|
||||
"incomingMessage": "Eingehende Nachricht",
|
||||
"language": "Sprache",
|
||||
"loggedIn": "Als {{name}} angemeldet",
|
||||
"microphones": "Mikrofon",
|
||||
@@ -712,12 +760,18 @@
|
||||
"more": "Mehr",
|
||||
"name": "Name",
|
||||
"noDevice": "Kein",
|
||||
"participantJoined": "Neue Person nimmt teil",
|
||||
"participantLeft": "Person verlässt die Konferenz",
|
||||
"playSounds": "Hinweistöne aktiviert",
|
||||
"sameAsSystem": "Wie System ({{label}})",
|
||||
"selectAudioOutput": "Audioausgabe",
|
||||
"selectCamera": "Kamera",
|
||||
"selectMic": "Mikrofon",
|
||||
"sounds": "Hinweistöne",
|
||||
"speakers": "Lautsprecher",
|
||||
"startAudioMuted": "Alle Personen treten stumm geschaltet bei",
|
||||
"startAudioMuted": "Alle Personen treten stummgeschaltet bei",
|
||||
"startVideoMuted": "Alle Personen treten ohne Video bei",
|
||||
"talkWhileMuted": "Wenn bei Stummschaltung gesprochen wird",
|
||||
"title": "Einstellungen"
|
||||
},
|
||||
"settingsView": {
|
||||
@@ -766,12 +820,14 @@
|
||||
"title": "Die Konferenz wurde unterbrochen, weil der Standby-Modus aktiviert wurde."
|
||||
},
|
||||
"toolbar": {
|
||||
"accessibilityLabel": {
|
||||
"accessibilityLabel": {
|
||||
"audioOnly": "„Nur Audio“ ein-/ausschalten",
|
||||
"audioRoute": "Audiogerät auswählen",
|
||||
"boo": "Buhen",
|
||||
"callQuality": "Qualitätseinstellungen",
|
||||
"cc": "Untertitel ein-/ausschalten",
|
||||
"chat": "Chatfenster öffnen / schließen",
|
||||
"clap": "Klatschen",
|
||||
"document": "Geteiltes Dokument schließen",
|
||||
"download": "Unsere Apps herunterladen",
|
||||
"embedMeeting": "Konferenz einbetten",
|
||||
@@ -782,6 +838,8 @@
|
||||
"help": "Hilfe",
|
||||
"invite": "Person einladen",
|
||||
"kick": "Person entfernen",
|
||||
"laugh": "Lachen",
|
||||
"like": "Daumen nach oben",
|
||||
"lobbyButton": "Lobbymodus ein-/ausschalten",
|
||||
"localRecording": "Lokale Aufzeichnungssteuerelemente ein-/ausschalten",
|
||||
"lockRoom": "Konferenzpasswort ein-/ausschalten",
|
||||
@@ -794,10 +852,12 @@
|
||||
"muteEveryonesVideo": "Alle Kameras ausschalten",
|
||||
"muteEveryoneElsesVideo": "Alle anderen Kameras ausschalten",
|
||||
"participants": "Anwesende",
|
||||
"party": "Konfetti",
|
||||
"pip": "Bild-in-Bild-Modus ein-/ausschalten",
|
||||
"privateMessage": "Private Nachricht senden",
|
||||
"profile": "Profil bearbeiten",
|
||||
"raiseHand": "Hand erheben / senken",
|
||||
"reactionsMenu": "Interaktionsmenü öffnen / schließen",
|
||||
"recording": "Aufzeichnung ein-/ausschalten",
|
||||
"remoteMute": "Personen stummschalten",
|
||||
"remoteVideoMute": "Kamera von dieser Person ausschalten",
|
||||
@@ -810,23 +870,29 @@
|
||||
"shortcuts": "Tastenkombinationen ein-/ausblenden",
|
||||
"show": "Im Vordergrund anzeigen",
|
||||
"speakerStats": "Sprechstatistik ein-/ausblenden",
|
||||
"surprised": "Überrascht",
|
||||
"tileView": "Kachelansicht ein-/ausschalten",
|
||||
"toggleCamera": "Kamera wechseln",
|
||||
"toggleFilmstrip": "Miniaturansichten ein-/ausschalten",
|
||||
"videomute": "„Video stummschalten“ ein-/ausschalten",
|
||||
"videoblur": "Unscharfer Hintergrund ein-/ausschalten",
|
||||
"selectBackground": "Hintergrund auswählen",
|
||||
"expand": "Ausklappen",
|
||||
"collapse": "Einklappen"
|
||||
},
|
||||
"addPeople": "Personen zur Konferenz hinzufügen",
|
||||
"audioSettings": "Ton-Einstellungen",
|
||||
"videoSettings": "Kameraeinstellungen",
|
||||
"audioOnlyOff": "Modus „Nur Audio“ deaktivieren",
|
||||
"audioOnlyOn": "Modus „Nur Audio“ aktivieren",
|
||||
"audioRoute": "Audiogerät auswählen",
|
||||
"authenticate": "Anmelden",
|
||||
"boo": "Buhen",
|
||||
"callQuality": "Qualitätseinstellungen",
|
||||
"chat": "Chat öffnen / schließen",
|
||||
"clap": "Klatschen",
|
||||
"closeChat": "Chat schließen",
|
||||
"closeReactionsMenu": "Interationsmenü schließen",
|
||||
"documentClose": "Geteiltes Dokument schließen",
|
||||
"documentOpen": "Geteiltes Dokument öffnen",
|
||||
"download": "Unsere Apps herunterladen",
|
||||
@@ -840,6 +906,8 @@
|
||||
"hangup": "Konferenz verlassen",
|
||||
"help": "Hilfe",
|
||||
"invite": "Personen einladen",
|
||||
"laugh": "Lachen",
|
||||
"like": "Daumen hoch",
|
||||
"lobbyButtonDisable": "Lobbymodus deaktivieren",
|
||||
"lobbyButtonEnable": "Lobbymodus aktivieren",
|
||||
"login": "Anmelden",
|
||||
@@ -858,12 +926,20 @@
|
||||
"noisyAudioInputTitle": "Ihr Mikrofon scheint lärmintensiv zu sein!",
|
||||
"noisyAudioInputDesc": "Es klingt, als ob Ihr Mikrofon Störgeräusche verursacht. Bitte überlegen Sie, ob Sie das Gerät stummschalten oder austauschen wollen.",
|
||||
"openChat": "Chat öffnen",
|
||||
"openReactionsMenu": "Interationsmenü öffnen",
|
||||
"participants": "Anwesende",
|
||||
"party": "Konfetti",
|
||||
"pip": "Bild-in-Bild-Modus einschalten",
|
||||
"privateMessage": "Private Nachricht senden",
|
||||
"profile": "Profil bearbeiten",
|
||||
"raiseHand": "Hand erheben / senken",
|
||||
"raiseYourHand": "Melden",
|
||||
"reactionBoo": "Buhen senden",
|
||||
"reactionClap": "Klatschen senden",
|
||||
"reactionLaugh": "Lachen senden",
|
||||
"reactionLike": "Daumen hoch senden",
|
||||
"reactionParty": "Konfetti senden",
|
||||
"reactionSurprised": "Überrascht senden",
|
||||
"security": "Sicherheitsoptionen",
|
||||
"Settings": "Einstellungen",
|
||||
"shareaudio": "Audio teilen",
|
||||
@@ -873,14 +949,15 @@
|
||||
"speakerStats": "Sprechstatistik",
|
||||
"startScreenSharing": "Bildschirmfreigabe starten",
|
||||
"startSubtitles": "Untertitel einschalten",
|
||||
"stopAudioSharing": "Audiofreigabe stoppen",
|
||||
"stopScreenSharing": "Bildschirmfreigabe stoppen",
|
||||
"stopSubtitles": "Untertitel ausschalten",
|
||||
"stopSharedVideo": "YouTube-Video stoppen",
|
||||
"surprised": "Überrascht",
|
||||
"talkWhileMutedPopup": "Versuchen Sie zu sprechen? Ihr Mikrofon ist stummgeschaltet.",
|
||||
"tileViewToggle": "Kachelansicht ein-/ausschalten",
|
||||
"toggleCamera": "Kamera wechseln",
|
||||
"videomute": "Kamera starten / stoppen",
|
||||
"videoSettings": "Video-Einstellungen",
|
||||
"selectBackground": "Hintergrund auswählen"
|
||||
},
|
||||
"transcribing": {
|
||||
@@ -974,10 +1051,10 @@
|
||||
"info": "Einwahlinformationen",
|
||||
"join": "ERSTELLEN / BEITRETEN",
|
||||
"jitsiOnMobile": "Jitsi unterwegs – einfach unsere Apps herunterladen und Meetings von überall starten",
|
||||
"moderatedMessage": "Oder <a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">reservieren Sie sich eine Konferenz-URL</a>, die nur Sie moderieren.",
|
||||
"mobileDownLoadLinkIos": "iOS App Download",
|
||||
"mobileDownLoadLinkAndroid": "Android App Download",
|
||||
"mobileDownLoadLinkFDroid": "F-Droid App Download",
|
||||
"moderatedMessage": "Oder <a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">reservieren Sie sich eine Konferenz-URL</a>, die nur Sie moderieren.",
|
||||
"privacy": "Datenschutz",
|
||||
"recentList": "Verlauf",
|
||||
"recentListDelete": "Eintrag löschen",
|
||||
@@ -1008,6 +1085,7 @@
|
||||
},
|
||||
"lobby": {
|
||||
"admit": "Zulassen",
|
||||
"admitAll": "Alle zulassen",
|
||||
"knockingParticipantList": "Liste anklopfender Personen",
|
||||
"allow": "Annehmen",
|
||||
"backToKnockModeButton": "Kein Passwort, stattdessen Beitritt anfragen",
|
||||
@@ -1038,6 +1116,7 @@
|
||||
"passwordField": "Konferenzpasswort eingeben",
|
||||
"passwordJoinButton": "Beitreten",
|
||||
"reject": "Ablehnen",
|
||||
"rejectAll": "Alle ablehnen",
|
||||
"toggleLabel": "Lobby aktivieren"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,6 +257,9 @@
|
||||
"passwordNotSupported": "No se soporta $t(lockRoomPassword) en la reunión",
|
||||
"passwordNotSupportedTitle": "$t(lockRoomPasswordUppercase) no es compatible",
|
||||
"passwordRequired": "$t(lockRoomPasswordUppercase) necesario",
|
||||
"permissionErrorTitle": "Permiso necesario",
|
||||
"permissionCameraRequiredError": "El permiso de cámara es necesario para participar en conferencias con vídeo. Por favor, permítelo en Ajustes",
|
||||
"permissionMicRequiredError": "El permiso de micrófono es necesario para participar en conferencias con sonido. Por favor, permítelo en Ajustes",
|
||||
"popupError": "Su navegador está bloqueando las ventanas emergentes de este sitio. Habilite las ventanas emergentes en la configuración de seguridad de su navegador y vuelva a intentarlo.",
|
||||
"popupErrorTitle": "Ventana emergente bloqueada",
|
||||
"readMore": "mas",
|
||||
|
||||
1006
lang/main-ml.json
1006
lang/main-ml.json
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,11 @@
|
||||
{
|
||||
"addPeople": {
|
||||
"add": "Convidar",
|
||||
"addContacts": "Convidatz vòstres contactes",
|
||||
"copyInvite": "Copiar l’invitacion de la conferéncia",
|
||||
"copyLink": "Copiar lo ligam de la reünion",
|
||||
"copyStream": "Copiar lo ligam del dirècte",
|
||||
"contacts": "contactes",
|
||||
"countryNotSupported": "Sèm pas encara compatibles amb aquesta destinacion.",
|
||||
"countryReminder": "Sonatz defòra los US ? Mercés de vos assegurar de començar amb lo còdi país.",
|
||||
"disabled": "Podètz pas convidar de monde.",
|
||||
@@ -72,7 +77,11 @@
|
||||
},
|
||||
"privateNotice": "Messatge privat per {{recipient}}",
|
||||
"title": "Messatjariá",
|
||||
"you": "vos"
|
||||
"you": "vos",
|
||||
"message": "Messatge",
|
||||
"messageAccessibleTitle": "{{user}} ditz :",
|
||||
"messageAccessibleTitleMe": "disi :",
|
||||
"smileysPanel": "Panèl d’Emoji"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
"joiningRoom": "Connexion a vòstra reünion…"
|
||||
|
||||
@@ -1,22 +1,33 @@
|
||||
{
|
||||
"addPeople": {
|
||||
"add": "Convidar",
|
||||
"countryNotSupported": "Ainda não suportamos este destino.",
|
||||
"countryReminder": "Está a ligar de fora dos EUA? Por favor, certifique-se de começar com o código do país!",
|
||||
"disabled": "Você não pode convidar pessoas.",
|
||||
"addContacts": "Convidar os seus contactos",
|
||||
"copyInvite": "Cópia do convite para reunião",
|
||||
"copyLink": "Cópia do link da reunião",
|
||||
"copyStream": "Copiar do link de transmissão em direto",
|
||||
"contacts": "contactos",
|
||||
"countryNotSupported": "Ainda não temos suporte para este destino.",
|
||||
"countryReminder": "Está a telefonar para fora dos EUA? Por favor, certifique-se de que começa com o código do país!",
|
||||
"defaultEmail": "O seu e-mail predefinido",
|
||||
"disabled": "Não pode convidar outras pessoas.",
|
||||
"failedToAdd": "Falha ao adicionar participantes",
|
||||
"footerText": "Digitação está desativada.",
|
||||
"inviteMorePrompt": "Convide mais pessoas",
|
||||
"loading": "A procurar por pessoas e números de telefone",
|
||||
"loadingNumber": "A validar o número de telefone",
|
||||
"loadingPeople": "A procurar pessoas para convidar",
|
||||
"noResults": "Nenhum resultado de busca correspondente",
|
||||
"noValidNumbers": "Por favor, digite um número de telefone",
|
||||
"searchNumbers": "Adicionar números de telefone",
|
||||
"searchPeople": "Pesquisar pessoas",
|
||||
"searchPeopleAndNumbers": "Pesquisar por pessoas ou adicionar os seus números de telefone",
|
||||
"footerText": "A marcação está desactivada.",
|
||||
"googleEmail": "E-mail do Google",
|
||||
"inviteMoreHeader": "Você é o único na reunião",
|
||||
"inviteMoreMailSubject": "Participar na reunião {{appName}}",
|
||||
"inviteMorePrompt": "Convidar mais pessoas",
|
||||
"linkCopied": "Link copiado para a área de transferência",
|
||||
"noResults": "Sem resultados de pesquisa correspondentes",
|
||||
"outlookEmail": "E-mail do Outlook",
|
||||
"phoneNumbers": "números de telefone",
|
||||
"searching": "A pesquisar...",
|
||||
"shareInvite": "Partilhar convite de reunião",
|
||||
"shareLink": "Partilhar o link da reunião para convidar outras pessoas",
|
||||
"shareStream": "Partilhar o link de transmissão em direto",
|
||||
"sipAddresses": "endereços SIP",
|
||||
"telephone": "Telefone: {{number}}",
|
||||
"title": "Convide pessoas para sua reunião"
|
||||
"title": "Convidar pessoas para esta reunião",
|
||||
"yahooEmail": "E-mail do Yahoo"
|
||||
},
|
||||
"audioDevices": {
|
||||
"bluetooth": "Bluetooth",
|
||||
@@ -136,138 +147,166 @@
|
||||
},
|
||||
"dialog": {
|
||||
"accessibilityLabel": {
|
||||
"liveStreaming": "Transmissão ao vivo"
|
||||
"liveStreaming": "Transmissão em direto"
|
||||
},
|
||||
"add": "Adicionar",
|
||||
"allow": "Permitir",
|
||||
"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",
|
||||
"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",
|
||||
"authenticationRequired": "Autenticação necessária",
|
||||
"Back": "Voltar",
|
||||
"cameraConstraintFailedError": "Sua câmera não satisfaz algumas condições necessárias.",
|
||||
"cameraNotFoundError": "A câmera não foi encontrada.",
|
||||
"cameraNotSendingData": "Estamos incapazes de acessar sua câmera. Verifique se outra aplicação está usando este dispositivo, selecione outro dispositivo do menu de configurações ou recarregue a aplicação.",
|
||||
"cameraNotSendingDataTitle": "Incapaz de acessar a câmera",
|
||||
"cameraPermissionDeniedError": "Não foi permitido acessar a sua câmera. Você ainda pode entrar na conferência, mas sem exibir o seu vídeo. Clique no botão da câmera para tentar reparar.",
|
||||
"cameraUnknownError": "Não pode usar a câmera por uma razão desconhecida.",
|
||||
"cameraUnsupportedResolutionError": "Sua câmera não suporta a resolução de vídeo requerida.",
|
||||
"cameraConstraintFailedError": "A sua câmara não satisfaz algumas das restrições exigidas.",
|
||||
"cameraNotFoundError": "A câmara não foi encontrada.",
|
||||
"cameraNotSendingData": "Não podemos aceder à sua câmara. Verifique se outra aplicação está a utilizar este dispositivo, seleccione outro dispositivo do menu de definições ou tente recarregar a aplicação.",
|
||||
"cameraNotSendingDataTitle": "Não é possível aceder à câmara",
|
||||
"cameraPermissionDeniedError": "Não concedeu autorização para utilizar a sua câmara. Ainda pode participar na conferência, mas outros não o verão. Use o botão da câmara na barra de endereço para corrigir isto.",
|
||||
"cameraTimeoutError": "Não foi possível iniciar a fonte de vídeo. Tempo limite esgotado!",
|
||||
"cameraUnknownError": "Não é possível utilizar a câmara por uma razão desconhecida.",
|
||||
"cameraUnsupportedResolutionError": "A sua câmara não suporta a resolução de vídeo necessária.",
|
||||
"Cancel": "Cancelar",
|
||||
"close": "Fechar",
|
||||
"conferenceDisconnectMsg": "Você pode querer verificar sua conexão de rede. Reconectando em {{seconds}} segundos ...",
|
||||
"conferenceDisconnectTitle": "Você foi desconectado.",
|
||||
"conferenceReloadMsg": "Estamos tentando consertar isto. Reconectando em {{seconds}} segundos...",
|
||||
"conferenceReloadTitle": "Infelizmente, algo deu errado.",
|
||||
"confirm": "Confirmar",
|
||||
"conferenceDisconnectMsg": "Poderá querer verificar a sua ligação à rede. Reconexão em {{seconds}} seg...",
|
||||
"conferenceDisconnectTitle": "Foi desconectado.",
|
||||
"conferenceReloadMsg": "Estamos a tentar resolver isto. Reconexão em {{seconds}} seg...",
|
||||
"conferenceReloadTitle": "Infelizmente, algo correu mal.",
|
||||
"confirm": "Confirme",
|
||||
"confirmNo": "Não",
|
||||
"confirmYes": "Sim",
|
||||
"connectError": "Oops! Alguma coisa está errada e nós não pudemos conectar à conferência.",
|
||||
"connectErrorWithMsg": "Oops! Alguma coisa está errada e não podemos conectar à conferência: {{msg}}",
|
||||
"connecting": "Conectando",
|
||||
"contactSupport": "Contate o suporte",
|
||||
"copy": "Copiar",
|
||||
"connectError": "Oops! Algo correu mal e não conseguimos estabelecer uma ligação com a conferência.",
|
||||
"connectErrorWithMsg": "Oops! Algo correu mal e não conseguimos estabelecer uma ligação com a conferência: {{msg}}",
|
||||
"connecting": "A ligar",
|
||||
"contactSupport": "Contacte o suporte",
|
||||
"copied": "Copiado",
|
||||
"copy": "Cópia",
|
||||
"dismiss": "Dispensar",
|
||||
"displayNameRequired": "Oi! Qual o seu nome?",
|
||||
"displayNameRequired": "Olá! Qual é o seu nome?",
|
||||
"done": "Feito",
|
||||
"enterDisplayName": "Digite seu nome aqui",
|
||||
"e2eeDescription": "A encriptação de ponta a ponta é actualmente EXPERIMENTAL. Tenha em mente que ligar a encriptação de ponta a ponta irá efectivamente desactivar os serviços fornecidos do lado do servidor, tais como: gravação, transmissão em directo e participação telefónica. Tenha também em mente que o encontro só funcionará para pessoas que se juntem a partir de browsers com suporte para \"insertable streams\".",
|
||||
"e2eeLabel": "Habilitar encriptação de ponta a ponta",
|
||||
"e2eeWarning": "AVISO: Nem todos os participantes neste encontro parecem ter apoio para a encriptação de ponta a ponta. Se o permitir, eles não o poderão ver nem ouvir.",
|
||||
"enterDisplayName": "Digite o seu nome aqui",
|
||||
"enterDisplayNameToJoin": "Por favor, digite o seu nome para participar",
|
||||
"embedMeeting": "Embutir reunião",
|
||||
"error": "Erro",
|
||||
"externalInstallationMsg": "Você precisa instalar nossa extensão de compartilhamento de tela.",
|
||||
"externalInstallationTitle": "Extensão requerida",
|
||||
"goToStore": "Vá para a loja virtual",
|
||||
"gracefulShutdown": "O sistema está em manutenção. Por favor tente novamente mais tarde.",
|
||||
"gracefulShutdown": "O nosso serviço está atualmente em manutenção. Por favor, tente novamente mais tarde.",
|
||||
"grantModeratorDialog": "Tem a certeza de que quer fazer deste participante um moderador?",
|
||||
"grantModeratorTitle": "Converter em moderador",
|
||||
"IamHost": "Eu sou o anfitrião",
|
||||
"incorrectRoomLockPassword": "Senha incorreta",
|
||||
"incorrectPassword": "Usuário ou senha incorretos",
|
||||
"inlineInstallationMsg": "Você precisa instalar nossa extensão de compartilhamento de tela.",
|
||||
"inlineInstallExtension": "Instalar agora",
|
||||
"internalError": "Oops! Alguma coisa está errada. O seguinte erro ocorreu: {{error}}",
|
||||
"incorrectRoomLockPassword": "Palavra-passe incorreta",
|
||||
"incorrectPassword": "Nome de utilizador ou palavra-passe incorretos",
|
||||
"internalError": "Oops! Alguma coisa correu mal. Ocorreu o seguinte erro: {{error}}",
|
||||
"internalErrorTitle": "Erro interno",
|
||||
"kickMessage": "Você pode contatar com {{participantDisplayName}} para obter mais detalhes.",
|
||||
"kickParticipantButton": "Remover",
|
||||
"kickParticipantDialog": "Tem certeza de que deseja remover este participante?",
|
||||
"kickParticipantTitle": "Chutar este participante?",
|
||||
"kickTitle": "Ai! {{participantDisplayName}} expulsou você da reunião",
|
||||
"liveStreaming": "Transmissão ao Vivo",
|
||||
"liveStreamingDisabledForGuestTooltip": "Visitantes não podem iniciar transmissão ao vivo.",
|
||||
"liveStreamingDisabledTooltip": "Iniciar transmissão ao vivo desativada.",
|
||||
"lockMessage": "Falha ao travar a conferência.",
|
||||
"lockRoom": "Adicionar reunião $t(lockRoomPasswordUppercase)",
|
||||
"lockTitle": "Bloqueio falhou",
|
||||
"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!",
|
||||
"kickMessage": "Pode contactar {{participantDisplayName}} para mais detalhes.",
|
||||
"kickParticipantButton": "Expulsar",
|
||||
"kickParticipantDialog": "Tem a certeza que quer expulsar este participante?",
|
||||
"kickParticipantTitle": "Expulsar este participante?",
|
||||
"kickTitle": "Ai! {{participantDisplayName}} expulsou-o da reunião",
|
||||
"liveStreaming": "Transmissão em direto",
|
||||
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "Não é possível enquanto a gravação estiver activa",
|
||||
"liveStreamingDisabledTooltip": "Início de transmissão em direto desactivada",
|
||||
"lockMessage": "Falha no bloqueio da conferência.",
|
||||
"lockRoom": "Adicionar reunião $t(lockRoomPassword)",
|
||||
"lockTitle": "Bloqueio falhado",
|
||||
"logoutQuestion": "Tem a certeza de que quer terminar a sessão e interromper a conferência?",
|
||||
"login": "Entrar",
|
||||
"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!",
|
||||
"maxUsersLimitReachedTitle": "Limite máximo de participantes atingido",
|
||||
"micConstraintFailedError": "Seu microfone não satisfaz algumas condições necessárias.",
|
||||
"micConstraintFailedError": "O seu microfone não satisfaz algumas das restrições exigidas.",
|
||||
"micNotFoundError": "O microfone não foi encontrado.",
|
||||
"micNotSendingData": "Vá para as configurações do seu computador para ativar o som do microfone e ajustar seu nível",
|
||||
"micNotSendingDataTitle": "Seu microfone está mudo pelas configurações do sistema",
|
||||
"micPermissionDeniedError": "Não foi permitido acessar o seu microfone. Você ainda pode entrar na conferência, mas sem enviar áudio. Clique no botão do microfone para tentar reparar.",
|
||||
"micUnknownError": "Não pode usar o microfone por uma razão desconhecida.",
|
||||
"muteParticipantBody": "Você não está habilitado para tirar o mudo deles, mas eles podem tirar o mudo deles mesmos a qualquer tempo.",
|
||||
"micNotSendingData": "Vá às definições do seu computador para desligar o seu microfone e ajustar o seu nível",
|
||||
"micNotSendingDataTitle": "O seu microfone está silenciado pelas definições do seu sistema",
|
||||
"micPermissionDeniedError": "Não concedeu autorização para utilizar o seu microfone. Ainda pode participar na conferência, mas outros não o ouvirão. Use o botão da câmara na barra de endereço para corrigir isto.",
|
||||
"micTimeoutError": "Não foi possível iniciar a fonte de áudio. Tempo limite esgotado!",
|
||||
"micUnknownError": "Não pode usar microfone por uma razão desconhecida.",
|
||||
"muteEveryoneElseDialog": "Uma vez silenciados, não poderá reativá-los, mas eles podem reativar-se a qualquer momento.",
|
||||
"muteEveryoneElseTitle": "Silenciar todos excepto {{whom}}?",
|
||||
"muteEveryoneDialog": "Tem a certeza de que quer silenciar toda a gente? Não poderá reativá-los, mas eles podem reativar-se a qualquer momento.",
|
||||
"muteEveryoneTitle": "Silenciar toda a gente?",
|
||||
"muteEveryoneElsesVideoDialog": "Quando a câmara for desativada, não poderá voltar a ligá-la, mas eles podem voltar a ligá-la em qualquer momento.",
|
||||
"muteEveryoneElsesVideoTitle": "Desativar a câmara de todos exceto {{whom}}?",
|
||||
"muteEveryonesVideoDialog": "Tem a certeza de que quer desativar a câmara de todos? Não poderá voltar a ligá-la, mas eles podem voltar a ligá-la a qualquer momento.",
|
||||
"muteEveryonesVideoDialogOk": "Desativar",
|
||||
"muteEveryonesVideoTitle": "Desativar a câmara de toda a gente?",
|
||||
"muteEveryoneSelf": "você mesmo",
|
||||
"muteEveryoneStartMuted": "A partir de agora, toda a gente começa a ficar calada",
|
||||
"muteParticipantBody": "Não poderá reativá-los, mas eles podem reativar-se a qualquer momento.",
|
||||
"muteParticipantButton": "Mudo",
|
||||
"muteParticipantDialog": "Tem certeza de que deseja silenciar este participante? Você não poderá desfazer isso, mas o participante pode reabilitar o áudio a qualquer momento.",
|
||||
"muteParticipantTitle": "Deixar mudo este participante?",
|
||||
"Ok": "Ok",
|
||||
"passwordLabel": "$t(lockRoomPasswordUppercase)",
|
||||
"passwordNotSupported": "A configuração de uma reunião $t(lockRoomPassword) não é suportada.",
|
||||
"passwordNotSupportedTitle": "$t(lockRoomPasswordUppercase) não suportado",
|
||||
"passwordRequired": "$t(lockRoomPasswordUppercase) requerido",
|
||||
"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",
|
||||
"recording": "Gravando",
|
||||
"recordingDisabledForGuestTooltip": "Visitantes não podem iniciar gravações.",
|
||||
"recordingDisabledTooltip": "Iniciar gravação desativada.",
|
||||
"rejoinNow": "Reconectar agora",
|
||||
"remoteControlAllowedMessage": "{{user}} aceitou sua requisição de controle remoto!",
|
||||
"remoteControlDeniedMessage": "{{user}} rejeitou sua requisição de controle remoto!",
|
||||
"remoteControlErrorMessage": "Um erro ocorreu enquanto tentava requerer a permissão de controle remoto de {{user}}!",
|
||||
"remoteControlRequestMessage": "Deseja permitir que {{user}} controle remotamente sua área de trabalho?",
|
||||
"remoteControlShareScreenWarning": "Note que se você pressionar \"Permitir\" você vai compartilhar sua tela!",
|
||||
"remoteControlStopMessage": "A sessão de controle remoto terminou!",
|
||||
"remoteControlTitle": "Conexão de área de trabalho remota",
|
||||
"muteParticipantDialog": "Tem a certeza de que quer silenciar este participante? Não poderá reativá-los, mas eles podem reativar-se a qualquer momento.",
|
||||
"muteParticipantTitle": "Silenciar este participante?",
|
||||
"muteParticipantsVideoButton": "Desativar a câmara",
|
||||
"muteParticipantsVideoTitle": "Desativar a câmara deste participante?",
|
||||
"muteParticipantsVideoBody": "Não poderá voltar a ligar a câmara, mas eles podem voltar a ligá-la a qualquer momento.",
|
||||
"Ok": "OK",
|
||||
"password": "Palavra-passe",
|
||||
"passwordLabel": "A reunião foi encerrada por um participante. Por favor, introduza a $t(lockRoomPassword) para participar.",
|
||||
"passwordNotSupported": "A definição na reunião $t(lockRoomPassword) não é suportada.",
|
||||
"passwordNotSupportedTitle": "$t(lockRoomPasswordUppercase) não é suportada.",
|
||||
"passwordRequired": "$t(lockRoomPasswordUppercase) necessário",
|
||||
"popupError": "O seu navegador está a bloquear janelas pop-up a partir deste site. Por favor, active os pop-ups nas definições de segurança do seu browser e tente novamente.",
|
||||
"popupErrorTitle": "Pop-up bloqueado",
|
||||
"readMore": "mais",
|
||||
"recording": "A gravar",
|
||||
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Não possível enquanto a transmissão em direto estiver activa",
|
||||
"recordingDisabledTooltip": "Início de gravação desactivada.",
|
||||
"rejoinNow": "Reingressar agora",
|
||||
"remoteControlAllowedMessage": "{{user}} aceitou o seu pedido de controlo remoto!",
|
||||
"remoteControlDeniedMessage": "{{user}} rejeitou o seu pedido de controlo remoto!",
|
||||
"remoteControlErrorMessage": "Ocorreu um erro ao tentar solicitar permissões de controlo remoto de {{user}}!",
|
||||
"remoteControlRequestMessage": "Vai permitir que {{user}} controle remotamente o seu ambiente de trabalho?",
|
||||
"remoteControlShareScreenWarning": "Note que se pressionar \"Permitir\" irá partilhar o seu ecrã!",
|
||||
"remoteControlStopMessage": "A sessão de controlo remoto terminou!",
|
||||
"remoteControlTitle": "Controlo remoto da área de trabalho",
|
||||
"Remove": "Remover",
|
||||
"removePassword": "Remove $t(lockRoomPassword)",
|
||||
"removeSharedVideoMsg": "Deseja remover seu vídeo compartilhado?",
|
||||
"removeSharedVideoTitle": "Remover vídeo compartilhado",
|
||||
"reservationError": "Erro de sistema de reserva",
|
||||
"reservationErrorMsg": "Código do erro: {{code}}, mensagem: {{msg}}",
|
||||
"retry": "Tentar novamente",
|
||||
"screenSharingFailedToInstall": "Oops! Falhou a instalação da extensão de compartilhamento de tela.",
|
||||
"screenSharingFailedToInstallTitle": "A extensão de compartilhamento de tela falhou ao instalar",
|
||||
"screenSharingFirefoxPermissionDeniedError": "Algo deu errado enquanto estávamos tentando compartilhar sua tela. Por favor, certifique-se de que você nos deu permissão para fazê-lo. ",
|
||||
"screenSharingFirefoxPermissionDeniedTitle": "Opa! Não foi possível iniciar o compartilhamento de tela.",
|
||||
"screenSharingPermissionDeniedError": "Oops! Alguma coisa está errada com suas permissões de compartilhamento de tela. Recarregue e tente de novo.",
|
||||
"sendPrivateMessage": "Você enviou uma mensagem privada recentemente. Tem intenção de responder em privado, ou deseja enviar sua mensagem para o grupo?",
|
||||
"removePassword": "Remover $t(lockRoomPassword)",
|
||||
"removeSharedVideoMsg": "Tem a certeza de que gostaria de remover o seu vídeo partilhado?",
|
||||
"removeSharedVideoTitle": "Remover vídeo partilhado",
|
||||
"reservationError": "Erro no sistema de reservas",
|
||||
"reservationErrorMsg": "Código de erro: {{code}}, mensagem: {{msg}}",
|
||||
"retry": "Tentativa",
|
||||
"screenSharingAudio": "Partilhar áudio",
|
||||
"screenSharingFailed": "Oops! Algo correu mal, não fomos capazes de começar a partilhar o ecrã!",
|
||||
"screenSharingFailedTitle": "A partilha de ecrã falhou!",
|
||||
"screenSharingPermissionDeniedError": "Oops! Alguma coisa correu mal com as vossas permissões de partilha de ecrã. Por favor, volte a carregar e tente novamente.",
|
||||
"sendPrivateMessage": "Recebeu recentemente uma mensagem privada. Pretende responder a essa mensagem em privado, ou quer enviar a sua mensagem ao grupo?",
|
||||
"sendPrivateMessageCancel": "Enviar para o grupo",
|
||||
"sendPrivateMessageOk": "Enviar em privado",
|
||||
"sendPrivateMessageTitle": "Enviar em privado?",
|
||||
"serviceUnavailable": "Serviço indisponível",
|
||||
"sessTerminated": "Chamada terminada",
|
||||
"Share": "Compartilhar",
|
||||
"shareVideoLinkError": "Por favor, forneça um link do youtube correto.",
|
||||
"shareVideoTitle": "Compartilhar um vídeo",
|
||||
"shareYourScreen": "Compartilhar sua tela",
|
||||
"shareYourScreenDisabled": "Compartilhamento de tela desativada.",
|
||||
"shareYourScreenDisabledForGuest": "Visitantes não podem compartilhar tela.",
|
||||
"startLiveStreaming": "Iniciar transmissão ao vivo",
|
||||
"sessionRestarted": "Chamada reiniciada pela ponte",
|
||||
"Share": "Partilhar",
|
||||
"shareVideoLinkError": "Por favor, forneça uma ligação correcta ao youtube.",
|
||||
"shareVideoTitle": "Partilhar vídeo",
|
||||
"shareYourScreen": "Partilhe o seu ecrã",
|
||||
"shareYourScreenDisabled": "Partilha de ecrã desactivada.",
|
||||
"startLiveStreaming": "Iniciar a transmissão em directo",
|
||||
"startRecording": "Iniciar gravação",
|
||||
"startRemoteControlErrorMessage": "Um erro ocorreu enquanto tentava iniciar uma sessão de controle remoto!",
|
||||
"stopLiveStreaming": "Parar transmissão ao vivo",
|
||||
"stopRecording": "Parar a gravação",
|
||||
"stopRecordingWarning": "Tem certeza que deseja parar a gravação?",
|
||||
"stopStreamingWarning": "Tem certeza que deseja parar a transmissão ao vivo?",
|
||||
"streamKey": "Chave para transmissão ao vivo",
|
||||
"Submit": "Enviar",
|
||||
"thankYou": "Obrigado por usar o {{appName}}!",
|
||||
"startRemoteControlErrorMessage": "Ocorreu um erro ao tentar iniciar a sessão de controlo remoto!",
|
||||
"stopLiveStreaming": "Parar a transmissão em direto",
|
||||
"stopRecording": "Parar gravação",
|
||||
"stopRecordingWarning": "Tem a certeza de que gostaria de parar a gravação?",
|
||||
"stopStreamingWarning": "Tem a certeza de que gostaria de parar a transmissão em direto?",
|
||||
"streamKey": "Chave de transmissão em direto",
|
||||
"Submit": "Submeter",
|
||||
"thankYou": "Obrigado por utilizar {{appName}}!",
|
||||
"token": "token",
|
||||
"tokenAuthFailed": "Desculpe, você não está autorizado a entrar nesta chamada.",
|
||||
"tokenAuthFailedTitle": "Falha de autenticação",
|
||||
"transcribing": "Transcrevendo",
|
||||
"unlockRoom": "Remove a reunião $t(lockRoomPassword)",
|
||||
"userPassword": "senha do usuário",
|
||||
"WaitForHostMsg": "A conferência <b>{{room}}</b> ainda não começou. Se você é o anfitrião, faça a autenticação. Do contrário, aguarde a chegada do anfitrião.",
|
||||
"WaitForHostMsgWOk": "A conferência <b>{{room}}</b> ainda não começou. Se você é o anfitrião, pressione Ok para autenticar. Do contrário, aguarde a chegada do anfitrião.",
|
||||
"WaitingForHost": "Esperando o hospedeiro...",
|
||||
"tokenAuthFailed": "Desculpe, não está autorizado a juntar-se a esta chamada.",
|
||||
"tokenAuthFailedTitle": "A autenticação falhou",
|
||||
"transcribing": "Transcrição",
|
||||
"unlockRoom": "Retirar reunião $t(lockRoomPassword)",
|
||||
"user": "Utilizador",
|
||||
"userIdentifier": "Identificador do utilizador",
|
||||
"userPassword": "Palavra-passe do utilizador",
|
||||
"videoLink": "Ligação do vídeo",
|
||||
"WaitForHostMsg": "A conferência <b>{{room}}</b> ainda não começou. Se for o anfitrião, por favor autentique. Caso contrário, por favor aguarde que o anfitrião chegue.",
|
||||
"WaitForHostMsgWOk": "A conferência <b>{{room}}</b> ainda não começou. Se for o anfitrião, por favor prima Ok para autenticar. Caso contrário, por favor aguarde que o anfitrião chegue.",
|
||||
"WaitingForHostTitle": "À espera do anfitrião ...",
|
||||
"Yes": "Sim",
|
||||
"yourEntireScreen": "Toda sua tela"
|
||||
"yourEntireScreen": "O seu ecrã inteiro",
|
||||
"remoteUserControls": "Controlos remotos do utilizador {{username}}",
|
||||
"localUserControls": "Controlos locais de utilizador"
|
||||
},
|
||||
"dialOut": {
|
||||
"statusMessage": "está agora {{status}}"
|
||||
@@ -340,7 +379,7 @@
|
||||
"focusRemote": "Focar no vídeo de outro participante",
|
||||
"fullScreen": "Entrar ou sair da tela cheia",
|
||||
"keyboardShortcuts": "Atalhos de teclado",
|
||||
"localRecording": "Mostrar ou ocultar controles de gravação local",
|
||||
"localRecording": "Mostrar ou ocultar controlos de gravação local",
|
||||
"mute": "Deixar mudo ou não o microfone",
|
||||
"pushToTalk": "Pressione para falar",
|
||||
"raiseHand": "Erga ou baixe sua mão",
|
||||
@@ -388,7 +427,7 @@
|
||||
"on": "Ligado",
|
||||
"unknown": "Desconhecido"
|
||||
},
|
||||
"dialogTitle": "Controles da Gravação Local",
|
||||
"dialogTitle": "Controlos da Gravação Local",
|
||||
"duration": "Duração",
|
||||
"durationNA": "N/D",
|
||||
"encoding": "Codificando",
|
||||
@@ -408,7 +447,7 @@
|
||||
"participantStats": "Estatísticas dos Participantes",
|
||||
"sessionToken": "Token de Sessão",
|
||||
"start": "Iniciar gravação",
|
||||
"stop": "Parar a Gravação",
|
||||
"stop": "Parar gravação",
|
||||
"yes": "Sim"
|
||||
},
|
||||
"lockRoomPassword": "senha",
|
||||
@@ -453,10 +492,62 @@
|
||||
"passwordDigitsOnly": "Até {{number}} dígitos",
|
||||
"poweredby": "distribuído por",
|
||||
"prejoin": {
|
||||
"doNotShow": "Não mostre este ecrã novamente",
|
||||
"joinMeeting": "Participar na reunião",
|
||||
"joinWithoutAudio": "Participar sem áudio",
|
||||
"lookGood": "O seu microfone está a funcionar corretamente"
|
||||
"audioAndVideoError": "Erro no áudio e vídeo:",
|
||||
"audioDeviceProblem": "Há um problema com o seu dispositivo de áudio",
|
||||
"audioOnlyError": "Erro no áudio:",
|
||||
"audioTrackError": "Não foi possível criar a pista de áudio.",
|
||||
"calling": "A chamar",
|
||||
"callMe": "Ligue-me",
|
||||
"callMeAtNumber": "Ligue-me para este número:",
|
||||
"configuringDevices": "A configurar os dispositivos...",
|
||||
"connectedWithAudioQ": "Está ligado com áudio?",
|
||||
"connection": {
|
||||
"good": "A sua ligação à Internet parece boa!",
|
||||
"nonOptimal": "A sua ligação à Internet não é óptima",
|
||||
"poor": "Tem uma má ligação à Internet"
|
||||
},
|
||||
"connectionDetails": {
|
||||
"audioClipping": "Prevemos que o seu áudio tenha cortes.",
|
||||
"audioHighQuality": "Prevemos que o seu áudio tenha excelente qualidade.",
|
||||
"audioLowNoVideo": "Prevemos que a qualidade do seu áudio seja baixa e sem vídeo.",
|
||||
"goodQuality": "Fantástico! A qualidade dos seus meios de comunicação vai ser óptima.",
|
||||
"noMediaConnectivity": "Não foi possível encontrar uma forma de estabelecer a conectividade dos meios de comunicação para este teste. Isto é tipicamente causado por uma firewall ou NAT.",
|
||||
"noVideo": "Prevemos que o seu vídeo seja terrível.",
|
||||
"undetectable": "Se mesmo assim não conseguir fazer chamadas no browser, recomendamos que se certifique de que os seus altifalantes, microfone e câmara estão devidamente configurados, que concedeu ao seu browser direitos de utilização do seu microfone e câmara, e que a versão do seu browser está actualizada. Se mesmo assim tiver problemas em telefonar, deverá contactar o criador da aplicação web.",
|
||||
"veryPoorConnection": "Prevemos que a qualidade da sua chamada seja realmente terrível.",
|
||||
"videoFreezing": "Prevemos que o seu vídeo congele, fique preto, e seja pixelizado.",
|
||||
"videoHighQuality": "Prevemos que o seu vídeo tenha boa qualidade.",
|
||||
"videoLowQuality": "Prevemos que o seu vídeo tenha baixa qualidade em termos de velocidade de fotogramas e resolução.",
|
||||
"videoTearing": "Prevemos que o seu vídeo seja pixelizado ou que tenha artefactos visuais."
|
||||
},
|
||||
"copyAndShare": "Copiar e partilhar a ligação da reunião.",
|
||||
"dialInMeeting": "Entrar com chamada telefónica",
|
||||
"dialInPin": "Entrar com chamada telefónica e introduzir o código PIN:",
|
||||
"dialing": "A marcar",
|
||||
"doNotShow": "Não volte a mostrar este ecrã",
|
||||
"errorDialOut": "Não foi possível marcar",
|
||||
"errorDialOutDisconnected": "Não foi possível marcar. Desligado",
|
||||
"errorDialOutFailed": "Não foi possível marcar. Falha na chamada",
|
||||
"errorDialOutStatus": "Erro ao obter o estado da chamada realizada",
|
||||
"errorMissingName": "Por favor, digite o seu nome para participar na reunião",
|
||||
"errorStatusCode": "Erro ao marcar, código do estado: {{status}}",
|
||||
"errorValidation": "Falhou a validação do número",
|
||||
"iWantToDialIn": "Quero entrar por telefone",
|
||||
"joinAudioByPhone": "Entrar com o áudio do telefone",
|
||||
"joinMeeting": "Entrar na reunião",
|
||||
"joinWithoutAudio": "Entrar sem áudio",
|
||||
"initiated": "Chamada iniciada",
|
||||
"linkCopied": "Ligação copiada para a área de transferência",
|
||||
"lookGood": "Parece que o seu microfone está a funcionar corretamente",
|
||||
"or": "ou",
|
||||
"premeeting": "Pré-reunião",
|
||||
"showScreen": "Ativar o ecrã de pré-reunião",
|
||||
"keyboardShortcuts" : "Ativar os atalhos de teclado",
|
||||
"startWithPhone": "Iniciar com o áudio do telefone",
|
||||
"screenSharingError": "Erro de partilha de ecrã:",
|
||||
"videoOnlyError": "Erro de vídeo:",
|
||||
"videoTrackError": "Não foi possível criar a pista de vídeo.",
|
||||
"viewAllNumbers": "ver todos os números"
|
||||
},
|
||||
"presenceStatus": {
|
||||
"busy": "Ocupado",
|
||||
@@ -511,26 +602,39 @@
|
||||
},
|
||||
"settings": {
|
||||
"calendar": {
|
||||
"about": "A integração do calendário {{appName}} é usada para acessar com segurança o seu calendário para que ele possa ler os próximos eventos.",
|
||||
"disconnect": "Desconectar",
|
||||
"microsoftSignIn": "Entrar com Microsoft",
|
||||
"signedIn": "Atualmente acessando eventos do calendário para {{email}}. Clique no botão Desconectar abaixo para parar de acessar os eventos da agenda.",
|
||||
"about": "A integração do calendário {{appName}} é utilizada para aceder com segurança ao seu calendário para que este possa ler os próximos eventos.",
|
||||
"disconnect": "Desligar",
|
||||
"microsoftSignIn": "Iniciar sessão com a Microsoft",
|
||||
"signedIn": "Atualmente a aceder a eventos de calendário por {{email}}. Clique no botão Desconectar abaixo para parar de aceder a eventos de calendário.",
|
||||
"title": "Calendário"
|
||||
},
|
||||
"desktopShareFramerate": "Taxa de fotogramas para partilha do ambiente de trabalho",
|
||||
"desktopShareWarning": "É necessário reiniciar a partilha do ecrã para que as novas definições entrem em vigor.",
|
||||
"desktopShareHighFpsWarning": "Uma taxa de fotogramas mais elevada para a partilha do ambiente de trabalho pode afectar a sua largura de banda. É necessário reiniciar a partilha de ecrã para que as novas definições entrem em vigor.",
|
||||
"devices": "Dispositivos",
|
||||
"followMe": "Todos me seguem",
|
||||
"framesPerSecond": "fotogramas-por-segundo",
|
||||
"incomingMessage": "Receber mensagem",
|
||||
"language": "Idioma",
|
||||
"loggedIn": "Conectado como {{name}}",
|
||||
"loggedIn": "Sessão iniciada como {{name}}",
|
||||
"microphones": "Microfones",
|
||||
"moderator": "Moderador",
|
||||
"more": "Mais",
|
||||
"name": "Nome",
|
||||
"noDevice": "Nenhum",
|
||||
"participantJoined": "Entrar participante",
|
||||
"participantLeft": "Sair participante",
|
||||
"playSounds": "Reproduzir som quando",
|
||||
"sameAsSystem": "O mesmo que o sistema ({{label}})",
|
||||
"selectAudioOutput": "Saída de áudio",
|
||||
"selectCamera": "Câmera",
|
||||
"selectCamera": "Câmara",
|
||||
"selectMic": "Microfone",
|
||||
"startAudioMuted": "Todos iniciam mudos",
|
||||
"startVideoMuted": "Todos iniciam ocultos",
|
||||
"title": "Configurações"
|
||||
"sounds": "Sons",
|
||||
"speakers": "Participantes",
|
||||
"startAudioMuted": "Todos começam com microfone desligado",
|
||||
"startVideoMuted": "Todos começam com câmara desligada",
|
||||
"talkWhileMuted": "se fala e está com microfone desligado",
|
||||
"title": "Definições"
|
||||
},
|
||||
"settingsView": {
|
||||
"advanced": "",
|
||||
@@ -574,92 +678,123 @@
|
||||
"title": "Sua chamada de vídeo foi interrompida, porque seu computador foi dormir."
|
||||
},
|
||||
"toolbar": {
|
||||
"accessibilityLabel": {
|
||||
"audioOnly": "Alternar para apenas áudio",
|
||||
"audioRoute": "Selecionar o dispositivo de som",
|
||||
"callQuality": "Gerenciar qualidade do vídeo",
|
||||
"cc": "Alternar legendas",
|
||||
"chat": "Alternar para janela de chat",
|
||||
"document": "Alternar para documento compartilhado",
|
||||
"download": "Baixe nossos aplicativos",
|
||||
"feedback": "Deixar feedback",
|
||||
"fullScreen": "Alternar para tela cheia",
|
||||
"hangup": "Sair da chamada",
|
||||
"help": "Ajuda",
|
||||
"invite": "Convidar pessoas",
|
||||
"kick": "Remover participante",
|
||||
"localRecording": "Alternar controles de gravação local",
|
||||
"lockRoom": "Ativar/desativar senha de reunião",
|
||||
"moreActions": "Alternar mais menu de ações",
|
||||
"moreActionsMenu": "Menu de mais ações",
|
||||
"mute": "Alternar mudo do áudio",
|
||||
"pip": "Alternar modo Picture-in-Picture",
|
||||
"privateMessage": "Enviar mensagem privada",
|
||||
"profile": "Editar seu perfil",
|
||||
"raiseHand": "Alternar levantar a mão",
|
||||
"recording": "Alternar gravação",
|
||||
"remoteMute": "Silenciar participante",
|
||||
"Settings": "Alternar configurações",
|
||||
"sharedvideo": "Alternar compartilhamento de vídeo do Youtube",
|
||||
"shareRoom": "Convidar alguém",
|
||||
"shareYourScreen": "Alternar compartilhamento de tela",
|
||||
"shortcuts": "Alternar atalhos",
|
||||
"show": "Mostrar no palco",
|
||||
"speakerStats": "Alternar estatísticas do apresentador",
|
||||
"tileView": "Alternar visualização em blocos",
|
||||
"toggleCamera": "Alternar câmera",
|
||||
"videomute": "Alternar mudo do vídeo",
|
||||
"videoblur": "Alternar desfoque de vídeo"
|
||||
},
|
||||
"addPeople": "Adicionar pessoas à sua chamada",
|
||||
"audioOnlyOff": "Desabilitar modo de largura de banda baixa",
|
||||
"audioOnlyOn": "Habilitar modo de largura de banda baixa",
|
||||
"accessibilityLabel": {
|
||||
"audioOnly": "Mudar para apenas áudio",
|
||||
"audioRoute": "Selecionar o dispositivo de som",
|
||||
"authenticate": "Autenticar",
|
||||
"callQuality": "Gerenciar qualidade do vídeo",
|
||||
"chat": "Abrir ou fechar o bate-papo",
|
||||
"closeChat": "Fechar chat",
|
||||
"documentClose": "Fechar documento compartilhado",
|
||||
"documentOpen": "Abrir documento compartilhado",
|
||||
"download": "Baixe nossos aplicativos",
|
||||
"enterFullScreen": "Ver em tela cheia",
|
||||
"enterTileView": "Entrar em exibição de bloco",
|
||||
"exitFullScreen": "Sair da tela cheia",
|
||||
"exitTileView": "Sair de exibição de bloco",
|
||||
"feedback": "Deixar feedback",
|
||||
"hangup": "Sair",
|
||||
"callQuality": "Gerir a qualidade do vídeo",
|
||||
"cc": "Mudar legendas",
|
||||
"chat": "Abrir / Fechar chat",
|
||||
"document": "Mudar para documento partilhado",
|
||||
"download": "Descarregar as nossas aplicações",
|
||||
"embedMeeting": "Reunião incorporada",
|
||||
"feedback": "Deixar comentários",
|
||||
"fullScreen": "Mudar para ecrã completo",
|
||||
"grantModerator": "Atribuir Moderador",
|
||||
"hangup": "Sair da reunião",
|
||||
"help": "Ajuda",
|
||||
"invite": "Convidar pessoas",
|
||||
"login": "Iniciar sessão",
|
||||
"logout": "Encerrar sessão",
|
||||
"lowerYourHand": "Baixar a mão",
|
||||
"kick": "Remover participante",
|
||||
"lobbyButton": "Ativar/desativar sala de espera",
|
||||
"localRecording": "Mudar os controlos locais de gravação",
|
||||
"lockRoom": "Mudar palavra-chave de reunião",
|
||||
"moreActions": "Mais ações",
|
||||
"moreActionsMenu": "Menu de mais ações",
|
||||
"moreOptions": "Mostrar mais opções",
|
||||
"mute": "Mudo / Não mudo",
|
||||
"noAudioSignalTitle": "",
|
||||
"noAudioSignalDesc": "",
|
||||
"noAudioSignalDescSuggestion": "",
|
||||
"openChat": "Abrir chat",
|
||||
"pip": "Entrar em modo Quadro-a-Quadro",
|
||||
"muteEveryone": "Silenciar a todos",
|
||||
"muteEveryoneElse": "Silenciar todos os outros",
|
||||
"muteEveryonesVideo": "Desativar a câmara de todos",
|
||||
"muteEveryoneElsesVideo": "Desativar a câmara de todos os outros",
|
||||
"participants": "Participantes",
|
||||
"pip": "Mudar para o modo Picture-in-Picture",
|
||||
"privateMessage": "Enviar mensagem privada",
|
||||
"profile": "Editar seu perfil",
|
||||
"raiseHand": "Erguer / Baixar sua mão",
|
||||
"raiseYourHand": "Levantar a mão",
|
||||
"Settings": "Configurações",
|
||||
"sharedvideo": "Compartilhar um vídeo do YouTube",
|
||||
"profile": "Editar o seu perfil",
|
||||
"raiseHand": "Levantar / Baixar a mão",
|
||||
"recording": "Mudar gravação",
|
||||
"remoteMute": "Participante mudo",
|
||||
"remoteVideoMute": "Desativar a câmara do participante",
|
||||
"security": "Opções de segurança",
|
||||
"Settings": "Mudar configurações",
|
||||
"shareaudio": "Partilhar áudio",
|
||||
"sharedvideo": "Mudar a partilha de vídeos do YouTube",
|
||||
"shareRoom": "Convidar alguém",
|
||||
"shortcuts": "Ver atalhos",
|
||||
"speakerStats": "Estatísticas do Apresentador",
|
||||
"startScreenSharing": "Iniciar compart. de tela",
|
||||
"startSubtitles": "Iniciar legendas",
|
||||
"stopScreenSharing": "Parar compart. de tela",
|
||||
"stopSubtitles": "Parar legendas",
|
||||
"stopSharedVideo": "Parar vídeo do YouTube",
|
||||
"talkWhileMutedPopup": "Tentando falar? Você está em mudo.",
|
||||
"tileViewToggle": "Alternar visualização em blocos",
|
||||
"toggleCamera": "Alternar câmera",
|
||||
"videomute": "Iniciar ou parar a câmera",
|
||||
"startvideoblur": "Desfocar meu plano de fundo",
|
||||
"stopvideoblur": "Desativar desfoque de fundo"
|
||||
"shareYourScreen": "Iniciar / Parar de partilhar o seu ecrã",
|
||||
"shortcuts": "Mostrar / Esconder atalhos",
|
||||
"show": "Mostrar no palco",
|
||||
"speakerStats": "Mostrar / Esconder estatísticas dos participantes",
|
||||
"tileView": "Mudar para vista em quadrícula",
|
||||
"toggleCamera": "Mudar a câmara",
|
||||
"toggleFilmstrip": "Mudar para película de filme",
|
||||
"videomute": "Iniciar / Parar câmara",
|
||||
"videoblur": "Mudar o desfoque de vídeo",
|
||||
"selectBackground": "Selecionar plano de fundo",
|
||||
"expand": "Expandir",
|
||||
"collapse": "Colapsar"
|
||||
},
|
||||
"addPeople": "Adicione pessoas à sua chamada",
|
||||
"audioSettings": "Definições de áudio",
|
||||
"videoSettings": "Definições de vídeo",
|
||||
"audioOnlyOff": "Desativar modo de largura de banda baixa",
|
||||
"audioOnlyOn": "Ativar modo de largura de banda baixa",
|
||||
"audioRoute": "Selecionar o dispositivo de som",
|
||||
"authenticate": "Autenticar",
|
||||
"callQuality": "Gerir a qualidade do vídeo",
|
||||
"chat": "Abrir / Fechar chat",
|
||||
"closeChat": "Fechar chat",
|
||||
"documentClose": "Fechar documento partilhado",
|
||||
"documentOpen": "Abrir documento partilhado",
|
||||
"download": "Descarregar as nossas aplicações",
|
||||
"e2ee": "Criptografia ponta a ponta",
|
||||
"embedMeeting": "Incorporar reunião",
|
||||
"enterFullScreen": "Ver em ecrã completo",
|
||||
"enterTileView": "Ver em quadrícula",
|
||||
"exitFullScreen": "Sair de ecrã completo",
|
||||
"exitTileView": "Sair de quadrícula",
|
||||
"feedback": "Deixar comentários",
|
||||
"hangup": "Sair da reunião",
|
||||
"help": "Ajuda",
|
||||
"invite": "Convidar pessoas",
|
||||
"lobbyButtonDisable": "Desativar sala de espera",
|
||||
"lobbyButtonEnable": "Ativar sala de espera",
|
||||
"login": "Iniciar sessão",
|
||||
"logout": "Encerrar sessão",
|
||||
"lowerYourHand": "Baixar a mão",
|
||||
"moreActions": "Mais ações",
|
||||
"moreOptions": "Mais opções",
|
||||
"mute": "Mudo / Não mudo",
|
||||
"muteEveryone": "Silenciar todos",
|
||||
"muteEveryonesVideo": "Desativar a câmara de todos",
|
||||
"noAudioSignalTitle": "Não há nenhuma entrada vinda do seu microfone!",
|
||||
"noAudioSignalDesc": "Se não o silenciou propositadamente a partir de configurações do sistema ou hardware, considere mudar de dispositivo.",
|
||||
"noAudioSignalDescSuggestion": "Se não o silenciou propositadamente a partir das configurações do sistema ou hardware, considere mudar para o dispositivo sugerido.",
|
||||
"noAudioSignalDialInDesc": "Também pode marcar usando:",
|
||||
"noAudioSignalDialInLinkDesc": "Números de marcação",
|
||||
"noisyAudioInputTitle": "Seu microfone parece estar barulhento!",
|
||||
"noisyAudioInputDesc": "Parece que o seu microfone está a fazer barulho, por favor considere silenciar ou mudar de dispositivo.",
|
||||
"openChat": "Abrir chat",
|
||||
"participants": "Participantes",
|
||||
"pip": "Entrar no modo Picture-in-Picture",
|
||||
"privateMessage": "Enviar mensagem privada",
|
||||
"profile": "Editar o seu perfil",
|
||||
"raiseHand": "Levantar / Baixar a mão",
|
||||
"raiseYourHand": "Levantar a mão",
|
||||
"security": "Opções de segurança",
|
||||
"Settings": "Definições",
|
||||
"shareaudio": "Partilhar áudio",
|
||||
"sharedvideo": "Partilhar vídeo",
|
||||
"shareRoom": "Convidar alguém",
|
||||
"shortcuts": "Ver atalhos",
|
||||
"speakerStats": "Estatísticas dos participantes",
|
||||
"startScreenSharing": "Iniciar partilha de ecrã",
|
||||
"startSubtitles": "Iniciar legendas",
|
||||
"stopScreenSharing": "Parar partilha de ecrã",
|
||||
"stopSubtitles": "Parar legendas",
|
||||
"stopSharedVideo": "Parar vídeo do YouTube",
|
||||
"talkWhileMutedPopup": "Está a tentar falar? Está mudo.",
|
||||
"tileViewToggle": "Mudar para vista em quadrícula",
|
||||
"toggleCamera": "Mudar a câmara",
|
||||
"videomute": "Iniciar / Parar câmara",
|
||||
"selectBackground": "Selecionar plano de fundo"
|
||||
},
|
||||
"transcribing": {
|
||||
"ccButtonTooltip": "Iniciar/parar legendas",
|
||||
|
||||
@@ -304,6 +304,7 @@
|
||||
"transcribing": "Transcrevendo",
|
||||
"unlockRoom": "Remove a reunião $t(lockRoomPassword)",
|
||||
"userPassword": "senha do usuário",
|
||||
"videoLink": "Link do vídeo",
|
||||
"WaitForHostMsg": "A conferência <b>{{room}}</b> ainda não começou. Se você é o anfitrião, faça a autenticação. Do contrário, aguarde a chegada do anfitrião.",
|
||||
"WaitForHostMsgWOk": "A conferência <b>{{room}}</b> ainda não começou. Se você é o anfitrião, pressione Ok para autenticar. Do contrário, aguarde a chegada do anfitrião.",
|
||||
"WaitingForHost": "Esperando o anfitrião...",
|
||||
@@ -321,6 +322,28 @@
|
||||
},
|
||||
"embedMeeting": {
|
||||
"title": "Reunião em formato compacto"
|
||||
},
|
||||
"virtualBackground": {
|
||||
"apply": "Aplicar",
|
||||
"title": "Fundos virtuais",
|
||||
"blur": "Desfoque",
|
||||
"slightBlur": "Desfoque suave",
|
||||
"removeBackground": "Remover fundo",
|
||||
"addBackground": "Adicionar novo fundo",
|
||||
"pleaseWait": "Aguarde...",
|
||||
"none": "Nenhum",
|
||||
"uploadedImage": "Imagem enviada {{index}}",
|
||||
"deleteImage": "Excluir imagem",
|
||||
"image1" : "Praia",
|
||||
"image2" : "Parede branca neutra",
|
||||
"image3" : "Quarto branco vazio",
|
||||
"image4" : "Luminária preta",
|
||||
"image5" : "Montanha",
|
||||
"image6" : "Floresta",
|
||||
"image7" : "Alvorada",
|
||||
"desktopShareError": "Não foi possível compartilhar o desktop",
|
||||
"desktopShare":"Compartilhar desktop",
|
||||
"webAssemblyWarning": "Não há suporte para WebAssembly"
|
||||
},
|
||||
"feedback": {
|
||||
"average": "Média",
|
||||
@@ -499,6 +522,18 @@
|
||||
"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",
|
||||
"oldElectronClientDescription3": " agora!"
|
||||
},
|
||||
"participantsPane": {
|
||||
"close": "Fechar",
|
||||
"headings": {
|
||||
"lobby": "Sala de espera ({{count}})",
|
||||
"participantsList": "Participantes da reunião ({{count}})"
|
||||
},
|
||||
"actions": {
|
||||
"invite": "Convidar alguém",
|
||||
"muteAll": "Silenciar todos",
|
||||
"stopVideo": "Parar vídeo"
|
||||
}
|
||||
},
|
||||
"passwordSetRemotely": "Definido por outro participante",
|
||||
"passwordDigitsOnly": "Até {{number}} dígitos",
|
||||
@@ -714,6 +749,7 @@
|
||||
"mute": "Alternar mudo do áudio",
|
||||
"muteEveryone": "Silenciar todos",
|
||||
"muteEveryonesVideo": "Desativar a câmera de todos",
|
||||
"participants": "Participantes",
|
||||
"pip": "Alternar modo Picture-in-Picture",
|
||||
"privateMessage": "Enviar mensagem privada",
|
||||
"profile": "Editar seu perfil",
|
||||
|
||||
@@ -5,29 +5,26 @@
|
||||
"copyInvite": "Kopjo ftesë takimi",
|
||||
"copyLink": "Kopjo lidhje takimi",
|
||||
"copyStream": "Kopjo lidhje transmetimi të drejtpërdrejtë",
|
||||
"contacts": "kontakte",
|
||||
"countryNotSupported": "S’e mbulojmë ende këtë vend.",
|
||||
"countryReminder": "Thirrje jashtë ShBA-s? Ju lutemi, sigurohuni se e nisni me kodin e vendit!",
|
||||
"countryReminder": "Thirrje nga jashtë ShBA-s? Ju lutemi, sigurohuni se e nisni me kodin e vendit!",
|
||||
"defaultEmail": "Email-i Juaj Parazgjedhje",
|
||||
"disabled": "S’mund të ftoni persona.",
|
||||
"failedToAdd": "S’u arrit të shtohen pjesëmarrës",
|
||||
"footerText": "Formimi i numrave është i çaktivizuar.",
|
||||
"googleEmail": "Email Google",
|
||||
"inviteMoreHeader": "Jeni i vetmi në takim",
|
||||
"inviteMoreHeader": "Në takim jeni vetëm ju",
|
||||
"inviteMoreMailSubject": "Merrni pjesë në takim me {{appName}}",
|
||||
"inviteMorePrompt": "Ftoni më tepër persona",
|
||||
"linkCopied": "Lidhja u kopjua në të papastër",
|
||||
"loading": "Po kërkohet për persona dhe numra telefonash",
|
||||
"loadingNumber": "Po vlerësohet numër telefoni",
|
||||
"loadingPeople": "Po kërkohet për persona për t’i ftuar",
|
||||
"noResults": "S’ka përfundime kërkimi me përputhje",
|
||||
"noValidNumbers": "Ju lutemi, jepni një numër telefoni",
|
||||
"outlookEmail": "Email Outlook",
|
||||
"searchNumbers": "Shtoni numra telefoni",
|
||||
"searchPeople": "Kërkoni për persona",
|
||||
"searchPeopleAndNumbers": "Kërkoni për persona ose shtoni numrat e tyre të telefonit",
|
||||
"phoneNumbers": "numra telefonash",
|
||||
"searching": "Po kërkohet…",
|
||||
"shareInvite": "Jepuni të tjerëve ftesë takimi",
|
||||
"shareLink": "Që të ftoni të tjerë, jepuni lidhjen për në takim",
|
||||
"shareStream": "Jepuni të tjerëve lidhjen e transmetimit të drejtpërdrejtë",
|
||||
"sipAddresses": "adresa SIP",
|
||||
"telephone": "Telefon: {{number}}",
|
||||
"title": "Ftoni persona në këtë takim",
|
||||
"yahooEmail": "Email Yahoo"
|
||||
@@ -40,7 +37,7 @@
|
||||
"none": "S’ka pajisje audio"
|
||||
},
|
||||
"audioOnly": {
|
||||
"audioOnly": "Sasi e vogël trafiku"
|
||||
"audioOnly": "Gjerësi e ulët bande"
|
||||
},
|
||||
"calendarSync": {
|
||||
"addMeetingURL": "Shtoni një lidhje takimi",
|
||||
@@ -56,7 +53,7 @@
|
||||
"noEvents": "S’ka veprimtari të ardhshme të vëna në plan.",
|
||||
"ongoingMeeting": "takim në zhvillim e sipër",
|
||||
"permissionButton": "Hapni rregullimet",
|
||||
"permissionMessage": "Që të shihni në aplikacion takimet tuaja, lejet mbi Kalendarin janë të domosdoshme.",
|
||||
"permissionMessage": "Që të shihni në aplikacion takimet tuaja, janë të domosdoshme lejet mbi Kalendarin.",
|
||||
"refresh": "Rifresko kalendarin",
|
||||
"today": "Sot"
|
||||
},
|
||||
@@ -73,12 +70,17 @@
|
||||
},
|
||||
"privateNotice": "Mesazh privat për {{recipient}}",
|
||||
"title": "Fjalosje",
|
||||
"you": "ju"
|
||||
"you": "ju",
|
||||
"message": "Mesazh",
|
||||
"messageAccessibleTitle": "{{user}} thotë:",
|
||||
"messageAccessibleTitleMe": "unë them:",
|
||||
"smileysPanel": "Panel emoji-sh"
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
"installExtensionText": "Instaloni zgjerimin për integrim të Google Calendar-it dhe Office 365-s",
|
||||
"buttonText": "Instaloni Zgjerimin për Chrome",
|
||||
"dontShowAgain": "Mos ma shfaq sërish këtë"
|
||||
"dontShowAgain": "Mos ma shfaq sërish këtë",
|
||||
"close": "Mbylle"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
"joiningRoom": "Po ju lidhim me takimin tuaj…"
|
||||
@@ -94,14 +96,14 @@
|
||||
"DISCONNECTING": "Po shkëputet",
|
||||
"ERROR": "Gabim",
|
||||
"FETCH_SESSION_ID": "Po merret ID sesioni…",
|
||||
"GET_SESSION_ID_ERROR": "Gabim marrjeje IS sesioni: {{code}}",
|
||||
"GET_SESSION_ID_ERROR": "Gabim marrjeje ID sesioni: {{code}}",
|
||||
"GOT_SESSION_ID": "Po merret ID sesioni… U bë",
|
||||
"LOW_BANDWIDTH": "Videoja për {{displayName}} është mbyllur, për të kursyer sasi trafiku"
|
||||
},
|
||||
"connectionindicator": {
|
||||
"address": "Adresë:",
|
||||
"audio_ssrc": "SSRC Audioje:",
|
||||
"bandwidth": "Sasi e hamendësuar trafiku:",
|
||||
"bandwidth": "Gjerësi e hamendësuar bande:",
|
||||
"bitrate": "Bitrate:",
|
||||
"bridgeCount": "Numër shërbyesish: ",
|
||||
"codecs": "Kodekë (A/V): ",
|
||||
@@ -113,7 +115,7 @@
|
||||
"localaddress_plural": "Adresa vendore:",
|
||||
"localport": "Portë vendore:",
|
||||
"localport_plural": "Porta vendore:",
|
||||
"maxEnabledResolution": "dërgo maksimumi",
|
||||
"maxEnabledResolution": "maksimum dërgimi",
|
||||
"more": "Shfaq më tepër",
|
||||
"packetloss": "Humbje paketesh:",
|
||||
"quality": {
|
||||
@@ -150,10 +152,10 @@
|
||||
"joinInApp": "Merrni pjesë në këtë takim duke përdorur aplikacionin",
|
||||
"launchWebButton": "Nise në web",
|
||||
"title": "Po niset takimi juaj në {{app}}…",
|
||||
"tryAgainButton": "Riprovo në desktop"
|
||||
"tryAgainButton": "Riprovoni në desktop"
|
||||
},
|
||||
"defaultLink": "p.sh. {{url}}",
|
||||
"defaultNickname": "shembull. Ndrikulla",
|
||||
"defaultLink": "p.sh., {{url}}",
|
||||
"defaultNickname": "p.sh., Ndrikulla",
|
||||
"deviceError": {
|
||||
"cameraError": "S’u arrit të hyhej në kamerën tuaj",
|
||||
"cameraPermission": "Gabim në marrje lejesh mbi kamerën",
|
||||
@@ -206,12 +208,14 @@
|
||||
"e2eeDescription": "Fshehtëzimi Skaj-më-Skaj aktualisht është EKSPERIMENTAL. Ju lutemi, mbani parasysh se aktivizimi i fshehtëzimit skaj-më-skaj praktikisht do të çaktivizojë shërbime të ofruara më anë të shërbyesit, të tillë si: regjistrim, transmetim të drejtpërdrejtë dhe pjesëmarrje me telefon. Mbani parasysh gjithashtu se takimi do të funksionojë vetëm për persona që hyjnë në të nga shfletues që mbulojnë futje rrjedhash transmetimi.",
|
||||
"e2eeLabel": "Aktivizo Fshehtëzim Skaj-më-Skaj",
|
||||
"e2eeWarning": "KUJDES: Jo të gjithë pjesëmarrësit në këtë takim duket të kenë mbulim për fshehtëzim Skaj-më-Skaj. Në e aktivizofshi, ata s’do të jenë në gjendje t’ju shohin apo dëgjojnë.",
|
||||
"enterDisplayName": "Ju lute, jepni këtu emrin tuaj",
|
||||
"enterDisplayName": "Ju lutemi, jepni këtu emrin tuaj",
|
||||
"enterDisplayNameToJoin": "Që të merrni pjesë, ju lutemi, jepni emrin tuaj",
|
||||
"embedMeeting": "Trupëzoni takim",
|
||||
"error": "Gabim",
|
||||
"gracefulShutdown": "Shërbimi ynë është aktualisht i ndërprerë, për punë mirëmbajtjeje. Ju lutemi, riprovoni më vonë.",
|
||||
"grantModeratorDialog": "Jeni i sigurt se doni ta bëni moderator këtë pjesëmarrës?",
|
||||
"grantModeratorTitle": "Akordoni të drejta moderatori",
|
||||
"IamHost": "Jam organizatori",
|
||||
"IamHost": "Jam organizuesi",
|
||||
"incorrectRoomLockPassword": "Fjalëkalim i pasaktë",
|
||||
"incorrectPassword": "Emër përdoruesi ose fjalëkalim i pasaktë",
|
||||
"internalError": "Hëm! Diç shkoi ters. Ndodhi gabimi vijues: {{error}}",
|
||||
@@ -230,8 +234,8 @@
|
||||
"logoutQuestion": "Jeni i sigurt se doni të dilet dhe të ndalet konferenca?",
|
||||
"login": "Hyrje",
|
||||
"logoutTitle": "Dalje",
|
||||
"maxUsersLimitReached": "U mbërrit në kufirin për numër maksimum pjesëmarrësish. Konferenca është plot. Ju lutemi, lidhuni me të zotin e takimit, ose provoni më vonë!",
|
||||
"maxUsersLimitReachedTitle": "U mbërrit në kufirin për numër maksimum pjesëmarrësish",
|
||||
"maxUsersLimitReached": "U mbërrit në kufi numri maksimum pjesëmarrësish. Konferenca është plot. Ju lutemi, lidhuni me të zotin e takimit, ose provoni më vonë!",
|
||||
"maxUsersLimitReachedTitle": "U mbërrit në kufi numri maksimum pjesëmarrësish",
|
||||
"micConstraintFailedError": "Mikrofoni juaj s’plotëson disa nga kufizimet e domosdoshme.",
|
||||
"micNotFoundError": "S’u gjet mikrofon.",
|
||||
"micNotSendingData": "Kaloni te rregullimet e kompjuterit tuaj që t’i hiqni mikrofonit heshtimin dhe të ujdisni volumin për të",
|
||||
@@ -258,6 +262,7 @@
|
||||
"muteParticipantsVideoTitle": "Të çaktivizohet kamera e këtij pjesëmarrësi?",
|
||||
"muteParticipantsVideoBody": "S’do të jeni në gjendje të rihapni kamerën, por ata mund ta bëjnë këtë për veten në çfarëdo kohe.",
|
||||
"Ok": "OK",
|
||||
"password": "Fjalëkalim",
|
||||
"passwordLabel": "Takimi është kyçur nga njëri prej pjesëmarrësve. Që të merrni pjesë, ju lutemi, jepni $t(lockRoomPassword).",
|
||||
"passwordNotSupported": "Nuk mbulohet caktimi i një $t(lockRoomPassword) takimi.",
|
||||
"passwordNotSupportedTitle": "$t(lockRoomPasswordUppercase) nuk mbulohet",
|
||||
@@ -294,9 +299,9 @@
|
||||
"serviceUnavailable": "Shërbim jashtë funksionimi",
|
||||
"sessTerminated": "Thirrja përfundoi",
|
||||
"sessionRestarted": "Thirrje e rinisur nga ura",
|
||||
"Share": "Share",
|
||||
"shareVideoLinkError": "Ju lutemi, jepni një lidhje youtube të saktë.",
|
||||
"shareVideoTitle": "Ndani një video me të tjerë",
|
||||
"Share": "Ndajeni",
|
||||
"shareVideoLinkError": "Ju lutemi, jepni një lidhje Youtube të saktë.",
|
||||
"shareVideoTitle": "Ndani video me të tjerë",
|
||||
"shareYourScreen": "Tregojuni ekranin tuaj",
|
||||
"shareYourScreenDisabled": "Tregimi i ekrani është i çaktivizuar.",
|
||||
"startLiveStreaming": "Nis transmetim të drejtpërdrejtë",
|
||||
@@ -322,13 +327,15 @@
|
||||
"WaitForHostMsgWOk": "Konferenca <b>{{room}}</b> s’ka nisur ende. Nëse jeni organizatori, atëherë ju lutemi, shtypni OK, që të kryhet mirëfilltësimi. Përndryshe, ju lutemi, pritni që të mbërrijë organizatori.",
|
||||
"WaitingForHostTitle": "Po pritet për organizatorin…",
|
||||
"Yes": "Po",
|
||||
"yourEntireScreen": "Krejt ekranin tuaj"
|
||||
"yourEntireScreen": "Krejt ekranin tuaj",
|
||||
"remoteUserControls": "Kontrolle përdoruesi të largët për {{username}}",
|
||||
"localUserControls": "Kontrolle përdoruesi vendor"
|
||||
},
|
||||
"dialOut": {
|
||||
"statusMessage": "tani është {{status}}"
|
||||
},
|
||||
"documentSharing": {
|
||||
"title": "Dokument i ndarë"
|
||||
"title": "Dokument i Ndarë"
|
||||
},
|
||||
"e2ee": {
|
||||
"labelToolTip": "Komunikimi Audio dhe Video në këtë thirrje fshehtëzohet skaj më skaj"
|
||||
@@ -337,12 +344,26 @@
|
||||
"title": "Trupëzojeni këtë takim"
|
||||
},
|
||||
"virtualBackground": {
|
||||
"title": "Sfonde",
|
||||
"enableBlur": "Aktivizo turbullim",
|
||||
"apply": "Zbatoje",
|
||||
"title": "Sfonde virtualë",
|
||||
"blur": "Turbulloje",
|
||||
"slightBlur": "Turbullim Paksa",
|
||||
"removeBackground": "Hiqe sfondin",
|
||||
"uploadImage": "Ngarkoni figurë",
|
||||
"addBackground": "Shtoni sfond",
|
||||
"pleaseWait": "Ju lutemi, pritni…",
|
||||
"none": "Asnjë"
|
||||
"none": "Asnjë",
|
||||
"uploadedImage": "Ngarkoni figurë {{index}}",
|
||||
"deleteImage": "Fshije figurën",
|
||||
"image1" : "Plazh",
|
||||
"image2" : "Mur i bardhë neutral",
|
||||
"image3" : "Dhomë e bardhë e zbrazët",
|
||||
"image4" : "Llambadar i zi dyshemeje",
|
||||
"image5" : "Mal",
|
||||
"image6" : "Pyll",
|
||||
"image7" : "Ag",
|
||||
"desktopShareError": "S’u krijua dot dhënie desktopi",
|
||||
"desktopShare":"Dhënie desktopi",
|
||||
"webAssemblyWarning": "WebAssembly nuk mbulohet"
|
||||
},
|
||||
"feedback": {
|
||||
"average": "Çka",
|
||||
@@ -351,7 +372,8 @@
|
||||
"good": "E mirë",
|
||||
"rateExperience": "Vlerësoni rastin tuaj",
|
||||
"veryBad": "Shumë e Keqe",
|
||||
"veryGood": "Shumë e Mirë"
|
||||
"veryGood": "Shumë e Mirë",
|
||||
"star": "Yll"
|
||||
},
|
||||
"incomingCall": {
|
||||
"answer": "Përgjigjuni",
|
||||
@@ -368,6 +390,7 @@
|
||||
"country": "Vend",
|
||||
"dialANumber": "Për të marrë pjesë në takimin tuaj, formoni një nga këta numra dhe mandej jepni PIN-in.",
|
||||
"dialInConferenceID": "PIN:",
|
||||
"copyNumber":"Kopjoje numrin",
|
||||
"dialInNotSupported": "Na ndjeni, aktualisht nuk mbulohet formimi i numrave.",
|
||||
"dialInNumber": "Formim numri:",
|
||||
"dialInSummaryError": "Gabim në sjellje hollësish formimi numri tani. Ju lutemi, riprovoni më vonë.",
|
||||
@@ -376,6 +399,7 @@
|
||||
"inviteLiveStream": "Që të shihni transmetimin e drejtpërdrejtë të këtij takimi, klikoni mbi këtë lidhje: {{url}}",
|
||||
"invitePhone": "Nga ana tjetër, që të merrni pjesë me telefon, prekni këtë: {{number}},,{{conferenceID}}#\n",
|
||||
"invitePhoneAlternatives": "Po kërkoni për një tjetër numër?\nShihni numra takimi: {{url}}\n\n\nNëse po provohet gjithashtu numër përmes telefoni dhome, merrni pjesë pa lidhje audioje: {{silentUrl}}",
|
||||
"inviteSipEndpoint": "Për të marrë pjesë duke përdorur adresën SIP, jepni këtë: {{sipUri}}",
|
||||
"inviteURLFirstPartGeneral": "Jeni ftuar të merrni pjesë në një takim.",
|
||||
"inviteURLFirstPartPersonal": "{{name}} po ju fton në një takim.\n",
|
||||
"inviteURLSecondPart": "\nMerrni pjesë te takimi:\n{{url}}\n",
|
||||
@@ -386,6 +410,7 @@
|
||||
"noRoom": "S’u dha dhomë për të cilën të formësohet numri.",
|
||||
"numbers": "Numra Për T’u Përdorur",
|
||||
"password": "$t(lockRoomPasswordUppercase):",
|
||||
"sip": "Adresë SIP",
|
||||
"title": "Ndani me të tjerë",
|
||||
"tooltip": "Ndani me të tjerë lidhje dhe hollësi numrash për këtë takim",
|
||||
"label": "Hollësi numrash"
|
||||
@@ -404,6 +429,7 @@
|
||||
"support": "Asistencë",
|
||||
"supportMsg": "Nëse kjo vazhdon të ndodhë, lidhuni me"
|
||||
},
|
||||
"jitsiHome": "Stemë {{logo}}, lidhje për te Faqja Hyrëse",
|
||||
"keyboardShortcuts": {
|
||||
"focusLocal": "Fokusi te videoja juaj",
|
||||
"focusRemote": "Fokusi te videoja e një personi tjetër",
|
||||
@@ -411,11 +437,12 @@
|
||||
"keyboardShortcuts": "Shkurtore tastiere",
|
||||
"localRecording": "Shfaqni ose fshini kontrolle regjistrimi lokal",
|
||||
"mute": "Mbyllni ose hapni mikrofonin tuaj",
|
||||
"pushToTalk": "Push to talk",
|
||||
"pushToTalk": "Për të folur, shtypeni",
|
||||
"raiseHand": "Ngrini ose ulni dorën",
|
||||
"showSpeakerStats": "Shfaq statistika folësish",
|
||||
"toggleChat": "Hapni ose mbyllni fjalosjen",
|
||||
"toggleFilmstrip": "Shfaqni ose fshihni miniatura video",
|
||||
"toggleParticipantsPane": "Shfaqni ose fshihni kuadratin e pjesëmarrësve",
|
||||
"toggleScreensharing": "Kaloni nga kamera te dhënie ekrani, ose anasjelltas",
|
||||
"toggleShortcuts": "Shfaqni ose fshihni shkurtore tastiere",
|
||||
"videoMute": "Vini në punë ose ndalni kamerën tuaj"
|
||||
@@ -480,7 +507,7 @@
|
||||
"participantStats": "Statistika Pjesëmarrësish",
|
||||
"sessionToken": "Token Sesioni",
|
||||
"start": "Nis Regjistrim",
|
||||
"stop": "Ndal Regjistrim",
|
||||
"stop": "Ndale Regjistrimin",
|
||||
"yes": "Po"
|
||||
},
|
||||
"lockRoomPassword": "fjalëkalim",
|
||||
@@ -494,6 +521,7 @@
|
||||
"focus": "Fokusi te konferenca",
|
||||
"focusFail": "{{component}} jo i passhëm - riprovoni pas {{ms}} sekondash",
|
||||
"grantedTo": "U akorduan të drejta moderatori për {{to}}!",
|
||||
"hostAskedUnmute": "Organizuesi do të donte që të hiqnit heshtimin",
|
||||
"invitedOneMember": "U ftua {{name}}",
|
||||
"invitedThreePlusMembers": "U ftuan {{name}} dhe {{count}} të tjerë",
|
||||
"invitedTwoMembers": "U ftua {{first}} dhe {{second}} tjetër",
|
||||
@@ -509,6 +537,8 @@
|
||||
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) u hoq nga një tjetër pjesëmarrës",
|
||||
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) u caktua nga një tjetër pjesëmarrës",
|
||||
"raisedHand": "{{name}} do të donte të fliste.",
|
||||
"screenShareNoAudio": " Kutizës për ndarje zëri me të tjerët s’i qe vënë shenjë te skena e përzgjedhjes.",
|
||||
"screenShareNoAudioTitle": "Ndarjes së audios s’i qe vënë shenjë",
|
||||
"somebody": "Dikush",
|
||||
"startSilentTitle": "Hytë pa audio!",
|
||||
"startSilentDescription": "Që të aktivizohet audioja, rihyni në takim",
|
||||
@@ -521,7 +551,36 @@
|
||||
"OldElectronAPPTitle": "Cenueshmëri sigurie!",
|
||||
"oldElectronClientDescription1": "Duket se përdorni një version të vjetër të klientit Jitsi Meet, i cili përmban cenueshmëri të ditura sigurie. Ju lutemi, siguroni përditësimin e tij me ",
|
||||
"oldElectronClientDescription2": "montimin tonë më të ri",
|
||||
"oldElectronClientDescription3": " që tani!"
|
||||
"oldElectronClientDescription3": " që tani!",
|
||||
"moderationInEffectDescription": "Ju lutemi, nëse doni të flisni, ngrini dorën",
|
||||
"moderationInEffectCSDescription": "Ju lutemi, nëse doni t’u jepni të tjerëve videon tuaj, ngrini dorën",
|
||||
"moderationInEffectVideoDescription": "Ju lutemi, nëse doni që videoja juaj të jetë e dukshme, ngrini dorën",
|
||||
"moderationInEffectTitle": "Mikrofoni është mbyllur nga moderatori",
|
||||
"moderationInEffectCSTitle": "Ndarje lënde me të tjerë është çaktivizuar nga moderatori",
|
||||
"moderationInEffectVideoTitle": "Vdeoja është mbyllur nga moderatori",
|
||||
"moderationRequestFromModerator": "Organizuesi do të donte që ju të hiqnit heshtimin",
|
||||
"moderationRequestFromParticipant": "Dëshiron të flasë",
|
||||
"moderationStartedTitle": "Filloi moderimi",
|
||||
"moderationStoppedTitle": "Moderimi u ndal",
|
||||
"moderationToggleDescription": "nga {{participantDisplayName}}",
|
||||
"raiseHandAction": "Ngrini dorën",
|
||||
"groupTitle": "Njoftime"
|
||||
},
|
||||
"participantsPane": {
|
||||
"close": "Mbylle",
|
||||
"headings": {
|
||||
"lobby": "Holli ({{count}})",
|
||||
"participantsList": "Pjesëmarrës në takim ({{count}})"
|
||||
},
|
||||
"actions": {
|
||||
"allow": "Lejoji pjesëmarrësit:",
|
||||
"invite": "Të Ftojnë Dikë",
|
||||
"askUnmute": "Të kërkojnë çheshtim",
|
||||
"muteAll": "Të Heshtojnë të tërë",
|
||||
"startModeration": "Të çheshtojnë veten ose të nisin videon",
|
||||
"stopEveryonesVideo": "Të ndalin videon e gjithkujt",
|
||||
"stopVideo": "Të ndalin video"
|
||||
}
|
||||
},
|
||||
"passwordSetRemotely": "caktuar nga një tjetër pjesëmarrës",
|
||||
"passwordDigitsOnly": "Deri në {{number}} shifra",
|
||||
@@ -577,6 +636,7 @@
|
||||
"or": "ose",
|
||||
"premeeting": "Para takimit",
|
||||
"showScreen": "Aktivizoni skenë para takimit",
|
||||
"keyboardShortcuts" : "Aktivizo shkurtore Tastiere",
|
||||
"startWithPhone": "Nise me audio telefoni",
|
||||
"screenSharingError": "Gabim ndarjeje ekrani me të tjerë:",
|
||||
"videoOnlyError": "Gabim video:",
|
||||
@@ -598,6 +658,7 @@
|
||||
"ringing": "Po i bihet ziles…"
|
||||
},
|
||||
"profile": {
|
||||
"avatar": "avatar",
|
||||
"setDisplayNameLabel": "Caktoni emrin tuaj për në ekran",
|
||||
"setEmailInput": "Jepni email",
|
||||
"setEmailLabel": "Caktoni email të gravatarit tuaj",
|
||||
@@ -612,12 +673,15 @@
|
||||
"beta": "BETA",
|
||||
"busy": "Po përpiqemi të lirojmë burime regjistrimi. Ju lutemi, riprovoni pas pak minutash.",
|
||||
"busyTitle": "Krejt regjistruesit janë të zënë",
|
||||
"copyLink": "Kopjoje Lidhjen",
|
||||
"error": "Regjistrimi dështoi. Ju lutemi, riprovoni.",
|
||||
"errorFetchingLink": "Gabim në sjellje lidhje regjistrimi.",
|
||||
"expandedOff": "Regjistrimi u ndal",
|
||||
"expandedOn": "Takimi është aktualisht duke u regjistruar.",
|
||||
"expandedPending": "Po niset regjistrimi…",
|
||||
"failedToStart": "S’u arrit të niset regjistrimi",
|
||||
"fileSharingdescription": "Ndajeni regjistrimin me pjesëmarrësit në takim",
|
||||
"linkGenerated": "Kemi prodhuar një lidhje për te regjistrimi juaj.",
|
||||
"live": "LIVE",
|
||||
"loggedIn": "I futur si {{userName}}",
|
||||
"off": "Regjistrimi u ndal",
|
||||
@@ -632,7 +696,8 @@
|
||||
"signIn": "Hyni",
|
||||
"signOut": "Dilni",
|
||||
"unavailable": "Hëm! {{serviceName}} s’është i passhëm aktualisht. Po punojmë për të zgjidhur problemin. Ju lutemi, riprovoni më vonë.",
|
||||
"unavailableTitle": "Regjistrim jo i passhëm"
|
||||
"unavailableTitle": "Regjistrim jo i passhëm",
|
||||
"uploadToCloud": "Ngarkojeni te reja"
|
||||
},
|
||||
"sectionList": {
|
||||
"pullToRefresh": "Tërhiqeni që të rifreskohet"
|
||||
@@ -645,7 +710,7 @@
|
||||
},
|
||||
"settings": {
|
||||
"calendar": {
|
||||
"about": "Integrimi i me kalendar {{appName}} përdoret për të hyrë me sukses te kalendari juaj, që kështu të mund të lexojë veprimtari të ardhshme.",
|
||||
"about": "Integrimi i me kalendar {{appName}} përdoret për të hyrë me sukses te kalendari juaj, që kështu të mund të lexohen veprimtari të ardhshme.",
|
||||
"disconnect": "Shkëputu",
|
||||
"microsoftSignIn": "Hyni me Microsoft",
|
||||
"signedIn": "Aktualisht duke parë veprimtari kalendari për {{email}}. Klikoni mbi butonin Shkëputu më poshtë që të ndalni parjen e veprimtarive të kalendarit.",
|
||||
@@ -660,6 +725,7 @@
|
||||
"more": "Më tepër",
|
||||
"name": "Emër",
|
||||
"noDevice": "Asnjë",
|
||||
"sameAsSystem": "Njësoj me sistemin ({{label}})",
|
||||
"selectAudioOutput": "Dalje audio",
|
||||
"selectCamera": "Kamerë",
|
||||
"selectMic": "Mikrofon",
|
||||
@@ -686,12 +752,12 @@
|
||||
"profileSection": "Profil",
|
||||
"serverURL": "URL Shërbyesi",
|
||||
"showAdvanced": "Shfaq rregullime të mëtejshme",
|
||||
"startWithAudioMuted": "Fillo me audio të heshtuar",
|
||||
"startWithVideoMuted": "Fillo me video të heshtuar",
|
||||
"startWithAudioMuted": "Fillo me audio të mbyllur",
|
||||
"startWithVideoMuted": "Fillo me video të mbyllur",
|
||||
"version": "Version"
|
||||
},
|
||||
"share": {
|
||||
"dialInfoText": "\n\n=====\n\nThjesht doni t’i bini numrin në telefonin tuaj?\n\n{{defaultDialInNumber}}Klikoni mbi këtë lidhje që të shihni numra telefoni për këtë takim\n{{dialInfoPageUrl}}",
|
||||
"dialInfoText": "\n\n=====\n\nThjesht doni t’i bini numrit në telefonin tuaj?\n\n{{defaultDialInNumber}}Klikoni mbi këtë lidhje, që të shihni numra telefoni për këtë takim\n{{dialInfoPageUrl}}",
|
||||
"mainText": "Që të merrni pjesë në takim, klikoni lidhjen vijuese:\n{{roomUrl}}"
|
||||
},
|
||||
"speaker": "Folës",
|
||||
@@ -705,7 +771,7 @@
|
||||
},
|
||||
"startupoverlay": {
|
||||
"policyText": " ",
|
||||
"genericTitle": "Takimit i duhet të përdorë mikrofonin dhe kamerën tuaj.",
|
||||
"genericTitle": "Takimi lyp përdorimin e mikrofonit dhe kamerës tuaj.",
|
||||
"title": "{{app}} i duhet të përdorë mikrofonin dhe kamerën tuaj."
|
||||
},
|
||||
"suspendedoverlay": {
|
||||
@@ -715,55 +781,61 @@
|
||||
},
|
||||
"toolbar": {
|
||||
"accessibilityLabel": {
|
||||
"audioOnly": "Hap/mbyll vetëm audion",
|
||||
"audioOnly": "Hap/Mbyll vetëm audion",
|
||||
"audioRoute": "Përzgjidhni pajisje zëri",
|
||||
"callQuality": "Administroni cilësi video",
|
||||
"cc": "Shfaq/Fshih titra",
|
||||
"chat": "Shfaq/Fshih dritare fjalosjesh",
|
||||
"chat": "Hap / Mbyll fjalosje",
|
||||
"document": "Shfaq/Fshih dokument të ndarë",
|
||||
"download": "Shkarkoni aplikacionet tona",
|
||||
"embedMeeting": "Trupëzoni takimin",
|
||||
"feedback": "Lini përshtypje",
|
||||
"fullScreen": "Kalo/Dil nga mënyra “Sa krejt ekrani”",
|
||||
"grantModerator": "Akordoji të Drejta Moderatori",
|
||||
"hangup": "Braktiseni thirrjen",
|
||||
"hangup": "Braktiseni takimin",
|
||||
"help": "Ndihmë",
|
||||
"invite": "Ftoni persona",
|
||||
"kick": "Përzini pjesëmarrës",
|
||||
"lobbyButton": "Aktivizo/çaktivizo mënyrën holl",
|
||||
"localRecording": "Shfaq/fshi kontrolle regjistrimi vendor",
|
||||
"lockRoom": "Aktivizoni/Çaktivizoni fjalëkalim takimi",
|
||||
"moreActions": "Shfaq/fshih menunë Më tepër veprime",
|
||||
"moreActionsMenu": "Menu më tepër veprime",
|
||||
"lobbyButton": "Aktivizo/Çaktivizo mënyrën holl",
|
||||
"localRecording": "Shfaq/Fshi kontrolle regjistrimi vendor",
|
||||
"lockRoom": "Aktivizo/Çaktivizo fjalëkalim takimi",
|
||||
"moreActions": "Më tepër veprime",
|
||||
"moreActionsMenu": "Menu “Më tepër veprime”",
|
||||
"moreOptions": "Shfaq më tepër mundësi",
|
||||
"mute": "Mbyllni/Hapni zërin",
|
||||
"mute": "Mbyll/Hap zërin",
|
||||
"muteEveryone": "Heshto gjithkënd",
|
||||
"muteEveryoneElse": "Heshto gjithkënd tjetër",
|
||||
"muteEveryonesVideo": "Çaktivizo kamerën e gjithkujt",
|
||||
"muteEveryoneElsesVideo": "Çaktivizo kamerën e gjithkujt tjetër",
|
||||
"participants": "Pjesëmarrës",
|
||||
"pip": "Kalo/Dil nga mënyra “Picture-in-Picture”",
|
||||
"privateMessage": "Dërgo mesazh privat",
|
||||
"profile": "Përpunoni profilin tuaj",
|
||||
"raiseHand": "Ngrini/ulni dorën",
|
||||
"recording": "Nisni/Ndalni regjistrim",
|
||||
"raiseHand": "Ngrini/Ulni dorën",
|
||||
"recording": "Nis/Ndal regjistrim",
|
||||
"remoteMute": "Heshto pjesëmarrësin",
|
||||
"remoteVideoMute": "Çaktivizo kamerën e pjesëmarrësit",
|
||||
"security": "Mundësi sigurie",
|
||||
"Settings": "Shfaqni/Fshihni rregullime",
|
||||
"sharedvideo": "Shfaqni/Fshini skenë për ndarje videoje YouTube me të tjerët",
|
||||
"Settings": "Shfaq/Fshih rregullime",
|
||||
"shareaudio": "Ndani audio me të tjerë",
|
||||
"sharedvideo": "Shfaq/Fshih skenë për ndarje videoje YouTube me të tjerët",
|
||||
"shareRoom": "Ftoni dikë",
|
||||
"shareYourScreen": "Aktivizoni/Çaktivizoni ndarje ekrani",
|
||||
"shortcuts": "Shfaqni/Fshini shkurtoret",
|
||||
"shareYourScreen": "Nisni / Ndalni dhënien e ekranit tuaj",
|
||||
"shortcuts": "Shfaq/Fshih shkurtoret",
|
||||
"show": "Show on stage",
|
||||
"speakerStats": "Shfaqni statistika folësi",
|
||||
"tileView": "Kaloni/Dilni nga mënyra mozaik",
|
||||
"toggleCamera": "Hapni/Mbyllni kamerën",
|
||||
"toggleFilmstrip": "Toggle filmstrip",
|
||||
"videomute": "Hapni/Mbyllni videon",
|
||||
"selectBackground": "Përzgjidhni Sfond"
|
||||
"tileView": "Kalo/Dil nga mënyra mozaik",
|
||||
"toggleCamera": "Hap/Mbyll kamerën",
|
||||
"toggleFilmstrip": "Shfaq/Fshih shirit filmi",
|
||||
"videomute": "Nis / Ndal kamerën",
|
||||
"videoblur": "Aktivizo/Çaktivizo turbullim videoje",
|
||||
"selectBackground": "Përzgjidhni Sfond",
|
||||
"expand": "Zgjeroje",
|
||||
"collapse": "Tkurre"
|
||||
},
|
||||
"addPeople": "Shtoni persona te thirrja juaj",
|
||||
"audioSettings": "Rregullime audio",
|
||||
"audioSettings": "Rregullime për audion",
|
||||
"videoSettings": "Rregullime për videon",
|
||||
"audioOnlyOff": "Çaktivizo mënyrën “Sasi e ulët të dhënash trafiku”",
|
||||
"audioOnlyOn": "Aktivizo mënyrën “Sasi e ulët të dhënash trafiku”",
|
||||
"audioRoute": "Përzgjidhni pajisje zëri",
|
||||
@@ -778,10 +850,10 @@
|
||||
"embedMeeting": "Trupëzoni takim",
|
||||
"enterFullScreen": "Shiheni sa krejt ekrani",
|
||||
"enterTileView": "Kalo te pamja me kuadrate",
|
||||
"exitFullScreen": "Dilni nga mënyra sa krejt ekrani",
|
||||
"exitFullScreen": "Dil nga mënyra sa krejt ekrani",
|
||||
"exitTileView": "Dil nga pamja me kuadrate",
|
||||
"feedback": "Lini përshtypje",
|
||||
"hangup": "Dilni",
|
||||
"hangup": "Braktisni takimin",
|
||||
"help": "Ndihmë",
|
||||
"invite": "Ftoni persona",
|
||||
"lobbyButtonDisable": "Çaktivizo mënyrën holl",
|
||||
@@ -802,6 +874,7 @@
|
||||
"noisyAudioInputTitle": "Mikrofoni juaj duket të jetë i zhurmshëm!",
|
||||
"noisyAudioInputDesc": "Dëgjohet sikur mikrofoni juaj prodhon zhurmë, ju lutemi, shihni mundësinë e heshtimit të tij, ose të ndërrimit të pajisjes.",
|
||||
"openChat": "Hapni fjalosje",
|
||||
"participants": "Pjesëmarrës",
|
||||
"pip": "Kalo nën mënyrën “Picture-in-Picture”",
|
||||
"privateMessage": "Dërgo mesazh privat",
|
||||
"profile": "Përpunoni profilin tuaj",
|
||||
@@ -809,7 +882,8 @@
|
||||
"raiseYourHand": "Ngrini dorën",
|
||||
"security": "Mundësi sigurie",
|
||||
"Settings": "Rregullime",
|
||||
"sharedvideo": "Ndani një video YouTube",
|
||||
"shareaudio": "Ndani audio me të tjerë",
|
||||
"sharedvideo": "Ndani video me të tjerë",
|
||||
"shareRoom": "Ftoni dikë",
|
||||
"shortcuts": "Shihni shkurtore",
|
||||
"speakerStats": "Statistika folësi",
|
||||
@@ -817,12 +891,11 @@
|
||||
"startSubtitles": "Nis titra",
|
||||
"stopScreenSharing": "Ndale tregimin e ekranit",
|
||||
"stopSubtitles": "Ndali titrat",
|
||||
"stopSharedVideo": "Ndale videon YouTube",
|
||||
"stopSharedVideo": "Ndale videon",
|
||||
"talkWhileMutedPopup": "Po provoni të flisni? Jeni i heshtuar.",
|
||||
"tileViewToggle": "Kaloni/Dilni nga mënyra mozaik",
|
||||
"toggleCamera": "Hapni/Mbyllni kamerën",
|
||||
"videomute": "Nise / Ndale kamerën",
|
||||
"videoSettings": "Rregullime për videon",
|
||||
"selectBackground": "Përzgjidhni sfond"
|
||||
},
|
||||
"transcribing": {
|
||||
@@ -831,7 +904,7 @@
|
||||
"expandedLabel": "Transkriptimi aktualisht është aktiv",
|
||||
"failedToStart": "S’u arrit të nisej transkriptim",
|
||||
"labelToolTip": "Takimit po i bëhet transkriptim",
|
||||
"off": "Transkriptimi i ndal",
|
||||
"off": "Transkriptimi u ndal",
|
||||
"pending": "Po përgatitet të transkriptohet takimi…",
|
||||
"start": "Fillo shfaqje titrash",
|
||||
"stop": "Ndal shfaqje titrash",
|
||||
@@ -849,6 +922,7 @@
|
||||
"react-nativeGrantPermissions": "Kur shfletuesi juaj të kërkojë leje, përzgjidhni <b><i>Lejoje</i></b>.",
|
||||
"safariGrantPermissions": "Kur shfletuesi juaj të kërkojë leje, përzgjidhni <b><i>OK</i></b>."
|
||||
},
|
||||
"volumeSlider": "Rrëshqitës volumi",
|
||||
"videoSIPGW": {
|
||||
"busy": "Po përpiqemi të lirojmë burime. Ju lutemi, riprovoni pas pak minutash.",
|
||||
"busyTitle": "Shërbimi i dhomës aktualisht është i zënë",
|
||||
@@ -888,11 +962,12 @@
|
||||
"mute": "Pjesëmarrësi është heshtuar",
|
||||
"muted": "I heshtuar",
|
||||
"videoMuted": "Kamera e çaktivizuar",
|
||||
"remoteControl": "Nis / Ndal kontroll së largëti",
|
||||
"remoteControl": "Nisni / Ndalni kontroll së largëti",
|
||||
"show": "Show on stage",
|
||||
"videomute": "Pjesëmarrësi ka ndalur kamerën"
|
||||
},
|
||||
"welcomepage": {
|
||||
"addMeetingName": "Shtoni emër Takimi",
|
||||
"accessibilityLabel": {
|
||||
"join": "Prekeni që të hyni",
|
||||
"roomname": "Jepni emër dhome"
|
||||
@@ -911,12 +986,15 @@
|
||||
"goSmall": "SHKO",
|
||||
"headerTitle": "Jitsi Meet",
|
||||
"headerSubtitle": "Takime me siguri dhe me cilësi të lartë",
|
||||
"info": "Dial-in info",
|
||||
"join": "CREATE / JOIN",
|
||||
"info": "Hollësi për dial-in",
|
||||
"join": "KRIJONI / MERRNI PJESË",
|
||||
"jitsiOnMobile": "Jitsi në celular – Shkarkoni aplikacione tona dhe nisni një takim prej ngado",
|
||||
"mobileDownLoadLinkIos": "Shkarkoni aplikacionin për celular me iOS",
|
||||
"mobileDownLoadLinkAndroid": "Shkarkoni aplikacionin për celular me Android",
|
||||
"mobileDownLoadLinkFDroid": "Shkarkoni aplikacionin për celular me F-Droid",
|
||||
"moderatedMessage": "Ose <a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">rezervoni një URL takimi</a> paraprakisht, kur jeni i vetmi moderator.",
|
||||
"privacy": "Privatësi",
|
||||
"recentList": "Recent",
|
||||
"recentList": "Së fundi",
|
||||
"recentListDelete": "Fshije zërin",
|
||||
"recentListEmpty": "Lista juaj për “së fundi” aktualisht është e zbrazët. Bisedoni me ekipin tuaj dhe do të gjeni këtu krejt takimet tuaj së fundi.",
|
||||
"reducedUIText": "Mirë se vini në {{app}}!",
|
||||
@@ -926,7 +1004,15 @@
|
||||
"sendFeedback": "Dërgoni përshtypje",
|
||||
"startMeeting": "Nisni takim",
|
||||
"terms": "Kushte",
|
||||
"title": "Konferenca video të parrezik, me të gjitha veçoritë dhe plotësisht të lira"
|
||||
"title": "Konferenca video të parrezik, me të gjitha veçoritë dhe plotësisht të lira",
|
||||
"logo":{
|
||||
"calendar":"Stemë Calendar-i",
|
||||
"microsoftLogo":"Stemë Microsoft-i",
|
||||
"logoDeepLinking":"Stemë Jitsi Meet",
|
||||
"desktopPreviewThumbnail":"Miniaturë paraparjeje në desktop",
|
||||
"googleLogo":"Stemë Google",
|
||||
"policyLogo":"Stemë Policy"
|
||||
}
|
||||
},
|
||||
"lonelyMeetingExperience": {
|
||||
"button": "Ftoni të tjerë",
|
||||
@@ -936,6 +1022,8 @@
|
||||
"header": "Qendër ndihme"
|
||||
},
|
||||
"lobby": {
|
||||
"admit": "Pranoje",
|
||||
"admitAll": "Pranoji të tërë",
|
||||
"knockingParticipantList": "Listë pjesëmarrësish me trokitje",
|
||||
"allow": "Lejoje",
|
||||
"backToKnockModeButton": "Pa fjalëkalim, kërkoni pjesëmarrje",
|
||||
|
||||
@@ -574,7 +574,7 @@
|
||||
"setDisplayNameLabel": "设定您的显示名称",
|
||||
"setEmailInput": "输入您的邮箱",
|
||||
"setEmailLabel": "设置您的个人全球统一标识邮箱",
|
||||
"title": "简介"
|
||||
"title": "个人信息"
|
||||
},
|
||||
"raisedHand": "请求发言",
|
||||
"recording": {
|
||||
@@ -621,7 +621,7 @@
|
||||
"disconnect": "断开连接",
|
||||
"microsoftSignIn": "Microsoft帐号登录",
|
||||
"signedIn": "目前通过 {{email}} 获取日历事件。点击下方断开连接按钮停止访问。",
|
||||
"title": "标题"
|
||||
"title": "日历集成"
|
||||
},
|
||||
"devices": "设备",
|
||||
"followMe": "分机随行",
|
||||
@@ -638,7 +638,7 @@
|
||||
"speakers": "发言人",
|
||||
"startAudioMuted": "所有人开始时静音",
|
||||
"startVideoMuted": "所有人开始时隐藏视频画面",
|
||||
"title": "抬头"
|
||||
"title": "设置"
|
||||
},
|
||||
"settingsView": {
|
||||
"advanced": "高级",
|
||||
|
||||
@@ -70,12 +70,17 @@
|
||||
},
|
||||
"privateNotice": "私人訊息傳送至 {{recipient}}",
|
||||
"title": "對話",
|
||||
"you": "您"
|
||||
"you": "您",
|
||||
"message": "訊息",
|
||||
"messageAccessibleTitle": "{{user}} 說:",
|
||||
"messageAccessibleTitleMe": "您說:",
|
||||
"smileysPanel": "表情符號面板"
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
"installExtensionText": "安裝適用於 Google 行事曆及 Office 365 整合的擴充功能",
|
||||
"buttonText": "安裝 Chrome 擴充功能",
|
||||
"dontShowAgain": "不再顯示"
|
||||
"dontShowAgain": "不再顯示",
|
||||
"close": "關閉"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
"joiningRoom": "正在將您連接至您的會議..."
|
||||
@@ -204,10 +209,13 @@
|
||||
"e2eeLabel": "啟用端對端加密",
|
||||
"e2eeWarning": "警告:看來不是每位此會議的參與者都有啟用端對端加密,如果您啟用了,他們可能無法看/聽到您。",
|
||||
"enterDisplayName": "請在此輸入您自己的名字",
|
||||
"enterDisplayNameToJoin": "請輸入您的名字以加入",
|
||||
"embedMeeting": "嵌入會議",
|
||||
"error": "錯誤",
|
||||
"gracefulShutdown": "我們的服務目前關閉維護中,請稍後再試。",
|
||||
"grantModeratorDialog": "您確定要使此參與者成為管理員嗎?",
|
||||
"grantModeratorTitle": "授予管理員",
|
||||
"hideShareAudioHelper": "不再顯示",
|
||||
"IamHost": "我是主辦人",
|
||||
"incorrectRoomLockPassword": "密碼不符",
|
||||
"incorrectPassword": "錯誤的用戶名稱或密碼",
|
||||
@@ -260,11 +268,14 @@
|
||||
"passwordNotSupported": "尚未支援設定會議密碼 $t(lockRoomPassword)。",
|
||||
"passwordNotSupportedTitle": "尚未支援 $t(lockRoomPasswordUppercase)",
|
||||
"passwordRequired": "必須要有 $t(lockRoomPasswordUppercase)",
|
||||
"permissionErrorTitle": "需要權限",
|
||||
"permissionCameraRequiredError": "參與視訊會議需要存取攝影機的權限。請在設定中授權",
|
||||
"permissionMicRequiredError": "參與音訊會議需要存取麥克風的權限。請在設定中授權",
|
||||
"popupError": "您的瀏覽器在此網站上阻擋彈出視窗。請在瀏覽器的安全設定中啟用並再試一次。",
|
||||
"popupErrorTitle": "彈出視窗遭到阻擋",
|
||||
"readMore": "閱讀更多",
|
||||
"readMore": "更多",
|
||||
"recording": "錄影中",
|
||||
"recordingDisabledForGuestTooltip": "訪客無法啟動錄影。",
|
||||
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "正在直播時無法使用",
|
||||
"recordingDisabledTooltip": "啟動錄影已停用。",
|
||||
"rejoinNow": "立即重新加入",
|
||||
"remoteControlAllowedMessage": "{{user}} 接受您進行遠端控制的請求!",
|
||||
@@ -293,6 +304,13 @@
|
||||
"sessTerminated": "通話已經終止",
|
||||
"sessionRestarted": "通話被橋接器重新啟動",
|
||||
"Share": "分享",
|
||||
"shareAudio": "繼續",
|
||||
"shareAudioTitle" : "如何分享音訊",
|
||||
"shareAudioWarningTitle": "您必須先停止分享畫面才能分享音訊",
|
||||
"shareAudioWarningH1": "如果您只要分享音訊:",
|
||||
"shareAudioWarningD1": "您必須先停止分享畫面才能分享音訊。",
|
||||
"shareAudioWarningD2": "您必須重新啟動畫面分享並勾選 \"分享音訊\" 選項。",
|
||||
"shareMediaWarningGenericH2": "如果您想要同時分享畫面跟音訊",
|
||||
"shareVideoLinkError": "請提供正確的 YouTube 連結。",
|
||||
"shareVideoTitle": "分享影像",
|
||||
"shareYourScreen": "分享自己的螢幕",
|
||||
@@ -300,6 +318,10 @@
|
||||
"startLiveStreaming": "啟動直播串流",
|
||||
"startRecording": "啟動錄影作業",
|
||||
"startRemoteControlErrorMessage": "嘗試啟動遠端控制階段時發生錯誤!",
|
||||
"shareScreenWarningTitle": "您必須先停止分享音訊才能分享畫面",
|
||||
"shareScreenWarningH1": "如果您只要分享畫面:",
|
||||
"shareScreenWarningD1": "您必須先停止分享音訊才能分享畫面。",
|
||||
"shareScreenWarningD2": "您必須先停止分享音訊,啟動畫面分享,然後勾選 \"分享音訊\" 選項。",
|
||||
"stopLiveStreaming": "停止直播串流",
|
||||
"stopRecording": "停止錄影",
|
||||
"stopRecordingWarning": "確定要停止錄影嗎?",
|
||||
@@ -316,11 +338,16 @@
|
||||
"userIdentifier": "使用者標識符",
|
||||
"userPassword": "用戶密碼",
|
||||
"videoLink": "影片連結",
|
||||
"viewUpgradeOptions": "查看升級方案",
|
||||
"viewUpgradeOptionsContent": "若要無限制地使用進階版功能,像是錄影、逐字稿、RTMP 串流...等,您必須升級您的方案。",
|
||||
"viewUpgradeOptionsTitle": "您找到了進階版功能!",
|
||||
"WaitForHostMsg": "此會議 <b>{{room}}</b> 尚未啟動。如果您是會議主人,請進行認證;否則,請等待會議主人到達。",
|
||||
"WaitForHostMsgWOk": "此會議 <b>{{room}}</b> 尚未啟動。如果您是會議主人,請按 [確定] 進行認證;否則,請等待會議主人到達。",
|
||||
"WaitingForHost": "等侯主辦人...",
|
||||
"Yes": "是的",
|
||||
"yourEntireScreen": "您的畫面"
|
||||
"yourEntireScreen": "您的畫面",
|
||||
"remoteUserControls": "{{username}} 的遠端使用者控制",
|
||||
"localUserControls": "本機使用者控制"
|
||||
},
|
||||
"dialOut": {
|
||||
"statusMessage": "現在狀態為 {{status}}"
|
||||
@@ -341,8 +368,20 @@
|
||||
"slightBlur": "稍微模糊",
|
||||
"removeBackground": "移除背景",
|
||||
"addBackground": "新增背景",
|
||||
"pleaseWait": "請稍候...",
|
||||
"none": "無",
|
||||
"desktopShareError": "無法建立桌面分享"
|
||||
"uploadedImage": "上傳圖片 {{index}}",
|
||||
"deleteImage": "刪除圖片",
|
||||
"image1" : "海灘",
|
||||
"image2" : "牆壁 (白)",
|
||||
"image3" : "空房間 (白)",
|
||||
"image4" : "落地燈 (黑)",
|
||||
"image5" : "山岳",
|
||||
"image6" : "森林",
|
||||
"image7" : "日出",
|
||||
"desktopShareError": "無法建立桌面分享",
|
||||
"desktopShare":"桌面分享",
|
||||
"webAssemblyWarning": "不支援 WebAssembly"
|
||||
},
|
||||
"feedback": {
|
||||
"average": "普通",
|
||||
@@ -351,7 +390,8 @@
|
||||
"good": "很好",
|
||||
"rateExperience": "對本次會議的體驗評分",
|
||||
"veryBad": "極差",
|
||||
"veryGood": "極好"
|
||||
"veryGood": "極好",
|
||||
"star": "星級"
|
||||
},
|
||||
"incomingCall": {
|
||||
"answer": "接通",
|
||||
@@ -366,8 +406,9 @@
|
||||
"cancelPassword": "取消 $t(lockRoomPassword)",
|
||||
"conferenceURL": "連結:",
|
||||
"country": "國家",
|
||||
"dialANumber": "要參加您的會議,撥打以下號碼其中之一,然後輸入 PIN 碼。",
|
||||
"dialANumber": "要參加您的會議,撥打以下其中一支號碼,然後輸入 PIN 碼。",
|
||||
"dialInConferenceID": "PIN 號碼:",
|
||||
"copyNumber":"複製號碼",
|
||||
"dialInNotSupported": "抱歉,目前不支援電話撥入。",
|
||||
"dialInNumber": "撥入:",
|
||||
"dialInSummaryError": "目前解析撥入資訊錯誤。請稍後再試一次。",
|
||||
@@ -387,6 +428,7 @@
|
||||
"noRoom": "沒有會議室指定要撥入。",
|
||||
"numbers": "撥入號碼",
|
||||
"password": "$t(lockRoomPasswordUppercase):",
|
||||
"sip": "SIP 位址",
|
||||
"title": "分享",
|
||||
"tooltip": "顯示此會議的連結及電話撥入號碼",
|
||||
"label": "撥入資訊"
|
||||
@@ -405,6 +447,7 @@
|
||||
"support": "支援",
|
||||
"supportMsg": "如果這種狀況持續發生,請聯絡"
|
||||
},
|
||||
"jitsiHome": "{{logo}} 商標,首頁連結",
|
||||
"keyboardShortcuts": {
|
||||
"focusLocal": "聚焦於自己的影像",
|
||||
"focusRemote": "聚焦於另一人的影像",
|
||||
@@ -495,7 +538,8 @@
|
||||
"disconnected": "已經中斷連接",
|
||||
"focus": "會議焦點",
|
||||
"focusFail": "{{component}} 無法使用 - 請在 {{ms}} 秒後重試",
|
||||
"grantedTo": "主持人權限已授予 {{to}} !",
|
||||
"grantedTo": "主持人權限已授予 {{to}}!",
|
||||
"hostAskedUnmute": "主持人希望您能解除靜音",
|
||||
"invitedOneMember": "{{name}} 已受邀請",
|
||||
"invitedThreePlusMembers": "{{name}} 及 {{count}} 位人員已受邀請",
|
||||
"invitedTwoMembers": "{{first}} 及 {{second}} 已受邀請",
|
||||
@@ -516,7 +560,7 @@
|
||||
"somebody": "某人",
|
||||
"startSilentTitle": "您加入了會議而無聲音輸出!",
|
||||
"startSilentDescription": "重新加入會議以啟用語音",
|
||||
"suboptimalBrowserWarning": "恐怕您本次會議體驗並不太好,我們會想辦法改進的。但在此之前,敬請使用 <a href='{{recommendedBrowserPageLink}}' target='_blank'>完全支援的瀏覽器</a> 。",
|
||||
"suboptimalBrowserWarning": "恐怕您本次會議體驗並不太好,我們會想辦法改進的。但在此之前,敬請使用<a href='{{recommendedBrowserPageLink}}' target='_blank'>完全支援的瀏覽器</a> 。",
|
||||
"suboptimalExperienceTitle": "瀏覽器警告",
|
||||
"unmute": "取消靜音",
|
||||
"newDeviceCameraTitle": "偵測到新的攝影裝置",
|
||||
@@ -525,16 +569,34 @@
|
||||
"OldElectronAPPTitle": "安全漏洞!",
|
||||
"oldElectronClientDescription1": "您似乎正在使用 Jitsi Meet 客戶端的舊版本,其有已知的安全漏洞。請更新到",
|
||||
"oldElectronClientDescription2": "最新版本",
|
||||
"oldElectronClientDescription3": "!"
|
||||
"oldElectronClientDescription3": "!",
|
||||
"moderationInEffectDescription": "若要說話,請舉手",
|
||||
"moderationInEffectCSDescription": "若要分享視訊,請舉手",
|
||||
"moderationInEffectVideoDescription": "若要使視訊可見,請舉手",
|
||||
"moderationInEffectTitle": "麥克風已被管理員靜音",
|
||||
"moderationInEffectCSTitle": "內容分享已被管理員停用",
|
||||
"moderationInEffectVideoTitle": "視訊已被管理員靜音",
|
||||
"moderationRequestFromModerator": "主持人希望您能解除靜音",
|
||||
"moderationRequestFromParticipant": "想要講話",
|
||||
"moderationStartedTitle": "開始管理",
|
||||
"moderationStoppedTitle": "停止管理",
|
||||
"moderationToggleDescription": "由 {{participantDisplayName}}",
|
||||
"raiseHandAction": "舉手",
|
||||
"groupTitle": "通知"
|
||||
},
|
||||
"participantsPane": {
|
||||
"close": "關閉",
|
||||
"headings": {
|
||||
"lobby": "大廳 ({{count}})",
|
||||
"participantsList": "會議參與者 ({{count}})"
|
||||
},
|
||||
"actions": {
|
||||
"allow": "允許參與者能夠:",
|
||||
"invite": "邀請他人",
|
||||
"askUnmute": "要求解除靜音",
|
||||
"muteAll": "靜音所有人",
|
||||
"startModeration": "將他們解除靜音或開始視訊",
|
||||
"stopEveryonesVideo": "停止所有人的視訊",
|
||||
"stopVideo": "停止影片"
|
||||
}
|
||||
},
|
||||
@@ -592,6 +654,7 @@
|
||||
"or": "或",
|
||||
"premeeting": "會前",
|
||||
"showScreen": "啟用會前畫面",
|
||||
"keyboardShortcuts" : "啟用鍵盤快捷鍵",
|
||||
"startWithPhone": "使用手機音訊裝置開始",
|
||||
"screenSharingError": "畫面分享錯誤:",
|
||||
"videoOnlyError": "視訊錯誤:",
|
||||
@@ -613,6 +676,7 @@
|
||||
"ringing": "鈴鈴鈴..."
|
||||
},
|
||||
"profile": {
|
||||
"avatar": "頭像",
|
||||
"setDisplayNameLabel": "設定您的顯示名稱",
|
||||
"setEmailInput": "輸入您的電子信箱",
|
||||
"setEmailLabel": "設定您的 Gravatar 電子信箱",
|
||||
@@ -627,12 +691,15 @@
|
||||
"beta": "BETA",
|
||||
"busy": "我們正在釋放錄影資源。請過幾分鐘後再試。",
|
||||
"busyTitle": "全部錄影目前忙碌",
|
||||
"copyLink": "複製連結",
|
||||
"error": "錄影失敗。請重試。",
|
||||
"errorFetchingLink": "取得錄影檔連結時發生錯誤。",
|
||||
"expandedOff": "錄影已經停止",
|
||||
"expandedOn": "此會議目前正在錄影。",
|
||||
"expandedPending": "錄影正在啟動...",
|
||||
"failedToStart": "錄影啟動失敗",
|
||||
"fileSharingdescription": "分享錄影給會議參與者",
|
||||
"linkGenerated": "我們建立了您的錄影檔的連結。",
|
||||
"live": "直播",
|
||||
"loggedIn": "以 {{userName}} 登入",
|
||||
"off": "錄影已經停止",
|
||||
@@ -647,7 +714,8 @@
|
||||
"signIn": "登入",
|
||||
"signOut": "登出",
|
||||
"unavailable": "喔哦!{{serviceName}} 目前無法使用。我們正在解決此問題,請稍後再試。",
|
||||
"unavailableTitle": "錄影無法使用"
|
||||
"unavailableTitle": "錄影無法使用",
|
||||
"uploadToCloud": "上傳至雲端"
|
||||
},
|
||||
"sectionList": {
|
||||
"pullToRefresh": "拉下以重新整理"
|
||||
@@ -666,8 +734,12 @@
|
||||
"signedIn": "目前能夠存取 {{email}} 的行事曆事件。點按下方取消連接鈕可以停止存取行事曆事件。",
|
||||
"title": "行事曆"
|
||||
},
|
||||
"desktopShareFramerate": "桌面分享幀數",
|
||||
"desktopShareWarning": "您必須重新啟動桌面分享以套用新的設定。",
|
||||
"desktopShareHighFpsWarning": "較高的桌面分享幀數可能會影響您的頻寬。您必須重新啟動桌面分享以套用新的設定。",
|
||||
"devices": "裝置",
|
||||
"followMe": "全部人跟隨我",
|
||||
"framesPerSecond": "幀數",
|
||||
"language": "語言",
|
||||
"loggedIn": "以 {{name}} 登入",
|
||||
"microphones": "麥克風",
|
||||
@@ -736,6 +808,7 @@
|
||||
"callQuality": "管理影像品質",
|
||||
"cc": "切換字幕",
|
||||
"chat": "切換聊天視窗",
|
||||
"clap": "鼓掌",
|
||||
"document": "切換分享文件",
|
||||
"download": "下載我們的應用程式",
|
||||
"embedMeeting": "嵌入會議",
|
||||
@@ -745,7 +818,9 @@
|
||||
"hangup": "離開通話",
|
||||
"help": "說明",
|
||||
"invite": "邀請人員",
|
||||
"joy": "笑到流淚",
|
||||
"kick": "踢出參與者",
|
||||
"like": "比讚",
|
||||
"lobbyButton": "啟用/停用大廳模式",
|
||||
"localRecording": "切換本地端錄影控制",
|
||||
"lockRoom": "切換會議密碼",
|
||||
@@ -758,10 +833,12 @@
|
||||
"muteEveryonesVideo": "停用所有人的攝影機",
|
||||
"muteEveryoneElsesVideo": "停用其他人的攝影機",
|
||||
"participants": "參與者",
|
||||
"party": "拉炮",
|
||||
"pip": "切換子母畫面模式",
|
||||
"privateMessage": "發送私人訊息",
|
||||
"profile": "編輯您的簡介",
|
||||
"raiseHand": "切換舉手",
|
||||
"reactionsMenu": "切換反應選單",
|
||||
"recording": "切換錄影",
|
||||
"remoteMute": "靜音參與者",
|
||||
"remoteVideoMute": "停用參與者的攝影機",
|
||||
@@ -773,22 +850,30 @@
|
||||
"shareYourScreen": "切換螢幕分享",
|
||||
"shortcuts": "切換快捷鍵",
|
||||
"show": "顯示在台上",
|
||||
"smile": "微笑",
|
||||
"speakerStats": "切換聲音輸出統計",
|
||||
"surprised": "驚訝",
|
||||
"tileView": "切換格狀檢視",
|
||||
"toggleCamera": "切換攝影機",
|
||||
"toggleFilmstrip": "切換幻燈片",
|
||||
"videomute": "切換影片靜音",
|
||||
"selectBackground": "選擇背景"
|
||||
"videomute": "啟用/停用攝影機",
|
||||
"videoblur": "切換畫面模糊",
|
||||
"selectBackground": "選擇背景",
|
||||
"expand": "展開",
|
||||
"collapse": "收回"
|
||||
},
|
||||
"addPeople": "新增人員到您的通話中",
|
||||
"audioSettings": "音訊設定",
|
||||
"videoSettings": "視訊設定",
|
||||
"audioOnlyOff": "停用低頻寬模式",
|
||||
"audioOnlyOn": "啟用低頻寬模式",
|
||||
"audioRoute": "選擇音訊裝置",
|
||||
"authenticate": "認證",
|
||||
"callQuality": "管理影像品質",
|
||||
"chat": "開啟/關閉聊天欄",
|
||||
"clap": "鼓掌",
|
||||
"closeChat": "關閉聊天欄",
|
||||
"closeReactionsMenu": "關閉反應選單",
|
||||
"documentClose": "關閉分享檔案欄",
|
||||
"documentOpen": "開啟分享檔案欄",
|
||||
"download": "下載我們的應用程式",
|
||||
@@ -802,6 +887,8 @@
|
||||
"hangup": "離開",
|
||||
"help": "說明",
|
||||
"invite": "邀請人員",
|
||||
"joy": "高興",
|
||||
"like": "比讚",
|
||||
"lobbyButtonDisable": "停用大廳模式",
|
||||
"lobbyButtonEnable": "啟用大廳模式",
|
||||
"login": "登入",
|
||||
@@ -819,30 +906,40 @@
|
||||
"noAudioSignalDialInLinkDesc": "撥入號碼",
|
||||
"noisyAudioInputTitle": "您的麥克風疑似有雜音!",
|
||||
"noisyAudioInputDesc": "噪音聽起來是從您的麥克風傳來的,請考慮靜音或更換裝置。",
|
||||
"openChat": "開啟交談",
|
||||
"openChat": "開啟聊天欄",
|
||||
"openReactionsMenu": "開啟反應選單",
|
||||
"participants": "參與者",
|
||||
"party": "慶祝",
|
||||
"pip": "進入子母畫面模式",
|
||||
"privateMessage": "發送私人訊息",
|
||||
"profile": "編輯您的簡介",
|
||||
"raiseHand": "舉手/取消請求發言",
|
||||
"raiseYourHand": "舉手發言",
|
||||
"reactionClap": "傳送鼓掌反應",
|
||||
"reactionJoy": "傳送高興反應",
|
||||
"reactionLike": "傳送比讚反應",
|
||||
"reactionParty": "傳送拉炮反應",
|
||||
"reactionSmile": "傳送微笑反應",
|
||||
"reactionSurprised": "傳送驚訝反應",
|
||||
"security": "安全性選項",
|
||||
"Settings": "設定",
|
||||
"shareaudio": "分享音訊",
|
||||
"sharedvideo": "分享影片",
|
||||
"shareRoom": "邀請他人",
|
||||
"shortcuts": "查看快捷鍵",
|
||||
"smile": "微笑",
|
||||
"speakerStats": "聲音輸出數據",
|
||||
"startScreenSharing": "啟動螢幕分享",
|
||||
"startScreenSharing": "啟動畫面分享",
|
||||
"startSubtitles": "啟動字幕",
|
||||
"stopScreenSharing": "停止螢幕分享",
|
||||
"stopAudioSharing": "停止分享音訊",
|
||||
"stopScreenSharing": "停止分享畫面",
|
||||
"stopSubtitles": "停止字幕",
|
||||
"stopSharedVideo": "停止影片",
|
||||
"surprised": "驚訝",
|
||||
"talkWhileMutedPopup": "您要發言嗎?目前您處於靜音。",
|
||||
"tileViewToggle": "切換格狀檢視",
|
||||
"toggleCamera": "切換攝影機",
|
||||
"videomute": "啟動/停止攝影機",
|
||||
"videoSettings": "影像設定",
|
||||
"selectBackground": "選擇背景"
|
||||
},
|
||||
"transcribing": {
|
||||
@@ -869,6 +966,7 @@
|
||||
"react-nativeGrantPermissions": "當瀏覽器要求權限時,請選擇<b><i>允許</i></b>。",
|
||||
"safariGrantPermissions": "當瀏覽器要求權限時,請選擇<b><i>確定</i></b>。"
|
||||
},
|
||||
"volumeSlider": "音量滑條",
|
||||
"videoSIPGW": {
|
||||
"busy": "我們正在釋放資源。請過幾分鐘後再試。",
|
||||
"busyTitle": "會議室服務目前忙碌中",
|
||||
@@ -913,6 +1011,7 @@
|
||||
"videomute": "參與者已經停止攝影裝置"
|
||||
},
|
||||
"welcomepage": {
|
||||
"addMeetingName": "新增會議名稱",
|
||||
"accessibilityLabel": {
|
||||
"join": "點擊即可加入",
|
||||
"roomname": "輸入會議室名稱"
|
||||
@@ -934,6 +1033,9 @@
|
||||
"info": "資訊",
|
||||
"join": "建立 / 加入",
|
||||
"jitsiOnMobile": "Jitsi 手機應用程式 – 下載應用程式,不論何時何地都能發起會議",
|
||||
"mobileDownLoadLinkIos": "下載 iOS 版本的手機應用程式",
|
||||
"mobileDownLoadLinkAndroid": "下載 Android 版本的手機應用程式",
|
||||
"mobileDownLoadLinkFDroid": "前往 F-Droid 下載 Android 版本的手機應用程式",
|
||||
"moderatedMessage": "或 <a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">預先建立會議</a>,您將成為唯一一個管理員。",
|
||||
"privacy": "隱私",
|
||||
"recentList": "最近使用",
|
||||
@@ -946,7 +1048,15 @@
|
||||
"sendFeedback": "傳送回饋",
|
||||
"startMeeting": "開始會議",
|
||||
"terms": "條款",
|
||||
"title": "安全、功能齊全、完全免費的視訊會議"
|
||||
"title": "安全、功能齊全、完全免費的視訊會議",
|
||||
"logo":{
|
||||
"calendar":"行事曆圖示",
|
||||
"microsoftLogo":"Microsoft 商標",
|
||||
"logoDeepLinking":"Jitsi meet 商標",
|
||||
"desktopPreviewThumbnail":"桌面分享縮圖",
|
||||
"googleLogo":"Google 商標",
|
||||
"policyLogo":"政策圖示"
|
||||
}
|
||||
},
|
||||
"lonelyMeetingExperience": {
|
||||
"button": "邀請其他人",
|
||||
|
||||
@@ -215,6 +215,7 @@
|
||||
"gracefulShutdown": "Our service is currently down for maintenance. Please try again later.",
|
||||
"grantModeratorDialog": "Are you sure you want to make this participant a moderator?",
|
||||
"grantModeratorTitle": "Grant moderator",
|
||||
"hideShareAudioHelper": "Don't show this dialog again",
|
||||
"IamHost": "I am the host",
|
||||
"incorrectRoomLockPassword": "Incorrect password",
|
||||
"incorrectPassword": "Incorrect username or password",
|
||||
@@ -257,16 +258,21 @@
|
||||
"muteParticipantBody": "You won't be able to unmute them, but they can unmute themselves at any time.",
|
||||
"muteParticipantButton": "Mute",
|
||||
"muteParticipantDialog": "Are you sure you want to mute this participant? You won't be able to unmute them, but they can unmute themselves at any time.",
|
||||
"muteParticipantsVideoDialog": "Are you sure you want to turn off this participant's camera? You won't be able to turn the camera back on, but they can turn it back on at any time.",
|
||||
"muteParticipantTitle": "Mute this participant?",
|
||||
"muteParticipantsVideoButton": "Disable camera",
|
||||
"muteParticipantsVideoTitle": "Disable camera of this participant?",
|
||||
"muteParticipantsVideoBody": "You won't be able to turn the camera back on, but they can turn it back on at any time.",
|
||||
"noDropboxToken": "No valid Dropbox token",
|
||||
"Ok": "OK",
|
||||
"password": "Password",
|
||||
"passwordLabel": "The meeting has been locked by a participant. Please enter the $t(lockRoomPassword) to join.",
|
||||
"passwordNotSupported": "Setting a meeting $t(lockRoomPassword) is not supported.",
|
||||
"passwordNotSupportedTitle": "$t(lockRoomPasswordUppercase) not supported",
|
||||
"passwordRequired": "$t(lockRoomPasswordUppercase) required",
|
||||
"permissionErrorTitle": "Permission required",
|
||||
"permissionCameraRequiredError": "Camera permission is required to participate in conferences with video. Please grant it in Settings",
|
||||
"permissionMicRequiredError": "Microphone permission is required to participate in conferences with audio. Please grant it in Settings",
|
||||
"popupError": "Your browser is blocking pop-up windows from this site. Please enable pop-ups in your browser's security settings and try again.",
|
||||
"popupErrorTitle": "Pop-up blocked",
|
||||
"readMore": "more",
|
||||
@@ -300,13 +306,24 @@
|
||||
"sessTerminated": "Call terminated",
|
||||
"sessionRestarted": "Call restarted by the bridge",
|
||||
"Share": "Share",
|
||||
"shareVideoLinkError": "Please provide a correct youtube link.",
|
||||
"shareAudio": "Continue",
|
||||
"shareAudioTitle" : "How to share audio",
|
||||
"shareAudioWarningTitle": "You need to stop screen sharing before sharing audio",
|
||||
"shareAudioWarningH1": "If you want to share just 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.",
|
||||
"shareMediaWarningGenericH2": "If you want to share your screen and audio",
|
||||
"shareVideoLinkError": "Please provide a correct video link.",
|
||||
"shareVideoTitle": "Share video",
|
||||
"shareYourScreen": "Share your screen",
|
||||
"shareYourScreenDisabled": "Screen sharing disabled.",
|
||||
"startLiveStreaming": "Start live stream",
|
||||
"startRecording": "Start recording",
|
||||
"startRemoteControlErrorMessage": "An error occurred while trying to start the remote control session!",
|
||||
"shareScreenWarningTitle": "You need to stop audio sharing before sharing your screen",
|
||||
"shareScreenWarningH1": "If you want to share just your screen:",
|
||||
"shareScreenWarningD1": "you need to stop audio sharing before sharing your screen.",
|
||||
"shareScreenWarningD2": "you need to stop audio sharing, start screen sharing and check the \"share audio\" option.",
|
||||
"stopLiveStreaming": "Stop live stream",
|
||||
"stopRecording": "Stop recording",
|
||||
"stopRecordingWarning": "Are you sure you would like to stop the recording?",
|
||||
@@ -323,6 +340,9 @@
|
||||
"userIdentifier": "User identifier",
|
||||
"userPassword": "User password",
|
||||
"videoLink": "Video link",
|
||||
"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!",
|
||||
"WaitForHostMsg": "The conference <b>{{room}}</b> has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
|
||||
"WaitForHostMsgWOk": "The conference <b>{{room}}</b> has not yet started. If you are the host then please press Ok to authenticate. Otherwise, please wait for the host to arrive.",
|
||||
"WaitingForHostTitle": "Waiting for the host ...",
|
||||
@@ -400,6 +420,10 @@
|
||||
"invitePhone": "To join by phone instead, tap this: {{number}},,{{conferenceID}}#\n",
|
||||
"invitePhoneAlternatives": "Looking for a different dial-in number?\nSee meeting dial-in numbers: {{url}}\n\n\nIf also dialing-in through a room phone, join without connecting to audio: {{silentUrl}}",
|
||||
"inviteSipEndpoint": "To join using the SIP address, enter this: {{sipUri}}",
|
||||
"inviteTextiOSPersonal": "{{name}} is inviting you to a meeting.",
|
||||
"inviteTextiOSJoinSilent": "If you are dialing-in through a room phone, use this link to join without connecting to audio: {{silentUrl}}.",
|
||||
"inviteTextiOSInviteUrl": "Click the following link to join: {{inviteUrl}}.",
|
||||
"inviteTextiOSPhone": "To join via phone, use this number: {{number}},,{{conferenceID}}#. If you are looking for a different number, this is the full list: {{didUrl}}.",
|
||||
"inviteURLFirstPartGeneral": "You are invited to join a meeting.",
|
||||
"inviteURLFirstPartPersonal": "{{name}} is inviting you to a meeting.\n",
|
||||
"inviteURLSecondPart": "\nJoin the meeting:\n{{url}}\n",
|
||||
@@ -410,6 +434,7 @@
|
||||
"noRoom": "No room was specified to dial-in into.",
|
||||
"numbers": "Dial-in Numbers",
|
||||
"password": "$t(lockRoomPasswordUppercase):",
|
||||
"sip": "SIP address",
|
||||
"title": "Share",
|
||||
"tooltip": "Share link and dial-in info for this meeting",
|
||||
"label": "Dial-in info"
|
||||
@@ -520,6 +545,7 @@
|
||||
"focus": "Conference focus",
|
||||
"focusFail": "{{component}} not available - retry in {{ms}} sec",
|
||||
"grantedTo": "Moderator rights granted to {{to}}!",
|
||||
"hostAskedUnmute": "The host would like you to unmute",
|
||||
"invitedOneMember": "{{name}} has been invited",
|
||||
"invitedThreePlusMembers": "{{name}} and {{count}} others have been invited",
|
||||
"invitedTwoMembers": "{{first}} and {{second}} have been invited",
|
||||
@@ -536,7 +562,7 @@
|
||||
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) set by another participant",
|
||||
"raisedHand": "{{name}} would like to speak.",
|
||||
"screenShareNoAudio": " Share audio box was not checked in the window selection screen.",
|
||||
"screenShareNoAudioTitle": "Share audio was not checked",
|
||||
"screenShareNoAudioTitle": "Couldn't share system audio!",
|
||||
"somebody": "Somebody",
|
||||
"startSilentTitle": "You joined with no audio output!",
|
||||
"startSilentDescription": "Rejoin the meeting to enable audio",
|
||||
@@ -550,18 +576,40 @@
|
||||
"oldElectronClientDescription1": "You appear to be using an old version of the Jitsi Meet client which has known security vulnerabilities. Please make sure you update to our ",
|
||||
"oldElectronClientDescription2": "latest build",
|
||||
"oldElectronClientDescription3": " now!",
|
||||
"moderationInEffectDescription": "Please raise hand if you want to speak",
|
||||
"moderationInEffectCSDescription": "Please raise hand if you want to share your video",
|
||||
"moderationInEffectVideoDescription": "Please raise your hand if you want your video to be visible",
|
||||
"moderationInEffectTitle": "The microphone is muted by the moderator",
|
||||
"moderationInEffectCSTitle": "Content sharing is disabled by moderator",
|
||||
"moderationInEffectVideoTitle": "The video is muted by the moderator",
|
||||
"moderationRequestFromModerator": "The host would like you to unmute",
|
||||
"moderationRequestFromParticipant": "Wants to speak",
|
||||
"moderationStartedTitle": "Moderation started",
|
||||
"moderationStoppedTitle": "Moderation stopped",
|
||||
"moderationToggleDescription": "by {{participantDisplayName}}",
|
||||
"raiseHandAction": "Raise hand",
|
||||
"groupTitle": "Notifications"
|
||||
},
|
||||
"participantsPane": {
|
||||
"close": "Close",
|
||||
"header": "Participants",
|
||||
"headings": {
|
||||
"lobby": "Lobby ({{count}})",
|
||||
"participantsList": "Meeting participants ({{count}})"
|
||||
"participantsList": "Meeting participants ({{count}})",
|
||||
"waitingLobby": "Waiting in lobby ({{count}})"
|
||||
},
|
||||
"actions": {
|
||||
"allow": "Allow attendees to:",
|
||||
"blockEveryoneMicCamera": "Block everyone's mic and camera",
|
||||
"invite": "Invite Someone",
|
||||
"askUnmute": "Ask to unmute",
|
||||
"mute": "Mute",
|
||||
"muteAll": "Mute all",
|
||||
"stopVideo": "Stop video"
|
||||
"muteEveryoneElse": "Mute everyone else",
|
||||
"startModeration": "Unmute themselves or start video",
|
||||
"stopEveryonesVideo": "Stop everyone's video",
|
||||
"stopVideo": "Stop video",
|
||||
"unblockEveryoneMicCamera": "Unblock everyone's mic and camera"
|
||||
}
|
||||
},
|
||||
"passwordSetRemotely": "Set by another participant",
|
||||
@@ -698,8 +746,13 @@
|
||||
"signedIn": "Currently accessing calendar events for {{email}}. Click the Disconnect button below to stop accessing calendar events.",
|
||||
"title": "Calendar"
|
||||
},
|
||||
"desktopShareFramerate": "Desktop sharing frame rate",
|
||||
"desktopShareWarning": "You need to restart the screen share for the new settings to take effect.",
|
||||
"desktopShareHighFpsWarning": "A higher frame rate for desktop sharing might affect your bandwidth. You need to restart the screen share for the new settings to take effect.",
|
||||
"devices": "Devices",
|
||||
"followMe": "Everyone follows me",
|
||||
"framesPerSecond": "frames-per-second",
|
||||
"incomingMessage": "Incoming message",
|
||||
"language": "Language",
|
||||
"loggedIn": "Logged in as {{name}}",
|
||||
"microphones": "Microphones",
|
||||
@@ -707,13 +760,18 @@
|
||||
"more": "More",
|
||||
"name": "Name",
|
||||
"noDevice": "None",
|
||||
"participantJoined": "Participant Joined",
|
||||
"participantLeft": "Participant Left",
|
||||
"playSounds": "Play sound on",
|
||||
"sameAsSystem": "Same as system ({{label}})",
|
||||
"selectAudioOutput": "Audio output",
|
||||
"selectCamera": "Camera",
|
||||
"selectMic": "Microphone",
|
||||
"sounds": "Sounds",
|
||||
"speakers": "Speakers",
|
||||
"startAudioMuted": "Everyone starts muted",
|
||||
"startVideoMuted": "Everyone starts hidden",
|
||||
"talkWhileMuted": "Talk while muted",
|
||||
"title": "Settings"
|
||||
},
|
||||
"settingsView": {
|
||||
@@ -765,9 +823,11 @@
|
||||
"accessibilityLabel": {
|
||||
"audioOnly": "Toggle audio only",
|
||||
"audioRoute": "Select the sound device",
|
||||
"boo": "Boo",
|
||||
"callQuality": "Manage video quality",
|
||||
"cc": "Toggle subtitles",
|
||||
"chat": "Open / Close chat",
|
||||
"clap": "Clap",
|
||||
"document": "Toggle shared document",
|
||||
"download": "Download our apps",
|
||||
"embedMeeting": "Embed meeting",
|
||||
@@ -778,6 +838,8 @@
|
||||
"help": "Help",
|
||||
"invite": "Invite people",
|
||||
"kick": "Kick participant",
|
||||
"laugh": "Laugh",
|
||||
"like": "Thumbs Up",
|
||||
"lobbyButton": "Enable/disable lobby mode",
|
||||
"localRecording": "Toggle local recording controls",
|
||||
"lockRoom": "Toggle meeting password",
|
||||
@@ -790,10 +852,12 @@
|
||||
"muteEveryonesVideo": "Disable everyone's camera",
|
||||
"muteEveryoneElsesVideo": "Disable everyone else's camera",
|
||||
"participants": "Participants",
|
||||
"party": "Party Popper",
|
||||
"pip": "Toggle Picture-in-Picture mode",
|
||||
"privateMessage": "Send private message",
|
||||
"profile": "Edit your profile",
|
||||
"raiseHand": "Raise / Lower your hand",
|
||||
"reactionsMenu": "Open / Close reactions menu",
|
||||
"recording": "Toggle recording",
|
||||
"remoteMute": "Mute participant",
|
||||
"remoteVideoMute": "Disable camera of participant",
|
||||
@@ -806,6 +870,7 @@
|
||||
"shortcuts": "Toggle shortcuts",
|
||||
"show": "Show on stage",
|
||||
"speakerStats": "Toggle speaker statistics",
|
||||
"surprised": "Surprised",
|
||||
"tileView": "Toggle tile view",
|
||||
"toggleCamera": "Toggle camera",
|
||||
"toggleFilmstrip": "Toggle filmstrip",
|
||||
@@ -822,9 +887,12 @@
|
||||
"audioOnlyOn": "Enable low bandwidth mode",
|
||||
"audioRoute": "Select the sound device",
|
||||
"authenticate": "Authenticate",
|
||||
"boo": "Boo",
|
||||
"callQuality": "Manage video quality",
|
||||
"chat": "Open / Close chat",
|
||||
"clap": "Clap",
|
||||
"closeChat": "Close chat",
|
||||
"closeReactionsMenu": "Close reactions menu",
|
||||
"documentClose": "Close shared document",
|
||||
"documentOpen": "Open shared document",
|
||||
"download": "Download our apps",
|
||||
@@ -838,6 +906,8 @@
|
||||
"hangup": "Leave the meeting",
|
||||
"help": "Help",
|
||||
"invite": "Invite people",
|
||||
"laugh": "Laugh",
|
||||
"like": "Thumbs Up",
|
||||
"lobbyButtonDisable": "Disable lobby mode",
|
||||
"lobbyButtonEnable": "Enable lobby mode",
|
||||
"login": "Login",
|
||||
@@ -856,12 +926,20 @@
|
||||
"noisyAudioInputTitle": "Your microphone appears to be noisy!",
|
||||
"noisyAudioInputDesc": "It sounds like your microphone is making noise, please consider muting or changing the device.",
|
||||
"openChat": "Open chat",
|
||||
"openReactionsMenu": "Open reactions menu",
|
||||
"participants": "Participants",
|
||||
"party": "Celebration",
|
||||
"pip": "Enter Picture-in-Picture mode",
|
||||
"privateMessage": "Send private message",
|
||||
"profile": "Edit your profile",
|
||||
"raiseHand": "Raise / Lower your hand",
|
||||
"raiseYourHand": "Raise your hand",
|
||||
"reactionBoo": "Send boo reaction",
|
||||
"reactionClap": "Send clap reaction",
|
||||
"reactionLaugh": "Send laugh reaction",
|
||||
"reactionLike": "Send thumbs up reaction",
|
||||
"reactionParty": "Send party popper reaction",
|
||||
"reactionSurprised": "Send surprised reaction",
|
||||
"security": "Security options",
|
||||
"Settings": "Settings",
|
||||
"shareaudio": "Share audio",
|
||||
@@ -871,9 +949,11 @@
|
||||
"speakerStats": "Speaker stats",
|
||||
"startScreenSharing": "Start screen sharing",
|
||||
"startSubtitles": "Start subtitles",
|
||||
"stopAudioSharing": "Stop audio sharing",
|
||||
"stopScreenSharing": "Stop screen sharing",
|
||||
"stopSubtitles": "Stop subtitles",
|
||||
"stopSharedVideo": "Stop video",
|
||||
"surprised": "Surprised",
|
||||
"talkWhileMutedPopup": "Trying to speak? You are muted.",
|
||||
"tileViewToggle": "Toggle tile view",
|
||||
"toggleCamera": "Toggle camera",
|
||||
@@ -1036,6 +1116,7 @@
|
||||
"passwordField": "Enter meeting password",
|
||||
"passwordJoinButton": "Join",
|
||||
"reject": "Reject",
|
||||
"rejectAll": "Reject all",
|
||||
"toggleLabel": "Enable lobby"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ var loggingConfig = {
|
||||
// {@link #defaultLogLevel}:
|
||||
'modules/RTC/TraceablePeerConnection.js': 'info',
|
||||
'modules/statistics/CallStats.js': 'info',
|
||||
'modules/sdp/SDPUtil.js': 'info',
|
||||
'modules/xmpp/JingleSessionPC.js': 'info',
|
||||
'modules/xmpp/strophe.jingle.js': 'info',
|
||||
'modules/xmpp/strophe.util.js': 'log'
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
import {
|
||||
getCurrentConference,
|
||||
sendTones,
|
||||
setFollowMe,
|
||||
setPassword,
|
||||
setSubject
|
||||
} from '../../react/features/base/conference';
|
||||
@@ -20,13 +21,15 @@ import { MEDIA_TYPE } from '../../react/features/base/media';
|
||||
import {
|
||||
getLocalParticipant,
|
||||
getParticipantById,
|
||||
participantUpdated,
|
||||
pinParticipant,
|
||||
kickParticipant
|
||||
kickParticipant,
|
||||
raiseHand,
|
||||
isParticipantModerator
|
||||
} from '../../react/features/base/participants';
|
||||
import { updateSettings } from '../../react/features/base/settings';
|
||||
import { isToggleCameraEnabled, toggleCamera } from '../../react/features/base/tracks';
|
||||
import {
|
||||
sendMessage,
|
||||
setPrivateMessageRecipient,
|
||||
toggleChat
|
||||
} from '../../react/features/chat/actions';
|
||||
@@ -47,6 +50,8 @@ import {
|
||||
import { toggleLobbyMode } from '../../react/features/lobby/actions';
|
||||
import { RECORDING_TYPES } from '../../react/features/recording/constants';
|
||||
import { getActiveSession } from '../../react/features/recording/functions';
|
||||
import { isScreenAudioSupported } from '../../react/features/screen-share';
|
||||
import { startScreenShareFlow, startAudioScreenShareFlow } from '../../react/features/screen-share/actions';
|
||||
import { playSharedVideo, stopSharedVideo } from '../../react/features/shared-video/actions.any';
|
||||
import { toggleTileView, setTileView } from '../../react/features/video-layout';
|
||||
import { muteAllParticipants } from '../../react/features/video-menu/actions';
|
||||
@@ -101,13 +106,14 @@ function initCommands() {
|
||||
const muteMediaType = mediaType ? mediaType : MEDIA_TYPE.AUDIO;
|
||||
|
||||
sendAnalytics(createApiEvent('muted-everyone'));
|
||||
const participants = APP.store.getState()['features/base/participants'];
|
||||
const localIds = participants
|
||||
.filter(participant => participant.local)
|
||||
.filter(participant => participant.role === 'moderator')
|
||||
.map(participant => participant.id);
|
||||
const localParticipant = getLocalParticipant(APP.store.getState());
|
||||
const exclude = [];
|
||||
|
||||
APP.store.dispatch(muteAllParticipants(localIds, muteMediaType));
|
||||
if (localParticipant && isParticipantModerator(localParticipant)) {
|
||||
exclude.push(localParticipant.id);
|
||||
}
|
||||
|
||||
APP.store.dispatch(muteAllParticipants(exclude, muteMediaType));
|
||||
},
|
||||
'toggle-lobby': isLobbyEnabled => {
|
||||
APP.store.dispatch(toggleLobbyMode(isLobbyEnabled));
|
||||
@@ -152,6 +158,17 @@ function initCommands() {
|
||||
|
||||
APP.store.dispatch(sendTones(tones, duration, pause));
|
||||
},
|
||||
'set-follow-me': value => {
|
||||
logger.debug('Set follow me command received');
|
||||
|
||||
if (value) {
|
||||
sendAnalytics(createApiEvent('follow.me.set'));
|
||||
} else {
|
||||
sendAnalytics(createApiEvent('follow.me.unset'));
|
||||
}
|
||||
|
||||
APP.store.dispatch(setFollowMe(value));
|
||||
},
|
||||
'set-large-video-participant': participantId => {
|
||||
logger.debug('Set large video participant command received');
|
||||
sendAnalytics(createApiEvent('largevideo.participant.set'));
|
||||
@@ -205,13 +222,17 @@ function initCommands() {
|
||||
const { raisedHand } = localParticipant;
|
||||
|
||||
sendAnalytics(createApiEvent('raise-hand.toggled'));
|
||||
APP.store.dispatch(
|
||||
participantUpdated({
|
||||
id: APP.conference.getMyUserId(),
|
||||
local: true,
|
||||
raisedHand: !raisedHand
|
||||
})
|
||||
);
|
||||
APP.store.dispatch(raiseHand(!raisedHand));
|
||||
},
|
||||
'toggle-share-audio': () => {
|
||||
sendAnalytics(createApiEvent('audio.screen.sharing.toggled'));
|
||||
if (isScreenAudioSupported()) {
|
||||
APP.store.dispatch(startAudioScreenShareFlow());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
logger.error('Audio screen sharing is not supported by the current platform!');
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -247,6 +268,24 @@ function initCommands() {
|
||||
sendAnalytics(createApiEvent('avatar.url.changed'));
|
||||
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);
|
||||
|
||||
if (participant) {
|
||||
APP.store.dispatch(setPrivateMessageRecipient(participant));
|
||||
} else {
|
||||
logger.error(`Participant with id ${to} not found!`);
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
APP.store.dispatch(setPrivateMessageRecipient());
|
||||
}
|
||||
|
||||
APP.store.dispatch(sendMessage(message, ignorePrivacy));
|
||||
},
|
||||
'send-endpoint-text-message': (to, text) => {
|
||||
logger.debug('Send endpoint message command received');
|
||||
try {
|
||||
@@ -535,6 +574,12 @@ function initCommands() {
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'get-custom-avatar-backgrounds' : {
|
||||
callback({
|
||||
avatarBackgrounds: APP.store.getState()['features/dynamic-branding'].avatarBackgrounds
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -571,9 +616,7 @@ function shouldBeEnabled() {
|
||||
*/
|
||||
function toggleScreenSharing(enable) {
|
||||
if (JitsiMeetJS.isDesktopSharingEnabled()) {
|
||||
APP.conference.toggleScreenSharing(enable).catch(() => {
|
||||
logger.warn('Failed to toggle screen-sharing');
|
||||
});
|
||||
APP.store.dispatch(startScreenShareFlow(enable));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,3 +15,8 @@ export const API_ID = parseURLParams(window.location).jitsi_meet_external_api_id
|
||||
* The payload name for the datachannel/endpoint text message event
|
||||
*/
|
||||
export const ENDPOINT_TEXT_MESSAGE_NAME = 'endpoint-text-message';
|
||||
|
||||
/**
|
||||
* The payload name for the datachannel/endpoint reaction event
|
||||
*/
|
||||
export const ENDPOINT_REACTION_NAME = 'endpoint-reaction';
|
||||
|
||||
16
modules/API/external/external_api.js
vendored
16
modules/API/external/external_api.js
vendored
@@ -41,8 +41,10 @@ const commands = {
|
||||
password: 'password',
|
||||
pinParticipant: 'pin-participant',
|
||||
resizeLargeVideo: 'resize-large-video',
|
||||
sendChatMessage: 'send-chat-message',
|
||||
sendEndpointTextMessage: 'send-endpoint-text-message',
|
||||
sendTones: 'send-tones',
|
||||
setFollowMe: 'set-follow-me',
|
||||
setLargeVideoParticipant: 'set-large-video-participant',
|
||||
setTileView: 'set-tile-view',
|
||||
setVideoQuality: 'set-video-quality',
|
||||
@@ -58,6 +60,7 @@ const commands = {
|
||||
toggleChat: 'toggle-chat',
|
||||
toggleFilmStrip: 'toggle-film-strip',
|
||||
toggleRaiseHand: 'toggle-raise-hand',
|
||||
toggleShareAudio: 'toggle-share-audio',
|
||||
toggleShareScreen: 'toggle-share-screen',
|
||||
toggleTileView: 'toggle-tile-view',
|
||||
toggleVirtualBackgroundDialog: 'toggle-virtual-background',
|
||||
@@ -167,7 +170,7 @@ function parseArguments(args) {
|
||||
|
||||
switch (typeof firstArg) {
|
||||
case 'string': // old arguments format
|
||||
case undefined: {
|
||||
case 'undefined': {
|
||||
// Not sure which format but we are trying to parse the old
|
||||
// format because if the new format is used everything will be undefined
|
||||
// anyway.
|
||||
@@ -766,6 +769,17 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
return getCurrentDevices(this._transport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns any custom avatars backgrounds.
|
||||
*
|
||||
* @returns {Promise} - Resolves with the list of custom avatar backgrounds.
|
||||
*/
|
||||
getCustomAvatarBackgrounds() {
|
||||
return this._transport.sendRequest({
|
||||
name: 'get-custom-avatar-backgrounds'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current livestream url.
|
||||
*
|
||||
|
||||
@@ -62,7 +62,6 @@ const _focusedElementsSelector = `:focus:is(${_elementsBlacklist.join(',')})`;
|
||||
* Maps keycode to character, id of popover for given function and function.
|
||||
*/
|
||||
const KeyboardShortcut = {
|
||||
isPushToTalkActive: false,
|
||||
|
||||
init() {
|
||||
this._initGlobalShortcuts();
|
||||
@@ -97,7 +96,6 @@ const KeyboardShortcut = {
|
||||
PRESSED));
|
||||
logger.log('Talk shortcut pressed');
|
||||
APP.conference.muteAudio(false);
|
||||
this.isPushToTalkActive = true;
|
||||
}
|
||||
}
|
||||
} else if (this._getKeyboardKey(e).toUpperCase() === 'ESCAPE') {
|
||||
@@ -144,20 +142,23 @@ const KeyboardShortcut = {
|
||||
* @param exec the function to be executed when the shortcut is pressed
|
||||
* @param helpDescription the description of the shortcut that would appear
|
||||
* in the help menu
|
||||
* @param altKey whether or not the alt key must be pressed.
|
||||
*/
|
||||
registerShortcut(// eslint-disable-line max-params
|
||||
shortcutChar,
|
||||
shortcutAttr,
|
||||
exec,
|
||||
helpDescription) {
|
||||
_shortcuts.set(shortcutChar, {
|
||||
helpDescription,
|
||||
altKey = false) {
|
||||
_shortcuts.set(altKey ? `:${shortcutChar}` : shortcutChar, {
|
||||
character: shortcutChar,
|
||||
function: exec,
|
||||
shortcutAttr
|
||||
shortcutAttr,
|
||||
altKey
|
||||
});
|
||||
|
||||
if (helpDescription) {
|
||||
this._addShortcutToHelp(shortcutChar, helpDescription);
|
||||
this._addShortcutToHelp(altKey ? `:${shortcutChar}` : shortcutChar, helpDescription);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -166,9 +167,10 @@ const KeyboardShortcut = {
|
||||
*
|
||||
* @param shortcutChar unregisters the given shortcut, which means it will
|
||||
* no longer be usable
|
||||
* @param altKey whether or not shortcut is combo with alt key
|
||||
*/
|
||||
unregisterShortcut(shortcutChar) {
|
||||
_shortcuts.delete(shortcutChar);
|
||||
unregisterShortcut(shortcutChar, altKey = false) {
|
||||
_shortcuts.delete(altKey ? `:${shortcutChar}` : shortcutChar);
|
||||
_shortcutsHelp.delete(shortcutChar);
|
||||
},
|
||||
|
||||
@@ -177,6 +179,15 @@ const KeyboardShortcut = {
|
||||
* @returns {string} e.key or something close if not supported
|
||||
*/
|
||||
_getKeyboardKey(e) {
|
||||
// If alt is pressed a different char can be returned so this takes
|
||||
// the char from the code. It also prefixes with a colon to differentiate
|
||||
// alt combo from simple keypress.
|
||||
if (e.altKey) {
|
||||
const key = e.code.replace('Key', '');
|
||||
|
||||
return `:${key}`;
|
||||
}
|
||||
|
||||
// If e.key is a string, then it is assumed it already plainly states
|
||||
// the key pressed. This may not be true in all cases, such as with Edge
|
||||
// and "?", when the browser cannot properly map a key press event to a
|
||||
@@ -232,12 +243,9 @@ const KeyboardShortcut = {
|
||||
// register SPACE shortcut in two steps to insure visibility of help
|
||||
// message
|
||||
this.registerShortcut(' ', null, () => {
|
||||
if (this.isPushToTalkActive) {
|
||||
sendAnalytics(createShortcutEvent('push.to.talk', RELEASED));
|
||||
logger.log('Talk shortcut released');
|
||||
APP.conference.muteAudio(true);
|
||||
this.isPushToTalkActive = false;
|
||||
}
|
||||
sendAnalytics(createShortcutEvent('push.to.talk', RELEASED));
|
||||
logger.log('Talk shortcut released');
|
||||
APP.conference.muteAudio(true);
|
||||
});
|
||||
this._addShortcutToHelp('SPACE', 'keyboardShortcuts.pushToTalk');
|
||||
|
||||
|
||||
80
package-lock.json
generated
80
package-lock.json
generated
@@ -2913,9 +2913,9 @@
|
||||
"integrity": "sha512-cPqjjzuFWNK3BSKLm0abspP0sp/IGOli4p5I5fKFAzdS8fvjdOwDCfZqAaIiXd9lPkOWi3SUUfZof3hEb7J/uw=="
|
||||
},
|
||||
"@react-native-async-storage/async-storage": {
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.13.2.tgz",
|
||||
"integrity": "sha512-isTDvUApRJPVWFxV15yrQSOGqarX7cIedq/y4N5yWSnotf68D9qvDEv1I7rCXhkBDi0u4OJt6GA9dksUT0D3wg==",
|
||||
"version": "1.15.5",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.15.5.tgz",
|
||||
"integrity": "sha512-4AYehLH39B9a8UXCMf3ieOK+G61wGMP72ikx6/XSMA0DUnvx0PgaeaT2Wyt06kTrDTy8edewKnbrbeqwaM50TQ==",
|
||||
"requires": {
|
||||
"deep-assign": "^3.0.0"
|
||||
}
|
||||
@@ -3102,6 +3102,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@react-native-community/netinfo/-/netinfo-4.1.5.tgz",
|
||||
"integrity": "sha512-lagdZr9UiVAccNXYfTEj+aUcPCx9ykbMe9puffeIyF3JsRuMmlu3BjHYx1klUHX7wNRmFNC8qVP0puxUt1sZ0A=="
|
||||
},
|
||||
"@react-native-community/slider": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-community/slider/-/slider-3.0.3.tgz",
|
||||
"integrity": "sha512-8IeHfDwJ9/CTUwFs6x90VlobV3BfuPgNLjTgC6dRZovfCWigaZwVNIFFJnHBakK3pW2xErAPwhdvNR4JeNoYbw=="
|
||||
},
|
||||
"@svgr/babel-plugin-add-jsx-attribute": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz",
|
||||
@@ -7534,6 +7539,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"eme-encryption-scheme-polyfill": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/eme-encryption-scheme-polyfill/-/eme-encryption-scheme-polyfill-2.0.3.tgz",
|
||||
"integrity": "sha512-44CNFMsqzHdKHrzWxlS7xZ8KUHn5XutBqpmCuWzNIynmAyFInHrrD3ozv/RvK9ZhgV6QY6Easx8EWAmxteNodg=="
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz",
|
||||
@@ -8239,7 +8249,8 @@
|
||||
"events": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz",
|
||||
"integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg=="
|
||||
"integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==",
|
||||
"dev": true
|
||||
},
|
||||
"eventsource": {
|
||||
"version": "1.0.7",
|
||||
@@ -11011,6 +11022,11 @@
|
||||
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz",
|
||||
"integrity": "sha1-fYa9VmefWM5qhHBKZX3TkruoGnk="
|
||||
},
|
||||
"keymirror": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/keymirror/-/keymirror-0.1.1.tgz",
|
||||
"integrity": "sha1-kYiJ6hP40KQufFVyUO7nE63JXDU="
|
||||
},
|
||||
"killable": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
|
||||
@@ -11071,8 +11087,8 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "github:jitsi/lib-jitsi-meet#24627e1b957d174ca5d3994b34c8a2a2be569ca8",
|
||||
"from": "github:jitsi/lib-jitsi-meet#24627e1b957d174ca5d3994b34c8a2a2be569ca8",
|
||||
"version": "github:jitsi/lib-jitsi-meet#6a3df11ffa7a2204b579326e23cdaa85a79521d1",
|
||||
"from": "github:jitsi/lib-jitsi-meet#6a3df11ffa7a2204b579326e23cdaa85a79521d1",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "1.0.2",
|
||||
"@jitsi/sdp-interop": "github:jitsi/sdp-interop#5fc4af6dcf8a6e6af9fedbcd654412fd47b1b4ae",
|
||||
@@ -11390,6 +11406,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"memoize-one": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz",
|
||||
"integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA=="
|
||||
},
|
||||
"memory-fs": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
|
||||
@@ -15133,14 +15154,25 @@
|
||||
"whatwg-url-without-unicode": "8.0.0-3"
|
||||
}
|
||||
},
|
||||
"react-native-video": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-video/-/react-native-video-5.1.1.tgz",
|
||||
"integrity": "sha512-zee8gRUrjPWRoZSEBiMebClqu1iAuCQNLjzqpmXFrRWEoJj7azM3BPqLQWJgsnfLiYUYGySeApC/G60THM5+tw==",
|
||||
"requires": {
|
||||
"keymirror": "^0.1.1",
|
||||
"prop-types": "^15.7.2",
|
||||
"shaka-player": "^2.5.9"
|
||||
}
|
||||
},
|
||||
"react-native-watch-connectivity": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/react-native-watch-connectivity/-/react-native-watch-connectivity-0.4.3.tgz",
|
||||
"integrity": "sha512-iqdJ1KpZbR4XGahgVmaeibB7kDhyMT7wrylINgJaYBY38IAiI0LF32VX1umO4pko6n21YF5I/kSeNQ+OXGqqow=="
|
||||
},
|
||||
"react-native-webrtc": {
|
||||
"version": "github:react-native-webrtc/react-native-webrtc#510d20dd62c1768885a98f36fde83f9e48a723fa",
|
||||
"from": "github:react-native-webrtc/react-native-webrtc#510d20dd62c1768885a98f36fde83f9e48a723fa",
|
||||
"version": "1.92.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.92.0.tgz",
|
||||
"integrity": "sha512-nztKQ/SmO1DgA3QWCDHHK8ZVDf+5rLbmH42Ukoqnld7ut8/ehmFZXc17aSV/BN0H60jPigGqAMYopt/LZak7Sg==",
|
||||
"requires": {
|
||||
"base64-js": "^1.1.2",
|
||||
"cross-os": "^1.3.0",
|
||||
@@ -15181,11 +15213,18 @@
|
||||
}
|
||||
},
|
||||
"react-native-youtube-iframe": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react-native-youtube-iframe/-/react-native-youtube-iframe-1.2.3.tgz",
|
||||
"integrity": "sha512-3O8OFJyohGNlYX4D97aWfLLlhEHhlLHDCLgXM+SsQBwP9r1oLnKgXWoy1gce+Vr8qgrqeQgmx1ki+10AAd4KWQ==",
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-youtube-iframe/-/react-native-youtube-iframe-2.1.1.tgz",
|
||||
"integrity": "sha512-vnLzA5zcnMwa1gMqGfvkjaE82NW1Nd2Up4Q1OUz6IKm69xSG/9/m4APZ5fCN8UMhy6lH95iagd497J7jwEwz3w==",
|
||||
"requires": {
|
||||
"events": "^3.0.0"
|
||||
"events": "^3.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"events": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
|
||||
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-node-resolver": {
|
||||
@@ -15318,6 +15357,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-window": {
|
||||
"version": "1.8.6",
|
||||
"resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.6.tgz",
|
||||
"integrity": "sha512-8VwEEYyjz6DCnGBsd+MgkD0KJ2/OXFULyDtorIiTz+QzwoP94tBoA7CnbtyXMm+cCeAUER5KJcPtWl9cpKbOBg==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"memoize-one": ">=3.1.1 <6"
|
||||
}
|
||||
},
|
||||
"react-youtube": {
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-youtube/-/react-youtube-7.13.1.tgz",
|
||||
@@ -16050,6 +16098,14 @@
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"shaka-player": {
|
||||
"version": "2.5.22",
|
||||
"resolved": "https://registry.npmjs.org/shaka-player/-/shaka-player-2.5.22.tgz",
|
||||
"integrity": "sha512-PAoeNLUQ/hT/9dY7QvNFgIiDtXSqbYVFuXXtLHh7ytVVqTvI/p4HLwfYShiR+sE/sbsDOr9D5l9D/ztLPhxgtw==",
|
||||
"requires": {
|
||||
"eme-encryption-scheme-polyfill": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"shallow-clone": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz",
|
||||
|
||||
11
package.json
11
package.json
@@ -36,9 +36,10 @@
|
||||
"@jitsi/js-utils": "1.0.6",
|
||||
"@material-ui/core": "4.11.3",
|
||||
"@microsoft/microsoft-graph-client": "1.1.0",
|
||||
"@react-native-async-storage/async-storage": "1.13.2",
|
||||
"@react-native-async-storage/async-storage": "1.15.5",
|
||||
"@react-native-community/google-signin": "3.0.1",
|
||||
"@react-native-community/netinfo": "4.1.5",
|
||||
"@react-native-community/slider": "3.0.3",
|
||||
"@svgr/webpack": "4.3.2",
|
||||
"amplitude-js": "8.2.1",
|
||||
"base64-js": "1.3.1",
|
||||
@@ -55,7 +56,7 @@
|
||||
"jquery-i18next": "1.2.1",
|
||||
"js-md5": "0.6.1",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#24627e1b957d174ca5d3994b34c8a2a2be569ca8",
|
||||
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#6a3df11ffa7a2204b579326e23cdaa85a79521d1",
|
||||
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.1",
|
||||
@@ -86,13 +87,15 @@
|
||||
"react-native-svg": "12.1.0",
|
||||
"react-native-svg-transformer": "0.14.3",
|
||||
"react-native-url-polyfill": "1.2.0",
|
||||
"react-native-video": "5.1.1",
|
||||
"react-native-watch-connectivity": "0.4.3",
|
||||
"react-native-webrtc": "github:react-native-webrtc/react-native-webrtc#510d20dd62c1768885a98f36fde83f9e48a723fa",
|
||||
"react-native-webrtc": "1.92.0",
|
||||
"react-native-webview": "11.0.2",
|
||||
"react-native-youtube-iframe": "1.2.3",
|
||||
"react-native-youtube-iframe": "2.1.1",
|
||||
"react-redux": "7.1.0",
|
||||
"react-textarea-autosize": "8.3.0",
|
||||
"react-transition-group": "2.4.0",
|
||||
"react-window": "1.8.6",
|
||||
"react-youtube": "7.13.1",
|
||||
"redux": "4.0.4",
|
||||
"redux-thunk": "2.2.0",
|
||||
|
||||
@@ -21,6 +21,7 @@ const TOOLBAR_TIMEOUT = 4000;
|
||||
*/
|
||||
type State = {
|
||||
avatarURL: string,
|
||||
customAvatarBackgrounds: Array<string>,
|
||||
displayName: string,
|
||||
formattedDisplayName: string,
|
||||
isVideoDisplayed: boolean,
|
||||
@@ -48,6 +49,7 @@ export default class AlwaysOnTop extends Component<*, State> {
|
||||
|
||||
this.state = {
|
||||
avatarURL: '',
|
||||
customAvatarBackgrounds: [],
|
||||
displayName: '',
|
||||
formattedDisplayName: '',
|
||||
isVideoDisplayed: true,
|
||||
@@ -178,7 +180,14 @@ export default class AlwaysOnTop extends Component<*, State> {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderVideoNotAvailableScreen() {
|
||||
const { avatarURL, displayName, formattedDisplayName, isVideoDisplayed, userID } = this.state;
|
||||
const {
|
||||
avatarURL,
|
||||
customAvatarBackgrounds,
|
||||
displayName,
|
||||
formattedDisplayName,
|
||||
isVideoDisplayed,
|
||||
userID
|
||||
} = this.state;
|
||||
|
||||
if (isVideoDisplayed) {
|
||||
return null;
|
||||
@@ -188,7 +197,7 @@ export default class AlwaysOnTop extends Component<*, State> {
|
||||
<div id = 'videoNotAvailableScreen'>
|
||||
<div id = 'avatarContainer'>
|
||||
<StatelessAvatar
|
||||
color = { getAvatarColor(userID) }
|
||||
color = { getAvatarColor(userID, customAvatarBackgrounds) }
|
||||
id = 'avatar'
|
||||
initials = { getInitials(displayName) }
|
||||
url = { avatarURL } />)
|
||||
@@ -218,6 +227,12 @@ export default class AlwaysOnTop extends Component<*, State> {
|
||||
window.addEventListener('mousemove', this._mouseMove);
|
||||
|
||||
this._hideToolbarAfterTimeout();
|
||||
api.getCustomAvatarBackgrounds()
|
||||
.then(res =>
|
||||
this.setState({
|
||||
customAvatarBackgrounds: res.avatarBackgrounds || []
|
||||
}))
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -795,6 +795,23 @@ export function createToolbarEvent(buttonName, attributes = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event associated with a reaction button being clicked/pressed.
|
||||
*
|
||||
* @param {string} buttonName - The identifier of the reaction button which was
|
||||
* clicked/pressed.
|
||||
* @returns {Object} The event in a format suitable for sending via
|
||||
* sendAnalytics.
|
||||
*/
|
||||
export function createReactionMenuEvent(buttonName) {
|
||||
return {
|
||||
action: 'clicked',
|
||||
actionSubject: buttonName,
|
||||
source: 'reaction.button',
|
||||
type: TYPE_UI
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event which indicates that a local track was muted.
|
||||
*
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
parseURIString,
|
||||
toURLString
|
||||
} from '../base/util';
|
||||
import { isVpaasMeeting } from '../billing-counter/functions';
|
||||
import { isVpaasMeeting } from '../jaas/functions';
|
||||
import { clearNotifications, showNotification } from '../notifications';
|
||||
import { setFatalError } from '../overlay';
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import { getFeatureFlag } from '../../base/flags/functions';
|
||||
import { Platform } from '../../base/react';
|
||||
import { DimensionsDetector, clientResized } from '../../base/responsive-ui';
|
||||
import { updateSettings } from '../../base/settings';
|
||||
import JitsiThemePaperProvider from '../../base/ui/components/JitsiThemeProvider.native';
|
||||
import logger from '../logger';
|
||||
|
||||
import { AbstractApp } from './AbstractApp';
|
||||
@@ -128,12 +127,10 @@ export class App extends AbstractApp {
|
||||
*/
|
||||
_createMainElement(component, props) {
|
||||
return (
|
||||
<JitsiThemePaperProvider>
|
||||
<DimensionsDetector
|
||||
onDimensionsChanged = { this._onDimensionsChanged }>
|
||||
{ super._createMainElement(component, props) }
|
||||
</DimensionsDetector>
|
||||
</JitsiThemePaperProvider>
|
||||
<DimensionsDetector
|
||||
onDimensionsChanged = { this._onDimensionsChanged }>
|
||||
{ super._createMainElement(component, props) }
|
||||
</DimensionsDetector>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ import '../base/sounds/middleware';
|
||||
import '../base/testing/middleware';
|
||||
import '../base/tracks/middleware';
|
||||
import '../base/user-interaction/middleware';
|
||||
import '../billing-counter/middleware';
|
||||
import '../calendar-sync/middleware';
|
||||
import '../chat/middleware';
|
||||
import '../conference/middleware';
|
||||
@@ -30,10 +29,12 @@ import '../etherpad/middleware';
|
||||
import '../filmstrip/middleware';
|
||||
import '../follow-me/middleware';
|
||||
import '../invite/middleware';
|
||||
import '../jaas/middleware';
|
||||
import '../large-video/middleware';
|
||||
import '../lobby/middleware';
|
||||
import '../notifications/middleware';
|
||||
import '../overlay/middleware';
|
||||
import '../reactions/middleware';
|
||||
import '../recent-list/middleware';
|
||||
import '../recording/middleware';
|
||||
import '../rejoin/middleware';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import '../authentication/middleware';
|
||||
import '../av-moderation/middleware';
|
||||
import '../base/devices/middleware';
|
||||
import '../e2ee/middleware';
|
||||
import '../external-api/middleware';
|
||||
@@ -12,6 +13,7 @@ import '../old-client-notification/middleware';
|
||||
import '../power-monitor/middleware';
|
||||
import '../prejoin/middleware';
|
||||
import '../remote-control/middleware';
|
||||
import '../screen-share/middleware';
|
||||
import '../shared-video/middleware';
|
||||
import '../talk-while-muted/middleware';
|
||||
import '../virtual-background/middleware';
|
||||
|
||||
@@ -25,7 +25,6 @@ import '../base/sounds/reducer';
|
||||
import '../base/testing/reducer';
|
||||
import '../base/tracks/reducer';
|
||||
import '../base/user-interaction/reducer';
|
||||
import '../billing-counter/reducer';
|
||||
import '../calendar-sync/reducer';
|
||||
import '../chat/reducer';
|
||||
import '../deep-linking/reducer';
|
||||
@@ -36,10 +35,13 @@ import '../filmstrip/reducer';
|
||||
import '../follow-me/reducer';
|
||||
import '../google-api/reducer';
|
||||
import '../invite/reducer';
|
||||
import '../jaas/reducer';
|
||||
import '../large-video/reducer';
|
||||
import '../lobby/reducer';
|
||||
import '../notifications/reducer';
|
||||
import '../overlay/reducer';
|
||||
import '../participants-pane/reducer';
|
||||
import '../reactions/reducer';
|
||||
import '../recent-list/reducer';
|
||||
import '../recording/reducer';
|
||||
import '../settings/reducer';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import '../av-moderation/reducer';
|
||||
import '../base/devices/reducer';
|
||||
import '../e2ee/reducer';
|
||||
import '../feedback/reducer';
|
||||
@@ -10,6 +11,7 @@ import '../participants-pane/reducer';
|
||||
import '../power-monitor/reducer';
|
||||
import '../prejoin/reducer';
|
||||
import '../remote-control/reducer';
|
||||
import '../screen-share/reducer';
|
||||
import '../screenshot-capture/reducer';
|
||||
import '../shared-video/reducer';
|
||||
import '../talk-while-muted/reducer';
|
||||
|
||||
87
react/features/av-moderation/actionTypes.js
Normal file
87
react/features/av-moderation/actionTypes.js
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* The type of (redux) action which signals that A/V Moderation had been disabled.
|
||||
*
|
||||
* {
|
||||
* type: DISABLE_MODERATION
|
||||
* }
|
||||
*/
|
||||
export const DISABLE_MODERATION = 'DISABLE_MODERATION';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which signals that the notification for audio/video unmute should
|
||||
* be dismissed.
|
||||
*
|
||||
* {
|
||||
* type: DISMISS_PARTICIPANT_PENDING_AUDIO
|
||||
* }
|
||||
*/
|
||||
export const DISMISS_PENDING_PARTICIPANT = 'DISMISS_PENDING_PARTICIPANT';
|
||||
|
||||
|
||||
/**
|
||||
* The type of (redux) action which signals that A/V Moderation had been enabled.
|
||||
*
|
||||
* {
|
||||
* type: ENABLE_MODERATION
|
||||
* }
|
||||
*/
|
||||
export const ENABLE_MODERATION = 'ENABLE_MODERATION';
|
||||
|
||||
|
||||
/**
|
||||
* The type of (redux) action which signals that A/V Moderation disable has been requested.
|
||||
*
|
||||
* {
|
||||
* type: REQUEST_DISABLE_MODERATION
|
||||
* }
|
||||
*/
|
||||
export const REQUEST_DISABLE_MODERATION = 'REQUEST_DISABLE_MODERATION';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which signals that A/V Moderation enable has been requested.
|
||||
*
|
||||
* {
|
||||
* type: REQUEST_ENABLE_MODERATION
|
||||
* }
|
||||
*/
|
||||
export const REQUEST_ENABLE_MODERATION = 'REQUEST_ENABLE_MODERATION';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which signals that the local participant had been approved.
|
||||
*
|
||||
* {
|
||||
* type: LOCAL_PARTICIPANT_APPROVED,
|
||||
* mediaType: MediaType
|
||||
* }
|
||||
*/
|
||||
export const LOCAL_PARTICIPANT_APPROVED = 'LOCAL_PARTICIPANT_APPROVED';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which signals to show notification to the local participant.
|
||||
*
|
||||
* {
|
||||
* type: LOCAL_PARTICIPANT_MODERATION_NOTIFICATION
|
||||
* }
|
||||
*/
|
||||
export const LOCAL_PARTICIPANT_MODERATION_NOTIFICATION = 'LOCAL_PARTICIPANT_MODERATION_NOTIFICATION';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which signals that a participant was approved for a media type.
|
||||
*
|
||||
* {
|
||||
* type: PARTICIPANT_APPROVED,
|
||||
* mediaType: MediaType
|
||||
* participantId: String
|
||||
* }
|
||||
*/
|
||||
export const PARTICIPANT_APPROVED = 'PARTICIPANT_APPROVED';
|
||||
|
||||
|
||||
/**
|
||||
* The type of (redux) action which signals that a participant asked to have its audio umuted.
|
||||
*
|
||||
* {
|
||||
* type: PARTICIPANT_PENDING_AUDIO
|
||||
* }
|
||||
*/
|
||||
export const PARTICIPANT_PENDING_AUDIO = 'PARTICIPANT_PENDING_AUDIO';
|
||||
173
react/features/av-moderation/actions.js
Normal file
173
react/features/av-moderation/actions.js
Normal file
@@ -0,0 +1,173 @@
|
||||
// @flow
|
||||
|
||||
import { getConferenceState } from '../base/conference';
|
||||
import { MEDIA_TYPE, type MediaType } from '../base/media/constants';
|
||||
|
||||
import {
|
||||
DISMISS_PENDING_PARTICIPANT,
|
||||
DISABLE_MODERATION,
|
||||
ENABLE_MODERATION,
|
||||
LOCAL_PARTICIPANT_APPROVED,
|
||||
LOCAL_PARTICIPANT_MODERATION_NOTIFICATION,
|
||||
PARTICIPANT_APPROVED,
|
||||
PARTICIPANT_PENDING_AUDIO,
|
||||
REQUEST_DISABLE_MODERATION,
|
||||
REQUEST_ENABLE_MODERATION
|
||||
} from './actionTypes';
|
||||
|
||||
/**
|
||||
* Action used by moderator to approve audio and video for a participant.
|
||||
*
|
||||
* @param {staring} id - The id of the participant to be approved.
|
||||
* @returns {void}
|
||||
*/
|
||||
export const approveParticipant = (id: string) => (dispatch: Function, getState: Function) => {
|
||||
const { conference } = getConferenceState(getState());
|
||||
|
||||
conference.avModerationApprove(MEDIA_TYPE.AUDIO, id);
|
||||
conference.avModerationApprove(MEDIA_TYPE.VIDEO, id);
|
||||
};
|
||||
|
||||
/**
|
||||
* Audio or video moderation is disabled.
|
||||
*
|
||||
* @param {MediaType} mediaType - The media type that was disabled.
|
||||
* @param {JitsiParticipant} actor - The actor disabling.
|
||||
* @returns {{
|
||||
* type: REQUEST_DISABLE_MODERATED_AUDIO
|
||||
* }}
|
||||
*/
|
||||
export const disableModeration = (mediaType: MediaType, actor: Object) => {
|
||||
return {
|
||||
type: DISABLE_MODERATION,
|
||||
mediaType,
|
||||
actor
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Hides the notification with the participant that asked to unmute audio.
|
||||
*
|
||||
* @param {Object} participant - The participant for which the notification to be hidden.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function dismissPendingAudioParticipant(participant: Object) {
|
||||
return dismissPendingParticipant(participant, MEDIA_TYPE.AUDIO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the notification with the participant that asked to unmute.
|
||||
*
|
||||
* @param {Object} participant - The participant for which the notification to be hidden.
|
||||
* @param {MediaType} mediaType - The media type.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function dismissPendingParticipant(participant: Object, mediaType: MediaType) {
|
||||
return {
|
||||
type: DISMISS_PENDING_PARTICIPANT,
|
||||
participant,
|
||||
mediaType
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Audio or video moderation is enabled.
|
||||
*
|
||||
* @param {MediaType} mediaType - The media type that was enabled.
|
||||
* @param {JitsiParticipant} actor - The actor enabling.
|
||||
* @returns {{
|
||||
* type: REQUEST_ENABLE_MODERATED_AUDIO
|
||||
* }}
|
||||
*/
|
||||
export const enableModeration = (mediaType: MediaType, actor: Object) => {
|
||||
return {
|
||||
type: ENABLE_MODERATION,
|
||||
mediaType,
|
||||
actor
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Requests disable of audio and video moderation.
|
||||
*
|
||||
* @returns {{
|
||||
* type: REQUEST_DISABLE_MODERATED_AUDIO
|
||||
* }}
|
||||
*/
|
||||
export const requestDisableModeration = () => {
|
||||
return {
|
||||
type: REQUEST_DISABLE_MODERATION
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Requests enabled audio & video moderation.
|
||||
*
|
||||
* @returns {{
|
||||
* type: REQUEST_ENABLE_MODERATED_AUDIO
|
||||
* }}
|
||||
*/
|
||||
export const requestEnableModeration = () => {
|
||||
return {
|
||||
type: REQUEST_ENABLE_MODERATION
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Local participant was approved to be able to unmute audio and video.
|
||||
*
|
||||
* @param {MediaType} mediaType - The media type to disable.
|
||||
* @returns {{
|
||||
* type: LOCAL_PARTICIPANT_APPROVED
|
||||
* }}
|
||||
*/
|
||||
export const localParticipantApproved = (mediaType: MediaType) => {
|
||||
return {
|
||||
type: LOCAL_PARTICIPANT_APPROVED,
|
||||
mediaType
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows notification when A/V moderation is enabled and local participant is still not approved.
|
||||
*
|
||||
* @param {MediaType} mediaType - Audio or video media type.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function showModeratedNotification(mediaType: MediaType) {
|
||||
return {
|
||||
type: LOCAL_PARTICIPANT_MODERATION_NOTIFICATION,
|
||||
mediaType
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a notification with the participant that asked to audio unmute.
|
||||
*
|
||||
* @param {Object} participant - The participant for which is the notification.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function participantPendingAudio(participant: Object) {
|
||||
return {
|
||||
type: PARTICIPANT_PENDING_AUDIO,
|
||||
participant
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A participant was approved to unmute for a mediaType.
|
||||
*
|
||||
* @param {string} id - The id of the approved participant.
|
||||
* @param {MediaType} mediaType - The media type which was approved.
|
||||
* @returns {{
|
||||
* type: PARTICIPANT_APPROVED,
|
||||
* }}
|
||||
*/
|
||||
export function participantApproved(id: string, mediaType: MediaType) {
|
||||
return {
|
||||
type: PARTICIPANT_APPROVED,
|
||||
id,
|
||||
mediaType
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import NotificationWithParticipants from '../../notifications/components/web/NotificationWithParticipants';
|
||||
import {
|
||||
approveParticipant,
|
||||
dismissPendingAudioParticipant
|
||||
} from '../actions';
|
||||
import { getParticipantsAskingToAudioUnmute } from '../functions';
|
||||
|
||||
|
||||
/**
|
||||
* Component used to display a list of participants who asked to be unmuted.
|
||||
* This is visible only to moderators.
|
||||
*
|
||||
* @returns {React$Element<'ul'> | null}
|
||||
*/
|
||||
export default function() {
|
||||
const participants = useSelector(getParticipantsAskingToAudioUnmute);
|
||||
const { t } = useTranslation();
|
||||
|
||||
return participants.length
|
||||
? (
|
||||
<>
|
||||
<div className = 'title'>
|
||||
{ t('raisedHand') }
|
||||
</div>
|
||||
<NotificationWithParticipants
|
||||
approveButtonText = { t('notify.unmute') }
|
||||
onApprove = { approveParticipant }
|
||||
onReject = { dismissPendingAudioParticipant }
|
||||
participants = { participants }
|
||||
rejectButtonText = { t('dialog.dismiss') }
|
||||
testIdPrefix = 'avModeration' />
|
||||
</>
|
||||
) : null;
|
||||
}
|
||||
19
react/features/av-moderation/constants.js
Normal file
19
react/features/av-moderation/constants.js
Normal file
@@ -0,0 +1,19 @@
|
||||
// @flow
|
||||
|
||||
import { MEDIA_TYPE, type MediaType } from '../base/media/constants';
|
||||
|
||||
/**
|
||||
* Mapping between a media type and the witelist reducer key.
|
||||
*/
|
||||
export const MEDIA_TYPE_TO_WHITELIST_STORE_KEY: {[key: MediaType]: string} = {
|
||||
[MEDIA_TYPE.AUDIO]: 'audioWhitelist',
|
||||
[MEDIA_TYPE.VIDEO]: 'videoWhitelist'
|
||||
};
|
||||
|
||||
/**
|
||||
* Mapping between a media type and the pending reducer key.
|
||||
*/
|
||||
export const MEDIA_TYPE_TO_PENDING_STORE_KEY: {[key: MediaType]: string} = {
|
||||
[MEDIA_TYPE.AUDIO]: 'pendingAudio',
|
||||
[MEDIA_TYPE.VIDEO]: 'pendingVideo'
|
||||
};
|
||||
132
react/features/av-moderation/functions.js
Normal file
132
react/features/av-moderation/functions.js
Normal file
@@ -0,0 +1,132 @@
|
||||
// @flow
|
||||
|
||||
import { MEDIA_TYPE, type MediaType } from '../base/media/constants';
|
||||
import { isLocalParticipantModerator } from '../base/participants/functions';
|
||||
|
||||
import { MEDIA_TYPE_TO_WHITELIST_STORE_KEY, MEDIA_TYPE_TO_PENDING_STORE_KEY } from './constants';
|
||||
|
||||
/**
|
||||
* Returns this feature's root state.
|
||||
*
|
||||
* @param {Object} state - Global state.
|
||||
* @returns {Object} Feature state.
|
||||
*/
|
||||
const getState = state => state['features/av-moderation'];
|
||||
|
||||
/**
|
||||
* We use to construct once the empty array so we can keep the same instance between calls
|
||||
* of getParticipantsAskingToAudioUnmute.
|
||||
*
|
||||
* @type {*[]}
|
||||
*/
|
||||
const EMPTY_ARRAY = [];
|
||||
|
||||
/**
|
||||
* Returns whether moderation is enabled per media type.
|
||||
*
|
||||
* @param {MEDIA_TYPE} mediaType - The media type to check.
|
||||
* @param {Object} state - Global state.
|
||||
* @returns {null|boolean|*}
|
||||
*/
|
||||
export const isEnabledFromState = (mediaType: MediaType, state: Object) =>
|
||||
(mediaType === MEDIA_TYPE.AUDIO
|
||||
? getState(state)?.audioModerationEnabled
|
||||
: getState(state)?.videoModerationEnabled) === true;
|
||||
|
||||
/**
|
||||
* Returns whether moderation is enabled per media type.
|
||||
*
|
||||
* @param {MEDIA_TYPE} mediaType - The media type to check.
|
||||
* @returns {null|boolean|*}
|
||||
*/
|
||||
export const isEnabled = (mediaType: MediaType) => (state: Object) => isEnabledFromState(mediaType, state);
|
||||
|
||||
/**
|
||||
* Returns whether moderation is supported by the backend.
|
||||
*
|
||||
* @returns {null|boolean}
|
||||
*/
|
||||
export const isSupported = () => (state: Object) => {
|
||||
const { conference } = state['features/base/conference'];
|
||||
|
||||
return conference ? conference.isAVModerationSupported() : false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether local participant is approved to unmute a media type.
|
||||
*
|
||||
* @param {MEDIA_TYPE} mediaType - The media type to check.
|
||||
* @param {Object} state - Global state.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isLocalParticipantApprovedFromState = (mediaType: MediaType, state: Object) => {
|
||||
const approved = (mediaType === MEDIA_TYPE.AUDIO
|
||||
? getState(state).audioUnmuteApproved
|
||||
: getState(state).videoUnmuteApproved) === true;
|
||||
|
||||
return approved || isLocalParticipantModerator(state);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether local participant is approved to unmute a media type.
|
||||
*
|
||||
* @param {MEDIA_TYPE} mediaType - The media type to check.
|
||||
* @returns {null|boolean|*}
|
||||
*/
|
||||
export const isLocalParticipantApproved = (mediaType: MediaType) =>
|
||||
(state: Object) =>
|
||||
isLocalParticipantApprovedFromState(mediaType, state);
|
||||
|
||||
/**
|
||||
* Returns a selector creator which determines if the participant is approved or not for a media type.
|
||||
*
|
||||
* @param {string} id - The participant id.
|
||||
* @param {MEDIA_TYPE} mediaType - The media type to check.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isParticipantApproved = (id: string, mediaType: MediaType) => (state: Object) => {
|
||||
const storeKey = MEDIA_TYPE_TO_WHITELIST_STORE_KEY[mediaType];
|
||||
|
||||
return Boolean(getState(state)[storeKey][id]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a selector creator which determines if the participant is pending or not for a media type.
|
||||
*
|
||||
* @param {Participant} participant - The participant.
|
||||
* @param {MEDIA_TYPE} mediaType - The media type to check.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isParticipantPending = (participant: Object, mediaType: MediaType) => (state: Object) => {
|
||||
const storeKey = MEDIA_TYPE_TO_PENDING_STORE_KEY[mediaType];
|
||||
const arr = getState(state)[storeKey];
|
||||
|
||||
return Boolean(arr.find(pending => pending.id === participant.id));
|
||||
};
|
||||
|
||||
/**
|
||||
* Selector which returns a list with all the participants asking to audio unmute.
|
||||
* This is visible ony for the moderator.
|
||||
*
|
||||
* @param {Object} state - The global state.
|
||||
* @returns {Array<Object>}
|
||||
*/
|
||||
export const getParticipantsAskingToAudioUnmute = (state: Object) => {
|
||||
if (isLocalParticipantModerator(state)) {
|
||||
return getState(state).pendingAudio;
|
||||
}
|
||||
|
||||
return EMPTY_ARRAY;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if a special notification can be displayed when a participant
|
||||
* tries to unmute.
|
||||
*
|
||||
* @param {MediaType} mediaType - 'audio' or 'video' media type.
|
||||
* @param {Object} state - The global state.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const shouldShowModeratedNotification = (mediaType: MediaType, state: Object) =>
|
||||
isEnabledFromState(mediaType, state)
|
||||
&& !isLocalParticipantApprovedFromState(mediaType, state);
|
||||
192
react/features/av-moderation/middleware.js
Normal file
192
react/features/av-moderation/middleware.js
Normal file
@@ -0,0 +1,192 @@
|
||||
// @flow
|
||||
import { batch } from 'react-redux';
|
||||
|
||||
import { getConferenceState } from '../base/conference';
|
||||
import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
|
||||
import { MEDIA_TYPE } from '../base/media';
|
||||
import {
|
||||
getParticipantDisplayName,
|
||||
isLocalParticipantModerator,
|
||||
PARTICIPANT_UPDATED,
|
||||
raiseHand
|
||||
} from '../base/participants';
|
||||
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
|
||||
import {
|
||||
hideNotification,
|
||||
NOTIFICATION_TIMEOUT,
|
||||
showNotification
|
||||
} from '../notifications';
|
||||
|
||||
import {
|
||||
DISABLE_MODERATION,
|
||||
ENABLE_MODERATION,
|
||||
LOCAL_PARTICIPANT_MODERATION_NOTIFICATION,
|
||||
REQUEST_DISABLE_MODERATION,
|
||||
REQUEST_ENABLE_MODERATION
|
||||
} from './actionTypes';
|
||||
import {
|
||||
disableModeration,
|
||||
dismissPendingParticipant,
|
||||
dismissPendingAudioParticipant,
|
||||
enableModeration,
|
||||
localParticipantApproved,
|
||||
participantApproved,
|
||||
participantPendingAudio
|
||||
} from './actions';
|
||||
import {
|
||||
isEnabledFromState,
|
||||
isParticipantApproved,
|
||||
isParticipantPending
|
||||
} from './functions';
|
||||
|
||||
const VIDEO_MODERATION_NOTIFICATION_ID = 'video-moderation';
|
||||
const AUDIO_MODERATION_NOTIFICATION_ID = 'audio-moderation';
|
||||
const CS_MODERATION_NOTIFICATION_ID = 'video-moderation';
|
||||
|
||||
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
const { actor, mediaType, type } = action;
|
||||
|
||||
switch (type) {
|
||||
case DISABLE_MODERATION:
|
||||
case ENABLE_MODERATION: {
|
||||
// Audio & video moderation are both enabled at the same time.
|
||||
// Avoid displaying 2 different notifications.
|
||||
if (mediaType === MEDIA_TYPE.VIDEO) {
|
||||
const titleKey = type === ENABLE_MODERATION
|
||||
? 'notify.moderationStartedTitle'
|
||||
: 'notify.moderationStoppedTitle';
|
||||
|
||||
dispatch(showNotification({
|
||||
descriptionKey: actor ? 'notify.moderationToggleDescription' : undefined,
|
||||
descriptionArguments: actor ? {
|
||||
participantDisplayName: getParticipantDisplayName(getState, actor.getId())
|
||||
} : undefined,
|
||||
titleKey
|
||||
}, NOTIFICATION_TIMEOUT));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case LOCAL_PARTICIPANT_MODERATION_NOTIFICATION: {
|
||||
let descriptionKey;
|
||||
let titleKey;
|
||||
let uid;
|
||||
|
||||
switch (action.mediaType) {
|
||||
case MEDIA_TYPE.AUDIO: {
|
||||
titleKey = 'notify.moderationInEffectTitle';
|
||||
descriptionKey = 'notify.moderationInEffectDescription';
|
||||
uid = AUDIO_MODERATION_NOTIFICATION_ID;
|
||||
break;
|
||||
}
|
||||
case MEDIA_TYPE.VIDEO: {
|
||||
titleKey = 'notify.moderationInEffectVideoTitle';
|
||||
descriptionKey = 'notify.moderationInEffectVideoDescription';
|
||||
uid = VIDEO_MODERATION_NOTIFICATION_ID;
|
||||
break;
|
||||
}
|
||||
case MEDIA_TYPE.PRESENTER: {
|
||||
titleKey = 'notify.moderationInEffectCSTitle';
|
||||
descriptionKey = 'notify.moderationInEffectCSDescription';
|
||||
uid = CS_MODERATION_NOTIFICATION_ID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(showNotification({
|
||||
customActionNameKey: 'notify.raiseHandAction',
|
||||
customActionHandler: () => batch(() => {
|
||||
dispatch(raiseHand(true));
|
||||
dispatch(hideNotification(uid));
|
||||
}),
|
||||
descriptionKey,
|
||||
sticky: true,
|
||||
titleKey,
|
||||
uid
|
||||
}));
|
||||
|
||||
break;
|
||||
}
|
||||
case REQUEST_DISABLE_MODERATION: {
|
||||
const { conference } = getConferenceState(getState());
|
||||
|
||||
conference.disableAVModeration(MEDIA_TYPE.AUDIO);
|
||||
conference.disableAVModeration(MEDIA_TYPE.VIDEO);
|
||||
break;
|
||||
}
|
||||
case REQUEST_ENABLE_MODERATION: {
|
||||
const { conference } = getConferenceState(getState());
|
||||
|
||||
conference.enableAVModeration(MEDIA_TYPE.AUDIO);
|
||||
conference.enableAVModeration(MEDIA_TYPE.VIDEO);
|
||||
break;
|
||||
}
|
||||
case PARTICIPANT_UPDATED: {
|
||||
const state = getState();
|
||||
const audioModerationEnabled = isEnabledFromState(MEDIA_TYPE.AUDIO, state);
|
||||
|
||||
// this is handled only by moderators
|
||||
if (audioModerationEnabled && isLocalParticipantModerator(state)) {
|
||||
const participant = action.participant;
|
||||
|
||||
if (participant.raisedHand) {
|
||||
// if participant raises hand show notification
|
||||
!isParticipantApproved(participant.id, MEDIA_TYPE.AUDIO)(state)
|
||||
&& dispatch(participantPendingAudio(participant));
|
||||
} else {
|
||||
// if participant lowers hand hide notification
|
||||
isParticipantPending(participant, MEDIA_TYPE.AUDIO)(state)
|
||||
&& dispatch(dismissPendingAudioParticipant(participant));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return next(action);
|
||||
});
|
||||
|
||||
/**
|
||||
* Registers a change handler for state['features/base/conference'].conference to
|
||||
* set the event listeners needed for the A/V moderation feature to operate.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
state => state['features/base/conference'].conference,
|
||||
(conference, { dispatch }, previousConference) => {
|
||||
if (conference && !previousConference) {
|
||||
// local participant is allowed to unmute
|
||||
conference.on(JitsiConferenceEvents.AV_MODERATION_APPROVED, ({ mediaType }) => {
|
||||
dispatch(localParticipantApproved(mediaType));
|
||||
|
||||
// Audio & video moderation are both enabled at the same time.
|
||||
// Avoid displaying 2 different notifications.
|
||||
if (mediaType === MEDIA_TYPE.VIDEO) {
|
||||
dispatch(showNotification({
|
||||
titleKey: 'notify.unmute',
|
||||
descriptionKey: 'notify.hostAskedUnmute',
|
||||
sticky: true
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
conference.on(JitsiConferenceEvents.AV_MODERATION_CHANGED, ({ enabled, mediaType, actor }) => {
|
||||
enabled ? dispatch(enableModeration(mediaType, actor)) : dispatch(disableModeration(mediaType, actor));
|
||||
});
|
||||
|
||||
// this is received by moderators
|
||||
conference.on(
|
||||
JitsiConferenceEvents.AV_MODERATION_PARTICIPANT_APPROVED,
|
||||
({ participant, mediaType }) => {
|
||||
const { _id: id } = participant;
|
||||
|
||||
batch(() => {
|
||||
// store in the whitelist
|
||||
dispatch(participantApproved(id, mediaType));
|
||||
|
||||
// remove from pending list
|
||||
dispatch(dismissPendingParticipant(id, mediaType));
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
234
react/features/av-moderation/reducer.js
Normal file
234
react/features/av-moderation/reducer.js
Normal file
@@ -0,0 +1,234 @@
|
||||
/* @flow */
|
||||
|
||||
import { MEDIA_TYPE } from '../base/media/constants';
|
||||
import type { MediaType } from '../base/media/constants';
|
||||
import {
|
||||
PARTICIPANT_LEFT,
|
||||
PARTICIPANT_UPDATED
|
||||
} from '../base/participants';
|
||||
import { ReducerRegistry } from '../base/redux';
|
||||
|
||||
import {
|
||||
DISABLE_MODERATION,
|
||||
DISMISS_PENDING_PARTICIPANT,
|
||||
ENABLE_MODERATION,
|
||||
LOCAL_PARTICIPANT_APPROVED,
|
||||
PARTICIPANT_APPROVED,
|
||||
PARTICIPANT_PENDING_AUDIO
|
||||
} from './actionTypes';
|
||||
import { MEDIA_TYPE_TO_PENDING_STORE_KEY } from './constants';
|
||||
|
||||
const initialState = {
|
||||
audioModerationEnabled: false,
|
||||
videoModerationEnabled: false,
|
||||
audioWhitelist: {},
|
||||
videoWhitelist: {},
|
||||
pendingAudio: [],
|
||||
pendingVideo: []
|
||||
};
|
||||
|
||||
/**
|
||||
Updates a participant in the state for the specified media type.
|
||||
*
|
||||
* @param {MediaType} mediaType - The media type.
|
||||
* @param {Object} participant - Information about participant to be modified.
|
||||
* @param {Object} state - The current state.
|
||||
* @private
|
||||
* @returns {boolean} - Whether state instance was modified.
|
||||
*/
|
||||
function _updatePendingParticipant(mediaType: MediaType, participant, state: Object = {}) {
|
||||
let arrayItemChanged = false;
|
||||
const storeKey = MEDIA_TYPE_TO_PENDING_STORE_KEY[mediaType];
|
||||
const arr = state[storeKey];
|
||||
const newArr = arr.map(pending => {
|
||||
if (pending.id === participant.id) {
|
||||
arrayItemChanged = true;
|
||||
|
||||
return {
|
||||
...pending,
|
||||
...participant
|
||||
};
|
||||
}
|
||||
|
||||
return pending;
|
||||
});
|
||||
|
||||
if (arrayItemChanged) {
|
||||
state[storeKey] = newArr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ReducerRegistry.register('features/av-moderation', (state = initialState, action) => {
|
||||
|
||||
switch (action.type) {
|
||||
case DISABLE_MODERATION: {
|
||||
const newState = action.mediaType === MEDIA_TYPE.AUDIO
|
||||
? {
|
||||
audioModerationEnabled: false,
|
||||
audioUnmuteApproved: undefined
|
||||
} : {
|
||||
videoModerationEnabled: false,
|
||||
videoUnmuteApproved: undefined
|
||||
};
|
||||
|
||||
return {
|
||||
...state,
|
||||
...newState,
|
||||
audioWhitelist: {},
|
||||
videoWhitelist: {},
|
||||
pendingAudio: [],
|
||||
pendingVideo: []
|
||||
};
|
||||
}
|
||||
|
||||
case ENABLE_MODERATION: {
|
||||
const newState = action.mediaType === MEDIA_TYPE.AUDIO
|
||||
? { audioModerationEnabled: true } : { videoModerationEnabled: true };
|
||||
|
||||
return {
|
||||
...state,
|
||||
...newState
|
||||
};
|
||||
}
|
||||
|
||||
case LOCAL_PARTICIPANT_APPROVED: {
|
||||
const newState = action.mediaType === MEDIA_TYPE.AUDIO
|
||||
? { audioUnmuteApproved: true } : { videoUnmuteApproved: true };
|
||||
|
||||
return {
|
||||
...state,
|
||||
...newState
|
||||
};
|
||||
}
|
||||
|
||||
case PARTICIPANT_PENDING_AUDIO: {
|
||||
const { participant } = action;
|
||||
|
||||
// Add participant to pendingAudio array only if it's not already added
|
||||
if (!state.pendingAudio.find(pending => pending.id === participant.id)) {
|
||||
const updated = [ ...state.pendingAudio ];
|
||||
|
||||
updated.push(participant);
|
||||
|
||||
return {
|
||||
...state,
|
||||
pendingAudio: updated
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
case PARTICIPANT_UPDATED: {
|
||||
const participant = action.participant;
|
||||
const { audioModerationEnabled, videoModerationEnabled } = state;
|
||||
let hasStateChanged = false;
|
||||
|
||||
// skips changing the reference of pendingAudio or pendingVideo,
|
||||
// if there is no change in the elements
|
||||
if (audioModerationEnabled) {
|
||||
hasStateChanged = _updatePendingParticipant(MEDIA_TYPE.AUDIO, participant, state);
|
||||
}
|
||||
|
||||
if (videoModerationEnabled) {
|
||||
hasStateChanged = _updatePendingParticipant(MEDIA_TYPE.VIDEO, participant, state);
|
||||
}
|
||||
|
||||
// If the state has changed we need to return a new object reference in order to trigger subscriber updates.
|
||||
if (hasStateChanged) {
|
||||
return {
|
||||
...state
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
case PARTICIPANT_LEFT: {
|
||||
const participant = action.participant;
|
||||
const { audioModerationEnabled, videoModerationEnabled } = state;
|
||||
let hasStateChanged = false;
|
||||
|
||||
// skips changing the reference of pendingAudio or pendingVideo,
|
||||
// if there is no change in the elements
|
||||
if (audioModerationEnabled) {
|
||||
const newPendingAudio = state.pendingAudio.filter(pending => pending.id !== participant.id);
|
||||
|
||||
if (state.pendingAudio.length !== newPendingAudio.length) {
|
||||
state.pendingAudio = newPendingAudio;
|
||||
hasStateChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (videoModerationEnabled) {
|
||||
const newPendingVideo = state.pendingVideo.filter(pending => pending.id !== participant.id);
|
||||
|
||||
if (state.pendingVideo.length !== newPendingVideo.length) {
|
||||
state.pendingVideo = newPendingVideo;
|
||||
hasStateChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the state has changed we need to return a new object reference in order to trigger subscriber updates.
|
||||
if (hasStateChanged) {
|
||||
return {
|
||||
...state
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
case DISMISS_PENDING_PARTICIPANT: {
|
||||
const { participant, mediaType } = action;
|
||||
|
||||
if (mediaType === MEDIA_TYPE.AUDIO) {
|
||||
return {
|
||||
...state,
|
||||
pendingAudio: state.pendingAudio.filter(pending => pending.id !== participant.id)
|
||||
};
|
||||
}
|
||||
|
||||
if (mediaType === MEDIA_TYPE.VIDEO) {
|
||||
return {
|
||||
...state,
|
||||
pendingVideo: state.pendingVideo.filter(pending => pending.id !== participant.id)
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
case PARTICIPANT_APPROVED: {
|
||||
const { mediaType, id } = action;
|
||||
|
||||
if (mediaType === MEDIA_TYPE.AUDIO) {
|
||||
return {
|
||||
...state,
|
||||
audioWhitelist: {
|
||||
...state.audioWhitelist,
|
||||
[id]: true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (mediaType === MEDIA_TYPE.VIDEO) {
|
||||
return {
|
||||
...state,
|
||||
videoWhitelist: {
|
||||
...state.videoWhitelist,
|
||||
[id]: true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return state;
|
||||
});
|
||||
@@ -10,6 +10,11 @@ import { StatelessAvatar } from '.';
|
||||
|
||||
export type Props = {
|
||||
|
||||
/**
|
||||
* Custom avatar backgrounds from branding.
|
||||
*/
|
||||
_customAvatarBackgrounds: Array<string>,
|
||||
|
||||
/**
|
||||
* The string we base the initials on (this is generated from a list of precedences).
|
||||
*/
|
||||
@@ -133,6 +138,7 @@ class Avatar<P: Props> extends PureComponent<P, State> {
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
_customAvatarBackgrounds,
|
||||
_initialsBase,
|
||||
_loadableAvatarUrl,
|
||||
className,
|
||||
@@ -172,7 +178,7 @@ class Avatar<P: Props> extends PureComponent<P, State> {
|
||||
|
||||
if (initials) {
|
||||
if (dynamicColor) {
|
||||
avatarProps.color = getAvatarColor(colorBase || _initialsBase);
|
||||
avatarProps.color = getAvatarColor(colorBase || _initialsBase, _customAvatarBackgrounds);
|
||||
}
|
||||
|
||||
avatarProps.initials = initials;
|
||||
@@ -211,6 +217,7 @@ export function _mapStateToProps(state: Object, ownProps: Props) {
|
||||
const _initialsBase = _participant?.name ?? displayName;
|
||||
|
||||
return {
|
||||
_customAvatarBackgrounds: state['features/dynamic-branding'].avatarBackgrounds,
|
||||
_initialsBase,
|
||||
_loadableAvatarUrl: _participant?.loadableAvatarUrl,
|
||||
colorBase: !colorBase && _participant ? _participant.id : colorBase
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { Icon } from '../../../icons';
|
||||
import AbstractStatelessAvatar, { type Props as AbstractProps } from '../AbstractStatelessAvatar';
|
||||
|
||||
@@ -31,19 +30,14 @@ type Props = AbstractProps & {
|
||||
/**
|
||||
* TestId of the element, if any.
|
||||
*/
|
||||
testId?: string,
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: Function
|
||||
testId?: string
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a stateless avatar component that renders an avatar purely from what gets passed through
|
||||
* props.
|
||||
*/
|
||||
class StatelessAvatar extends AbstractStatelessAvatar<Props> {
|
||||
export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
|
||||
/**
|
||||
* Implements {@code Component#render}.
|
||||
*
|
||||
@@ -70,7 +64,7 @@ class StatelessAvatar extends AbstractStatelessAvatar<Props> {
|
||||
return (
|
||||
<div className = { this._getBadgeClassName() }>
|
||||
<img
|
||||
alt = { this.props.t('profile.avatar') }
|
||||
alt = 'avatar'
|
||||
className = { this._getAvatarClassName() }
|
||||
data-testid = { this.props.testId }
|
||||
id = { this.props.id }
|
||||
@@ -111,7 +105,7 @@ class StatelessAvatar extends AbstractStatelessAvatar<Props> {
|
||||
return (
|
||||
<div className = { this._getBadgeClassName() }>
|
||||
<img
|
||||
alt = { this.props.t('profile.avatar') }
|
||||
alt = 'avatar'
|
||||
className = { this._getAvatarClassName('defaultAvatar') }
|
||||
data-testid = { this.props.testId }
|
||||
id = { this.props.id }
|
||||
@@ -131,7 +125,7 @@ class StatelessAvatar extends AbstractStatelessAvatar<Props> {
|
||||
const { size } = this.props;
|
||||
|
||||
return {
|
||||
backgroundColor: color || undefined,
|
||||
background: color || undefined,
|
||||
fontSize: size ? size * 0.5 : '180%',
|
||||
height: size || '100%',
|
||||
width: size || '100%'
|
||||
@@ -165,5 +159,3 @@ class StatelessAvatar extends AbstractStatelessAvatar<Props> {
|
||||
|
||||
_isIcon: (?string | ?Object) => boolean
|
||||
}
|
||||
|
||||
export default translate(StatelessAvatar);
|
||||
|
||||
@@ -16,9 +16,13 @@ const AVATAR_OPACITY = 0.4;
|
||||
* Generates the background color of an initials based avatar.
|
||||
*
|
||||
* @param {string?} initials - The initials of the avatar.
|
||||
* @param {Array<strig>} customAvatarBackgrounds - Custom avatar background values.
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getAvatarColor(initials: ?string) {
|
||||
export function getAvatarColor(initials: ?string, customAvatarBackgrounds: Array<string>) {
|
||||
const hasCustomAvatarBackgronds = customAvatarBackgrounds && customAvatarBackgrounds.length;
|
||||
const colorsBase = hasCustomAvatarBackgronds ? customAvatarBackgrounds : AVATAR_COLORS;
|
||||
|
||||
let colorIndex = 0;
|
||||
|
||||
if (initials) {
|
||||
@@ -28,10 +32,10 @@ export function getAvatarColor(initials: ?string) {
|
||||
nameHash += s.codePointAt(0);
|
||||
}
|
||||
|
||||
colorIndex = nameHash % AVATAR_COLORS.length;
|
||||
colorIndex = nameHash % colorsBase.length;
|
||||
}
|
||||
|
||||
return `rgba(${AVATAR_COLORS[colorIndex]}, ${AVATAR_OPACITY})`;
|
||||
return hasCustomAvatarBackgronds ? colorsBase[colorIndex] : `rgba(${colorsBase[colorIndex]}, ${AVATAR_OPACITY})`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
createStartMutedConfigurationEvent,
|
||||
sendAnalytics
|
||||
} from '../../analytics';
|
||||
import { getName } from '../../app/functions';
|
||||
import { endpointMessageReceived } from '../../subtitles';
|
||||
import { getReplaceParticipant } from '../config/functions';
|
||||
import { JITSI_CONNECTION_CONFERENCE_KEY } from '../connection';
|
||||
@@ -14,7 +13,6 @@ import { JitsiConferenceEvents } from '../lib-jitsi-meet';
|
||||
import { MEDIA_TYPE, setAudioMuted, setVideoMuted } from '../media';
|
||||
import {
|
||||
dominantSpeakerChanged,
|
||||
getLocalParticipant,
|
||||
getNormalizedDisplayName,
|
||||
participantConnectionStatusChanged,
|
||||
participantKicked,
|
||||
@@ -24,11 +22,7 @@ import {
|
||||
participantUpdated
|
||||
} from '../participants';
|
||||
import { getLocalTracks, replaceLocalTrack, trackAdded, trackRemoved } from '../tracks';
|
||||
import {
|
||||
getBackendSafePath,
|
||||
getBackendSafeRoomName,
|
||||
getJitsiMeetGlobalNS
|
||||
} from '../util';
|
||||
import { getBackendSafeRoomName } from '../util';
|
||||
|
||||
import {
|
||||
AUTH_STATUS_CHANGED,
|
||||
@@ -61,6 +55,7 @@ import {
|
||||
_addLocalTracksToConference,
|
||||
commonUserJoinedHandling,
|
||||
commonUserLeftHandling,
|
||||
getConferenceOptions,
|
||||
getCurrentConference,
|
||||
sendLocalParticipant
|
||||
} from './functions';
|
||||
@@ -434,22 +429,7 @@ export function createConference() {
|
||||
throw new Error('Cannot join a conference without a room name!');
|
||||
}
|
||||
|
||||
const config = state['features/base/config'];
|
||||
const { tenant } = state['features/base/jwt'];
|
||||
const { email, name: nick } = getLocalParticipant(state);
|
||||
|
||||
const conference
|
||||
= connection.initJitsiConference(
|
||||
|
||||
getBackendSafeRoomName(room), {
|
||||
...config,
|
||||
applicationName: getName(),
|
||||
getWiFiStatsMethod: getJitsiMeetGlobalNS().getWiFiStats,
|
||||
confID: `${locationURL.host}${getBackendSafePath(locationURL.pathname)}`,
|
||||
siteID: tenant,
|
||||
statisticsDisplayName: config.enableDisplayNameInStats ? nick : undefined,
|
||||
statisticsId: config.enableEmailInStats ? email : undefined
|
||||
});
|
||||
const conference = connection.initJitsiConference(getBackendSafeRoomName(room), getConferenceOptions(state));
|
||||
|
||||
connection[JITSI_CONNECTION_CONFERENCE_KEY] = conference;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
import { getName } from '../../app/functions';
|
||||
import { JitsiTrackErrors } from '../lib-jitsi-meet';
|
||||
import {
|
||||
getLocalParticipant,
|
||||
@@ -11,7 +12,7 @@ import {
|
||||
participantLeft
|
||||
} from '../participants';
|
||||
import { toState } from '../redux';
|
||||
import { safeDecodeURIComponent } from '../util';
|
||||
import { getBackendSafePath, getJitsiMeetGlobalNS, safeDecodeURIComponent } from '../util';
|
||||
|
||||
import {
|
||||
AVATAR_URL_COMMAND,
|
||||
@@ -198,6 +199,53 @@ export function getConferenceNameForTitle(stateful: Function | Object) {
|
||||
return safeStartCase(safeDecodeURIComponent(getConferenceState(toState(stateful)).room));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object aggregating the conference options.
|
||||
*
|
||||
* @param {Object|Function} stateful - The redux store state.
|
||||
* @returns {Object} - Options object.
|
||||
*/
|
||||
export function getConferenceOptions(stateful: Function | Object) {
|
||||
const state = toState(stateful);
|
||||
|
||||
const config = state['features/base/config'];
|
||||
const { locationURL } = state['features/base/connection'];
|
||||
const { tenant } = state['features/base/jwt'];
|
||||
const { email, name: nick } = getLocalParticipant(state);
|
||||
const options = { ...config };
|
||||
|
||||
if (tenant) {
|
||||
options.siteID = tenant;
|
||||
}
|
||||
|
||||
if (options.enableDisplayNameInStats && nick) {
|
||||
options.statisticsDisplayName = nick;
|
||||
}
|
||||
|
||||
if (options.enableEmailInStats && email) {
|
||||
options.statisticsId = email;
|
||||
}
|
||||
|
||||
if (locationURL) {
|
||||
options.confID = `${locationURL.host}${getBackendSafePath(locationURL.pathname)}`;
|
||||
}
|
||||
|
||||
options.applicationName = getName();
|
||||
|
||||
// Disable analytics, if requessted.
|
||||
if (options.disableThirdPartyRequests) {
|
||||
delete config.analytics.scriptURLs;
|
||||
delete config.analytics.amplitudeAPPKey;
|
||||
delete config.analytics.googleAnalyticsTrackingId;
|
||||
delete options.callStatsID;
|
||||
delete options.callStatsSecret;
|
||||
} else {
|
||||
options.getWiFiStatsMethod = getWiFiStatsMethod;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UTC timestamp when the first participant joined the conference.
|
||||
*
|
||||
@@ -244,6 +292,21 @@ export function getRoomName(state: Object): string {
|
||||
return getConferenceState(state).room;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result of getWiFiStats from the global NS or does nothing
|
||||
* (returns empty result).
|
||||
* Fixes a concurrency problem where we need to pass a function when creating
|
||||
* a JitsiConference, but that method is added to the context later.
|
||||
*
|
||||
* @returns {Promise}
|
||||
* @private
|
||||
*/
|
||||
function getWiFiStatsMethod() {
|
||||
const gloabalNS = getJitsiMeetGlobalNS();
|
||||
|
||||
return gloabalNS.getWiFiStats ? gloabalNS.getWiFiStats() : Promise.resolve('{}');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an error thrown by the backend (i.e. {@code lib-jitsi-meet}) while
|
||||
* manipulating a conference participant (e.g. Pin or select participant).
|
||||
|
||||
@@ -398,10 +398,9 @@ function _pinParticipant({ getState }, next, action) {
|
||||
return next(action);
|
||||
}
|
||||
|
||||
const participants = state['features/base/participants'];
|
||||
const id = action.participant.id;
|
||||
const participantById = getParticipantById(participants, id);
|
||||
const pinnedParticipant = getPinnedParticipant(participants);
|
||||
const participantById = getParticipantById(state, id);
|
||||
const pinnedParticipant = getPinnedParticipant(state);
|
||||
const actionName = id ? ACTION_PINNED : ACTION_UNPINNED;
|
||||
const local
|
||||
= (participantById && participantById.local)
|
||||
|
||||
@@ -87,6 +87,7 @@ export default [
|
||||
'disableH264',
|
||||
'disableHPF',
|
||||
'disableInviteFunctions',
|
||||
'disableIncomingMessageSound',
|
||||
'disableJoinLeaveSounds',
|
||||
'disableLocalVideoFlip',
|
||||
'disableNS',
|
||||
@@ -96,6 +97,7 @@ export default [
|
||||
'disableResponsiveTiles',
|
||||
'disableRtx',
|
||||
'disableShortcuts',
|
||||
'disableShowMoreStats',
|
||||
'disableSimulcast',
|
||||
'disableThirdPartyRequests',
|
||||
'disableTileView',
|
||||
@@ -112,6 +114,7 @@ export default [
|
||||
'enableLipSync',
|
||||
'enableOpusRed',
|
||||
'enableRemb',
|
||||
'enableSaveLogs',
|
||||
'enableScreenshotCapture',
|
||||
'enableTalkWhileMuted',
|
||||
'enableNoAudioDetection',
|
||||
@@ -128,6 +131,7 @@ export default [
|
||||
'gatherStats',
|
||||
'googleApiApplicationClientID',
|
||||
'hideConferenceSubject',
|
||||
'hideRecordingLabel',
|
||||
'hideParticipantsStats',
|
||||
'hideConferenceTimer',
|
||||
'hiddenDomain',
|
||||
@@ -148,6 +152,7 @@ export default [
|
||||
'p2p',
|
||||
'pcStatsInterval',
|
||||
'preferH264',
|
||||
'preferredCodec',
|
||||
'prejoinPageEnabled',
|
||||
'requireDisplayName',
|
||||
'remoteVideoMenu',
|
||||
|
||||
@@ -14,10 +14,35 @@ export const _CONFIG_STORE_PREFIX = 'config.js';
|
||||
* @type Array<string>
|
||||
*/
|
||||
export const TOOLBAR_BUTTONS = [
|
||||
'microphone', 'camera', 'closedcaptions', 'desktop', 'embedmeeting', 'fullscreen',
|
||||
'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
|
||||
'livestreaming', 'etherpad', 'sharedvideo', 'shareaudio', 'settings', 'raisehand',
|
||||
'videoquality', 'filmstrip', 'participants-pane', 'feedback', 'stats', 'shortcuts',
|
||||
'tileview', 'select-background', 'download', 'help', 'mute-everyone', 'mute-video-everyone',
|
||||
'security', 'toggle-camera'
|
||||
'camera',
|
||||
'chat',
|
||||
'closedcaptions',
|
||||
'desktop',
|
||||
'download',
|
||||
'embedmeeting',
|
||||
'etherpad',
|
||||
'feedback',
|
||||
'filmstrip',
|
||||
'fullscreen',
|
||||
'hangup',
|
||||
'help',
|
||||
'invite',
|
||||
'livestreaming',
|
||||
'microphone',
|
||||
'mute-everyone',
|
||||
'mute-video-everyone',
|
||||
'participants-pane',
|
||||
'profile',
|
||||
'raisehand',
|
||||
'recording',
|
||||
'security',
|
||||
'select-background',
|
||||
'settings',
|
||||
'shareaudio',
|
||||
'sharedvideo',
|
||||
'shortcuts',
|
||||
'stats',
|
||||
'tileview',
|
||||
'toggle-camera',
|
||||
'videoquality'
|
||||
];
|
||||
|
||||
@@ -60,8 +60,6 @@ export function getRecordingSharingUrl(state: Object) {
|
||||
return state['features/base/config'].recordingSharingUrl;
|
||||
}
|
||||
|
||||
/* eslint-disable max-params, no-shadow */
|
||||
|
||||
/**
|
||||
* Overrides JSON properties in {@code config} and
|
||||
* {@code interfaceConfig} Objects with the values from {@code newConfig}.
|
||||
|
||||
@@ -56,12 +56,15 @@ export function getToolbarButtons(state: Object): Array<string> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Curried selector to check if the specified button is enabled.
|
||||
* Checks if the specified button is enabled.
|
||||
*
|
||||
* @param {string} buttonName - The name of the button.
|
||||
* {@link interfaceConfig}.
|
||||
* @returns {Function} - Selector that returns a boolean.
|
||||
* @param {Object|Array<string>} state - The redux state or the array with the enabled buttons.
|
||||
* @returns {boolean} - True if the button is enabled and false otherwise.
|
||||
*/
|
||||
export const isToolbarButtonEnabled = (buttonName: string) =>
|
||||
(state: Object): boolean =>
|
||||
getToolbarButtons(state).includes(buttonName);
|
||||
export function isToolbarButtonEnabled(buttonName: string, state: Object | Array<string>) {
|
||||
const buttons = Array.isArray(state) ? state : getToolbarButtons(state);
|
||||
|
||||
return buttons.includes(buttonName);
|
||||
}
|
||||
|
||||
@@ -53,3 +53,5 @@ export const CONNECTION_WILL_CONNECT = 'CONNECTION_WILL_CONNECT';
|
||||
* }
|
||||
*/
|
||||
export const SET_LOCATION_URL = 'SET_LOCATION_URL';
|
||||
|
||||
export const SHOW_CONNECTION_INFO = 'SHOW_CONNECTION_INFO';
|
||||
|
||||
@@ -9,7 +9,8 @@ import {
|
||||
CONNECTION_ESTABLISHED,
|
||||
CONNECTION_FAILED,
|
||||
CONNECTION_WILL_CONNECT,
|
||||
SET_LOCATION_URL
|
||||
SET_LOCATION_URL,
|
||||
SHOW_CONNECTION_INFO
|
||||
} from './actionTypes';
|
||||
import type { ConnectionFailedError } from './actions.native';
|
||||
|
||||
@@ -37,6 +38,9 @@ ReducerRegistry.register(
|
||||
|
||||
case SET_ROOM:
|
||||
return _setRoom(state);
|
||||
|
||||
case SHOW_CONNECTION_INFO:
|
||||
return _setShowConnectionInfo(state, action);
|
||||
}
|
||||
|
||||
return state;
|
||||
@@ -195,3 +199,19 @@ function _setRoom(state: Object) {
|
||||
passwordRequired: undefined
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces a specific redux action {@link SHOW_CONNECTION_INFO} of the feature
|
||||
* base/connection.
|
||||
*
|
||||
* @param {Object} state - The redux state of the feature base/connection.
|
||||
* @param {Action} action - The redux action {@code SHOW_CONNECTION_INFO} to reduce.
|
||||
* @private
|
||||
* @returns {Object} The new state of the feature base/connection after the
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _setShowConnectionInfo(
|
||||
state: Object,
|
||||
{ showConnectionInfo }: { showConnectionInfo: boolean }) {
|
||||
return set(state, 'showConnectionInfo', showConnectionInfo);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { type ReactionEmojiProps } from '../../../reactions/constants';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link DialogContainer}.
|
||||
*/
|
||||
@@ -25,7 +27,12 @@ type Props = {
|
||||
/**
|
||||
* True if the UI is in a compact state where we don't show dialogs.
|
||||
*/
|
||||
_reducedUI: boolean
|
||||
_reducedUI: boolean,
|
||||
|
||||
/**
|
||||
* Array of reactions to be displayed.
|
||||
*/
|
||||
_reactionsQueue: Array<ReactionEmojiProps>
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,11 +25,21 @@ const GESTURE_SPEED_THRESHOLD = 0.2;
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The height of the screen.
|
||||
*/
|
||||
_height: number,
|
||||
|
||||
/**
|
||||
* The color-schemed stylesheet of the feature.
|
||||
*/
|
||||
_styles: StyleType,
|
||||
|
||||
/**
|
||||
* Whether to add padding to scroll view.
|
||||
*/
|
||||
addScrollViewPadding?: boolean,
|
||||
|
||||
/**
|
||||
* The children to be displayed within this component.
|
||||
*/
|
||||
@@ -49,7 +59,22 @@ type Props = {
|
||||
/**
|
||||
* Function to render a bottom sheet header element, if necessary.
|
||||
*/
|
||||
renderHeader: ?Function
|
||||
renderHeader: ?Function,
|
||||
|
||||
/**
|
||||
* Function to render a bottom sheet footer element, if necessary.
|
||||
*/
|
||||
renderFooter: ?Function,
|
||||
|
||||
/**
|
||||
* Whether to show sliding view or not.
|
||||
*/
|
||||
showSlidingView?: boolean,
|
||||
|
||||
/**
|
||||
* The component's external style
|
||||
*/
|
||||
style: Object
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -58,6 +83,16 @@ type Props = {
|
||||
class BottomSheet extends PureComponent<Props> {
|
||||
panResponder: Object;
|
||||
|
||||
/**
|
||||
* Default values for {@code BottomSheet} component's properties.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static defaultProps = {
|
||||
addScrollViewPadding: true,
|
||||
showSlidingView: true
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiates a new component.
|
||||
*
|
||||
@@ -80,7 +115,15 @@ class BottomSheet extends PureComponent<Props> {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { _styles, renderHeader } = this.props;
|
||||
const {
|
||||
_height,
|
||||
_styles,
|
||||
addScrollViewPadding,
|
||||
renderHeader,
|
||||
renderFooter,
|
||||
showSlidingView,
|
||||
style
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<SlidingView
|
||||
@@ -88,7 +131,7 @@ class BottomSheet extends PureComponent<Props> {
|
||||
accessibilityViewIsModal = { true }
|
||||
onHide = { this.props.onCancel }
|
||||
position = 'bottom'
|
||||
show = { true }>
|
||||
show = { showSlidingView }>
|
||||
<View
|
||||
pointerEvents = 'box-none'
|
||||
style = { styles.sheetContainer }>
|
||||
@@ -99,15 +142,22 @@ class BottomSheet extends PureComponent<Props> {
|
||||
<SafeAreaView
|
||||
style = { [
|
||||
styles.sheetItemContainer,
|
||||
_styles.sheet
|
||||
renderHeader
|
||||
? _styles.sheetHeader
|
||||
: _styles.sheet,
|
||||
style,
|
||||
{
|
||||
maxHeight: _height - 100
|
||||
}
|
||||
] }
|
||||
{ ...this.panResponder.panHandlers }>
|
||||
<ScrollView
|
||||
bounces = { false }
|
||||
showsVerticalScrollIndicator = { false }
|
||||
style = { styles.scrollView } >
|
||||
style = { addScrollViewPadding && styles.scrollView } >
|
||||
{ this.props.children }
|
||||
</ScrollView>
|
||||
{ renderFooter && renderFooter() }
|
||||
</SafeAreaView>
|
||||
</View>
|
||||
</SlidingView>
|
||||
@@ -167,7 +217,8 @@ class BottomSheet extends PureComponent<Props> {
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
return {
|
||||
_styles: ColorSchemeRegistry.get(state, 'BottomSheet')
|
||||
_styles: ColorSchemeRegistry.get(state, 'BottomSheet'),
|
||||
_height: state['features/base/responsive-ui'].clientHeight
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import { ReactionEmoji } from '../../../../reactions/components';
|
||||
import { getReactionsQueue } from '../../../../reactions/functions.any';
|
||||
import { connect } from '../../../redux';
|
||||
import AbstractDialogContainer, {
|
||||
abstractMapStateToProps
|
||||
@@ -11,6 +15,22 @@ import AbstractDialogContainer, {
|
||||
* @extends AbstractDialogContainer
|
||||
*/
|
||||
class DialogContainer extends AbstractDialogContainer {
|
||||
|
||||
/**
|
||||
* Returns the reactions to be displayed.
|
||||
*
|
||||
* @returns {Array<React$Element>}
|
||||
*/
|
||||
_renderReactions() {
|
||||
const { _reactionsQueue } = this.props;
|
||||
|
||||
return _reactionsQueue.map(({ reaction, uid }, index) => (<ReactionEmoji
|
||||
index = { index }
|
||||
key = { uid }
|
||||
reaction = { reaction }
|
||||
uid = { uid } />));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
@@ -18,8 +38,18 @@ class DialogContainer extends AbstractDialogContainer {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
return this._renderDialogContent();
|
||||
return (<React.Fragment>
|
||||
{this._renderReactions()}
|
||||
{this._renderDialogContent()}
|
||||
</React.Fragment>);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(abstractMapStateToProps)(DialogContainer);
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
...abstractMapStateToProps(state),
|
||||
_reactionsQueue: getReactionsQueue(state)
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(DialogContainer);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
import BaseTheme from '../../../../base/ui/components/BaseTheme.native';
|
||||
import { ColorSchemeRegistry, schemeColor } from '../../../color-scheme';
|
||||
import { BoxModel, ColorPalette } from '../../../styles';
|
||||
import { PREFERRED_DIALOG_SIZE } from '../../constants';
|
||||
@@ -33,7 +34,7 @@ export const bottomSheetStyles = {
|
||||
},
|
||||
|
||||
scrollView: {
|
||||
paddingHorizontal: MD_ITEM_MARGIN_PADDING
|
||||
paddingHorizontal: 0
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -117,7 +118,7 @@ const brandedDialogText = {
|
||||
};
|
||||
|
||||
const brandedDialogLabelStyle = {
|
||||
color: schemeColor('text'),
|
||||
color: ColorPalette.white,
|
||||
flexShrink: 1,
|
||||
fontSize: MD_FONT_SIZE,
|
||||
opacity: 0.90
|
||||
@@ -130,7 +131,7 @@ const brandedDialogItemContainerStyle = {
|
||||
};
|
||||
|
||||
const brandedDialogIconStyle = {
|
||||
color: schemeColor('icon'),
|
||||
color: ColorPalette.white,
|
||||
fontSize: 24
|
||||
};
|
||||
|
||||
@@ -171,27 +172,37 @@ ColorSchemeRegistry.register('BottomSheet', {
|
||||
*/
|
||||
labelStyle: {
|
||||
...brandedDialogLabelStyle,
|
||||
marginLeft: 32
|
||||
marginLeft: 16
|
||||
},
|
||||
|
||||
/**
|
||||
* Container style for a generic item rendered in the menu.
|
||||
*/
|
||||
style: {
|
||||
...brandedDialogItemContainerStyle
|
||||
...brandedDialogItemContainerStyle,
|
||||
paddingHorizontal: MD_ITEM_MARGIN_PADDING
|
||||
},
|
||||
|
||||
/**
|
||||
* Additional style that is not directly used as a style object.
|
||||
*/
|
||||
underlayColor: ColorPalette.overflowMenuItemUnderlay
|
||||
underlayColor: ColorPalette.toggled
|
||||
},
|
||||
|
||||
/**
|
||||
* Bottom sheet's base style.
|
||||
*/
|
||||
sheet: {
|
||||
backgroundColor: schemeColor('background')
|
||||
backgroundColor: BaseTheme.palette.ui02,
|
||||
borderTopLeftRadius: 16,
|
||||
borderTopRightRadius: 16
|
||||
},
|
||||
|
||||
/**
|
||||
* Bottom sheet's base style with header.
|
||||
*/
|
||||
sheetHeader: {
|
||||
backgroundColor: BaseTheme.palette.ui02
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -214,3 +214,9 @@ export const VIDEO_SHARE_BUTTON_ENABLED = 'video-share.enabled';
|
||||
* Default: disabled (false).
|
||||
*/
|
||||
export const WELCOME_PAGE_ENABLED = 'welcomepage.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if the reactions feature should be enabled.
|
||||
* Default: disabled (false).
|
||||
*/
|
||||
export const REACTIONS_ENABLED = 'reactions.enabled';
|
||||
|
||||
@@ -20,8 +20,17 @@ export default {
|
||||
|
||||
detect() {
|
||||
const { LocaleDetector } = NativeModules;
|
||||
const [ lang, region ] = LocaleDetector.locale.replace(/_/, '-').split('-');
|
||||
const locale = `${lang}${region}`;
|
||||
const parts = LocaleDetector.locale.replace(/_/, '-').split('-');
|
||||
const [ lang, regionOrScript, region ] = parts;
|
||||
let locale;
|
||||
|
||||
if (parts.length >= 3) {
|
||||
locale = `${lang}${region}`;
|
||||
} else if (parts.length === 2) {
|
||||
locale = `${lang}${regionOrScript}`;
|
||||
} else {
|
||||
locale = lang;
|
||||
}
|
||||
|
||||
if (LANGUAGES.includes(locale)) {
|
||||
return locale;
|
||||
|
||||
@@ -111,6 +111,7 @@ export { default as IconShareDesktop } from './share-desktop.svg';
|
||||
export { default as IconShareDoc } from './share-doc.svg';
|
||||
export { default as IconShareVideo } from './shared-video.svg';
|
||||
export { default as IconSmile } from './smile.svg';
|
||||
export { default as IconStopAudioShare } from './stop-audio-share.svg';
|
||||
export { default as IconSwitchCamera } from './switch-camera.svg';
|
||||
export { default as IconTileView } from './tiles-many.svg';
|
||||
export { default as IconToggleRecording } from './camera-take-picture.svg';
|
||||
@@ -130,3 +131,4 @@ export { default as IconWifi1Bar } from './wifi-1.svg';
|
||||
export { default as IconWifi2Bars } from './wifi-2.svg';
|
||||
export { default as IconWifi3Bars } from './wifi-3.svg';
|
||||
export { default as IconYahoo } from './yahoo.svg';
|
||||
export { default as IconSip } from './sip.svg';
|
||||
|
||||
3
react/features/base/icons/svg/sip.svg
Normal file
3
react/features/base/icons/svg/sip.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="20" height="14" viewBox="0 0 20 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.41201 1.90767C3.50689 3.37865 5.24438 7.52348 7.36096 9.64007C7.36096 9.64004 7.36175 9.63923 7.36329 9.63765C9.48 11.7541 13.6215 13.4932 15.0923 12.5882C16.1022 11.9668 16.0078 9.51337 15.2427 8.76783C14.7369 8.2749 13.1882 8.01994 12.5497 8.14762C12.3496 8.18763 11.7907 8.76515 11.4793 9.08696C11.4184 9.14994 11.3669 9.20313 11.3295 9.24058C11.1007 9.46937 9.63912 8.22168 9.20588 7.78845L7.60102 9.39838C8.10053 8.89635 9.2057 7.78701 9.2057 7.78701C8.77247 7.35377 7.53081 5.89935 7.7596 5.67056C7.79705 5.63311 7.85024 5.58164 7.91322 5.5207C8.23503 5.20928 8.81255 4.65041 8.85256 4.45033C8.98024 3.81178 8.72528 2.26311 8.23236 1.75727C7.48681 0.992193 5.03342 0.897765 4.41201 1.90767Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 868 B |
3
react/features/base/icons/svg/stop-audio-share.svg
Normal file
3
react/features/base/icons/svg/stop-audio-share.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.57392 5.35509L6.56245 5.36465L3.11271 1.9149C2.78183 1.58402 2.24546 1.58394 1.91469 1.91471C1.58392 2.24548 1.58401 2.78185 1.91488 3.11272L5.25574 6.45358L5.00001 6.66669H2.50001C2.03977 6.66669 1.66667 7.03978 1.66667 7.50002V12.5C1.66667 12.9603 2.03977 13.3334 2.50001 13.3334H5.00001L9.3166 16.9305C9.39148 16.9929 9.48586 17.0271 9.58334 17.0271C9.81346 17.0271 10 16.8405 10 16.6104V11.1978L11.6667 12.8645V13.3334C11.8158 13.3334 11.9627 13.3236 12.1067 13.3046L13.4679 14.6657C12.9091 14.8816 12.3017 15 11.6667 15V16.6667C12.7697 16.6667 13.8102 16.3988 14.7267 15.9245L16.8873 18.0851C17.2182 18.416 17.7545 18.4161 18.0853 18.0853C18.4161 17.7546 18.416 17.2182 18.0851 16.8873L16.1405 14.9427C16.1442 14.9394 16.1478 14.936 16.1515 14.9327L14.9712 13.7524C14.9675 13.7557 14.9638 13.759 14.9601 13.7622L13.7777 12.5798C13.7815 12.5767 13.7854 12.5735 13.7892 12.5704L12.6003 11.3814C12.5961 11.3843 12.5919 11.3871 12.5877 11.3899L10 8.8022V8.78118L8.33334 7.11451V7.13553L7.74583 6.54802L7.75729 6.53846L6.57392 5.35509ZM11.9766 8.36212L11.6667 8.0522V6.66669C13.5076 6.66669 15 8.15907 15 10C15 10.4129 14.9249 10.8083 14.7877 11.1732L13.3046 9.6901C13.1782 9.01814 12.6486 8.48848 11.9766 8.36212ZM16.04 12.4255L17.2535 13.639C17.9364 12.5927 18.3333 11.3427 18.3333 10C18.3333 6.31812 15.3486 3.33335 11.6667 3.33335V5.00002C14.4281 5.00002 16.6667 7.2386 16.6667 10C16.6667 10.8802 16.4393 11.7072 16.04 12.4255ZM10 6.38553L7.88064 4.26616L9.3166 3.06953C9.49338 2.92221 9.75611 2.9461 9.90343 3.12288C9.96583 3.19776 10 3.29215 10 3.38962V6.38553ZM5.60342 8.33335L6.43911 7.63695L8.33334 9.53118V13.9416L5.60342 11.6667H3.33334V8.33335H5.60342Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -2,6 +2,9 @@
|
||||
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { showModeratedNotification } from '../../av-moderation/actions';
|
||||
import { shouldShowModeratedNotification } from '../../av-moderation/functions';
|
||||
|
||||
import {
|
||||
SET_AUDIO_MUTED,
|
||||
SET_AUDIO_AVAILABLE,
|
||||
@@ -12,8 +15,8 @@ import {
|
||||
TOGGLE_CAMERA_FACING_MODE
|
||||
} from './actionTypes';
|
||||
import {
|
||||
CAMERA_FACING_MODE,
|
||||
MEDIA_TYPE,
|
||||
type MediaType,
|
||||
VIDEO_MUTISM_AUTHORITY
|
||||
} from './constants';
|
||||
|
||||
@@ -64,7 +67,7 @@ export function setAudioMuted(muted: boolean, ensureTrack: boolean = false) {
|
||||
* cameraFacingMode: CAMERA_FACING_MODE
|
||||
* }}
|
||||
*/
|
||||
export function setCameraFacingMode(cameraFacingMode: CAMERA_FACING_MODE) {
|
||||
export function setCameraFacingMode(cameraFacingMode: string) {
|
||||
return {
|
||||
type: SET_CAMERA_FACING_MODE,
|
||||
cameraFacingMode
|
||||
@@ -102,11 +105,20 @@ export function setVideoAvailable(available: boolean) {
|
||||
*/
|
||||
export function setVideoMuted(
|
||||
muted: boolean,
|
||||
mediaType: MEDIA_TYPE = MEDIA_TYPE.VIDEO,
|
||||
mediaType: MediaType = MEDIA_TYPE.VIDEO,
|
||||
authority: number = VIDEO_MUTISM_AUTHORITY.USER,
|
||||
ensureTrack: boolean = false) {
|
||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||
const oldValue = getState()['features/base/media'].video.muted;
|
||||
const state = getState();
|
||||
|
||||
// check for A/V Moderation when trying to unmute
|
||||
if (!muted && shouldShowModeratedNotification(MEDIA_TYPE.VIDEO, state)) {
|
||||
ensureTrack && dispatch(showModeratedNotification(MEDIA_TYPE.VIDEO));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const oldValue = state['features/base/media'].video.muted;
|
||||
|
||||
// eslint-disable-next-line no-bitwise
|
||||
const newValue = muted ? oldValue | authority : oldValue & ~authority;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { createAudioPlayErrorEvent, createAudioPlaySuccessEvent, sendAnalytics } from '../../../../analytics';
|
||||
import { connect } from '../../../redux';
|
||||
import logger from '../../logger';
|
||||
|
||||
/**
|
||||
@@ -10,6 +11,16 @@ import logger from '../../logger';
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Represents muted property of the underlying audio element.
|
||||
*/
|
||||
_muted: ?Boolean,
|
||||
|
||||
/**
|
||||
* Represents volume property of the underlying audio element.
|
||||
*/
|
||||
_volume: ?number,
|
||||
|
||||
/**
|
||||
* The value of the id attribute of the audio element.
|
||||
*/
|
||||
@@ -28,26 +39,15 @@ type Props = {
|
||||
autoPlay: boolean,
|
||||
|
||||
/**
|
||||
* Represents muted property of the underlying audio element.
|
||||
* The ID of the participant associated with the audio element.
|
||||
*/
|
||||
muted: ?Boolean,
|
||||
|
||||
/**
|
||||
* Represents volume property of the underlying audio element.
|
||||
*/
|
||||
volume: ?number,
|
||||
|
||||
/**
|
||||
* A function that will be executed when the reference to the underlying audio element changes in order to report
|
||||
* the initial volume value.
|
||||
*/
|
||||
onInitialVolumeSet: Function
|
||||
participantId: string
|
||||
};
|
||||
|
||||
/**
|
||||
* The React/Web {@link Component} which is similar to and wraps around {@code HTMLAudioElement}.
|
||||
*/
|
||||
export default class AudioTrack extends Component<Props> {
|
||||
class AudioTrack extends Component<Props> {
|
||||
/**
|
||||
* Reference to the HTML audio element, stored until the file is ready.
|
||||
*/
|
||||
@@ -94,14 +94,14 @@ export default class AudioTrack extends Component<Props> {
|
||||
this._attachTrack(this.props.audioTrack);
|
||||
|
||||
if (this._ref) {
|
||||
const { muted, volume } = this.props;
|
||||
const { _muted, _volume } = this.props;
|
||||
|
||||
if (typeof volume === 'number') {
|
||||
this._ref.volume = volume;
|
||||
if (typeof _volume === 'number') {
|
||||
this._ref.volume = _volume;
|
||||
}
|
||||
|
||||
if (typeof muted === 'boolean') {
|
||||
this._ref.muted = muted;
|
||||
if (typeof _muted === 'boolean') {
|
||||
this._ref.muted = _muted;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,14 +136,14 @@ export default class AudioTrack extends Component<Props> {
|
||||
|
||||
if (this._ref) {
|
||||
const currentVolume = this._ref.volume;
|
||||
const nextVolume = nextProps.volume;
|
||||
const nextVolume = nextProps._volume;
|
||||
|
||||
if (typeof nextVolume === 'number' && !isNaN(nextVolume) && currentVolume !== nextVolume) {
|
||||
this._ref.volume = nextVolume;
|
||||
}
|
||||
|
||||
const currentMuted = this._ref.muted;
|
||||
const nextMuted = nextProps.muted;
|
||||
const nextMuted = nextProps._muted;
|
||||
|
||||
if (typeof nextMuted === 'boolean' && currentMuted !== nextVolume) {
|
||||
this._ref.muted = nextMuted;
|
||||
@@ -258,10 +258,24 @@ export default class AudioTrack extends Component<Props> {
|
||||
*/
|
||||
_setRef(audioElement: ?HTMLAudioElement) {
|
||||
this._ref = audioElement;
|
||||
const { onInitialVolumeSet } = this.props;
|
||||
|
||||
if (this._ref && onInitialVolumeSet) {
|
||||
onInitialVolumeSet(this._ref.volume);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the Redux state to the associated {@code AudioTrack}'s props.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @param {Object} ownProps - The props passed to the component.
|
||||
* @private
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state, ownProps) {
|
||||
const { participantsVolume } = state['features/filmstrip'];
|
||||
|
||||
return {
|
||||
_muted: state['features/base/config'].startSilent,
|
||||
_volume: participantsVolume[ownProps.participantId]
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(AudioTrack);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user