Compare commits

...

65 Commits

Author SHA1 Message Date
titus.moldovan
63754f01a5 chore(deps) updates react-native-webrtc 2021-10-15 12:58:12 +03:00
Zoltán Ulrich
dcf677bdf0 fix(ios) Fixes RCTBridge not being released when JitsiMeet is trying to destroy its bridge on some OS versions 2021-10-14 13:05:37 +02:00
titus.moldovan
eaea2cdef0 chore(versions) bump iOS SDK version 2021-10-08 12:29:41 +03:00
Saúl Ibarra Corretgé
bcad87e894 chore(versions) bump iOS app version 2021-10-07 11:47:22 +02:00
Saúl Ibarra Corretgé
d500493649 chore(deps) update lib-jitsi-meet to fix iOS 15 issue
Not unmuting when "everyone starts muted".
2021-10-07 11:45:53 +02:00
tmoldovan8x8
8ad3ef0022 chore(versions) bump Android SDK version 2021-10-05 09:24:39 +03:00
Saúl Ibarra Corretgé
d0664d9ea0 chore(versions) bump iOS SDK version 2021-10-01 15:49:11 +02:00
Saúl Ibarra Corretgé
45c40d7afc chore(versions) bump iOS app version 2021-10-01 15:48:09 +02:00
Saúl Ibarra Corretgé
e33edfd2a5 fix(rn,conference) fix unmute when "everyone starts muted" is set
Since iOS 15 we really need the audio stream to exist, so make sure we don't
destroy it even when "everyone starts muted" is set, we'll just mute it.

Fixes: https://github.com/jitsi/jitsi-meet/issues/10053
2021-10-01 15:47:22 +02:00
Saúl Ibarra Corretgé
96b2a07172 chore(versions) bump iOS app version 2021-09-30 15:18:26 +02:00
Saúl Ibarra Corretgé
0e8c01af75 fix(ios) fix crash on WebSocket errors
Bacckport
748aa13747

Fixes:

~~~
Fatal Exception: NSInvalidArgumentException
0  CoreFoundation                 0x129708 __exceptionPreprocess
1  libobjc.A.dylib                0x287a8 objc_exception_throw
2  CoreFoundation                 0x19b9c8 -[__NSCFString characterAtIndex:].cold.1
3  CoreFoundation                 0x1a7a20 -[__NSPlaceholderDictionary initWithCapacity:].cold.1
4  CoreFoundation                 0x164c0 -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]
5  CoreFoundation                 0x8de0 +[NSDictionary dictionaryWithObjects:forKeys:count:]
6  JitsiMeetSDK                   0x5704b4 -[RCTWebSocketModule webSocket:didFailWithError:] + 168 (RCTWebSocketModule.m:168)
7  JitsiMeetSDK                   0x54a5ec __33-[RCTSRWebSocket _failWithError:]_block_invoke_2 + 622 (RCTSRWebSocket.m:622)
8  libdispatch.dylib              0x2a84 _dispatch_call_block_and_release
9  libdispatch.dylib              0x481c _dispatch_client_callout
10 libdispatch.dylib              0xc004 _dispatch_lane_serial_drain
11 libdispatch.dylib              0xcc00 _dispatch_lane_invoke
12 libdispatch.dylib              0x174bc _dispatch_workloop_worker_thread
13 libsystem_pthread.dylib        0x37a4 _pthread_wqthread
14 libsystem_pthread.dylib        0xa74c start_wqthread
~~~
2021-09-30 15:12:46 +02:00
tmoldovan8x8
3049ad6dbf feat(android) target sdk 31 2021-09-30 14:06:37 +02:00
Saúl Ibarra Corretgé
9a30ad87a7 chore(versions) bump Android sdk version 2021-09-29 14:49:03 +02:00
Saúl Ibarra Corretgé
11c05560c4 chore(versions) bump Android app version 2021-09-29 14:15:43 +02:00
titus.moldovan
d92fa59c74 fix(android) disables uncompressed native libs usage 2021-09-29 14:15:11 +02:00
Saúl Ibarra Corretgé
4eb1d16faa chore(deps): update react-native-webrtc@1.92.2
Fixes a crash on Android
2021-09-29 14:13:47 +02:00
Saúl Ibarra Corretgé
91adc70724 chore(rn,versions) bump sdk version 2021-09-24 11:09:25 +02:00
Saúl Ibarra Corretgé
15b083c182 fix(ios) create audio track early
In iOS 15 we observe that not creating the audio track early may result in not
getting audio after unmuting for the first time.

Creating the audio track early means the first unmute doesn't need to add the
track to the conference, resulting in a much faster operation.

Note that creating the track early doesn't mean we will start unmuted, the track
will be muted.
2021-09-24 11:01:33 +02:00
titus.moldovan
26fdaf7b8d fix(rn) add default value when retrieving e2ee redux state 2021-09-24 10:11:52 +02:00
Saúl Ibarra Corretgé
64a9874d63 chore(rn,versions) bump sdk version 2021-09-23 14:13:51 +02:00
Saúl Ibarra Corretgé
753cffc458 fix(ios) fix black screen when using Bluetooth in iOS 15
Fixes: https://github.com/jitsi/jitsi-meet/issues/9996

On iOS 15 Bluetooth devices are reported twice for some reason, one with the
normal type "Bluetooth" but another type without a know (to me) type, and the
uid ends in "-reference".

While we send those unkwno devices to JS, we were not filtering them properly.
This patch skips them altogether.
2021-09-23 14:11:49 +02:00
Saúl Ibarra Corretgé
99e56e229d chore(rn,versions) bump sdk version 2021-09-22 16:13:57 +02:00
robertpin
c3dae1f6e9 feat(rn,av-moderation) updated advanced moderation on Native
Updated participants list to:
- show Moderator label
- show correct status icons (red for force muted)
- show participants in the right order

Updated moderation to:
- show moderation menu at all times
- make moderation options functional

Updated notifications:
- fixed raise hand to show name
- display moderator rights granted

Updated mute/ stop video for all dialogs to include moderation toggles

Added ask to unmute button

Fix comments on ask to unmute

Co-authored-by: robertpin <robert.pin9@gmail.com>
2021-09-22 16:05:42 +02:00
robertpin
703e43ecd7 fix(av-moderation) Display Allow Video instead of Ask to Unmute (#9991)
When the user is allowed audio but not video display Allow Video button instead of Ask to Unmute
2021-09-22 16:26:55 +03:00
Vlad Piersec
0bf52b613b feat(api): Expose event used for sending browser support 2021-09-22 09:20:56 +03:00
robertpin
584ec7c82e fix(reactions) Reactions improvements (#9964)
* Register shortcuts on mount

* Changed icon for reactions menu

* Enable reactions by default

* Fix unreadCount bug

When having unread messages and sending a reaction the unread count now shows the correct count

* Fix overflow menu bottom color when reactions are enabled

* Revert raise hand icon

* Update raise hand functionality

On desktop show raise button with arrow for reactions. Only show raise hand in the reactions menu on mobile

* Fix lint error

Add required prop to ToolboxButtonWithIcon

* Legacy support for enable reactions

If disableReactions is undefined treat it as true

* Remove unnecessary code

* Fix unread counter showing negative count

* Fix unreadCount with reactions

UnreadCount ignores all reactions messages

* Fixed typo

* Fix background color
2021-09-21 12:30:24 -05:00
robertpin
5f5cac0e01 fix(config,notifications) fix rendering moderator notifications (#9986)
Move DISABLE_FOCUS_INDICATOR from interface_config.js to config.js (disableModeratorIndicator).
2021-09-21 17:38:06 +02:00
Vlad Piersec
0a9b9bb41d fix(responsive-ui): Shrink self view when in portrait mode on mobile web 2021-09-21 16:47:47 +03:00
tmoldovan8x8
5ad98d193a feat(e2ee) disable e2ee when large number of participants 2021-09-21 14:00:23 +03:00
Дамян Минков
4cd5be9d8b chore(deps) lib-jitsi-meet@latest
* fix(JitsiConference) Check for room before calling isFocus method on the room object.
* fix(Jingle) Reverse the order of ssrcs signaled for Firefox. This fixes an issue where the bridge doesn't forward the HD stream from Firefox to other users in the call. The order of the ssrcs produced by the browser is from Highest resolution to lowest whereas the bridge assumes it to be from lowest to highest as is the case in Chrome and Safari.
* fix(codec-selection): Impose VP9 bitrates only when VP9 is the negotiated codec. If Jicofo doesn't offer VP9 but the client expresses a preference for VP9, VP9 bitrates were being imposed before.

609e3d5a1a...3b8baa9d3b
2021-09-20 17:35:08 -05:00
Horatiu Muresan
5514be630d feat(conference-info-header) Make conference info header configurable. (#9638) 2021-09-20 21:12:56 +03:00
hmuresan
6a6146727f fix(notifications) Fix recording start notif not disappearing 2021-09-20 19:08:12 +03:00
Avram Tudor
52e9e90b3a fix(jaas) do not show overriden unsupported browser page for jaas users (#9962) 2021-09-20 11:38:46 +03:00
Alexey Matveev
7ff3b669ee fix(lang) update Russian translation
Co-authored-by: Alexey Matveev <malex@1forma.ru>
2021-09-18 11:15:13 +02:00
Hristo Terezov
e791c4f70c fix(recorder): tile view
In the case of the recorder we were not taking into account that the
local thumbnail is not visible. This was braking the rendering  and
positioning of the thumbnails in tile view.
2021-09-17 18:20:00 -05:00
Дамян Минков
fc75fd9644 chore(deps) lib-jitsi-meet@latest
* fix: Reads shard name and from disco-info if available.
* chore(deps): bump sdp-interop to get another fix for ICE restart
* update sdp-interop to include Unified ICE restart fix

fbf85bdcec...609e3d5a1a
2021-09-17 15:51:23 -05:00
Дамян Минков
62e5d6c139 fix: Fixes undefined error causing to stop reloads.
Jibri was hitting a problem where it reloads and in certain cases (remote user is screensharing) we hit this participant undefined, which stops reload and stops recording.
It is still not obvious why we try to render this on leaving the conference and for a participant that is not in the conference ... this re-render should not happen as this component should be removed from its parent when the participant is not existing.
2021-09-17 15:04:32 -05:00
Saúl Ibarra Corretgé
06d8956bdb android: fix initializing soloader from Activity context
It has to be an application context.
2021-09-17 13:43:45 +02:00
Avram Tudor
adbb5f8ead fix(prejoin) implement ux improvements for mobile (#9939) 2021-09-17 13:12:34 +03:00
Hristo Terezov
32ed2bccec fix(Filmstrip) fix not being able to scroll 2021-09-17 11:22:20 +02:00
Jaya Allamsetty
58d98ad7d3 fix(device-selection) Do not create preview when mic selection is disabled.
This fixes an issue on mobile Safari when audio is lost after the user opens the device selection menu.
2021-09-16 15:41:44 -04:00
Vlad Piersec
e278703c58 fix(context-menus) Don't show volume slider on iOS web 2021-09-16 14:56:55 +03:00
Jaya Allamsetty
042a2cb447 fix(filmstrip) Fix filmstrip on RN when thumbnail reordering is disabled. 2021-09-15 11:29:46 -05:00
Saúl Ibarra Corretgé
a8f281a43e feat((rn,config) add a/b test flag to enable XMPP WebSockets on mobile 2021-09-15 15:26:25 +02:00
paweldomas
663752be2c feat(rn,connection) enable XMPP WebSocket on mobile
Co-authored-by: Saúl Ibarra Corretgé <saghul@jitsi.org>
2021-09-15 15:26:25 +02:00
Vlad Piersec
380ef3da0b fix(feedback): Scroll to the top when opening feedback dialog 2021-09-15 15:21:56 +03:00
Saúl Ibarra Corretgé
07da5940a5 fix(rn,conference) show underlay when tapping navbar buttons 2021-09-15 13:35:33 +02:00
robertpin
ab366b9d94 fix(av-moderation) Advanced moderation improvements (#9935)
* Update moderation in effect notifications

Only display one notification for each media type. Display notification for keyboard shortcuts as well

* Update muted remotely notification

Display name of moderator in the notification

* Fix indentation on moderation menu

* Update text for video moderation

* Added moderator label in participant pane

* Update microphone icon in participant list

For participants that speak, or are noisy, but aren't dominant speaker, the icon in the participant list will look the same as the dominant speaker icon but will not change their position in the list

* Added sound for asked to unmute notification

* Code review changes

* Code review changes

Use simple var instead of function for audio media state

* Move constants to constants file

* Moved constants from notifications to av-moderation
2021-09-15 11:28:44 +03:00
Pawel Domas
bba1917820 fix(conference.js): add tracks to the conference 2021-09-14 18:24:45 -04:00
Saúl Ibarra Corretgé
0833f8c867 feat(rn,conference) show invite button on the top navbar 2021-09-14 15:03:24 +02:00
Saúl Ibarra Corretgé
3bf9c41f08 fix(rn,conference) count fake participants when checking if lonely meeting
A shared video participant counts, so the lonely meeting invite options can
disappear.
2021-09-14 12:50:22 +02:00
Saúl Ibarra Corretgé
0b54e005d7 fix(rn,shared-video) validate URLs to avoid crashes on the native side 2021-09-14 12:50:22 +02:00
Saúl Ibarra Corretgé
b92c1f52d5 fix(shared-video) make placeholder translatable
Also fix capitalization.
2021-09-14 12:50:22 +02:00
tmoldovan8x8
8eaf99586e fix(rn) disable pip while authorising dropbox 2021-09-14 12:37:08 +03:00
tmoldovan8x8
c7ad5b5b26 feat(android) expose channels ids 2021-09-14 12:35:25 +03:00
robertpin
61c3613de0 Show reactions buttons at all times
Don't send reactions via the channel if there's only one participant in the meeting
2021-09-14 12:26:50 +03:00
Horatiu Muresan
b801e0115d fix(context-menus) Fix participant context menus/toolbar overflow menu
- on ipads, long touch open dialog now opens the context menu to the left of the thumbnail as expected
- on ipads, now we close context menus on tap out
- fix case when participant context menu's height > tileview videos' height causing scroll on videos pane
- keep toolbox open while the overflow menu is shown
- keep remote participant video thumbnail in filmstrip visible even if toolbox is hidden, if context menu is opened
- Fix bug where toolbox could be completely disabled
2021-09-14 10:43:52 +03:00
Horatiu Muresan
1add438a1f feat(toolbar-buttons): Add event for notify overwritten toolbar buttons 2021-09-14 10:07:20 +03:00
Hristo Terezov
aadbe59d00 chore(deps) lib-jitsi-meet@latest
* fix(replaceTrack):  Don't wrap Error in Error.

64cdf69ffb...fbf85bdcec
2021-09-13 17:50:56 -05:00
Дамян Минков
350f0fbb27 feat: Whitelists enableUnifiedOnChrome.
Whitelists it, so we can run tests by setting it to false.
2021-09-13 15:23:53 -05:00
Paweł Domas
1db52354fb Use redux for local tracks instead of conference.js (#9920)
* do not use this.local video

* move tracks initialized flag around

* do not use this.localAudio

* untangle use audio/video stream methods

It should be safe to call setVideoMuteStatus and
setAudioMuteStatus regardless of the prejoin page
visibility state.

* add NO-OP to use track methods and fix crash
in _setLocalAudioVideoStreams on not a promise

* use allSettled
2021-09-13 12:33:04 -05:00
Jaya Allamsetty
6711801c3b chore(deps) lib-jitsi-meet@latest
* ref(JitsiConference): don't crash on wrong oldTrack (#1709)

ad1f06d768...64cdf69ffb
2021-09-13 11:49:53 -04:00
csett86
e2443f8d01 lang: update German translation (#9921)
Signed-off-by: Christoph Settgast <csett86@web.de>
2021-09-11 10:58:15 -05:00
dimitardelchev93
11a86a9383 fix: Add different text when disablePolls is enabled/disabled (#9900)
* Add different text when disablePolls is enabled/disabled #9890

* Add different text when disablePolls is enabled/disabled v2 #9890
2021-09-10 13:57:36 -05:00
Jaya Allamsetty
40a485ec6c Thumbnail reordering and participant pane enhancements.
* fix(participant-pane) Use the sorted participant list from redux instead of sorting it on every render making it better performant. Match the participant order with that of the order in the filmstrip. Also move the participants with raised hand to the top of the list.

* ref(filmstrip) Move enableThumbnailReordering flag to testing section.

* fix(participants) Add new selectors for getting sorted participants.
2021-09-10 13:37:05 -04:00
243 changed files with 2717 additions and 1363 deletions

View File

@@ -78,7 +78,7 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.2.0'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.2'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
if (!rootProject.ext.libreBuild) {
implementation 'com.google.android.gms:play-services-auth:16.0.1'
@@ -109,6 +109,7 @@ gradle.projectsEvaluated {
def dropboxActivity = """
<activity
android:configChanges="keyboard|orientation"
android:exported="true"
android:launchMode="singleTask"
android:name="com.dropbox.core.android.AuthActivity">
<intent-filter>

View File

@@ -4,6 +4,7 @@
android:installLocation="auto">
<application
android:allowBackup="true"
android:extractNativeLibs="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
@@ -13,6 +14,7 @@
android:resource="@xml/app_restrictions" />
<activity
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize"
android:exported="true"
android:label="@string/app_name"
android:launchMode="singleTask"
android:name=".MainActivity"

View File

@@ -18,9 +18,9 @@ buildscript {
ext {
buildToolsVersion = "30.0.3"
compileSdkVersion = 30
compileSdkVersion = 31
minSdkVersion = 23
targetSdkVersion = 30
targetSdkVersion = 31
supportLibVersion = "28.0.0"
// The Maven artifact groupdId of the third-party react-native modules which

View File

@@ -24,6 +24,7 @@ android.enableDexingArtifactTransform.desugaring=false
android.useAndroidX=true
android.enableJetifier=true
android.bundle.enableUncompressedNativeLibs=false
appVersion=21.4.0
sdkVersion=3.9.1
appVersion=21.4.1
sdkVersion=3.10.2

View File

@@ -184,14 +184,21 @@ class DropboxModule
public void onHostResume() {
DbxCredential credential = Auth.getDbxCredential();
if (credential != null && this.promise != null) {
WritableMap result = Arguments.createMap();
result.putString("token", credential.getAccessToken());
result.putString("rToken", credential.getRefreshToken());
result.putDouble("expireDate", credential.getExpiresAt());
if (this.promise != null ) {
if (credential != null) {
WritableMap result = Arguments.createMap();
result.putString("token", credential.getAccessToken());
result.putString("rToken", credential.getRefreshToken());
result.putDouble("expireDate", credential.getExpiresAt());
this.promise.resolve(result);
this.promise = null;
} else {
this.promise.reject("Invalid dropbox credentials");
}
this.promise.resolve(result);
this.promise = null;
}
}
}

View File

@@ -0,0 +1,11 @@
package org.jitsi.meet.sdk;
import java.util.ArrayList;
import java.util.List;
public class NotificationChannels {
static final String ONGOING_CONFERENCE_CHANNEL_ID = "JitsiOngoingConferenceChannel";
static final String ONGOING_CONFERNCE_CHANNEL_NAME = "Ongoing Conference Notifications";
public static List<String> allIds = new ArrayList<String>() {{ add(ONGOING_CONFERENCE_CHANNEL_ID); }};
}

View File

@@ -16,6 +16,9 @@
package org.jitsi.meet.sdk;
import static org.jitsi.meet.sdk.NotificationChannels.ONGOING_CONFERENCE_CHANNEL_ID;
import static org.jitsi.meet.sdk.NotificationChannels.ONGOING_CONFERNCE_CHANNEL_NAME;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -39,9 +42,6 @@ import java.util.Random;
class OngoingNotification {
private static final String TAG = OngoingNotification.class.getSimpleName();
private static final String CHANNEL_ID = "JitsiNotificationChannel";
private static final String CHANNEL_NAME = "Ongoing Conference Notifications";
static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
private static long startingTime = 0;
@@ -60,13 +60,13 @@ class OngoingNotification {
= (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel
= notificationManager.getNotificationChannel(CHANNEL_ID);
= notificationManager.getNotificationChannel(ONGOING_CONFERENCE_CHANNEL_ID);
if (channel != null) {
// The channel was already created, no need to do it again.
return;
}
channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel = new NotificationChannel(ONGOING_CONFERENCE_CHANNEL_ID, ONGOING_CONFERNCE_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(false);
channel.enableVibration(false);
channel.setShowBadge(false);
@@ -82,9 +82,9 @@ class OngoingNotification {
}
Intent notificationIntent = new Intent(context, context.getClass());
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, ONGOING_CONFERENCE_CHANNEL_ID);
if (startingTime == 0) {
startingTime = System.currentTimeMillis();
@@ -125,7 +125,7 @@ class OngoingNotification {
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
intent.setAction(action.getName());
PendingIntent pendingIntent
= PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
= PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
String title = context.getString(titleId);
return new NotificationCompat.Action(0, title, pendingIntent);
}

View File

@@ -174,7 +174,7 @@ class ReactInstanceManagerHolder {
return;
}
SoLoader.init(activity, /* native exopackage */ false);
SoLoader.init(activity.getApplication(), /* native exopackage */ false);
List<ReactPackage> packages
= new ArrayList<>(Arrays.asList(

View File

@@ -24,6 +24,8 @@ import {
redirectToStaticPage,
reloadWithStoredParams
} from './react/features/app/actions';
import { showModeratedNotification } from './react/features/av-moderation/actions';
import { shouldShowModeratedNotification } from './react/features/av-moderation/functions';
import {
AVATAR_URL_COMMAND,
EMAIL_COMMAND,
@@ -44,7 +46,8 @@ import {
lockStateChanged,
onStartMutedPolicyChanged,
p2pStatusChanged,
sendLocalParticipant
sendLocalParticipant,
_conferenceWillJoin
} from './react/features/base/conference';
import { getReplaceParticipant } from './react/features/base/config/functions';
import {
@@ -119,7 +122,7 @@ import {
maybeOpenFeedbackDialog,
submitFeedback
} from './react/features/feedback';
import { showNotification } from './react/features/notifications';
import { isModerationNotificationDisplayed, showNotification } from './react/features/notifications';
import { mediaPermissionPromptVisibilityChanged, toggleSlowGUMOverlay } from './react/features/overlay';
import { suspendDetected } from './react/features/power-monitor';
import {
@@ -454,27 +457,12 @@ export default {
isSharingScreen: false,
/**
* The local audio track (if any).
* FIXME tracks from redux store should be the single source of truth
* @type {JitsiLocalTrack|null}
*/
localAudio: null,
/**
* The local presenter video track (if any).
* @type {JitsiLocalTrack|null}
*/
localPresenterVideo: null,
/**
* The local video track (if any).
* FIXME tracks from redux store should be the single source of truth, but
* more refactoring is required around screen sharing ('localVideo' usages).
* @type {JitsiLocalTrack|null}
*/
localVideo: null,
/**
* Returns an object containing a promise which resolves with the created tracks &
* the errors resulting from that process.
@@ -728,9 +716,7 @@ export default {
track.mute();
}
});
logger.log(`Initialized with ${tracks.length} local tracks`);
this._localTracksInitialized = true;
con.addEventListener(JitsiConnectionEvents.CONNECTION_FAILED, _connectionFailedHandler);
APP.connection = connection = con;
@@ -887,13 +873,24 @@ export default {
* dialogs in case of media permissions error.
*/
muteAudio(mute, showUI = true) {
const state = APP.store.getState();
if (!mute
&& isUserInteractionRequiredForUnmute(APP.store.getState())) {
&& isUserInteractionRequiredForUnmute(state)) {
logger.error('Unmuting audio requires user interaction');
return;
}
// check for A/V Moderation when trying to unmute
if (!mute && shouldShowModeratedNotification(MEDIA_TYPE.AUDIO, state)) {
if (!isModerationNotificationDisplayed(MEDIA_TYPE.AUDIO, state)) {
APP.store.dispatch(showModeratedNotification(MEDIA_TYPE.AUDIO));
}
return;
}
// Not ready to modify track's state yet
if (!this._localTracksInitialized) {
// This will only modify base/media.audio.muted which is then synced
@@ -907,7 +904,9 @@ export default {
return;
}
if (!this.localAudio && !mute) {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
if (!localAudio && !mute) {
const maybeShowErrorDialog = error => {
showUI && APP.store.dispatch(notifyMicError(error));
};
@@ -961,17 +960,18 @@ export default {
const maybeShowErrorDialog = error => {
showUI && APP.store.dispatch(notifyCameraError(error));
};
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
if (mute) {
try {
await this.localVideo.setEffect(undefined);
await localVideo.setEffect(undefined);
} catch (err) {
logger.error('Failed to remove the presenter effect', err);
maybeShowErrorDialog(err);
}
} else {
try {
await this.localVideo.setEffect(await this._createPresenterStreamEffect());
await localVideo.setEffect(await this._createPresenterStreamEffect());
} catch (err) {
logger.error('Failed to apply the presenter effect', err);
maybeShowErrorDialog(err);
@@ -1013,7 +1013,9 @@ export default {
return;
}
if (!this.localVideo && !mute) {
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
if (!localVideo && !mute) {
const maybeShowErrorDialog = error => {
showUI && APP.store.dispatch(notifyCameraError(error));
};
@@ -1327,14 +1329,14 @@ export default {
APP.conference.roomName,
this._getConferenceOptions());
APP.store.dispatch(conferenceWillJoin(room));
// Filter out the tracks that are muted (except on mobile Safari).
const tracks = isIosMobileBrowser() ? localTracks : localTracks.filter(track => !track.isMuted());
this._setLocalAudioVideoStreams(tracks);
this._room = room; // FIXME do not use this
APP.store.dispatch(_conferenceWillJoin(room));
sendLocalParticipant(APP.store, room);
this._setupListeners();
@@ -1347,7 +1349,7 @@ export default {
* @private
*/
_setLocalAudioVideoStreams(tracks = []) {
return tracks.map(track => {
const promises = tracks.map(track => {
if (track.isAudioTrack()) {
return this.useAudioStream(track);
} else if (track.isVideoTrack()) {
@@ -1356,12 +1358,16 @@ export default {
return this.useVideoStream(track);
}
logger.error(
'Ignored not an audio nor a video track: ', track);
logger.error('Ignored not an audio nor a video track: ', track);
return Promise.resolve();
});
return Promise.allSettled(promises).then(() => {
this._localTracksInitialized = true;
logger.log(`Initialized with ${tracks.length} local tracks`);
});
},
_getConferenceOptions() {
@@ -1383,29 +1389,20 @@ export default {
return new Promise((resolve, reject) => {
_replaceLocalVideoTrackQueue.enqueue(onFinish => {
const state = APP.store.getState();
const oldTrack = getLocalJitsiVideoTrack(APP.store.getState());
// When the prejoin page is displayed localVideo is not set
// so just replace the video track from the store with the new one.
if (isPrejoinPageVisible(state)) {
const oldTrack = getLocalJitsiVideoTrack(state);
logger.debug(`useVideoStream: Replacing ${oldTrack} with ${newTrack}`);
logger.debug(`useVideoStream on the prejoin screen: Replacing ${oldTrack} with ${newTrack}`);
if (oldTrack === newTrack) {
resolve();
onFinish();
return APP.store.dispatch(replaceLocalTrack(oldTrack, newTrack))
.then(resolve)
.catch(error => {
logger.error(`useVideoStream failed on the prejoin screen: ${error}`);
reject(error);
})
.then(onFinish);
return;
}
logger.debug(`useVideoStream: Replacing ${this.localVideo} with ${newTrack}`);
APP.store.dispatch(
replaceLocalTrack(this.localVideo, newTrack, room))
replaceLocalTrack(oldTrack, newTrack, room))
.then(() => {
this.localVideo = newTrack;
this._setSharingScreen(newTrack);
this.setVideoMuteStatus();
})
@@ -1455,23 +1452,18 @@ export default {
useAudioStream(newTrack) {
return new Promise((resolve, reject) => {
_replaceLocalAudioTrackQueue.enqueue(onFinish => {
const state = APP.store.getState();
const oldTrack = getLocalJitsiAudioTrack(APP.store.getState());
// When the prejoin page is displayed localAudio is not set
// so just replace the audio track from the store with the new one.
if (isPrejoinPageVisible(state)) {
const oldTrack = getLocalJitsiAudioTrack(state);
if (oldTrack === newTrack) {
resolve();
onFinish();
return APP.store.dispatch(replaceLocalTrack(oldTrack, newTrack))
.then(resolve)
.catch(reject)
.then(onFinish);
return;
}
APP.store.dispatch(
replaceLocalTrack(this.localAudio, newTrack, room))
replaceLocalTrack(oldTrack, newTrack, room))
.then(() => {
this.localAudio = newTrack;
this.setAudioMuteStatus(this.isLocalAudioMuted());
})
.then(resolve)
@@ -1546,7 +1538,9 @@ export default {
// If system audio was also shared stop the AudioMixerEffect and dispose of the desktop audio track.
if (this._mixerEffect) {
await this.localAudio.setEffect(undefined);
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
await localAudio.setEffect(undefined);
await this._desktopAudioStream.dispose();
this._mixerEffect = undefined;
this._desktopAudioStream = undefined;
@@ -1772,7 +1766,8 @@ export default {
// Create a new presenter track and apply the presenter effect.
if (!this.localPresenterVideo && !mute) {
const { height, width } = this.localVideo.track.getSettings() ?? this.localVideo.track.getConstraints();
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
const { height, width } = localVideo.track.getSettings() ?? localVideo.track.getConstraints();
const isPortrait = height >= width;
const DESKTOP_STREAM_CAP = 720;
@@ -1801,7 +1796,7 @@ export default {
// Apply the constraints on the desktop track.
try {
await this.localVideo.track.applyConstraints(desktopResizeConstraints);
await localVideo.track.applyConstraints(desktopResizeConstraints);
} catch (err) {
logger.error('Failed to apply constraints on the desktop stream for presenter mode', err);
@@ -1809,7 +1804,7 @@ export default {
}
}
const trackHeight = resizeDesktopStream
? this.localVideo.track.getSettings().height ?? DESKTOP_STREAM_CAP
? localVideo.track.getSettings().height ?? DESKTOP_STREAM_CAP
: height;
let effect;
@@ -1824,7 +1819,7 @@ export default {
// Replace the desktop track on the peerconnection.
try {
await this.localVideo.setEffect(effect);
await localVideo.setEffect(effect);
APP.store.dispatch(setVideoMuted(mute, MEDIA_TYPE.PRESENTER));
this.setVideoMuteStatus();
} catch (err) {
@@ -1880,12 +1875,14 @@ export default {
}
if (this._desktopAudioStream) {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
// If there is a localAudio stream, mix in the desktop audio stream captured by the screen sharing
// api.
if (this.localAudio) {
if (localAudio) {
this._mixerEffect = new AudioMixerEffect(this._desktopAudioStream);
await this.localAudio.setEffect(this._mixerEffect);
await localAudio.setEffect(this._mixerEffect);
} else {
// If no local stream is present ( i.e. no input audio devices) we use the screen share audio
// stream as we would use a regular stream.
@@ -2066,10 +2063,10 @@ export default {
});
room.on(JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED, (id, lvl) => {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
let newLvl = lvl;
if (this.isLocalId(id)
&& this.localAudio && this.localAudio.isMuted()) {
if (this.isLocalId(id) && localAudio?.isMuted()) {
newLvl = 0;
}
@@ -2311,6 +2308,7 @@ export default {
APP.UI.addListener(
UIEvents.VIDEO_DEVICE_CHANGED,
cameraDeviceId => {
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
const videoWasMuted = this.isLocalVideoMuted();
sendAnalytics(createDeviceChangedEvent('video', 'input'));
@@ -2318,7 +2316,7 @@ export default {
// If both screenshare and video are in progress, restart the
// presenter mode with the new camera device.
if (this.isSharingScreen && !videoWasMuted) {
const { height } = this.localVideo.track.getSettings();
const { height } = localVideo.track.getSettings();
// dispose the existing presenter track and create a new
// camera track.
@@ -2327,7 +2325,7 @@ export default {
this.localPresenterVideo = null;
return this._createPresenterStreamEffect(height, cameraDeviceId)
.then(effect => this.localVideo.setEffect(effect))
.then(effect => localVideo.setEffect(effect))
.then(() => {
this.setVideoMuteStatus();
logger.log('Switched local video device while screen sharing and the video is unmuted');
@@ -2340,7 +2338,7 @@ export default {
// that can be applied on un-mute.
} else if (this.isSharingScreen && videoWasMuted) {
logger.log('Switched local video device: while screen sharing and the video is muted');
const { height } = this.localVideo.track.getSettings();
const { height } = localVideo.track.getSettings();
this._updateVideoDeviceId();
@@ -2426,13 +2424,15 @@ export default {
return this.useAudioStream(stream);
})
.then(() => {
if (this.localAudio && hasDefaultMicChanged) {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
if (localAudio && hasDefaultMicChanged) {
// workaround for the default device to be shown as selected in the
// settings even when the real device id was passed to gUM because of the
// above mentioned chrome bug.
this.localAudio._realDeviceId = this.localAudio.deviceId = 'default';
localAudio._realDeviceId = localAudio.deviceId = 'default';
}
logger.log(`switched local audio device: ${this.localAudio?.getDeviceId()}`);
logger.log(`switched local audio device: ${localAudio?.getDeviceId()}`);
this._updateAudioDeviceId();
})
@@ -2498,9 +2498,6 @@ export default {
JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED,
this.deviceChangeListener);
}
this.localVideo = null;
this.localAudio = null;
},
/**
@@ -2563,10 +2560,11 @@ export default {
* @private
*/
_updateVideoDeviceId() {
if (this.localVideo
&& this.localVideo.videoType === 'camera') {
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
if (localVideo && localVideo.videoType === 'camera') {
APP.store.dispatch(updateSettings({
cameraDeviceId: this.localVideo.getDeviceId()
cameraDeviceId: localVideo.getDeviceId()
}));
}
@@ -2584,9 +2582,11 @@ export default {
* @private
*/
_updateAudioDeviceId() {
if (this.localAudio) {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
if (localAudio) {
APP.store.dispatch(updateSettings({
micDeviceId: this.localAudio.getDeviceId()
micDeviceId: localAudio.getDeviceId()
}));
}
},
@@ -2600,6 +2600,8 @@ export default {
*/
_onDeviceListChanged(devices) {
const oldDevices = APP.store.getState()['features/base/devices'].availableDevices;
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
APP.store.dispatch(updateDeviceList(devices));
@@ -2607,8 +2609,8 @@ export default {
= mediaDeviceHelper.getNewMediaDevicesAfterDeviceListChanged(
devices,
this.isSharingScreen,
this.localVideo,
this.localAudio);
localVideo,
localAudio);
const promises = [];
const audioWasMuted = this.isLocalAudioMuted();
const videoWasMuted = this.isLocalVideoMuted();
@@ -2631,12 +2633,12 @@ export default {
// simpler):
// If the default device is changed we need to first stop the local streams and then call GUM. Otherwise GUM
// will return a stream using the old default device.
if (requestedInput.audio && this.localAudio) {
this.localAudio.stopStream();
if (requestedInput.audio && localAudio) {
localAudio.stopStream();
}
if (requestedInput.video && this.localVideo) {
this.localVideo.stopStream();
if (requestedInput.video && localVideo) {
localVideo.stopStream();
}
// Let's handle unknown/non-preferred devices
@@ -2716,15 +2718,16 @@ export default {
= mediaType === 'audio'
? this.useAudioStream.bind(this)
: this.useVideoStream.bind(this);
const track = tracks.find(t => t.getType() === mediaType) || null;
// Use the new stream or null if we failed to obtain it.
return useStream(tracks.find(track => track.getType() === mediaType) || null)
return useStream(track)
.then(() => {
if (this.localAudio && hasDefaultMicChanged) {
if (track?.isAudioTrack() && hasDefaultMicChanged) {
// workaround for the default device to be shown as selected in the
// settings even when the real device id was passed to gUM because of
// the above mentioned chrome bug.
this.localAudio._realDeviceId = this.localAudio.deviceId = 'default';
track._realDeviceId = track.deviceId = 'default';
}
mediaType === 'audio'
? this._updateAudioDeviceId()
@@ -2764,14 +2767,13 @@ export default {
* Determines whether or not the audio button should be enabled.
*/
updateAudioIconEnabled() {
const audioMediaDevices
= APP.store.getState()['features/base/devices'].availableDevices.audioInput;
const audioDeviceCount
= audioMediaDevices ? audioMediaDevices.length : 0;
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
const audioMediaDevices = APP.store.getState()['features/base/devices'].availableDevices.audioInput;
const audioDeviceCount = audioMediaDevices ? audioMediaDevices.length : 0;
// The audio functionality is considered available if there are any
// audio devices detected or if the local audio stream already exists.
const available = audioDeviceCount > 0 || Boolean(this.localAudio);
const available = audioDeviceCount > 0 || Boolean(localAudio);
APP.store.dispatch(setAudioAvailable(available));
APP.API.notifyAudioAvailabilityChanged(available);
@@ -2785,13 +2787,14 @@ export default {
= APP.store.getState()['features/base/devices'].availableDevices.videoInput;
const videoDeviceCount
= videoMediaDevices ? videoMediaDevices.length : 0;
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
// The video functionality is considered available if there are any
// video devices detected or if there is local video stream already
// active which could be either screensharing stream or a video track
// created before the permissions were rejected (through browser
// config).
const available = videoDeviceCount > 0 || Boolean(this.localVideo);
const available = videoDeviceCount > 0 || Boolean(localVideo);
APP.store.dispatch(setVideoAvailable(available));
APP.API.notifyVideoAvailabilityChanged(available);
@@ -2809,8 +2812,6 @@ export default {
APP.store.dispatch(destroyLocalTracks());
this._localTracksInitialized = false;
this.localVideo = null;
this.localAudio = null;
// Remove unnecessary event listeners from firing callbacks.
if (this.deviceChangeListener) {

View File

@@ -41,9 +41,16 @@ var config = {
// issues related to insertable streams.
// disableE2EE: false,
// Enables/disables thumbnail reordering in the filmstrip. It is enabled by default unless explicitly
// disabled by the below option.
// enableThumbnailReordering: true,
// Enables XMPP WebSocket (as opposed to BOSH) for the given amount of users.
// mobileXmppWsThreshold: 10 // enable XMPP WebSockets on mobile for 10% of the users
// P2P test mode disables automatic switching to P2P when there are 2
// participants in the conference.
p2pTestMode: false
// p2pTestMode: false,
// Enables the test specific features consumed by jitsi-meet-torture
// testMode: false
@@ -67,8 +74,11 @@ var config = {
// callStatsThreshold: 5 // enable callstats for 5% of the users.
},
// Enables reactions feature.
// enableReactions: false,
// Disables moderator indicators.
// disableModeratorIndicator: false,
// Disables the reactions feature.
// disableReactions: true,
// Disables polls feature.
// disablePolls: false,
@@ -535,6 +545,43 @@ var config = {
// '__end'
// ],
// Toolbar buttons which have their click event exposed through the API on
// `toolbarButtonClicked` event instead of executing the normal click routine.
// buttonsWithNotifyClick: [
// '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'
// ],
// List of pre meeting screens buttons to hide. The values must be one or more of the 5 allowed buttons:
// 'microphone', 'camera', 'select-background', 'invite', 'settings'
// hiddenPremeetingButtons: [],
@@ -696,6 +743,7 @@ var config = {
// Array<string> of disabled sounds.
// Possible values:
// - 'ASKED_TO_UNMUTE_SOUND'
// - 'E2EE_OFF_SOUND'
// - 'E2EE_ON_SOUND'
// - 'INCOMING_MSG_SOUND'
@@ -859,15 +907,32 @@ var config = {
// If true, tile view will not be enabled automatically when the participants count threshold is reached.
// disableTileView: true,
// Controls the visibility and behavior of the top header conference info labels.
// If a label's id is not in any of the 2 arrays, it will not be visible at all on the header.
// conferenceInfo: {
// // those labels will not be hidden in tandem with the toolbox.
// alwaysVisible: ['recording', 'local-recording'],
// // those labels will be auto-hidden in tandem with the toolbox buttons.
// autoHide: [
// 'subject',
// 'conference-timer',
// 'participants-count',
// 'e2ee',
// 'transcribing',
// 'video-quality',
// 'insecure-room'
// ]
// },
// Hides the conference subject
// hideConferenceSubject: true,
// Hides the recording label
// hideRecordingLabel: false,
// Hides the conference timer.
// hideConferenceTimer: true,
// Hides the recording label
// hideRecordingLabel: false,
// Hides the participants stats
// hideParticipantsStats: true,

View File

@@ -106,9 +106,7 @@ export async function connect(id, password, roomName) {
serviceUrl += `?room=${roomName}`;
// FIXME Remove deprecated 'bosh' option assignment at some point(LJM will be accepting only 'serviceUrl' option
// in future). It's included for the time being for Jitsi Meet and lib-jitsi-meet versions interoperability.
connectionConfig.serviceUrl = connectionConfig.bosh = serviceUrl;
connectionConfig.serviceUrl = serviceUrl;
if (connectionConfig.websocketKeepAliveUrl) {
connectionConfig.websocketKeepAliveUrl += `?room=${roomName}`;

View File

@@ -2,7 +2,7 @@
.reactions-menu {
width: 280px;
background: #292929;
background: $menuBG;
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;

View File

@@ -1,54 +1,22 @@
.subject {
box-sizing: border-box;
color: #fff;
margin-top: 20px;
position: absolute;
top: -120px;
transition: top .3s ease-in;
width: 100%;
margin-top: -120px;
transition: margin-top .3s ease-in;
z-index: $zindex3;
&.visible {
top: 0;
margin-top: 20px;
}
&.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 {
display: flex;
justify-content: center;
max-width: calc(100% - 280px);
margin: 0 auto;
&--full-width {
max-width: 100%;
}
height: 28px;
@media (max-width: 500px) {
flex-wrap: wrap;
max-width: 100%;
}
}
@@ -63,21 +31,47 @@
.subject-text {
background: rgba(0, 0, 0, 0.6);
border-radius: 3px 0px 0px 3px;
box-sizing: border-box;
font-size: 14px;
line-height: 24px;
padding: 2px 16px;
height: 24px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 28px;
padding: 0 16px;
height: 28px;
@media (max-width: 700px) {
max-width: 100px;
}
@media (max-width: 300px) {
display: none;
}
&--content {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.subject-timer {
background: rgba(0, 0, 0, 0.8);
border-radius: 0px 3px 3px 0px;
display: inline-block;
box-sizing: border-box;
font-size: 12px;
line-height: 16px;
line-height: 28px;
min-width: 34px;
padding: 6px 8px;
padding: 0 8px;
height: 28px;
@media (max-width: 300px) {
display: none;
}
}
.details-container {
width: 100%;
display: flex;
justify-content: center;
position: absolute;
top: 0;
height: 48px;
}

View File

@@ -84,6 +84,10 @@
margin-bottom: 3px;
margin-left: $remoteVideoMenuIconMargin;
}
.self-view-mobile-portrait video {
object-fit: contain;
}
}
/**
@@ -112,3 +116,11 @@
transition-delay: 0.1s;
}
}
/**
* Overrides for self view when in portrait mode on mobile.
* This is done in order to keep the aspect ratio.
*/
.vertical-filmstrip .self-view-mobile-portrait #localVideo_container {
object-fit: contain;
}

View File

@@ -11,7 +11,7 @@
background-color: rgba(0, 0, 0, 0.7);
align-items: center;
display: flex;
padding: 8px 12px;
padding: 14px 16px;
}
&-circle {

View File

@@ -1,16 +1,25 @@
.device {
&-status {
align-items: center;
align-self: stretch;
color: #fff;
display: flex;
font-size: 14px;
font-weight: 400;
justify-content: center;
line-height: 20px;
margin-top: 8px;
padding: 6px;
text-align: center;
&-error {
align-items: flex-start;
background-color: #F8AE1A;
border-radius: 6px;
color: #040404;
padding: 12px 16px;
text-align: left;
}
span {
margin-left: 16px;
}
}
&-icon {
@@ -18,14 +27,8 @@
background-repeat: no-repeat;
display: inline-block;
height: 16px;
margin-right: 10px;
width: 16px;
&--warning {
svg path {
fill: rgba(241, 173, 51, 1);
}
}
&--ok {
svg path {
fill: #189b55;

View File

@@ -3,21 +3,16 @@
width: 100%;
}
&-checkbox-container {
margin-bottom: 16px;
width: 100%;
text-align: center;
}
&-error {
color: white;
background-color: #E04757;
border-radius: 6px;
padding: 4px;
box-sizing: border-box;
color: white;
font-size: 12px;
line-height: 16px;
margin-bottom: 16px;
margin-top: -8px;
font-size: 12px;
padding: 4px;
text-align: center;
width: 100%;
}

View File

@@ -16,6 +16,7 @@
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: 600;
line-height: 24px;
margin-bottom: 16px;
padding: 7px 16px;
@@ -128,10 +129,22 @@
#new-toolbox {
bottom: 0;
margin-bottom: 16px;
position: relative;
transition: none;
.toolbox-content {
margin-bottom: 4px;
}
.toolbox-content-items {
background: transparent;
border-radius: 0;
box-shadow: none;
display: flex;
justify-content: space-evenly;
padding: 8px 0;
}
.toolbox-content,
.toolbox-content-wrapper,
.toolbox-content-items {
@@ -163,17 +176,26 @@
padding: 16px;
width: 100%;
&-controls {
input.field {
font-size: 16px;
padding: 14px 16px;
}
}
.title {
font-size: 20px;
line-height: 28px;
letter-spacing: -0.012;
margin-bottom: 24px;
display: none;
}
}
.con-status {
margin: 16px;
width: calc(100% - 32px);
margin: 0;
width: 100%;
}
.device-status-error {
border-radius: 0;
margin: 0 -16px;
}
input.field {
@@ -183,15 +205,9 @@
.action-btn {
font-size: 16px;
margin-bottom: 8px;
padding: 11px 16px;
}
.toolbox-content-items {
border-radius: 0;
display: flex;
justify-content: space-evenly;
padding: 8px 0;
}
}
input::placeholder {
@@ -227,68 +243,3 @@
display: flex;
justify-content: center;
}
@mixin icon-container($bg, $fill) {
.toggle-button-icon-container {
background: $bg;
svg {
fill: $fill
}
}
}
.toggle-button {
border-radius: 6px;
cursor: pointer;
color: #fff;
font-size: 13px;
height: 40px;
margin: 0 auto;
transition: background 0.16s ease-out;
@include flex-centered();
svg {
fill: transparent;
}
label {
cursor: pointer;
}
&:hover {
background: rgba(255, 255, 255, 0.1);
.toggle-button-icon-container {
display: none;
}
}
&-container {
position: relative;
@include flex-centered();
}
&-icon-container {
border-radius: 50%;
left: -22px;
padding: 2px;
position: absolute;
}
&--toggled {
@include icon-container(white, #1C2025);
&:hover {
.toggle-button-icon-container {
display: block;
}
}
.toggle-button-icon-container {
display: block;
}
}
}

View File

@@ -39,7 +39,8 @@ var interfaceConfig = {
DISABLE_DOMINANT_SPEAKER_INDICATOR: false,
DISABLE_FOCUS_INDICATOR: false,
// Deprecated. Please use disableModeratorIndicator from config.js
// DISABLE_FOCUS_INDICATOR: false,
/**
* If true, notifications regarding joining/leaving are no longer displayed.

View File

@@ -299,7 +299,7 @@ PODS:
- react-native-video/Video (= 5.1.1)
- react-native-video/Video (5.1.1):
- React-Core
- react-native-webrtc (1.92.1):
- react-native-webrtc (1.92.2):
- React-Core
- react-native-webview (11.0.2):
- React-Core
@@ -584,7 +584,7 @@ SPEC CHECKSUMS:
react-native-slider: b733e17fdd31186707146debf1f04b5d94aa1a93
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
react-native-video: 1574074179ecaf6a9dd067116c8f31bf9fec15c8
react-native-webrtc: 77b969fe6bc5b7c93b455f93a13698812fb8bb4e
react-native-webrtc: 41526e4060dac373c18676f866962d4180ee47b9
react-native-webview: b2542d6fd424bcc3e3b2ec5f854f0abb4ec86c87
React-RCTActionSheet: bcbc311dc3b47bc8efb2737ff0940239a45789a9
React-RCTAnimation: 65f61080ce632f6dea23d52e354ffac9948396c6

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>21.4.0</string>
<string>21.4.3</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>21.4.0</string>
<string>21.4.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>21.4.0</string>
<string>21.4.3</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>UISupportedInterfaceOrientations</key>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>21.4.0</string>
<string>21.4.3</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CLKComplicationPrincipalClass</key>

View File

@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.9.0</string>
<string>3.10.4</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>

View File

@@ -127,6 +127,7 @@
}
- (void)destroyReactNativeBridge {
[_bridgeWrapper invalidate];
_bridgeWrapper = nil;
}

View File

@@ -34,4 +34,6 @@
@property (nonatomic, readonly, strong) RCTBridge *bridge;
- (void)invalidate;
@end

View File

@@ -33,6 +33,10 @@
return self;
}
- (void)invalidate {
[_bridge invalidate];
}
#pragma mark helper methods for getting the packager URL
#if DEBUG

View File

@@ -49,9 +49,11 @@
"messagebox": "",
"nickname": {
"popover": "Kies n bynaam",
"title": ""
"title": "",
"titleWithPolls": ""
},
"title": ""
"title": "",
"titleWithPolls": ""
},
"connectingOverlay": {
"joiningRoom": ""

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "لا يوجد أي رسالة في الاجتماع بعد. ابدأ محادثة هنا.",
"nickname": {
"popover": "اختر لقبًا",
"title": "اكتب لقبًا لاعتماده في المحادثة"
"title": "اكتب لقبًا لاعتماده في المحادثة",
"titleWithPolls": "اكتب لقبًا لاعتماده في المحادثة"
},
"privateNotice": "أرسل رسالة خاصة إلى {{recipient}}",
"title": "محادثة",
"titleWithPolls": "محادثة",
"you": "أنت"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "У канферэнцыі пакуль няма ніякіх паведамленняў. Пачніце размову!",
"nickname": {
"popover": "Калі ласка, пазначце імя",
"title": "Калі ласка, увядзіце імя для выкарыстання чата"
"title": "Калі ласка, увядзіце імя для выкарыстання чата",
"titleWithPolls": "Калі ласка, увядзіце імя для выкарыстання чата"
},
"privateNotice": "Асабістае паведамленне карыстальнiку {{recipient}}",
"title": "Чат",
"titleWithPolls": "Чат",
"you": "Вы"
},
"chromeExtensionBanner": {

View File

@@ -65,10 +65,12 @@
"noMessagesMessage": "Все още няма съобщения в срещата. Започнете разговор тук!",
"nickname": {
"popover": "Избор на име",
"title": "Въведете име, за да обменяте съобщения"
"title": "Въведете име, за да обменяте съобщения",
"titleWithPolls": "Въведете име, за да обменяте съобщения"
},
"privateNotice": "Лично съобщение до {{recipient}}",
"title": "Текстови съобщения",
"titleWithPolls": "Текстови съобщения",
"you": "вие"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Encara no hi ha cap missatge en aquesta reunió. Comenceu una conversa aquí!",
"nickname": {
"popover": "Trieu un sobrenom",
"title": "Introduïu un sobrenom per a usar el xat"
"title": "Introduïu un sobrenom per a usar el xat",
"titleWithPolls": "Introduïu un sobrenom per a usar el xat"
},
"privateNotice": "Missatge privat per a {{recipient}}",
"title": "Xat",
"titleWithPolls": "Xat",
"you": "vós"
},
"chromeExtensionBanner": {

View File

@@ -67,11 +67,13 @@
"messagebox": "Napište zprávu",
"nickname": {
"popover": "Zvolte si přezdívku",
"title": "Vložte přezdívku, abyste mohl/a používat zprávy"
"title": "Vložte přezdívku, abyste mohl/a používat zprávy",
"titleWithPolls": "Vložte přezdívku, abyste mohl/a používat zprávy"
},
"noMessagesMessage": "V setkání zatím nejsou žádné zprávy. Tady můžete začít konverzaci!",
"privateNotice": "Soukromá zpráva pro {{recipient}}",
"title": "Zprávy",
"titleWithPolls": "Zprávy",
"you": "vy"
},
"chromeExtensionBanner": {

View File

@@ -54,10 +54,12 @@
"noMessagesMessage": "Der er ikke nogen beskeder i mødet endnu. Skriv noget!",
"nickname": {
"popover": "Vælg dit navn/alias",
"title": "Indtast et navn/alias for at deltage i chatten"
"title": "Indtast et navn/alias for at deltage i chatten",
"titleWithPolls": "Indtast et navn/alias for at deltage i chatten"
},
"privateNotice": "Privat besked til {{recipient}}",
"title": "Chat",
"titleWithPolls": "Chat",
"you": "Dig"
},
"chromeExtensionBanner": {

View File

@@ -66,15 +66,21 @@
"noMessagesMessage": "Es gibt noch keine Nachricht in dieser Konferenz. Starten Sie hier eine Unterhaltung!",
"nickname": {
"popover": "Wähle einen Alias",
"title": "Geben Sie einen Alias zum Chatten ein"
"title": "Geben Sie einen Alias zum Chatten ein",
"titleWithPolls": "Geben Sie einen Alias zum Chatten ein"
},
"privateNotice": "Private Nachricht an {{recipient}}",
"title": "Chatten",
"you": "Sie",
"message": "Nachricht",
"messageAccessibleTitle": "{{user}} sagt:",
"messageAccessibleTitleMe": "Ich sage:",
"smileysPanel": "Emoji-Auswahl"
"smileysPanel": "Emoji-Auswahl",
"tabs": {
"chat": "Chatten",
"polls": "Umfragen"
},
"title": "Chatten",
"titleWithPolls": "Chatten und Umfragen",
"you": "Sie"
},
"chromeExtensionBanner": {
"installExtensionText": "Installieren Sie die Erweiterung für die Integration von Google Calendar und Office 365",
@@ -243,13 +249,17 @@
"micPermissionDeniedError": "Die Berechtigung zur Verwendung des Mikrofons wurde nicht erteilt. Sie können trotzdem an der Konferenz teilnehmen, aber die anderen Personen können Sie nicht hören. Verwenden Sie die Kamera-Schaltfläche in der Adressleiste, um die Berechtigungen zu erteilen.",
"micTimeoutError": "Audioquelle konnte nicht gestartet werden. Zeitüberschreitung",
"micUnknownError": "Das Mikrofon kann aus einem unbekannten Grund nicht verwendet werden.",
"moderationAudioLabel": "Erlaube Anwesenden die Stummschaltung für sich aufzuheben",
"moderationVideoLabel": "Erlaube Anwesenden ihre Kamera einzuschalten",
"muteEveryoneElseDialog": "Einmal stummgeschaltet, können Sie deren Stummschaltung nicht mehr beenden, aber sie können ihre Stummschaltung jederzeit selbst beenden.",
"muteEveryoneElseTitle": "Alle außer {{whom}} stummschalten?",
"muteEveryoneDialog": "Wollen Sie wirklich alle stummschalten? Sie können deren Stummschaltung nicht mehr beenden, aber sie können ihre Stummschaltung jederzeit selbst beenden.",
"muteEveryoneDialogModerationOn": "Die Anwesenden können eine Anfrage zum Sprechen jederzeit senden.",
"muteEveryoneTitle": "Alle stummschalten?",
"muteEveryoneElsesVideoDialog": "Sobald die Kamera deaktiviert ist, können Sie sie nicht wieder aktivieren, die Teilnehmer können dies aber jederzeit wieder ändern.",
"muteEveryoneElsesVideoTitle": "Die Kamera von allen außer {{whom}} ausschalten?",
"muteEveryonesVideoDialog": "Sind Sie sicher, dass Sie die Kamera von allen Teilnehmern deaktivieren möchten? Sie können sie nicht wieder aktivieren, die Teilnehmer können dies aber jederzeit wieder ändern.",
"muteEveryonesVideoDialogModerationOn": "Die Anwesenden können jederzeit eine Anfrage senden, um ihre Kamera einzuschalten.",
"muteEveryonesVideoDialogOk": "deaktivieren",
"muteEveryonesVideoTitle": "Die Kamera von allen anderen ausschalten?",
"muteEveryoneSelf": "sich selbst",
@@ -382,7 +392,8 @@
"image7" : "Sonnenaufgang",
"desktopShareError": "Desktop konnte nicht freigegeben werden",
"desktopShare": "Desktopfreigabe",
"webAssemblyWarning": "WebAssembly wird nicht unterstützt"
"webAssemblyWarning": "WebAssembly wird nicht unterstützt",
"backgroundEffectError": "Failed to apply background effect."
},
"feedback": {
"average": "Durchschnittlich",
@@ -587,6 +598,8 @@
"moderationStoppedTitle": "Moderation gestoppt",
"moderationToggleDescription": "von {{participantDisplayName}}",
"raiseHandAction": "Melden",
"groupTitle": "Benachrichtigungen",
"reactionSounds": "Interaktionstöne deaktivieren",
"groupTitle": "Benachrichtigungen"
},
"participantsPane": {
@@ -599,20 +612,49 @@
},
"actions": {
"allow": "Anwesenden erlauben:",
"audioModeration": "Für sich selbst die Stummschaltung aufzuheben",
"blockEveryoneMicCamera": "Kamera und Mikrofon von allen sperren",
"invite": "Person einladen",
"askUnmute": "Anfragen, Stummschaltung aufzuheben",
"mute": "Stummschalten",
"muteAll": "Alle stummschalten",
"muteEveryoneElse": "Alle anderen stummschalten",
"startModeration": "Stummschaltung aufheben oder Kamera aktivieren",
"stopEveryonesVideo": "Alle Kameras ausschalten",
"stopVideo": "Kamera ausschalten",
"unblockEveryoneMicCamera": "Kamera und Mikrofon von allen entsperren"
"unblockEveryoneMicCamera": "Kamera und Mikrofon von allen entsperren",
"videoModeration": "Kamera einschalten"
}
},
"passwordSetRemotely": "von einer anderen Person gesetzt",
"passwordDigitsOnly": "Bis zu {{number}} Ziffern",
"polls": {
"create": {
"addOption": "Antwort hinzufügen",
"answerPlaceholder": "Antwort {{index}}",
"create": "Umfrage erstellen",
"cancel": "Abbrechen",
"pollOption" : "Antwort {{index}}",
"pollQuestion" : "Frage",
"questionPlaceholder": "Eine Frage stellen",
"removeOption": "Antwort entfernen",
"send": "Erstellen"
},
"answer": {
"skip": "Überspringen",
"submit": "Speichern"
},
"results": {
"vote": "Vote",
"changeVote": "Antwort ändern",
"empty": "Es gibt bisher keine Umfragen in dieser Konferenz. Sie können hier eine Umfrage starten!",
"hideDetailedResults": "Details verbergen",
"showDetailedResults": "Details anzeigen"
},
"notification": {
"title": "Dieser Konferenz wurde eine Umfrage hinzugefügt",
"description": "Öffnen Sie das Umfragen-Tab um abzustimmen"
}
},
"poweredby": "Betrieben von",
"prejoin": {
"audioAndVideoError": "Audio- und Videofehler:",
@@ -762,6 +804,7 @@
"participantJoined": "Neue Person nimmt teil",
"participantLeft": "Person verlässt die Konferenz",
"playSounds": "Hinweistöne aktiviert",
"reactions": "Interaktionen",
"sameAsSystem": "Wie System ({{label}})",
"selectAudioOutput": "Audioausgabe",
"selectCamera": "Kamera",
@@ -852,7 +895,6 @@
"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",
@@ -869,6 +911,7 @@
"shareYourScreen": "Bildschirmfreigabe ein-/ausschalten",
"shortcuts": "Tastenkombinationen ein-/ausblenden",
"show": "Im Vordergrund anzeigen",
"silence": "Stille",
"speakerStats": "Sprechstatistik ein-/ausblenden",
"surprised": "Überrascht",
"tileView": "Kachelansicht ein-/ausschalten",
@@ -893,6 +936,7 @@
"clap": "Klatschen",
"closeChat": "Chat schließen",
"closeReactionsMenu": "Interationsmenü schließen",
"disableReactionSounds": "Sie können die Interaktionstöne für diese Konferenz deaktivieren",
"documentClose": "Geteiltes Dokument schließen",
"documentOpen": "Geteiltes Dokument öffnen",
"download": "Unsere Apps herunterladen",
@@ -928,7 +972,6 @@
"openChat": "Chat öffnen",
"openReactionsMenu": "Interationsmenü öffnen",
"participants": "Anwesende",
"party": "Konfetti",
"pip": "Bild-in-Bild-Modus einschalten",
"privateMessage": "Private Nachricht senden",
"profile": "Profil bearbeiten",
@@ -938,7 +981,7 @@
"reactionClap": "Klatschen senden",
"reactionLaugh": "Lachen senden",
"reactionLike": "Daumen hoch senden",
"reactionParty": "Konfetti senden",
"reactionSilence": "Stille senden",
"reactionSurprised": "Überrascht senden",
"security": "Sicherheitsoptionen",
"Settings": "Einstellungen",
@@ -946,6 +989,7 @@
"sharedvideo": "YouTube-Video teilen",
"shareRoom": "Person einladen",
"shortcuts": "Tastenkürzel anzeigen",
"silence": "Stille",
"speakerStats": "Sprechstatistik",
"startScreenSharing": "Bildschirmfreigabe starten",
"startSubtitles": "Untertitel einschalten",
@@ -1098,6 +1142,7 @@
"enableDialogText": "Mit dem Lobbymodus schützen Sie Ihre Konferenz, damit der Beitritt von Ihnen moderiert werden kann.",
"enterPasswordButton": "Konferenzpasswort eingeben",
"enterPasswordTitle": "Passwort zum Beitreten benutzen",
"errorMissingPassword": "Bitte das Konferenzpasswort eingeben",
"invalidPassword": "Ungültiges Passwort",
"joiningMessage": "Sie treten der Konferenz bei, sobald jemand Ihre Anfrage annimmt.",
"joinWithPasswordMessage": "Beitrittsversuch mit Passwort, bitte warten …",

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "Δεν υπάρχουν μηνύματα στη συνάντηση ακόμα. Ξεκινήστε μια συζήτηση εδώ!",
"nickname": {
"popover": "Επιλέξτε ένα ψευδώνυμο",
"title": "Εισάγετε ένα ψευδώνυμο για τη χρήση της συνομιλίας"
"title": "Εισάγετε ένα ψευδώνυμο για τη χρήση της συνομιλίας",
"titleWithPolls": "Εισάγετε ένα ψευδώνυμο για τη χρήση της συνομιλίας"
},
"privateNotice": "Ιδιωτικό μηνύμα στον / στην {recipient}}",
"title": "Συνομιλία",
"titleWithPolls": "Συνομιλία",
"you": "Εσείς"
},
"chromeExtensionBanner": {

View File

@@ -50,9 +50,11 @@
"messagebox": "Type a message",
"nickname": {
"popover": "Choose a nickname",
"title": "Enter a nickname to use chat"
"title": "Enter a nickname to use chat",
"titleWithPolls": "Enter a nickname to use chat"
},
"title": "Chat",
"titleWithPolls": "Chat",
"you": "",
"privateNotice": "",
"noMessagesMessage": "",

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Ankoraŭ ne estas mesaĝoj en la kunveno. Komencu konversation ĉi tie!",
"nickname": {
"popover": "Elektu kaŝnomon",
"title": "Elektu kaŝnomon por uzi la babilejon"
"title": "Elektu kaŝnomon por uzi la babilejon",
"titleWithPolls": "Elektu kaŝnomon por uzi la babilejon"
},
"privateNotice": "Privata mesaĝo al {{recipient}}",
"title": "Babilejo",
"titleWithPolls": "Babilejo",
"you": "vi"
},
"chromeExtensionBanner": {

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "No hay mensajes en la reunión. ¡Inicie una conversación!",
"nickname": {
"popover": "Selecciona un apodo",
"title": "Introduce un apodo para usar el chat"
"title": "Introduce un apodo para usar el chat",
"titleWithPolls": "Introduce un apodo para usar el chat"
},
"privateNotice": "Mensaje privado para {{recipient}}",
"title": "Chat",
"titleWithPolls": "Chat",
"you": "usted"
},
"chromeExtensionBanner": {

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "No hay mensajes en la reunión. ¡Inicie una conversación!",
"nickname": {
"popover": "Selecciona un apodo",
"title": "Introduce un apodo para usar el chat"
"title": "Introduce un apodo para usar el chat",
"titleWithPolls": "Introduce un apodo para usar el chat"
},
"privateNotice": "Mensaje privado para {{recipient}}",
"title": "Chat",
"titleWithPolls": "Chat",
"you": "usted"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Kirjavahetust pole veel alustatud. Alusta kirjavahetust siin!",
"nickname": {
"popover": "Sisesta nimi",
"title": "Sisesta nimi, et kõnega alustada"
"title": "Sisesta nimi, et kõnega alustada",
"titleWithPolls": "Sisesta nimi, et kõnega alustada"
},
"privateNotice": "Privaatsõnum kasutajale {{recipient}}",
"title": "Kõne",
"titleWithPolls": "Kõne",
"you": "you"
},
"chromeExtensionBanner": {

View File

@@ -64,10 +64,12 @@
"noMessagesMessage": "Bileran oraindik mezurik ez dago. Hasi elkarrizketa hemen!",
"nickname": {
"popover": "Aukeratu goitizena",
"title": "Sartu goitizena txata erabiltzeko"
"title": "Sartu goitizena txata erabiltzeko",
"titleWithPolls": "Sartu goitizena txata erabiltzeko"
},
"privateNotice": "Mezu pribatua {{recipient}}(e)ri",
"title": "Txata",
"titleWithPolls": "Txata",
"you": "zu",
"message": "Mezua",
"messageAccessibleTitle": "{{user}} partaideak zera dio:",

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "هیچ گفتگویی در جلسه وجود ندارد، گفتگو را شما آعاز کنید!",
"nickname": {
"popover": "نام نمایشی خود را وارد نمایید",
"title": "نام نمایشی خود را در گفتگو وارد نمایید"
"title": "نام نمایشی خود را در گفتگو وارد نمایید",
"titleWithPolls": "نام نمایشی خود را در گفتگو وارد نمایید"
},
"privateNotice": "پیام خصوصی به {{recipient}}",
"title": "گفتگو",
"titleWithPolls": "گفتگو",
"you": "شما"
},
"chromeExtensionBanner": {

View File

@@ -49,9 +49,11 @@
"messagebox": "Kirjoita viesti",
"nickname": {
"popover": "Valitse lempinimi",
"title": "Anna chatissä käytettävä lempinimi"
"title": "Anna chatissä käytettävä lempinimi",
"titleWithPolls": "Anna chatissä käytettävä lempinimi"
},
"title": "Chatti"
"title": "Chatti",
"titleWithPolls": "Chatti"
},
"connectingOverlay": {
"joiningRoom": "Yhdistetään kokoukseen…"

View File

@@ -66,7 +66,8 @@
"noMessagesMessage": "Il n'y a pas encore de messages dans cette réunion. Démarrez une conversation ici !",
"nickname": {
"popover": "Choisissez un pseudonyme",
"title": "Entrez un pseudonyme pour utiliser le chat et les sondages"
"title": "Entrez un pseudonyme pour utiliser le chat",
"titleWithPolls": "Entrez un pseudonyme pour utiliser le chat et les sondages"
},
"privateNotice": "Message privé à {{recipient}}",
"message": "Message",
@@ -74,11 +75,12 @@
"messageAccessibleTitleMe": "Je dis: ",
"smileysPanel": "Panneaux des Émojis",
"tabs": {
"chat": "Chat",
"polls": "Sondages"
},
"title": "Chat et Sondages",
"you": "vous"
"chat": "Chat",
"polls": "Sondages"
},
"title": "Chat",
"titleWithPolls": "Chat et Sondages",
"you": "vous"
},
"chromeExtensionBanner": {
"installExtensionText": "Installer l'extension pour l'intégration de Google Calendar et Office 365",

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Il n'y a pas encore de messages dans cette réunion. Démarrez une conversation ici !",
"nickname": {
"popover": "Choisissez un nom d'affichage",
"title": "Entrer un nom d'affichage pour utiliser le clavardage"
"title": "Entrer un nom d'affichage pour utiliser le clavardage",
"titleWithPolls": "Entrer un nom d'affichage pour utiliser le clavardage"
},
"privateNotice": "Message privé à {{recipient}}",
"title": "Clavardage",
"titleWithPolls": "Clavardage",
"you": "vous"
},
"connectingOverlay": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Aínda non hai mensaxes na reunión. Comece unha conversación aquí!",
"nickname": {
"popover": "Escolla un alcume",
"title": "Escriba un alcume para utilizar no chat"
"title": "Escriba un alcume para utilizar no chat",
"titleWithPolls": "Escriba un alcume para utilizar no chat"
},
"privateNotice": "Mensaxe privada para {{recipient}}",
"title": "Chat",
"titleWithPolls": "Chat",
"you": "vostede"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "אין עדיין הודעות בפגישה. התחל שיחה כאן!",
"nickname": {
"popover": "בחר שם משתמש",
"title": "נא להזין שם משתמש בכדי להשתמש בצ'אט"
"title": "נא להזין שם משתמש בכדי להשתמש בצ'אט",
"titleWithPolls": "נא להזין שם משתמש בכדי להשתמש בצ'אט"
},
"privateNotice": "הודעה פרטית אל {{recipient}}",
"title": "צ'אט",
"titleWithPolls": "צ'אט",
"you": "אתה"
},
"chromeExtensionBanner": {

View File

@@ -70,10 +70,12 @@
"noMessagesMessage": "अभी तक मीटिंग में कोई संदेश नहीं आया है। वार्तालाप प्रारंभ करें!",
"nickname": {
"popover": "एक उपनाम चुनें",
"title": "चैट का उपयोग करने के लिए एक उपनाम दर्ज करें"
"title": "चैट का उपयोग करने के लिए एक उपनाम दर्ज करें",
"titleWithPolls": "चैट का उपयोग करने के लिए एक उपनाम दर्ज करें"
},
"privateNotice": "{{recipient}} के लिए निजी संदेश",
"title": "चैट",
"titleWithPolls": "चैट",
"you": "आप"
},
"chromeExtensionBanner": {

View File

@@ -49,9 +49,11 @@
"messagebox": "",
"nickname": {
"popover": "Odaberite nadimak",
"title": "Unesite nadimak za čavrljanje"
"title": "Unesite nadimak za čavrljanje",
"titleWithPolls": "Unesite nadimak za čavrljanje"
},
"title": "Čavrljanje"
"title": "Čavrljanje",
"titleWithPolls": "Čavrljanje"
},
"connectingOverlay": {
"joiningRoom": ""

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "A találkozón még nincsenek üzenetek. Itt kezdhet beszélgetést!",
"nickname": {
"popover": "Becenév kiválasztása",
"title": "Adjon meg egy becenevet a csevegés számára"
"title": "Adjon meg egy becenevet a csevegés számára",
"titleWithPolls": "Adjon meg egy becenevet a csevegés számára"
},
"privateNotice": "Privát üzenet a felhasználónak: {{recipient}}",
"title": "Csevegés",
"titleWithPolls": "Csevegés",
"you": "neked"
},
"connectingOverlay": {

View File

@@ -49,9 +49,11 @@
"messagebox": "",
"nickname": {
"popover": "Ընտրեք մականուն",
"title": ""
"title": "",
"titleWithPolls": ""
},
"title": ""
"title": "",
"titleWithPolls": ""
},
"connectingOverlay": {
"joiningRoom": ""

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "There are no messages in the meeting yet. Start a conversation here!",
"nickname": {
"popover": "Choose a nickname",
"title": "Enter a nickname to use chat"
"title": "Enter a nickname to use chat",
"titleWithPolls": "Enter a nickname to use chat"
},
"privateNotice": "Private message to {{recipient}}",
"title": "Chat",
"titleWithPolls": "Chat",
"you": "you"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Það eru ennþá engin skilaboð á fundinum. Byrjaðu umræðuna hér!",
"nickname": {
"popover": "Veldu gælunafn",
"title": "Settu inn gælunafn/stuttnefni til að nota við spjall"
"title": "Settu inn gælunafn/stuttnefni til að nota við spjall",
"titleWithPolls": "Settu inn gælunafn/stuttnefni til að nota við spjall"
},
"privateNotice": "Einkaskilaboð til {{recipient}}",
"title": "Spjall",
"titleWithPolls": "Spjall",
"you": "þú"
},
"chromeExtensionBanner": {

View File

@@ -70,10 +70,12 @@
"noMessagesMessage": "Non ci sono ancora messaggi nella riunione. Comincia una conversazione, qui!",
"nickname": {
"popover": "Scegli un nickname",
"title": "Inserire un nickname per utilizzare la conversazione"
"title": "Inserire un nickname per utilizzare la conversazione",
"titleWithPolls": "Inserire un nickname per utilizzare la conversazione"
},
"privateNotice": "Messaggio privato per {{recipient}}",
"title": "Conversazione",
"titleWithPolls": "Conversazione",
"you": "tu"
},
"chromeExtensionBanner": {

View File

@@ -72,10 +72,12 @@
"noMessagesMessage": "このミーティングにはまだメッセージがありません。会話を開始してください!",
"nickname": {
"popover": "ニックネームを入力",
"title": "チャットで使用するニックネームを入力してください"
"title": "チャットで使用するニックネームを入力してください",
"titleWithPolls": "チャットで使用するニックネームを入力してください"
},
"privateNotice": "{{recipient}} へのプライベートメッセージ",
"title": "チャット",
"titleWithPolls": "チャット",
"you": "あなた"
},
"chromeExtensionBanner": {

View File

@@ -63,9 +63,11 @@
"messagebox": "Aru izen",
"nickname": {
"popover": "Fren meffer isem",
"title": "Sekcem meffer isem i useqdec n usqerdec"
"title": "Sekcem meffer isem i useqdec n usqerdec",
"titleWithPolls": "Sekcem meffer isem i useqdec n usqerdec"
},
"title": "Asqerdec",
"titleWithPolls": "Asqerdec",
"noMessagesMessage": "Ulac iznan akka tura deg temlilit. Bdu adiwenni da!",
"you": "kečč·kemm",
"fieldPlaceHolder": "Aru izen-inek·inem da"

View File

@@ -69,10 +69,12 @@
"noMessagesMessage": "아직 회의에 메시지가 없습니다. 여기서 대화를 시작하세요!",
"nickname": {
"popover": "닉네임을 선택하세요",
"title": "채팅에서 사용할 닉네임을 입력하세요"
"title": "채팅에서 사용할 닉네임을 입력하세요",
"titleWithPolls": "채팅에서 사용할 닉네임을 입력하세요"
},
"privateNotice": "{{recipient}}에게 보내는 비공개 메시지",
"title": "채팅",
"titleWithPolls": "채팅",
"you": "당신"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Susitikime dar nėra pranešimų. Pradėkite pokalbį čia!",
"nickname": {
"popover": "Pridėkite slapyvardį",
"title": "Norėdami naudoti pokalbį, įveskite slapyvardį"
"title": "Norėdami naudoti pokalbį, įveskite slapyvardį",
"titleWithPolls": "Norėdami naudoti pokalbį, įveskite slapyvardį"
},
"privateNotice": "Asmeninis pranešimas {{gavėjui}}",
"title": "Pokalbis",
"titleWithPolls": "Pokalbis",
"you": "Jūs"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Sapulcē pagaidām nav nevienas ziņas. Uzsāciet saraksti!",
"nickname": {
"popover": "Izvēlieties vārdu",
"title": "Ierakstiet vārdu izmantošanai tērziņā"
"title": "Ierakstiet vārdu izmantošanai tērziņā",
"titleWithPolls": "Ierakstiet vārdu izmantošanai tērziņā"
},
"privateNotice": "Privāta ziņa/paziņojums lietotājam {{recipient}}",
"title": "Tērzēšana",
"titleWithPolls": "Tērzēšana",
"you": "mans vārds"
},
"chromeExtensionBanner": {

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "മീറ്റിംഗിൽ ഇതുവരെ മെസ്സേജുകളൊന്നുമില്ല. ഇവിടെ ഒരു സംഭാഷണം ആരംഭിക്കുക!",
"nickname": {
"popover": "ഒരു വിളിപ്പേര് തിരഞ്ഞെടുക്കുക",
"title": "ചാറ്റ് ഉപയോഗിക്കുന്നതിന് ഒരു വിളിപ്പേര് നൽകുക"
"title": "ചാറ്റ് ഉപയോഗിക്കുന്നതിന് ഒരു വിളിപ്പേര് നൽകുക",
"titleWithPolls": "ചാറ്റ് ഉപയോഗിക്കുന്നതിന് ഒരു വിളിപ്പേര് നൽകുക"
},
"privateNotice": " {{recipient}}-ലേക്കുള്ള സ്വകാര്യ സന്ദേശം",
"title": "ചാറ്റ്",
"titleWithPolls": "ചാറ്റ്",
"you": "നിങ്ങൾ"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Энэ хуралд ямар ч зурвас байхгүй. Эндээс зурвасаа эхлүүл!",
"nickname": {
"popover": "Нэр бичнэ үү",
"title": "Нэрээ оруулна уу"
"title": "Нэрээ оруулна уу",
"titleWithPolls": "Нэрээ оруулна уу"
},
"privateNotice": "Хувийн зурвас {{recipient}}",
"title": "Чат",
"titleWithPolls": "Чат",
"you": "чи"
},
"chromeExtensionBanner": {

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "अद्याप मीटिंगमध्ये कोणतेही संदेश नाहीत. येथे संभाषण सुरू करा!",
"nickname": {
"popover": "टोपणनाव निवडा",
"title": "चॅट वापरण्यासाठी टोपणनाव प्रविष्ट करा"
"title": "चॅट वापरण्यासाठी टोपणनाव प्रविष्ट करा",
"titleWithPolls": "चॅट वापरण्यासाठी टोपणनाव प्रविष्ट करा"
},
"privateNotice": "यांना खाजगी संदेश{{recipient}}",
"title": "गप्पा",
"titleWithPolls": "गप्पा",
"you": "आपण"
},
"chromeExtensionBanner": {

View File

@@ -46,9 +46,11 @@
"messagebox": "Skriv en melding",
"nickname": {
"popover": "Velg et kallenavn",
"title": ""
"title": "",
"titleWithPolls": ""
},
"title": "",
"titleWithPolls": "",
"messageTo": "Privat melding til {{recipient}}",
"fieldPlaceHolder": "Skriv inn din melding her"
},

View File

@@ -69,10 +69,12 @@
"noMessagesMessage": "Er zijn nog geen berichten in de vergadering. Begin hier een gesprek!",
"nickname": {
"popover": "Kies een bijnaam",
"title": "Voer een bijnaam in om chat te gebruiken"
"title": "Voer een bijnaam in om chat te gebruiken",
"titleWithPolls": "Voer een bijnaam in om chat te gebruiken"
},
"privateNotice": "Privébericht aan {{recipient}}",
"title": "Chat",
"titleWithPolls": "Chat",
"you": "u"
},
"chromeExtensionBanner": {

View File

@@ -71,12 +71,14 @@
"messageTo": "Messatge privat per {{recipient}}",
"nickname": {
"popover": "Causissètz un escais",
"title": "Picatz un escais-nom per utilizar la messatjariá"
"title": "Picatz un escais-nom per utilizar la messatjariá",
"titleWithPolls": "Picatz un escais-nom per utilizar la messatjariá"
},
"noMessagesMessage": "I a pas cap de messatge dins la conferéncia pel moment. Començat una conversacion aquí!",
"privateNotice": "Messatge privat per {{recipient}}",
"smileysPanel": "Panèl dEmoji",
"title": "Messatjariá",
"titleWithPolls": "Messatjariá",
"you": "vos"
},
"chromeExtensionBanner": {

View File

@@ -66,7 +66,8 @@
"noMessagesMessage": "Aktualnie brak wiadomości w tym spotkaniu. Rozpocznij konwersację!",
"nickname": {
"popover": "Wybierz swój nick",
"title": "Wpisz swoją nazwę, aby użyć rozmowy"
"title": "Wpisz swoją nazwę, aby użyć rozmowy",
"titleWithPolls": "Wpisz swoją nazwę, aby użyć rozmowy"
},
"privateNotice": "Prywatna wiadomość do {{recipient}}",
"message": "Wiadomość",
@@ -78,6 +79,7 @@
"polls": "Ankiety"
},
"title": "Rozmowa",
"titleWithPolls": "Rozmowa",
"you": "Ty"
},
"chromeExtensionBanner": {

View File

@@ -66,7 +66,8 @@
"noMessagesMessage": "Ainda não há mensagens na reunião. Comece aqui uma conversa!",
"nickname": {
"popover": "Escolha um apelido",
"title": "Introduza um apelido para usar no chat e nas sondagens"
"title": "Introduza um apelido para usar no chat e nas sondagens",
"titleWithPolls": "Introduza um apelido para usar no chat e nas sondagens"
},
"privateNotice": "Mensagem privada para {{recipient}}",
"message": "Mensagem",
@@ -78,6 +79,7 @@
"polls": "Sondagens"
},
"title": "Chat e Sondagens",
"titleWithPolls": "Chat e Sondagens",
"you": "você"
},
"chromeExtensionBanner": {

View File

@@ -66,10 +66,12 @@
"noMessagesMessage": "Não há mensagens na reunião ainda. Inicie uma conversa aqui!",
"nickname": {
"popover": "Escolha um apelido",
"title": "Digite um apelido para usar o bate-papo"
"title": "Digite um apelido para usar o bate-papo",
"titleWithPolls": "Digite um apelido para usar o bate-papo"
},
"privateNotice": "Mensagem privada para {{recipient}}",
"title": "Bate-papo",
"titleWithPolls": "Bate-papo",
"you": "você",
"message": "Mensagem",
"messageAccessibleTitle": "{{user}} disse:",

View File

@@ -50,9 +50,11 @@
"messagebox": "Scrieți mesajul",
"nickname": {
"popover": "Alegeți un pseudonim",
"title": "Introduceți un pseudonim pentru a conversa"
"title": "Introduceți un pseudonim pentru a conversa",
"titleWithPolls": "Introduceți un pseudonim pentru a conversa"
},
"title": "Apel video",
"titleWithPolls": "Apel video",
"you": "",
"privateNotice": "",
"noMessagesMessage": "",

View File

@@ -67,11 +67,13 @@
"messagebox": "Введите сообщение",
"nickname": {
"popover": "Выберите имя",
"title": "Введите имя для использования чата"
"title": "Введите имя для использования чата",
"titleWithPolls": "Введите имя для использования чата"
},
"noMessagesMessage": "В конференции пока нет никаких сообщений. Начните разговор!",
"privateNotice": "Личное сообщение пользователю {{recipient}}",
"title": "Чат",
"titleWithPolls": "Чат",
"you": "вы"
},
"chromeExtensionBanner": {
@@ -452,6 +454,7 @@
"youtubeTerms": "Условия использования YouTube"
},
"lobby": {
"allow": "Разрешить",
"disableDialogContent": "В настоящее время включен режим лобби. Эта функция гарантирует, что нежелательные участники не смогут присоединиться к вашей встрече. Вы хотите его отключить?",
"disableDialogSubmit": "Отключить",
"emailField": "Введите ваш адрес электронной почты",
@@ -748,6 +751,7 @@
"moreOptions": "Меню доп. настроек",
"mute": "Вкл/Выкл звук",
"muteEveryone": "Выкл. микрофон у всех",
"participants": "Участники",
"pip": "Вкл/Выкл режим Картинка-в-картинке",
"privateMessage": "Отправить личное сообщение",
"profile": "Редактировать профиль",
@@ -805,6 +809,7 @@
"noisyAudioInputDesc": "Возможно, ваш микрофон создает шум. Вы можете выключить его или смените устройство.",
"noisyAudioInputTitle": "Похоже, ваш микрофон создает шум!",
"openChat": "Открыть чат",
"participants": "Участники",
"pip": "Вкл режим Картинка-в-картинке",
"privateMessage": "Отправить личное сообщение",
"profile": "Редактировать профиль",

View File

@@ -53,10 +53,12 @@
"noMessagesMessage": "Perunu messàgiu ancora in sa riunione. Cumintza una tzarrada inoghe!",
"nickname": {
"popover": "Sèbera unu nòmine",
"title": "Inserta su nòmine pro impreare sa tzarrada"
"title": "Inserta su nòmine pro impreare sa tzarrada",
"titleWithPolls": "Inserta su nòmine pro impreare sa tzarrada"
},
"privateNotice": "Messàgiu privadu a {{recipient}}",
"title": "Tzarrada",
"titleWithPolls": "Tzarrada",
"you": "tue"
},
"chromeExtensionBanner": {

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "V tejto konferencii ešte nie je žiadna správa. Začnite tu vašu diskusiu!",
"nickname": {
"popover": "Zvoľte meno",
"title": "Zadajte vašu prezývku"
"title": "Zadajte vašu prezývku",
"titleWithPolls": "Zadajte vašu prezývku"
},
"privateNotice": "Súkromná správa pre {{recipient}}",
"title": "Chat",
"titleWithPolls": "Chat",
"you": "Vy"
},
"chromeExtensionBanner": {

View File

@@ -52,11 +52,13 @@
"messagebox": "Vnesite sporočilo",
"nickname": {
"popover": "Izberite svoje ime",
"title": "Vnesite ime, ki ga želite uporabljati na srečanju"
"title": "Vnesite ime, ki ga želite uporabljati na srečanju",
"titleWithPolls": "Vnesite ime, ki ga želite uporabljati na srečanju"
},
"noMessagesMessage": "There are no messages in the meeting yet. Start a conversation here!",
"privateNotice": "Zasebno sporočilo za uporabnika {{recipient}}",
"title": "Klepet",
"titleWithPolls": "Klepet",
"you": "vi"
},
"chromeExtensionBanner": {

View File

@@ -66,10 +66,12 @@
"noMessagesMessage": "Ende ska mesazhe te takimi. Filloni një bisedë këtu!",
"nickname": {
"popover": "Zgjidhni një nofkë",
"title": "Që të përdorni fjalosjen, jepni një nofkë"
"title": "Që të përdorni fjalosjen, jepni një nofkë",
"titleWithPolls": "Që të përdorni fjalosjen, jepni një nofkë"
},
"privateNotice": "Mesazh privat për {{recipient}}",
"title": "Fjalosje",
"titleWithPolls": "Fjalosje",
"you": "ju",
"message": "Mesazh",
"messageAccessibleTitle": "{{user}} thotë:",

View File

@@ -70,9 +70,11 @@
"messagebox": "Skriv ett meddelande",
"nickname": {
"popover": "Välj ett namn",
"title": "Skriv in ett namn för att börja använda chatten"
"title": "Skriv in ett namn för att börja använda chatten",
"titleWithPolls": "Skriv in ett namn för att börja använda chatten"
},
"title": "Chatt",
"titleWithPolls": "Chatt",
"you": "du",
"privateNotice": "Privat meddelande till {{recipient}}",
"noMessagesMessage": "Det finns ännu inga meddelanden i mötet. Påbörja en konversation!",

View File

@@ -70,10 +70,12 @@
"noMessagesMessage": "ఈ సమావేశంలో ఇంకా సందేశాలేమీ లేవు. ఇక్కడ ఒక సంభాషణను మొదలుపెట్టండి!",
"nickname": {
"popover": "ఒక మారుపేరు ఎంచుకోండి",
"title": "సంభాషణను మొదలుపెట్టడానికి ఒక మారుపేరును ఇవ్వండి"
"title": "సంభాషణను మొదలుపెట్టడానికి ఒక మారుపేరును ఇవ్వండి",
"titleWithPolls": "సంభాషణను మొదలుపెట్టడానికి ఒక మారుపేరును ఇవ్వండి"
},
"privateNotice": "{{recipient}}‌కి అంతరంగిక సందేశం",
"title": "సంభాషణ",
"titleWithPolls": "సంభాషణ",
"you": "మీరు"
},
"chromeExtensionBanner": {

View File

@@ -67,12 +67,13 @@
"noMessagesMessage": "Toplantıda henüz mesaj yok. Burada bir konuşma başlatın!",
"nickname": {
"popover": "Bir takma ad seçin",
"title": "Sohbette kullanmak için bir takma ad girin"
"title": "Sohbette kullanmak için bir takma ad girin",
"titleWithPolls": "Sohbette kullanmak için bir takma ad girin"
},
"privateNotice": "{{recipient}} için özel mesaj",
"privateNotice": "{{recipient}} için özel mesaj",
"title": "Sohbet",
"titleWithPolls": "Sohbet",
"you": "sen"
},
"connectingOverlay": {
"joiningRoom": "Toplantıya bağlanılıyor..."

View File

@@ -67,10 +67,12 @@
"noMessagesMessage": "У цій конференції відсутні повідомлення. Будь ласка, почніть розмову тут.",
"nickname": {
"popover": "Зазначте ім'я",
"title": "Зазначте ваше ім'я для чату"
"title": "Зазначте ваше ім'я для чату",
"titleWithPolls": "Зазначте ваше ім'я для чату"
},
"privateNotice": "Приватне повідомлення для {{recipient}}",
"title": "Чат",
"titleWithPolls": "Чат",
"you": "Ви"
},
"chromeExtensionBanner": {

View File

@@ -53,9 +53,11 @@
"messagebox": "Nhập nội dung tin nhắn",
"nickname": {
"popover": "Chọn tên",
"title": "Nhập tên của bạn để tán gẫu"
"title": "Nhập tên của bạn để tán gẫu",
"titleWithPolls": "Nhập tên của bạn để tán gẫu"
},
"title": "Tán gẫu",
"titleWithPolls": "Tán gẫu",
"you": "bạn"
},
"connectingOverlay": {

View File

@@ -68,10 +68,12 @@
"noMessagesMessage": "会议中还没有消息,在这里开始谈话吧!",
"nickname": {
"popover": "选择一个昵称",
"title": "输入一个昵称用于聊天"
"title": "输入一个昵称用于聊天",
"titleWithPolls": "输入一个昵称用于聊天"
},
"privateNotice": "与 {{recipient}} 的私人聊天",
"title": "话题",
"titleWithPolls": "话题",
"you": "您"
},
"chromeExtensionBanner": {

View File

@@ -66,10 +66,12 @@
"noMessagesMessage": "此會議尚無訊息。在此開始對話交談!",
"nickname": {
"popover": "選擇名稱",
"title": "輸入名稱來使用交談"
"title": "輸入名稱來使用交談",
"titleWithPolls": "輸入名稱來使用交談"
},
"privateNotice": "私人訊息傳送至 {{recipient}}",
"title": "對話",
"titleWithPolls": "對話",
"you": "您",
"message": "訊息",
"messageAccessibleTitle": "{{user}} 說:",

View File

@@ -66,7 +66,8 @@
"noMessagesMessage": "There are no messages in the meeting yet. Start a conversation here!",
"nickname": {
"popover": "Choose a nickname",
"title": "Enter a nickname to use chat and polls"
"title": "Enter a nickname to use chat",
"titleWithPolls": "Enter a nickname to use chat and polls"
},
"privateNotice": "Private message to {{recipient}}",
"message": "Message",
@@ -77,7 +78,8 @@
"chat": "Chat",
"polls": "Polls"
},
"title": "Chat and Polls",
"title": "Chat",
"titleWithPolls": "Chat and Polls",
"you": "you"
},
"chromeExtensionBanner": {
@@ -211,7 +213,9 @@
"done": "Done",
"e2eeDescription": "End-to-End Encryption is currently EXPERIMENTAL. Please keep in mind that turning on end-to-end encryption will effectively disable server-side provided services such as: phone participation. Also keep in mind that the meeting will only work for people joining from browsers with support for insertable streams.",
"e2eeLabel": "Enable End-to-End Encryption",
"e2eeDisabledDueToMaxModeDescription": "Cannot enable End-to-End Encryption due to large number of participants in the conference.",
"e2eeWarning": "WARNING: Not all participants in this meeting seem to have support for End-to-End encryption. If you enable it they won't be able to see nor hear you.",
"e2eeWillDisableDueToMaxModeDescription": "WARNING: End-to-End Encryption will be automatically disabled if more participants join the conference.",
"enterDisplayName": "Enter your name here",
"embedMeeting": "Embed meeting",
"error": "Error",
@@ -331,6 +335,7 @@
"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.",
"sharedVideoLinkPlaceholder": "YouTube link or direct video link",
"stopLiveStreaming": "Stop live stream",
"stopRecording": "Stop recording",
"stopRecordingWarning": "Are you sure you would like to stop the recording?",
@@ -563,9 +568,9 @@
"moderator": "You're now a moderator",
"muted": "You have started the conversation muted.",
"mutedTitle": "You're muted!",
"mutedRemotelyTitle": "You've been muted by the moderator",
"mutedRemotelyTitle": "You've been muted by {{moderator}}",
"mutedRemotelyDescription": "You can always unmute when you're ready to speak. Mute back when you're done to keep noise away from the meeting.",
"videoMutedRemotelyTitle": "Your camera has been turned off by the moderator",
"videoMutedRemotelyTitle": "Your video has been turned off by {{moderator}}",
"videoMutedRemotelyDescription": "You can always turn it on again.",
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) removed by another participant",
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) set by another participant",
@@ -610,6 +615,7 @@
},
"actions": {
"allow": "Allow attendees to:",
"allowVideo": "Allow video",
"audioModeration": "Unmute themselves",
"blockEveryoneMicCamera": "Block everyone's mic and camera",
"invite": "Invite Someone",
@@ -620,7 +626,7 @@
"stopEveryonesVideo": "Stop everyone's video",
"stopVideo": "Stop video",
"unblockEveryoneMicCamera": "Unblock everyone's mic and camera",
"videoModeration": "Start video"
"videoModeration": "Start their video"
}
},
"passwordSetRemotely": "Set by another participant",
@@ -693,6 +699,7 @@
"errorDialOutFailed": "Could not dial out. Call failed",
"errorDialOutStatus": "Error getting dial out status",
"errorMissingName": "Please enter your name to join the meeting",
"errorNoPermissions": "You need to enable microphone and camera access",
"errorStatusCode": "Error dialing out, status code: {{status}}",
"errorValidation": "Number validation failed",
"iWantToDialIn": "I want to dial in",

View File

@@ -15,6 +15,7 @@ import {
} from '../../react/features/base/conference';
import { overwriteConfig, getWhitelistedJSON } from '../../react/features/base/config';
import { toggleDialog } from '../../react/features/base/dialog/actions';
import { isSupportedBrowser } from '../../react/features/base/environment';
import { parseJWTFromURLParams } from '../../react/features/base/jwt';
import JitsiMeetJS, { JitsiRecordingConstants } from '../../react/features/base/lib-jitsi-meet';
import { MEDIA_TYPE } from '../../react/features/base/media';
@@ -692,6 +693,7 @@ class API {
this._enabled = true;
initCommands();
this.notifyBrowserSupport(isSupportedBrowser());
}
/**
@@ -1342,6 +1344,32 @@ class API {
});
}
/**
* Notify external application ( if API is enabled) that a toolbar button was clicked.
*
* @param {string} key - The key of the toolbar button.
* @returns {void}
*/
notifyToolbarButtonClicked(key: string) {
this._sendEvent({
name: 'toolbar-button-clicked',
key
});
}
/**
* Notify external application (if API is enabled) wether the used browser is supported or not.
*
* @param {boolean} supported - If browser is supported or not.
* @returns {void}
*/
notifyBrowserSupport(supported: boolean) {
this._sendEvent({
name: 'browser-support',
supported
});
}
/**
* Disposes the allocated resources.
*

View File

@@ -76,6 +76,7 @@ const events = {
'avatar-changed': 'avatarChanged',
'audio-availability-changed': 'audioAvailabilityChanged',
'audio-mute-status-changed': 'audioMuteStatusChanged',
'browser-support': 'browserSupport',
'camera-error': 'cameraError',
'chat-updated': 'chatUpdated',
'content-sharing-participants-changed': 'contentSharingParticipantsChanged',
@@ -112,7 +113,8 @@ const events = {
'dominant-speaker-changed': 'dominantSpeakerChanged',
'subject-change': 'subjectChange',
'suspend-detected': 'suspendDetected',
'tile-view-changed': 'tileViewChanged'
'tile-view-changed': 'tileViewChanged',
'toolbar-button-clicked': 'toolbarButtonClicked'
};
/**

15
package-lock.json generated
View File

@@ -2752,8 +2752,8 @@
}
},
"@jitsi/sdp-interop": {
"version": "github:jitsi/sdp-interop#98cd62cc00f92c8c2430e52ca746a86813658e83",
"from": "github:jitsi/sdp-interop#98cd62cc00f92c8c2430e52ca746a86813658e83",
"version": "github:jitsi/sdp-interop#4669790bb9020cc8f10c1d1f3823c26b08497547",
"from": "github:jitsi/sdp-interop#4669790bb9020cc8f10c1d1f3823c26b08497547",
"requires": {
"lodash.clonedeep": "4.5.0",
"sdp-transform": "2.14.1"
@@ -11117,11 +11117,11 @@
}
},
"lib-jitsi-meet": {
"version": "github:jitsi/lib-jitsi-meet#ad1f06d76833e5d7233c86bab36e76bcd5ce44e0",
"from": "github:jitsi/lib-jitsi-meet#ad1f06d76833e5d7233c86bab36e76bcd5ce44e0",
"version": "github:jitsi/lib-jitsi-meet#1bef6319fbdfdfb03b51d3f7efa348a111ac5805",
"from": "github:jitsi/lib-jitsi-meet#1bef6319fbdfdfb03b51d3f7efa348a111ac5805",
"requires": {
"@jitsi/js-utils": "1.0.2",
"@jitsi/sdp-interop": "github:jitsi/sdp-interop#98cd62cc00f92c8c2430e52ca746a86813658e83",
"@jitsi/sdp-interop": "github:jitsi/sdp-interop#4669790bb9020cc8f10c1d1f3823c26b08497547",
"@jitsi/sdp-simulcast": "0.4.0",
"async": "0.9.0",
"base64-js": "1.3.1",
@@ -15201,9 +15201,8 @@
"integrity": "sha512-iqdJ1KpZbR4XGahgVmaeibB7kDhyMT7wrylINgJaYBY38IAiI0LF32VX1umO4pko6n21YF5I/kSeNQ+OXGqqow=="
},
"react-native-webrtc": {
"version": "1.92.1",
"resolved": "https://registry.npmjs.org/react-native-webrtc/-/react-native-webrtc-1.92.1.tgz",
"integrity": "sha512-cbFU1acL9aud/ohk/40jwahSNac4PwBKdmRPgXb9WqaGwxAr4CgSsrBRmruCISMdw0Pec+ZoZtYjXVuHzF51sg==",
"version": "github:react-native-webrtc/react-native-webrtc#aeb735154c9393bbfde40bf02b797e6eeb91f63a",
"from": "github:react-native-webrtc/react-native-webrtc#aeb735154c9393bbfde40bf02b797e6eeb91f63a",
"requires": {
"base64-js": "^1.1.2",
"cross-os": "^1.3.0",

View File

@@ -59,7 +59,7 @@
"jquery-i18next": "1.2.1",
"js-md5": "0.6.1",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#ad1f06d76833e5d7233c86bab36e76bcd5ce44e0",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#1bef6319fbdfdfb03b51d3f7efa348a111ac5805",
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"lodash": "4.17.21",
"moment": "2.29.1",
@@ -92,7 +92,7 @@
"react-native-url-polyfill": "1.2.0",
"react-native-video": "5.1.1",
"react-native-watch-connectivity": "0.4.3",
"react-native-webrtc": "1.92.1",
"react-native-webrtc": "github:react-native-webrtc/react-native-webrtc#aeb735154c9393bbfde40bf02b797e6eeb91f63a",
"react-native-webview": "11.0.2",
"react-native-youtube-iframe": "2.1.1",
"react-redux": "7.1.0",

View File

@@ -1,3 +1,22 @@
diff --git a/node_modules/react-native/Libraries/WebSocket/RCTWebSocketModule.m b/node_modules/react-native/Libraries/WebSocket/RCTWebSocketModule.m
index d9387c4..a487da0 100644
--- a/node_modules/react-native/Libraries/WebSocket/RCTWebSocketModule.m
+++ b/node_modules/react-native/Libraries/WebSocket/RCTWebSocketModule.m
@@ -165,10 +165,10 @@ - (void)webSocket:(RCTSRWebSocket *)webSocket didFailWithError:(NSError *)error
NSNumber *socketID = [webSocket reactTag];
_contentHandlers[socketID] = nil;
_sockets[socketID] = nil;
- [self sendEventWithName:@"websocketFailed" body:@{
- @"message": error.localizedDescription,
- @"id": socketID
- }];
+ NSDictionary *body =
+ @{@"message" : error.localizedDescription ?: @"Undefined, error is nil",
+ @"id" : socketID ?: @(-1)};
+ [self sendEventWithName:@"websocketFailed" body:body];
}
- (void)webSocket:(RCTSRWebSocket *)webSocket
diff --git a/node_modules/react-native/React/CxxBridge/RCTCxxBridge.mm b/node_modules/react-native/React/CxxBridge/RCTCxxBridge.mm
index bd48f44..d243ed0 100644
--- a/node_modules/react-native/React/CxxBridge/RCTCxxBridge.mm

View File

@@ -181,7 +181,7 @@ export function initAnalytics({ getState }: { getState: Function }, handlers: Ar
permanentProperties.appName = getAppName();
// Report if user is using websocket
permanentProperties.websocket = navigator.product !== 'ReactNative' && typeof config.websocket === 'string';
permanentProperties.websocket = typeof config.websocket === 'string';
// Report if user is using the external API
permanentProperties.externalApi = typeof API_ID === 'number';

View File

@@ -1,6 +1,7 @@
// @flow
import '../analytics/middleware';
import '../av-moderation/middleware';
import '../base/conference/middleware';
import '../base/config/middleware';
import '../base/jwt/middleware';

View File

@@ -1,7 +1,6 @@
// @flow
import '../authentication/middleware';
import '../av-moderation/middleware';
import '../base/devices/middleware';
import '../e2ee/middleware';
import '../external-api/middleware';

View File

@@ -2,6 +2,7 @@
import '../analytics/reducer';
import '../authentication/reducer';
import '../av-moderation/reducer';
import '../base/app/reducer';
import '../base/audio-only/reducer';
import '../base/color-scheme/reducer';

View File

@@ -1,6 +1,5 @@
// @flow
import '../av-moderation/reducer';
import '../base/devices/reducer';
import '../e2ee/reducer';
import '../feedback/reducer';

View File

@@ -2,6 +2,8 @@
import { getConferenceState } from '../base/conference';
import { MEDIA_TYPE, type MediaType } from '../base/media/constants';
import { getParticipantById } from '../base/participants';
import { isForceMuted } from '../participants-pane/functions';
import {
DISMISS_PENDING_PARTICIPANT,
@@ -27,11 +29,15 @@ import { isEnabledFromState } from './functions';
export const approveParticipant = (id: string) => (dispatch: Function, getState: Function) => {
const state = getState();
const { conference } = getConferenceState(state);
const participant = getParticipantById(state, id);
if (isEnabledFromState(MEDIA_TYPE.AUDIO, state)) {
const isAudioForceMuted = isForceMuted(participant, MEDIA_TYPE.AUDIO, state);
const isVideoForceMuted = isForceMuted(participant, MEDIA_TYPE.VIDEO, state);
if (isEnabledFromState(MEDIA_TYPE.AUDIO, state) && isAudioForceMuted) {
conference.avModerationApprove(MEDIA_TYPE.AUDIO, id);
}
if (isEnabledFromState(MEDIA_TYPE.VIDEO, state)) {
if (isEnabledFromState(MEDIA_TYPE.VIDEO, state) && isVideoForceMuted) {
conference.avModerationApprove(MEDIA_TYPE.VIDEO, id);
}
};

View File

@@ -17,3 +17,15 @@ export const MEDIA_TYPE_TO_PENDING_STORE_KEY: {[key: MediaType]: string} = {
[MEDIA_TYPE.AUDIO]: 'pendingAudio',
[MEDIA_TYPE.VIDEO]: 'pendingVideo'
};
export const ASKED_TO_UNMUTE_SOUND_ID = 'ASKED_TO_UNMUTE_SOUND';
export const AUDIO_MODERATION_NOTIFICATION_ID = 'audio-moderation';
export const VIDEO_MODERATION_NOTIFICATION_ID = 'video-moderation';
export const CS_MODERATION_NOTIFICATION_ID = 'screensharing-moderation';
export const MODERATION_NOTIFICATIONS = {
[MEDIA_TYPE.AUDIO]: AUDIO_MODERATION_NOTIFICATION_ID,
[MEDIA_TYPE.VIDEO]: VIDEO_MODERATION_NOTIFICATION_ID,
[MEDIA_TYPE.PRESENTER]: CS_MODERATION_NOTIFICATION_ID
};

View File

@@ -1,6 +1,7 @@
// @flow
import { batch } from 'react-redux';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
import { getConferenceState } from '../base/conference';
import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
import { MEDIA_TYPE } from '../base/media';
@@ -13,6 +14,7 @@ import {
raiseHand
} from '../base/participants';
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
import { playSound, registerSound, unregisterSound } from '../base/sounds';
import {
hideNotification,
showNotification
@@ -35,21 +37,31 @@ import {
participantApproved,
participantPendingAudio
} from './actions';
import {
ASKED_TO_UNMUTE_SOUND_ID, AUDIO_MODERATION_NOTIFICATION_ID,
CS_MODERATION_NOTIFICATION_ID,
VIDEO_MODERATION_NOTIFICATION_ID
} from './constants';
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';
import { ASKED_TO_UNMUTE_FILE } from './sounds';
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
const { type } = action;
const { conference } = getConferenceState(getState());
switch (type) {
case APP_WILL_MOUNT: {
dispatch(registerSound(ASKED_TO_UNMUTE_SOUND_ID, ASKED_TO_UNMUTE_FILE));
break;
}
case APP_WILL_UNMOUNT: {
dispatch(unregisterSound(ASKED_TO_UNMUTE_SOUND_ID));
break;
}
case LOCAL_PARTICIPANT_MODERATION_NOTIFICATION: {
let descriptionKey;
let titleKey;
@@ -160,6 +172,7 @@ StateListenerRegistry.register(
customActionNameKey: 'notify.unmute',
customActionHandler: () => dispatch(muteLocal(false, MEDIA_TYPE.AUDIO))
}));
dispatch(playSound(ASKED_TO_UNMUTE_SOUND_ID));
}
});

View File

@@ -0,0 +1,6 @@
/**
* The name of the bundled audio file which will be played for the raise hand sound.
*
* @type {string}
*/
export const ASKED_TO_UNMUTE_FILE = 'asked-unmute.mp3';

View File

@@ -135,8 +135,11 @@ function _addConferenceListeners(conference, dispatch, state) {
// Remove the tracks from peerconnection as well.
for (const track of localTracks) {
if ((audioMuted && track.jitsiTrack.getType() === MEDIA_TYPE.AUDIO)
|| (videoMuted && track.jitsiTrack.getType() === MEDIA_TYPE.VIDEO)) {
const trackType = track.jitsiTrack.getType();
// Do not remove the audio track on RN. Starting with iOS 15 it will fail to unmute otherwise.
if ((audioMuted && trackType === MEDIA_TYPE.AUDIO && navigator.product !== 'ReactNative')
|| (videoMuted && trackType === MEDIA_TYPE.VIDEO)) {
dispatch(replaceLocalTrack(track.jitsiTrack, null, conference));
}
}
@@ -357,7 +360,7 @@ export function conferenceUniqueIdSet(conference: Object) {
* the local participant will (try to) join.
* @returns {Function}
*/
function _conferenceWillJoin(conference: Object) {
export function _conferenceWillJoin(conference: Object) {
return (dispatch: Dispatch<any>, getState: Function) => {
const localTracks
= getLocalTracks(getState()['features/base/tracks'])

View File

@@ -19,6 +19,7 @@ export default [
'apiLogLevels',
'avgRtpStatsN',
'backgroundAlpha',
'buttonsWithNotifyClick',
/**
* The display name of the CallKit call representing the conference/meeting
@@ -69,6 +70,7 @@ export default [
*/
'callUUID',
'conferenceInfo',
'channelLastN',
'connectionIndicators',
'constraints',
@@ -94,9 +96,11 @@ export default [
'disableIncomingMessageSound',
'disableJoinLeaveSounds',
'disableLocalVideoFlip',
'disableModeratorIndicator',
'disableNS',
'disablePolls',
'disableProfile',
'disableReactions',
'disableRecordAudioNotification',
'disableRemoteControl',
'disableRemoteMute',
@@ -124,11 +128,11 @@ export default [
'enableLayerSuspension',
'enableLipSync',
'enableOpusRed',
'enableReactions',
'enableRemb',
'enableSaveLogs',
'enableScreenshotCapture',
'enableTalkWhileMuted',
'enableUnifiedOnChrome',
'enableNoAudioDetection',
'enableNoisyMicDetection',
'enableTcc',

Some files were not shown because too many files have changed in this diff Show More