mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-09-09 20:48:41 +00:00
Compare commits
107 Commits
7754
...
jitsi-meet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba95ea3ac8 | ||
|
|
7dcd9c21bc | ||
|
|
990d21038e | ||
|
|
a4d53f271f | ||
|
|
2a1f472873 | ||
|
|
8679119677 | ||
|
|
b02c072ba7 | ||
|
|
e8317fccfe | ||
|
|
bbc9c64978 | ||
|
|
8d2b8bc772 | ||
|
|
52c2911350 | ||
|
|
a1ebcd559b | ||
|
|
5bc47ec16a | ||
|
|
e1ac7d1609 | ||
|
|
8a596f1ba2 | ||
|
|
38e7c65836 | ||
|
|
9602a939d8 | ||
|
|
07b01b1371 | ||
|
|
a1549086aa | ||
|
|
7e0b00ba5f | ||
|
|
3016853d81 | ||
|
|
ead27ace30 | ||
|
|
067bb653e6 | ||
|
|
ba20fc71a8 | ||
|
|
a7b2726ebe | ||
|
|
a98eef7eb3 | ||
|
|
895afbab65 | ||
|
|
1d6529af65 | ||
|
|
4d5fb719d2 | ||
|
|
4061a77af8 | ||
|
|
7f889b2028 | ||
|
|
6f49041d80 | ||
|
|
e73c3b6697 | ||
|
|
5a6b1d0b47 | ||
|
|
da9cded75b | ||
|
|
9b61ad3616 | ||
|
|
583725bf31 | ||
|
|
9e2244210d | ||
|
|
361b82a1ed | ||
|
|
0ed25cda7e | ||
|
|
73ee1205eb | ||
|
|
21f2c60638 | ||
|
|
fd062c40fb | ||
|
|
b87e6abc11 | ||
|
|
9f25726706 | ||
|
|
d5ee7f3069 | ||
|
|
ba1102100a | ||
|
|
e1ce83d0c3 | ||
|
|
78cf510c0b | ||
|
|
3f657c3ded | ||
|
|
2035cd7e62 | ||
|
|
6207e95cad | ||
|
|
40b63a187a | ||
|
|
6c40250e18 | ||
|
|
0268374b88 | ||
|
|
b1b60ec143 | ||
|
|
82c58178b3 | ||
|
|
46d15a9c5c | ||
|
|
248908f476 | ||
|
|
4a5ba0f05d | ||
|
|
b23f3b9e17 | ||
|
|
b6b77f55f1 | ||
|
|
b106c20fa2 | ||
|
|
fab61d8c32 | ||
|
|
9ac614cc4b | ||
|
|
a3bb1a3459 | ||
|
|
34abd279be | ||
|
|
ad6554a789 | ||
|
|
2be8377009 | ||
|
|
0a0b0a760e | ||
|
|
fec6de4536 | ||
|
|
29b2a519b3 | ||
|
|
831d39d447 | ||
|
|
35bc430549 | ||
|
|
77927f3f2e | ||
|
|
7f6d55f5f0 | ||
|
|
32f4767edd | ||
|
|
ba88fc0279 | ||
|
|
ba7ed83d48 | ||
|
|
5a96050973 | ||
|
|
7e8c1fd99a | ||
|
|
6e6433e2d9 | ||
|
|
4ff2422e3c | ||
|
|
cfbcfdc857 | ||
|
|
3074b1741f | ||
|
|
00503d163a | ||
|
|
f847a3e2e0 | ||
|
|
93d0ee710b | ||
|
|
0102efd2d0 | ||
|
|
8afdebca08 | ||
|
|
d2bfb464ba | ||
|
|
5f3233b9a6 | ||
|
|
3c32d9c552 | ||
|
|
f51d8d54e4 | ||
|
|
ac26dce0a5 | ||
|
|
7a23625752 | ||
|
|
4cb4a4db00 | ||
|
|
05e484c4aa | ||
|
|
5871e50a20 | ||
|
|
95ad04b19c | ||
|
|
36fab239cc | ||
|
|
92492dc482 | ||
|
|
51c3658205 | ||
|
|
418d333caf | ||
|
|
7f3f2f7034 | ||
|
|
bd3012f110 | ||
|
|
f8cef330f7 |
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
@@ -73,6 +73,17 @@ jobs:
|
||||
node-version: 16
|
||||
cache: 'npm'
|
||||
- run: npm install
|
||||
- name: setup-cocoapods
|
||||
uses: maxim-lobanov/setup-cocoapods@v1
|
||||
with:
|
||||
podfile-path: ios/Podfile.lock
|
||||
- name: Install Pods
|
||||
run: |
|
||||
pod --version
|
||||
cd ios
|
||||
pod install --repo-update
|
||||
- name: Check if the git repository is clean
|
||||
run: $(exit $(git status --porcelain --untracked-files=no | head -255 | wc -l)) || (echo "Dirty git tree"; git diff; exit 1)
|
||||
- run: npx react-native bundle --entry-file react/index.native.js --platform ios --bundle-output /tmp/ios.bundle --reset-cache
|
||||
debian-build:
|
||||
name: Test Debian packages build
|
||||
|
||||
@@ -15,11 +15,13 @@ def vcode = (int) (((new Date().getTime() / 1000) - 1546297200) / 10)
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
packagingOptions {
|
||||
exclude 'lib/*/libhermes*.so'
|
||||
jniLibs {
|
||||
excludes += ['lib/*/libhermes*.so']
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'org.jitsi.meet'
|
||||
versionCode vcode
|
||||
@@ -72,12 +74,13 @@ android {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
namespace 'org.jitsi.meet'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.5.1'
|
||||
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.13'
|
||||
|
||||
if (!rootProject.ext.libreBuild) {
|
||||
// Sync with react-native-google-signin
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.jitsi.meet"
|
||||
android:installLocation="auto">
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
||||
@@ -10,7 +10,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.3.1'
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
classpath 'com.google.gms:google-services:4.4.0'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.9'
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ android {
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace 'org.jitsi.meet.sdk'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="org.jitsi.meet.sdk">
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- XXX ACCESS_NETWORK_STATE is required by WebRTC. -->
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
@@ -13,6 +12,8 @@
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
|
||||
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00020000"
|
||||
@@ -48,6 +49,10 @@
|
||||
|
||||
<service
|
||||
android:name="org.jitsi.meet.sdk.JitsiMeetOngoingConferenceService"
|
||||
android:foregroundServiceType="mediaPlayback" />
|
||||
|
||||
<service
|
||||
android:name="org.jitsi.meet.sdk.JitsiMeetMediaProjectionService"
|
||||
android:foregroundServiceType="mediaProjection" />
|
||||
|
||||
<provider
|
||||
@@ -66,4 +71,4 @@
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
||||
@@ -87,6 +87,7 @@ class AudioDeviceHandlerGeneric implements
|
||||
devices.add(AudioModeModule.DEVICE_EARPIECE);
|
||||
break;
|
||||
case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER:
|
||||
case AudioDeviceInfo.TYPE_HDMI:
|
||||
devices.add(AudioModeModule.DEVICE_SPEAKER);
|
||||
break;
|
||||
case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
|
||||
|
||||
@ReactModule(name = JitsiMeetMediaProjectionModule.NAME)
|
||||
class JitsiMeetMediaProjectionModule
|
||||
extends ReactContextBaseJavaModule {
|
||||
|
||||
public static final String NAME = "JitsiMeetMediaProjectionModule";
|
||||
|
||||
public JitsiMeetMediaProjectionModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void launch() {
|
||||
Context context = getReactApplicationContext();
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
|
||||
JitsiMeetMediaProjectionService.launch(context, currentActivity);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void abort() {
|
||||
Context context = getReactApplicationContext();
|
||||
|
||||
JitsiMeetMediaProjectionService.abort(context);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Notification;
|
||||
import android.app.Service;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* This class implements an Android {@link Service}, a foreground one specifically, and it's
|
||||
* responsible for presenting an ongoing notification when a conference is in progress.
|
||||
* The service will help keep the app running while in the background.
|
||||
*
|
||||
* See: https://developer.android.com/guide/components/services
|
||||
*/
|
||||
public class JitsiMeetMediaProjectionService extends Service {
|
||||
private static final String TAG = JitsiMeetMediaProjectionService.class.getSimpleName();
|
||||
|
||||
static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
|
||||
|
||||
public static void launch(Context context, Activity currentActivity) {
|
||||
|
||||
NotificationUtils.createNotificationChannel(currentActivity);
|
||||
|
||||
Intent intent = new Intent(context, JitsiMeetMediaProjectionService.class);
|
||||
|
||||
ComponentName componentName;
|
||||
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
componentName = context.startForegroundService(intent);
|
||||
} else {
|
||||
componentName = context.startService(intent);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
// Avoid crashing due to ForegroundServiceStartNotAllowedException (API level 31).
|
||||
// See: https://developer.android.com/guide/components/foreground-services#background-start-restrictions
|
||||
JitsiMeetLogger.w(TAG + "Media projection service not started", e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (componentName == null) {
|
||||
JitsiMeetLogger.w(TAG + "Media projection service not started");
|
||||
}
|
||||
}
|
||||
|
||||
public static void abort(Context context) {
|
||||
Intent intent = new Intent(context, JitsiMeetMediaProjectionService.class);
|
||||
context.stopService(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
|
||||
Notification notification = MediaProjectionNotification.buildMediaProjectionNotification(this);
|
||||
|
||||
if (notification == null) {
|
||||
stopSelf();
|
||||
JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null");
|
||||
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);
|
||||
} else {
|
||||
startForeground(NOTIFICATION_ID, notification);
|
||||
}
|
||||
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
@@ -23,6 +24,7 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
@@ -32,6 +34,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* This class implements an Android {@link Service}, a foreground one specifically, and it's
|
||||
@@ -51,8 +54,12 @@ public class JitsiMeetOngoingConferenceService extends Service
|
||||
|
||||
private boolean isAudioMuted;
|
||||
|
||||
static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
|
||||
|
||||
|
||||
public static void launch(Context context, HashMap<String, Object> extraData) {
|
||||
OngoingNotification.createOngoingConferenceNotificationChannel();
|
||||
|
||||
NotificationUtils.createNotificationChannel((Activity) context);
|
||||
|
||||
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
|
||||
|
||||
@@ -89,13 +96,16 @@ public class JitsiMeetOngoingConferenceService extends Service
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
Notification notification = OngoingNotification.buildOngoingConferenceNotification(isAudioMuted);
|
||||
Notification notification = OngoingNotification.buildOngoingConferenceNotification(isAudioMuted, this);
|
||||
if (notification == null) {
|
||||
stopSelf();
|
||||
JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null");
|
||||
} else {
|
||||
startForeground(OngoingNotification.NOTIFICATION_ID, notification);
|
||||
JitsiMeetLogger.i(TAG + " Service started");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK);
|
||||
} else {
|
||||
startForeground(NOTIFICATION_ID, notification);
|
||||
}
|
||||
}
|
||||
|
||||
OngoingConferenceTracker.getInstance().addListener(this);
|
||||
@@ -126,13 +136,13 @@ public class JitsiMeetOngoingConferenceService extends Service
|
||||
if (isAudioMuted != null) {
|
||||
this.isAudioMuted = Boolean.parseBoolean(intent.getStringExtra("muted"));
|
||||
|
||||
Notification notification = OngoingNotification.buildOngoingConferenceNotification(isAudioMuted);
|
||||
Notification notification = OngoingNotification.buildOngoingConferenceNotification(isAudioMuted, this);
|
||||
if (notification == null) {
|
||||
stopSelf();
|
||||
JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null");
|
||||
} else {
|
||||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify(OngoingNotification.NOTIFICATION_ID, notification);
|
||||
notificationManager.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,13 +222,13 @@ public class JitsiMeetOngoingConferenceService extends Service
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
isAudioMuted = Boolean.parseBoolean(intent.getStringExtra("muted"));
|
||||
Notification notification = OngoingNotification.buildOngoingConferenceNotification(isAudioMuted);
|
||||
Notification notification = OngoingNotification.buildOngoingConferenceNotification(isAudioMuted, context);
|
||||
if (notification == null) {
|
||||
stopSelf();
|
||||
JitsiMeetLogger.w(TAG + " Couldn't update service, notification is null");
|
||||
} else {
|
||||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify(OngoingNotification.NOTIFICATION_ID, notification);
|
||||
notificationManager.notify(NOTIFICATION_ID, notification);
|
||||
|
||||
JitsiMeetLogger.i(TAG + " audio muted changed");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import static org.jitsi.meet.sdk.NotificationUtils.ONGOING_CONFERENCE_CHANNEL_ID;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
/**
|
||||
* Helper class for creating the media projection notification which is used with
|
||||
* {@link JitsiMeetMediaProjectionService}.
|
||||
*/
|
||||
class MediaProjectionNotification {
|
||||
private static final String TAG = MediaProjectionNotification.class.getSimpleName();
|
||||
|
||||
static Notification buildMediaProjectionNotification(Context context) {
|
||||
|
||||
if (context == null) {
|
||||
JitsiMeetLogger.d(TAG, " Cannot create notification: no current context");
|
||||
return null;
|
||||
}
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, ONGOING_CONFERENCE_CHANNEL_ID);
|
||||
|
||||
builder
|
||||
.setCategory(NotificationCompat.CATEGORY_CALL)
|
||||
.setContentTitle(context.getString(R.string.media_projection_notification_title))
|
||||
.setContentText(context.getString(R.string.media_projection_notification_text))
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
.setOngoing(false)
|
||||
.setUsesChronometer(false)
|
||||
.setAutoCancel(true)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setSmallIcon(context.getResources().getIdentifier("ic_notification", "drawable", context.getPackageName()));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class NotificationChannels {
|
||||
static final String ONGOING_CONFERENCE_CHANNEL_ID = "JitsiOngoingConferenceChannel";
|
||||
|
||||
public static List<String> allIds = new ArrayList<String>() {{ add(ONGOING_CONFERENCE_CHANNEL_ID); }};
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class NotificationUtils {
|
||||
|
||||
static final String ONGOING_CONFERENCE_CHANNEL_ID = "JitsiOngoingConferenceChannel";
|
||||
|
||||
public static List<String> allIds = new ArrayList<String>() {{ add(ONGOING_CONFERENCE_CHANNEL_ID); }};
|
||||
|
||||
private static final String TAG = NotificationUtils.class.getSimpleName();
|
||||
|
||||
static void createNotificationChannel(Activity context) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context == null) {
|
||||
JitsiMeetLogger.w(TAG + " Cannot create notification channel: no current context");
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationManager notificationManager
|
||||
= (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
NotificationChannel channel
|
||||
= notificationManager.getNotificationChannel(ONGOING_CONFERENCE_CHANNEL_ID);
|
||||
|
||||
if (channel != null) {
|
||||
// The channel was already created, no need to do it again.
|
||||
return;
|
||||
}
|
||||
|
||||
channel = new NotificationChannel(ONGOING_CONFERENCE_CHANNEL_ID, context.getString(R.string.ongoing_notification_channel_name), NotificationManager.IMPORTANCE_DEFAULT);
|
||||
channel.enableLights(false);
|
||||
channel.enableVibration(false);
|
||||
channel.setShowBadge(false);
|
||||
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
@@ -16,23 +16,18 @@
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import static org.jitsi.meet.sdk.NotificationChannels.ONGOING_CONFERENCE_CHANNEL_ID;
|
||||
import static org.jitsi.meet.sdk.NotificationUtils.ONGOING_CONFERENCE_CHANNEL_ID;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Helper class for creating the ongoing notification which is used with
|
||||
* {@link JitsiMeetOngoingConferenceService}. It allows the user to easily get back to the app
|
||||
@@ -41,40 +36,10 @@ import java.util.Random;
|
||||
class OngoingNotification {
|
||||
private static final String TAG = OngoingNotification.class.getSimpleName();
|
||||
|
||||
static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
|
||||
private static long startingTime = 0;
|
||||
|
||||
static void createOngoingConferenceNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
return;
|
||||
}
|
||||
static Notification buildOngoingConferenceNotification(Boolean isMuted, Context context) {
|
||||
|
||||
Context context = ReactInstanceManagerHolder.getCurrentActivity();
|
||||
if (context == null) {
|
||||
JitsiMeetLogger.w(TAG + " Cannot create notification channel: no current context");
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationManager notificationManager
|
||||
= (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
NotificationChannel channel
|
||||
= notificationManager.getNotificationChannel(ONGOING_CONFERENCE_CHANNEL_ID);
|
||||
if (channel != null) {
|
||||
// The channel was already created, no need to do it again.
|
||||
return;
|
||||
}
|
||||
|
||||
channel = new NotificationChannel(ONGOING_CONFERENCE_CHANNEL_ID, context.getString(R.string.ongoing_notification_action_unmute), NotificationManager.IMPORTANCE_DEFAULT);
|
||||
channel.enableLights(false);
|
||||
channel.enableVibration(false);
|
||||
channel.setShowBadge(false);
|
||||
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
static Notification buildOngoingConferenceNotification(boolean isMuted) {
|
||||
Context context = ReactInstanceManagerHolder.getCurrentActivity();
|
||||
if (context == null) {
|
||||
JitsiMeetLogger.w(TAG + " Cannot create notification: no current context");
|
||||
return null;
|
||||
|
||||
@@ -67,6 +67,7 @@ class ReactInstanceManagerHolder {
|
||||
new DropboxModule(reactContext),
|
||||
new ExternalAPIModule(reactContext),
|
||||
new JavaScriptSandboxModule(reactContext),
|
||||
new JitsiMeetMediaProjectionModule(reactContext),
|
||||
new LocaleDetector(reactContext),
|
||||
new LogBridgeModule(reactContext),
|
||||
new SplashScreenModule(reactContext),
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<resources>
|
||||
<string name="app_name">Jitsi Meet SDK</string>
|
||||
<string name="dropbox_app_key"></string>
|
||||
<string name="media_projection_notification_title">Media projection</string>
|
||||
<string name="media_projection_notification_text">You are currently sharing your screen.</string>
|
||||
<string name="ongoing_notification_title">Ongoing meeting</string>
|
||||
<string name="ongoing_notification_text">You are currently in a meeting. Tap to return to it.</string>
|
||||
<string name="ongoing_notification_action_hang_up">Hang up</string>
|
||||
|
||||
@@ -38,6 +38,7 @@ import {
|
||||
dataChannelClosed,
|
||||
dataChannelOpened,
|
||||
e2eRttChanged,
|
||||
endpointMessageReceived,
|
||||
kickedOut,
|
||||
lockStateChanged,
|
||||
nonParticipantMessageReceived,
|
||||
@@ -162,7 +163,6 @@ import { isScreenAudioShared } from './react/features/screen-share/functions';
|
||||
import { toggleScreenshotCaptureSummary } from './react/features/screenshot-capture/actions';
|
||||
import { AudioMixerEffect } from './react/features/stream-effects/audio-mixer/AudioMixerEffect';
|
||||
import { createRnnoiseProcessor } from './react/features/stream-effects/rnnoise';
|
||||
import { endpointMessageReceived } from './react/features/subtitles/actions.any';
|
||||
import { handleToggleVideoMuted } from './react/features/toolbox/actions.any';
|
||||
import { muteLocal } from './react/features/video-menu/actions.any';
|
||||
import { iAmVisitor } from './react/features/visitors/functions';
|
||||
@@ -679,6 +679,8 @@ export default {
|
||||
startWithVideoMuted: getStartWithVideoMuted(state) || isUserInteractionRequiredForUnmute(state)
|
||||
};
|
||||
|
||||
logger.debug(`Executed conference.init with roomName: ${roomName}`);
|
||||
|
||||
this.roomName = roomName;
|
||||
|
||||
try {
|
||||
@@ -1824,28 +1826,24 @@ export default {
|
||||
|
||||
room.on(
|
||||
JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
|
||||
(...args) => {
|
||||
APP.store.dispatch(endpointMessageReceived(...args));
|
||||
if (args && args.length >= 2) {
|
||||
const [ sender, eventData ] = args;
|
||||
|
||||
if (eventData.name === ENDPOINT_TEXT_MESSAGE_NAME) {
|
||||
APP.API.notifyEndpointTextMessageReceived({
|
||||
senderInfo: {
|
||||
jid: sender._jid,
|
||||
id: sender._id
|
||||
},
|
||||
eventData
|
||||
});
|
||||
}
|
||||
(participant, data) => {
|
||||
APP.store.dispatch(endpointMessageReceived(participant, data));
|
||||
if (data?.name === ENDPOINT_TEXT_MESSAGE_NAME) {
|
||||
APP.API.notifyEndpointTextMessageReceived({
|
||||
senderInfo: {
|
||||
jid: participant.getJid(),
|
||||
id: participant.getId()
|
||||
},
|
||||
eventData: data
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
room.on(
|
||||
JitsiConferenceEvents.NON_PARTICIPANT_MESSAGE_RECEIVED,
|
||||
(...args) => {
|
||||
APP.store.dispatch(nonParticipantMessageReceived(...args));
|
||||
APP.API.notifyNonParticipantMessageReceived(...args);
|
||||
(id, data) => {
|
||||
APP.store.dispatch(nonParticipantMessageReceived(id, data));
|
||||
APP.API.notifyNonParticipantMessageReceived(id, data);
|
||||
});
|
||||
|
||||
room.on(
|
||||
|
||||
33
config.js
33
config.js
@@ -85,7 +85,7 @@ var config = {
|
||||
// disableE2EE: false,
|
||||
|
||||
// Enables supports for AV1 codec.
|
||||
// enableAv1: false,
|
||||
// enableAv1Support: false,
|
||||
|
||||
// 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
|
||||
@@ -103,6 +103,9 @@ var config = {
|
||||
|
||||
// Experiment: Whether to skip interim transcriptions.
|
||||
// skipInterimTranscriptions: false,
|
||||
|
||||
// Dump transcripts to a <transcript> element for debugging.
|
||||
// dumpTranscript: false,
|
||||
},
|
||||
|
||||
// Disables moderator indicators.
|
||||
@@ -324,6 +327,16 @@ var config = {
|
||||
// 'https://jitsi-meet.example.com/subfolder/static/oauth.html',
|
||||
// },
|
||||
|
||||
// configuration for all things recording related. Existing settings will be migrated here in the future.
|
||||
// recordings: {
|
||||
// // If true, shows a notification at the start of the meeting with a call to action button
|
||||
// // to start recording (for users who can do so).
|
||||
// // suggestRecording: true,
|
||||
// // If true, shows a warning label in the prejoin screen to point out the possibility that
|
||||
// // the call you're joining might be recorded.
|
||||
// // showPrejoinWarning: true,
|
||||
// },
|
||||
|
||||
// recordingService: {
|
||||
// // When integrations like dropbox are enabled only that will be shown,
|
||||
// // by enabling fileRecordingsServiceEnabled, we show both the integrations
|
||||
@@ -413,9 +426,6 @@ var config = {
|
||||
// // ./src/react/features/transcribing/transcriber-langs.json.
|
||||
// preferredLanguage: 'en-US',
|
||||
|
||||
// // Disable start transcription for all participants.
|
||||
// disableStartForAll: false,
|
||||
|
||||
// // Enables automatic turning on transcribing when recording is started
|
||||
// autoTranscribeOnRecord: false,
|
||||
// },
|
||||
@@ -713,7 +723,7 @@ var config = {
|
||||
// Configs for prejoin page.
|
||||
// prejoinConfig: {
|
||||
// // When 'true', it shows an intermediate page before joining, where the user can configure their devices.
|
||||
// // This replaces `prejoinPageEnabled`.
|
||||
// // This replaces `prejoinPageEnabled`. Defaults to true.
|
||||
// enabled: true,
|
||||
// // Hides the participant name editing field in the prejoin screen.
|
||||
// // If requireDisplayName is also set as true, a name should still be provided through
|
||||
@@ -1197,9 +1207,17 @@ var config = {
|
||||
// https://firebase.google.com/docs/dynamic-links/create-manually
|
||||
// deeplinking: {
|
||||
//
|
||||
// // The desktop deeplinking config.
|
||||
// // The desktop deeplinking config, disabled by default.
|
||||
// desktop: {
|
||||
// appName: 'Jitsi Meet'
|
||||
// appName: 'Jitsi Meet',
|
||||
// appScheme: 'jitsi-meet,
|
||||
// download: {
|
||||
// linux:
|
||||
// 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet-x86_64.AppImage',
|
||||
// macos: 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet.dmg',
|
||||
// windows: 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet.exe'
|
||||
// },
|
||||
// enabled: false
|
||||
// },
|
||||
// // If true, any checks to handoff to another application will be prevented
|
||||
// // and instead the app will continue to display in the current browser.
|
||||
@@ -1421,7 +1439,6 @@ var config = {
|
||||
// 'conference-timer',
|
||||
// 'participants-count',
|
||||
// 'e2ee',
|
||||
// 'transcribing',
|
||||
// 'video-quality',
|
||||
// 'insecure-room',
|
||||
// 'highlight-moment',
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.reactions-animations-container {
|
||||
.reactions-animations-overflow-container {
|
||||
position: absolute;
|
||||
width: 20%;
|
||||
bottom: 0;
|
||||
@@ -117,6 +117,13 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.reactions-animations-container {
|
||||
left: 50%;
|
||||
bottom: 0px;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
$reactionCount: 20;
|
||||
|
||||
@function random($min, $max) {
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 48px;
|
||||
max-width: calc(100% - 24px);
|
||||
}
|
||||
|
||||
@keyframes hideSubject {
|
||||
|
||||
@@ -36,6 +36,7 @@ $flagsImagePath: "../images/";
|
||||
@import 'modals/invite/info';
|
||||
@import 'modals/screen-share/share-audio';
|
||||
@import 'modals/screen-share/share-screen-warning';
|
||||
@import 'modals/whiteboard';
|
||||
@import 'videolayout_default';
|
||||
@import 'subject';
|
||||
@import 'popup_menu';
|
||||
|
||||
7
css/modals/_whiteboard.scss
Normal file
7
css/modals/_whiteboard.scss
Normal file
@@ -0,0 +1,7 @@
|
||||
.whiteboard {
|
||||
|
||||
.excalidraw-wrapper {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,6 @@ VirtualHost "jitmeet.example.com"
|
||||
}
|
||||
av_moderation_component = "avmoderation.jitmeet.example.com"
|
||||
speakerstats_component = "speakerstats.jitmeet.example.com"
|
||||
conference_duration_component = "conferenceduration.jitmeet.example.com"
|
||||
end_conference_component = "endconference.jitmeet.example.com"
|
||||
-- we need bosh
|
||||
modules_enabled = {
|
||||
@@ -130,9 +129,6 @@ Component "focus.jitmeet.example.com" "client_proxy"
|
||||
Component "speakerstats.jitmeet.example.com" "speakerstats_component"
|
||||
muc_component = "conference.jitmeet.example.com"
|
||||
|
||||
Component "conferenceduration.jitmeet.example.com" "conference_duration_component"
|
||||
muc_component = "conference.jitmeet.example.com"
|
||||
|
||||
Component "endconference.jitmeet.example.com" "end_conference"
|
||||
muc_component = "conference.jitmeet.example.com"
|
||||
|
||||
|
||||
@@ -38,9 +38,9 @@ apt install token-generator
|
||||
|
||||
mkdir -p /etc/jitsi/meet/jaas
|
||||
|
||||
VPASS_COOKIE=$(echo -n ${JAAS_KEY_ID}| cut -d/ -f1)
|
||||
VPAAS_COOKIE=$(echo -n ${JAAS_KEY_ID}| cut -d/ -f1)
|
||||
cp /usr/share/jitsi-meet-web-config/nginx-jaas.conf /etc/jitsi/meet/jaas
|
||||
sed -i "s/jaas_magic_cookie/${VPASS_COOKIE}/g" /etc/jitsi/meet/jaas/nginx-jaas.conf
|
||||
sed -i "s/jaas_magic_cookie/${VPAAS_COOKIE}/g" /etc/jitsi/meet/jaas/nginx-jaas.conf
|
||||
|
||||
cp /usr/share/jitsi-meet-web-config/8x8.vc-config.js /etc/jitsi/meet/jaas/
|
||||
echo "set \$config_js_location /etc/jitsi/meet/jaas/8x8.vc-config.js;" >> /etc/jitsi/meet/jaas/jaas-vars
|
||||
|
||||
1
globals.d.ts
vendored
1
globals.d.ts
vendored
@@ -21,6 +21,7 @@ declare global {
|
||||
JitsiMeetElectron?: any;
|
||||
PressureObserver?: any;
|
||||
PressureRecord?: any;
|
||||
ReactNativeWebView?: any;
|
||||
// selenium tests handler
|
||||
_sharedVideoPlayer: any;
|
||||
alwaysOnTop: { api: any };
|
||||
|
||||
3
globals.native.d.ts
vendored
3
globals.native.d.ts
vendored
@@ -19,6 +19,9 @@ interface IWindow {
|
||||
location: ILocation;
|
||||
PressureObserver?: any;
|
||||
PressureRecord?: any;
|
||||
ReactNativeWebView?: any;
|
||||
TextDecoder?: any;
|
||||
TextEncoder?: any;
|
||||
self: any;
|
||||
top: any;
|
||||
|
||||
|
||||
@@ -447,10 +447,10 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-splash-screen (3.3.0):
|
||||
- React-Core
|
||||
- react-native-video (6.0.0-alpha.7):
|
||||
- react-native-video (6.0.0-alpha.11):
|
||||
- React-Core
|
||||
- react-native-video/Video (= 6.0.0-alpha.7)
|
||||
- react-native-video/Video (6.0.0-alpha.7):
|
||||
- react-native-video/Video (= 6.0.0-alpha.11)
|
||||
- react-native-video/Video (6.0.0-alpha.11):
|
||||
- PromisesSwift
|
||||
- React-Core
|
||||
- react-native-webrtc (118.0.0):
|
||||
@@ -880,7 +880,7 @@ SPEC CHECKSUMS:
|
||||
react-native-safe-area-context: 9697629f7b2cda43cf52169bb7e0767d330648c2
|
||||
react-native-slider: 1cdd6ba29675df21f30544253bf7351d3c2d68c4
|
||||
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
|
||||
react-native-video: 967eead48aaa42c25a9e1d65c3b1ab30762a88df
|
||||
react-native-video: 472b7c366eaaaa0207e546d9a50410df89790bcf
|
||||
react-native-webrtc: c8d9ad3c152105b2720ca2851d04b49659551992
|
||||
react-native-webview: 8baa0f5c6d336d6ba488e942bcadea5bf51f050a
|
||||
React-NativeModulesApple: 4225ac31a26696c02c54b471052b3e85e74a9a0c
|
||||
|
||||
@@ -209,7 +209,7 @@
|
||||
"appNotInstalled": "Sie benötigen die „{{app}}“-App, um der Konferenz auf dem Smartphone beizutreten.",
|
||||
"description": "Nichts passiert? Wir haben versucht, die Konferenz in {{app}} zu öffnen. Versuchen Sie es erneut oder treten Sie der Konferenz in {{app}} im Web bei.",
|
||||
"descriptionNew": "Nichts passiert? Wir haben versucht, die Konferenz in {{app}} zu öffnen. <br /><br /> Versuchen Sie es erneut oder treten Sie der Konferenz im Web bei.",
|
||||
"descriptionWithoutWeb": "Ist nichts passiert? Wir haben versucht, Ihre Besprechung in der „{{app}}“-Desktop-App zu starten.",
|
||||
"descriptionWithoutWeb": "Ist nichts passiert? Wir haben versucht, Ihre Konferenz in der „{{app}}“-Desktop-App zu starten.",
|
||||
"downloadApp": "App herunterladen",
|
||||
"downloadMobileApp": "Aus dem App Store herunterladen",
|
||||
"ifDoNotHaveApp": "Wenn Sie die App noch nicht haben:",
|
||||
@@ -219,11 +219,13 @@
|
||||
"joinInBrowser": "Im Browser",
|
||||
"launchMeetingLabel": "Wie möchten Sie an der Konferenz teilnehmen?",
|
||||
"launchWebButton": "Im Web öffnen",
|
||||
"noDesktopApp": "Sie haben die App noch nicht installiert?",
|
||||
"noMobileApp": "Sie haben die App noch nicht installiert?",
|
||||
"termsAndConditions": "Indem Sie fortfahren, stimmen Sie underen<a href='{{termsAndConditionsLink}}' rel='noopener noreferrer' target='_blank'>Nutzungsbedingungen</a> zu.",
|
||||
"or": "oder",
|
||||
"termsAndConditions": "Indem Sie fortfahren, stimmen Sie unseren <a href='{{termsAndConditionsLink}}' rel='noopener noreferrer' target='_blank'>Nutzungsbedingungen</a> zu.",
|
||||
"title": "Die Konferenz wird in {{app}} geöffnet …",
|
||||
"titleNew": "Konferenz starten ...",
|
||||
"tryAgainButton": "Erneut mit der nativen Applikation versuchen",
|
||||
"tryAgainButton": "Erneut versuchen",
|
||||
"unsupportedBrowser": "Sie verwenden einen Browser, der noch nicht unterstützt wird."
|
||||
},
|
||||
"defaultLink": "Bsp.: {{url}}",
|
||||
@@ -534,7 +536,7 @@
|
||||
"conferenceURL": "Link:",
|
||||
"copyNumber": "Nummer kopieren",
|
||||
"country": "Land",
|
||||
"dialANumber": "Um am Meeting teilzunehmen, müssen Sie eine dieser Nummern wählen und dann die PIN eingeben.",
|
||||
"dialANumber": "Um an der Konferenz teilzunehmen, müssen Sie eine dieser Nummern wählen und dann die PIN eingeben.",
|
||||
"dialInConferenceID": "PIN:",
|
||||
"dialInNotSupported": "Entschuldigung, leider wird das Einwählen derzeit nicht unterstützt.",
|
||||
"dialInNumber": "Einwählen:",
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"addPeople": {
|
||||
"accessibilityLabel": {
|
||||
"meetingLink": "Lien de la réunion: {{url}}"
|
||||
},
|
||||
"add": "Inviter",
|
||||
"addContacts": "Inviter vos contacts",
|
||||
"contacts": "contacts",
|
||||
@@ -39,6 +42,18 @@
|
||||
"audioOnly": {
|
||||
"audioOnly": "Bande passante faible"
|
||||
},
|
||||
"bandwidthSettings": {
|
||||
"assumedBandwidthBps": "p. ex. 10000000 pour 10 Mbps ",
|
||||
"assumedBandwidthBpsWarning": "Des valeurs élevées peuvent provoquer des problèmes réseaux.",
|
||||
"customValue": "valeur personnalisée",
|
||||
"customValueEffect": "Positionner la valeur actuelle en bps",
|
||||
"leaveEmpty": "Laisser vide",
|
||||
"leaveEmptyEffect": "Autoriser l'utilisation de l'estimation",
|
||||
"possibleValues": "Valeurs possibles",
|
||||
"setAssumedBandwidthBps": "Bande passante estimée",
|
||||
"title": "Réglage de bande passante",
|
||||
"zeroEffect": "Désactiver la vidéo"
|
||||
},
|
||||
"breakoutRooms": {
|
||||
"actions": {
|
||||
"add": "Ajouter salle annexe",
|
||||
@@ -48,15 +63,22 @@
|
||||
"leaveBreakoutRoom": "Quitter la salle annexe",
|
||||
"more": "Plus",
|
||||
"remove": "Supprimer",
|
||||
"rename": "Renommer",
|
||||
"renameBreakoutRoom": "Renommer la salle annexe",
|
||||
"sendToBreakoutRoom": "Envoyer le participant dans:"
|
||||
},
|
||||
"breakoutList": "Liste des salles annexes",
|
||||
"buttonLabel": "Salles annexes",
|
||||
"defaultName": "Salle annexe #{{index}}",
|
||||
"hideParticipantList": "Masquer la liste des participants",
|
||||
"mainRoom": "Salle principale",
|
||||
"notifications": {
|
||||
"joined": "Entrée en salle annexe \"{{name}}\"",
|
||||
"joinedMainRoom": "Retour à la salle principalem",
|
||||
"joinedTitle": "Salles annexes"
|
||||
}
|
||||
},
|
||||
"showParticipantList": "Afficher la liste des participants",
|
||||
"title": "Salles annexes"
|
||||
},
|
||||
"calendarSync": {
|
||||
"addMeetingURL": "Ajouter un lien de conférence",
|
||||
@@ -118,7 +140,7 @@
|
||||
"buttonText": "Installer l'extension Chrome",
|
||||
"buttonTextEdge": "Installer l’extension Edge",
|
||||
"close": "Fermer",
|
||||
"dontShowAgain": "Ne plus me montrer ceci",
|
||||
"dontShowAgain": "Ne plus m'afficher ceci",
|
||||
"installExtensionText": "Installer l'extension pour l'intégration de Google Calendar et Office 365"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
@@ -149,13 +171,14 @@
|
||||
"connectedTo": "Connecté à :",
|
||||
"e2eeVerified": "E2EE vérifié",
|
||||
"framerate": "Images par seconde :",
|
||||
"less": "Cacher les détails",
|
||||
"less": "Masquer les détails",
|
||||
"localaddress": "Adresse locale :",
|
||||
"localaddress_plural": "Adresses locales :",
|
||||
"localport": "Port local :",
|
||||
"localport_plural": "Ports locaux :",
|
||||
"maxEnabledResolution": "débit max",
|
||||
"more": "Montrer les détails",
|
||||
"more": "Afficher les détails",
|
||||
"no": "non",
|
||||
"packetloss": "Perte de paquets :",
|
||||
"participant_id": "ID du participant:",
|
||||
"quality": {
|
||||
@@ -174,7 +197,8 @@
|
||||
"status": "Connexion :",
|
||||
"transport": "Transport :",
|
||||
"transport_plural": "Transports :",
|
||||
"video_ssrc": "Video SSRC :"
|
||||
"video_ssrc": "Video SSRC :",
|
||||
"yes": "oui"
|
||||
},
|
||||
"dateUtils": {
|
||||
"earlier": "Plus tôt",
|
||||
@@ -237,9 +261,12 @@
|
||||
"Share": "Partager",
|
||||
"Submit": "Soumettre",
|
||||
"WaitForHostMsg": "La conférence n'a pas encore commencé. Si vous en êtes l'hôte, veuillez vous authentifier. Sinon, veuillez attendre son arrivée.",
|
||||
"WaitingForHostButton": "Attendre l'hôte",
|
||||
"WaitingForHostTitle": "En attente de l'hôte ...",
|
||||
"Yes": "Oui",
|
||||
"accessibilityLabel": {
|
||||
"Cancel": "Annuler (quiter la popup)",
|
||||
"Ok": "Ok (Sauvegarder et quiter la popup)",
|
||||
"close": "Fermer la popup",
|
||||
"liveStreaming": "Diffusion en direct",
|
||||
"sharingTabs": "Options de partage"
|
||||
@@ -248,6 +275,8 @@
|
||||
"addMeetingNote": "Ajouter une note à cette conférence",
|
||||
"addOptionalNote": "Ajouter une note (optionnel):",
|
||||
"allow": "Autoriser",
|
||||
"allowToggleCameraDialog": "Autorisez-vous {{initiatorName}} à changer votre mode de caméra ?",
|
||||
"allowToggleCameraTitle": "Autoriser-vous le changement de mode de caméra ?",
|
||||
"alreadySharedVideoMsg": "Un autre participant est en train de partager sa vidéo. Cette conférence ne permet de partager qu'une seule vidéo à la fois.",
|
||||
"alreadySharedVideoTitle": "Une seule vidéo partagée est autorisée à la fois",
|
||||
"applicationWindow": "Fenêtre d'application",
|
||||
@@ -288,8 +317,8 @@
|
||||
"gracefulShutdown": "Notre service est actuellement en maintenance. Veuillez réessayer plus tard.",
|
||||
"grantModeratorDialog": "Êtes-vous sûr de vouloir rendre ce participant modérateur ?",
|
||||
"grantModeratorTitle": "Nommer modérateur",
|
||||
"hide": "Cacher",
|
||||
"hideShareAudioHelper": "Ne pas montrer ce dialogue à nouveau",
|
||||
"hide": "Masquer",
|
||||
"hideShareAudioHelper": "Ne pas afficher ce dialogue à nouveau",
|
||||
"incorrectPassword": "Nom d'utilisateur ou mot de passe incorrect",
|
||||
"incorrectRoomLockPassword": "Mot de passe incorrect",
|
||||
"internalError": "Oups ! Quelque chose s'est mal passée. L'erreur suivante s'est produite : {{error}}",
|
||||
@@ -308,6 +337,7 @@
|
||||
"lockRoom": "Ajouter un $t(lockRoomPassword) à la réunion ",
|
||||
"lockTitle": "Échec du verrouillage",
|
||||
"login": "Connexion",
|
||||
"loginQuestion": "Voulez-vous vraiment vous connecter et quitter la conférence ?",
|
||||
"logoutQuestion": "Voulez-vous vraiment vous déconnecter et arrêter la conférence ?",
|
||||
"logoutTitle": "Déconnexion",
|
||||
"maxUsersLimitReached": "Le nombre maximal de participants est atteint. Le conférence est complète. Merci de contacter l'organisateur de la réunion ou réessayer plus tard !",
|
||||
@@ -351,8 +381,6 @@
|
||||
"permissionCameraRequiredError": "L'autorisation caméra est nécessaire pour participer aux réunions avec vidéo. Merci de l'accorder dans les paramètres",
|
||||
"permissionErrorTitle": "Permission nécessaire",
|
||||
"permissionMicRequiredError": "L'autorisation microphone est nécessaire pour participer aux réunions avec son. Merci de l'accorder dans les paramètres",
|
||||
"popupError": "Votre navigateur bloque les fenêtres pop-up. Veuillez autoriser les fenêtres pop-up dans les paramètres de votre navigateur.",
|
||||
"popupErrorTitle": "Pop-up bloquée",
|
||||
"readMore": "plus",
|
||||
"recentlyUsedObjects": "Vos objets récemment utilisés",
|
||||
"recording": "Enregistrement",
|
||||
@@ -369,6 +397,8 @@
|
||||
"removePassword": "Supprimer le $t(lockRoomPassword)",
|
||||
"removeSharedVideoMsg": "Voulez-vous vraiment supprimer votre vidéo partagée ?",
|
||||
"removeSharedVideoTitle": "Supprimer la vidéo partagée",
|
||||
"renameBreakoutRoomLabel": "Nom de la salle annexe",
|
||||
"renameBreakoutRoomTitle": "Renommer la salle annexe",
|
||||
"reservationError": "Erreur du système de réservation",
|
||||
"reservationErrorMsg": "Code d'erreur: {{code}}, message: {{msg}}",
|
||||
"retry": "Réessayer",
|
||||
@@ -388,8 +418,10 @@
|
||||
"sendPrivateMessageTitle": "Envoyer en privé ?",
|
||||
"serviceUnavailable": "Service indisponible",
|
||||
"sessTerminated": "Appel terminé",
|
||||
"sessTerminatedReason": "L'appel a été terminé",
|
||||
"sessionRestarted": "L'appel est relancé par la passerelle",
|
||||
"shareAudio": "Continuer",
|
||||
"shareAudioAltText": "Pour partager le contenu voulu, naviguer vers \"Onglet du Navigateur\", sélectionner le contenu, activer le bouton \"partager l’audio\" et enfin cliquer sur le bouton \"partager\"",
|
||||
"shareAudioTitle": "Comment partager le son",
|
||||
"shareAudioWarningD1": "vous devez cesser le partage d'écran avant de partager votre son.",
|
||||
"shareAudioWarningD2": "viys devez partager votre écran à nouveau et cocher l'ootion \"Partager l'audio\".",
|
||||
@@ -419,12 +451,30 @@
|
||||
"thankYou": "Merci d'avoir utilisé {{appName}} !",
|
||||
"token": "jeton",
|
||||
"tokenAuthFailed": "Désolé, vous n'êtes pas autorisé à rejoindre cette conversation.",
|
||||
"tokenAuthFailedReason": {
|
||||
"audInvalid": "Valeur `aud` invalide. Cela doit être `jitsi`.",
|
||||
"contextNotFound": "L'objet `context` est absent du payload.",
|
||||
"expInvalid": "Valeur `exp` invalide.",
|
||||
"featureInvalid": "Fonctionnalité invalide: {{feature}}, probablement pas encore implémentée.",
|
||||
"featureValueInvalid": "Valeur invalide pour la fonctionnalité: {{feature}}.",
|
||||
"featuresNotFound": "L'objet `feature` est absent du payload.",
|
||||
"headerNotFound": "Header non trouvé.",
|
||||
"issInvalid": "Valeur `iss` invalide. Cela doit être `chat`.",
|
||||
"kidMismatch": "Key ID (kid) ne correspond pas au sub.",
|
||||
"kidNotFound": "Key ID (kid) manquant.",
|
||||
"nbfFuture": "La valeur `nbf` est dans le futur.",
|
||||
"nbfInvalid": "Valeur `nbf` invalide.",
|
||||
"payloadNotFound": "Payload non trouvé",
|
||||
"tokenExpired": "Jeton expiré"
|
||||
},
|
||||
"tokenAuthFailedTitle": "Échec de l'authentification",
|
||||
"tokenAuthFailedWithReasons": "Désolé, vous n’êtes pas autorisé à rejoindre l’appel. La raison possible : {{reason}}.",
|
||||
"tokenAuthUnsupported": "Token URL n'est pas supporté.",
|
||||
"transcribing": "Transcription",
|
||||
"unlockRoom": "Supprimer le $t(lockRoomPassword) de la réunion",
|
||||
"user": "Utilisateur",
|
||||
"userIdentifier": "Identifiant utilisateur",
|
||||
"userPassword": "mot de passe utilisateur",
|
||||
"userPassword": "Mot de passe utilisateur",
|
||||
"verifyParticipantConfirm": "Ils correspondent",
|
||||
"verifyParticipantDismiss": "Ils ne correspondent pas",
|
||||
"verifyParticipantQuestion": "EXPÉRIMENTAL: Demander au participant {{participantName}} s'il voit le même contenu dans le même ordre. ",
|
||||
@@ -433,6 +483,10 @@
|
||||
"viewUpgradeOptions": "Voir les options de mise à jour",
|
||||
"viewUpgradeOptionsContent": "Pour obtenir un accès illimité à des capacités premium comme l'enregistrement, les transcriptions, diffusion RTMP et plus, vous devez mettre à jour votre plan.",
|
||||
"viewUpgradeOptionsTitle": "Vous avez découvert une capacité premium !",
|
||||
"whiteboardLimitContent": "Désolé, la limite d’utilisateur du tableau blanc a été atteinte.",
|
||||
"whiteboardLimitReference": "Pour plus d’informations merci de visiter",
|
||||
"whiteboardLimitReferenceUrl": "notre site web",
|
||||
"whiteboardLimitTitle": "Utilisation du tableau blanc limitée",
|
||||
"yourEntireScreen": "Votre écran entier"
|
||||
},
|
||||
"documentSharing": {
|
||||
@@ -445,6 +499,9 @@
|
||||
"title": "Intégrer cette réunion"
|
||||
},
|
||||
"feedback": {
|
||||
"accessibilityLabel": {
|
||||
"yourChoice": "Votre choix: {{rating}}"
|
||||
},
|
||||
"average": "Moyen",
|
||||
"bad": "Mauvais",
|
||||
"detailsLabel": "Dites nous en plus à ce sujet.",
|
||||
@@ -505,6 +562,7 @@
|
||||
"password": "$t(lockRoomPasswordUppercase) :",
|
||||
"reachedLimit": "Vous avez atteint la limite de votre abonnement.",
|
||||
"sip": "adresse SIP",
|
||||
"sipAudioOnly": "Adresse SIP en audio uniquement",
|
||||
"title": "Partager",
|
||||
"tooltip": "Partager le lien et les informations de connexion pour cette conférence",
|
||||
"upgradeOptions": "Veuillez vérifier les options de mise à niveau"
|
||||
@@ -544,7 +602,7 @@
|
||||
},
|
||||
"largeVideo": {
|
||||
"screenIsShared": "Vous êtes en train de partager votre écran",
|
||||
"showMeWhatImSharing": "Me montrer ce que je partage"
|
||||
"showMeWhatImSharing": "M'afficher ce que je partage"
|
||||
},
|
||||
"liveStreaming": {
|
||||
"busy": "Nous tentons de libérer des ressources de diffusion. Veuillez réessayez dans quelques minutes.",
|
||||
@@ -609,13 +667,13 @@
|
||||
"knockingParticipantList": "Liste des participants en attente",
|
||||
"lobbyChatStartedNotification": "Un modérateur dialogue en salle d'attente avec {{attendee}}",
|
||||
"lobbyChatStartedTitle": "Un modérateur dialogue en salle d'attente avec vous.",
|
||||
"lobbyClosed": "La salle d'attente a été fermée.",
|
||||
"nameField": "Saisissez votre nom",
|
||||
"notificationLobbyAccessDenied": "{{targetParticipantName}} a été refusé par {{originParticipantName}}",
|
||||
"notificationLobbyAccessGranted": "{{targetParticipantName}} a été accepté par {{originParticipantName}}",
|
||||
"notificationLobbyDisabled": "Le mode salle d'attente a été désactivé par {{originParticipantName}}",
|
||||
"notificationLobbyEnabled": "Le mode salle d'attente a été activé par {{originParticipantName}}",
|
||||
"notificationTitle": "Salle d'attente",
|
||||
"passwordField": "Veuillez saisir le mot de passe de la réunion",
|
||||
"passwordJoinButton": "Rejoindre",
|
||||
"title": "Salle d'attente",
|
||||
"toggleLabel": "Activer la salle d'attente"
|
||||
@@ -648,6 +706,8 @@
|
||||
"sessionToken": "Token de la session",
|
||||
"start": "Démarrer l'enregistrement",
|
||||
"stop": "Arrêter l'enregistrement",
|
||||
"stopping": "Arrêt de l'enregistrement",
|
||||
"wait": "Patienter pendant la sauvegarde de votre enregistrement.",
|
||||
"yes": "Oui"
|
||||
},
|
||||
"lockRoomPassword": "mot de passe",
|
||||
@@ -669,8 +729,11 @@
|
||||
"connectedTwoMembers": "{{first}} et {{second}} ont rejoint la réunion",
|
||||
"dataChannelClosed": "Qualité vidéo dégradée",
|
||||
"dataChannelClosedDescription": "Le canal de communication avec le Bridge a été interrompu, la qualité vidéo se trouve limitée à sa valeur la plus faible.",
|
||||
"disabledIframe": "L'intégration Iframe est uniquement destinée à des démos, cet appel se terminera dans {{timeout}} minutes.",
|
||||
"disabledIframeSecondary": "L'intégration Iframe de {{domaine}} est uniquement destinée à des démos, cet appel se terminera dans {{timeout}} minutes.",
|
||||
"disconnected": "déconnecté",
|
||||
"displayNotifications": "Afficher les notifications pour",
|
||||
"dontRemindMe": "Ne pas me le rappeler",
|
||||
"focus": "Focus de conférence",
|
||||
"focusFail": "{{component}} n'est pas disponible - réessayez dans {{ms}} sec",
|
||||
"gifsMenu": "GIPHY",
|
||||
@@ -679,6 +742,7 @@
|
||||
"invitedOneMember": "{{name}} a été invité(e)",
|
||||
"invitedThreePlusMembers": "{{name}} et {{count}} autres ont été invités",
|
||||
"invitedTwoMembers": "{{first}} et {{second}} ont été invités",
|
||||
"joinMeeting": "Rejoindre",
|
||||
"kickParticipant": "{{kicked}} a été expulsé par {{kicker}}",
|
||||
"leftOneMember": "{{name}} a quitté la réunion",
|
||||
"leftThreePlusMembers": "{{name}} et beaucoup d'autres ont quitté la réunion",
|
||||
@@ -713,7 +777,6 @@
|
||||
"newDeviceCameraTitle": "Nouvelle caméra détectée",
|
||||
"noiseSuppressionDesktopAudioDescription": "La suppression de bruit ne peut pas être activée en même temps que la partage audio du système, veuillez le désactiver et réessayer.",
|
||||
"noiseSuppressionFailedTitle": "Échec du démarrage de la suppression de bruit",
|
||||
"noiseSuppressionNoTrackDescription": "Veuillez activer votre microphone d'abord.",
|
||||
"noiseSuppressionStereoDescription": "La suppression de bruit d’une source stéréo n’est pas encore supportée.",
|
||||
"oldElectronClientDescription1": "Vous semblez utiliser une ancienne version du client Jitsi Meet qui présente des failles de sécurité connues. Veuillez vous assurer de mettre à jour vers notre ",
|
||||
"oldElectronClientDescription2": "dernière build",
|
||||
@@ -743,7 +806,9 @@
|
||||
"videoUnmuteBlockedDescription": "Le rétablissement de la vidéo a été bloqué temporairement en raison de limites système.",
|
||||
"videoUnmuteBlockedTitle": "Rétablissement de la caméra bloqué !",
|
||||
"viewLobby": "Voir la salle d'attente",
|
||||
"waitingParticipants": "{{waitingParticipants}} personnes"
|
||||
"waitingParticipants": "{{waitingParticipants}} personnes",
|
||||
"whiteboardLimitDescription": "Veuillez sauvegarder votre progression, car la limite d’utilisation du tableau blanc sera bientôt atteinte et celui-ci sera fermé.",
|
||||
"whiteboardLimitTitle": "Utiilisation du tableau blanc"
|
||||
},
|
||||
"participantsPane": {
|
||||
"actions": {
|
||||
@@ -754,6 +819,7 @@
|
||||
"askUnmute": "Demander de réactiver le micro",
|
||||
"audioModeration": "Rouvrir leur micro",
|
||||
"blockEveryoneMicCamera": "Bloquer tous les micros et caméras",
|
||||
"breakoutRooms": "Salles annexes",
|
||||
"invite": "Inviter quelqu'un",
|
||||
"moreModerationActions": "Options de modération supplémentaires",
|
||||
"moreModerationControls": "Options de modération supplémentaires",
|
||||
@@ -771,6 +837,7 @@
|
||||
"headings": {
|
||||
"lobby": "Salle d'attente ({{count}})",
|
||||
"participantsList": "Participants de la réunion ({{count}})",
|
||||
"visitorRequests": "(Demande {{count}} )",
|
||||
"visitors": "Visiteurs {{count}}",
|
||||
"waitingLobby": "Dans la salle d'attente ({{count}})"
|
||||
},
|
||||
@@ -805,8 +872,8 @@
|
||||
"results": {
|
||||
"changeVote": "Changer le vote",
|
||||
"empty": "Il n'y a pas encore de sondages dans cette réunion. Démarrez un sondage ici !",
|
||||
"hideDetailedResults": "Cacher les détails",
|
||||
"showDetailedResults": "Montrer les détails",
|
||||
"hideDetailedResults": "Masquer les détails",
|
||||
"showDetailedResults": "Afficher les détails",
|
||||
"vote": "Voter"
|
||||
}
|
||||
},
|
||||
@@ -864,9 +931,11 @@
|
||||
"lookGood": "Il semble que votre microphone fonctionne correctement",
|
||||
"or": "ou",
|
||||
"premeeting": "Pré-séance",
|
||||
"proceedAnyway": "Continuer quand même",
|
||||
"screenSharingError": "Erreur de partage d'écran:",
|
||||
"showScreen": "Activer l'écran de pré-séance",
|
||||
"startWithPhone": "Commencez avec l'audio du téléphone",
|
||||
"unsafeRoomConsent": "Je comprends les risques et je veux quand même rejoindre cette réunion",
|
||||
"videoOnlyError": "Erreur vidéo:",
|
||||
"videoTrackError": "Impossible de créer une piste vidéo.",
|
||||
"viewAllNumbers": "voir tous les numéros"
|
||||
@@ -929,7 +998,6 @@
|
||||
"limitNotificationDescriptionNative": "En raison d'une forte demande, votre enregistrement sera limité à {{limit}} min. Pour des enregistrements illimités, essayez <3> {{app}} </3>.",
|
||||
"limitNotificationDescriptionWeb": "En raison d'une forte demande, votre enregistrement sera limité à {{limit}} min. Pour des enregistrements illimités, essayez <a href={{url}} rel='noopener noreferrer' target='_blank'> {{app}} </a>.",
|
||||
"linkGenerated": "Nous avons généré un lien à votre enregistrement.",
|
||||
"live": "DIRECT",
|
||||
"localRecordingNoNotificationWarning": "Le démarrage de l’enregistrement ne sera pas annoncé aux autres participants. Vous devrez les informer par vous-même que la réunion sera enregistrée.",
|
||||
"localRecordingNoVideo": "La vidéo n'est pas en cours d’enregistrement",
|
||||
"localRecordingStartWarning": "Assurez-vous d’arrêter l’enregistrement vidéo avant de quitter la réunion afin de pouvoir le sauvegarder.",
|
||||
@@ -946,13 +1014,15 @@
|
||||
"onBy": "{{name}} a démarré l'enregistrement",
|
||||
"onlyRecordSelf": "Enregistrer seulement mon audio et ma vidéo.",
|
||||
"pending": "Préparation de l'enregistrement de la réunion ...",
|
||||
"rec": "REC",
|
||||
"recordAudioAndVideo": "Enregistrer l'audio et la vidéo",
|
||||
"recordTranscription": "Enregistrer la transcription",
|
||||
"saveLocalRecording": "Sauvegarder l’enregistrement local (Beta)",
|
||||
"serviceDescription": "Votre enregistrement sera enregistré par le service dédié",
|
||||
"serviceDescriptionCloud": "Enregistrement Cloud",
|
||||
"serviceDescriptionCloudInfo": "Les conférences enregistrées sont automatiquement supprimées 24h après leur heure d'enregistrement.",
|
||||
"serviceName": "Service d'enregistrement",
|
||||
"sessionAlreadyActive": "Cette session est déjà en cours d'enregistrement ou de diffusion.",
|
||||
"showAdvancedOptions": "Afficher les options avancées",
|
||||
"signIn": "Se connecter",
|
||||
"signOut": "Se déconnecter",
|
||||
"surfaceError": "Veuillez sélectionner l’onglet courant.",
|
||||
@@ -968,8 +1038,14 @@
|
||||
"security": {
|
||||
"about": "Vous pouvez ajouter un mot de passe à votre réunion. Les participants devront fournir le mot de passe avant de pouvoir rejoindre la réunion.",
|
||||
"aboutReadOnly": "Les modérateurs peuvent ajouter un mot de passe à la réunion. Les participants devront fournir le mot de passe avant de pouvoir rejoindre la réunion.",
|
||||
"insecureRoomNameWarning": "Le nom de la salle est peu sûr. Des participants non désirés peuvent rejoindre votre réunion. Pensez à sécuriser votre réunion en cliquant sur le bouton de sécurité.",
|
||||
"title": "Options de sécurité"
|
||||
"insecureRoomNameWarningNative": "Le nom de la réunion n’est pas sûr. Des participants non voulus pourraient rejoindre cette réunion. {{recommendAction}} En apprendre plus sur la sécurisation des réunions.",
|
||||
"insecureRoomNameWarningWeb": "Le nom de la réunion n’est pas sûr. Des participants non voulus pourraient rejoindre cette réunion. {{recommendAction}} En apprendre plus sur la sécurisation des réunions <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">here</a>.",
|
||||
"title": "Options de sécurité",
|
||||
"unsafeRoomActions": {
|
||||
"meeting": "Envisagez de sécuriser votre réunion en utilisant le bouton options de sécurité.",
|
||||
"prejoin": "Envisagez d'utiliser un nom plus unique",
|
||||
"welcome": "Envisagez d'utiliser un nom plus unique ou choisissez en un parmi ceux suggérés"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"audio": "Audio",
|
||||
@@ -1002,7 +1078,7 @@
|
||||
"participantKnocking": "un participant en salle d’attente",
|
||||
"participantLeft": "un participant quitte",
|
||||
"playSounds": "Jouer un son quand",
|
||||
"reactions": "il y a une réaction à la réunion",
|
||||
"reactions": "Il y a une réaction à la réunion",
|
||||
"sameAsSystem": "Identique au système ({{label}})",
|
||||
"selectAudioOutput": "Sortie audio",
|
||||
"selectCamera": "Caméra",
|
||||
@@ -1023,6 +1099,7 @@
|
||||
"alertOk": "D'accord",
|
||||
"alertTitle": "Avertissement",
|
||||
"alertURLText": "L'URL du serveur est invalide",
|
||||
"apply": "Appliquer",
|
||||
"buildInfoSection": "Informations de build",
|
||||
"conferenceSection": "Conférence",
|
||||
"disableCallIntegration": "Désactiver l'intégration d'appels native",
|
||||
@@ -1033,12 +1110,14 @@
|
||||
"displayNamePlaceholderText": "Ex : Jean Dupond",
|
||||
"email": "Email",
|
||||
"emailPlaceholderText": "email@example..com",
|
||||
"gavatarMessage": "Si votre email est associé à un compte Gravatar, nous allons l’utiliser pour afficher votre image de profil.",
|
||||
"goTo": "Aller à",
|
||||
"header": "Paramètres",
|
||||
"help": "Aide",
|
||||
"links": "Liens",
|
||||
"privacy": "Confidentialité",
|
||||
"profileSection": "Profil",
|
||||
"sdkVersion": "Version du SDK",
|
||||
"serverURL": "URL du serveur",
|
||||
"showAdvanced": "Afficher les paramètres avancés",
|
||||
"startCarModeInLowBandwidthMode": "Commencer le mode voiture en mode bande passante réduite",
|
||||
@@ -1091,17 +1170,26 @@
|
||||
"audioOnly": "Activer / Désactiver le mode voix uniquement",
|
||||
"audioRoute": "Sélectionner la source audio",
|
||||
"boo": "Hou",
|
||||
"breakoutRoom": "Rejoindre/quitter une salle annexe",
|
||||
"breakoutRooms": "Rejoindre / quitter une salle annexe",
|
||||
"callQuality": "Ajuster la qualité vidéo",
|
||||
"carmode": "Mode voiture",
|
||||
"cc": "Activer / Désactiver les sous-titres",
|
||||
"chat": "Afficher / Masquer la discussion instantanée",
|
||||
"clap": "Applaudir",
|
||||
"closeChat": "Fermer la discussion instantanée",
|
||||
"closeMoreActions": "Fermer le menu plus d'actions",
|
||||
"closeParticipantsPane": "Fermer le panneau des participants",
|
||||
"collapse": "Plier",
|
||||
"document": "Activer / Désactiver le document partagé",
|
||||
"documentClose": "Fermer le document partagé",
|
||||
"documentOpen": "Ouvrir le document partagé",
|
||||
"download": "Télécharger nos applications",
|
||||
"embedMeeting": "Intégrer la réunion",
|
||||
"endConference": "Terminer la réunion pour tout le monde",
|
||||
"enterFullScreen": "Passer en mode plein écran",
|
||||
"enterTileView": "Passer en vue mosaïque",
|
||||
"exitFullScreen": "Quitter le mode plein écran",
|
||||
"exitTileView": "Quitter la vue mosaïque",
|
||||
"expand": "Développer",
|
||||
"feedback": "Laisser des commentaires",
|
||||
"fullScreen": "Activer / Désactiver le plein écran",
|
||||
@@ -1110,6 +1198,7 @@
|
||||
"hangup": "Quitter la conversation",
|
||||
"heading": "Barre d'outils",
|
||||
"help": "Aide",
|
||||
"hideWhiteboard": "Masquer le tableau blanc",
|
||||
"invite": "Inviter des participants",
|
||||
"kick": "Expulser le participant",
|
||||
"laugh": "Rire",
|
||||
@@ -1119,6 +1208,7 @@
|
||||
"lobbyButton": "Activer / Désactiver le mode salle d'attente",
|
||||
"localRecording": "Activer / Désactiver les contrôles d'enregistrement local",
|
||||
"lockRoom": "Activer / Désactiver le mot de passe de la réunion",
|
||||
"lowerHand": "Baisser la main",
|
||||
"moreActions": "Activer / Désactiver le menu d'actions supplémentaires",
|
||||
"moreActionsMenu": "Menu d'actions supplémentaires",
|
||||
"moreOptions": "Voir plus d'options",
|
||||
@@ -1127,12 +1217,15 @@
|
||||
"muteEveryoneElse": "Couper le micro de tous les autres",
|
||||
"muteEveryoneElsesVideoStream": "Couper la caméra de tous les autres",
|
||||
"muteEveryonesVideoStream": "Couper la caméra de tout le monde",
|
||||
"muteGUMPending": "Connection de votre microphone",
|
||||
"noiseSuppression": "Suppression du bruit",
|
||||
"openChat": "Ouvrir le chat",
|
||||
"participants": "Participants",
|
||||
"pip": "Activer / Désactiver le mode Picture in Picture",
|
||||
"privateMessage": "Envoyer un message privé",
|
||||
"profile": "Éditer votre profil",
|
||||
"raiseHand": "Lever la main",
|
||||
"reactions": "Réactions",
|
||||
"reactionsMenu": "Ouvrir / fermer le menu réactions",
|
||||
"recording": "Activer / Désactiver l'enregistrement",
|
||||
"remoteMute": "Couper le micro du participant",
|
||||
@@ -1146,15 +1239,20 @@
|
||||
"sharedvideo": "Démarrer / Arrêter le partage de vidéo",
|
||||
"shortcuts": "Afficher / Masquer les raccourcis",
|
||||
"show": "Afficher en premier plan",
|
||||
"showWhiteboard": "Afficher le tableux blanc",
|
||||
"silence": "Silence",
|
||||
"speakerStats": "Afficher / Cacher les statistiques de parole",
|
||||
"speakerStats": "Afficher / Masquer les statistiques de parole",
|
||||
"stopScreenSharing": "Arrêter le partage d'écran",
|
||||
"stopSharedVideo": "Arrêter la vidéo partagée",
|
||||
"surprised": "Surpris",
|
||||
"tileView": "Activer / Désactiver la vue mosaïque",
|
||||
"toggleCamera": "Changer de caméra",
|
||||
"toggleFilmstrip": "Afficher ou masquer les vignettes vidéo",
|
||||
"unmute": "Rétablir le son",
|
||||
"videoblur": "Activer / désactiver le floutage",
|
||||
"videomute": "Activer / Couper la vidéo",
|
||||
"whiteboard": "Afficher / Cacher le tableau blanc"
|
||||
"videomuteGUMPending": "Connexion de votre caméra",
|
||||
"videounmute": "Démarrer la vidéo"
|
||||
},
|
||||
"addPeople": "Ajouter des personnes à votre appel",
|
||||
"audioOnlyOff": "Désactiver le mode bande passante réduite",
|
||||
@@ -1167,6 +1265,7 @@
|
||||
"chat": "Ouvrir / Fermer le chat",
|
||||
"clap": "Applaudir",
|
||||
"closeChat": "Fermer le chat",
|
||||
"closeParticipantsPane": "Fermer le panneau des participants",
|
||||
"closeReactionsMenu": "Fermer le menu réactions",
|
||||
"disableNoiseSuppression": "Arrêter la suppression du bruit",
|
||||
"disableReactionSounds": "Vous pouvez interdire les réactions sonores à cette réunion",
|
||||
@@ -1185,7 +1284,7 @@
|
||||
"giphy": "Activer/désactiver le menu GIPHY",
|
||||
"hangup": "Quitter",
|
||||
"help": "Aide",
|
||||
"hideWhiteboard": "Cacher le tableau blanc",
|
||||
"hideWhiteboard": "Masquer le tableau blanc",
|
||||
"invite": "Inviter des participants",
|
||||
"joinBreakoutRoom": "Rejoindre salle annexe",
|
||||
"laugh": "Rire",
|
||||
@@ -1203,6 +1302,7 @@
|
||||
"mute": "Muet / Actif",
|
||||
"muteEveryone": "Couper le micro à tout le monde",
|
||||
"muteEveryonesVideo": "Couper la caméra de tout le monde",
|
||||
"muteGUMPending": "Connection de votre microphone",
|
||||
"noAudioSignalDesc": "Si vous n'avez pas délibérément coupé le son des paramètres du système ou du matériel, envisagez de changer de périphérique utilisé.",
|
||||
"noAudioSignalDescSuggestion": "Si vous n'avez pas délibérément coupé le son des paramètres du système ou du matériel, pensez à utiliser le périphérique suivant :",
|
||||
"noAudioSignalDialInDesc": "Vous pouvez également appeler en utilisant :",
|
||||
@@ -1225,6 +1325,7 @@
|
||||
"reactionLike": "Envoyer réaction approuver",
|
||||
"reactionSilence": "Envoyer réaction silence",
|
||||
"reactionSurprised": "Envoyer réaction surprise",
|
||||
"reactions": "Reactions",
|
||||
"security": "Options de sécurité",
|
||||
"selectBackground": "Sélectionner un arrière-plan",
|
||||
"shareRoom": "Inviter quelqu'un",
|
||||
@@ -1244,8 +1345,11 @@
|
||||
"talkWhileMutedPopup": "Vous voulez parler ? Votre micro est coupé.",
|
||||
"tileViewToggle": "Activer / Désactiver la vue mosaïque",
|
||||
"toggleCamera": "Changer de caméra",
|
||||
"unmute": "Rétablir le son",
|
||||
"videoSettings": "Paramètres vidéo",
|
||||
"videomute": "Démarrer / Arrêter la caméra"
|
||||
"videomute": "Arrêter la caméra",
|
||||
"videomuteGUMPending": "Connexion de votre caméra",
|
||||
"videounmute": "Démarrer la caméra"
|
||||
},
|
||||
"transcribing": {
|
||||
"ccButtonTooltip": "Activer / Désactiver les sous-titres",
|
||||
@@ -1253,7 +1357,8 @@
|
||||
"expandedLabel": "La transcription est actuellement activée",
|
||||
"failedToStart": "Échec de démarrage de la transcription",
|
||||
"labelToolTip": "La transcription de la réunion est en cours",
|
||||
"off": "La transcription désactivée",
|
||||
"off": "La transcription est désactivée",
|
||||
"on": "La transcription est activée",
|
||||
"pending": "Préparation de la transcription de la réunion ...",
|
||||
"sourceLanguageDesc": "Actuellement, la langue de la réunion est sélectionnée à <b>{{sourceLanguage}}</b>. <br/> Vous pouvez la changer à partir de ",
|
||||
"sourceLanguageHere": "ici",
|
||||
@@ -1316,7 +1421,7 @@
|
||||
"domuteVideoOfOthers": "Couper la caméra des autres",
|
||||
"flip": "Miroir",
|
||||
"grantModerator": "Donner des droits de modérateur",
|
||||
"hideSelfView": "Cacher l'affichage de votre propre vidéo",
|
||||
"hideSelfView": "Masquer l'affichage de votre propre vidéo",
|
||||
"kick": "Exclure",
|
||||
"mirrorVideo": "Inverser ma vidéo",
|
||||
"moderator": "Modérateur",
|
||||
@@ -1326,13 +1431,17 @@
|
||||
"remoteControl": "Démarrer / Arrêter le contrôle à distance",
|
||||
"screenSharing": "Cette personne partage son écran",
|
||||
"show": "Afficher en premier plan",
|
||||
"showSelfView": "Montrer votre propre vidéo",
|
||||
"showSelfView": "Afficher votre propre vidéo",
|
||||
"unpinFromStage": "Ne plus garder affiché",
|
||||
"verify": "Vérifier le participant",
|
||||
"videoMuted": "Caméra coupée",
|
||||
"videomute": "Le participant a arrêté la caméra"
|
||||
},
|
||||
"virtualBackground": {
|
||||
"accessibilityLabel": {
|
||||
"currentBackground": "Arrière-plan actuel: {{background}}",
|
||||
"selectBackground": "Sélectionner un arrière-plan"
|
||||
},
|
||||
"addBackground": "Ajouter un arrière-plan",
|
||||
"apply": "Appliquer",
|
||||
"backgroundEffectError": "Erreur dans l'application de l'effet d'arrière-plan.",
|
||||
@@ -1356,7 +1465,14 @@
|
||||
"webAssemblyWarning": "WebAssembly non supporté",
|
||||
"webAssemblyWarningDescription": "WebAssembly invalidé ou non supporté par ce navigateur"
|
||||
},
|
||||
"visitorsLabel": "Nombre de visiteurs: {{count}}",
|
||||
"visitors": {
|
||||
"chatIndicator": "(visiteur)",
|
||||
"labelTooltip": "Nombre de Visiteurs",
|
||||
"notification": {
|
||||
"description": "Pour participer lever la main.",
|
||||
"title": "Vous êtes visiteur dans cette réunion"
|
||||
}
|
||||
},
|
||||
"volumeSlider": "Curseur de volume",
|
||||
"welcomepage": {
|
||||
"accessibilityLabel": {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -219,7 +219,9 @@
|
||||
"joinInBrowser": "Pievienojieties pārlūkā",
|
||||
"launchMeetingLabel": "Kā vēlaties pievienoties šai sapulcei?",
|
||||
"launchWebButton": "Palaist tīmekļa pārlūkā",
|
||||
"noDesktopApp": "Vai jums nav lietotnes?",
|
||||
"noMobileApp": "Vai jums nav lietotnes?",
|
||||
"or": "vai",
|
||||
"termsAndConditions": "Turpinot jūs piekrītat mūsu <a href='{{termsAndConditionsLink}}' rel='noopener noreferrer' target='_blank'>pakalpojumu sniegšanas noteikumiem.</a>",
|
||||
"title": "Notiek jūsu sapulces palaišana lietotnē {{app}}...",
|
||||
"titleNew": "Notiek jūsu sapulces palaišana ...",
|
||||
@@ -837,6 +839,7 @@
|
||||
"headings": {
|
||||
"lobby": "Vestibils ({{count}})",
|
||||
"participantsList": "Sapulces dalībnieki ({{count}})",
|
||||
"visitorRequests": " (pieprasījumi {{count}})",
|
||||
"visitors": "Apmeklētāji ({{count}})",
|
||||
"waitingLobby": "Gaida vestibilā ({{count}})"
|
||||
},
|
||||
@@ -997,7 +1000,6 @@
|
||||
"limitNotificationDescriptionNative": "Lielā pieprasījuma dēļ jūsu ieraksts tiks ierobežots līdz {{limit}} min. Lai iegūtu neierobežotu ierakstu skaitu, izmēģiniet <3>{{app}}</3>.",
|
||||
"limitNotificationDescriptionWeb": "Lielā pieprasījuma dēļ jūsu ieraksts tiks ierobežots līdz {{limit}} min. Lai iegūtu neierobežotu ierakstu skaitu, izmēģiniet <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"linkGenerated": "Mēs esam izveidojuši saiti uz jūsu ierakstu.",
|
||||
"live": "ĒTERĀ",
|
||||
"localRecordingNoNotificationWarning": "Ieraksts netiks izziņots citiem dalībniekiem. Jums būs jāpaziņo viņiem, ka sapulce tiek ierakstīta.",
|
||||
"localRecordingNoVideo": "Video netiek ierakstīts",
|
||||
"localRecordingStartWarning": "Pirms iziešanas no sapulces, lūdzu, apturiet ierakstīšanu, lai to saglabātu.",
|
||||
@@ -1014,14 +1016,16 @@
|
||||
"onBy": "{{name}} ieslēdza ierakstu",
|
||||
"onlyRecordSelf": "Ierakstīt tikai manas audio un video straumes",
|
||||
"pending": "Gatavojas ierakstīt sapulci...",
|
||||
"rec": "Notiek ieraksts",
|
||||
"recordAudioAndVideo": "Ierakstīt audio un video",
|
||||
"recordTranscription": "Ierakstīt transkripciju",
|
||||
"saveLocalRecording": "Ieraksta faila saglabāšana lokāli (beta)",
|
||||
"serviceDescription": "Jūsu ierakstu saglabās attiecīgais pakalpojums",
|
||||
"serviceDescriptionCloud": "Mākoņa ierakstīšana",
|
||||
"serviceDescriptionCloud": "Ierakstīšana mākonī",
|
||||
"serviceDescriptionCloudInfo": "Ierakstītās sapulces tiek automātiski dzēstas 24 stundas pēc to ierakstīšanas laika.",
|
||||
"serviceName": "Ieraksta pakalpojums",
|
||||
"sessionAlreadyActive": "Šī sesija jau tiek ierakstīta vai straumēta tiešraidē.",
|
||||
"signIn": "Ierakstīties",
|
||||
"showAdvancedOptions": "Papildus iespējas",
|
||||
"signIn": "Pierakstīties",
|
||||
"signOut": "Izrakstīties",
|
||||
"surfaceError": "Lūdzu, izvēlieties pašreizējo cilni.",
|
||||
"title": "Ieraksts",
|
||||
@@ -1351,12 +1355,9 @@
|
||||
},
|
||||
"transcribing": {
|
||||
"ccButtonTooltip": "Iesl./izsl. subtitrus",
|
||||
"error": "Transkripcijas kļūme. Lūdzu, mēģiniet vēlāk.",
|
||||
"expandedLabel": "Transkripcija ieslēgta",
|
||||
"expandedLabel": "Transkripcija ir ieslēgta",
|
||||
"failedToStart": "Neizdevās sākt transkripciju",
|
||||
"labelToolTip": "Notiek sapulces transkripcija.",
|
||||
"off": "Transkripcija izslēgta",
|
||||
"pending": "Gatavojas veikt sapulces transkripciju...",
|
||||
"labelToolTip": "Notiek sapulces transkripcija",
|
||||
"sourceLanguageDesc": "Pašlaik sapulces valoda ir iestatīta uz <b>{{sourceLanguage}}</b>. <br/> Varat to mainīt no ",
|
||||
"sourceLanguageHere": "šeit",
|
||||
"start": "Iesl. subtitru rādīšanu",
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"addPeople": {
|
||||
"accessibilityLabel": {
|
||||
"meetingLink": "Lidhje takimi: {{url}}"
|
||||
},
|
||||
"add": "Ftoni",
|
||||
"addContacts": "Ftoni kontaktet tuaja",
|
||||
"contacts": "kontakte",
|
||||
@@ -39,6 +42,18 @@
|
||||
"audioOnly": {
|
||||
"audioOnly": "Gjerësi e ulët bande"
|
||||
},
|
||||
"bandwidthSettings": {
|
||||
"assumedBandwidthBps": "p.sh. 10000000 për 10 Mbps",
|
||||
"assumedBandwidthBpsWarning": "Vlera më të mëdha mund të shkaktojnë probleme rrjeti.",
|
||||
"customValue": "vlerë vetjake",
|
||||
"customValueEffect": "për të ujdisur vlerën e tanishme bps",
|
||||
"leaveEmpty": "lëreni të zbrazët",
|
||||
"leaveEmptyEffect": "për të lejuar kryerje vlerësimesh",
|
||||
"possibleValues": "Vlera të mundshme",
|
||||
"setAssumedBandwidthBps": "Gjerësi bande e supozuar (bps)",
|
||||
"title": "Rregullime gjerësi bande",
|
||||
"zeroEffect": "për të çaktivizuar videon"
|
||||
},
|
||||
"breakoutRooms": {
|
||||
"actions": {
|
||||
"add": "Shtoni aneks konsultimesh",
|
||||
@@ -48,15 +63,22 @@
|
||||
"leaveBreakoutRoom": "Dilni nga aneks konsultimesh",
|
||||
"more": "Më tepër",
|
||||
"remove": "Hiqe",
|
||||
"rename": "Riemërtojeni",
|
||||
"renameBreakoutRoom": "Riemërtoni aneks konsultimesh",
|
||||
"sendToBreakoutRoom": "Dërgoje pjesëmarrësin te:"
|
||||
},
|
||||
"breakoutList": "Listë aneksesh",
|
||||
"buttonLabel": "Dhoma aneks konsultimesh",
|
||||
"defaultName": "Dhomë aneks konsultimesh #{{index}}",
|
||||
"hideParticipantList": "Fshihe listën e pjesëmarrësve",
|
||||
"mainRoom": "Dhoma kryesore",
|
||||
"notifications": {
|
||||
"joined": "Po hyhet te dhomë aneks konsultimesh \"{{name}}\"",
|
||||
"joinedMainRoom": "Po hyhet te dhoma kryesore",
|
||||
"joinedTitle": "Dhoma Aneks Konsultimesh"
|
||||
}
|
||||
},
|
||||
"showParticipantList": "Shfaq listë pjesëmarrësish",
|
||||
"title": "Dhoma Aneks Konsultimesh"
|
||||
},
|
||||
"calendarSync": {
|
||||
"addMeetingURL": "Shtoni një lidhje takimi",
|
||||
@@ -68,9 +90,9 @@
|
||||
},
|
||||
"join": "Merrni pjesë",
|
||||
"joinTooltip": "Merrni pjesë në takim",
|
||||
"nextMeeting": "takimi pasues",
|
||||
"nextMeeting": "Takimi pasues",
|
||||
"noEvents": "S’ka veprimtari të ardhshme të vëna në plan.",
|
||||
"ongoingMeeting": "takim në zhvillim e sipër",
|
||||
"ongoingMeeting": "Takim në zhvillim e sipër",
|
||||
"permissionButton": "Hapni rregullimet",
|
||||
"permissionMessage": "Që të shihni në aplikacion takimet tuaja, janë të domosdoshme lejet mbi Kalendarin.",
|
||||
"refresh": "Rifresko kalendarin",
|
||||
@@ -156,6 +178,7 @@
|
||||
"localport_plural": "Porta vendore:",
|
||||
"maxEnabledResolution": "maksimum dërgimi",
|
||||
"more": "Shfaq më tepër",
|
||||
"no": "jo",
|
||||
"packetloss": "Humbje paketesh:",
|
||||
"participant_id": "ID pjesëmarrësi:",
|
||||
"quality": {
|
||||
@@ -174,7 +197,8 @@
|
||||
"status": "Lidhje:",
|
||||
"transport": "Transport:",
|
||||
"transport_plural": "Transporte:",
|
||||
"video_ssrc": "SSRC Videoje:"
|
||||
"video_ssrc": "Video SSRC:",
|
||||
"yes": "po"
|
||||
},
|
||||
"dateUtils": {
|
||||
"earlier": "Më herët",
|
||||
@@ -195,7 +219,9 @@
|
||||
"joinInBrowser": "Hyni që nga shfletues",
|
||||
"launchMeetingLabel": "Si doni të hyhet në këtë takim?",
|
||||
"launchWebButton": "Nise në web",
|
||||
"noDesktopApp": "S’e keni aplikacionin?",
|
||||
"noMobileApp": "S’e keni aplikacionin?",
|
||||
"or": "OR",
|
||||
"termsAndConditions": "Duke vazhduar, pajtoheni me <a href='{{termsAndConditionsLink}}' rel='noopener noreferrer' target='_blank'>terms & conditions.</a> tona",
|
||||
"title": "Po niset takimi juaj në {{app}}…",
|
||||
"titleNew": "Po niset takimi juaj…",
|
||||
@@ -220,7 +246,7 @@
|
||||
"noPermission": "S’u akordua leje",
|
||||
"previewUnavailable": "S’bëhet dot paraparje",
|
||||
"selectADevice": "Përzgjidhni një pajisje",
|
||||
"testAudio": "Luaj një tingull, për provë"
|
||||
"testAudio": "Testojeni"
|
||||
},
|
||||
"dialIn": {
|
||||
"screenTitle": "Përmbledhje rënieje numrash"
|
||||
@@ -231,21 +257,28 @@
|
||||
"dialog": {
|
||||
"Back": "Mbrapsht",
|
||||
"Cancel": "Anuloje",
|
||||
"IamHost": "Jam organizatori",
|
||||
"IamHost": "Hyni",
|
||||
"Ok": "OK",
|
||||
"Remove": "Hiqe",
|
||||
"Share": "Ndaje",
|
||||
"Submit": "Parashtroje",
|
||||
"WaitForHostMsg": "Konferenca s’ka nisur ende. Nëse jeni organizatori, ju lutemi, bëni mirëfilltësimin. Përndryshe, ju lutemi, pritni që të mbërrijë organizatori.",
|
||||
"WaitingForHostTitle": "Po pritet për organizatorin…",
|
||||
"WaitForHostMsg": "Konferenca s’ka nisur, ngaqë s’ka mbërritur ende ndonjë moderator. Nëse dëshironi të bëheni një moderator, ju lutemi, bëni hyrjen. Përndryshe, ju lutemi, pritni.",
|
||||
"WaitingForHostButton": "Prit për moderator",
|
||||
"WaitingForHostTitle": "Po pritet për një moderator…",
|
||||
"Yes": "Po",
|
||||
"accessibilityLabel": {
|
||||
"liveStreaming": "Transmetim i Drejtpërdrejtë"
|
||||
"Cancel": "Anuloje (dilni nga dialogu)",
|
||||
"Ok": "OK (ruajeni dhe dilni nga dialogu)",
|
||||
"close": "Mbylle dialogun",
|
||||
"liveStreaming": "Transmetim i Drejtpërdrejtë",
|
||||
"sharingTabs": "Mundësi ndarjeje me të tjerë"
|
||||
},
|
||||
"add": "Shtoni",
|
||||
"addMeetingNote": "Shtoni një shënim rreth këtij takimi",
|
||||
"addOptionalNote": "Shtoni një shënim (në daçi):",
|
||||
"allow": "Lejoje",
|
||||
"allowToggleCameraDialog": "A e lejoni {{initiatorName}} të ndryshojë anën nga sheh kamera juaj?",
|
||||
"allowToggleCameraTitle": "Të lejohet ndryshimi i kamerës?",
|
||||
"alreadySharedVideoMsg": "Një tjetër pjesëmarrës po ndan me të tjerët një video. Kjo konferencë lejon vetëm një ndarje videoje në herë.",
|
||||
"alreadySharedVideoTitle": "Lejohet vetëm një ndarje videoje me të tjerët në herë",
|
||||
"applicationWindow": "Dritare aplikacioni",
|
||||
@@ -306,7 +339,8 @@
|
||||
"lockRoom": "Shtoni takim $t(lockRoomPasswordUppercase)",
|
||||
"lockTitle": "Kyçja dështoi",
|
||||
"login": "Hyrje",
|
||||
"logoutQuestion": "Jeni i sigurt se doni të dilet dhe të ndalet konferenca?",
|
||||
"loginQuestion": "Jeni i sigurt se doni të hyhet dhe të braktiset konferenca?",
|
||||
"logoutQuestion": "Jeni i sigurt se doni të dilet dhe të braktiset konferenca?",
|
||||
"logoutTitle": "Dalje",
|
||||
"maxUsersLimitReached": "U mbërrit në kufi numri maksimum pjesëmarrësish. Konferenca është plot. Ju lutemi, lidhuni me të zotin e takimit, ose provoni më vonë!",
|
||||
"maxUsersLimitReachedTitle": "U mbërrit në kufi numri maksimum pjesëmarrësish",
|
||||
@@ -334,7 +368,7 @@
|
||||
"muteEveryonesVideoTitle": "Të ndalet videoja e gjithkujt?",
|
||||
"muteParticipantBody": "S’do jeni në gjendje të hiqni heshtimin për ta, por ata munden kurdo ta heqin për veten.",
|
||||
"muteParticipantButton": "Heshtoje",
|
||||
"muteParticipantsVideoBody": "S’do të jeni në gjendje të riaktivizoni kamerën e tyre, por ata munden kurdo ta riaktvizojnë për veten.",
|
||||
"muteParticipantsVideoBody": "S’do të jeni në gjendje të riaktivizoni kamerën e tyre, por ata munden kurdo ta riaktivizojnë për veten.",
|
||||
"muteParticipantsVideoBodyModerationOn": "S’do të jeni në gjendje të riaktivizoni kamerën e tyre dhe as ata s’do të munden.",
|
||||
"muteParticipantsVideoButton": "Ndale videon",
|
||||
"muteParticipantsVideoDialog": "Jeni i sigurt se doni të çaktivizoni kamerën e këtij pjesëmarrësi? S’do të jeni në gjendje të riaktivizoni kamerën, por ai mund ta riaktivizojë kurdo.",
|
||||
@@ -349,8 +383,6 @@
|
||||
"permissionCameraRequiredError": "Leja mbi kamerën është e domosdoshme për të marrë pjesë në konferenca me video. Ju lutemi, akordojeni që nga Rregullimet",
|
||||
"permissionErrorTitle": "Leje e domosdoshme",
|
||||
"permissionMicRequiredError": "Leja mbi mikrofonin është e domosdoshme për të marrë pjesë në konferenca me audio. Ju lutemi, akordojeni që nga Rregullimet",
|
||||
"popupError": "Shfletuesi juaj i bllokon dritaret flluskë prej këtij sajti. Ju lutemi, aktivizoni flluskat te rregullimet e sigurisë të shfletuesit tuaj dhe riprovoni.",
|
||||
"popupErrorTitle": "Flluska u bllokua",
|
||||
"readMore": "më tepër",
|
||||
"recentlyUsedObjects": "Së fundi përdorët objekte",
|
||||
"recording": "Regjistrim",
|
||||
@@ -367,6 +399,8 @@
|
||||
"removePassword": "Hiqe $t(lockRoomPassword)",
|
||||
"removeSharedVideoMsg": "Jeni i sigurt se doni të hiqni videon që keni ndarë me të tjerë?",
|
||||
"removeSharedVideoTitle": "Hiqe videon e ndarë me të tjerë",
|
||||
"renameBreakoutRoomLabel": "Emër dhome",
|
||||
"renameBreakoutRoomTitle": "Riemërtoni aneks konsultimesh",
|
||||
"reservationError": "Gabim sistemi rezervimi",
|
||||
"reservationErrorMsg": "Kod gabimi: {{code}}, mesazh: {{msg}}",
|
||||
"retry": "Riprovoni",
|
||||
@@ -386,8 +420,10 @@
|
||||
"sendPrivateMessageTitle": "Të dërgohet privatisht?",
|
||||
"serviceUnavailable": "Shërbim jashtë funksionimi",
|
||||
"sessTerminated": "Thirrja përfundoi",
|
||||
"sessTerminatedReason": "Takimi u përfundua",
|
||||
"sessionRestarted": "Thirrja rinisi për shkak të një problemi lidhjeje.",
|
||||
"shareAudio": "Vazhdo",
|
||||
"shareAudio": "Vazhdoni",
|
||||
"shareAudioAltText": "që të ndani me të tjerë lëndën e dëshiruar, kaloni te \"Skedë Shfletuesi\", përzgjidhni lëndën, aktivizoni shenjën për \"ndani audio me të tjerë\" dhe mandej klikoni butonin \"ndaje me të tjerë\"",
|
||||
"shareAudioTitle": "Si të ndahet audio me të tjerë",
|
||||
"shareAudioWarningD1": "lypset të ndalni tregim ekrani, para se të ndani audion tuaj me të tjerë.",
|
||||
"shareAudioWarningD2": "lypset të rinisni tregimin e ekranit tuaj dhe t’i vini shenjë mundësisë “ndani audio me të tjerë”.",
|
||||
@@ -417,7 +453,25 @@
|
||||
"thankYou": "Faleminderit që përdorni {{appName}}!",
|
||||
"token": "token",
|
||||
"tokenAuthFailed": "Na ndjeni, s’keni leje të merrni pjesë në këtë thirrje.",
|
||||
"tokenAuthFailedReason": {
|
||||
"audInvalid": "Vlerë `aud` e pavlefshme. Duhet të jetë `jitsi`.",
|
||||
"contextNotFound": "Prej ngarkesës mungon objekti `context`.",
|
||||
"expInvalid": "Vlerë `exp` e pavlefshme.",
|
||||
"featureInvalid": "Veçori e pavlefshme: {{feature}}, gjasat janë të mos jetë sendërtuar ende.",
|
||||
"featureValueInvalid": "Vlerë e pavlefshme për veçorinë: {{feature}}.",
|
||||
"featuresNotFound": "Prej ngarkesës mungon objekti `features`.",
|
||||
"headerNotFound": "Mungon krye.",
|
||||
"issInvalid": "Vlerë `iss` e pavlefshme. Duhet të jetë `chat`.",
|
||||
"kidMismatch": "ID kyçi (kid) nuk përputhet me sub.",
|
||||
"kidNotFound": "Mungon ID Kyçi (kid).",
|
||||
"nbfFuture": "Vlera `nbf` gjendet në të ardhmen.",
|
||||
"nbfInvalid": "Vlerë `nbf` e pavlefshme.",
|
||||
"payloadNotFound": "Mungon ngarkesë.",
|
||||
"tokenExpired": "Token-i ka skaduar."
|
||||
},
|
||||
"tokenAuthFailedTitle": "Mirëfilltësimi dështoi",
|
||||
"tokenAuthFailedWithReasons": "Na ndjeni, nuk keni leje të merrni pjesë në këtë thirrje. Arsye e mundshme: {{reason}}",
|
||||
"tokenAuthUnsupported": "Nuk mbulohet URL token-i.",
|
||||
"transcribing": "Transkriptim",
|
||||
"unlockRoom": "Hiq $t(lockRoomPassword) takimi",
|
||||
"user": "Përdorues",
|
||||
@@ -429,8 +483,12 @@
|
||||
"verifyParticipantTitle": "Verifikim përdoruesi",
|
||||
"videoLink": "Lidhje videoje",
|
||||
"viewUpgradeOptions": "Shihni mundësi përmirësimi",
|
||||
"viewUpgradeOptionsContent": "Që të përfitoni përdorim të pakufizuar veçorish me pagesë, të tilla si regjistrimi, transcriptime, RTMP Streaming & etj, duhet të përmirësoni planin tuaj.",
|
||||
"viewUpgradeOptionsContent": "Që të përfitoni përdorim të pakufizuar veçorish me pagesë, të tilla si regjistrimi, transkriptime, RTMP Streaming & etj, duhet të përmirësoni planin tuaj.",
|
||||
"viewUpgradeOptionsTitle": "Zbuluat një veçori me pagesë!",
|
||||
"whiteboardLimitContent": "Na ndjeni, është mbërritur te kufiri i tabelave të njëkohshme.",
|
||||
"whiteboardLimitReference": "Për më tepër hollësi, ju lutemi, vizitoni",
|
||||
"whiteboardLimitReferenceUrl": "sajtin tonë",
|
||||
"whiteboardLimitTitle": "Kufizim përdorimi tabele",
|
||||
"yourEntireScreen": "Krejt ekranin tuaj"
|
||||
},
|
||||
"documentSharing": {
|
||||
@@ -443,6 +501,9 @@
|
||||
"title": "Trupëzojeni këtë takim"
|
||||
},
|
||||
"feedback": {
|
||||
"accessibilityLabel": {
|
||||
"yourChoice": "Zgjedhja juaj: {{rating}}"
|
||||
},
|
||||
"average": "Çka",
|
||||
"bad": "I dobët",
|
||||
"detailsLabel": "Na thoni më tepër rreth tij.",
|
||||
@@ -499,13 +560,16 @@
|
||||
"noNumbers": "S’ka numra për përdorim.",
|
||||
"noPassword": "Asnjë",
|
||||
"noRoom": "S’u dha dhomë për të cilën të formësohet numri.",
|
||||
"noWhiteboard": "S’u ngarkua dot tabela.",
|
||||
"numbers": "Numra Për T’u Përdorur",
|
||||
"password": "$t(lockRoomPasswordUppercase): ",
|
||||
"reachedLimit": "Keni mbërritur në kufijtë e planit tuaj.",
|
||||
"sip": "Adresë SIP",
|
||||
"sipAudioOnly": "Adresë SIP vetëm për audio",
|
||||
"title": "Ndani me të tjerë",
|
||||
"tooltip": "Ndani me të tjerë lidhje dhe hollësi numrash për këtë takim",
|
||||
"upgradeOptions": "Ju lutemi, shihni mundësitë e përmirësimit, te"
|
||||
"upgradeOptions": "Ju lutemi, shihni mundësitë e përmirësimit, te",
|
||||
"whiteboardError": "Gabim në ngarkimin e tabelës. Ju lutemi, riprovoni më vonë."
|
||||
},
|
||||
"inlineDialogFailure": {
|
||||
"msg": "Ngecëm pak.",
|
||||
@@ -607,13 +671,13 @@
|
||||
"knockingParticipantList": "Listë pjesëmarrësish që duan të hyjnë",
|
||||
"lobbyChatStartedNotification": "{{moderator}} filloi një fjalosje në holl me {{attendee}}",
|
||||
"lobbyChatStartedTitle": "{{moderator}} ka filluar një fjalosje në holl me ju.",
|
||||
"lobbyClosed": "Dhoma holl u mbyll.",
|
||||
"nameField": "Jepni emrin tuaj",
|
||||
"notificationLobbyAccessDenied": "Hyrja e {{targetParticipantName}} është hedhur poshtë nga {{originParticipantName}}",
|
||||
"notificationLobbyAccessGranted": "{{targetParticipantName}} është lejuar të hyjë nga {{originParticipantName}}",
|
||||
"notificationLobbyDisabled": "Holli është çaktivizuar nga {{originParticipantName}}",
|
||||
"notificationLobbyEnabled": "Holli është aktivizuar nga {{originParticipantName}}",
|
||||
"notificationTitle": "Holl",
|
||||
"passwordField": "Jepni fjalëkalim takimi",
|
||||
"passwordJoinButton": "Hyni",
|
||||
"title": "Holl",
|
||||
"toggleLabel": "Aktivizoni hollin"
|
||||
@@ -646,6 +710,8 @@
|
||||
"sessionToken": "Token Sesioni",
|
||||
"start": "Nis Regjistrim",
|
||||
"stop": "Ndale Regjistrimin",
|
||||
"stopping": "Po ndalet Regjistrimi",
|
||||
"wait": "Ju lutemi, prisni, teksa ruajmë regjistrimin tuaj",
|
||||
"yes": "Po"
|
||||
},
|
||||
"lockRoomPassword": "fjalëkalim",
|
||||
@@ -667,8 +733,11 @@
|
||||
"connectedTwoMembers": "{{first}} dhe {{second}} tjetër hynë në takim",
|
||||
"dataChannelClosed": "Rënie cilësie videoje",
|
||||
"dataChannelClosedDescription": "Kanali urë u shkëput, kështu që cilësia e videos është kufizuar te vlera më e ulët.",
|
||||
"disabledIframe": "Trupëzimi është menduar vetëm për qëllime demonstrimi, ndaj kjo thirrje do të ndërpritet pas {{timeout}} minutash.",
|
||||
"disabledIframeSecondary": "Trupëzimi i {{domain}} është menduar vetëm për qëllime demonstrimi, ndaj kjo thirrje do të ndërpritet pas {{timeout}} minutash. Ju lutemi, për trupëzime të njëmendta përdorni <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi as a Service</a>!",
|
||||
"disconnected": "u shkëput",
|
||||
"displayNotifications": "Shfaq njoftime për",
|
||||
"dontRemindMe": "Mos ma kujto",
|
||||
"focus": "Fokusi te konferenca",
|
||||
"focusFail": "{{component}} jo i passhëm - riprovoni pas {{ms}} sekondash",
|
||||
"gifsMenu": "GIPHY",
|
||||
@@ -677,6 +746,7 @@
|
||||
"invitedOneMember": "{{name}} u ftua",
|
||||
"invitedThreePlusMembers": "{{name}} dhe {{count}} të tjerë u ftuan",
|
||||
"invitedTwoMembers": "{{first}} dhe {{second}} u ftuan",
|
||||
"joinMeeting": "Hyni",
|
||||
"kickParticipant": "{{kicked}} u përzu nga {{kicker}}",
|
||||
"leftOneMember": "{{name}} doli nga takimi",
|
||||
"leftThreePlusMembers": "{{name}} dhe mjaft të tjerë dolën nga takimi",
|
||||
@@ -711,7 +781,6 @@
|
||||
"newDeviceCameraTitle": "U pikas kamerë e re",
|
||||
"noiseSuppressionDesktopAudioDescription": "Mbytja e zhurmave s’mund të aktivizohet teksa ndahet me të tjerët audioja e desktopit, ju lutemi, çaktivizojeni dhe riprovoni.",
|
||||
"noiseSuppressionFailedTitle": "S’u arrit të nisej mbytja e zhurmave",
|
||||
"noiseSuppressionNoTrackDescription": "Ju lutemi, së pari, çheshtoni mikrofonin tuaj.",
|
||||
"noiseSuppressionStereoDescription": "Aktualisht nuk mbulohet mbytje zhurmash audioje stereo.",
|
||||
"oldElectronClientDescription1": "Duket se përdorni një version të vjetër të klientit Jitsi Meet, i cili ka cenueshmëri të ditura sigurie. Ju lutemi, siguroni përditësimin me ",
|
||||
"oldElectronClientDescription2": "montimin tonë më të ri",
|
||||
@@ -735,13 +804,18 @@
|
||||
"startSilentTitle": "Hytë pa zë në dalje!",
|
||||
"suboptimalBrowserWarning": "Kemi frikë se funksionimi i takimit për ju s’do të jetë kushedi këtu. Po kërkojmë rrugë për ta përmirësuar këtë punë, por deri atëherë, ju lutemi, provoni të përdorni një nga <a href='{{recommendedBrowserPageLink}}' target='_blank'>shfletuesit e mbuluar plotësisht</a>.",
|
||||
"suboptimalExperienceTitle": "Sinjalizim Mbi Shfletuesin",
|
||||
"suggestRecordingAction": "Niseni",
|
||||
"suggestRecordingDescription": "Do të donit të nisej një regjistrim?",
|
||||
"suggestRecordingTitle": "Regjistroje këtë takim",
|
||||
"unmute": "Çheshtoje",
|
||||
"videoMutedRemotelyDescription": "Mundeni përherë ta rihapni.",
|
||||
"videoMutedRemotelyTitle": "Videoja juaj u mbyll nga {{moderator}}",
|
||||
"videoUnmuteBlockedDescription": "Heqja e heshtimit të kamerës dhe veprimi i tregimit të desktopit janë bllokuar përkohësisht për shkak kufizimesh të sistemit.",
|
||||
"videoUnmuteBlockedTitle": "Heqja e heshtimit të kamerës dhe tregimi i desktopit janë bllokuar!",
|
||||
"viewLobby": "Shihni hollin",
|
||||
"waitingParticipants": "{{waitingParticipants}} vetë"
|
||||
"waitingParticipants": "{{waitingParticipants}} vetë",
|
||||
"whiteboardLimitDescription": "Ju lutemi, ruani ç’keni bërë, ngaqë së shpejti do të mbërrihet në kufi përdoruesi dhe tabela do të mbyllet.",
|
||||
"whiteboardLimitTitle": "Përdorim tabele"
|
||||
},
|
||||
"participantsPane": {
|
||||
"actions": {
|
||||
@@ -752,6 +826,7 @@
|
||||
"askUnmute": "Kërkoni heqje heshtimi",
|
||||
"audioModeration": "Heqin heshtim të vetes",
|
||||
"blockEveryoneMicCamera": "Bllokoni mikrofonin dhe kamerën e gjithkujt",
|
||||
"breakoutRooms": "Dhoma anekse konsultimesh",
|
||||
"invite": "Ftoni Dikë",
|
||||
"moreModerationActions": "Më tepër mundësi moderimi",
|
||||
"moreModerationControls": "Më tepër kontrolle moderimi",
|
||||
@@ -769,7 +844,8 @@
|
||||
"headings": {
|
||||
"lobby": "Holli ({{count}})",
|
||||
"participantsList": "Pjesëmarrës në takim ({{count}})",
|
||||
"visitors": "Vizitorë ({{count}})",
|
||||
"visitorRequests": " (requests {{count}})",
|
||||
"visitors": "Vizitorë {{count}}",
|
||||
"waitingLobby": "Duke pritur në holl ({{count}})"
|
||||
},
|
||||
"search": "Kërkoni te pjesëmarrësit",
|
||||
@@ -859,12 +935,15 @@
|
||||
"joinWithoutAudio": "Merrni pjesë pa audio",
|
||||
"keyboardShortcuts": "Aktivizo shkurtore tastiere",
|
||||
"linkCopied": "Lidhja u kopjua në të papastër",
|
||||
"lookGood": "Mikrofoni juaj po punon si duhet",
|
||||
"lookGood": "Gjithçka po punon si duhet",
|
||||
"or": "ose",
|
||||
"premeeting": "Para takimit",
|
||||
"proceedAnyway": "Vazhdo, sido qoftë",
|
||||
"recordingWarning": "Këtë thirrje pjesëmarrës të tjerë mund ta regjistrojnë",
|
||||
"screenSharingError": "Gabim ndarjeje ekrani me të tjerë:",
|
||||
"showScreen": "Aktivizoni skenë para takimit",
|
||||
"startWithPhone": "Nise me audio telefoni",
|
||||
"unsafeRoomConsent": "I kuptoj rreziqet, dëshiroj të marr pjesë te takimi",
|
||||
"videoOnlyError": "Gabim video:",
|
||||
"videoTrackError": "S’u krijua dot pistë video.",
|
||||
"viewAllNumbers": "shihni krejt numrat"
|
||||
@@ -885,9 +964,9 @@
|
||||
},
|
||||
"profile": {
|
||||
"avatar": "avatar",
|
||||
"setDisplayNameLabel": "Caktoni emrin tuaj për në ekran",
|
||||
"setDisplayNameLabel": "Emër",
|
||||
"setEmailInput": "Jepni email",
|
||||
"setEmailLabel": "Caktoni email të gravatarit tuaj",
|
||||
"setEmailLabel": "Jepni email të gravatarit tuaj",
|
||||
"title": "Profil"
|
||||
},
|
||||
"raisedHand": "Do të donte të fliste",
|
||||
@@ -919,17 +998,16 @@
|
||||
"failedToStart": "S’u arrit të niset regjistrimi",
|
||||
"fileSharingdescription": "Ndajeni regjistrimin me pjesëmarrësit në takim",
|
||||
"highlight": "Nxjerrje në pah",
|
||||
"highlightMoment": "Nxirni në pah një çast",
|
||||
"highlightMoment": "Nxirrni në pah një çast",
|
||||
"highlightMomentDisabled": "Mund të nxirrni në pah çaste kur fillon regjistrimi",
|
||||
"highlightMomentSuccess": "Çasti u nxorr në pah",
|
||||
"highlightMomentSuccess": "Çasti u nxor në pah",
|
||||
"highlightMomentSucessDescription": "Çasti i nxjerrë në pah nga ju do të shtohet te përmbledhja e takimit.",
|
||||
"inProgress": "Regjistrim ose transmetim drejtpërsëdrejti në ecuri e sipër",
|
||||
"limitNotificationDescriptionNative": "Për shkak kërkesash të shumta, regjistrimi juaj do të kufizohet në {{limit}} min. Për regjistrime të pakufizuara provoni <3>{{app}}</3>.",
|
||||
"limitNotificationDescriptionWeb": "Për shkak kërkesash të shumta, regjistrimi juaj do të kufizohet në {{limit}} min. Për regjistrime të pakufizuara provoni <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
|
||||
"linkGenerated": "Kemi prodhuar një lidhje për te regjistrimi juaj.",
|
||||
"live": "DREJTPËRSËDREJTI",
|
||||
"localRecordingNoNotificationWarning": "Regjistrimi s’do t’u njoftohet pjesëmarrësve të tjerë. Do t’ju duhet t’i vini në dijeni se takimi po regjistrohet.",
|
||||
"localRecordingNoVideo": "Videoja nuk po regjistrohet",
|
||||
"localRecordingNoVideo": "Videoja s’po regjistrohet",
|
||||
"localRecordingStartWarning": "Ju lutemi, sigurohuni se e ndalni regjistrimin para se dilni nga takimi, që të mund ta ruani.",
|
||||
"localRecordingStartWarningTitle": "Ndaleni regjistrimin që ta ruani",
|
||||
"localRecordingVideoStop": "Ndalja e videos tuaj do të ndalë gjithashtu edhe regjistrimin vendor. Jeni i sigurt se doni të vazhdohet?",
|
||||
@@ -944,13 +1022,15 @@
|
||||
"onBy": "{{name}} nisi regjistrimin",
|
||||
"onlyRecordSelf": "Regjistro vetëm rrjedhat e mia audio dhe video",
|
||||
"pending": "Po përgatitet të regjistrohet takimi…",
|
||||
"rec": "REC",
|
||||
"recordAudioAndVideo": "Regjistro audio dhe video",
|
||||
"recordTranscription": "Regjistro transkriptimin",
|
||||
"saveLocalRecording": "Ruajeni lokalisht kartelën e regjistrimit (Beta)",
|
||||
"serviceDescription": "Regjistrimi juaj do të ruhet nga shërbimi i regjistrimit",
|
||||
"serviceDescriptionCloud": "Regjistrim në re",
|
||||
"serviceDescriptionCloudInfo": "Takimet e regjistruara spastrohen automatikisht 24h pas kohës së regjistrimit të tyre.",
|
||||
"serviceName": "Shërbim regjistrimi",
|
||||
"sessionAlreadyActive": "Ky sesion po regjistrohet ose transmetohet drejtpërsëdrejti tashmë.",
|
||||
"showAdvancedOptions": "Mundësi të mëtejshme",
|
||||
"signIn": "Hyni",
|
||||
"signOut": "Dilni",
|
||||
"surfaceError": "Ju lutemi, përdorni skedën e tanishme.",
|
||||
@@ -966,10 +1046,17 @@
|
||||
"security": {
|
||||
"about": "Takimit tuaj mund t’i shtoni një $t(lockRoomPassword). Pjesëmarrësve do t’u duhet të japin $t(lockRoomPassword) përpara se të lejohen të marrin pjesë në takim.",
|
||||
"aboutReadOnly": "Pjesëmarrësit moderatorë mund t’i shtojnë takimit një $t(lockRoomPassword). Pjesëmarrësve do t’u duhet të japin $t(lockRoomPassword) përpara se të lejohen të marrin pjesë në takim.",
|
||||
"insecureRoomNameWarning": "Emri i dhomës s’është pa rrezik. Pjesëmarrës të padëshiruar munden të marrin pjesë në konferencën tuaj. Shihni mundësinë e bërjes të sigurt të takimit tuaj, duke përdorur butonin e sigurisë.",
|
||||
"title": "Mundësi Sigurie"
|
||||
"insecureRoomNameWarningNative": "Emri i dhomës s’është pa rrezik. Pjesëmarrës të padëshiruar munden të hyjnë në takimin tuaj. {{recommendAction}} Mësoni më tepër rreth sigurimit të takimit tuaj ",
|
||||
"insecureRoomNameWarningWeb": "Emri i dhomës s’është pa rrezik. Pjesëmarrës të padëshiruar munden të hyjnë në takimin tuaj. {{recommendAction}} Mësoni më tepër rreth sigurimit të takimit tuaj <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">këtu</a>.",
|
||||
"title": "Mundësi Sigurie",
|
||||
"unsafeRoomActions": {
|
||||
"meeting": "Shihni mundësinë e sigurimit të takimit tuaj, duke përdorur butonin e sigurisë.",
|
||||
"prejoin": "Shihni mundësinë e përdorimit për takimin të një emri më të veçantë.",
|
||||
"welcome": "Shihni mundësinë e përdorimit për takimin të një emri më të veçantë, ose zgjidhni një nga sugjerimet."
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"audio": "Audio",
|
||||
"buttonLabel": "Rregullime",
|
||||
"calendar": {
|
||||
"about": "Integrimi me kalendar {{appName}} përdoret për të hyrë me sukses te kalendari juaj, që kështu të mund të lexohen veprimtari të ardhshme.",
|
||||
@@ -990,9 +1077,11 @@
|
||||
"maxStageParticipants": "Numër maksimum pjesëmarrësish që mund të fiksohen te skena kryesore (EKSPERIMENTALe)",
|
||||
"microphones": "Mikrofona",
|
||||
"moderator": "Moderator",
|
||||
"more": "Më tepër",
|
||||
"moderatorOptions": "Mundësi moderatori",
|
||||
"more": "Të përgjitshme",
|
||||
"name": "Emër",
|
||||
"noDevice": "Asnjë",
|
||||
"notifications": "Njoftime",
|
||||
"participantJoined": "Hyri Pjesëmarrës",
|
||||
"participantKnocking": "Pjesëmarrës hyri në holl",
|
||||
"participantLeft": "Doli Pjesëmarrës",
|
||||
@@ -1003,13 +1092,14 @@
|
||||
"selectCamera": "Kamerë",
|
||||
"selectMic": "Mikrofon",
|
||||
"selfView": "Parje e vetes",
|
||||
"sounds": "Tinguj",
|
||||
"shortcuts": "Shkurtore",
|
||||
"speakers": "Altoparlantë",
|
||||
"startAudioMuted": "Gjithkush fillon i heshtuar",
|
||||
"startReactionsMuted": "Heshto tinguj reagimesh për këdo",
|
||||
"startVideoMuted": "Gjithkush fillon i fshehur",
|
||||
"talkWhileMuted": "Flisni, teksa jeni i heshtuar",
|
||||
"title": "Rregullime"
|
||||
"title": "Rregullime",
|
||||
"video": "Video"
|
||||
},
|
||||
"settingsView": {
|
||||
"advanced": "Të mëtejshme",
|
||||
@@ -1017,6 +1107,7 @@
|
||||
"alertOk": "OK",
|
||||
"alertTitle": "Kujdes",
|
||||
"alertURLText": "URL-ja e dhënë për shërbyesin është e pavlefshme",
|
||||
"apply": "Aplikoji",
|
||||
"buildInfoSection": "Hollësi Montimi",
|
||||
"conferenceSection": "Konferencë",
|
||||
"disableCallIntegration": "Çaktivizo integrim thirrje me sistemin",
|
||||
@@ -1027,19 +1118,21 @@
|
||||
"displayNamePlaceholderText": "P.sh.: Zamir Gjoli",
|
||||
"email": "Email",
|
||||
"emailPlaceholderText": "email@example.com",
|
||||
"gavatarMessage": "Nëse emal-i juaj është i përshoqëruar me një llogari Gravatar, do ta përdorim për të shfaqur foton e profilit tuaj.",
|
||||
"goTo": "Kalo te",
|
||||
"header": "Rregullime",
|
||||
"help": "Ndihmë",
|
||||
"links": "Lidhje",
|
||||
"privacy": "Privatësi",
|
||||
"profileSection": "Profil",
|
||||
"sdkVersion": "Version SDK",
|
||||
"serverURL": "URL Shërbyesi",
|
||||
"showAdvanced": "Shfaq rregullime të mëtejshme",
|
||||
"startCarModeInLowBandwidthMode": "Nën mënyrën “gjerësi e ulët bande” nis mënyrën automjet",
|
||||
"startWithAudioMuted": "Fillo me audio të mbyllur",
|
||||
"startWithVideoMuted": "Fillo me video të mbyllur",
|
||||
"terms": "Terma",
|
||||
"version": "Version"
|
||||
"version": "Version aplikacioni"
|
||||
},
|
||||
"share": {
|
||||
"dialInfoText": "\n\n=====\n\nThjesht doni t’i bini numrit në telefonin tuaj?\n\n{{defaultDialInNumber}}Klikoni mbi këtë lidhje, që të shihni numra telefoni për këtë takim\n{{dialInfoPageUrl}}",
|
||||
@@ -1050,7 +1143,7 @@
|
||||
"angry": "I zemëruar",
|
||||
"disgusted": "I pështirosur",
|
||||
"displayEmotions": "Shfaq emocione",
|
||||
"fearful": "I firkësuar",
|
||||
"fearful": "I frikësuar",
|
||||
"happy": "I gëzuar",
|
||||
"hours": "{{count}}h",
|
||||
"minutes": "{{count}}m",
|
||||
@@ -1058,7 +1151,7 @@
|
||||
"neutral": "Asnjanës",
|
||||
"sad": "I trishtuar",
|
||||
"search": "Kërko",
|
||||
"searchHint": "Kërkoni pjesëmarrësit",
|
||||
"searchHint": "Kërkoni për pjesëmarrës",
|
||||
"seconds": "{{count}}s",
|
||||
"speakerStats": "Statistika Folësi",
|
||||
"speakerTime": "Kohë Folësi",
|
||||
@@ -1081,7 +1174,7 @@
|
||||
"toolbar": {
|
||||
"Settings": "Rregullime",
|
||||
"accessibilityLabel": {
|
||||
"Settings": "Shfaq/Fshih rregullimet",
|
||||
"Settings": "Hap rregullimet",
|
||||
"audioOnly": "Hap/Mbyll vetëm audion",
|
||||
"audioRoute": "Përzgjidhni pajisje zëri",
|
||||
"boo": "Ya",
|
||||
@@ -1091,11 +1184,20 @@
|
||||
"cc": "Shfaq/Fshih titra",
|
||||
"chat": "Hapni / Mbyllni fjalosje",
|
||||
"clap": "Duartrokitje",
|
||||
"closeChat": "Mbylle fjalosjen",
|
||||
"closeMoreActions": "Mbyll menunë Më Tepër Veprime",
|
||||
"closeParticipantsPane": "Mbyll kuadratin pjesëmarrës",
|
||||
"collapse": "Tkurre",
|
||||
"document": "Shfaq/Fshih dokument të ndarë",
|
||||
"documentClose": "Mbyll dokument të ndarë",
|
||||
"documentOpen": "Hap dokument të ndarë",
|
||||
"download": "Shkarkoni aplikacionet tona",
|
||||
"embedMeeting": "Trupëzoni takimin",
|
||||
"endConference": "Përfundoje takimin për të tërë",
|
||||
"enterFullScreen": "Shiheni sa krejt ekrani",
|
||||
"enterTileView": "Kaloni nën mënyrën me kuadrate",
|
||||
"exitFullScreen": "Dil nga mënyra “Sa krejt ekrani”",
|
||||
"exitTileView": "Dil nga mënyra me kuadrate",
|
||||
"expand": "Zgjeroje",
|
||||
"feedback": "Lini përshtypje",
|
||||
"fullScreen": "Kalo nën/Dil nga mënyra “Sa krejt ekrani”",
|
||||
@@ -1104,6 +1206,7 @@
|
||||
"hangup": "Braktiseni takimin",
|
||||
"heading": "Panel",
|
||||
"help": "Ndihmë",
|
||||
"hideWhiteboard": "Fshihe tabelën",
|
||||
"invite": "Ftoni njerëz",
|
||||
"kick": "Përzëre pjesëmarrësin",
|
||||
"laugh": "E qeshur",
|
||||
@@ -1113,21 +1216,25 @@
|
||||
"lobbyButton": "Aktivizo/Çaktivizoni mënyrën holl",
|
||||
"localRecording": "Shfaq/Fshih kontrolle regjistrimi vendor",
|
||||
"lockRoom": "Aktivizo/Çaktivizo fjalëkalim takimi",
|
||||
"lowerHand": "Ulni dorën",
|
||||
"moreActions": "Më tepër veprime",
|
||||
"moreActionsMenu": "Menu “Më tepër veprime”",
|
||||
"moreOptions": "Shfaq më tepër mundësi",
|
||||
"mute": "Heshtoje / Çheshtoje",
|
||||
"mute": "Heshto mikrofonin",
|
||||
"muteEveryone": "Heshto gjithkënd",
|
||||
"muteEveryoneElse": "Heshto gjithkënd tjetër",
|
||||
"muteEveryoneElsesVideoStream": "Ndal videon e gjithkujt tjetër",
|
||||
"muteEveryonesVideoStream": "Ndal videon e gjithkujt",
|
||||
"muteGUMPending": "Po lidhet mikrofoni juaj",
|
||||
"noiseSuppression": "Mbytje zhurmash",
|
||||
"participants": "Pjesëmarrës",
|
||||
"openChat": "Hapni fjalosje",
|
||||
"participants": "Hapni kuadrat pjesëmarrësish",
|
||||
"pip": "Aktivizo/Çaktivizo mënyrën “Picture-in-Picture”",
|
||||
"privateMessage": "Dërgoni mesazh privat",
|
||||
"profile": "Përpunoni profilin tuaj",
|
||||
"raiseHand": "Ngrini / Ulni dorën tuaj",
|
||||
"reactionsMenu": "Hap / Mbyll menu reagimesh",
|
||||
"raiseHand": "Ngrini dorën",
|
||||
"reactions": "Reagime",
|
||||
"reactionsMenu": "Menu reagimesh",
|
||||
"recording": "Nis/Ndal regjistrimin",
|
||||
"remoteMute": "Heshto pjesëmarrësin",
|
||||
"remoteVideoMute": "Çaktivizo kamerën e pjesëmarrësit",
|
||||
@@ -1135,20 +1242,25 @@
|
||||
"selectBackground": "Përzgjidhni Sfond",
|
||||
"selfView": "Shfaq/Fshih pamje të vetes",
|
||||
"shareRoom": "Ftoni dikë",
|
||||
"shareYourScreen": "Nisni / Ndalni tregimin e ekranit tuaj",
|
||||
"shareYourScreen": "Nisni tregimin e ekranit tuaj",
|
||||
"shareaudio": "Ndani audio me të tjerë",
|
||||
"sharedvideo": "Aktivizo/Çaktivizo ndarje videoje me të tjerë",
|
||||
"sharedvideo": "Ndani video me të tjerë",
|
||||
"shortcuts": "Shfaq/Fshih shkurtore",
|
||||
"show": "Shfaqe në skenë",
|
||||
"showWhiteboard": "Shfaq tabelë",
|
||||
"silence": "Heshtje",
|
||||
"speakerStats": "Shfaq/Fshih statistika folësi",
|
||||
"stopScreenSharing": "Ndalni tregimin e ekranit tuaj",
|
||||
"stopSharedVideo": "Ndalni videon",
|
||||
"surprised": "I befasuar",
|
||||
"tileView": "Kalo në/Dil nga mënyra mozaik",
|
||||
"toggleCamera": "Hap/Mbyll kamerën",
|
||||
"toggleFilmstrip": "Shfaq/Fshih shirit filmi",
|
||||
"unmute": "Hiqni heshtim mikrofoni",
|
||||
"videoblur": "Aktivizo/Çaktivizo turbullim videoje",
|
||||
"videomute": "Nis / Ndal kamerën",
|
||||
"whiteboard": "Shfaq / Fshih tabelën"
|
||||
"videomute": "Ndal kamerën",
|
||||
"videomuteGUMPending": "Po lidhet kamera juaj",
|
||||
"videounmute": "Nis kamerën"
|
||||
},
|
||||
"addPeople": "Shtoni persona te thirrja juaj",
|
||||
"audioOnlyOff": "Çaktivizo mënyrën “Sasi e ulët të dhënash trafiku”",
|
||||
@@ -1161,6 +1273,7 @@
|
||||
"chat": "Hap / Mbyll fjalosje",
|
||||
"clap": "Duartrokitje",
|
||||
"closeChat": "Mbyll fjalosjen",
|
||||
"closeParticipantsPane": "Mbylle kuadratin e pjesëmarrësve",
|
||||
"closeReactionsMenu": "Mbyll menu reagimesh",
|
||||
"disableNoiseSuppression": "Çaktivizo mbytje zhurmash",
|
||||
"disableReactionSounds": "Mund të çaktivizoni tinguj reagimesh për këtë takim",
|
||||
@@ -1169,6 +1282,7 @@
|
||||
"download": "Shkarkoni aplikacione tonat",
|
||||
"e2ee": "Fshehtëzim Skaj-Më-Skaj",
|
||||
"embedMeeting": "Trupëzoni takim",
|
||||
"enableNoiseSuppression": "Aktivizoni mbytje zhurmash",
|
||||
"endConference": "Përfundoje takimin për të tërë",
|
||||
"enterFullScreen": "Shiheni sa krejt ekrani",
|
||||
"enterTileView": "Kalo te pamja me kuadrate",
|
||||
@@ -1193,9 +1307,10 @@
|
||||
"lowerYourHand": "Ulni dorën",
|
||||
"moreActions": "Më tepër veprime",
|
||||
"moreOptions": "Më tepër veprime",
|
||||
"mute": "Heshtoje / Hiqi heshtimin",
|
||||
"mute": "Heshto mikrofonin",
|
||||
"muteEveryone": "Heshto gjithkënd",
|
||||
"muteEveryonesVideo": "Çaktivizo videon e gjithkujt",
|
||||
"muteGUMPending": "Po lidhet mikrofoni juaj",
|
||||
"noAudioSignalDesc": "Nëse s’e keni heshtuar që nga rregullimet e sistemit, ose nga hardware-i, shihni mundësinë e ndërrimit të pajisjes.",
|
||||
"noAudioSignalDescSuggestion": "Nëse s’e keni heshtuar që nga rregullimet e sistemit, ose nga hardware-i, shihni mundësinë e kalimit te pajisja e sugjeruar.",
|
||||
"noAudioSignalDialInDesc": "Mund t’i bini numrit edhe duke përdorur:",
|
||||
@@ -1210,7 +1325,7 @@
|
||||
"pip": "Kalo nën mënyrën “Picture-in-Picture”",
|
||||
"privateMessage": "Dërgo mesazh privat",
|
||||
"profile": "Përpunoni profilin tuaj",
|
||||
"raiseHand": "Ngrini / Ulni dorën",
|
||||
"raiseHand": "Ngrini dorën",
|
||||
"raiseYourHand": "Ngrini dorën",
|
||||
"reactionBoo": "Dërgoni reagim me ya",
|
||||
"reactionClap": "Dërgoni reagim me duartrokitje",
|
||||
@@ -1218,6 +1333,7 @@
|
||||
"reactionLike": "Dërgoni reagim me “thumbs up”",
|
||||
"reactionSilence": "Dërgoni reagim me heshtje",
|
||||
"reactionSurprised": "Dërgoni reagim të befasuari",
|
||||
"reactions": "Reagime",
|
||||
"security": "Mundësi sigurie",
|
||||
"selectBackground": "Përzgjidhni sfond",
|
||||
"shareRoom": "Ftoni dikë",
|
||||
@@ -1237,17 +1353,17 @@
|
||||
"talkWhileMutedPopup": "Po provoni të flisni? Jeni i heshtuar.",
|
||||
"tileViewToggle": "Kalo në/Dil nga mënyra mozaik",
|
||||
"toggleCamera": "Hapni/Mbyllni kamerën",
|
||||
"videoSetting": "Rregullime videoje",
|
||||
"videomute": "Nisni / Ndalni kamerën"
|
||||
"unmute": "Hiqni heshtimin e mikrofonit",
|
||||
"videoSettings": "Rregullime videoje",
|
||||
"videomute": "Ndalni kamerën",
|
||||
"videomuteGUMPending": "Po lidhet kamera juaj",
|
||||
"videounmute": "Nisni kamerën"
|
||||
},
|
||||
"transcribing": {
|
||||
"ccButtonTooltip": "Ndali / Nisi titrat",
|
||||
"error": "Transkriptimi dështoi. Ju lutemi, riprovoni.",
|
||||
"expandedLabel": "Transkriptimi aktualisht është aktiv",
|
||||
"failedToStart": "S’u arrit të nisej transkriptim",
|
||||
"labelToolTip": "Takimit po i bëhet transkriptim",
|
||||
"off": "Transkriptimi u ndal",
|
||||
"pending": "Po përgatitet të transkriptohet takimi…",
|
||||
"sourceLanguageDesc": "Aktualisht si gjuhë takimi është caktuar <b>{{sourceLanguage}}</b>. <br/> Mund ta ndryshoni që nga ",
|
||||
"sourceLanguageHere": "këtu",
|
||||
"start": "Fillo shfaqje titrash",
|
||||
@@ -1284,7 +1400,7 @@
|
||||
"audioOnly": "AUD",
|
||||
"audioOnlyExpanded": "Gjendeni nën mënyrën “gjerësi e ulët bande”. Nën këtë mënyrë, do të merrni vetëm audio dhe tregim ekrani.",
|
||||
"bestPerformance": "Punimi më i mirë",
|
||||
"callQuality": "Cilësi videoje",
|
||||
"callQuality": "Cilësi Videoje (0 për punimin më të mirë, 3 për cilësinë më të lartë)",
|
||||
"hd": "CL",
|
||||
"hdTooltip": "Po shihet video në cilësi të lartë",
|
||||
"highDefinition": "Cilësi e Lartë",
|
||||
@@ -1326,6 +1442,10 @@
|
||||
"videomute": "Pjesëmarrësi ka ndalur kamerën"
|
||||
},
|
||||
"virtualBackground": {
|
||||
"accessibilityLabel": {
|
||||
"currentBackground": "Sfondi i tanishëm: {{background}}",
|
||||
"selectBackground": "Përzgjidhni një sfond"
|
||||
},
|
||||
"addBackground": "Shtoni sfond",
|
||||
"apply": "Zbatoje",
|
||||
"backgroundEffectError": "S’u arrit të zbatohej efekt sfondi.",
|
||||
@@ -1343,13 +1463,20 @@
|
||||
"none": "Asnjë",
|
||||
"pleaseWait": "Ju lutemi, pritni…",
|
||||
"removeBackground": "Hiqe sfondin",
|
||||
"slightBlur": "Turbullim Paksa",
|
||||
"slightBlur": "Gjysmë-Turbullim",
|
||||
"title": "Sfonde virtualë",
|
||||
"uploadedImage": "Ngarkoi figurën {{index}}",
|
||||
"webAssemblyWarning": "Nuk mbulohet WebAssembly",
|
||||
"webAssemblyWarningDescription": "WebAssembly e çaktivizuar ose e pambuluar nga ky shfletues"
|
||||
},
|
||||
"visitorsLabel": "Numër vizitorësh: {{count}}",
|
||||
"visitors": {
|
||||
"chatIndicator": "(vizitor)",
|
||||
"labelTooltip": "Numër vizitorësh: {{count}}",
|
||||
"notification": {
|
||||
"description": "Që të merrni pjesë, ngrini dorën",
|
||||
"title": "Jeni vizitor në takim"
|
||||
}
|
||||
},
|
||||
"volumeSlider": "Rrëshqitës volumi",
|
||||
"welcomepage": {
|
||||
"accessibilityLabel": {
|
||||
@@ -1382,6 +1509,7 @@
|
||||
"microsoftLogo": "Stemë Microsoft-i",
|
||||
"policyLogo": "Stemë Rregullash"
|
||||
},
|
||||
"meetingsAccessibilityLabel": "Takime",
|
||||
"mobileDownLoadLinkAndroid": "Shkarkoni aplikacionin për celular me Android",
|
||||
"mobileDownLoadLinkFDroid": "Shkarkoni aplikacionin për celular me F-Droid",
|
||||
"mobileDownLoadLinkIos": "Shkarkoni aplikacionin për celular me iOS",
|
||||
@@ -1405,6 +1533,7 @@
|
||||
"whiteboard": {
|
||||
"accessibilityLabel": {
|
||||
"heading": "Tabelë shënimesh"
|
||||
}
|
||||
},
|
||||
"screenTitle": "Tabelë shënimesh"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,6 +222,7 @@
|
||||
"Share": "Paylaş",
|
||||
"Submit": "Gönder",
|
||||
"WaitForHostMsg": "Toplantısı henüz başlamadı. Toplantı sahibi sizseniz, lütfen kimlik doğrulaması yapın. Değilseniz lütfen toplantı sahibinin gelmesini bekleyin.",
|
||||
"WaitingForHostButton": "Toplantı sahibini bekle",
|
||||
"WaitingForHostTitle": "Toplantı sahibi bekleniyor ...",
|
||||
"Yes": "Evet",
|
||||
"accessibilityLabel": {
|
||||
|
||||
@@ -219,7 +219,9 @@
|
||||
"joinInBrowser": "Join in browser",
|
||||
"launchMeetingLabel": "How do you want to join this meeting?",
|
||||
"launchWebButton": "Launch in web",
|
||||
"noDesktopApp": "You don’t have the app?",
|
||||
"noMobileApp": "You don’t have the app?",
|
||||
"or": "OR",
|
||||
"termsAndConditions": "By continuing you agree to our <a href='{{termsAndConditionsLink}}' rel='noopener noreferrer' target='_blank'>terms & conditions.</a>",
|
||||
"title": "Launching your meeting in {{app}}...",
|
||||
"titleNew": "Launching your meeting ...",
|
||||
@@ -558,6 +560,7 @@
|
||||
"noNumbers": "No dial-in numbers.",
|
||||
"noPassword": "None",
|
||||
"noRoom": "No room was specified to dial-in into.",
|
||||
"noWhiteboard": "Could not load the whiteboard.",
|
||||
"numbers": "Dial-in Numbers",
|
||||
"password": "$t(lockRoomPasswordUppercase): ",
|
||||
"reachedLimit": "You have reached the limit of your plan.",
|
||||
@@ -565,7 +568,8 @@
|
||||
"sipAudioOnly": "SIP audio only address",
|
||||
"title": "Share",
|
||||
"tooltip": "Share link and dial-in info for this meeting",
|
||||
"upgradeOptions": "Please check the upgrade options on"
|
||||
"upgradeOptions": "Please check the upgrade options on",
|
||||
"whiteboardError": "Error loading the whiteboard. Please try again later."
|
||||
},
|
||||
"inlineDialogFailure": {
|
||||
"msg": "We stumbled a bit.",
|
||||
@@ -615,7 +619,7 @@
|
||||
"errorAPI": "An error occurred while accessing your YouTube broadcasts. Please try logging in again.",
|
||||
"errorLiveStreamNotEnabled": "Live Streaming is not enabled on {{email}}. Please enable live streaming or log into an account with live streaming enabled.",
|
||||
"expandedOff": "The live streaming has stopped",
|
||||
"expandedOn": "The meeting is currently being streamed to YouTube.",
|
||||
"expandedOn": "The meeting is currently being live streamed",
|
||||
"expandedPending": "The live streaming is being started...",
|
||||
"failedToStart": "Live Streaming failed to start",
|
||||
"getStreamKeyManually": "We weren’t able to fetch any live streams. Try getting your live stream key from YouTube.",
|
||||
@@ -800,6 +804,9 @@
|
||||
"startSilentTitle": "You joined with no audio output!",
|
||||
"suboptimalBrowserWarning": "We are afraid your meeting experience isn't going to be that great here. We are looking for ways to improve this, but until then please try using one of the <a href='{{recommendedBrowserPageLink}}' target='_blank'>fully supported browsers</a>.",
|
||||
"suboptimalExperienceTitle": "Browser Warning",
|
||||
"suggestRecordingAction": "Start",
|
||||
"suggestRecordingDescription": "Would you like to start a recording?",
|
||||
"suggestRecordingTitle": "Record this meeting",
|
||||
"unmute": "Unmute",
|
||||
"videoMutedRemotelyDescription": "You can always turn it on again.",
|
||||
"videoMutedRemotelyTitle": "Your video has been turned off by {{participantDisplayName}}",
|
||||
@@ -932,6 +939,7 @@
|
||||
"or": "or",
|
||||
"premeeting": "Pre meeting",
|
||||
"proceedAnyway": "Proceed anyway",
|
||||
"recordingWarning": "Other participants may be recording this call",
|
||||
"screenSharingError": "Screen sharing error:",
|
||||
"showScreen": "Enable pre meeting screen",
|
||||
"startWithPhone": "Start with phone audio",
|
||||
@@ -985,7 +993,7 @@
|
||||
"error": "Recording failed. Please try again.",
|
||||
"errorFetchingLink": "Error fetching recording link.",
|
||||
"expandedOff": "Recording has stopped",
|
||||
"expandedOn": "The meeting is currently being recorded.",
|
||||
"expandedOn": "The meeting is currently being recorded",
|
||||
"expandedPending": "Recording is being started...",
|
||||
"failedToStart": "Recording failed to start",
|
||||
"fileSharingdescription": "Share the recording link with the meeting participants",
|
||||
@@ -1353,13 +1361,9 @@
|
||||
},
|
||||
"transcribing": {
|
||||
"ccButtonTooltip": "Start / Stop subtitles",
|
||||
"error": "Transcribing failed. Please try again.",
|
||||
"expandedLabel": "Transcribing is currently on",
|
||||
"failedToStart": "Transcribing failed to start",
|
||||
"labelToolTip": "The meeting is being transcribed",
|
||||
"off": "Transcribing stopped",
|
||||
"on": "Transcribing started",
|
||||
"pending": "Preparing to transcribe the meeting...",
|
||||
"sourceLanguageDesc": "Currently the meeting language is set to <b>{{sourceLanguage}}</b>. <br/> You can change it from ",
|
||||
"sourceLanguageHere": "here",
|
||||
"start": "Start showing subtitles",
|
||||
@@ -1529,6 +1533,7 @@
|
||||
"whiteboard": {
|
||||
"accessibilityLabel": {
|
||||
"heading": "Whiteboard"
|
||||
}
|
||||
},
|
||||
"screenTitle": "Whiteboard"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ import { isAudioMuteButtonDisabled } from '../../react/features/toolbox/function
|
||||
import { setTileView, toggleTileView } from '../../react/features/video-layout/actions.any';
|
||||
import { muteAllParticipants } from '../../react/features/video-menu/actions';
|
||||
import { setVideoQuality } from '../../react/features/video-quality/actions';
|
||||
import { toggleWhiteboard } from '../../react/features/whiteboard/actions.any';
|
||||
import { toggleWhiteboard } from '../../react/features/whiteboard/actions.web';
|
||||
import { getJitsiMeetTransport } from '../transport';
|
||||
|
||||
import {
|
||||
|
||||
@@ -229,6 +229,9 @@ export default class LargeVideoManager {
|
||||
|
||||
preUpdate.then(() => {
|
||||
const { id, stream, videoType, resolve } = this.newStreamData;
|
||||
|
||||
this.newStreamData = null;
|
||||
|
||||
const state = APP.store.getState();
|
||||
const shouldHideSelfView = getHideSelfView(state);
|
||||
const localId = getLocalParticipant(state)?.id;
|
||||
@@ -239,8 +242,6 @@ export default class LargeVideoManager {
|
||||
// the video container type (Etherpad, SharedVideo, VideoContainer).
|
||||
const isVideoContainer = LargeVideoManager.isVideoContainer(videoType);
|
||||
|
||||
this.newStreamData = null;
|
||||
|
||||
logger.debug(`Scheduled large video update for ${id}`);
|
||||
this.state = videoType;
|
||||
// eslint-disable-next-line no-shadow
|
||||
@@ -287,10 +288,6 @@ export default class LargeVideoManager {
|
||||
|| streamingStatusActive
|
||||
);
|
||||
|
||||
this.videoTrack?.jitsiTrack?.getVideoType() === VIDEO_TYPE.DESKTOP
|
||||
&& logger.debug(`Remote track ${videoTrack?.jitsiTrack}, isVideoMuted=${isVideoMuted},`
|
||||
+ ` streamingStatusActive=${streamingStatusActive}, isVideoRenderable=${isVideoRenderable}`);
|
||||
|
||||
const isAudioOnly = APP.conference.isAudioOnly();
|
||||
|
||||
// Multi-stream is not supported on plan-b endpoints even if its is enabled via config.js. A virtual
|
||||
@@ -303,6 +300,10 @@ export default class LargeVideoManager {
|
||||
= isVideoContainer
|
||||
&& ((isAudioOnly && videoType !== VIDEO_TYPE.DESKTOP) || !isVideoRenderable || legacyScreenshare);
|
||||
|
||||
logger.debug(`scheduleLargeVideoUpdate: Remote track ${videoTrack?.jitsiTrack}, isVideoMuted=${
|
||||
isVideoMuted}, streamingStatusActive=${streamingStatusActive}, isVideoRenderable=${
|
||||
isVideoRenderable}, showAvatar=${showAvatar}`);
|
||||
|
||||
let promise;
|
||||
|
||||
// do not show stream if video is muted
|
||||
|
||||
@@ -26,6 +26,13 @@ const FADE_DURATION_MS = 300;
|
||||
|
||||
const logger = Logger.getLogger(__filename);
|
||||
|
||||
/**
|
||||
* List of container events that we are going to process for the large video.
|
||||
*
|
||||
* NOTE: Currently used only for logging for debug purposes.
|
||||
*/
|
||||
const containerEvents = [ 'abort', 'canplaythrough', 'ended', 'error', 'stalled', 'suspend', 'waiting' ];
|
||||
|
||||
/**
|
||||
* Returns an array of the video dimensions, so that it keeps it's aspect
|
||||
* ratio and fits available area with it's larger dimension. This method
|
||||
@@ -242,11 +249,18 @@ export class VideoContainer extends LargeContainer {
|
||||
this.wrapperParent = document.getElementById('largeVideoElementsContainer');
|
||||
this.avatarHeight = document.getElementById('dominantSpeakerAvatarContainer').getBoundingClientRect().height;
|
||||
this.video.onplaying = function(event) {
|
||||
logger.debug('Large video is playing!');
|
||||
if (typeof resizeContainer === 'function') {
|
||||
resizeContainer(event);
|
||||
}
|
||||
};
|
||||
|
||||
containerEvents.forEach(event => {
|
||||
this.video.addEventListener(event, () => {
|
||||
logger.debug(`${event} handler was called for the large video.`);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* A Set of functions to invoke when the video element resizes.
|
||||
*
|
||||
@@ -255,6 +269,7 @@ export class VideoContainer extends LargeContainer {
|
||||
this._resizeListeners = new Set();
|
||||
|
||||
this.video.onresize = this._onResize.bind(this);
|
||||
this._play = this._play.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -455,6 +470,30 @@ export class VideoContainer extends LargeContainer {
|
||||
this._resizeListeners.delete(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the large video element.
|
||||
*
|
||||
* @param {number} retries - Number of retries to play the large video if play fails.
|
||||
* @returns {void}
|
||||
*/
|
||||
_play(retries = 0) {
|
||||
this.video.play()
|
||||
.then(() => {
|
||||
logger.debug(`Successfully played large video after ${retries + 1} retries!`);
|
||||
})
|
||||
.catch(e => {
|
||||
if (retries < 3) {
|
||||
logger.debug(`Error while trying to playing the large video. Will retry after 1s. Retries: ${
|
||||
retries}. Error: ${e}`);
|
||||
window.setTimeout(() => {
|
||||
this._play(retries + 1);
|
||||
}, 1000);
|
||||
} else {
|
||||
logger.error(`Error while trying to playing the large video after 3 retries: ${e}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update video stream.
|
||||
* @param {string} userID
|
||||
@@ -464,6 +503,8 @@ export class VideoContainer extends LargeContainer {
|
||||
setStream(userID, stream, videoType) {
|
||||
this.userId = userID;
|
||||
if (this.stream === stream && !stream?.forceStreamToReattach) {
|
||||
logger.debug(`SetStream on the large video for user ${userID} ignored: the stream is not changed!`);
|
||||
|
||||
// Handles the use case for the remote participants when the
|
||||
// videoType is received with delay after turning on/off the
|
||||
// desktop sharing.
|
||||
@@ -488,22 +529,28 @@ export class VideoContainer extends LargeContainer {
|
||||
this.videoType = videoType;
|
||||
|
||||
if (!stream) {
|
||||
logger.debug('SetStream on the large video is called without a stream argument!');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.video) {
|
||||
logger.debug(`Attaching a remote track to the large video for user ${userID}`);
|
||||
stream.attach(this.video).catch(error => {
|
||||
logger.error(`Attaching the remote track ${stream} has failed with `, error);
|
||||
logger.error(`Attaching the remote track ${stream} to large video has failed with `, error);
|
||||
});
|
||||
|
||||
// Ensure large video gets play() called on it when a new stream is attached to it. This is necessary in the
|
||||
// case of Safari as autoplay doesn't kick-in automatically on Safari 15 and newer versions.
|
||||
browser.isWebKitBased() && this.video.play();
|
||||
browser.isWebKitBased() && this._play();
|
||||
|
||||
const flipX = stream.isLocal() && this.localFlipX && !this.isScreenSharing();
|
||||
|
||||
this.video.style.transform = flipX ? 'scaleX(-1)' : 'none';
|
||||
this._updateBackground();
|
||||
} else {
|
||||
logger.debug(`SetStream on the large video won't attach a track for ${
|
||||
userID} because no large video element was found!`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -154,6 +154,8 @@ const VideoLayout = {
|
||||
|
||||
updateLargeVideo(id, forceUpdate, forceStreamToReattach = false) {
|
||||
if (!largeVideo) {
|
||||
logger.debug(`Ignoring large video update with user id ${id}: large video not initialized yet!`);
|
||||
|
||||
return;
|
||||
}
|
||||
const currentContainer = largeVideo.getCurrentContainer();
|
||||
|
||||
296
package-lock.json
generated
296
package-lock.json
generated
@@ -42,7 +42,8 @@
|
||||
"@vladmandic/human": "2.6.5",
|
||||
"@vladmandic/human-models": "2.5.9",
|
||||
"@xmldom/xmldom": "0.8.7",
|
||||
"amplitude-js": "8.2.1",
|
||||
"abab": "2.0.6",
|
||||
"amplitude-js": "8.21.9",
|
||||
"base64-js": "1.5.1",
|
||||
"bc-css-flags": "3.0.0",
|
||||
"clipboard-copy": "4.0.1",
|
||||
@@ -60,7 +61,7 @@
|
||||
"js-md5": "0.6.1",
|
||||
"js-sha512": "0.8.0",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1759.0.0+fc2f2490/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1777.0.0+3898d7aa/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -97,7 +98,7 @@
|
||||
"react-native-svg-transformer": "1.1.0",
|
||||
"react-native-tab-view": "3.5.2",
|
||||
"react-native-url-polyfill": "2.0.0",
|
||||
"react-native-video": "6.0.0-alpha.7",
|
||||
"react-native-video": "6.0.0-alpha.11",
|
||||
"react-native-watch-connectivity": "1.1.0",
|
||||
"react-native-webrtc": "118.0.0",
|
||||
"react-native-webview": "13.5.1",
|
||||
@@ -110,6 +111,7 @@
|
||||
"redux-thunk": "2.4.1",
|
||||
"seamless-scroll-polyfill": "2.1.8",
|
||||
"semver": "7.5.4",
|
||||
"text-encoding": "0.7.0",
|
||||
"tss-react": "4.4.4",
|
||||
"util": "0.12.1",
|
||||
"uuid": "8.3.2",
|
||||
@@ -125,7 +127,7 @@
|
||||
"@babel/preset-env": "7.21.5",
|
||||
"@babel/preset-react": "7.16.0",
|
||||
"@jitsi/eslint-config": "4.1.5",
|
||||
"@types/amplitude-js": "8.16.2",
|
||||
"@types/amplitude-js": "8.16.5",
|
||||
"@types/audioworklet": "0.0.29",
|
||||
"@types/dom-screen-wake-lock": "1.0.1",
|
||||
"@types/js-md5": "0.4.3",
|
||||
@@ -236,6 +238,11 @@
|
||||
"extraneous": true,
|
||||
"devDependencies": {}
|
||||
},
|
||||
"node_modules/@amplitude/analytics-connector": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/analytics-connector/-/analytics-connector-1.5.0.tgz",
|
||||
"integrity": "sha512-T8mOYzB9RRxckzhL0NTHwdge9xuFxXEOplC8B1Y3UX3NHa3BLh7DlBUZlCOwQgMc2nxDfnSweDL5S3bhC+W90g=="
|
||||
},
|
||||
"node_modules/@amplitude/react-native": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/react-native/-/react-native-2.7.0.tgz",
|
||||
@@ -246,38 +253,43 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@amplitude/types": {
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/types/-/types-1.9.2.tgz",
|
||||
"integrity": "sha512-s+Q/O8kNfocZiyGvVdtM5T4JGPwLRZ4Q26wtEF5xJhyCtJglGMe0ixe6u/6iW9s4JHIq+LlPlUu5095pVsdtNA==",
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/types/-/types-1.10.2.tgz",
|
||||
"integrity": "sha512-I8qenRI7uU6wKNb9LiZrAosSHVoNHziXouKY81CrqxH9xhVTEIJFXeuCV0hbtBr0Al/8ejnGjQRx+S2SvU/pPg==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@amplitude/ua-parser-js": {
|
||||
"version": "0.7.24",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/ua-parser-js/-/ua-parser-js-0.7.24.tgz",
|
||||
"integrity": "sha512-VbQuJymJ20WEw0HtI2np7EdC3NJGUWi8+Xdbc7uk8WfMIF308T0howpzkQ3JFMN7ejnrcSM/OyNGveeE3TP3TA==",
|
||||
"version": "0.7.33",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/ua-parser-js/-/ua-parser-js-0.7.33.tgz",
|
||||
"integrity": "sha512-wKEtVR4vXuPT9cVEIJkYWnlF++Gx3BdLatPBM+SZ1ztVIvnhdGBZR/mn9x/PzyrMcRlZmyi6L56I2J3doVBnjA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/ua-parser-js"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/faisalman"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@amplitude/utils": {
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/utils/-/utils-1.9.2.tgz",
|
||||
"integrity": "sha512-hGOIoIjmZ0pq/3b2gBrr17TaEarlR+qzFGu5npm76+scd/51F0eNvjd0vgV6WbJT1cxhyH/5Z8kihGWOU3vS3Q==",
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/utils/-/utils-1.10.2.tgz",
|
||||
"integrity": "sha512-tVsHXu61jITEtRjB7NugQ5cVDd4QDzne8T3ifmZye7TiJeUfVRvqe44gDtf55A+7VqhDhyEIIXTA1iVcDGqlEw==",
|
||||
"dependencies": {
|
||||
"@amplitude/types": "^1.9.2",
|
||||
"tslib": "^1.9.3"
|
||||
"@amplitude/types": "^1.10.2",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@amplitude/utils/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
|
||||
@@ -5574,11 +5586,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native/normalize-color": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.1.0.tgz",
|
||||
"integrity": "sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA=="
|
||||
},
|
||||
"node_modules/@react-native/normalize-colors": {
|
||||
"version": "0.72.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.72.0.tgz",
|
||||
@@ -6502,9 +6509,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/amplitude-js": {
|
||||
"version": "8.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/amplitude-js/-/amplitude-js-8.16.2.tgz",
|
||||
"integrity": "sha512-a+tb/CEQOlrHRvEvAuYNOcoUy1POERANnAhfKgiTmsy0eACj3eukGP0ucA9t115QOPzVUhbnUfZqtyHp99IZyA==",
|
||||
"version": "8.16.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/amplitude-js/-/amplitude-js-8.16.5.tgz",
|
||||
"integrity": "sha512-W73JfDpwDH4VijOGo+nVuQOqUCiqyEGGVdajU4ziWTLn27cn+QtFuFuBdlhCraIIrO52fDRO4NSOGkawtn77Jw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/audioworklet": {
|
||||
@@ -7521,7 +7528,8 @@
|
||||
"node_modules/abab": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
|
||||
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA=="
|
||||
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
|
||||
"deprecated": "Use your platform's native atob() and btoa() methods instead"
|
||||
},
|
||||
"node_modules/abort-controller": {
|
||||
"version": "3.0.0",
|
||||
@@ -7660,36 +7668,62 @@
|
||||
}
|
||||
},
|
||||
"node_modules/amplitude-js": {
|
||||
"version": "8.2.1",
|
||||
"resolved": "https://registry.npmjs.org/amplitude-js/-/amplitude-js-8.2.1.tgz",
|
||||
"integrity": "sha512-jp8lm/koTNRceO16RCTlQg9+gUbxip1esod+d0oApBCJYpxuABec2bLHXv/OkVYICvnUWoiz17AZLxiaX/aK4Q==",
|
||||
"deprecated": "Excessive logging into console at default levels",
|
||||
"version": "8.21.9",
|
||||
"resolved": "https://registry.npmjs.org/amplitude-js/-/amplitude-js-8.21.9.tgz",
|
||||
"integrity": "sha512-d0jJH00wbXu7sxKtVwkdSXtVffjqdUrxuACKlnzP7jU5qt9wriXXMgHifdH5Oq+buKmyF8wKL9S02gAykysURA==",
|
||||
"dependencies": {
|
||||
"@amplitude/ua-parser-js": "0.7.24",
|
||||
"@amplitude/utils": "^1.0.5",
|
||||
"blueimp-md5": "^2.10.0",
|
||||
"query-string": "5"
|
||||
"@amplitude/analytics-connector": "^1.4.6",
|
||||
"@amplitude/ua-parser-js": "0.7.33",
|
||||
"@amplitude/utils": "^1.10.2",
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"blueimp-md5": "^2.19.0",
|
||||
"query-string": "8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/amplitude-js/node_modules/decode-uri-component": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.4.1.tgz",
|
||||
"integrity": "sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==",
|
||||
"engines": {
|
||||
"node": ">=14.16"
|
||||
}
|
||||
},
|
||||
"node_modules/amplitude-js/node_modules/filter-obj": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-5.1.0.tgz",
|
||||
"integrity": "sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==",
|
||||
"engines": {
|
||||
"node": ">=14.16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/amplitude-js/node_modules/query-string": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
|
||||
"integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==",
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-8.1.0.tgz",
|
||||
"integrity": "sha512-BFQeWxJOZxZGix7y+SByG3F36dA0AbTy9o6pSmKFcFz7DAj0re9Frkty3saBn3nHo3D0oZJ/+rx3r8H8r8Jbpw==",
|
||||
"dependencies": {
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
"decode-uri-component": "^0.4.1",
|
||||
"filter-obj": "^5.1.0",
|
||||
"split-on-first": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
"node": ">=14.16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/amplitude-js/node_modules/strict-uri-encode": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
|
||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
|
||||
"node_modules/amplitude-js/node_modules/split-on-first": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-3.0.0.tgz",
|
||||
"integrity": "sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/anser": {
|
||||
@@ -9335,16 +9369,6 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/deprecated-react-native-prop-types": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz",
|
||||
"integrity": "sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA==",
|
||||
"dependencies": {
|
||||
"@react-native/normalize-color": "*",
|
||||
"invariant": "*",
|
||||
"prop-types": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/destroy": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
|
||||
@@ -12872,11 +12896,6 @@
|
||||
"rollup": ">= 1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/keymirror": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/keymirror/-/keymirror-0.1.1.tgz",
|
||||
"integrity": "sha512-vIkZAFWoDijgQT/Nvl2AHCMmnegN2ehgTPYuyy2hWQkQSntI0S7ESYqdLkoSe1HyEBFHHkCgSIvVdSEiWwKvCg=="
|
||||
},
|
||||
"node_modules/kind-of": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||
@@ -12924,8 +12943,8 @@
|
||||
},
|
||||
"node_modules/lib-jitsi-meet": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1759.0.0+fc2f2490/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-YCFcx5SxyFDJXc0zeTIvF8jxlwgqgFlEq8UFCa2c68gpEwOE5iSOVn9tQT9jXXk9FAJhN9aUr5e2ar34sUYl3w==",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1777.0.0+3898d7aa/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-qs18nB89iQgiNR/UWTg/GCuEqUAIBdJRyFv9r0EaDThkQS8vHLNzYO9UQId8xZxiOGOR2kunJO84SbcivOTqbw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@@ -16953,13 +16972,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-video": {
|
||||
"version": "6.0.0-alpha.7",
|
||||
"resolved": "https://registry.npmjs.org/react-native-video/-/react-native-video-6.0.0-alpha.7.tgz",
|
||||
"integrity": "sha512-X/siSaJf0V//IbnozjDm1jAjNaXlFy6Hbr6X8GNFl/ztLvN+Z8R/Quq9Q8o22XVwlPacPQ9VS/G0Stdktn0FEw==",
|
||||
"dependencies": {
|
||||
"deprecated-react-native-prop-types": "^2.2.0",
|
||||
"keymirror": "^0.1.1",
|
||||
"prop-types": "^15.7.2"
|
||||
"version": "6.0.0-alpha.11",
|
||||
"resolved": "https://registry.npmjs.org/react-native-video/-/react-native-video-6.0.0-alpha.11.tgz",
|
||||
"integrity": "sha512-Z1FqIkNBqQWdBVKoh5WlmM01LIVhxlOsddKVV9IzMJ3EDl8PAU4ln7hdo85RHCHhgWSHzathPDo0UK7gPB48MA==",
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-watch-connectivity": {
|
||||
@@ -18646,6 +18664,12 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/text-encoding": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.7.0.tgz",
|
||||
"integrity": "sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==",
|
||||
"deprecated": "no longer maintained"
|
||||
},
|
||||
"node_modules/text-table": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||
@@ -20154,35 +20178,33 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@amplitude/analytics-connector": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/analytics-connector/-/analytics-connector-1.5.0.tgz",
|
||||
"integrity": "sha512-T8mOYzB9RRxckzhL0NTHwdge9xuFxXEOplC8B1Y3UX3NHa3BLh7DlBUZlCOwQgMc2nxDfnSweDL5S3bhC+W90g=="
|
||||
},
|
||||
"@amplitude/react-native": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/react-native/-/react-native-2.7.0.tgz",
|
||||
"integrity": "sha512-2dMxCVgRPwReHRDm9JKbL+sZGyozJlcdr5Jokv8TQR7idNxxGmm4YSYkjhGjSWkoEyGEyy+lh9kRJQL/DcUWJQ=="
|
||||
},
|
||||
"@amplitude/types": {
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/types/-/types-1.9.2.tgz",
|
||||
"integrity": "sha512-s+Q/O8kNfocZiyGvVdtM5T4JGPwLRZ4Q26wtEF5xJhyCtJglGMe0ixe6u/6iW9s4JHIq+LlPlUu5095pVsdtNA=="
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/types/-/types-1.10.2.tgz",
|
||||
"integrity": "sha512-I8qenRI7uU6wKNb9LiZrAosSHVoNHziXouKY81CrqxH9xhVTEIJFXeuCV0hbtBr0Al/8ejnGjQRx+S2SvU/pPg=="
|
||||
},
|
||||
"@amplitude/ua-parser-js": {
|
||||
"version": "0.7.24",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/ua-parser-js/-/ua-parser-js-0.7.24.tgz",
|
||||
"integrity": "sha512-VbQuJymJ20WEw0HtI2np7EdC3NJGUWi8+Xdbc7uk8WfMIF308T0howpzkQ3JFMN7ejnrcSM/OyNGveeE3TP3TA=="
|
||||
"version": "0.7.33",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/ua-parser-js/-/ua-parser-js-0.7.33.tgz",
|
||||
"integrity": "sha512-wKEtVR4vXuPT9cVEIJkYWnlF++Gx3BdLatPBM+SZ1ztVIvnhdGBZR/mn9x/PzyrMcRlZmyi6L56I2J3doVBnjA=="
|
||||
},
|
||||
"@amplitude/utils": {
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/utils/-/utils-1.9.2.tgz",
|
||||
"integrity": "sha512-hGOIoIjmZ0pq/3b2gBrr17TaEarlR+qzFGu5npm76+scd/51F0eNvjd0vgV6WbJT1cxhyH/5Z8kihGWOU3vS3Q==",
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/utils/-/utils-1.10.2.tgz",
|
||||
"integrity": "sha512-tVsHXu61jITEtRjB7NugQ5cVDd4QDzne8T3ifmZye7TiJeUfVRvqe44gDtf55A+7VqhDhyEIIXTA1iVcDGqlEw==",
|
||||
"requires": {
|
||||
"@amplitude/types": "^1.9.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
"@amplitude/types": "^1.10.2",
|
||||
"tslib": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@ampproject/remapping": {
|
||||
@@ -23970,11 +23992,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@react-native/normalize-color": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.1.0.tgz",
|
||||
"integrity": "sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA=="
|
||||
},
|
||||
"@react-native/normalize-colors": {
|
||||
"version": "0.72.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.72.0.tgz",
|
||||
@@ -24628,9 +24645,9 @@
|
||||
"integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA=="
|
||||
},
|
||||
"@types/amplitude-js": {
|
||||
"version": "8.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/amplitude-js/-/amplitude-js-8.16.2.tgz",
|
||||
"integrity": "sha512-a+tb/CEQOlrHRvEvAuYNOcoUy1POERANnAhfKgiTmsy0eACj3eukGP0ucA9t115QOPzVUhbnUfZqtyHp99IZyA==",
|
||||
"version": "8.16.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/amplitude-js/-/amplitude-js-8.16.5.tgz",
|
||||
"integrity": "sha512-W73JfDpwDH4VijOGo+nVuQOqUCiqyEGGVdajU4ziWTLn27cn+QtFuFuBdlhCraIIrO52fDRO4NSOGkawtn77Jw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/audioworklet": {
|
||||
@@ -25577,30 +25594,42 @@
|
||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="
|
||||
},
|
||||
"amplitude-js": {
|
||||
"version": "8.2.1",
|
||||
"resolved": "https://registry.npmjs.org/amplitude-js/-/amplitude-js-8.2.1.tgz",
|
||||
"integrity": "sha512-jp8lm/koTNRceO16RCTlQg9+gUbxip1esod+d0oApBCJYpxuABec2bLHXv/OkVYICvnUWoiz17AZLxiaX/aK4Q==",
|
||||
"version": "8.21.9",
|
||||
"resolved": "https://registry.npmjs.org/amplitude-js/-/amplitude-js-8.21.9.tgz",
|
||||
"integrity": "sha512-d0jJH00wbXu7sxKtVwkdSXtVffjqdUrxuACKlnzP7jU5qt9wriXXMgHifdH5Oq+buKmyF8wKL9S02gAykysURA==",
|
||||
"requires": {
|
||||
"@amplitude/ua-parser-js": "0.7.24",
|
||||
"@amplitude/utils": "^1.0.5",
|
||||
"blueimp-md5": "^2.10.0",
|
||||
"query-string": "5"
|
||||
"@amplitude/analytics-connector": "^1.4.6",
|
||||
"@amplitude/ua-parser-js": "0.7.33",
|
||||
"@amplitude/utils": "^1.10.2",
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"blueimp-md5": "^2.19.0",
|
||||
"query-string": "8.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"decode-uri-component": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.4.1.tgz",
|
||||
"integrity": "sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ=="
|
||||
},
|
||||
"filter-obj": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-5.1.0.tgz",
|
||||
"integrity": "sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng=="
|
||||
},
|
||||
"query-string": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
|
||||
"integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==",
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-8.1.0.tgz",
|
||||
"integrity": "sha512-BFQeWxJOZxZGix7y+SByG3F36dA0AbTy9o6pSmKFcFz7DAj0re9Frkty3saBn3nHo3D0oZJ/+rx3r8H8r8Jbpw==",
|
||||
"requires": {
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
"decode-uri-component": "^0.4.1",
|
||||
"filter-obj": "^5.1.0",
|
||||
"split-on-first": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"strict-uri-encode": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
|
||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
|
||||
"split-on-first": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-3.0.0.tgz",
|
||||
"integrity": "sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -26841,16 +26870,6 @@
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
|
||||
},
|
||||
"deprecated-react-native-prop-types": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz",
|
||||
"integrity": "sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA==",
|
||||
"requires": {
|
||||
"@react-native/normalize-color": "*",
|
||||
"invariant": "*",
|
||||
"prop-types": "*"
|
||||
}
|
||||
},
|
||||
"destroy": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
|
||||
@@ -29474,11 +29493,6 @@
|
||||
"debounce": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"keymirror": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/keymirror/-/keymirror-0.1.1.tgz",
|
||||
"integrity": "sha512-vIkZAFWoDijgQT/Nvl2AHCMmnegN2ehgTPYuyy2hWQkQSntI0S7ESYqdLkoSe1HyEBFHHkCgSIvVdSEiWwKvCg=="
|
||||
},
|
||||
"kind-of": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||
@@ -29513,8 +29527,8 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1759.0.0+fc2f2490/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-YCFcx5SxyFDJXc0zeTIvF8jxlwgqgFlEq8UFCa2c68gpEwOE5iSOVn9tQT9jXXk9FAJhN9aUr5e2ar34sUYl3w==",
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1777.0.0+3898d7aa/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-qs18nB89iQgiNR/UWTg/GCuEqUAIBdJRyFv9r0EaDThkQS8vHLNzYO9UQId8xZxiOGOR2kunJO84SbcivOTqbw==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "2.2.1",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
@@ -32442,14 +32456,9 @@
|
||||
}
|
||||
},
|
||||
"react-native-video": {
|
||||
"version": "6.0.0-alpha.7",
|
||||
"resolved": "https://registry.npmjs.org/react-native-video/-/react-native-video-6.0.0-alpha.7.tgz",
|
||||
"integrity": "sha512-X/siSaJf0V//IbnozjDm1jAjNaXlFy6Hbr6X8GNFl/ztLvN+Z8R/Quq9Q8o22XVwlPacPQ9VS/G0Stdktn0FEw==",
|
||||
"requires": {
|
||||
"deprecated-react-native-prop-types": "^2.2.0",
|
||||
"keymirror": "^0.1.1",
|
||||
"prop-types": "^15.7.2"
|
||||
}
|
||||
"version": "6.0.0-alpha.11",
|
||||
"resolved": "https://registry.npmjs.org/react-native-video/-/react-native-video-6.0.0-alpha.11.tgz",
|
||||
"integrity": "sha512-Z1FqIkNBqQWdBVKoh5WlmM01LIVhxlOsddKVV9IzMJ3EDl8PAU4ln7hdo85RHCHhgWSHzathPDo0UK7gPB48MA=="
|
||||
},
|
||||
"react-native-watch-connectivity": {
|
||||
"version": "1.1.0",
|
||||
@@ -33675,6 +33684,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"text-encoding": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.7.0.tgz",
|
||||
"integrity": "sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA=="
|
||||
},
|
||||
"text-table": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||
|
||||
10
package.json
10
package.json
@@ -48,7 +48,8 @@
|
||||
"@vladmandic/human": "2.6.5",
|
||||
"@vladmandic/human-models": "2.5.9",
|
||||
"@xmldom/xmldom": "0.8.7",
|
||||
"amplitude-js": "8.2.1",
|
||||
"abab": "2.0.6",
|
||||
"amplitude-js": "8.21.9",
|
||||
"base64-js": "1.5.1",
|
||||
"bc-css-flags": "3.0.0",
|
||||
"clipboard-copy": "4.0.1",
|
||||
@@ -66,7 +67,7 @@
|
||||
"js-md5": "0.6.1",
|
||||
"js-sha512": "0.8.0",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1759.0.0+fc2f2490/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1777.0.0+3898d7aa/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -103,7 +104,7 @@
|
||||
"react-native-svg-transformer": "1.1.0",
|
||||
"react-native-tab-view": "3.5.2",
|
||||
"react-native-url-polyfill": "2.0.0",
|
||||
"react-native-video": "6.0.0-alpha.7",
|
||||
"react-native-video": "6.0.0-alpha.11",
|
||||
"react-native-watch-connectivity": "1.1.0",
|
||||
"react-native-webrtc": "118.0.0",
|
||||
"react-native-webview": "13.5.1",
|
||||
@@ -116,6 +117,7 @@
|
||||
"redux-thunk": "2.4.1",
|
||||
"seamless-scroll-polyfill": "2.1.8",
|
||||
"semver": "7.5.4",
|
||||
"text-encoding": "0.7.0",
|
||||
"tss-react": "4.4.4",
|
||||
"util": "0.12.1",
|
||||
"uuid": "8.3.2",
|
||||
@@ -131,7 +133,7 @@
|
||||
"@babel/preset-env": "7.21.5",
|
||||
"@babel/preset-react": "7.16.0",
|
||||
"@jitsi/eslint-config": "4.1.5",
|
||||
"@types/amplitude-js": "8.16.2",
|
||||
"@types/amplitude-js": "8.16.5",
|
||||
"@types/audioworklet": "0.0.29",
|
||||
"@types/dom-screen-wake-lock": "1.0.1",
|
||||
"@types/js-md5": "0.4.3",
|
||||
|
||||
@@ -328,6 +328,22 @@ export function createNetworkInfoEvent({ isOnline, networkType, details }:
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a "not allowed error" event.
|
||||
*
|
||||
* @param {string} reason - The reason for the error.
|
||||
* @returns {Object} The event in a format suitable for sending via
|
||||
* sendAnalytics.
|
||||
*/
|
||||
export function createNotAllowedErrorEvent(reason: string) {
|
||||
return {
|
||||
action: 'not.allowed.error',
|
||||
attributes: {
|
||||
reason
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an "offer/answer failure" event.
|
||||
*
|
||||
|
||||
@@ -35,6 +35,12 @@ export default class AmplitudeHandler extends AbstractHandler {
|
||||
this._enabled = false;
|
||||
};
|
||||
|
||||
// Forces sending all events on exit (flushing) via sendBeacon
|
||||
const onExitPage = () => {
|
||||
// @ts-ignore
|
||||
amplitude.getInstance().sendEvents();
|
||||
};
|
||||
|
||||
if (navigator.product === 'ReactNative') {
|
||||
amplitude.getInstance().init(amplitudeAPPKey);
|
||||
fixDeviceID(amplitude.getInstance()).then(() => {
|
||||
@@ -50,7 +56,8 @@ export default class AmplitudeHandler extends AbstractHandler {
|
||||
includeReferrer: true,
|
||||
includeUtm,
|
||||
saveParamsReferrerOncePerSession: false,
|
||||
onError
|
||||
onError,
|
||||
onExitPage
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
|
||||
@@ -51,5 +51,6 @@ import '../video-layout/middleware';
|
||||
import '../video-quality/middleware';
|
||||
import '../videosipgw/middleware';
|
||||
import '../visitors/middleware';
|
||||
import '../whiteboard/middleware.any';
|
||||
|
||||
import './middleware';
|
||||
|
||||
@@ -13,5 +13,6 @@ import '../mobile/react-native-sdk/middleware';
|
||||
import '../mobile/watchos/middleware';
|
||||
import '../share-room/middleware';
|
||||
import '../shared-video/middleware';
|
||||
import '../whiteboard/middleware.native';
|
||||
|
||||
import './middlewares.any';
|
||||
|
||||
@@ -22,6 +22,6 @@ import '../talk-while-muted/middleware';
|
||||
import '../toolbox/middleware';
|
||||
import '../face-landmarks/middleware';
|
||||
import '../gifs/middleware';
|
||||
import '../whiteboard/middleware';
|
||||
import '../whiteboard/middleware.web';
|
||||
|
||||
import './middlewares.any';
|
||||
|
||||
@@ -55,3 +55,4 @@ import '../video-layout/reducer';
|
||||
import '../video-quality/reducer';
|
||||
import '../videosipgw/reducer';
|
||||
import '../visitors/reducer';
|
||||
import '../whiteboard/reducer';
|
||||
|
||||
@@ -16,7 +16,6 @@ import '../noise-suppression/reducer';
|
||||
import '../screenshot-capture/reducer';
|
||||
import '../talk-while-muted/reducer';
|
||||
import '../virtual-background/reducer';
|
||||
import '../whiteboard/reducer';
|
||||
import '../web-hid/reducer';
|
||||
|
||||
import './reducers.any';
|
||||
|
||||
@@ -178,6 +178,18 @@ export const DATA_CHANNEL_OPENED = 'DATA_CHANNEL_OPENED';
|
||||
*/
|
||||
export const DATA_CHANNEL_CLOSED = 'DATA_CHANNEL_CLOSED';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which indicates that an endpoint message
|
||||
* sent by another participant to the data channel is received.
|
||||
*
|
||||
* {
|
||||
* type: ENDPOINT_MESSAGE_RECEIVED,
|
||||
* participant: Object,
|
||||
* data: Object
|
||||
* }
|
||||
*/
|
||||
export const ENDPOINT_MESSAGE_RECEIVED = 'ENDPOINT_MESSAGE_RECEIVED';
|
||||
|
||||
/**
|
||||
* The type of action which signals that the user has been kicked out from
|
||||
* the conference.
|
||||
@@ -333,3 +345,13 @@ export const SET_START_MUTED_POLICY = 'SET_START_MUTED_POLICY';
|
||||
* }
|
||||
*/
|
||||
export const SET_ASSUMED_BANDWIDTH_BPS = 'SET_ASSUMED_BANDWIDTH_BPS';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which updated the conference metadata.
|
||||
*
|
||||
* {
|
||||
* type: UPDATE_CONFERENCE_METADATA,
|
||||
* metadata: Object
|
||||
* }
|
||||
*/
|
||||
export const UPDATE_CONFERENCE_METADATA = 'UPDATE_CONFERENCE_METADATA';
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { createStartMutedConfigurationEvent } from '../../analytics/AnalyticsEvents';
|
||||
import { sendAnalytics } from '../../analytics/functions';
|
||||
import { IReduxState, IStore } from '../../app/types';
|
||||
import { endpointMessageReceived } from '../../subtitles/actions.any';
|
||||
import { setIAmVisitor } from '../../visitors/actions';
|
||||
import { iAmVisitor } from '../../visitors/functions';
|
||||
import { overwriteConfig } from '../config/actions';
|
||||
@@ -48,6 +47,7 @@ import {
|
||||
DATA_CHANNEL_CLOSED,
|
||||
DATA_CHANNEL_OPENED,
|
||||
E2E_RTT_CHANGED,
|
||||
ENDPOINT_MESSAGE_RECEIVED,
|
||||
KICKED_OUT,
|
||||
LOCK_STATE_CHANGED,
|
||||
NON_PARTICIPANT_MESSAGE_RECEIVED,
|
||||
@@ -61,7 +61,8 @@ import {
|
||||
SET_PENDING_SUBJECT_CHANGE,
|
||||
SET_ROOM,
|
||||
SET_START_MUTED_POLICY,
|
||||
SET_START_REACTIONS_MUTED
|
||||
SET_START_REACTIONS_MUTED,
|
||||
UPDATE_CONFERENCE_METADATA
|
||||
} from './actionTypes';
|
||||
import {
|
||||
AVATAR_URL_COMMAND,
|
||||
@@ -79,7 +80,7 @@ import {
|
||||
sendLocalParticipant
|
||||
} from './functions';
|
||||
import logger from './logger';
|
||||
import { IJitsiConference } from './reducer';
|
||||
import { IConferenceMetadata, IJitsiConference } from './reducer';
|
||||
|
||||
/**
|
||||
* Adds conference (event) listeners.
|
||||
@@ -275,6 +276,21 @@ function _addConferenceListeners(conference: IJitsiConference, dispatch: IStore[
|
||||
})));
|
||||
}
|
||||
|
||||
/**
|
||||
* Action for updating the conference metadata.
|
||||
*
|
||||
* @param {IConferenceMetadata} metadata - The metadata object.
|
||||
* @returns {{
|
||||
* type: UPDATE_CONFERENCE_METADATA,
|
||||
* metadata: IConferenceMetadata
|
||||
* }}
|
||||
*/
|
||||
export function updateConferenceMetadata(metadata: IConferenceMetadata | null) {
|
||||
return {
|
||||
type: UPDATE_CONFERENCE_METADATA,
|
||||
metadata
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an action for when the end-to-end RTT against a specific remote participant has changed.
|
||||
@@ -630,6 +646,25 @@ export function dataChannelClosed(code: number, reason: string) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that a participant sent an endpoint message on the data channel.
|
||||
*
|
||||
* @param {Object} participant - The participant details sending the message.
|
||||
* @param {Object} data - The data carried by the endpoint message.
|
||||
* @returns {{
|
||||
* type: ENDPOINT_MESSAGE_RECEIVED,
|
||||
* participant: Object,
|
||||
* data: Object
|
||||
* }}
|
||||
*/
|
||||
export function endpointMessageReceived(participant: Object, data: Object) {
|
||||
return {
|
||||
type: ENDPOINT_MESSAGE_RECEIVED,
|
||||
participant,
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to end a conference for all participants.
|
||||
*
|
||||
|
||||
@@ -6,6 +6,7 @@ import { MIN_ASSUMED_BANDWIDTH_BPS } from '../../../../modules/API/constants';
|
||||
import {
|
||||
ACTION_PINNED,
|
||||
ACTION_UNPINNED,
|
||||
createNotAllowedErrorEvent,
|
||||
createOfferAnswerFailedEvent,
|
||||
createPinnedEvent
|
||||
} from '../../analytics/AnalyticsEvents';
|
||||
@@ -25,7 +26,7 @@ import { overwriteConfig } from '../config/actions';
|
||||
import { CONNECTION_ESTABLISHED, CONNECTION_FAILED } from '../connection/actionTypes';
|
||||
import { connect, connectionDisconnected, disconnect } from '../connection/actions';
|
||||
import { validateJwt } from '../jwt/functions';
|
||||
import { JitsiConferenceErrors, JitsiConnectionErrors } from '../lib-jitsi-meet';
|
||||
import { JitsiConferenceErrors, JitsiConferenceEvents, JitsiConnectionErrors } from '../lib-jitsi-meet';
|
||||
import { PARTICIPANT_UPDATED, PIN_PARTICIPANT } from '../participants/actionTypes';
|
||||
import { PARTICIPANT_ROLE } from '../participants/constants';
|
||||
import {
|
||||
@@ -34,6 +35,7 @@ import {
|
||||
getPinnedParticipant
|
||||
} from '../participants/functions';
|
||||
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
import StateListenerRegistry from '../redux/StateListenerRegistry';
|
||||
import { TRACK_ADDED, TRACK_REMOVED } from '../tracks/actionTypes';
|
||||
import { getLocalTracks } from '../tracks/functions.any';
|
||||
|
||||
@@ -54,7 +56,8 @@ import {
|
||||
conferenceWillLeave,
|
||||
createConference,
|
||||
setLocalSubject,
|
||||
setSubject
|
||||
setSubject,
|
||||
updateConferenceMetadata
|
||||
} from './actions';
|
||||
import { CONFERENCE_LEAVE_REASONS } from './constants';
|
||||
import {
|
||||
@@ -65,6 +68,7 @@ import {
|
||||
restoreConferenceOptions
|
||||
} from './functions';
|
||||
import logger from './logger';
|
||||
import { IConferenceMetadata } from './reducer';
|
||||
|
||||
/**
|
||||
* Handler for before unload event.
|
||||
@@ -124,6 +128,24 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
return next(action);
|
||||
});
|
||||
|
||||
/**
|
||||
* Set up state change listener to perform maintenance tasks when the conference
|
||||
* is left or failed.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
state => getCurrentConference(state),
|
||||
(conference, { dispatch }, previousConference): void => {
|
||||
if (conference && !previousConference) {
|
||||
conference.on(JitsiConferenceEvents.METADATA_UPDATED, (metadata: IConferenceMetadata) => {
|
||||
dispatch(updateConferenceMetadata(metadata));
|
||||
});
|
||||
}
|
||||
|
||||
if (conference !== previousConference) {
|
||||
dispatch(updateConferenceMetadata(null));
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Makes sure to leave a failed conference in order to release any allocated
|
||||
* resources like peer connections, emit participant left events, etc.
|
||||
@@ -197,6 +219,12 @@ function _conferenceFailed({ dispatch, getState }: IStore, next: Function, actio
|
||||
|
||||
break;
|
||||
}
|
||||
case JitsiConferenceErrors.NOT_ALLOWED_ERROR: {
|
||||
const [ msg ] = error.params;
|
||||
|
||||
sendAnalytics(createNotAllowedErrorEvent(msg));
|
||||
break;
|
||||
}
|
||||
case JitsiConferenceErrors.OFFER_ANSWER_FAILED:
|
||||
sendAnalytics(createOfferAnswerFailedEvent());
|
||||
break;
|
||||
|
||||
@@ -27,7 +27,8 @@ import {
|
||||
SET_PENDING_SUBJECT_CHANGE,
|
||||
SET_ROOM,
|
||||
SET_START_MUTED_POLICY,
|
||||
SET_START_REACTIONS_MUTED
|
||||
SET_START_REACTIONS_MUTED,
|
||||
UPDATE_CONFERENCE_METADATA
|
||||
} from './actionTypes';
|
||||
import { isRoomValid } from './functions';
|
||||
|
||||
@@ -39,10 +40,23 @@ const DEFAULT_STATE = {
|
||||
leaving: undefined,
|
||||
locked: undefined,
|
||||
membersOnly: undefined,
|
||||
metadata: undefined,
|
||||
password: undefined,
|
||||
passwordRequired: undefined
|
||||
};
|
||||
|
||||
export interface IConferenceMetadata {
|
||||
recording?: {
|
||||
isTranscribingEnabled: boolean;
|
||||
};
|
||||
whiteboard?: {
|
||||
collabDetails: {
|
||||
roomId: string;
|
||||
roomKey: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface IJitsiConference {
|
||||
addCommandListener: Function;
|
||||
addLobbyMessageListener: Function;
|
||||
@@ -141,6 +155,7 @@ export interface IConferenceState {
|
||||
localSubject?: string;
|
||||
locked?: string;
|
||||
membersOnly?: IJitsiConference;
|
||||
metadata?: IConferenceMetadata;
|
||||
obfuscatedRoom?: string;
|
||||
obfuscatedRoomSource?: string;
|
||||
p2p?: Object;
|
||||
@@ -247,6 +262,12 @@ ReducerRegistry.register<IConferenceState>('features/base/conference',
|
||||
startAudioMutedPolicy: action.startAudioMutedPolicy,
|
||||
startVideoMutedPolicy: action.startVideoMutedPolicy
|
||||
};
|
||||
|
||||
case UPDATE_CONFERENCE_METADATA:
|
||||
return {
|
||||
...state,
|
||||
metadata: action.metadata
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
|
||||
@@ -131,19 +131,30 @@ export interface IMobileDynamicLink {
|
||||
|
||||
export interface IDeeplinkingPlatformConfig {
|
||||
appName: string;
|
||||
appScheme: string;
|
||||
}
|
||||
|
||||
export interface IDeeplinkingMobileConfig extends IDeeplinkingPlatformConfig {
|
||||
appPackage?: string;
|
||||
appScheme: string;
|
||||
downloadLink: string;
|
||||
dynamicLink?: IMobileDynamicLink;
|
||||
fDroidUrl?: string;
|
||||
}
|
||||
|
||||
export interface IDesktopDownloadConfig {
|
||||
linux?: string;
|
||||
macos?: string;
|
||||
windows?: string;
|
||||
}
|
||||
|
||||
export interface IDeeplinkingDesktopConfig extends IDeeplinkingPlatformConfig {
|
||||
download?: IDesktopDownloadConfig;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface IDeeplinkingConfig {
|
||||
android?: IDeeplinkingMobileConfig;
|
||||
desktop?: IDeeplinkingPlatformConfig;
|
||||
desktop?: IDeeplinkingDesktopConfig;
|
||||
disabled?: boolean;
|
||||
hideLogo?: boolean;
|
||||
ios?: IDeeplinkingMobileConfig;
|
||||
@@ -519,6 +530,10 @@ export interface IConfig {
|
||||
sharingEnabled?: boolean;
|
||||
};
|
||||
recordingSharingUrl?: string;
|
||||
recordings?: {
|
||||
showPrejoinWarning?: boolean;
|
||||
suggestRecording?: boolean;
|
||||
};
|
||||
remoteVideoMenu?: {
|
||||
disableGrantModerator?: boolean;
|
||||
disableKick?: boolean;
|
||||
@@ -559,6 +574,7 @@ export interface IConfig {
|
||||
testing?: {
|
||||
assumeBandwidth?: boolean;
|
||||
disableE2EE?: boolean;
|
||||
dumpTranscript?: boolean;
|
||||
mobileXmppWsThreshold?: number;
|
||||
noAutoPlayVideo?: boolean;
|
||||
p2pTestMode?: boolean;
|
||||
@@ -583,7 +599,6 @@ export interface IConfig {
|
||||
transcribingEnabled?: boolean;
|
||||
transcription?: {
|
||||
autoTranscribeOnRecord?: boolean;
|
||||
disableStartForAll?: boolean;
|
||||
enabled?: boolean;
|
||||
preferredLanguage?: string;
|
||||
translationLanguages?: Array<string>;
|
||||
|
||||
@@ -201,6 +201,7 @@ export default [
|
||||
'remoteVideoMenu',
|
||||
'roomPasswordNumberOfDigits',
|
||||
'readOnlyName',
|
||||
'recordings',
|
||||
'replaceParticipant',
|
||||
'resolution',
|
||||
'salesforceUrl',
|
||||
|
||||
@@ -5,8 +5,8 @@ import { NOTIFY_CLICK_MODE } from '../../toolbox/constants';
|
||||
import {
|
||||
IConfig,
|
||||
IDeeplinkingConfig,
|
||||
IDeeplinkingDesktopConfig,
|
||||
IDeeplinkingMobileConfig,
|
||||
IDeeplinkingPlatformConfig,
|
||||
NotifyClickButton,
|
||||
ToolbarButton
|
||||
} from './configType';
|
||||
@@ -94,13 +94,21 @@ export function areAudioLevelsEnabled(state: IReduxState): boolean {
|
||||
* @returns {void}
|
||||
*/
|
||||
export function _setDeeplinkingDefaults(deeplinking: IDeeplinkingConfig) {
|
||||
const {
|
||||
desktop = {} as IDeeplinkingPlatformConfig,
|
||||
android = {} as IDeeplinkingMobileConfig,
|
||||
ios = {} as IDeeplinkingMobileConfig
|
||||
} = deeplinking;
|
||||
deeplinking.desktop = deeplinking.desktop || {} as IDeeplinkingDesktopConfig;
|
||||
deeplinking.android = deeplinking.android || {} as IDeeplinkingMobileConfig;
|
||||
deeplinking.ios = deeplinking.ios || {} as IDeeplinkingMobileConfig;
|
||||
|
||||
const { android, desktop, ios } = deeplinking;
|
||||
|
||||
desktop.appName = desktop.appName || 'Jitsi Meet';
|
||||
desktop.appScheme = desktop.appScheme || 'jitsi-meet';
|
||||
desktop.download = desktop.download || {};
|
||||
desktop.download.windows = desktop.download.windows
|
||||
|| 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet.exe';
|
||||
desktop.download.macos = desktop.download.macos
|
||||
|| 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet.dmg';
|
||||
desktop.download.linux = desktop.download.linux
|
||||
|| 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet-x86_64.AppImage';
|
||||
|
||||
ios.appName = ios.appName || 'Jitsi Meet';
|
||||
ios.appScheme = ios.appScheme || 'org.jitsi.meet';
|
||||
|
||||
@@ -14,8 +14,8 @@ import {
|
||||
import {
|
||||
IConfig,
|
||||
IDeeplinkingConfig,
|
||||
IDeeplinkingDesktopConfig,
|
||||
IDeeplinkingMobileConfig,
|
||||
IDeeplinkingPlatformConfig,
|
||||
IMobileDynamicLink,
|
||||
ToolbarButton
|
||||
} from './configType';
|
||||
@@ -295,7 +295,7 @@ function _translateInterfaceConfig(oldValue: IConfig) {
|
||||
} else {
|
||||
const disabled = Boolean(oldValue.disableDeepLinking);
|
||||
const deeplinking: IDeeplinkingConfig = {
|
||||
desktop: {} as IDeeplinkingPlatformConfig,
|
||||
desktop: {} as IDeeplinkingDesktopConfig,
|
||||
hideLogo: false,
|
||||
disabled,
|
||||
android: {} as IDeeplinkingMobileConfig,
|
||||
|
||||
@@ -90,6 +90,12 @@ export const HELP_BUTTON_ENABLED = 'help.enabled';
|
||||
*/
|
||||
export const INVITE_ENABLED = 'invite.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if dial-in invite functionality should be enabled.
|
||||
* Default: enabled (true).
|
||||
*/
|
||||
export const INVITE_DIAL_IN_ENABLED = 'invite-dial-in.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if recording should be enabled in iOS.
|
||||
* Default: disabled (false).
|
||||
|
||||
@@ -683,7 +683,7 @@ function _participantJoinedOrUpdated(store: IStore, next: Function, action: AnyA
|
||||
|
||||
// Only run this if the config is populated, otherwise we preload external resources
|
||||
// even if disableThirdPartyRequests is set to true in config
|
||||
if (Object.keys(getState()['features/base/config']).length) {
|
||||
if (getState()['features/base/config']?.hosts) {
|
||||
const { disableThirdPartyRequests } = getState()['features/base/config'];
|
||||
|
||||
if (!disableThirdPartyRequests && (avatarURL || email || id || name)) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import { IReduxState } from '../../../../app/types';
|
||||
import DeviceStatus from '../../../../prejoin/components/web/preview/DeviceStatus';
|
||||
import { isRoomNameEnabled } from '../../../../prejoin/functions';
|
||||
import Toolbox from '../../../../toolbox/components/web/Toolbox';
|
||||
import { getConferenceName } from '../../../conference/functions';
|
||||
import { PREMEETING_BUTTONS, THIRD_PARTY_PREJOIN_BUTTONS } from '../../../config/constants';
|
||||
@@ -13,6 +14,7 @@ import { withPixelLineHeight } from '../../../styles/functions.web';
|
||||
|
||||
import ConnectionStatus from './ConnectionStatus';
|
||||
import Preview from './Preview';
|
||||
import RecordingWarning from './RecordingWarning';
|
||||
import UnsafeRoomWarning from './UnsafeRoomWarning';
|
||||
|
||||
interface IProps {
|
||||
@@ -57,6 +59,11 @@ interface IProps {
|
||||
*/
|
||||
showDeviceStatus: boolean;
|
||||
|
||||
/**
|
||||
* Indicates whether to display the recording warning.
|
||||
*/
|
||||
showRecordingWarning?: boolean;
|
||||
|
||||
/**
|
||||
* If should show unsafe room warning when joining.
|
||||
*/
|
||||
@@ -167,6 +174,7 @@ const PreMeetingScreen = ({
|
||||
children,
|
||||
className,
|
||||
showDeviceStatus,
|
||||
showRecordingWarning,
|
||||
showUnsafeRoomWarning,
|
||||
skipPrejoinButton,
|
||||
title,
|
||||
@@ -200,6 +208,7 @@ const PreMeetingScreen = ({
|
||||
{skipPrejoinButton}
|
||||
{showUnsafeRoomWarning && <UnsafeRoomWarning />}
|
||||
{showDeviceStatus && <DeviceStatus />}
|
||||
{showRecordingWarning && <RecordingWarning />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -219,7 +228,7 @@ const PreMeetingScreen = ({
|
||||
* @returns {Object}
|
||||
*/
|
||||
function mapStateToProps(state: IReduxState, ownProps: Partial<IProps>) {
|
||||
const { hiddenPremeetingButtons, hideConferenceSubject } = state['features/base/config'];
|
||||
const { hiddenPremeetingButtons } = state['features/base/config'];
|
||||
const toolbarButtons = getToolbarButtons(state);
|
||||
const premeetingButtons = (ownProps.thirdParty
|
||||
? THIRD_PARTY_PREJOIN_BUTTONS
|
||||
@@ -237,7 +246,7 @@ function mapStateToProps(state: IReduxState, ownProps: Partial<IProps>) {
|
||||
? premeetingButtons
|
||||
: premeetingButtons.filter(b => isToolbarButtonEnabled(b, toolbarButtons)),
|
||||
_premeetingBackground: premeetingBackground,
|
||||
_roomName: (hideConferenceSubject ? undefined : getConferenceName(state)) ?? ''
|
||||
_roomName: isRoomNameEnabled(state) ? getConferenceName(state) : ''
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import { withPixelLineHeight } from '../../../styles/functions.web';
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
warning: {
|
||||
bottom: 0,
|
||||
color: theme.palette.text03,
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
...withPixelLineHeight(theme.typography.bodyShortRegular),
|
||||
marginBottom: theme.spacing(3),
|
||||
marginTop: theme.spacing(2),
|
||||
paddingLeft: theme.spacing(3),
|
||||
paddingRight: theme.spacing(3),
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
|
||||
'@media (max-width: 720px)': {
|
||||
position: 'relative'
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const RecordingWarning = () => {
|
||||
const { t } = useTranslation();
|
||||
const { classes } = useStyles();
|
||||
|
||||
return (
|
||||
<div className = { classes.warning }>
|
||||
{t('prejoin.recordingWarning')}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RecordingWarning;
|
||||
@@ -10,6 +10,8 @@ if (userAgent.match(/Android/i)) {
|
||||
OS = 'macos';
|
||||
} else if (userAgent.match(/Windows/i)) {
|
||||
OS = 'windows';
|
||||
} else if (userAgent.match(/Linux/i)) {
|
||||
OS = 'linux';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { NativeModules, Platform } from 'react-native';
|
||||
|
||||
import { IReduxState, IStore } from '../../app/types';
|
||||
import { setPictureInPictureEnabled } from '../../mobile/picture-in-picture/functions';
|
||||
import { showNotification } from '../../notifications/actions';
|
||||
@@ -12,6 +14,8 @@ import { VIDEO_MUTISM_AUTHORITY } from '../media/constants';
|
||||
import { addLocalTrack, replaceLocalTrack } from './actions.any';
|
||||
import { getLocalDesktopTrack, getTrackState, isLocalVideoTrackDesktop } from './functions.native';
|
||||
|
||||
const { JitsiMeetMediaProjectionModule } = NativeModules;
|
||||
|
||||
export * from './actions.any';
|
||||
|
||||
/**
|
||||
@@ -29,7 +33,10 @@ export function toggleScreensharing(enabled: boolean, _ignore1?: boolean, _ignor
|
||||
if (enabled) {
|
||||
const isSharing = isLocalVideoTrackDesktop(state);
|
||||
|
||||
if (!isSharing) {
|
||||
if (isSharing) {
|
||||
Platform.OS === 'android' && JitsiMeetMediaProjectionModule.abort();
|
||||
} else {
|
||||
Platform.OS === 'android' && JitsiMeetMediaProjectionModule.launch();
|
||||
_startScreenSharing(dispatch, state);
|
||||
}
|
||||
} else {
|
||||
@@ -77,7 +84,7 @@ async function _startScreenSharing(dispatch: IStore['dispatch'], state: IReduxSt
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('ERROR creating ScreeSharing stream ', error);
|
||||
console.log('ERROR creating screen-sharing stream ', error);
|
||||
|
||||
setPictureInPictureEnabled(true);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import base64js from 'base64-js';
|
||||
|
||||
import { timeoutPromise } from './timeoutPromise';
|
||||
|
||||
/**
|
||||
@@ -43,3 +45,37 @@ export function doGetJSON(url: string, retry?: boolean, options?: Object) {
|
||||
|
||||
return fetchPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes strings to Base64URL.
|
||||
*
|
||||
* @param {any} data - The byte array to encode.
|
||||
* @returns {string}
|
||||
*/
|
||||
export const encodeToBase64URL = (data: string): string => base64js
|
||||
.fromByteArray(new window.TextEncoder().encode(data))
|
||||
.replace(/=/g, '')
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_');
|
||||
|
||||
/**
|
||||
* Decodes strings from Base64URL.
|
||||
*
|
||||
* @param {string} data - The byte array to decode.
|
||||
* @returns {string}
|
||||
*/
|
||||
export const decodeFromBase64URL = (data: string): string => {
|
||||
let s = data;
|
||||
|
||||
// Convert from Base64URL to Base64.
|
||||
if (s.length % 4 === 2) {
|
||||
s += '==';
|
||||
} else if (s.length % 4 === 3) {
|
||||
s += '=';
|
||||
}
|
||||
|
||||
s = s.replace(/-/g, '+').replace(/_/g, '/');
|
||||
|
||||
// Convert Base64 to a byte array.
|
||||
return new window.TextDecoder().decode(base64js.toByteArray(s));
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import { getFeatureFlag } from '../../../base/flags/functions';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import { IconChatUnread, IconMessage } from '../../../base/icons/svg';
|
||||
import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
|
||||
import { arePollsDisabled } from '../../../conference/functions.any';
|
||||
import { navigate } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
import { screen } from '../../../mobile/navigation/routes';
|
||||
import { getUnreadPollCount } from '../../../polls/functions';
|
||||
@@ -65,11 +66,10 @@ class ChatButton extends AbstractButton<IProps> {
|
||||
*/
|
||||
function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const enabled = getFeatureFlag(state, CHAT_ENABLED, true);
|
||||
const { disablePolls } = state['features/base/config'];
|
||||
const { visible = enabled } = ownProps;
|
||||
|
||||
return {
|
||||
_isPollsDisabled: disablePolls,
|
||||
_isPollsDisabled: arePollsDisabled(state),
|
||||
|
||||
// The toggled icon should also be available for new polls
|
||||
_unreadMessageCount: getUnreadCount(state) || getUnreadPollCount(state),
|
||||
|
||||
@@ -8,6 +8,7 @@ import { IconMessage, IconReply } from '../../../base/icons/svg';
|
||||
import { getParticipantById } from '../../../base/participants/functions';
|
||||
import { IParticipant } from '../../../base/participants/types';
|
||||
import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
|
||||
import { arePollsDisabled } from '../../../conference/functions.any';
|
||||
import { navigate } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
import { screen } from '../../../mobile/navigation/routes';
|
||||
import { handleLobbyChatInitialized, openChat } from '../../actions.native';
|
||||
@@ -96,11 +97,10 @@ class PrivateMessageButton extends AbstractButton<IProps, any> {
|
||||
*/
|
||||
export function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const enabled = getFeatureFlag(state, CHAT_ENABLED, true);
|
||||
const { disablePolls } = state['features/base/config'];
|
||||
const { visible = enabled, isLobbyMessage, participantID } = ownProps;
|
||||
|
||||
return {
|
||||
_isPollsDisabled: disablePolls,
|
||||
_isPollsDisabled: arePollsDisabled(state),
|
||||
_participant: getParticipantById(state, participantID),
|
||||
_isLobbyMessage: isLobbyMessage,
|
||||
visible
|
||||
|
||||
@@ -7,6 +7,7 @@ import { translate } from '../../../base/i18n/functions';
|
||||
import { getLocalParticipant } from '../../../base/participants/functions';
|
||||
import { withPixelLineHeight } from '../../../base/styles/functions.web';
|
||||
import Tabs from '../../../base/ui/components/web/Tabs';
|
||||
import { arePollsDisabled } from '../../../conference/functions.any';
|
||||
import PollsPane from '../../../polls/components/web/PollsPane';
|
||||
import { sendMessage, setIsPollsTabFocused, toggleChat } from '../../actions.web';
|
||||
import { CHAT_SIZE, CHAT_TABS, SMALL_WIDTH_THRESHOLD } from '../../constants';
|
||||
@@ -316,12 +317,11 @@ function _mapStateToProps(state: IReduxState, _ownProps: any) {
|
||||
const { isOpen, isPollsTabFocused, messages, nbUnreadMessages } = state['features/chat'];
|
||||
const { nbUnreadPolls } = state['features/polls'];
|
||||
const _localParticipant = getLocalParticipant(state);
|
||||
const { disablePolls } = state['features/base/config'];
|
||||
|
||||
return {
|
||||
_isModal: window.innerWidth <= SMALL_WIDTH_THRESHOLD,
|
||||
_isOpen: isOpen,
|
||||
_isPollsEnabled: !disablePolls,
|
||||
_isPollsEnabled: !arePollsDisabled(state),
|
||||
_isPollsTabFocused: isPollsTabFocused,
|
||||
_messages: messages,
|
||||
_nbUnreadMessages: nbUnreadMessages,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { AnyAction } from 'redux';
|
||||
|
||||
import { IReduxState, IStore } from '../app/types';
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes';
|
||||
import { CONFERENCE_JOINED } from '../base/conference/actionTypes';
|
||||
import { CONFERENCE_JOINED, ENDPOINT_MESSAGE_RECEIVED } from '../base/conference/actionTypes';
|
||||
import { getCurrentConference } from '../base/conference/functions';
|
||||
import { IJitsiConference } from '../base/conference/reducer';
|
||||
import { openDialog } from '../base/dialog/actions';
|
||||
@@ -29,7 +29,6 @@ import { ADD_REACTION_MESSAGE } from '../reactions/actionTypes';
|
||||
import { pushReactions } from '../reactions/actions.any';
|
||||
import { ENDPOINT_REACTION_NAME } from '../reactions/constants';
|
||||
import { getReactionMessageFromBuffer, isReactionsEnabled } from '../reactions/functions.any';
|
||||
import { endpointMessageReceived } from '../subtitles/actions.any';
|
||||
import { showToolbox } from '../toolbox/actions';
|
||||
|
||||
|
||||
@@ -93,14 +92,6 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
_addChatMsgListener(action.conference, store);
|
||||
break;
|
||||
|
||||
case OPEN_CHAT:
|
||||
unreadCount = 0;
|
||||
|
||||
if (typeof APP !== 'undefined') {
|
||||
APP.API.notifyChatUpdated(unreadCount, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case CLOSE_CHAT: {
|
||||
const isPollTabOpen = getState()['features/chat'].isPollsTabFocused;
|
||||
|
||||
@@ -116,6 +107,38 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
break;
|
||||
}
|
||||
|
||||
case ENDPOINT_MESSAGE_RECEIVED: {
|
||||
const state = store.getState();
|
||||
|
||||
if (!isReactionsEnabled(state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { participant, data } = action;
|
||||
|
||||
if (data?.name === ENDPOINT_REACTION_NAME) {
|
||||
store.dispatch(pushReactions(data.reactions));
|
||||
|
||||
_handleReceivedMessage(store, {
|
||||
id: participant.getId(),
|
||||
message: getReactionMessageFromBuffer(data.reactions),
|
||||
privateMessage: false,
|
||||
lobbyChat: false,
|
||||
timestamp: data.timestamp
|
||||
}, false, true);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case OPEN_CHAT:
|
||||
unreadCount = 0;
|
||||
|
||||
if (typeof APP !== 'undefined') {
|
||||
APP.API.notifyChatUpdated(unreadCount, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case SET_IS_POLL_TAB_FOCUSED: {
|
||||
dispatch(resetNbUnreadPollsMessages());
|
||||
break;
|
||||
@@ -253,35 +276,6 @@ function _addChatMsgListener(conference: IJitsiConference, store: IStore) {
|
||||
}
|
||||
);
|
||||
|
||||
conference.on(
|
||||
JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
|
||||
(...args: any) => {
|
||||
const state = store.getState();
|
||||
|
||||
if (!isReactionsEnabled(state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
store.dispatch(endpointMessageReceived(...args));
|
||||
|
||||
if (args && args.length >= 2) {
|
||||
const [ { _id }, eventData ] = args;
|
||||
|
||||
if (eventData.name === ENDPOINT_REACTION_NAME) {
|
||||
store.dispatch(pushReactions(eventData.reactions));
|
||||
|
||||
_handleReceivedMessage(store, {
|
||||
id: _id,
|
||||
message: getReactionMessageFromBuffer(eventData.reactions),
|
||||
privateMessage: false,
|
||||
lobbyChat: false,
|
||||
timestamp: eventData.timestamp
|
||||
}, false, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
conference.on(
|
||||
JitsiConferenceEvents.CONFERENCE_ERROR, (errorType: string, error: Error) => {
|
||||
errorType === JitsiConferenceErrors.CHAT_ERROR && _handleChatError(store, error);
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { TouchableOpacity } from 'react-native';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
|
||||
import { openHighlightDialog } from '../../../recording/actions.native';
|
||||
import HighlightButton from '../../../recording/components/Recording/native/HighlightButton';
|
||||
import RecordingLabel from '../../../recording/components/native/RecordingLabel';
|
||||
import { getActiveSession } from '../../../recording/functions';
|
||||
import VisitorsCountLabel from '../../../visitors/components/native/VisitorsCountLabel';
|
||||
|
||||
import RaisedHandsCountLabel from './RaisedHandsCountLabel';
|
||||
@@ -28,7 +30,10 @@ interface IProps {
|
||||
|
||||
const AlwaysOnLabels = ({ createOnPress }: IProps) => {
|
||||
const dispatch = useDispatch();
|
||||
const openHighlightDialogCallback = useCallback(() => dispatch(openHighlightDialog()), [ dispatch ]);
|
||||
const isStreaming = useSelector((state: IReduxState) =>
|
||||
Boolean(getActiveSession(state, JitsiRecordingConstants.mode.STREAM)));
|
||||
const openHighlightDialogCallback = useCallback(() =>
|
||||
dispatch(openHighlightDialog()), [ dispatch ]);
|
||||
|
||||
return (<>
|
||||
<TouchableOpacity
|
||||
@@ -36,11 +41,14 @@ const AlwaysOnLabels = ({ createOnPress }: IProps) => {
|
||||
onPress = { createOnPress(LABEL_ID_RECORDING) } >
|
||||
<RecordingLabel mode = { JitsiRecordingConstants.mode.FILE } />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
hitSlop = { LabelHitSlop }
|
||||
onPress = { createOnPress(LABEL_ID_STREAMING) } >
|
||||
<RecordingLabel mode = { JitsiRecordingConstants.mode.STREAM } />
|
||||
</TouchableOpacity>
|
||||
{
|
||||
isStreaming
|
||||
&& <TouchableOpacity
|
||||
hitSlop = { LabelHitSlop }
|
||||
onPress = { createOnPress(LABEL_ID_STREAMING) } >
|
||||
<RecordingLabel mode = { JitsiRecordingConstants.mode.STREAM } />
|
||||
</TouchableOpacity>
|
||||
}
|
||||
<TouchableOpacity
|
||||
hitSlop = { LabelHitSlop }
|
||||
onPress = { openHighlightDialogCallback }>
|
||||
|
||||
@@ -17,7 +17,6 @@ import { IReduxState, IStore } from '../../../app/types';
|
||||
import { CONFERENCE_BLURRED, CONFERENCE_FOCUSED } from '../../../base/conference/actionTypes';
|
||||
import { FULLSCREEN_ENABLED, PIP_ENABLED } from '../../../base/flags/constants';
|
||||
import { getFeatureFlag } from '../../../base/flags/functions';
|
||||
import { getParticipantCount } from '../../../base/participants/functions';
|
||||
import Container from '../../../base/react/components/native/Container';
|
||||
import LoadingIndicator from '../../../base/react/components/native/LoadingIndicator';
|
||||
import TintedView from '../../../base/react/components/native/TintedView';
|
||||
@@ -101,11 +100,6 @@ interface IProps extends AbstractProps {
|
||||
*/
|
||||
_fullscreenEnabled: boolean;
|
||||
|
||||
/**
|
||||
* The indicator which determines if the conference type is one to one.
|
||||
*/
|
||||
_isOneToOneConference: boolean;
|
||||
|
||||
/**
|
||||
* The indicator which determines if the participants pane is open.
|
||||
*/
|
||||
@@ -370,7 +364,6 @@ class Conference extends AbstractConference<IProps, State> {
|
||||
_aspectRatio,
|
||||
_connecting,
|
||||
_filmstripVisible,
|
||||
_isOneToOneConference,
|
||||
_largeVideoParticipantId,
|
||||
_reducedUI,
|
||||
_shouldDisplayTileView,
|
||||
@@ -426,13 +419,11 @@ class Conference extends AbstractConference<IProps, State> {
|
||||
<Captions onPress = { this._onClick } />
|
||||
|
||||
{
|
||||
_shouldDisplayTileView || (
|
||||
!_isOneToOneConference
|
||||
&& <Container style = { styles.displayNameContainer }>
|
||||
<DisplayNameLabel
|
||||
participantId = { _largeVideoParticipantId } />
|
||||
</Container>
|
||||
)
|
||||
_shouldDisplayTileView
|
||||
|| <Container style = { styles.displayNameContainer }>
|
||||
<DisplayNameLabel
|
||||
participantId = { _largeVideoParticipantId } />
|
||||
</Container>
|
||||
}
|
||||
|
||||
{ !_shouldDisplayTileView && <LonelyMeetingExperience /> }
|
||||
@@ -573,7 +564,6 @@ function _mapStateToProps(state: IReduxState, _ownProps: any) {
|
||||
const { backgroundColor } = state['features/dynamic-branding'];
|
||||
const { startCarMode } = state['features/base/settings'];
|
||||
const { enabled: audioOnlyEnabled } = state['features/base/audio-only'];
|
||||
const participantCount = getParticipantCount(state);
|
||||
const brandingStyles = backgroundColor ? {
|
||||
backgroundColor
|
||||
} : undefined;
|
||||
@@ -587,7 +577,6 @@ function _mapStateToProps(state: IReduxState, _ownProps: any) {
|
||||
_connecting: isConnecting(state),
|
||||
_filmstripVisible: isFilmstripVisible(state),
|
||||
_fullscreenEnabled: getFeatureFlag(state, FULLSCREEN_ENABLED, true),
|
||||
_isOneToOneConference: Boolean(participantCount === 2),
|
||||
_isParticipantsPaneOpen: isOpen,
|
||||
_largeVideoParticipantId: state['features/large-video'].participantId,
|
||||
_pictureInPictureEnabled: getFeatureFlag(state, PIP_ENABLED),
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import React, { Component } from 'react';
|
||||
import { TouchableOpacity, View, ViewStyle } from 'react-native';
|
||||
|
||||
import TranscribingLabel from '../../../transcribing/components/TranscribingLabel.native';
|
||||
import VideoQualityLabel from '../../../video-quality/components/VideoQualityLabel.native';
|
||||
|
||||
import InsecureRoomNameLabel from './InsecureRoomNameLabel';
|
||||
import { LABEL_ID_INSECURE_ROOM_NAME, LABEL_ID_QUALITY, LABEL_ID_TRANSCRIBING, LabelHitSlop } from './constants';
|
||||
import { LABEL_ID_INSECURE_ROOM_NAME, LABEL_ID_QUALITY, LabelHitSlop } from './constants';
|
||||
import styles from './styles';
|
||||
|
||||
interface IProps {
|
||||
@@ -33,13 +32,6 @@ class Labels extends Component<IProps> {
|
||||
<View
|
||||
pointerEvents = 'box-none'
|
||||
style = { styles.indicatorContainer as ViewStyle }>
|
||||
<TouchableOpacity
|
||||
hitSlop = { LabelHitSlop }
|
||||
onPress = {
|
||||
this.props.createOnPress(LABEL_ID_TRANSCRIBING)
|
||||
} >
|
||||
<TranscribingLabel />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
hitSlop = { LabelHitSlop }
|
||||
onPress = {
|
||||
|
||||
@@ -4,11 +4,12 @@ import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { getConferenceName, getConferenceTimestamp } from '../../../base/conference/functions';
|
||||
import { CONFERENCE_TIMER_ENABLED, MEETING_NAME_ENABLED } from '../../../base/flags/constants';
|
||||
import { CONFERENCE_TIMER_ENABLED } from '../../../base/flags/constants';
|
||||
import { getFeatureFlag } from '../../../base/flags/functions';
|
||||
import AudioDeviceToggleButton from '../../../mobile/audio-mode/components/AudioDeviceToggleButton';
|
||||
import PictureInPictureButton from '../../../mobile/picture-in-picture/components/PictureInPictureButton';
|
||||
import ParticipantsPaneButton from '../../../participants-pane/components/native/ParticipantsPaneButton';
|
||||
import { isRoomNameEnabled } from '../../../prejoin/functions';
|
||||
import ToggleCameraButton from '../../../toolbox/components/native/ToggleCameraButton';
|
||||
import { isToolboxVisible } from '../../../toolbox/functions.native';
|
||||
import ConferenceTimer from '../ConferenceTimer';
|
||||
@@ -16,6 +17,7 @@ import ConferenceTimer from '../ConferenceTimer';
|
||||
import Labels from './Labels';
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
@@ -35,9 +37,9 @@ interface IProps {
|
||||
_meetingName: string;
|
||||
|
||||
/**
|
||||
* Whether displaying the current meeting name is enabled or not.
|
||||
* Whether displaying the current room name is enabled or not.
|
||||
*/
|
||||
_meetingNameEnabled: boolean;
|
||||
_roomNameEnabled: boolean;
|
||||
|
||||
/**
|
||||
* True if the navigation bar should be visible.
|
||||
@@ -75,7 +77,7 @@ const TitleBar = (props: IProps) => {
|
||||
</View>
|
||||
}
|
||||
{
|
||||
props._meetingNameEnabled
|
||||
props._roomNameEnabled
|
||||
&& <View style = { styles.roomNameView as ViewStyle }>
|
||||
<Text
|
||||
numberOfLines = { 1 }
|
||||
@@ -107,15 +109,14 @@ const TitleBar = (props: IProps) => {
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
const { hideConferenceTimer, hideConferenceSubject } = state['features/base/config'];
|
||||
const { hideConferenceTimer } = state['features/base/config'];
|
||||
const startTimestamp = getConferenceTimestamp(state);
|
||||
|
||||
return {
|
||||
_conferenceTimerEnabled:
|
||||
Boolean(getFeatureFlag(state, CONFERENCE_TIMER_ENABLED, true) && !hideConferenceTimer && startTimestamp),
|
||||
_meetingName: getConferenceName(state),
|
||||
_meetingNameEnabled:
|
||||
getFeatureFlag(state, MEETING_NAME_ENABLED, true) && !hideConferenceSubject,
|
||||
_roomNameEnabled: isRoomNameEnabled(state),
|
||||
_visible: isToolboxVisible(state)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import React from 'react';
|
||||
|
||||
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
|
||||
import RecordingExpandedLabel from '../../../recording/components/native/RecordingExpandedLabel';
|
||||
import TranscribingExpandedLabel from '../../../transcribing/components/TranscribingExpandedLabel.native';
|
||||
import VideoQualityExpandedLabel from '../../../video-quality/components/VideoQualityExpandedLabel.native';
|
||||
|
||||
import InsecureRoomNameExpandedLabel from './InsecureRoomNameExpandedLabel';
|
||||
@@ -23,7 +22,6 @@ export const EXPANDED_LABEL_TIMEOUT = 5000;
|
||||
export const LABEL_ID_QUALITY = 'quality';
|
||||
export const LABEL_ID_RECORDING = 'recording';
|
||||
export const LABEL_ID_STREAMING = 'streaming';
|
||||
export const LABEL_ID_TRANSCRIBING = 'transcribing';
|
||||
export const LABEL_ID_INSECURE_ROOM_NAME = 'insecure-room-name';
|
||||
export const LABEL_ID_RAISED_HANDS_COUNT = 'raised-hands-count';
|
||||
export const LABEL_ID_VISITORS_COUNT = 'visitors-count';
|
||||
@@ -58,9 +56,6 @@ export const EXPANDED_LABELS: {
|
||||
},
|
||||
alwaysOn: true
|
||||
},
|
||||
[LABEL_ID_TRANSCRIBING]: {
|
||||
component: TranscribingExpandedLabel
|
||||
},
|
||||
[LABEL_ID_INSECURE_ROOM_NAME]: {
|
||||
component: InsecureRoomNameExpandedLabel
|
||||
},
|
||||
|
||||
@@ -23,6 +23,7 @@ import { getOverlayToRender } from '../../../overlay/functions.web';
|
||||
import ParticipantsPane from '../../../participants-pane/components/web/ParticipantsPane';
|
||||
import Prejoin from '../../../prejoin/components/web/Prejoin';
|
||||
import { isPrejoinPageVisible } from '../../../prejoin/functions';
|
||||
import ReactionAnimations from '../../../reactions/components/web/ReactionsAnimations';
|
||||
import { toggleToolboxVisible } from '../../../toolbox/actions.any';
|
||||
import { fullScreenChanged, showToolbox } from '../../../toolbox/actions.web';
|
||||
import JitsiPortal from '../../../toolbox/components/web/JitsiPortal';
|
||||
@@ -260,6 +261,7 @@ class Conference extends AbstractConference<IProps, any> {
|
||||
{ _showLobby && <LobbyScreen />}
|
||||
</div>
|
||||
<ParticipantsPane />
|
||||
<ReactionAnimations />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import HighlightButton from '../../../recording/components/Recording/web/Highlig
|
||||
import RecordingLabel from '../../../recording/components/web/RecordingLabel';
|
||||
import { showToolbox } from '../../../toolbox/actions.web';
|
||||
import { isToolboxVisible } from '../../../toolbox/functions.web';
|
||||
import TranscribingLabel from '../../../transcribing/components/TranscribingLabel.web';
|
||||
import VideoQualityLabel from '../../../video-quality/components/VideoQualityLabel.web';
|
||||
import VisitorsCountLabel from '../../../visitors/components/web/VisitorsCountLabel';
|
||||
import ConferenceTimer from '../ConferenceTimer';
|
||||
@@ -83,10 +82,6 @@ const COMPONENTS: Array<{
|
||||
Component: RaisedHandsCountLabel,
|
||||
id: 'raised-hands-count'
|
||||
},
|
||||
{
|
||||
Component: TranscribingLabel,
|
||||
id: 'transcribing'
|
||||
},
|
||||
{
|
||||
Component: VideoQualityLabel,
|
||||
id: 'video-quality'
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IStateful } from '../base/app/types';
|
||||
import { toState } from '../base/redux/functions';
|
||||
import { iAmVisitor } from '../visitors/functions';
|
||||
|
||||
|
||||
/**
|
||||
@@ -15,3 +16,19 @@ export function shouldDisplayNotifications(stateful: IStateful) {
|
||||
|
||||
return !calleeInfoVisible;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Returns true if polls feature is disabled.
|
||||
*
|
||||
* @param {(Function|Object)} stateful - The (whole) redux state, or redux's
|
||||
* {@code getState} function to be used to retrieve the state
|
||||
* features/base/config.
|
||||
* @returns {boolean}.
|
||||
*/
|
||||
export function arePollsDisabled(stateful: IStateful) {
|
||||
const state = toState(stateful);
|
||||
|
||||
return state['features/base/config']?.disablePolls || iAmVisitor(state);
|
||||
}
|
||||
|
||||
@@ -1,21 +1 @@
|
||||
import { IStateful } from '../base/app/types';
|
||||
import { toState } from '../base/redux/functions';
|
||||
|
||||
export * from './functions.any';
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Returns true if polls feature is disabled.
|
||||
*
|
||||
* @param {(Function|Object)} stateful - The (whole) redux state, or redux's
|
||||
* {@code getState} function to be used to retrieve the state
|
||||
* features/base/config.
|
||||
* @returns {boolean}.
|
||||
*/
|
||||
export function getDisablePolls(stateful: IStateful) {
|
||||
const state = toState(stateful)['features/base/config'];
|
||||
|
||||
return state.disablePolls;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
NOTIFICATION_ICON,
|
||||
NOTIFICATION_TIMEOUT_TYPE
|
||||
} from '../notifications/constants';
|
||||
import { showStartRecordingNotification } from '../recording/actions';
|
||||
import { showSalesforceNotification } from '../salesforce/actions';
|
||||
import { setToolboxEnabled } from '../toolbox/actions.any';
|
||||
|
||||
@@ -149,6 +150,8 @@ function _conferenceJoined({ dispatch, getState }: IStore) {
|
||||
}
|
||||
|
||||
dispatch(showSalesforceNotification());
|
||||
dispatch(showStartRecordingNotification());
|
||||
|
||||
_checkIframe(getState(), dispatch);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
|
||||
import i18next from 'i18next';
|
||||
|
||||
import { CONFERENCE_JOINED, KICKED_OUT } from '../base/conference/actionTypes';
|
||||
import { IJitsiConference } from '../base/conference/reducer';
|
||||
import { ENDPOINT_MESSAGE_RECEIVED, KICKED_OUT } from '../base/conference/actionTypes';
|
||||
import { hangup } from '../base/connection/actions.web';
|
||||
import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
|
||||
import { getParticipantDisplayName } from '../base/participants/functions';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import { openAllowToggleCameraDialog, setCameraFacingMode } from '../base/tracks/actions.web';
|
||||
@@ -14,8 +11,15 @@ import './middleware.any';
|
||||
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
switch (action.type) {
|
||||
case CONFERENCE_JOINED: {
|
||||
_addSetCameraFacingModeListener(action.conference);
|
||||
case ENDPOINT_MESSAGE_RECEIVED: {
|
||||
const { participant, data } = action;
|
||||
|
||||
if (data?.name === CAMERA_FACING_MODE_MESSAGE) {
|
||||
APP.store.dispatch(openAllowToggleCameraDialog(
|
||||
/* onAllow */ () => APP.store.dispatch(setCameraFacingMode(data.facingMode)),
|
||||
/* initiatorId */ participant.getId()
|
||||
));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -34,28 +38,3 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
|
||||
return next(action);
|
||||
});
|
||||
|
||||
/**
|
||||
* Registers listener for {@link JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED} that
|
||||
* will perform various chat related activities.
|
||||
*
|
||||
* @param {IJitsiConference} conference - The conference.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _addSetCameraFacingModeListener(conference: IJitsiConference) {
|
||||
conference.on(
|
||||
JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
|
||||
(...args: any) => {
|
||||
if (args && args.length >= 2) {
|
||||
const [ sender, eventData ] = args;
|
||||
|
||||
if (eventData.name === CAMERA_FACING_MODE_MESSAGE) {
|
||||
APP.store.dispatch(openAllowToggleCameraDialog(
|
||||
/* onAllow */ () => APP.store.dispatch(setCameraFacingMode(eventData.facingMode)),
|
||||
/* initiatorId */ sender._id
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import { IDeeplinkingConfig } from '../../base/config/configType';
|
||||
import { getLegalUrls } from '../../base/config/functions.any';
|
||||
import { isSupportedBrowser } from '../../base/environment/environment';
|
||||
import { translate, translateToHTML } from '../../base/i18n/functions';
|
||||
import Platform from '../../base/react/Platform.web';
|
||||
import { withPixelLineHeight } from '../../base/styles/functions.web';
|
||||
import Button from '../../base/ui/components/web/Button';
|
||||
import { BUTTON_TYPES } from '../../base/ui/constants.any';
|
||||
@@ -85,6 +86,14 @@ const DeepLinkingDesktopPage: React.FC<WithTranslation> = ({ t }) => {
|
||||
const deeplinkingCfg = useSelector((state: IReduxState) =>
|
||||
state['features/base/config']?.deeplinking || {} as IDeeplinkingConfig);
|
||||
|
||||
const generateDownloadURL = useCallback(() => {
|
||||
const downloadCfg = deeplinkingCfg.desktop?.download;
|
||||
|
||||
if (downloadCfg) {
|
||||
return downloadCfg[Platform.OS as keyof typeof downloadCfg];
|
||||
}
|
||||
}, [ deeplinkingCfg ]);
|
||||
|
||||
const legalUrls = useSelector(getLegalUrls);
|
||||
|
||||
const { hideLogo, desktop } = deeplinkingCfg;
|
||||
@@ -134,6 +143,16 @@ const DeepLinkingDesktopPage: React.FC<WithTranslation> = ({ t }) => {
|
||||
: t(`${_TNS}.descriptionWithoutWeb`, { app: desktop?.appName })
|
||||
}
|
||||
</div>
|
||||
<div className = { styles.descriptionLabel }>
|
||||
{
|
||||
t(`${_TNS}.noDesktopApp`)
|
||||
}
|
||||
<a href = { generateDownloadURL() }>
|
||||
{
|
||||
t(`${_TNS}.downloadApp`)
|
||||
}
|
||||
</a>
|
||||
</div>
|
||||
<div className = { styles.buttonsContainer }>
|
||||
<Button
|
||||
label = { t(`${_TNS}.tryAgainButton`) }
|
||||
|
||||
@@ -211,7 +211,7 @@ const DeepLinkingMobilePage: React.FC<WithTranslation> = ({ t }) => {
|
||||
</a>
|
||||
{isSupportedMobileBrowser() ? (
|
||||
<div className = { styles.supportedBrowserContent }>
|
||||
<div className = { styles.labelOr }>OR</div>
|
||||
<div className = { styles.labelOr }>{ t(`${_TNS}.or`) }</div>
|
||||
<a
|
||||
className = { styles.linkWrapper }
|
||||
onClick = { onLaunchWeb }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IReduxState } from '../app/types';
|
||||
import { isMobileBrowser } from '../base/environment/utils';
|
||||
import { browser } from '../base/lib-jitsi-meet';
|
||||
import Platform from '../base/react/Platform';
|
||||
import { URI_PROTOCOL_PATTERN } from '../base/util/uri';
|
||||
import { isVpaasMeeting } from '../jaas/functions';
|
||||
@@ -63,6 +64,7 @@ export function getDeepLinkingPage(state: IReduxState) {
|
||||
if (launchInWeb
|
||||
|| !room
|
||||
|| state['features/base/config'].deeplinking?.disabled
|
||||
|| browser.isElectron()
|
||||
|| (isVpaasMeeting(state) && (!appScheme || appScheme === 'com.8x8.meet'))) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { IReduxState } from '../app/types';
|
||||
import { URI_PROTOCOL_PATTERN } from '../base/util/uri';
|
||||
|
||||
/**
|
||||
* Opens the desktop app.
|
||||
*
|
||||
@@ -6,5 +9,17 @@
|
||||
* with false otherwise.
|
||||
*/
|
||||
export function _openDesktopApp(_state: Object) {
|
||||
const state = _state as IReduxState;
|
||||
const deeplinkingDesktop = state['features/base/config'].deeplinking?.desktop;
|
||||
|
||||
if (deeplinkingDesktop?.enabled) {
|
||||
const { appScheme } = deeplinkingDesktop;
|
||||
const regex = new RegExp(URI_PROTOCOL_PATTERN, 'gi');
|
||||
|
||||
window.location.href = window.location.href.replace(regex, `${appScheme}:`);
|
||||
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ class SharedDocument extends PureComponent<IProps> {
|
||||
style = { styles.sharedDocContainer }>
|
||||
<WebView
|
||||
hideKeyboardAccessoryView = { true }
|
||||
incognito = { true }
|
||||
renderLoading = { this._renderLoading }
|
||||
source = {{ uri: _documentUrl ?? '' }}
|
||||
startInLoadingState = { true }
|
||||
|
||||
@@ -3,12 +3,11 @@ import { AnyAction } from 'redux';
|
||||
import { IStore } from '../app/types';
|
||||
import {
|
||||
CONFERENCE_JOINED,
|
||||
CONFERENCE_WILL_LEAVE
|
||||
CONFERENCE_WILL_LEAVE,
|
||||
ENDPOINT_MESSAGE_RECEIVED
|
||||
} from '../base/conference/actionTypes';
|
||||
import { getCurrentConference } from '../base/conference/functions';
|
||||
import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
|
||||
import { getLocalParticipant, getParticipantCount } from '../base/participants/functions';
|
||||
import { IParticipant } from '../base/participants/types';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import { TRACK_ADDED, TRACK_REMOVED, TRACK_UPDATED } from '../base/tracks/actionTypes';
|
||||
|
||||
@@ -28,27 +27,22 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA
|
||||
FaceLandmarksDetector.init(store);
|
||||
}
|
||||
|
||||
// allow using remote face centering data when local face centering is not enabled
|
||||
action.conference.on(
|
||||
JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
|
||||
(participant: IParticipant | undefined, eventData: any) => {
|
||||
if (!participant || !eventData || !participant.getId) {
|
||||
return;
|
||||
}
|
||||
return next(action);
|
||||
} else if (action.type === ENDPOINT_MESSAGE_RECEIVED) {
|
||||
// Allow using remote face centering data when local face centering is not enabled.
|
||||
const { participant, data } = action;
|
||||
|
||||
if (eventData.type === FACE_BOX_EVENT_TYPE) {
|
||||
dispatch({
|
||||
type: UPDATE_FACE_COORDINATES,
|
||||
faceBox: eventData.faceBox,
|
||||
id: participant.getId()
|
||||
});
|
||||
}
|
||||
if (data?.type === FACE_BOX_EVENT_TYPE) {
|
||||
dispatch({
|
||||
type: UPDATE_FACE_COORDINATES,
|
||||
faceBox: data.faceBox,
|
||||
id: participant.getId()
|
||||
});
|
||||
}
|
||||
|
||||
return next(action);
|
||||
}
|
||||
|
||||
|
||||
if (!isEnabled) {
|
||||
return next(action);
|
||||
}
|
||||
@@ -57,7 +51,7 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA
|
||||
case CONFERENCE_WILL_LEAVE : {
|
||||
FaceLandmarksDetector.stopDetection(store);
|
||||
|
||||
return next(action);
|
||||
break;
|
||||
}
|
||||
case TRACK_ADDED: {
|
||||
const { jitsiTrack: { isLocal, videoType }, muted } = action.track;
|
||||
@@ -67,18 +61,18 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA
|
||||
FaceLandmarksDetector.startDetection(store, action.track);
|
||||
}
|
||||
|
||||
return next(action);
|
||||
break;
|
||||
}
|
||||
case TRACK_UPDATED: {
|
||||
const { jitsiTrack: { isLocal, videoType } } = action.track;
|
||||
|
||||
if (videoType !== 'camera' || !isLocal()) {
|
||||
return next(action);
|
||||
break;
|
||||
}
|
||||
|
||||
const { muted } = action.track;
|
||||
|
||||
if (muted !== undefined) {
|
||||
if (typeof muted !== 'undefined') {
|
||||
// addresses video mute state changes
|
||||
if (muted) {
|
||||
FaceLandmarksDetector.stopDetection(store);
|
||||
@@ -87,7 +81,7 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA
|
||||
}
|
||||
}
|
||||
|
||||
return next(action);
|
||||
break;
|
||||
}
|
||||
case TRACK_REMOVED: {
|
||||
const { jitsiTrack: { isLocal, videoType } } = action.track;
|
||||
@@ -96,7 +90,7 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA
|
||||
FaceLandmarksDetector.stopDetection(store);
|
||||
}
|
||||
|
||||
return next(action);
|
||||
break;
|
||||
}
|
||||
case ADD_FACE_LANDMARKS: {
|
||||
const state = getState();
|
||||
@@ -110,7 +104,7 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA
|
||||
// Disabling for now as there is no value of having the data in speakerstats at the server
|
||||
// sendFaceExpressionToServer(conference, faceLandmarks);
|
||||
|
||||
return next(action);
|
||||
break;
|
||||
}
|
||||
case NEW_FACE_COORDINATES: {
|
||||
const state = getState();
|
||||
@@ -127,6 +121,8 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA
|
||||
faceBox,
|
||||
id: localParticipant?.id
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ class DialInSummary extends PureComponent<IProps> {
|
||||
<JitsiScreen
|
||||
style = { styles.backDrop }>
|
||||
<WebView
|
||||
incognito = { true }
|
||||
onError = { this._onError }
|
||||
onShouldStartLoadWithRequest = { this._onNavigate }
|
||||
renderLoading = { this._renderLoading }
|
||||
|
||||
@@ -66,7 +66,7 @@ const ConferenceID: React.FC<IProps> = ({ conferenceID, t }) => {
|
||||
return (
|
||||
<div className = { styles.container }>
|
||||
<div className = { styles.descriptionLabel }>
|
||||
To join the meeting via phone, dial one of these numbers and then enter the pin
|
||||
{ t('info.dialANumber') }
|
||||
</div>
|
||||
<div className = { styles.separator } />
|
||||
<div className = { styles.pinLabel }>
|
||||
|
||||
@@ -571,12 +571,13 @@ export function searchDirectory( // eslint-disable-line max-params
|
||||
* @param {IReduxState} state - The current state.
|
||||
* @param {string} inviteUrl - The conference/location URL.
|
||||
* @param {boolean} useHtml - Whether to return html text.
|
||||
* @param {boolean} skipDialIn - Whether to skip dial-in options or not.
|
||||
* @returns {Promise<string>} A {@code Promise} resolving with a
|
||||
* descriptive text that can be used to invite participants to a meeting.
|
||||
*/
|
||||
export function getShareInfoText(state: IReduxState, inviteUrl: string, useHtml?: boolean): Promise<string> {
|
||||
export function getShareInfoText(
|
||||
state: IReduxState, inviteUrl: string, useHtml?: boolean, skipDialIn?: boolean): Promise<string> {
|
||||
let roomUrl = _decodeRoomURI(inviteUrl);
|
||||
const includeDialInfo = state['features/base/config'] !== undefined;
|
||||
|
||||
if (useHtml) {
|
||||
roomUrl = `<a href="${roomUrl}">${roomUrl}</a>`;
|
||||
@@ -584,85 +585,72 @@ export function getShareInfoText(state: IReduxState, inviteUrl: string, useHtml?
|
||||
|
||||
let infoText = i18next.t('share.mainText', { roomUrl });
|
||||
|
||||
if (includeDialInfo) {
|
||||
const { room } = parseURIString(inviteUrl);
|
||||
let numbersPromise;
|
||||
let hasPaymentError = false;
|
||||
const { room } = parseURIString(inviteUrl);
|
||||
const { dialInConfCodeUrl, dialInNumbersUrl, hosts } = state['features/base/config'];
|
||||
const { locationURL = {} } = state['features/base/connection'];
|
||||
const mucURL = hosts?.muc;
|
||||
|
||||
if (state['features/invite'].numbers
|
||||
&& state['features/invite'].conferenceID) {
|
||||
numbersPromise = Promise.resolve(state['features/invite']);
|
||||
} else {
|
||||
// we are requesting numbers and conferenceId directly
|
||||
// not using updateDialInNumbers, because custom room
|
||||
// is specified and we do not want to store the data
|
||||
// in the state
|
||||
const { dialInConfCodeUrl, dialInNumbersUrl, hosts }
|
||||
= state['features/base/config'];
|
||||
const { locationURL = {} } = state['features/base/connection'];
|
||||
const mucURL = hosts?.muc;
|
||||
|
||||
if (!dialInConfCodeUrl || !dialInNumbersUrl || !mucURL) {
|
||||
// URLs for fetching dial in numbers not defined
|
||||
return Promise.resolve(infoText);
|
||||
}
|
||||
|
||||
numbersPromise = Promise.all([
|
||||
getDialInNumbers(dialInNumbersUrl, room, mucURL), // @ts-ignore
|
||||
getDialInConferenceID(dialInConfCodeUrl, room, mucURL, locationURL)
|
||||
]).then(([ numbers, {
|
||||
conference, id, message } ]) => {
|
||||
|
||||
if (!conference || !id) {
|
||||
return Promise.reject(message);
|
||||
}
|
||||
|
||||
return {
|
||||
numbers,
|
||||
conferenceID: id
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return numbersPromise.then(
|
||||
({ conferenceID, numbers }) => {
|
||||
const phoneNumber = _getDefaultPhoneNumber(numbers) || '';
|
||||
|
||||
return `${
|
||||
i18next.t('info.dialInNumber')} ${
|
||||
phoneNumber} ${
|
||||
i18next.t('info.dialInConferenceID')} ${
|
||||
conferenceID}#\n\n`;
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('Error fetching numbers or conferenceID', error);
|
||||
hasPaymentError = error?.status === StatusCode.PaymentRequired;
|
||||
})
|
||||
.then(defaultDialInNumber => {
|
||||
if (hasPaymentError) {
|
||||
infoText += `${
|
||||
i18next.t('info.dialInNumber')} ${i18next.t('info.reachedLimit')} ${
|
||||
i18next.t('info.upgradeOptions')} ${UPGRADE_OPTIONS_TEXT}`;
|
||||
|
||||
return infoText;
|
||||
}
|
||||
|
||||
let dialInfoPageUrl = getDialInfoPageURL(state, room);
|
||||
|
||||
if (useHtml) {
|
||||
dialInfoPageUrl
|
||||
= `<a href="${dialInfoPageUrl}">${dialInfoPageUrl}</a>`;
|
||||
}
|
||||
|
||||
infoText += i18next.t('share.dialInfoText', {
|
||||
defaultDialInNumber,
|
||||
dialInfoPageUrl });
|
||||
|
||||
return infoText;
|
||||
});
|
||||
if (skipDialIn || !dialInConfCodeUrl || !dialInNumbersUrl || !mucURL) {
|
||||
// URLs for fetching dial in numbers not defined.
|
||||
return Promise.resolve(infoText);
|
||||
}
|
||||
|
||||
return Promise.resolve(infoText);
|
||||
let hasPaymentError = false;
|
||||
|
||||
// We are requesting numbers and conferenceId directly
|
||||
// not using updateDialInNumbers, because custom room
|
||||
// is specified and we do not want to store the data
|
||||
// in the state.
|
||||
const numbersPromise = Promise.all([
|
||||
getDialInNumbers(dialInNumbersUrl, room, mucURL), // @ts-ignore
|
||||
getDialInConferenceID(dialInConfCodeUrl, room, mucURL, locationURL)
|
||||
]).then(([ numbers, {
|
||||
conference, id, message } ]) => {
|
||||
|
||||
if (!conference || !id) {
|
||||
return Promise.reject(message);
|
||||
}
|
||||
|
||||
return {
|
||||
numbers,
|
||||
conferenceID: id
|
||||
};
|
||||
});
|
||||
|
||||
return numbersPromise.then(({ conferenceID, numbers }) => {
|
||||
const phoneNumber = _getDefaultPhoneNumber(numbers) || '';
|
||||
|
||||
return `${
|
||||
i18next.t('info.dialInNumber')} ${
|
||||
phoneNumber} ${
|
||||
i18next.t('info.dialInConferenceID')} ${
|
||||
conferenceID}#\n\n`;
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('Error fetching numbers or conferenceID', error);
|
||||
hasPaymentError = error?.status === StatusCode.PaymentRequired;
|
||||
})
|
||||
.then(defaultDialInNumber => {
|
||||
if (hasPaymentError) {
|
||||
infoText += `${
|
||||
i18next.t('info.dialInNumber')} ${i18next.t('info.reachedLimit')} ${
|
||||
i18next.t('info.upgradeOptions')} ${UPGRADE_OPTIONS_TEXT}`;
|
||||
|
||||
return infoText;
|
||||
}
|
||||
|
||||
let dialInfoPageUrl = getDialInfoPageURL(state, room);
|
||||
|
||||
if (useHtml) {
|
||||
dialInfoPageUrl = `<a href="${dialInfoPageUrl}">${dialInfoPageUrl}</a>`;
|
||||
}
|
||||
|
||||
infoText += i18next.t('share.dialInfoText', {
|
||||
defaultDialInNumber,
|
||||
dialInfoPageUrl });
|
||||
|
||||
return infoText;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,7 +30,7 @@ export const registerShortcut = (shortcut: IKeyboardShortcut): AnyAction => {
|
||||
*/
|
||||
export const unregisterShortcut = (character: string, altKey = false): AnyAction => {
|
||||
return {
|
||||
altKey,
|
||||
alt: altKey,
|
||||
type: UNREGISTER_KEYBOARD_SHORTCUT,
|
||||
character
|
||||
};
|
||||
|
||||
@@ -21,7 +21,8 @@ import {
|
||||
SET_PASSWORD_JOIN_FAILED
|
||||
} from './actionTypes';
|
||||
import { LOBBY_CHAT_INITIALIZED, MODERATOR_IN_CHAT_WITH_LEFT } from './constants';
|
||||
import { getKnockingParticipants, getLobbyConfig, getLobbyEnabled } from './functions';
|
||||
import { getKnockingParticipants, getLobbyConfig, getLobbyEnabled, isEnablingLobbyAllowed } from './functions';
|
||||
import logger from './logger';
|
||||
import { IKnockingParticipant } from './types';
|
||||
|
||||
/**
|
||||
@@ -243,7 +244,11 @@ export function toggleLobbyMode(enabled: boolean) {
|
||||
const conference = getCurrentConference(getState);
|
||||
|
||||
if (enabled) {
|
||||
conference?.enableLobby();
|
||||
if (isEnablingLobbyAllowed(getState())) {
|
||||
conference?.enableLobby();
|
||||
} else {
|
||||
logger.info('Ignoring enable lobby request because there are visitors in the call already.');
|
||||
}
|
||||
} else {
|
||||
conference?.disableLobby();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IReduxState } from '../app/types';
|
||||
import { getCurrentConference } from '../base/conference/functions';
|
||||
import { getVisitorsCount } from '../visitors/functions';
|
||||
|
||||
import { IKnockingParticipant } from './types';
|
||||
|
||||
@@ -92,3 +93,13 @@ export function showLobbyChatButton(
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if enabling lobby is allowed and false otherwise.
|
||||
*
|
||||
* @param {IReduxState} state - State object.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isEnablingLobbyAllowed(state: IReduxState) {
|
||||
return getVisitorsCount(state) <= 0;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ import { IStore } from '../app/types';
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes';
|
||||
import {
|
||||
CONFERENCE_FAILED,
|
||||
CONFERENCE_JOINED
|
||||
CONFERENCE_JOINED,
|
||||
ENDPOINT_MESSAGE_RECEIVED
|
||||
} from '../base/conference/actionTypes';
|
||||
import { conferenceWillJoin } from '../base/conference/actions';
|
||||
import {
|
||||
@@ -31,6 +32,7 @@ import {
|
||||
handleLobbyChatInitialized,
|
||||
removeLobbyChatParticipant
|
||||
} from '../chat/actions.any';
|
||||
import { arePollsDisabled } from '../conference/functions.any';
|
||||
import { hideNotification, showNotification } from '../notifications/actions';
|
||||
import {
|
||||
LOBBY_NOTIFICATION_ID,
|
||||
@@ -41,7 +43,11 @@ import {
|
||||
import { INotificationProps } from '../notifications/types';
|
||||
import { open as openParticipantsPane } from '../participants-pane/actions';
|
||||
import { getParticipantsPaneOpen } from '../participants-pane/functions';
|
||||
import { isPrejoinPageVisible, shouldAutoKnock } from '../prejoin/functions';
|
||||
import {
|
||||
isPrejoinEnabledInConfig,
|
||||
isPrejoinPageVisible,
|
||||
shouldAutoKnock
|
||||
} from '../prejoin/functions';
|
||||
|
||||
import {
|
||||
KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED,
|
||||
@@ -78,6 +84,13 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
return _conferenceFailed(store, next, action);
|
||||
case CONFERENCE_JOINED:
|
||||
return _conferenceJoined(store, next, action);
|
||||
case ENDPOINT_MESSAGE_RECEIVED: {
|
||||
const { participant, data } = action;
|
||||
|
||||
_maybeSendLobbyNotification(participant, data, store);
|
||||
|
||||
break;
|
||||
}
|
||||
case KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED: {
|
||||
// We need the full update result to be in the store already
|
||||
const result = next(action);
|
||||
@@ -165,13 +178,6 @@ StateListenerRegistry.register(
|
||||
dispatch(updateLobbyParticipantOnLeave(id));
|
||||
});
|
||||
});
|
||||
|
||||
conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, (origin: any, sender: any) =>
|
||||
_maybeSendLobbyNotification(origin, sender, {
|
||||
dispatch,
|
||||
getState
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -201,7 +207,6 @@ function _handleLobbyNotification(store: IStore) {
|
||||
|
||||
if (knockingParticipants.length === 1) {
|
||||
const firstParticipant = knockingParticipants[0];
|
||||
const { disablePolls } = getState()['features/base/config'];
|
||||
const showChat = showLobbyChatButton(firstParticipant)(getState());
|
||||
|
||||
descriptionKey = 'notify.participantWantsToJoin';
|
||||
@@ -225,7 +230,7 @@ function _handleLobbyNotification(store: IStore) {
|
||||
customActionType.splice(1, 0, BUTTON_TYPES.SECONDARY);
|
||||
customActionHandler.splice(1, 0, () => batch(() => {
|
||||
dispatch(handleLobbyChatInitialized(firstParticipant.id));
|
||||
dispatch(openChat({}, disablePolls));
|
||||
dispatch(openChat({}, arePollsDisabled(getState())));
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
@@ -268,7 +273,6 @@ function _conferenceFailed({ dispatch, getState }: IStore, next: Function, actio
|
||||
const { membersOnly } = state['features/base/conference'];
|
||||
const nonFirstFailure = Boolean(membersOnly);
|
||||
const { isDisplayNameRequiredError } = state['features/lobby'];
|
||||
const { prejoinConfig } = state['features/base/config'];
|
||||
|
||||
if (error.name === JitsiConferenceErrors.MEMBERS_ONLY_ERROR) {
|
||||
if (typeof error.recoverable === 'undefined') {
|
||||
@@ -283,7 +287,9 @@ function _conferenceFailed({ dispatch, getState }: IStore, next: Function, actio
|
||||
dispatch(openLobbyScreen());
|
||||
|
||||
// if there was an error about display name and pre-join is not enabled
|
||||
if (shouldAutoKnock(state) || (isDisplayNameRequiredError && !prejoinConfig?.enabled) || lobbyWaitingForHost) {
|
||||
if (shouldAutoKnock(state)
|
||||
|| (isDisplayNameRequiredError && !isPrejoinEnabledInConfig(state))
|
||||
|| lobbyWaitingForHost) {
|
||||
dispatch(startKnocking());
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
CONFERENCE_JOINED,
|
||||
CONFERENCE_LEFT,
|
||||
CONFERENCE_WILL_JOIN,
|
||||
ENDPOINT_MESSAGE_RECEIVED,
|
||||
SET_ROOM
|
||||
} from '../../base/conference/actionTypes';
|
||||
import { JITSI_CONFERENCE_URL_KEY } from '../../base/conference/constants';
|
||||
@@ -184,6 +185,22 @@ externalAPIEnabled && MiddlewareRegistry.register(store => next => action => {
|
||||
break;
|
||||
}
|
||||
|
||||
case ENDPOINT_MESSAGE_RECEIVED: {
|
||||
const { participant, data } = action;
|
||||
|
||||
if (data?.name === ENDPOINT_TEXT_MESSAGE_NAME) {
|
||||
sendEvent(
|
||||
store,
|
||||
ENDPOINT_TEXT_MESSAGE_RECEIVED,
|
||||
/* data */ {
|
||||
message: data.text,
|
||||
senderId: participant.getId()
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ENTER_PICTURE_IN_PICTURE:
|
||||
sendEvent(store, type, /* data */ {});
|
||||
break;
|
||||
@@ -419,24 +436,6 @@ function _unregisterForNativeEvents() {
|
||||
function _registerForEndpointTextMessages(store: IStore) {
|
||||
const conference = getCurrentConference(store.getState());
|
||||
|
||||
conference?.on(
|
||||
JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
|
||||
(...args: any[]) => {
|
||||
if (args && args.length >= 2) {
|
||||
const [ sender, eventData ] = args;
|
||||
|
||||
if (eventData.name === ENDPOINT_TEXT_MESSAGE_NAME) {
|
||||
sendEvent(
|
||||
store,
|
||||
ENDPOINT_TEXT_MESSAGE_RECEIVED,
|
||||
/* data */ {
|
||||
message: eventData.text,
|
||||
senderId: sender._id
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
conference?.on(
|
||||
JitsiConferenceEvents.MESSAGE_RECEIVED,
|
||||
(id: string, message: string, timestamp: number) => {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { isUnsafeRoomWarningEnabled } from '../../../prejoin/functions';
|
||||
// @ts-ignore
|
||||
import WelcomePage from '../../../welcome/components/WelcomePage';
|
||||
import { isWelcomePageEnabled } from '../../../welcome/functions';
|
||||
import Whiteboard from '../../../whiteboard/components/native/Whiteboard';
|
||||
import { _ROOT_NAVIGATION_READY } from '../actionTypes';
|
||||
import { rootNavigationRef } from '../rootNavigationContainerRef';
|
||||
import { screen } from '../routes';
|
||||
@@ -23,7 +24,8 @@ import {
|
||||
navigationContainerTheme,
|
||||
preJoinScreenOptions,
|
||||
unsafeMeetingScreenOptions,
|
||||
welcomeScreenOptions
|
||||
welcomeScreenOptions,
|
||||
whiteboardScreenOptions
|
||||
} from '../screenOptions';
|
||||
|
||||
import ConnectingPage from './ConnectingPage';
|
||||
@@ -94,6 +96,10 @@ const RootNavigationContainer = ({ dispatch, isUnsafeRoomWarningAvailable, isWel
|
||||
component = { ConnectingPage }
|
||||
name = { screen.connecting }
|
||||
options = { connectingScreenOptions } />
|
||||
<RootStack.Screen // @ts-ignore
|
||||
component = { Whiteboard }
|
||||
name = { screen.conference.whiteboard }
|
||||
options = { whiteboardScreenOptions } />
|
||||
<RootStack.Screen
|
||||
component = { Prejoin }
|
||||
name = { screen.preJoin }
|
||||
|
||||
@@ -16,7 +16,7 @@ import Conference from '../../../../../conference/components/native/Conference';
|
||||
// @ts-ignore
|
||||
import CarMode from '../../../../../conference/components/native/carmode/CarMode';
|
||||
// @ts-ignore
|
||||
import { getDisablePolls } from '../../../../../conference/functions';
|
||||
import { arePollsDisabled } from '../../../../../conference/functions';
|
||||
// @ts-ignore
|
||||
import SharedDocument from '../../../../../etherpad/components/native/SharedDocument';
|
||||
// @ts-ignore
|
||||
@@ -81,7 +81,7 @@ const ConferenceStack = createStackNavigator();
|
||||
|
||||
|
||||
const ConferenceNavigationContainer = () => {
|
||||
const isPollsDisabled = useSelector(getDisablePolls);
|
||||
const isPollsDisabled = useSelector(arePollsDisabled);
|
||||
let ChatScreen;
|
||||
let chatScreenName;
|
||||
let chatTitleString;
|
||||
|
||||
@@ -11,6 +11,7 @@ import { getFeatureFlag } from '../../base/flags/functions';
|
||||
import { IconCloseLarge } from '../../base/icons/svg';
|
||||
import { toState } from '../../base/redux/functions';
|
||||
import { cancelKnocking } from '../../lobby/actions.native';
|
||||
import { isPrejoinEnabledInConfig } from '../../prejoin/functions';
|
||||
|
||||
import HeaderNavigationButton from './components/HeaderNavigationButton';
|
||||
|
||||
@@ -50,10 +51,8 @@ export function screenHeaderCloseButton(goBack: (e?: GestureResponderEvent | Rea
|
||||
*/
|
||||
export function isPrejoinPageEnabled(stateful: IStateful) {
|
||||
const state = toState(stateful);
|
||||
const { prejoinConfig } = state['features/base/config'];
|
||||
const isPrejoinEnabledInConfig = prejoinConfig?.enabled;
|
||||
|
||||
return getFeatureFlag(state, PREJOIN_PAGE_ENABLED, isPrejoinEnabledInConfig ?? true);
|
||||
return getFeatureFlag(state, PREJOIN_PAGE_ENABLED, isPrejoinEnabledInConfig(state));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,8 @@ export const screen = {
|
||||
security: 'Security Options',
|
||||
sharedDocument: 'Shared document',
|
||||
speakerStats: 'Speaker Stats',
|
||||
subtitles: 'Subtitles'
|
||||
subtitles: 'Subtitles',
|
||||
whiteboard: 'Whiteboard'
|
||||
},
|
||||
connecting: 'Connecting',
|
||||
dialInSummary: 'Dial-In Info',
|
||||
|
||||
@@ -188,6 +188,19 @@ export const connectingScreenOptions = {
|
||||
headerShown: false
|
||||
};
|
||||
|
||||
/**
|
||||
* Screen options for the whiteboard screen.
|
||||
*/
|
||||
export const whiteboardScreenOptions = {
|
||||
gestureEnabled: true,
|
||||
headerStyle: {
|
||||
backgroundColor: BaseTheme.palette.ui01
|
||||
},
|
||||
headerTitleStyle: {
|
||||
color: BaseTheme.palette.text01
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Screen options for pre-join screen.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { DOMParser } from '@xmldom/xmldom';
|
||||
import { atob, btoa } from 'abab';
|
||||
import { Platform } from 'react-native';
|
||||
import BackgroundTimer from 'react-native-background-timer';
|
||||
import { TextDecoder, TextEncoder } from 'text-encoding';
|
||||
|
||||
import 'promise.allsettled/auto'; // Promise.allSettled.
|
||||
import 'react-native-url-polyfill/auto'; // Complete URL polyfill.
|
||||
@@ -313,4 +315,23 @@ function _visitNode(node, callback) {
|
||||
global.sessionStorage = new Storage();
|
||||
}
|
||||
|
||||
global.TextDecoder = TextDecoder;
|
||||
global.TextEncoder = TextEncoder;
|
||||
|
||||
// atob
|
||||
//
|
||||
// Required by:
|
||||
// - Strophe
|
||||
if (typeof global.atob === 'undefined') {
|
||||
global.atob = atob;
|
||||
}
|
||||
|
||||
// btoa
|
||||
//
|
||||
// Required by:
|
||||
// - Strophe
|
||||
if (typeof global.btoa === 'undefined') {
|
||||
global.btoa = btoa;
|
||||
}
|
||||
|
||||
})(global || window || this); // eslint-disable-line no-invalid-this
|
||||
|
||||
@@ -103,6 +103,13 @@ export const RAISE_HAND_NOTIFICATION_ID = 'RAISE_HAND_NOTIFICATION';
|
||||
*/
|
||||
export const SALESFORCE_LINK_NOTIFICATION_ID = 'SALESFORCE_LINK_NOTIFICATION';
|
||||
|
||||
/**
|
||||
* The identifier of the lobby notification.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
export const VISITORS_PROMOTION_NOTIFICATION_ID = 'VISITORS_PROMOTION_NOTIFICATION';
|
||||
|
||||
/**
|
||||
* Amount of participants beyond which no join notification will be emitted.
|
||||
*/
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { IStore } from '../app/types';
|
||||
import { CONFERENCE_JOIN_IN_PROGRESS } from '../base/conference/actionTypes';
|
||||
import { ENDPOINT_MESSAGE_RECEIVED, NON_PARTICIPANT_MESSAGE_RECEIVED } from '../base/conference/actionTypes';
|
||||
import { getCurrentConference } from '../base/conference/functions';
|
||||
import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import StateListenerRegistry from '../base/redux/StateListenerRegistry';
|
||||
import { playSound } from '../base/sounds/actions';
|
||||
import { INCOMING_MSG_SOUND_ID } from '../chat/constants';
|
||||
import { arePollsDisabled } from '../conference/functions.any';
|
||||
import { showNotification } from '../notifications/actions';
|
||||
import { NOTIFICATION_TIMEOUT_TYPE, NOTIFICATION_TYPE } from '../notifications/constants';
|
||||
|
||||
@@ -58,37 +58,38 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
const result = next(action);
|
||||
|
||||
switch (action.type) {
|
||||
case CONFERENCE_JOIN_IN_PROGRESS: {
|
||||
const { conference } = action;
|
||||
case ENDPOINT_MESSAGE_RECEIVED: {
|
||||
const { participant, data } = action;
|
||||
const isNewPoll = data.type === COMMAND_NEW_POLL;
|
||||
|
||||
conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
|
||||
(user: any, data: any) => {
|
||||
const isNewPoll = data.type === COMMAND_NEW_POLL;
|
||||
|
||||
_handleReceivePollsMessage({
|
||||
...data,
|
||||
senderId: isNewPoll ? user._id : undefined,
|
||||
voterId: isNewPoll ? undefined : user._id
|
||||
}, dispatch);
|
||||
});
|
||||
conference.on(JitsiConferenceEvents.NON_PARTICIPANT_MESSAGE_RECEIVED,
|
||||
(id: any, data: any) => {
|
||||
const isNewPoll = data.type === COMMAND_NEW_POLL;
|
||||
|
||||
_handleReceivePollsMessage({
|
||||
...data,
|
||||
senderId: isNewPoll ? id : undefined,
|
||||
voterId: isNewPoll ? undefined : id
|
||||
}, dispatch);
|
||||
});
|
||||
_handleReceivePollsMessage({
|
||||
...data,
|
||||
senderId: isNewPoll ? participant.getId() : undefined,
|
||||
voterId: isNewPoll ? undefined : participant.getId()
|
||||
}, dispatch, getState);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Middleware triggered when a poll is received
|
||||
case RECEIVE_POLL: {
|
||||
case NON_PARTICIPANT_MESSAGE_RECEIVED: {
|
||||
const { id, json: data } = action;
|
||||
const isNewPoll = data.type === COMMAND_NEW_POLL;
|
||||
|
||||
_handleReceivePollsMessage({
|
||||
...data,
|
||||
senderId: isNewPoll ? id : undefined,
|
||||
voterId: isNewPoll ? undefined : id
|
||||
}, dispatch, getState);
|
||||
break;
|
||||
}
|
||||
|
||||
case RECEIVE_POLL: {
|
||||
const state = getState();
|
||||
|
||||
if (arePollsDisabled(state)) {
|
||||
break;
|
||||
}
|
||||
|
||||
const isChatOpen: boolean = state['features/chat'].isOpen;
|
||||
const isPollsTabFocused: boolean = state['features/chat'].isPollsTabFocused;
|
||||
|
||||
@@ -109,10 +110,15 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
*
|
||||
* @param {Object} data - The json data carried by the polls message.
|
||||
* @param {Function} dispatch - The dispatch function.
|
||||
* @param {Function} getState - The getState function.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function _handleReceivePollsMessage(data: any, dispatch: IStore['dispatch']) {
|
||||
function _handleReceivePollsMessage(data: any, dispatch: IStore['dispatch'], getState: IStore['getState']) {
|
||||
if (arePollsDisabled(getState())) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (data.type) {
|
||||
case COMMAND_NEW_POLL: {
|
||||
const { question, answers, pollId, senderId } = data;
|
||||
|
||||
@@ -38,7 +38,7 @@ import { navigateRoot } from '../../../mobile/navigation/rootNavigationContainer
|
||||
import { screen } from '../../../mobile/navigation/routes';
|
||||
import AudioMuteButton from '../../../toolbox/components/native/AudioMuteButton';
|
||||
import VideoMuteButton from '../../../toolbox/components/native/VideoMuteButton';
|
||||
import { isDisplayNameRequired } from '../../functions';
|
||||
import { isDisplayNameRequired, isRoomNameEnabled } from '../../functions';
|
||||
import { IPrejoinProps } from '../../types';
|
||||
import { hasDisplayName } from '../../utils';
|
||||
|
||||
@@ -58,6 +58,7 @@ const Prejoin: React.FC<IPrejoinProps> = ({ navigation }: IPrejoinProps) => {
|
||||
= useSelector((state: IReduxState) => !getFeatureFlag(state, PREJOIN_PAGE_HIDE_DISPLAY_NAME, false));
|
||||
const isDisplayNameReadonly = useSelector(isNameReadOnly);
|
||||
const roomName = useSelector((state: IReduxState) => getConferenceName(state));
|
||||
const roomNameEnabled = useSelector((state: IReduxState) => isRoomNameEnabled(state));
|
||||
const participantName = localParticipant?.name;
|
||||
const [ displayName, setDisplayName ]
|
||||
= useState(participantName || '');
|
||||
@@ -168,12 +169,16 @@ const Prejoin: React.FC<IPrejoinProps> = ({ navigation }: IPrejoinProps) => {
|
||||
{
|
||||
isFocused
|
||||
&& <View style = { largeVideoContainerStyles as StyleProp<ViewStyle> }>
|
||||
<View style = { styles.displayRoomNameBackdrop as StyleProp<TextStyle> }>
|
||||
<Text
|
||||
numberOfLines = { 1 }
|
||||
style = { styles.preJoinRoomName as StyleProp<TextStyle> }>
|
||||
{ roomName }
|
||||
</Text>
|
||||
<View style = { styles.conferenceInfo as StyleProp<ViewStyle> }>
|
||||
{roomNameEnabled && (
|
||||
<View style = { styles.displayRoomNameBackdrop as StyleProp<TextStyle> }>
|
||||
<Text
|
||||
numberOfLines = { 1 }
|
||||
style = { styles.preJoinRoomName as StyleProp<TextStyle> }>
|
||||
{ roomName }
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<LargeVideo />
|
||||
</View>
|
||||
@@ -194,10 +199,15 @@ const Prejoin: React.FC<IPrejoinProps> = ({ navigation }: IPrejoinProps) => {
|
||||
placeholder = { t('dialog.enterDisplayName') }
|
||||
value = { displayName } />
|
||||
}
|
||||
{showDisplayNameError && (
|
||||
<View style = { styles.errorContainer as StyleProp<TextStyle> }>
|
||||
<Text style = { styles.error as StyleProp<TextStyle> }>{t('prejoin.errorMissingName')}</Text>
|
||||
</View>)}
|
||||
{
|
||||
showDisplayNameError && (
|
||||
<View style = { styles.errorContainer as StyleProp<TextStyle> }>
|
||||
<Text style = { styles.error as StyleProp<TextStyle> }>
|
||||
{ t('prejoin.errorMissingName') }
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
<Button
|
||||
accessibilityLabel = 'prejoin.joinMeeting'
|
||||
disabled = { showDisplayNameError }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user