Compare commits
69 Commits
7814
...
jitsi-meet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c45d87d1a | ||
|
|
7140a90201 | ||
|
|
0a846606fc | ||
|
|
68dc111e3c | ||
|
|
c81184df69 | ||
|
|
9b0747a0d9 | ||
|
|
c8cd80a8df | ||
|
|
f1d4332668 | ||
|
|
55b3256dc4 | ||
|
|
aa8bb55f3e | ||
|
|
58b73e21de | ||
|
|
b1c955890a | ||
|
|
6ab945c2cb | ||
|
|
7291e1ef00 | ||
|
|
43e075d48e | ||
|
|
885e1afdaa | ||
|
|
e2ec4842a1 | ||
|
|
ea075d9bae | ||
|
|
68f7448624 | ||
|
|
954ef6df4f | ||
|
|
6a3c12b316 | ||
|
|
5be616a224 | ||
|
|
58d8f3be12 | ||
|
|
8ae6ba76cc | ||
|
|
a06c2e056c | ||
|
|
fa0b06b859 | ||
|
|
4c3512b375 | ||
|
|
92e3a1ff99 | ||
|
|
701e3d2b43 | ||
|
|
2626a894e2 | ||
|
|
a6f6b3a2d2 | ||
|
|
05aa48774a | ||
|
|
e82fc480f0 | ||
|
|
9f8662c0a1 | ||
|
|
5b860c20b1 | ||
|
|
a4c52b02e7 | ||
|
|
73952ee1f7 | ||
|
|
0a9f6c2e4d | ||
|
|
94f9ccfe1c | ||
|
|
ff9f767cfd | ||
|
|
5a5ec9e4d9 | ||
|
|
aff671b44a | ||
|
|
495b925fa0 | ||
|
|
2f6b11a6ac | ||
|
|
2b7052995b | ||
|
|
5c69baefbf | ||
|
|
8b25265f9e | ||
|
|
f43020f650 | ||
|
|
ba95ea3ac8 | ||
|
|
7dcd9c21bc | ||
|
|
990d21038e | ||
|
|
a4d53f271f | ||
|
|
2a1f472873 | ||
|
|
8679119677 | ||
|
|
b02c072ba7 | ||
|
|
e8317fccfe | ||
|
|
bbc9c64978 | ||
|
|
8d2b8bc772 | ||
|
|
52c2911350 | ||
|
|
a1ebcd559b | ||
|
|
5bc47ec16a | ||
|
|
e1ac7d1609 | ||
|
|
8a596f1ba2 | ||
|
|
38e7c65836 | ||
|
|
9602a939d8 | ||
|
|
07b01b1371 | ||
|
|
a1549086aa | ||
|
|
7e0b00ba5f | ||
|
|
3016853d81 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -99,10 +99,6 @@ tsconfig.json
|
||||
#
|
||||
react-native-sdk/*.tgz
|
||||
react-native-sdk/android/src
|
||||
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/JitsiMeetOngoingConferenceService.java
|
||||
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/JitsiMeetReactNativePackage.java
|
||||
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/JMOngoingConferenceModule.java
|
||||
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/RNOngoingNotification.java
|
||||
react-native-sdk/images
|
||||
react-native-sdk/ios
|
||||
react-native-sdk/lang
|
||||
|
||||
@@ -19,9 +19,9 @@ buildscript {
|
||||
ext {
|
||||
kotlinVersion = "1.7.0"
|
||||
buildToolsVersion = "33.0.2"
|
||||
compileSdkVersion = 33
|
||||
compileSdkVersion = 34
|
||||
minSdkVersion = 24
|
||||
targetSdkVersion = 33
|
||||
targetSdkVersion = 34
|
||||
supportLibVersion = "28.0.0"
|
||||
|
||||
// We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
<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
|
||||
@@ -51,10 +50,6 @@
|
||||
android:name="org.jitsi.meet.sdk.JitsiMeetOngoingConferenceService"
|
||||
android:foregroundServiceType="mediaPlayback" />
|
||||
|
||||
<service
|
||||
android:name="org.jitsi.meet.sdk.JitsiMeetMediaProjectionService"
|
||||
android:foregroundServiceType="mediaProjection" />
|
||||
|
||||
<provider
|
||||
android:name="com.reactnativecommunity.webview.RNCWebViewFileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -58,8 +58,8 @@ public class JitsiMeetOngoingConferenceService extends Service
|
||||
|
||||
|
||||
public static void launch(Context context, HashMap<String, Object> extraData) {
|
||||
|
||||
NotificationUtils.createNotificationChannel((Activity) context);
|
||||
|
||||
OngoingNotification.createNotificationChannel((Activity) context);
|
||||
|
||||
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
|
||||
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* 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.NotificationChannels.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); }};
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import static org.jitsi.meet.sdk.NotificationChannels.ONGOING_CONFERENCE_CHANNEL_ID;
|
||||
|
||||
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;
|
||||
|
||||
class NotificationUtils {
|
||||
|
||||
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,8 +16,11 @@
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import static org.jitsi.meet.sdk.NotificationChannels.ONGOING_CONFERENCE_CHANNEL_ID;
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
@@ -26,7 +29,8 @@ import android.content.Intent;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
import android.os.Build;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class for creating the ongoing notification which is used with
|
||||
@@ -38,6 +42,37 @@ class OngoingNotification {
|
||||
|
||||
private static long startingTime = 0;
|
||||
|
||||
static final String ONGOING_CONFERENCE_CHANNEL_ID = "JitsiOngoingConferenceChannel";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static Notification buildOngoingConferenceNotification(Boolean isMuted, Context context) {
|
||||
|
||||
if (context == null) {
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.oney.WebRTCModule.webrtcutils.H264AndSoftwareVideoEncoderFactory;
|
||||
|
||||
import org.devio.rn.splashscreen.SplashScreenModule;
|
||||
import org.webrtc.EglBase;
|
||||
import org.webrtc.Logging;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
@@ -67,7 +68,6 @@ class ReactInstanceManagerHolder {
|
||||
new DropboxModule(reactContext),
|
||||
new ExternalAPIModule(reactContext),
|
||||
new JavaScriptSandboxModule(reactContext),
|
||||
new JitsiMeetMediaProjectionModule(reactContext),
|
||||
new LocaleDetector(reactContext),
|
||||
new LogBridgeModule(reactContext),
|
||||
new SplashScreenModule(reactContext),
|
||||
@@ -241,6 +241,8 @@ class ReactInstanceManagerHolder {
|
||||
|
||||
options.videoDecoderFactory = new H264AndSoftwareVideoDecoderFactory(eglContext);
|
||||
options.videoEncoderFactory = new H264AndSoftwareVideoEncoderFactory(eglContext);
|
||||
options.enableMediaProjectionService = true;
|
||||
// options.loggingSeverity = Logging.Severity.LS_INFO;
|
||||
|
||||
Log.d(TAG, "initializing RN with Activity");
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ import {
|
||||
setVideoMuted,
|
||||
setVideoUnmutePermissions
|
||||
} from './react/features/base/media/actions';
|
||||
import { MEDIA_TYPE } from './react/features/base/media/constants';
|
||||
import { MEDIA_TYPE, VIDEO_TYPE } from './react/features/base/media/constants';
|
||||
import {
|
||||
getStartWithAudioMuted,
|
||||
getStartWithVideoMuted,
|
||||
@@ -165,7 +165,6 @@ import { AudioMixerEffect } from './react/features/stream-effects/audio-mixer/Au
|
||||
import { createRnnoiseProcessor } from './react/features/stream-effects/rnnoise';
|
||||
import { handleToggleVideoMuted } from './react/features/toolbox/actions.any';
|
||||
import { muteLocal } from './react/features/video-menu/actions.any';
|
||||
import { iAmVisitor } from './react/features/visitors/functions';
|
||||
import UIEvents from './service/UI/UIEvents';
|
||||
|
||||
const logger = Logger.getLogger(__filename);
|
||||
@@ -405,7 +404,13 @@ function disconnect() {
|
||||
* @returns {void}
|
||||
*/
|
||||
function setGUMPendingStateOnFailedTracks(tracks) {
|
||||
const tracksTypes = tracks.map(track => track.getType());
|
||||
const tracksTypes = tracks.map(track => {
|
||||
if (track.getVideoType() === VIDEO_TYPE.DESKTOP) {
|
||||
return MEDIA_TYPE.SCREENSHARE;
|
||||
}
|
||||
|
||||
return track.getType();
|
||||
});
|
||||
const nonPendingTracks = [ MEDIA_TYPE.AUDIO, MEDIA_TYPE.VIDEO ].filter(type => !tracksTypes.includes(type));
|
||||
|
||||
APP.store.dispatch(gumPending(nonPendingTracks, IGUMPendingState.NONE));
|
||||
@@ -679,6 +684,8 @@ export default {
|
||||
startWithVideoMuted: getStartWithVideoMuted(state) || isUserInteractionRequiredForUnmute(state)
|
||||
};
|
||||
|
||||
logger.debug(`Executed conference.init with roomName: ${roomName}`);
|
||||
|
||||
this.roomName = roomName;
|
||||
|
||||
try {
|
||||
@@ -697,10 +704,6 @@ export default {
|
||||
const handleInitialTracks = (options, tracks) => {
|
||||
let localTracks = tracks;
|
||||
|
||||
// No local tracks are added when user joins as a visitor.
|
||||
if (iAmVisitor(state)) {
|
||||
return [];
|
||||
}
|
||||
if (options.startWithAudioMuted || room?.isStartAudioMuted()) {
|
||||
// Always add the track on Safari because of a known issue where audio playout doesn't happen
|
||||
// if the user joins audio and video muted, i.e., if there is no local media capture.
|
||||
@@ -1253,7 +1256,24 @@ export default {
|
||||
room = APP.connection.initJitsiConference(APP.conference.roomName, this._getConferenceOptions());
|
||||
|
||||
// Filter out the tracks that are muted (except on Safari).
|
||||
const tracks = browser.isWebKitBased() ? localTracks : localTracks.filter(track => !track.isMuted());
|
||||
let tracks = localTracks;
|
||||
|
||||
if (!browser.isWebKitBased()) {
|
||||
const mutedTrackTypes = [];
|
||||
|
||||
tracks = localTracks.filter(track => {
|
||||
if (!track.isMuted()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (track.getVideoType() !== VIDEO_TYPE.DESKTOP) {
|
||||
mutedTrackTypes.push(track.getType());
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
APP.store.dispatch(gumPending(mutedTrackTypes, IGUMPendingState.NONE));
|
||||
}
|
||||
|
||||
this._setLocalAudioVideoStreams(tracks);
|
||||
this._room = room; // FIXME do not use this
|
||||
|
||||
@@ -650,7 +650,7 @@ var config = {
|
||||
// // Whether to disable welcome page. In case it's disabled a random room
|
||||
// // will be joined when no room is specified.
|
||||
// disabled: false,
|
||||
// // If set,landing page will redirect to this URL.
|
||||
// // If set, landing page will redirect to this URL.
|
||||
// customUrl: ''
|
||||
// },
|
||||
|
||||
@@ -723,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
|
||||
@@ -1300,6 +1300,8 @@ var config = {
|
||||
// remoteVideoMenu: {
|
||||
// // Whether the remote video context menu to be rendered or not.
|
||||
// disabled: true,
|
||||
// // If set to true the 'Switch to visitor' button will be disabled.
|
||||
// disableDemote: true,
|
||||
// // If set to true the 'Kick out' button will be disabled.
|
||||
// disableKick: true,
|
||||
// // If set to true the 'Grant moderator' button will be disabled.
|
||||
@@ -1388,6 +1390,8 @@ var config = {
|
||||
|
||||
// Options related to the participants pane.
|
||||
// participantsPane: {
|
||||
// // Enables feature
|
||||
// enabled: true,
|
||||
// // Hides the moderator settings tab.
|
||||
// hideModeratorSettingsTab: false,
|
||||
// // Hides the more actions button.
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 48px;
|
||||
max-width: calc(100% - 24px);
|
||||
}
|
||||
|
||||
@keyframes hideSubject {
|
||||
|
||||
@@ -453,7 +453,7 @@ PODS:
|
||||
- react-native-video/Video (6.0.0-alpha.11):
|
||||
- PromisesSwift
|
||||
- React-Core
|
||||
- react-native-webrtc (118.0.0):
|
||||
- react-native-webrtc (118.0.2):
|
||||
- JitsiWebRTC (~> 118.0.0)
|
||||
- React-Core
|
||||
- react-native-webview (13.5.1):
|
||||
@@ -881,7 +881,7 @@ SPEC CHECKSUMS:
|
||||
react-native-slider: 1cdd6ba29675df21f30544253bf7351d3c2d68c4
|
||||
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
|
||||
react-native-video: 472b7c366eaaaa0207e546d9a50410df89790bcf
|
||||
react-native-webrtc: c8d9ad3c152105b2720ca2851d04b49659551992
|
||||
react-native-webrtc: a0a8a1730b6cc5a5bda8a6e2166a74c9b78029e2
|
||||
react-native-webview: 8baa0f5c6d336d6ba488e942bcadea5bf51f050a
|
||||
React-NativeModulesApple: 4225ac31a26696c02c54b471052b3e85e74a9a0c
|
||||
React-perflogger: cb433f318c6667060fc1f62e26eb58d6eb30a627
|
||||
|
||||
@@ -629,7 +629,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "export NODE_BINARY=node\nexport NODE_ARGS=\"--max_old_space_size=4096\"\n../../node_modules/react-native/scripts/react-native-xcode.sh\n";
|
||||
shellScript = "WITH_ENVIRONMENT=\"../../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
|
||||
};
|
||||
DE9A016B289A9A9A00E41CBB /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,6 +305,8 @@
|
||||
"contactSupport": "Contact support",
|
||||
"copied": "Copied",
|
||||
"copy": "Copy",
|
||||
"demoteParticipantDialog": "Are you sure you want to move this participant to visitor?",
|
||||
"demoteParticipantTitle": "Move to visitor",
|
||||
"dismiss": "Dismiss",
|
||||
"displayNameRequired": "Hi! What’s your name?",
|
||||
"done": "Done",
|
||||
@@ -813,6 +815,7 @@
|
||||
"videoUnmuteBlockedDescription": "Camera unmute and desktop sharing operation have been temporarily blocked because of system limits.",
|
||||
"videoUnmuteBlockedTitle": "Camera unmute and desktop sharing blocked!",
|
||||
"viewLobby": "View lobby",
|
||||
"viewVisitors": "View visitors",
|
||||
"waitingParticipants": "{{waitingParticipants}} people",
|
||||
"whiteboardLimitDescription": "Please save your progress, as the user limit will soon be reached and the whiteboard will close.",
|
||||
"whiteboardLimitTitle": "Whiteboard usage"
|
||||
@@ -1419,6 +1422,7 @@
|
||||
},
|
||||
"videothumbnail": {
|
||||
"connectionInfo": "Connection Info",
|
||||
"demote": "Move to visitor",
|
||||
"domute": "Mute",
|
||||
"domuteOthers": "Mute everyone else",
|
||||
"domuteVideo": "Disable camera",
|
||||
@@ -1473,6 +1477,7 @@
|
||||
"chatIndicator": "(visitor)",
|
||||
"labelTooltip": "Number of visitors: {{count}}",
|
||||
"notification": {
|
||||
"demoteDescription": "Sent here by {{actor}}, raise your hand to participate",
|
||||
"description": "To participate raise your hand",
|
||||
"title": "You are a visitor in the meeting"
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
} from '../../react/features/base/conference/actions';
|
||||
import { isMobileBrowser } from '../../react/features/base/environment/utils';
|
||||
import { setColorAlpha } from '../../react/features/base/util/helpers';
|
||||
import { sanitizeUrl } from '../../react/features/base/util/uri';
|
||||
import { setDocumentUrl } from '../../react/features/etherpad/actions';
|
||||
import { setFilmstripVisible } from '../../react/features/filmstrip/actions.any';
|
||||
import {
|
||||
@@ -135,14 +136,16 @@ UI.unbindEvents = () => {
|
||||
* @param {string} name etherpad id
|
||||
*/
|
||||
UI.initEtherpad = name => {
|
||||
if (etherpadManager || !config.etherpad_base || !name) {
|
||||
const etherpadBaseUrl = sanitizeUrl(config.etherpad_base);
|
||||
|
||||
if (etherpadManager || !etherpadBaseUrl || !name) {
|
||||
return;
|
||||
}
|
||||
logger.log('Etherpad is enabled');
|
||||
|
||||
etherpadManager = new EtherpadManager(eventEmitter);
|
||||
|
||||
const url = new URL(name, config.etherpad_base);
|
||||
const url = new URL(name, etherpadBaseUrl);
|
||||
|
||||
APP.store.dispatch(setDocumentUrl(url.toString()));
|
||||
|
||||
|
||||
867
package-lock.json
generated
867
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@@ -17,12 +17,13 @@
|
||||
"readmeFilename": "README.md",
|
||||
"dependencies": {
|
||||
"@amplitude/react-native": "2.7.0",
|
||||
"@braintree/sanitize-url": "7.0.0",
|
||||
"@emotion/react": "11.10.6",
|
||||
"@emotion/styled": "11.10.6",
|
||||
"@giphy/js-fetch-api": "4.7.1",
|
||||
"@giphy/react-components": "6.8.1",
|
||||
"@giphy/react-native-sdk": "2.3.0",
|
||||
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.16/jitsi-excalidraw-0.0.16.tgz",
|
||||
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.17/jitsi-excalidraw-0.0.17.tgz",
|
||||
"@jitsi/js-utils": "2.2.1",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
"@jitsi/rnnoise-wasm": "0.1.0",
|
||||
@@ -30,7 +31,6 @@
|
||||
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
|
||||
"@microsoft/microsoft-graph-client": "3.0.1",
|
||||
"@mui/material": "5.12.1",
|
||||
"@mui/styles": "5.12.0",
|
||||
"@react-native-async-storage/async-storage": "1.19.4",
|
||||
"@react-native-community/clipboard": "1.5.1",
|
||||
"@react-native-community/netinfo": "11.1.0",
|
||||
@@ -67,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/v1773.0.0+cc9b0e60/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1789.0.0+a8f8666b/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -106,7 +106,7 @@
|
||||
"react-native-url-polyfill": "2.0.0",
|
||||
"react-native-video": "6.0.0-alpha.11",
|
||||
"react-native-watch-connectivity": "1.1.0",
|
||||
"react-native-webrtc": "118.0.0",
|
||||
"react-native-webrtc": "118.0.2",
|
||||
"react-native-webview": "13.5.1",
|
||||
"react-native-youtube-iframe": "2.3.0",
|
||||
"react-redux": "7.2.9",
|
||||
@@ -118,7 +118,7 @@
|
||||
"seamless-scroll-polyfill": "2.1.8",
|
||||
"semver": "7.5.4",
|
||||
"text-encoding": "0.7.0",
|
||||
"tss-react": "4.4.4",
|
||||
"tss-react": "4.9.4",
|
||||
"util": "0.12.1",
|
||||
"uuid": "8.3.2",
|
||||
"wasm-check": "2.0.1",
|
||||
@@ -132,7 +132,7 @@
|
||||
"@babel/plugin-proposal-export-default-from": "7.22.5",
|
||||
"@babel/preset-env": "7.21.5",
|
||||
"@babel/preset-react": "7.16.0",
|
||||
"@jitsi/eslint-config": "4.1.5",
|
||||
"@jitsi/eslint-config": "4.1.10",
|
||||
"@types/amplitude-js": "8.16.5",
|
||||
"@types/audioworklet": "0.0.29",
|
||||
"@types/dom-screen-wake-lock": "1.0.1",
|
||||
@@ -164,7 +164,7 @@
|
||||
"css-loader": "6.8.1",
|
||||
"eslint": "8.40.0",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-jsdoc": "37.0.3",
|
||||
"eslint-plugin-jsdoc": "46.2.6",
|
||||
"eslint-plugin-react": "7.32.2",
|
||||
"eslint-plugin-react-native": "4.0.0",
|
||||
"eslint-plugin-typescript-sort-keys": "2.3.0",
|
||||
|
||||
@@ -133,7 +133,7 @@ dependencies {
|
||||
|
||||
if (isNewArchitectureEnabled()) {
|
||||
react {
|
||||
jsRootDir = file("../src/")
|
||||
jsRootDir = file("../")
|
||||
libraryName = "JitsiMeetReactNative"
|
||||
codegenJavaPackageName = "org.jitsi.meet.sdk"
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
|
||||
|
||||
@ReactModule(name = JMOngoingConferenceModule.NAME)
|
||||
class JMOngoingConferenceModule
|
||||
extends ReactContextBaseJavaModule {
|
||||
|
||||
public static final String NAME = "JMOngoingConference";
|
||||
|
||||
public JMOngoingConferenceModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void launch() {
|
||||
Context context = getReactApplicationContext();
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
|
||||
JitsiMeetOngoingConferenceService.launch(context, currentActivity);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void abort() {
|
||||
Context context = getReactApplicationContext();
|
||||
|
||||
JitsiMeetOngoingConferenceService.abort(context);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* This class implements an Android {@link Service}, a foreground one specifically, and it's
|
||||
* responsible for presenting an ongoing notification when a conference is in progress.
|
||||
* The service will help keep the app running while in the background.
|
||||
*
|
||||
* See: https://developer.android.com/guide/components/services
|
||||
*/
|
||||
public class JitsiMeetOngoingConferenceService extends Service {
|
||||
private static final String TAG = JitsiMeetOngoingConferenceService.class.getSimpleName();
|
||||
|
||||
public static void launch(Context context, Activity currentActivity) {
|
||||
|
||||
RNOngoingNotification.createOngoingConferenceNotificationChannel(currentActivity);
|
||||
|
||||
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
|
||||
|
||||
ComponentName componentName;
|
||||
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
componentName = context.startForegroundService(intent);
|
||||
} else {
|
||||
componentName = context.startService(intent);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
// Avoid crashing due to ForegroundServiceStartNotAllowedException (API level 31).
|
||||
// See: https://developer.android.com/guide/components/foreground-services#background-start-restrictions
|
||||
JitsiMeetLogger.w(TAG + " Ongoing conference service not started", e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (componentName == null) {
|
||||
JitsiMeetLogger.w(TAG + " Ongoing conference service not started");
|
||||
}
|
||||
}
|
||||
|
||||
public static void abort(Context context) {
|
||||
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
|
||||
context.stopService(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
Notification notification = RNOngoingNotification.buildOngoingConferenceNotification(this);
|
||||
|
||||
if (notification == null) {
|
||||
stopSelf();
|
||||
JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null");
|
||||
} else {
|
||||
startForeground(RNOngoingNotification.NOTIFICATION_ID, notification);
|
||||
JitsiMeetLogger.i(TAG + " Service started");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class JitsiMeetReactNativePackage implements ReactPackage {
|
||||
@NonNull
|
||||
@Override
|
||||
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
|
||||
List<NativeModule> modules
|
||||
= new ArrayList<>(Arrays.<NativeModule>asList(
|
||||
new AndroidSettingsModule(reactContext),
|
||||
new AppInfoModule(reactContext),
|
||||
new AudioModeModule(reactContext),
|
||||
new JMOngoingConferenceModule(reactContext),
|
||||
new JavaScriptSandboxModule(reactContext),
|
||||
new LocaleDetector(reactContext),
|
||||
new LogBridgeModule(reactContext),
|
||||
new PictureInPictureModule(reactContext),
|
||||
new ProximityModule(reactContext),
|
||||
new org.jitsi.meet.sdk.net.NAT64AddrInfoModule(reactContext)
|
||||
));
|
||||
return modules;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Helper class for creating the ongoing notification which is used with
|
||||
* {@link JitsiMeetOngoingConferenceService}. It allows the user to easily get back to the app
|
||||
* and to hangup from within the notification itself.
|
||||
*/
|
||||
class RNOngoingNotification {
|
||||
private static final String TAG = RNOngoingNotification.class.getSimpleName();
|
||||
|
||||
static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
|
||||
|
||||
static void createOngoingConferenceNotificationChannel(Activity currentActivity) {
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentActivity == null) {
|
||||
JitsiMeetLogger.w(TAG + " Cannot create notification channel: no current context");
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationManager notificationManager
|
||||
= (NotificationManager) currentActivity.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
NotificationChannel channel
|
||||
= notificationManager.getNotificationChannel("JitsiOngoingConferenceChannel");
|
||||
if (channel != null) {
|
||||
// The channel was already created, no need to do it again.
|
||||
return;
|
||||
}
|
||||
|
||||
channel = new NotificationChannel("JitsiOngoingConferenceChannel", currentActivity.getString(R.string.ongoing_notification_channel_name), NotificationManager.IMPORTANCE_DEFAULT);
|
||||
channel.enableLights(false);
|
||||
channel.enableVibration(false);
|
||||
channel.setShowBadge(false);
|
||||
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
static Notification buildOngoingConferenceNotification(Context context) {
|
||||
|
||||
if (context == null) {
|
||||
JitsiMeetLogger.w(TAG + " Cannot create notification: no current context");
|
||||
return null;
|
||||
}
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "JitsiOngoingConferenceChannel");
|
||||
|
||||
builder
|
||||
.setCategory(NotificationCompat.CATEGORY_CALL)
|
||||
.setContentTitle(context.getString(R.string.ongoing_notification_title))
|
||||
.setContentText(context.getString(R.string.ongoing_notification_text))
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.setOngoing(true)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setUsesChronometer(true)
|
||||
.setAutoCancel(false)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setSmallIcon(context.getResources().getIdentifier("ic_notification", "drawable", context.getPackageName()));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
224
react-native-sdk/package-lock.json
generated
224
react-native-sdk/package-lock.json
generated
@@ -10,7 +10,7 @@
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "2.1.3",
|
||||
"@jitsi/js-utils": "2.2.1",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
"@jitsi/rtcstats": "9.5.1",
|
||||
"@react-navigation/bottom-tabs": "6.5.8",
|
||||
@@ -19,7 +19,7 @@
|
||||
"@react-navigation/native": "6.1.7",
|
||||
"@react-navigation/stack": "6.3.17",
|
||||
"@xmldom/xmldom": "0.8.7",
|
||||
"base64-js": "1.3.1",
|
||||
"base64-js": "1.5.1",
|
||||
"grapheme-splitter": "1.0.4",
|
||||
"i18n-iso-countries": "6.8.0",
|
||||
"i18next": "17.0.6",
|
||||
@@ -27,7 +27,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/v1687.0.0+cafe30d7/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1789.0.0+a8f8666b/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -37,7 +37,6 @@
|
||||
"react-emoji-render": "1.2.4",
|
||||
"react-i18next": "10.11.4",
|
||||
"react-linkify": "1.0.0-alpha",
|
||||
"react-native-callstats": "3.73.22",
|
||||
"react-native-dialog": "https://github.com/jitsi/react-native-dialog/releases/download/v9.2.2-jitsi.1/react-native-dialog-9.2.2.tgz",
|
||||
"react-native-svg-transformer": "1.1.0",
|
||||
"react-native-tab-view": "3.5.2",
|
||||
@@ -53,12 +52,13 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@amplitude/react-native": "2.7.0",
|
||||
"@braintree/sanitize-url": "7.0.0",
|
||||
"@giphy/react-native-sdk": "2.3.0",
|
||||
"@react-native-async-storage/async-storage": "1.19.3",
|
||||
"@react-native-async-storage/async-storage": "1.19.4",
|
||||
"@react-native-community/clipboard": "1.5.1",
|
||||
"@react-native-community/netinfo": "9.4.1",
|
||||
"@react-native-community/netinfo": "11.1.0",
|
||||
"@react-native-community/slider": "4.4.3",
|
||||
"@react-native-google-signin/google-signin": "10.0.1",
|
||||
"@react-native-google-signin/google-signin": "10.1.0",
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-background-timer": "2.4.1",
|
||||
@@ -69,7 +69,7 @@
|
||||
"react-native-get-random-values": "1.9.0",
|
||||
"react-native-immersive-mode": "2.0.1",
|
||||
"react-native-keep-awake": "4.0.0",
|
||||
"react-native-orientation-locker": "1.5.0",
|
||||
"react-native-orientation-locker": "1.6.0",
|
||||
"react-native-pager-view": "6.2.0",
|
||||
"react-native-paper": "5.10.3",
|
||||
"react-native-performance": "5.0.0",
|
||||
@@ -78,10 +78,11 @@
|
||||
"react-native-sound": "0.11.2",
|
||||
"react-native-splash-screen": "3.3.0",
|
||||
"react-native-svg": "13.13.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": "111.0.3",
|
||||
"react-native-webview": "13.5.1"
|
||||
"react-native-webrtc": "118.0.2",
|
||||
"react-native-webview": "13.5.1",
|
||||
"text-encoding": "0.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
@@ -396,13 +397,13 @@
|
||||
"integrity": "sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w=="
|
||||
},
|
||||
"node_modules/@jitsi/js-utils": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-2.1.3.tgz",
|
||||
"integrity": "sha512-fXoNLu2JHQGPgzjCDG5qWPPStiXI+AxSzu1JIVY4dMULIFsw4a+doMgcjTIlSfB393J2xccKQYwZSejZUn9MEw==",
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-2.2.1.tgz",
|
||||
"integrity": "sha512-4Ia4hWO7aTMGbYftzeBr+IHIu5YxiWwTlhsSK34z6925oNAUNI863WgYYGTcXkW/1yuM6LBZrnuZBySDqosISA==",
|
||||
"dependencies": {
|
||||
"@hapi/bourne": "^3.0.0",
|
||||
"bowser": "2.7.0",
|
||||
"js-md5": "0.7.3"
|
||||
"js-md5": "0.7.3",
|
||||
"ua-parser-js": "1.0.35"
|
||||
}
|
||||
},
|
||||
"node_modules/@jitsi/js-utils/node_modules/js-md5": {
|
||||
@@ -443,14 +444,6 @@
|
||||
"sdp-verify": "checker.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@jitsi/sdp-simulcast": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/sdp-simulcast/-/sdp-simulcast-0.4.0.tgz",
|
||||
"integrity": "sha512-jXJM3/XM853UwPlxhSJx5Fc13G4158RIeTgjis3lA286Y7lp18GOR0xFlRvx/5UyhtE3qT2NzSmAwR+CpJohFw==",
|
||||
"dependencies": {
|
||||
"sdp-transform": "2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||
@@ -987,15 +980,24 @@
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/base-64": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
|
||||
"integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA=="
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
|
||||
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
@@ -1010,11 +1012,6 @@
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
|
||||
},
|
||||
"node_modules/bowser": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/bowser/-/bowser-2.7.0.tgz",
|
||||
"integrity": "sha512-aIlMvstvu8x+34KEiOHD3AsBgdrzg6sxALYiukOWhFvGMbQI6TRP/iY0LMhUrHs56aD6P1G0Z7h45PUJaa5m9w=="
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
@@ -2443,14 +2440,6 @@
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/jssha": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/jssha/-/jssha-3.3.0.tgz",
|
||||
"integrity": "sha512-w9OtT4ALL+fbbwG3gw7erAO0jvS5nfvrukGPMWIAoea359B26ALXGpzy4YJSp9yGnpUvuvOw1nSjSoHDfWSr1w==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/jwt-decode": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz",
|
||||
@@ -2481,16 +2470,15 @@
|
||||
},
|
||||
"node_modules/lib-jitsi-meet": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1687.0.0+cafe30d7/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-ky3q5gLeLDHFtenXe7+QlxAh33opz0a3bqEp8svA9urR1AICUi0QthOwmUerTdfSRFU3wfVObF9axlX1fbHZ3A==",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1789.0.0+a8f8666b/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-nWHUC16US3x9dHz8/auJk8qAsiyvisWr954e5LcaFIImwR8ArD8ZVgyMMeQcnH+a8tFmzSB2NEZR4o/v0lKV9Q==",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "2.1.3",
|
||||
"@jitsi/js-utils": "2.2.1",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
"@jitsi/rtcstats": "9.5.1",
|
||||
"@jitsi/rtcstats": "9.7.0",
|
||||
"@jitsi/sdp-interop": "git+https://github.com/jitsi/sdp-interop#3d49eb4aa26863a3f8d32d7581cdb4321244266b",
|
||||
"@jitsi/sdp-simulcast": "0.4.0",
|
||||
"@testrtc/watchrtc-sdk": "1.36.3",
|
||||
"async-es": "3.2.4",
|
||||
"base64-js": "1.3.1",
|
||||
@@ -2509,6 +2497,30 @@
|
||||
"webrtc-adapter": "8.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/lib-jitsi-meet/node_modules/@jitsi/rtcstats": {
|
||||
"version": "9.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.7.0.tgz",
|
||||
"integrity": "sha512-OPURb3GO7zciPYoF/5IWLl2VVd90GD9KFlOnLQPalI2gUQDfxYNqn7JqeKAug1peTgml6I2o55lWYINuzPETWQ==",
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "^2.2.0",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
"sdp": "^3.0.3",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/lib-jitsi-meet/node_modules/@jitsi/rtcstats/node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/lib-jitsi-meet/node_modules/base64-js": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
|
||||
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
|
||||
},
|
||||
"node_modules/lib-jitsi-meet/node_modules/uuid": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz",
|
||||
@@ -3054,15 +3066,6 @@
|
||||
"tlds": "^1.199.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-callstats": {
|
||||
"version": "3.73.22",
|
||||
"resolved": "https://registry.npmjs.org/react-native-callstats/-/react-native-callstats-3.73.22.tgz",
|
||||
"integrity": "sha512-1l1n9XIca8VT7Vp/xaQY8grPDmgVp++nx0cYhelOWyn4TwBrWxIOPU1Ok4ODrNiYtnsh+/Dyqq+lSSwZksr7LA==",
|
||||
"dependencies": {
|
||||
"base-64": "0.1.0",
|
||||
"jssha": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-dialog": {
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://github.com/jitsi/react-native-dialog/releases/download/v9.2.2-jitsi.1/react-native-dialog-9.2.2.tgz",
|
||||
@@ -3570,6 +3573,24 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/ua-parser-js": {
|
||||
"version": "1.0.35",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.35.tgz",
|
||||
"integrity": "sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/ua-parser-js"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/faisalman"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/uc.micro": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
|
||||
@@ -4044,13 +4065,13 @@
|
||||
"integrity": "sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w=="
|
||||
},
|
||||
"@jitsi/js-utils": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-2.1.3.tgz",
|
||||
"integrity": "sha512-fXoNLu2JHQGPgzjCDG5qWPPStiXI+AxSzu1JIVY4dMULIFsw4a+doMgcjTIlSfB393J2xccKQYwZSejZUn9MEw==",
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-2.2.1.tgz",
|
||||
"integrity": "sha512-4Ia4hWO7aTMGbYftzeBr+IHIu5YxiWwTlhsSK34z6925oNAUNI863WgYYGTcXkW/1yuM6LBZrnuZBySDqosISA==",
|
||||
"requires": {
|
||||
"@hapi/bourne": "^3.0.0",
|
||||
"bowser": "2.7.0",
|
||||
"js-md5": "0.7.3"
|
||||
"js-md5": "0.7.3",
|
||||
"ua-parser-js": "1.0.35"
|
||||
},
|
||||
"dependencies": {
|
||||
"js-md5": {
|
||||
@@ -4091,14 +4112,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@jitsi/sdp-simulcast": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/sdp-simulcast/-/sdp-simulcast-0.4.0.tgz",
|
||||
"integrity": "sha512-jXJM3/XM853UwPlxhSJx5Fc13G4158RIeTgjis3lA286Y7lp18GOR0xFlRvx/5UyhtE3qT2NzSmAwR+CpJohFw==",
|
||||
"requires": {
|
||||
"sdp-transform": "2.3.0"
|
||||
}
|
||||
},
|
||||
"@jridgewell/gen-mapping": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||
@@ -4439,15 +4452,10 @@
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"base-64": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
|
||||
"integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA=="
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
|
||||
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
@@ -4459,11 +4467,6 @@
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
|
||||
},
|
||||
"bowser": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/bowser/-/bowser-2.7.0.tgz",
|
||||
"integrity": "sha512-aIlMvstvu8x+34KEiOHD3AsBgdrzg6sxALYiukOWhFvGMbQI6TRP/iY0LMhUrHs56aD6P1G0Z7h45PUJaa5m9w=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
@@ -5448,11 +5451,6 @@
|
||||
"universalify": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"jssha": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/jssha/-/jssha-3.3.0.tgz",
|
||||
"integrity": "sha512-w9OtT4ALL+fbbwG3gw7erAO0jvS5nfvrukGPMWIAoea359B26ALXGpzy4YJSp9yGnpUvuvOw1nSjSoHDfWSr1w=="
|
||||
},
|
||||
"jwt-decode": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz",
|
||||
@@ -5476,14 +5474,13 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1687.0.0+cafe30d7/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-ky3q5gLeLDHFtenXe7+QlxAh33opz0a3bqEp8svA9urR1AICUi0QthOwmUerTdfSRFU3wfVObF9axlX1fbHZ3A==",
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1789.0.0+a8f8666b/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-nWHUC16US3x9dHz8/auJk8qAsiyvisWr954e5LcaFIImwR8ArD8ZVgyMMeQcnH+a8tFmzSB2NEZR4o/v0lKV9Q==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "2.1.3",
|
||||
"@jitsi/js-utils": "2.2.1",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
"@jitsi/rtcstats": "9.5.1",
|
||||
"@jitsi/rtcstats": "9.7.0",
|
||||
"@jitsi/sdp-interop": "git+https://github.com/jitsi/sdp-interop#3d49eb4aa26863a3f8d32d7581cdb4321244266b",
|
||||
"@jitsi/sdp-simulcast": "0.4.0",
|
||||
"@testrtc/watchrtc-sdk": "1.36.3",
|
||||
"async-es": "3.2.4",
|
||||
"base64-js": "1.3.1",
|
||||
@@ -5502,6 +5499,29 @@
|
||||
"webrtc-adapter": "8.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jitsi/rtcstats": {
|
||||
"version": "9.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.7.0.tgz",
|
||||
"integrity": "sha512-OPURb3GO7zciPYoF/5IWLl2VVd90GD9KFlOnLQPalI2gUQDfxYNqn7JqeKAug1peTgml6I2o55lWYINuzPETWQ==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "^2.2.0",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
"sdp": "^3.0.3",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
|
||||
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz",
|
||||
@@ -5902,15 +5922,6 @@
|
||||
"tlds": "^1.199.0"
|
||||
}
|
||||
},
|
||||
"react-native-callstats": {
|
||||
"version": "3.73.22",
|
||||
"resolved": "https://registry.npmjs.org/react-native-callstats/-/react-native-callstats-3.73.22.tgz",
|
||||
"integrity": "sha512-1l1n9XIca8VT7Vp/xaQY8grPDmgVp++nx0cYhelOWyn4TwBrWxIOPU1Ok4ODrNiYtnsh+/Dyqq+lSSwZksr7LA==",
|
||||
"requires": {
|
||||
"base-64": "0.1.0",
|
||||
"jssha": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"react-native-dialog": {
|
||||
"version": "https://github.com/jitsi/react-native-dialog/releases/download/v9.2.2-jitsi.1/react-native-dialog-9.2.2.tgz",
|
||||
"integrity": "sha512-MKbuBbovO8eGiAM9i6o0nrdBXivhRpzPQ+aVBXGJEPMH7RrCSNUKaCoEpkjfGHlTxjZimi6WjDCjjzCRSHlV1A=="
|
||||
@@ -6263,6 +6274,11 @@
|
||||
"is-typed-array": "^1.1.9"
|
||||
}
|
||||
},
|
||||
"ua-parser-js": {
|
||||
"version": "1.0.35",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.35.tgz",
|
||||
"integrity": "sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA=="
|
||||
},
|
||||
"uc.micro": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"url": "git+https://github.com/jitsi/jitsi-meet.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "2.1.3",
|
||||
"@jitsi/js-utils": "2.2.1",
|
||||
"@jitsi/logger": "2.0.2",
|
||||
"@jitsi/rtcstats": "9.5.1",
|
||||
"@react-navigation/bottom-tabs": "6.5.8",
|
||||
@@ -20,7 +20,7 @@
|
||||
"@react-navigation/native": "6.1.7",
|
||||
"@react-navigation/stack": "6.3.17",
|
||||
"@xmldom/xmldom": "0.8.7",
|
||||
"base64-js": "1.3.1",
|
||||
"base64-js": "1.5.1",
|
||||
"grapheme-splitter": "1.0.4",
|
||||
"i18n-iso-countries": "6.8.0",
|
||||
"i18next": "17.0.6",
|
||||
@@ -28,7 +28,7 @@
|
||||
"i18next-http-backend": "^2.2.1",
|
||||
"js-sha512": "0.8.0",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1687.0.0+cafe30d7/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1789.0.0+a8f8666b/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -53,12 +53,13 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@amplitude/react-native": "2.7.0",
|
||||
"@braintree/sanitize-url": "7.0.0",
|
||||
"@giphy/react-native-sdk": "2.3.0",
|
||||
"@react-native-async-storage/async-storage": "1.19.3",
|
||||
"@react-native-async-storage/async-storage": "1.19.4",
|
||||
"@react-native-community/clipboard": "1.5.1",
|
||||
"@react-native-community/netinfo": "9.4.1",
|
||||
"@react-native-community/netinfo": "11.1.0",
|
||||
"@react-native-community/slider": "4.4.3",
|
||||
"@react-native-google-signin/google-signin": "10.0.1",
|
||||
"@react-native-google-signin/google-signin": "10.1.0",
|
||||
"react-native": "*",
|
||||
"react": "*",
|
||||
"react-native-background-timer": "2.4.1",
|
||||
@@ -72,16 +73,17 @@
|
||||
"react-native-pager-view": "6.2.0",
|
||||
"react-native-paper": "5.10.3",
|
||||
"react-native-performance": "5.0.0",
|
||||
"react-native-orientation-locker": "1.5.0",
|
||||
"react-native-orientation-locker": "1.6.0",
|
||||
"react-native-safe-area-context": "4.7.1",
|
||||
"react-native-screens": "3.24.0",
|
||||
"react-native-sound": "0.11.2",
|
||||
"react-native-splash-screen": "3.3.0",
|
||||
"react-native-svg": "13.13.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": "111.0.3",
|
||||
"react-native-webview": "13.5.1"
|
||||
"react-native-webrtc": "118.0.2",
|
||||
"react-native-webview": "13.5.1",
|
||||
"text-encoding": "0.7.0"
|
||||
},
|
||||
"overrides": {
|
||||
"@xmldom/xmldom": "0.8.7"
|
||||
@@ -96,4 +98,4 @@
|
||||
"keywords": [
|
||||
"react-native"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ export default class AmplitudeHandler extends AbstractHandler {
|
||||
/**
|
||||
* Creates new instance of the Amplitude analytics handler.
|
||||
*
|
||||
* @param {Object} options -
|
||||
* @param {Object} options - The amplitude options.
|
||||
* @param {string} options.amplitudeAPPKey - The Amplitude app key required by the Amplitude API.
|
||||
* @param {boolean} options.amplitudeIncludeUTM - Whether to include UTM parameters
|
||||
* in the Amplitude events.
|
||||
|
||||
@@ -14,7 +14,7 @@ class GoogleAnalyticsHandler extends AbstractHandler {
|
||||
/**
|
||||
* Creates new instance of the GA analytics handler.
|
||||
*
|
||||
* @param {Object} options -
|
||||
* @param {Object} options - The Google Analytics options.
|
||||
* @param {string} options.googleAnalyticsTrackingId - The GA track id
|
||||
* required by the GA API.
|
||||
*/
|
||||
@@ -34,7 +34,7 @@ class GoogleAnalyticsHandler extends AbstractHandler {
|
||||
/**
|
||||
* Initializes the ga object.
|
||||
*
|
||||
* @param {Object} options -
|
||||
* @param {Object} options - The Google Analytics options.
|
||||
* @param {string} options.googleAnalyticsTrackingId - The GA track id
|
||||
* required by the GA API.
|
||||
* @returns {void}
|
||||
|
||||
@@ -13,7 +13,7 @@ export default class MatomoHandler extends AbstractHandler {
|
||||
/**
|
||||
* Creates new instance of the Matomo handler.
|
||||
*
|
||||
* @param {Object} options -
|
||||
* @param {Object} options - The matomo options.
|
||||
* @param {string} options.matomoEndpoint - The Matomo endpoint.
|
||||
* @param {string} options.matomoSiteID - The site ID.
|
||||
*/
|
||||
@@ -39,7 +39,7 @@ export default class MatomoHandler extends AbstractHandler {
|
||||
/**
|
||||
* Initializes the _paq object.
|
||||
*
|
||||
* @param {Object} options -
|
||||
* @param {Object} options - The matomo options.
|
||||
* @param {string} options.matomoEndpoint - The Matomo endpoint.
|
||||
* @param {string} options.matomoSiteID - The site ID.
|
||||
* @returns {void}
|
||||
|
||||
@@ -3,6 +3,7 @@ import '../authentication/middleware';
|
||||
import '../av-moderation/middleware';
|
||||
import '../base/conference/middleware';
|
||||
import '../base/config/middleware';
|
||||
import '../base/i18n/middleware';
|
||||
import '../base/jwt/middleware';
|
||||
import '../base/known-domains/middleware';
|
||||
import '../base/lastn/middleware';
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import '../base/app/middleware';
|
||||
import '../base/connection/middleware';
|
||||
import '../base/i18n/middleware';
|
||||
import '../base/devices/middleware';
|
||||
import '../base/media/middleware';
|
||||
import '../dynamic-branding/middleware';
|
||||
|
||||
@@ -133,7 +133,7 @@ function _upgradeRoleStarted(thenableWithCancel: Object) {
|
||||
* Hides an authentication dialog where the local participant
|
||||
* should authenticate.
|
||||
*
|
||||
* @returns {Function}.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function hideLoginDialog() {
|
||||
return hideDialog(LoginDialog);
|
||||
|
||||
@@ -18,7 +18,7 @@ interface IProps {
|
||||
* Implements the dialog that warns the user that the login will leave the conference.
|
||||
*
|
||||
* @param {Object} props - The props of the component.
|
||||
* @returns {React$Element}.
|
||||
* @returns {React$Element}
|
||||
*/
|
||||
const LoginQuestionDialog = ({ handler }: IProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -8,8 +8,15 @@ import { getReplaceParticipant } from '../config/functions';
|
||||
import { connect, disconnect, hangup } from '../connection/actions';
|
||||
import { JITSI_CONNECTION_CONFERENCE_KEY } from '../connection/constants';
|
||||
import { JitsiConferenceEvents, JitsiE2ePingEvents } from '../lib-jitsi-meet';
|
||||
import { setAudioMuted, setAudioUnmutePermissions, setVideoMuted, setVideoUnmutePermissions } from '../media/actions';
|
||||
import {
|
||||
gumPending,
|
||||
setAudioMuted,
|
||||
setAudioUnmutePermissions,
|
||||
setVideoMuted,
|
||||
setVideoUnmutePermissions
|
||||
} from '../media/actions';
|
||||
import { MEDIA_TYPE } from '../media/constants';
|
||||
import { IGUMPendingState } from '../media/types';
|
||||
import {
|
||||
dominantSpeakerChanged,
|
||||
participantKicked,
|
||||
@@ -1052,6 +1059,11 @@ export function redirect(vnode: string, focusJid: string, username: string) {
|
||||
.then(() => dispatch(conferenceWillInit()))
|
||||
.then(() => dispatch(connect()))
|
||||
.then(() => {
|
||||
|
||||
// Clear the gum pending state in case we have set it to pending since we are starting the
|
||||
// conference without tracks.
|
||||
dispatch(gumPending([ MEDIA_TYPE.AUDIO, MEDIA_TYPE.VIDEO ], IGUMPendingState.NONE));
|
||||
|
||||
// FIXME: Workaround for the web version. To be removed once we get rid of conference.js
|
||||
if (typeof APP !== 'undefined') {
|
||||
APP.conference.startConference([]);
|
||||
|
||||
@@ -400,7 +400,7 @@ function _connectionFailed({ dispatch, getState }: IStore, next: Function, actio
|
||||
descriptionKey: errors ? 'dialog.tokenAuthFailedWithReasons' : 'dialog.tokenAuthFailed',
|
||||
descriptionArguments: { reason: errors },
|
||||
titleKey: 'dialog.tokenAuthFailedTitle'
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +1,4 @@
|
||||
export type ToolbarButton = 'camera' |
|
||||
'chat' |
|
||||
'closedcaptions' |
|
||||
'desktop' |
|
||||
'download' |
|
||||
'embedmeeting' |
|
||||
'etherpad' |
|
||||
'feedback' |
|
||||
'filmstrip' |
|
||||
'fullscreen' |
|
||||
'hangup' |
|
||||
'help' |
|
||||
'highlight' |
|
||||
'invite' |
|
||||
'linktosalesforce' |
|
||||
'livestreaming' |
|
||||
'microphone' |
|
||||
'mute-everyone' |
|
||||
'mute-video-everyone' |
|
||||
'noisesuppression' |
|
||||
'participants-pane' |
|
||||
'profile' |
|
||||
'raisehand' |
|
||||
'reactions' |
|
||||
'recording' |
|
||||
'security' |
|
||||
'select-background' |
|
||||
'settings' |
|
||||
'shareaudio' |
|
||||
'sharedvideo' |
|
||||
'shortcuts' |
|
||||
'stats' |
|
||||
'tileview' |
|
||||
'toggle-camera' |
|
||||
'videoquality' |
|
||||
'whiteboard' |
|
||||
'__end';
|
||||
import { ToolbarButton } from '../../toolbox/types';
|
||||
|
||||
type ButtonsWithNotifyClick = 'camera' |
|
||||
'chat' |
|
||||
@@ -503,6 +467,7 @@ export interface IConfig {
|
||||
preventExecution: boolean;
|
||||
}>;
|
||||
participantsPane?: {
|
||||
enabled?: boolean;
|
||||
hideModeratorSettingsTab?: boolean;
|
||||
hideMoreActionsButton?: boolean;
|
||||
hideMuteAllButton?: boolean;
|
||||
@@ -535,6 +500,7 @@ export interface IConfig {
|
||||
suggestRecording?: boolean;
|
||||
};
|
||||
remoteVideoMenu?: {
|
||||
disableDemote?: boolean;
|
||||
disableGrantModerator?: boolean;
|
||||
disableKick?: boolean;
|
||||
disablePrivateChat?: boolean;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { ToolbarButton } from './configType';
|
||||
|
||||
/**
|
||||
* The prefix of the {@code localStorage} key into which {@link storeConfig}
|
||||
* stores and from which {@link restoreConfig} restores.
|
||||
@@ -9,50 +7,6 @@ import { ToolbarButton } from './configType';
|
||||
*/
|
||||
export const _CONFIG_STORE_PREFIX = 'config.js';
|
||||
|
||||
/**
|
||||
* The list of all possible UI buttons.
|
||||
*
|
||||
* @protected
|
||||
* @type Array<string>
|
||||
*/
|
||||
export const TOOLBAR_BUTTONS: ToolbarButton[] = [
|
||||
'camera',
|
||||
'chat',
|
||||
'closedcaptions',
|
||||
'desktop',
|
||||
'download',
|
||||
'embedmeeting',
|
||||
'etherpad',
|
||||
'feedback',
|
||||
'filmstrip',
|
||||
'fullscreen',
|
||||
'hangup',
|
||||
'help',
|
||||
'highlight',
|
||||
'invite',
|
||||
'linktosalesforce',
|
||||
'livestreaming',
|
||||
'microphone',
|
||||
'mute-everyone',
|
||||
'mute-video-everyone',
|
||||
'participants-pane',
|
||||
'profile',
|
||||
'raisehand',
|
||||
'recording',
|
||||
'security',
|
||||
'select-background',
|
||||
'settings',
|
||||
'shareaudio',
|
||||
'noisesuppression',
|
||||
'sharedvideo',
|
||||
'shortcuts',
|
||||
'stats',
|
||||
'tileview',
|
||||
'toggle-camera',
|
||||
'videoquality',
|
||||
'whiteboard'
|
||||
];
|
||||
|
||||
/**
|
||||
* The toolbar buttons to show on premeeting screens.
|
||||
*/
|
||||
@@ -63,11 +17,6 @@ export const PREMEETING_BUTTONS = [ 'microphone', 'camera', 'select-background',
|
||||
*/
|
||||
export const THIRD_PARTY_PREJOIN_BUTTONS = [ 'microphone', 'camera', 'select-background' ];
|
||||
|
||||
/**
|
||||
* The toolbar buttons to show when in visitors mode.
|
||||
*/
|
||||
export const VISITORS_MODE_BUTTONS = [ 'chat', 'hangup', 'raisehand', 'settings', 'tileview' ];
|
||||
|
||||
/**
|
||||
* The set of feature flags.
|
||||
*
|
||||
|
||||
@@ -65,7 +65,7 @@ export function getMeetingRegion(state: IReduxState) {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function getSsrcRewritingFeatureFlag(state: IReduxState) {
|
||||
return getFeatureFlag(state, FEATURE_FLAGS.SSRC_REWRITING);
|
||||
return getFeatureFlag(state, FEATURE_FLAGS.SSRC_REWRITING) ?? true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,10 +7,8 @@ import {
|
||||
IDeeplinkingConfig,
|
||||
IDeeplinkingDesktopConfig,
|
||||
IDeeplinkingMobileConfig,
|
||||
NotifyClickButton,
|
||||
ToolbarButton
|
||||
NotifyClickButton
|
||||
} from './configType';
|
||||
import { TOOLBAR_BUTTONS } from './constants';
|
||||
|
||||
export * from './functions.any';
|
||||
|
||||
@@ -34,25 +32,6 @@ export function getReplaceParticipant(state: IReduxState): string | undefined {
|
||||
return state['features/base/config'].replaceParticipant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of enabled toolbar buttons.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {Array<string>} - The list of enabled toolbar buttons.
|
||||
*/
|
||||
export function getToolbarButtons(state: IReduxState): Array<string> {
|
||||
const { toolbarButtons, customToolbarButtons } = state['features/base/config'];
|
||||
const customButtons = customToolbarButtons?.map(({ id }) => id);
|
||||
|
||||
const buttons = Array.isArray(toolbarButtons) ? toolbarButtons : TOOLBAR_BUTTONS;
|
||||
|
||||
if (customButtons) {
|
||||
buttons.push(...customButtons as ToolbarButton[]);
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuration value of web-hid feature.
|
||||
*
|
||||
@@ -63,20 +42,6 @@ export function getWebHIDFeatureConfig(state: IReduxState): boolean {
|
||||
return state['features/base/config'].enableWebHIDFeature || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified button is enabled.
|
||||
*
|
||||
* @param {string} buttonName - The name of the button.
|
||||
* {@link interfaceConfig}.
|
||||
* @param {Object|Array<string>} state - The redux state or the array with the enabled buttons.
|
||||
* @returns {boolean} - True if the button is enabled and false otherwise.
|
||||
*/
|
||||
export function isToolbarButtonEnabled(buttonName: string, state: IReduxState | Array<string>) {
|
||||
const buttons = Array.isArray(state) ? state : getToolbarButtons(state);
|
||||
|
||||
return buttons.includes(buttonName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether audio level measurement is enabled or not.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
import { CONFERENCE_INFO } from '../../conference/components/constants';
|
||||
import { TOOLBAR_BUTTONS } from '../../toolbox/constants';
|
||||
import { ToolbarButton } from '../../toolbox/types';
|
||||
import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
import { equals } from '../redux/functions';
|
||||
|
||||
@@ -16,10 +18,8 @@ import {
|
||||
IDeeplinkingConfig,
|
||||
IDeeplinkingDesktopConfig,
|
||||
IDeeplinkingMobileConfig,
|
||||
IMobileDynamicLink,
|
||||
ToolbarButton
|
||||
IMobileDynamicLink
|
||||
} from './configType';
|
||||
import { TOOLBAR_BUTTONS } from './constants';
|
||||
import { _cleanupConfig, _setDeeplinkingDefaults } from './functions';
|
||||
|
||||
/**
|
||||
|
||||
@@ -52,6 +52,16 @@ export const CONNECTION_WILL_CONNECT = 'CONNECTION_WILL_CONNECT';
|
||||
*/
|
||||
export const SET_LOCATION_URL = 'SET_LOCATION_URL';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which sets the preferVisitor in store.
|
||||
*
|
||||
* {
|
||||
* type: SET_PREFER_VISITOR,
|
||||
* preferVisitor: ?boolean
|
||||
* }
|
||||
*/
|
||||
export const SET_PREFER_VISITOR = 'SET_PREFER_VISITOR';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which tells whether connection info should be displayed
|
||||
* on context menu.
|
||||
|
||||
@@ -16,7 +16,8 @@ import {
|
||||
CONNECTION_ESTABLISHED,
|
||||
CONNECTION_FAILED,
|
||||
CONNECTION_WILL_CONNECT,
|
||||
SET_LOCATION_URL
|
||||
SET_LOCATION_URL,
|
||||
SET_PREFER_VISITOR
|
||||
} from './actionTypes';
|
||||
import { JITSI_CONNECTION_URL_KEY } from './constants';
|
||||
import logger from './logger';
|
||||
@@ -180,6 +181,22 @@ export function setLocationURL(locationURL?: URL) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* To change prefer visitor in the store. Used later to decide what to request from jicofo on connection.
|
||||
*
|
||||
* @param {boolean} preferVisitor - The value to set.
|
||||
* @returns {{
|
||||
* type: SET_PREFER_VISITOR,
|
||||
* preferVisitor: boolean
|
||||
* }}
|
||||
*/
|
||||
export function setPreferVisitor(preferVisitor: boolean) {
|
||||
return {
|
||||
type: SET_PREFER_VISITOR,
|
||||
preferVisitor
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens new connection.
|
||||
*
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
CONNECTION_FAILED,
|
||||
CONNECTION_WILL_CONNECT,
|
||||
SET_LOCATION_URL,
|
||||
SET_PREFER_VISITOR,
|
||||
SHOW_CONNECTION_INFO
|
||||
} from './actionTypes';
|
||||
import { ConnectionFailedError } from './types';
|
||||
@@ -57,6 +58,11 @@ ReducerRegistry.register<IConnectionState>(
|
||||
case SET_LOCATION_URL:
|
||||
return _setLocationURL(state, action);
|
||||
|
||||
case SET_PREFER_VISITOR:
|
||||
return assign(state, {
|
||||
preferVisitor: action.preferVisitor
|
||||
});
|
||||
|
||||
case SET_ROOM:
|
||||
return _setRoom(state);
|
||||
|
||||
|
||||
@@ -164,6 +164,12 @@ export const NOTIFICATIONS_ENABLED = 'notifications.enabled';
|
||||
*/
|
||||
export const OVERFLOW_MENU_ENABLED = 'overflow-menu.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if participants should be enabled.
|
||||
* Default: enabled (true).
|
||||
*/
|
||||
export const PARTICIPANTS_ENABLED = 'participants.enabled';
|
||||
|
||||
/**
|
||||
* Flag indicating if Picture-in-Picture should be enabled.
|
||||
* Default: auto-detected.
|
||||
|
||||
@@ -8,7 +8,7 @@ import { toState } from '../../redux/functions';
|
||||
* @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 {number}.
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getClientWidth(stateful: IStateful) {
|
||||
const state = toState(stateful)['features/base/responsive-ui'];
|
||||
@@ -23,7 +23,7 @@ export function getClientWidth(stateful: IStateful) {
|
||||
* @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 {number}.
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getClientHeight(stateful: IStateful) {
|
||||
const state = toState(stateful)['features/base/responsive-ui'];
|
||||
|
||||
@@ -7,9 +7,9 @@ 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 { isButtonEnabled } from '../../../../toolbox/functions.web';
|
||||
import { getConferenceName } from '../../../conference/functions';
|
||||
import { PREMEETING_BUTTONS, THIRD_PARTY_PREJOIN_BUTTONS } from '../../../config/constants';
|
||||
import { getToolbarButtons, isToolbarButtonEnabled } from '../../../config/functions.web';
|
||||
import { withPixelLineHeight } from '../../../styles/functions.web';
|
||||
|
||||
import ConnectionStatus from './ConnectionStatus';
|
||||
@@ -229,7 +229,7 @@ const PreMeetingScreen = ({
|
||||
*/
|
||||
function mapStateToProps(state: IReduxState, ownProps: Partial<IProps>) {
|
||||
const { hiddenPremeetingButtons } = state['features/base/config'];
|
||||
const toolbarButtons = getToolbarButtons(state);
|
||||
const { toolbarButtons } = state['features/toolbox'];
|
||||
const premeetingButtons = (ownProps.thirdParty
|
||||
? THIRD_PARTY_PREJOIN_BUTTONS
|
||||
: PREMEETING_BUTTONS).filter((b: any) => !(hiddenPremeetingButtons || []).includes(b));
|
||||
@@ -244,7 +244,7 @@ function mapStateToProps(state: IReduxState, ownProps: Partial<IProps>) {
|
||||
// toolbarButtons config overwrite.
|
||||
_buttons: hiddenPremeetingButtons
|
||||
? premeetingButtons
|
||||
: premeetingButtons.filter(b => isToolbarButtonEnabled(b, toolbarButtons)),
|
||||
: premeetingButtons.filter(b => isButtonEnabled(b, toolbarButtons)),
|
||||
_premeetingBackground: premeetingBackground,
|
||||
_roomName: isRoomNameEnabled(state) ? getConferenceName(state) : ''
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
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';
|
||||
import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants';
|
||||
import { PIP_WHILE_SCREEN_SHARING_ENABLED } from '../flags/constants';
|
||||
import { getFeatureFlag } from '../flags/functions';
|
||||
import JitsiMeetJS from '../lib-jitsi-meet';
|
||||
import {
|
||||
setScreenshareMuted,
|
||||
@@ -14,7 +14,6 @@ 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';
|
||||
|
||||
@@ -33,10 +32,7 @@ export function toggleScreensharing(enabled: boolean, _ignore1?: boolean, _ignor
|
||||
if (enabled) {
|
||||
const isSharing = isLocalVideoTrackDesktop(state);
|
||||
|
||||
if (isSharing) {
|
||||
Platform.OS === 'android' && JitsiMeetMediaProjectionModule.abort();
|
||||
} else {
|
||||
Platform.OS === 'android' && JitsiMeetMediaProjectionModule.launch();
|
||||
if (!isSharing) {
|
||||
_startScreenSharing(dispatch, state);
|
||||
}
|
||||
} else {
|
||||
@@ -56,7 +52,11 @@ export function toggleScreensharing(enabled: boolean, _ignore1?: boolean, _ignor
|
||||
* @returns {void}
|
||||
*/
|
||||
async function _startScreenSharing(dispatch: IStore['dispatch'], state: IReduxState) {
|
||||
setPictureInPictureEnabled(false);
|
||||
const pipWhileScreenSharingEnabled = getFeatureFlag(state, PIP_WHILE_SCREEN_SHARING_ENABLED, false);
|
||||
|
||||
if (!pipWhileScreenSharingEnabled) {
|
||||
setPictureInPictureEnabled(false);
|
||||
}
|
||||
|
||||
try {
|
||||
const tracks: any[] = await JitsiMeetJS.createLocalTracks({ devices: [ 'desktop' ] });
|
||||
|
||||
@@ -145,6 +145,24 @@ const useStyles = makeStyles()(theme => {
|
||||
pointerEvents: 'none'
|
||||
},
|
||||
|
||||
contextMenuItemIconDisabled: {
|
||||
'& svg': {
|
||||
fill: `${theme.palette.text03} !important`
|
||||
}
|
||||
},
|
||||
|
||||
contextMenuItemLabelDisabled: {
|
||||
color: theme.palette.text03,
|
||||
|
||||
'&:hover': {
|
||||
background: 'none'
|
||||
},
|
||||
|
||||
'& svg': {
|
||||
fill: theme.palette.text03
|
||||
}
|
||||
},
|
||||
|
||||
contextMenuItemDrawer: {
|
||||
padding: '13px 16px'
|
||||
},
|
||||
@@ -233,13 +251,15 @@ const ContextMenuItem = ({
|
||||
tabIndex = { onClick ? tabIndex : undefined }>
|
||||
{customIcon ? customIcon
|
||||
: icon && <Icon
|
||||
className = { styles.contextMenuItemIcon }
|
||||
className = { cx(styles.contextMenuItemIcon,
|
||||
disabled && styles.contextMenuItemIconDisabled) }
|
||||
size = { 20 }
|
||||
src = { icon } />}
|
||||
{text && (
|
||||
<TextWithOverflow
|
||||
className = { cx(styles.text,
|
||||
_overflowDrawer && styles.drawerText,
|
||||
disabled && styles.contextMenuItemLabelDisabled,
|
||||
textClassName) }
|
||||
overflowType = { overflowType } >
|
||||
{text}
|
||||
|
||||
@@ -145,7 +145,7 @@ export function setColorAlpha(color: string, opacity: number) {
|
||||
/**
|
||||
* Gets the hexa rgb values for a shorthand css color.
|
||||
*
|
||||
* @param {string} color -
|
||||
* @param {string} color - The shorthand css color.
|
||||
* @returns {Array<number>} - Array containing parsed r, g, b values of the color.
|
||||
*/
|
||||
function parseShorthandColor(color: string) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { sanitizeUrl as _sanitizeUrl } from '@braintree/sanitize-url';
|
||||
|
||||
import { parseURLParams } from './parseURLParams';
|
||||
import { normalizeNFKC } from './strings';
|
||||
|
||||
@@ -657,3 +659,25 @@ export function appendURLHashParam(url: string, name: string, value: string) {
|
||||
|
||||
return newUrl.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes the given URL so that it's safe to use. If it's unsafe, null is returned.
|
||||
*
|
||||
* @param {string|URL} url - The URL that needs to be sanitized.
|
||||
*
|
||||
* @returns {URL?} - The sanitized URL, or null otherwise.
|
||||
*/
|
||||
export function sanitizeUrl(url?: string | URL): URL | null {
|
||||
if (!url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const urlStr = url.toString();
|
||||
const result = _sanitizeUrl(urlStr);
|
||||
|
||||
if (result === 'about:blank') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new URL(result);
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ export default class MessageContainer extends AbstractMessageContainer<IProps, I
|
||||
/**
|
||||
* Check if a message is visible in view.
|
||||
*
|
||||
* @param {Element} message -
|
||||
* @param {Element} message - The message.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
|
||||
@@ -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 }>
|
||||
|
||||
@@ -9,6 +9,7 @@ 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 { isParticipantsPaneEnabled } from '../../../participants-pane/functions';
|
||||
import { isRoomNameEnabled } from '../../../prejoin/functions';
|
||||
import ToggleCameraButton from '../../../toolbox/components/native/ToggleCameraButton';
|
||||
import { isToolboxVisible } from '../../../toolbox/functions.native';
|
||||
@@ -31,6 +32,11 @@ interface IProps {
|
||||
*/
|
||||
_createOnPress: Function;
|
||||
|
||||
/**
|
||||
* Whether participants feature is enabled or not.
|
||||
*/
|
||||
_isParticipantsPaneEnabled: boolean;
|
||||
|
||||
/**
|
||||
* Name of the meeting we're currently in.
|
||||
*/
|
||||
@@ -55,7 +61,7 @@ interface IProps {
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
const TitleBar = (props: IProps) => {
|
||||
const { _visible } = props;
|
||||
const { _isParticipantsPaneEnabled, _visible } = props;
|
||||
|
||||
if (!_visible) {
|
||||
return null;
|
||||
@@ -95,9 +101,13 @@ const TitleBar = (props: IProps) => {
|
||||
<View style = { styles.titleBarButtonContainer }>
|
||||
<AudioDeviceToggleButton styles = { styles.titleBarButton } />
|
||||
</View>
|
||||
<View style = { styles.titleBarButtonContainer }>
|
||||
<ParticipantsPaneButton styles = { styles.titleBarButton } />
|
||||
</View>
|
||||
{
|
||||
_isParticipantsPaneEnabled
|
||||
&& <View style = { styles.titleBarButtonContainer }>
|
||||
<ParticipantsPaneButton
|
||||
styles = { styles.titleBarButton } />
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
@@ -115,6 +125,7 @@ function _mapStateToProps(state: IReduxState) {
|
||||
return {
|
||||
_conferenceTimerEnabled:
|
||||
Boolean(getFeatureFlag(state, CONFERENCE_TIMER_ENABLED, true) && !hideConferenceTimer && startTimestamp),
|
||||
_isParticipantsPaneEnabled: isParticipantsPaneEnabled(state),
|
||||
_meetingName: getConferenceName(state),
|
||||
_roomNameEnabled: isRoomNameEnabled(state),
|
||||
_visible: isToolboxVisible(state)
|
||||
|
||||
@@ -8,7 +8,6 @@ import BaseTheme from '../../../../base/ui/components/BaseTheme.native';
|
||||
* React component for Audio icon.
|
||||
*
|
||||
* @returns {JSX.Element} - The Audio icon.
|
||||
*
|
||||
*/
|
||||
const AudioIcon = (): JSX.Element => (<Icon
|
||||
color = { BaseTheme.palette.ui02 }
|
||||
|
||||
@@ -25,7 +25,7 @@ export function shouldDisplayNotifications(stateful: IStateful) {
|
||||
* @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}.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function arePollsDisabled(stateful: IStateful) {
|
||||
const state = toState(stateful);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Theme } from '@mui/material';
|
||||
import { withStyles } from '@mui/styles';
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { connect } from 'react-redux';
|
||||
import { withStyles } from 'tss-react/mui';
|
||||
|
||||
import { IReduxState, IStore } from '../../../app/types';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
@@ -114,7 +114,7 @@ interface IProps extends AbstractProps, WithTranslation {
|
||||
/**
|
||||
* An object containing the CSS classes.
|
||||
*/
|
||||
classes: any;
|
||||
classes?: Partial<Record<keyof ReturnType<typeof styles>, string>>;
|
||||
|
||||
/**
|
||||
* The Redux dispatch function.
|
||||
@@ -225,7 +225,8 @@ class ConnectionIndicator extends AbstractConnectionIndicator<IProps, IState> {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { enableStatsDisplay, participantId, statsPopoverPosition, classes, t } = this.props;
|
||||
const { enableStatsDisplay, participantId, statsPopoverPosition, t } = this.props;
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
const visibilityClass = this._getVisibilityClass();
|
||||
|
||||
if (this.props._popoverDisabled) {
|
||||
@@ -305,7 +306,8 @@ class ConnectionIndicator extends AbstractConnectionIndicator<IProps, IState> {
|
||||
* @returns {string}
|
||||
*/
|
||||
_getVisibilityClass() {
|
||||
const { _isConnectionStatusInactive, _isConnectionStatusInterrupted, classes } = this.props;
|
||||
const { _isConnectionStatusInactive, _isConnectionStatusInterrupted } = this.props;
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
|
||||
return this.state.showIndicator
|
||||
|| this.props.alwaysVisible
|
||||
@@ -399,4 +401,4 @@ export function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(translate(withStyles(styles)(ConnectionIndicator)));
|
||||
export default connect(_mapStateToProps)(translate(withStyles(ConnectionIndicator, styles)));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
import { useStyles } from 'tss-react/mui';
|
||||
|
||||
import Icon from '../../../base/icons/components/Icon';
|
||||
import { IconConnection, IconConnectionInactive } from '../../../base/icons/svg';
|
||||
@@ -13,7 +13,7 @@ interface IProps {
|
||||
/**
|
||||
* An object containing the CSS classes.
|
||||
*/
|
||||
classes: any;
|
||||
classes?: Partial<Record<'icon' | 'inactiveIcon', string>>;
|
||||
|
||||
/**
|
||||
* A CSS class that interprets the current connection status as a color.
|
||||
@@ -41,10 +41,6 @@ interface IProps {
|
||||
track?: ITrack;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()(() => {
|
||||
return {};
|
||||
});
|
||||
|
||||
export const ConnectionIndicatorIcon = ({
|
||||
classes,
|
||||
colorClass,
|
||||
@@ -90,7 +86,7 @@ export const ConnectionIndicatorIcon = ({
|
||||
return (
|
||||
<span className = 'connection_ninja'>
|
||||
<Icon
|
||||
className = { cx(classes.icon, classes.inactiveIcon, colorClass) }
|
||||
className = { cx(classes?.icon, classes?.inactiveIcon, colorClass) }
|
||||
size = { 24 }
|
||||
src = { IconConnectionInactive } />
|
||||
</span>
|
||||
@@ -107,7 +103,7 @@ export const ConnectionIndicatorIcon = ({
|
||||
return (
|
||||
<span className = { emptyIconWrapperClassName }>
|
||||
<Icon
|
||||
className = { cx(classes.icon, colorClass) }
|
||||
className = { cx(classes?.icon, colorClass) }
|
||||
size = { 16 }
|
||||
src = { IconConnection } />
|
||||
</span>
|
||||
|
||||
@@ -8,9 +8,11 @@ import {
|
||||
/**
|
||||
* Contains all the callbacks to be notified when stats are updated.
|
||||
*
|
||||
* ```
|
||||
* {
|
||||
* userId: Function[]
|
||||
* }.
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
const subscribers: any = {};
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Theme } from '@mui/material';
|
||||
import { withStyles } from '@mui/styles';
|
||||
import React from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { connect } from 'react-redux';
|
||||
import { withStyles } from 'tss-react/mui';
|
||||
|
||||
import { IReduxState, IStore } from '../../app/types';
|
||||
import { getAvailableDevices } from '../../base/devices/actions.web';
|
||||
@@ -37,7 +37,7 @@ interface IProps extends AbstractDialogTabProps, WithTranslation {
|
||||
/**
|
||||
* CSS classes object.
|
||||
*/
|
||||
classes: any;
|
||||
classes?: Partial<Record<keyof ReturnType<typeof styles>, string>>;
|
||||
|
||||
/**
|
||||
* Whether or not the audio selector can be interacted with. If true,
|
||||
@@ -234,7 +234,6 @@ class AudioDevicesSelection extends AbstractDialogTab<IProps, IState> {
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
classes,
|
||||
hasAudioPermission,
|
||||
hideAudioInputPreview,
|
||||
hideAudioOutputPreview,
|
||||
@@ -247,6 +246,8 @@ class AudioDevicesSelection extends AbstractDialogTab<IProps, IState> {
|
||||
} = this.props;
|
||||
const { audioInput, audioOutput } = this._getSelectors();
|
||||
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
|
||||
return (
|
||||
<div className = { classes.container }>
|
||||
{!iAmVisitor && <div
|
||||
@@ -392,4 +393,4 @@ const mapStateToProps = (state: IReduxState) => {
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(withStyles(styles)(translate(AudioDevicesSelection)));
|
||||
export default connect(mapStateToProps)(withStyles(translate(AudioDevicesSelection), styles));
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Theme } from '@mui/material';
|
||||
import { withStyles } from '@mui/styles';
|
||||
import React from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { connect } from 'react-redux';
|
||||
import { withStyles } from 'tss-react/mui';
|
||||
|
||||
import { IReduxState, IStore } from '../../app/types';
|
||||
import { getAvailableDevices } from '../../base/devices/actions.web';
|
||||
@@ -33,7 +33,7 @@ export interface IProps extends AbstractDialogTabProps, WithTranslation {
|
||||
/**
|
||||
* CSS classes object.
|
||||
*/
|
||||
classes: any;
|
||||
classes?: Partial<Record<keyof ReturnType<typeof styles>, string>>;
|
||||
|
||||
/**
|
||||
* The currently selected desktop share frame rate in the frame rate select dropdown.
|
||||
@@ -203,13 +203,14 @@ class VideoDeviceSelection extends AbstractDialogTab<IProps, IState> {
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
classes,
|
||||
hideAdditionalSettings,
|
||||
hideVideoInputPreview,
|
||||
localFlipX,
|
||||
t
|
||||
} = this.props;
|
||||
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
|
||||
return (
|
||||
<div className = { classes.container }>
|
||||
{ !hideVideoInputPreview
|
||||
@@ -366,4 +367,4 @@ const mapStateToProps = (state: IReduxState) => {
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(withStyles(styles)(translate(VideoDeviceSelection)));
|
||||
export default connect(mapStateToProps)(withStyles(translate(VideoDeviceSelection), styles));
|
||||
|
||||
@@ -23,7 +23,8 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
backgroundImageUrl,
|
||||
brandedIcons,
|
||||
didPageUrl,
|
||||
inviteDomain
|
||||
inviteDomain,
|
||||
labels
|
||||
} = action.value;
|
||||
|
||||
action.value = {
|
||||
@@ -32,7 +33,8 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
backgroundImageUrl,
|
||||
brandedIcons,
|
||||
didPageUrl,
|
||||
inviteDomain
|
||||
inviteDomain,
|
||||
labels
|
||||
};
|
||||
|
||||
// The backend may send an empty string, make sure we skip that.
|
||||
|
||||
@@ -230,7 +230,7 @@ ReducerRegistry.register<IDynamicBrandingState>(STORE_NAME, (state = DEFAULT_STA
|
||||
* Transforms the branding images into an array of Images objects ready
|
||||
* to be used as virtual backgrounds.
|
||||
*
|
||||
* @param {Array<string>} images -
|
||||
* @param {Array<string>} images - The branding images.
|
||||
* @private
|
||||
* @returns {{Props}}
|
||||
*/
|
||||
|
||||
@@ -50,7 +50,7 @@ export function doesEveryoneSupportE2EE(stateful: IStateful) {
|
||||
*
|
||||
* @param {Function|Object} stateful - The redux store or {@code getState}
|
||||
* function.
|
||||
* @returns {boolean}.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isMaxModeReached(stateful: IStateful) {
|
||||
const participantCount = getParticipantCount(toState(stateful));
|
||||
@@ -63,7 +63,7 @@ export function isMaxModeReached(stateful: IStateful) {
|
||||
*
|
||||
* @param {Function|Object} stateful - The redux store or {@code getState}
|
||||
* function.
|
||||
* @returns {boolean}.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isMaxModeThresholdReached(stateful: IStateful) {
|
||||
const participantCount = getParticipantCount(toState(stateful));
|
||||
|
||||
@@ -4,6 +4,7 @@ import { CONFERENCE_JOIN_IN_PROGRESS } from '../base/conference/actionTypes';
|
||||
import { getCurrentConference } from '../base/conference/functions';
|
||||
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import StateListenerRegistry from '../base/redux/StateListenerRegistry';
|
||||
import { sanitizeUrl } from '../base/util/uri';
|
||||
|
||||
import { TOGGLE_DOCUMENT_EDITING } from './actionTypes';
|
||||
import { setDocumentUrl } from './actions';
|
||||
@@ -27,9 +28,10 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
({ value }: { value: string; }) => {
|
||||
let url;
|
||||
const { etherpad_base: etherpadBase } = getState()['features/base/config'];
|
||||
const etherpadBaseUrl = sanitizeUrl(etherpadBase);
|
||||
|
||||
if (etherpadBase) {
|
||||
url = new URL(value, etherpadBase).toString();
|
||||
if (etherpadBaseUrl) {
|
||||
url = new URL(value, etherpadBaseUrl.toString()).toString();
|
||||
}
|
||||
|
||||
dispatch(setDocumentUrl(url));
|
||||
|
||||
@@ -81,7 +81,7 @@ interface IProps {
|
||||
class Filmstrip extends PureComponent<IProps> {
|
||||
/**
|
||||
* Whether the local participant should be rendered separately from the
|
||||
* remote participants ie outside of their {@link ScrollView}.
|
||||
* remote participants i.e. outside of their {@link ScrollView}.
|
||||
*/
|
||||
_separateLocalThumbnail: boolean;
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import { withStyles } from '@mui/styles';
|
||||
import clsx from 'clsx';
|
||||
import _ from 'lodash';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { connect } from 'react-redux';
|
||||
import { FixedSizeGrid, FixedSizeList } from 'react-window';
|
||||
import { withStyles } from 'tss-react/mui';
|
||||
|
||||
import { ACTION_SHORTCUT_TRIGGERED, createShortcutEvent, createToolbarEvent } from '../../../analytics/AnalyticsEvents';
|
||||
import { sendAnalytics } from '../../../analytics/functions';
|
||||
import { IReduxState, IStore } from '../../../app/types';
|
||||
import { getToolbarButtons } from '../../../base/config/functions.web';
|
||||
import { isMobileBrowser } from '../../../base/environment/utils';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import Icon from '../../../base/icons/components/Icon';
|
||||
@@ -213,7 +212,7 @@ interface IProps extends WithTranslation {
|
||||
/**
|
||||
* An object containing the CSS classes.
|
||||
*/
|
||||
classes: any;
|
||||
classes?: Partial<Record<keyof ReturnType<typeof styles>, string>>;
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
@@ -349,10 +348,10 @@ class Filmstrip extends PureComponent <IProps, IState> {
|
||||
_verticalViewBackground,
|
||||
_verticalViewGrid,
|
||||
_verticalViewMaxWidth,
|
||||
classes,
|
||||
filmstripType,
|
||||
t
|
||||
} = this.props;
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
const { isMouseDown } = this.state;
|
||||
const tileViewActive = _currentLayout === LAYOUTS.TILE_VIEW;
|
||||
|
||||
@@ -838,12 +837,12 @@ class Filmstrip extends PureComponent <IProps, IState> {
|
||||
_renderToggleButton() {
|
||||
const {
|
||||
t,
|
||||
classes,
|
||||
_isVerticalFilmstrip,
|
||||
_mainFilmstripVisible,
|
||||
_topPanelFilmstrip,
|
||||
_topPanelVisible
|
||||
} = this.props;
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
const icon = (_topPanelFilmstrip ? _topPanelVisible : _mainFilmstripVisible) ? IconArrowDown : IconArrowUp;
|
||||
const actions = isMobileBrowser()
|
||||
? { onTouchStart: this._onToggleButtonTouch }
|
||||
@@ -884,11 +883,11 @@ class Filmstrip extends PureComponent <IProps, IState> {
|
||||
*/
|
||||
function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const { _hasScroll = false, filmstripType, _topPanelFilmstrip, _remoteParticipants } = ownProps;
|
||||
const toolbarButtons = getToolbarButtons(state);
|
||||
const { toolbarButtons } = state['features/toolbox'];
|
||||
const { iAmRecorder } = state['features/base/config'];
|
||||
const { topPanelHeight, topPanelVisible, visible, width: verticalFilmstripWidth } = state['features/filmstrip'];
|
||||
const { localScreenShare } = state['features/base/participants'];
|
||||
const reduceHeight = state['features/toolbox'].visible && toolbarButtons.length;
|
||||
const reduceHeight = state['features/toolbox'].visible && toolbarButtons?.length;
|
||||
const remoteVideosVisible = shouldRemoteVideosBeVisible(state);
|
||||
const { isOpen: shiftRight } = state['features/chat'];
|
||||
const disableSelfView = getHideSelfView(state);
|
||||
@@ -942,4 +941,4 @@ function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
};
|
||||
}
|
||||
|
||||
export default withStyles(styles)(translate(connect(_mapStateToProps)(Filmstrip)));
|
||||
export default withStyles(translate(connect(_mapStateToProps)(Filmstrip)), styles);
|
||||
|
||||
@@ -2,7 +2,6 @@ import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { getToolbarButtons } from '../../../base/config/functions.web';
|
||||
import { isMobileBrowser } from '../../../base/environment/utils';
|
||||
import { LAYOUTS } from '../../../video-layout/constants';
|
||||
import { getCurrentLayout } from '../../../video-layout/functions.web';
|
||||
@@ -107,9 +106,9 @@ const MainFilmstrip = (props: IProps) => (
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state: IReduxState, _ownProps: any) {
|
||||
const toolbarButtons = getToolbarButtons(state);
|
||||
const { toolbarButtons } = state['features/toolbox'];
|
||||
const { remoteParticipants, width: verticalFilmstripWidth } = state['features/filmstrip'];
|
||||
const reduceHeight = state['features/toolbox'].visible && toolbarButtons.length;
|
||||
const reduceHeight = state['features/toolbox'].visible && toolbarButtons?.length;
|
||||
const {
|
||||
gridDimensions: dimensions = { columns: undefined,
|
||||
rows: undefined },
|
||||
|
||||
@@ -2,7 +2,6 @@ import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { getToolbarButtons } from '../../../base/config/functions.web';
|
||||
import { isMobileBrowser } from '../../../base/environment/utils';
|
||||
import { LAYOUTS, LAYOUT_CLASSNAMES } from '../../../video-layout/constants';
|
||||
import { getCurrentLayout } from '../../../video-layout/functions.web';
|
||||
@@ -108,9 +107,9 @@ const StageFilmstrip = (props: IProps) =>
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state: IReduxState, _ownProps: any) {
|
||||
const toolbarButtons = getToolbarButtons(state);
|
||||
const { toolbarButtons } = state['features/toolbox'];
|
||||
const activeParticipants = getActiveParticipantsIds(state);
|
||||
const reduceHeight = state['features/toolbox'].visible && toolbarButtons.length;
|
||||
const reduceHeight = state['features/toolbox'].visible && toolbarButtons?.length;
|
||||
const {
|
||||
gridDimensions: dimensions = { columns: undefined,
|
||||
rows: undefined },
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Theme } from '@mui/material';
|
||||
import { withStyles } from '@mui/styles';
|
||||
import clsx from 'clsx';
|
||||
import debounce from 'lodash/debounce';
|
||||
import React, { Component, KeyboardEvent, RefObject, createRef } from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { connect } from 'react-redux';
|
||||
import { withStyles } from 'tss-react/mui';
|
||||
|
||||
import { createScreenSharingIssueEvent } from '../../../analytics/AnalyticsEvents';
|
||||
import { sendAnalytics } from '../../../analytics/functions';
|
||||
@@ -227,7 +227,7 @@ export interface IProps extends WithTranslation {
|
||||
/**
|
||||
* An object containing CSS classes.
|
||||
*/
|
||||
classes: any;
|
||||
classes?: Partial<Record<keyof ReturnType<typeof defaultStyles>, string>>;
|
||||
|
||||
/**
|
||||
* The redux dispatch function.
|
||||
@@ -351,8 +351,8 @@ const defaultStyles = (theme: Theme) => {
|
||||
'& img': {
|
||||
maxWidth: '100%',
|
||||
maxHeight: '100%',
|
||||
objectFit: 'contain',
|
||||
flexGrow: '1'
|
||||
objectFit: 'contain' as const,
|
||||
flexGrow: 1
|
||||
}
|
||||
},
|
||||
|
||||
@@ -946,9 +946,9 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
_isDominantSpeakerDisabled,
|
||||
_participant,
|
||||
_raisedHand,
|
||||
_thumbnailType,
|
||||
classes
|
||||
_thumbnailType
|
||||
} = this.props;
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
|
||||
className += ` ${DISPLAY_MODE_TO_CLASS_NAME[displayMode]}`;
|
||||
|
||||
@@ -994,7 +994,8 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
* @returns {Component}
|
||||
*/
|
||||
_renderGif() {
|
||||
const { _gifSrc, classes } = this.props;
|
||||
const { _gifSrc } = this.props;
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
|
||||
return _gifSrc && (
|
||||
<div className = { classes.gif }>
|
||||
@@ -1033,10 +1034,10 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
_shouldDisplayTintBackground,
|
||||
_thumbnailType,
|
||||
_videoTrack,
|
||||
classes,
|
||||
filmstripType,
|
||||
t
|
||||
} = this.props;
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
const { id, name, pinned } = _participant || {};
|
||||
const { isHovered, popoverVisible } = this.state;
|
||||
const styles = this._getStyles();
|
||||
@@ -1197,7 +1198,8 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
|
||||
if (_isVirtualScreenshareParticipant) {
|
||||
const { isHovered } = this.state;
|
||||
const { _videoTrack, _isMobile, classes, _thumbnailType } = this.props;
|
||||
const { _videoTrack, _isMobile, _thumbnailType } = this.props;
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
|
||||
return (
|
||||
<VirtualScreenshareParticipant
|
||||
@@ -1399,4 +1401,4 @@ function _mapStateToProps(state: IReduxState, ownProps: any): Object {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(withStyles(defaultStyles)(translate(Thumbnail)));
|
||||
export default connect(_mapStateToProps)(withStyles(translate(Thumbnail), defaultStyles));
|
||||
|
||||
@@ -17,7 +17,7 @@ interface IProps {
|
||||
/**
|
||||
* Class name for indicators container.
|
||||
*/
|
||||
className: string;
|
||||
className?: string;
|
||||
|
||||
/**
|
||||
* Whether or not the indicators are for the local participant.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import clsx from 'clsx';
|
||||
import React, { TouchEventHandler } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useStyles } from 'tss-react/mui';
|
||||
|
||||
import VideoTrack from '../../../base/media/components/web/VideoTrack';
|
||||
import { ITrack } from '../../../base/tracks/types';
|
||||
@@ -15,7 +15,15 @@ interface IProps {
|
||||
/**
|
||||
* An object containing the CSS classes.
|
||||
*/
|
||||
classes: any;
|
||||
classes?: Partial<Record<
|
||||
'containerBackground' |
|
||||
'indicatorsContainer' |
|
||||
'indicatorsTopContainer' |
|
||||
'tintBackground' |
|
||||
'indicatorsBottomContainer' |
|
||||
'indicatorsBackground',
|
||||
string
|
||||
>>;
|
||||
|
||||
/**
|
||||
* The class name that will be used for the container.
|
||||
@@ -125,6 +133,8 @@ const VirtualScreenshareParticipant = ({
|
||||
style = { styles.video }
|
||||
videoTrack = { videoTrack } />;
|
||||
|
||||
const { cx } = useStyles();
|
||||
|
||||
return (
|
||||
<span
|
||||
className = { containerClassName }
|
||||
@@ -144,10 +154,10 @@ const VirtualScreenshareParticipant = ({
|
||||
) }
|
||||
style = { styles.thumbnail }>
|
||||
{video}
|
||||
<div className = { classes.containerBackground } />
|
||||
<div className = { classes?.containerBackground } />
|
||||
<div
|
||||
className = { clsx(classes.indicatorsContainer,
|
||||
classes.indicatorsTopContainer,
|
||||
className = { cx(classes?.indicatorsContainer,
|
||||
classes?.indicatorsTopContainer,
|
||||
currentLayout === LAYOUTS.TILE_VIEW && 'tile-view-mode'
|
||||
) }>
|
||||
<ThumbnailTopIndicators
|
||||
@@ -155,14 +165,14 @@ const VirtualScreenshareParticipant = ({
|
||||
participantId = { participantId }
|
||||
thumbnailType = { thumbnailType } />
|
||||
</div>
|
||||
{shouldDisplayTintBackground && <div className = { classes.tintBackground } />}
|
||||
{shouldDisplayTintBackground && <div className = { classes?.tintBackground } />}
|
||||
<div
|
||||
className = { clsx(classes.indicatorsContainer,
|
||||
classes.indicatorsBottomContainer,
|
||||
className = { cx(classes?.indicatorsContainer,
|
||||
classes?.indicatorsBottomContainer,
|
||||
currentLayout === LAYOUTS.TILE_VIEW && 'tile-view-mode'
|
||||
) }>
|
||||
<ThumbnailBottomIndicators
|
||||
className = { classes.indicatorsBackground }
|
||||
className = { classes?.indicatorsBackground }
|
||||
local = { false }
|
||||
participantId = { participantId }
|
||||
showStatusIndicators = { true } />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Theme } from '@mui/material';
|
||||
import { withStyles } from '@mui/styles';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { withStyles } from 'tss-react/mui';
|
||||
|
||||
import { IReduxState, IStore } from '../../../../app/types';
|
||||
import Avatar from '../../../../base/avatar/components/Avatar';
|
||||
@@ -53,7 +53,7 @@ interface IProps extends AbstractProps {
|
||||
/**
|
||||
* Css classes.
|
||||
*/
|
||||
classes: any;
|
||||
classes?: Partial<Record<keyof ReturnType<typeof styles>, string>>;
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
@@ -159,6 +159,7 @@ class InviteContactsForm extends AbstractAddPeopleDialog<IProps, IState> {
|
||||
_sipInviteEnabled,
|
||||
t
|
||||
} = this.props;
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
let isMultiSelectDisabled = this.state.addToCallInProgress;
|
||||
const loadingMessage = 'addPeople.searching';
|
||||
const noMatches = 'addPeople.noResults';
|
||||
@@ -182,7 +183,7 @@ class InviteContactsForm extends AbstractAddPeopleDialog<IProps, IState> {
|
||||
|
||||
return (
|
||||
<div
|
||||
className = { this.props.classes.formWrap }
|
||||
className = { classes.formWrap }
|
||||
onKeyDown = { this._onKeyDown }>
|
||||
<MultiSelectAutocomplete
|
||||
id = 'invite-contacts-input'
|
||||
@@ -443,7 +444,8 @@ class InviteContactsForm extends AbstractAddPeopleDialog<IProps, IState> {
|
||||
*/
|
||||
_renderFormActions() {
|
||||
const { inviteItems } = this.state;
|
||||
const { t, classes } = this.props;
|
||||
const { t } = this.props;
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
|
||||
if (!inviteItems.length) {
|
||||
return null;
|
||||
@@ -511,4 +513,4 @@ function _mapStateToProps(state: IReduxState) {
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(withStyles(styles)(InviteContactsForm)));
|
||||
export default translate(connect(_mapStateToProps)(withStyles(InviteContactsForm, styles)));
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Theme } from '@mui/material';
|
||||
import { withStyles } from '@mui/styles';
|
||||
import clsx from 'clsx';
|
||||
import React, { Component } from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { withStyles } from 'tss-react/mui';
|
||||
|
||||
import { translate } from '../../../../base/i18n/functions';
|
||||
import { withPixelLineHeight } from '../../../../base/styles/functions.web';
|
||||
@@ -24,7 +24,7 @@ interface IProps extends WithTranslation {
|
||||
/**
|
||||
* An object containing the CSS classes.
|
||||
*/
|
||||
classes: any;
|
||||
classes?: Partial<Record<keyof ReturnType<typeof styles>, string>>;
|
||||
|
||||
/**
|
||||
* Whether or not numbers should include links with the telephone protocol.
|
||||
@@ -172,7 +172,8 @@ class DialInSummary extends Component<IProps, State> {
|
||||
let contents;
|
||||
|
||||
const { conferenceID, error, loading, numbersEnabled } = this.state;
|
||||
const { classes, hideError, showTitle, room, clickableNumbers, scrollable, t } = this.props;
|
||||
const { hideError, showTitle, room, clickableNumbers, scrollable, t } = this.props;
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
|
||||
if (loading) {
|
||||
contents = '';
|
||||
@@ -309,4 +310,4 @@ class DialInSummary extends Component<IProps, State> {
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(withStyles(styles)(DialInSummary));
|
||||
export default translate(withStyles(DialInSummary, styles));
|
||||
|
||||
@@ -116,9 +116,7 @@ export function admitMultiple(participants: Array<IKnockingParticipant>) {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const conference = getCurrentConference(getState);
|
||||
|
||||
participants.forEach(p => {
|
||||
conference?.lobbyApproveAccess(p.id);
|
||||
});
|
||||
conference?.lobbyApproveAccess(participants.map(p => p.id));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -43,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,
|
||||
@@ -269,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') {
|
||||
@@ -284,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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { NativeModules, Platform } from 'react-native';
|
||||
|
||||
import { getAppProp } from '../../base/app/functions';
|
||||
import {
|
||||
CONFERENCE_BLURRED,
|
||||
@@ -11,7 +9,6 @@ import {
|
||||
import { SET_AUDIO_MUTED, SET_VIDEO_MUTED } from '../../base/media/actionTypes';
|
||||
import { PARTICIPANT_JOINED, PARTICIPANT_LEFT } from '../../base/participants/actionTypes';
|
||||
import MiddlewareRegistry from '../../base/redux/MiddlewareRegistry';
|
||||
import StateListenerRegistry from '../../base/redux/StateListenerRegistry';
|
||||
import { READY_TO_CLOSE } from '../external-api/actionTypes';
|
||||
import { participantToParticipantInfo } from '../external-api/functions';
|
||||
import { ENTER_PICTURE_IN_PICTURE } from '../picture-in-picture/actionTypes';
|
||||
@@ -19,7 +16,6 @@ import { ENTER_PICTURE_IN_PICTURE } from '../picture-in-picture/actionTypes';
|
||||
import { isExternalAPIAvailable } from './functions';
|
||||
|
||||
const externalAPIEnabled = isExternalAPIAvailable();
|
||||
const { JMOngoingConference } = NativeModules;
|
||||
|
||||
|
||||
/**
|
||||
@@ -78,21 +74,3 @@ const { JMOngoingConference } = NativeModules;
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
/**
|
||||
* Before enabling media projection service control on Android,
|
||||
* we need to check if native modules are being used or not.
|
||||
*/
|
||||
Platform.OS === 'android' && !externalAPIEnabled && StateListenerRegistry.register(
|
||||
state => state['features/base/conference'].conference,
|
||||
(conference, previousConference) => {
|
||||
if (!conference) {
|
||||
JMOngoingConference.abort();
|
||||
} else if (conference && !previousConference) {
|
||||
JMOngoingConference.launch();
|
||||
} else if (conference !== previousConference) {
|
||||
JMOngoingConference.abort();
|
||||
JMOngoingConference.launch();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
isParticipantAudioMuted,
|
||||
isParticipantVideoMuted
|
||||
} from '../../../base/tracks/functions.native';
|
||||
import { showConnectionStatus, showContextMenuDetails, showSharedVideoMenu } from '../../actions.native';
|
||||
import { showContextMenuDetails, showSharedVideoMenu } from '../../actions.native';
|
||||
import type { MediaState } from '../../constants';
|
||||
import { getParticipantAudioMediaState, getParticipantVideoMediaState } from '../../functions';
|
||||
|
||||
@@ -117,11 +117,7 @@ class MeetingParticipantItem extends PureComponent<IProps> {
|
||||
if (_fakeParticipant && _localVideoOwner) {
|
||||
dispatch(showSharedVideoMenu(_participantID));
|
||||
} else if (!_fakeParticipant) {
|
||||
if (_local) {
|
||||
dispatch(showConnectionStatus(_participantID));
|
||||
} else {
|
||||
dispatch(showContextMenuDetails(_participantID));
|
||||
}
|
||||
dispatch(showContextMenuDetails(_participantID, _local));
|
||||
} // else no-op
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import { makeStyles } from 'tss-react/mui';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { rejectParticipantAudio, rejectParticipantVideo } from '../../../av-moderation/actions';
|
||||
import participantsPaneTheme from '../../../base/components/themes/participantsPaneTheme.json';
|
||||
import { isToolbarButtonEnabled } from '../../../base/config/functions.web';
|
||||
import { MEDIA_TYPE } from '../../../base/media/constants';
|
||||
import { getParticipantById, isScreenShareParticipant } from '../../../base/participants/functions';
|
||||
import { withPixelLineHeight } from '../../../base/styles/functions.web';
|
||||
@@ -14,7 +13,7 @@ import Input from '../../../base/ui/components/web/Input';
|
||||
import useContextMenu from '../../../base/ui/hooks/useContextMenu.web';
|
||||
import { normalizeAccents } from '../../../base/util/strings.web';
|
||||
import { getBreakoutRooms, getCurrentRoomId, isInBreakoutRoom } from '../../../breakout-rooms/functions';
|
||||
import { showOverflowDrawer } from '../../../toolbox/functions.web';
|
||||
import { isButtonEnabled, showOverflowDrawer } from '../../../toolbox/functions.web';
|
||||
import { muteRemote } from '../../../video-menu/actions.web';
|
||||
import { getSortedParticipantIds, isCurrentRoomRenamable, shouldRenderInviteButton } from '../../functions';
|
||||
import { useParticipantDrawer } from '../../hooks';
|
||||
@@ -184,7 +183,7 @@ function _mapStateToProps(state: IReduxState) {
|
||||
});
|
||||
|
||||
const participantsCount = sortedParticipantIds.length;
|
||||
const showInviteButton = shouldRenderInviteButton(state) && isToolbarButtonEnabled('invite', state);
|
||||
const showInviteButton = shouldRenderInviteButton(state) && isButtonEnabled('invite', state);
|
||||
const overflowDrawer = showOverflowDrawer(state);
|
||||
const currentRoomId = getCurrentRoomId(state);
|
||||
const currentRoom = getBreakoutRooms(state)[currentRoomId];
|
||||
|
||||
@@ -9,9 +9,11 @@ import {
|
||||
close as closeParticipantsPane,
|
||||
open as openParticipantsPane
|
||||
} from '../../../participants-pane/actions.web';
|
||||
import { isParticipantsPaneEnabled } from '../../functions';
|
||||
|
||||
import ParticipantsCounter from './ParticipantsCounter';
|
||||
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link ParticipantsPaneButton}.
|
||||
*/
|
||||
@@ -21,6 +23,11 @@ interface IProps extends AbstractButtonProps {
|
||||
* Whether or not the participants pane is open.
|
||||
*/
|
||||
_isOpen: boolean;
|
||||
|
||||
/**
|
||||
* Whether participants feature is enabled or not.
|
||||
*/
|
||||
_isParticipantsPaneEnabled: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,10 +76,16 @@ class ParticipantsPaneButton extends AbstractButton<IProps> {
|
||||
* @returns {React$Node}
|
||||
*/
|
||||
render() {
|
||||
const { _isParticipantsPaneEnabled } = this.props;
|
||||
|
||||
if (!_isParticipantsPaneEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className = 'toolbar-button-with-badge'>
|
||||
{super.render()}
|
||||
{ super.render() }
|
||||
<ParticipantsCounter />
|
||||
</div>
|
||||
);
|
||||
@@ -89,7 +102,8 @@ function mapStateToProps(state: IReduxState) {
|
||||
const { isOpen } = state['features/participants-pane'];
|
||||
|
||||
return {
|
||||
_isOpen: isOpen
|
||||
_isOpen: isOpen,
|
||||
_isParticipantsPaneEnabled: isParticipantsPaneEnabled(state)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
} from '../av-moderation/functions';
|
||||
import { IStateful } from '../base/app/types';
|
||||
import { getCurrentConference } from '../base/conference/functions';
|
||||
import { INVITE_ENABLED } from '../base/flags/constants';
|
||||
import { INVITE_ENABLED, PARTICIPANTS_ENABLED } from '../base/flags/constants';
|
||||
import { getFeatureFlag } from '../base/flags/functions';
|
||||
import { MEDIA_TYPE, type MediaType } from '../base/media/constants';
|
||||
import {
|
||||
@@ -309,3 +309,17 @@ export function isBreakoutRoomRenameAllowed(state: IReduxState) {
|
||||
|
||||
return isLocalModerator && isRenameBreakoutRoomsSupported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if participants is enabled and false otherwise.
|
||||
*
|
||||
* @param {IStateful} stateful - The redux store, the redux
|
||||
* {@code getState} function, or the redux state itself.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isParticipantsPaneEnabled = (stateful: IStateful) => {
|
||||
const state = toState(stateful);
|
||||
const { enabled = true } = getParticipantsPaneConfig(state);
|
||||
|
||||
return Boolean(getFeatureFlag(state, PARTICIPANTS_ENABLED, true) && enabled);
|
||||
};
|
||||
|
||||
@@ -42,6 +42,16 @@ export function isDisplayNameRequired(state: IReduxState): boolean {
|
||||
|| state['features/base/config']?.requireDisplayName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector for determining if the prejoin page is enabled in config. Defaults to `true`.
|
||||
*
|
||||
* @param {IReduxState} state - The state of the app.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isPrejoinEnabledInConfig(state: IReduxState): boolean {
|
||||
return state['features/base/config'].prejoinConfig?.enabled ?? true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector for determining if the prejoin display name field is visible.
|
||||
*
|
||||
@@ -154,7 +164,7 @@ export function isJoinByPhoneDialogVisible(state: IReduxState): boolean {
|
||||
*/
|
||||
export function isPrejoinPageVisible(state: IReduxState): boolean {
|
||||
return Boolean(navigator.product !== 'ReactNative'
|
||||
&& state['features/base/config'].prejoinConfig?.enabled
|
||||
&& isPrejoinEnabledInConfig(state)
|
||||
&& state['features/prejoin']?.showPrejoin
|
||||
&& !(state['features/base/config'].enableForcedReload && state['features/prejoin'].skipPrejoinOnReload));
|
||||
}
|
||||
@@ -166,12 +176,11 @@ export function isPrejoinPageVisible(state: IReduxState): boolean {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function shouldAutoKnock(state: IReduxState): boolean {
|
||||
const { iAmRecorder, iAmSipGateway, prejoinConfig } = state['features/base/config'];
|
||||
const { iAmRecorder, iAmSipGateway } = state['features/base/config'];
|
||||
const { userSelectedSkipPrejoin } = state['features/base/settings'];
|
||||
const { autoKnock } = getLobbyConfig(state);
|
||||
const isPrejoinEnabled = prejoinConfig?.enabled;
|
||||
|
||||
return Boolean(((isPrejoinEnabled && !userSelectedSkipPrejoin)
|
||||
return Boolean(((isPrejoinEnabledInConfig(state) && !userSelectedSkipPrejoin)
|
||||
|| autoKnock || (iAmRecorder && iAmSipGateway))
|
||||
&& !state['features/lobby'].knocking);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { IReduxState } from '../app/types';
|
||||
import { getToolbarButtons } from '../base/config/functions.web';
|
||||
|
||||
import { shouldDisplayReactionsButtons } from './functions.any';
|
||||
import { isReactionsEnabled } from './functions.any';
|
||||
|
||||
export * from './functions.any';
|
||||
|
||||
@@ -22,5 +21,7 @@ export function getReactionsMenuVisibility(state: IReduxState): boolean {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isReactionsButtonEnabled(state: IReduxState) {
|
||||
return Boolean(getToolbarButtons(state).includes('reactions')) && shouldDisplayReactionsButtons(state);
|
||||
const { toolbarButtons } = state['features/toolbox'];
|
||||
|
||||
return Boolean(toolbarButtons?.includes('reactions')) && isReactionsEnabled(state);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
import { NOTIFICATION_TIMEOUT_TYPE, NOTIFICATION_TYPE } from '../notifications/constants';
|
||||
import { INotificationProps } from '../notifications/types';
|
||||
import { setRequestingSubtitles } from '../subtitles/actions.any';
|
||||
import { isRecorderTranscriptionsRunning } from '../transcribing/functions';
|
||||
|
||||
import {
|
||||
CLEAR_RECORDING_SESSIONS,
|
||||
@@ -404,11 +405,11 @@ export function stopLocalVideoRecording() {
|
||||
*/
|
||||
export function showStartRecordingNotificationWithCallback(openRecordingDialog: Function) {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const state = getState();
|
||||
let state = getState();
|
||||
const { recordings } = state['features/base/config'];
|
||||
const { suggestRecording } = recordings || {};
|
||||
const recordButtonProps = getRecordButtonProps(state);
|
||||
const isAlreadyRecording = isRecordingRunning(state);
|
||||
const isAlreadyRecording = isRecordingRunning(state) || isRecorderTranscriptionsRunning(state);
|
||||
const wasNotificationShown = state['features/recording'].wasStartRecordingSuggested;
|
||||
|
||||
if (!suggestRecording
|
||||
@@ -427,9 +428,9 @@ export function showStartRecordingNotificationWithCallback(openRecordingDialog:
|
||||
customActionType: [ BUTTON_TYPES.PRIMARY ],
|
||||
customActionNameKey: [ 'notify.suggestRecordingAction' ],
|
||||
customActionHandler: [ () => {
|
||||
state = getState();
|
||||
const isModerator = isLocalParticipantModerator(state);
|
||||
const { recordingService } = state['features/base/config'];
|
||||
|
||||
const canBypassDialog = isModerator
|
||||
&& recordingService?.enabled
|
||||
&& isJwtFeatureEnabled(state, 'recording', true);
|
||||
|
||||
@@ -2,66 +2,57 @@ import React, { Component } from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
|
||||
import { IReduxState } from '../../app/types';
|
||||
import { isTranscribing } from '../../transcribing/functions';
|
||||
import { getSessionStatusToShow, isRecordingRunning } from '../functions';
|
||||
import { JitsiRecordingConstants } from '../../base/lib-jitsi-meet';
|
||||
import { isRecorderTranscriptionsRunning } from '../../transcribing/functions';
|
||||
import {
|
||||
getActiveSession,
|
||||
getSessionStatusToShow,
|
||||
isRecordingRunning,
|
||||
isRemoteParticipantRecordingLocally
|
||||
} from '../functions';
|
||||
|
||||
|
||||
interface IProps extends WithTranslation {
|
||||
export interface IProps extends WithTranslation {
|
||||
|
||||
/**
|
||||
* Whether this is the Jibri recorder participant.
|
||||
*/
|
||||
_iAmRecorder: boolean;
|
||||
|
||||
/**
|
||||
* Whether the recording is currently running.
|
||||
*/
|
||||
_isRecordingRunning: boolean;
|
||||
|
||||
/**
|
||||
* Whether this meeting is being transcribed.
|
||||
*/
|
||||
_isTranscribing: boolean;
|
||||
*/
|
||||
_isTranscribing: boolean;
|
||||
|
||||
/**
|
||||
* Whether the recording/livestreaming/transcriber is currently running.
|
||||
*/
|
||||
_isVisible: boolean;
|
||||
|
||||
/**
|
||||
* The status of the higher priority session.
|
||||
*/
|
||||
_status?: string;
|
||||
|
||||
/**
|
||||
* An object containing the CSS classes.
|
||||
*/
|
||||
classes?: { [ key: string]: string; };
|
||||
|
||||
/**
|
||||
* The recording mode this indicator should display.
|
||||
*/
|
||||
mode: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* State of the component.
|
||||
*/
|
||||
interface IState {
|
||||
|
||||
/**
|
||||
* True if the label status is stale, so it needs to be removed.
|
||||
*/
|
||||
staleLabel: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract class for the {@code RecordingLabel} component.
|
||||
*/
|
||||
export default class AbstractRecordingLabel extends Component<IProps, IState> {
|
||||
export default class AbstractRecordingLabel<P extends IProps = IProps> extends Component<P> {
|
||||
/**
|
||||
* Implements React {@code Component}'s render.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
return this.props._isRecordingRunning && !this.props._iAmRecorder
|
||||
? this._renderLabel() : null;
|
||||
const { _iAmRecorder, _isVisible } = this.props;
|
||||
|
||||
return _isVisible && !_iAmRecorder ? this._renderLabel() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,11 +79,18 @@ export default class AbstractRecordingLabel extends Component<IProps, IState> {
|
||||
*/
|
||||
export function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const { mode } = ownProps;
|
||||
const isLiveStreamingLabel = mode === JitsiRecordingConstants.mode.STREAM;
|
||||
const _isTranscribing = isRecorderTranscriptionsRunning(state);
|
||||
const isLivestreamingRunning = Boolean(getActiveSession(state, JitsiRecordingConstants.mode.STREAM));
|
||||
const _isVisible = isLiveStreamingLabel
|
||||
? isLivestreamingRunning // this is the livestreaming label
|
||||
: isRecordingRunning(state) || isRemoteParticipantRecordingLocally(state)
|
||||
|| _isTranscribing; // this is the recording label
|
||||
|
||||
return {
|
||||
_isRecordingRunning: isRecordingRunning(state),
|
||||
_isVisible,
|
||||
_iAmRecorder: Boolean(state['features/base/config'].iAmRecorder),
|
||||
_isTranscribing: isTranscribing(state),
|
||||
_isTranscribing,
|
||||
_status: getSessionStatusToShow(state, mode)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { isLocalParticipantModerator } from '../../../base/participants/function
|
||||
import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
|
||||
import { isInBreakoutRoom } from '../../../breakout-rooms/functions';
|
||||
import { maybeShowPremiumFeatureDialog } from '../../../jaas/actions';
|
||||
import { isRecorderTranscriptionsRunning } from '../../../transcribing/functions';
|
||||
import { getActiveSession, isCloudRecordingRunning } from '../../functions';
|
||||
|
||||
import { getLiveStreaming } from './functions';
|
||||
@@ -140,7 +141,7 @@ export function _mapStateToProps(state: IReduxState, ownProps: IProps) {
|
||||
}
|
||||
|
||||
// disable the button if the recording is running.
|
||||
if (visible && isCloudRecordingRunning(state)) {
|
||||
if (visible && (isCloudRecordingRunning(state) || isRecorderTranscriptionsRunning(state))) {
|
||||
_disabled = true;
|
||||
_tooltip = 'dialog.liveStreamingDisabledBecauseOfActiveRecordingTooltip';
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@ export type LiveStreaming = {
|
||||
};
|
||||
|
||||
export type LiveStreamingProps = {
|
||||
dataPrivacyURL: string;
|
||||
dataPrivacyURL?: string;
|
||||
enabled: boolean;
|
||||
helpURL: string;
|
||||
helpURL?: string;
|
||||
streamLinkRegexp: RegExp;
|
||||
termsURL: string;
|
||||
termsURL?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -38,8 +38,6 @@ export interface IProps extends WithTranslation {
|
||||
*/
|
||||
_liveStreaming: LiveStreamingProps;
|
||||
|
||||
classes?: any;
|
||||
|
||||
/**
|
||||
* Callback invoked when the entered stream key has changed.
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { sanitizeUrl } from '../../../base/util/uri';
|
||||
|
||||
import {
|
||||
FOUR_GROUPS_DASH_SEPARATED,
|
||||
@@ -15,15 +16,13 @@ import {
|
||||
*/
|
||||
export function getLiveStreaming(state: IReduxState) {
|
||||
const { liveStreaming = {} } = state['features/base/config'];
|
||||
|
||||
const regexp = liveStreaming.validatorRegExpString
|
||||
&& new RegExp(liveStreaming.validatorRegExpString);
|
||||
const regexp = liveStreaming.validatorRegExpString && new RegExp(liveStreaming.validatorRegExpString);
|
||||
|
||||
return {
|
||||
enabled: Boolean(liveStreaming.enabled),
|
||||
helpURL: liveStreaming.helpLink || JITSI_LIVE_STREAMING_HELP_LINK,
|
||||
termsURL: liveStreaming.termsLink || YOUTUBE_TERMS_URL,
|
||||
dataPrivacyURL: liveStreaming.dataPrivacyLink || GOOGLE_PRIVACY_POLICY,
|
||||
helpURL: sanitizeUrl(liveStreaming.helpLink || JITSI_LIVE_STREAMING_HELP_LINK)?.toString(),
|
||||
termsURL: sanitizeUrl(liveStreaming.termsLink || YOUTUBE_TERMS_URL)?.toString(),
|
||||
dataPrivacyURL: sanitizeUrl(liveStreaming.dataPrivacyLink || GOOGLE_PRIVACY_POLICY)?.toString(),
|
||||
streamLinkRegexp: regexp || FOUR_GROUPS_DASH_SEPARATED
|
||||
};
|
||||
}
|
||||
|
||||
@@ -107,7 +107,11 @@ class StreamKeyForm extends AbstractStreamKeyForm<IProps> {
|
||||
* @returns {void}
|
||||
*/
|
||||
_onOpenGooglePrivacyPolicy() {
|
||||
Linking.openURL(this.props._liveStreaming.dataPrivacyURL);
|
||||
const url = this.props._liveStreaming.dataPrivacyURL;
|
||||
|
||||
if (typeof url === 'string') {
|
||||
Linking.openURL(url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,10 +122,10 @@ class StreamKeyForm extends AbstractStreamKeyForm<IProps> {
|
||||
* @returns {void}
|
||||
*/
|
||||
_onOpenHelp() {
|
||||
const helpURL = this.props._liveStreaming.helpURL;
|
||||
const url = this.props._liveStreaming.helpURL;
|
||||
|
||||
if (typeof helpURL === 'string') {
|
||||
Linking.openURL(helpURL);
|
||||
if (typeof url === 'string') {
|
||||
Linking.openURL(url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +136,11 @@ class StreamKeyForm extends AbstractStreamKeyForm<IProps> {
|
||||
* @returns {void}
|
||||
*/
|
||||
_onOpenYoutubeTerms() {
|
||||
Linking.openURL(this.props._liveStreaming.termsURL);
|
||||
const url = this.props._liveStreaming.termsURL;
|
||||
|
||||
if (typeof url === 'string') {
|
||||
Linking.openURL(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../../app/types';
|
||||
import { getToolbarButtons } from '../../../../base/config/functions.web';
|
||||
import { openDialog } from '../../../../base/dialog/actions';
|
||||
import { translate } from '../../../../base/i18n/functions';
|
||||
import AbstractLiveStreamButton, {
|
||||
@@ -50,11 +49,11 @@ class LiveStreamButton extends AbstractLiveStreamButton<IProps> {
|
||||
*/
|
||||
function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const abstractProps = _abstractMapStateToProps(state, ownProps);
|
||||
const toolbarButtons = getToolbarButtons(state);
|
||||
const { toolbarButtons } = state['features/toolbox'];
|
||||
let { visible } = ownProps;
|
||||
|
||||
if (typeof visible === 'undefined') {
|
||||
visible = toolbarButtons.includes('livestreaming') && abstractProps.visible;
|
||||
visible = Boolean(toolbarButtons?.includes('livestreaming') && abstractProps.visible);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
import { Theme } from '@mui/material';
|
||||
import { withStyles } from '@mui/styles';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { withStyles } from 'tss-react/mui';
|
||||
|
||||
import { translate } from '../../../../base/i18n/functions';
|
||||
import { withPixelLineHeight } from '../../../../base/styles/functions.web';
|
||||
import Input from '../../../../base/ui/components/web/Input';
|
||||
import AbstractStreamKeyForm, {
|
||||
IProps, _mapStateToProps
|
||||
IProps as AbstractProps,
|
||||
_mapStateToProps
|
||||
} from '../AbstractStreamKeyForm';
|
||||
|
||||
interface IProps extends AbstractProps {
|
||||
|
||||
/**
|
||||
* An object containing the CSS classes.
|
||||
*/
|
||||
classes?: Partial<Record<keyof ReturnType<typeof styles>, string>>;
|
||||
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) => {
|
||||
return {
|
||||
helperLink: {
|
||||
@@ -46,7 +56,8 @@ class StreamKeyForm extends AbstractStreamKeyForm<IProps> {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { classes, t, value } = this.props;
|
||||
const { t, value } = this.props;
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
|
||||
return (
|
||||
<div className = 'stream-key-form'>
|
||||
@@ -99,4 +110,4 @@ class StreamKeyForm extends AbstractStreamKeyForm<IProps> {
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(withStyles(styles)(StreamKeyForm)));
|
||||
export default translate(connect(_mapStateToProps)(withStyles(StreamKeyForm, styles)));
|
||||
|
||||
@@ -32,6 +32,11 @@ export interface IProps extends WithTranslation {
|
||||
*/
|
||||
_conference?: IJitsiConference;
|
||||
|
||||
/**
|
||||
* Whether subtitles should be displayed or not.
|
||||
*/
|
||||
_displaySubtitles?: boolean;
|
||||
|
||||
/**
|
||||
* Whether to show file recordings service, even if integrations
|
||||
* are enabled.
|
||||
@@ -69,6 +74,11 @@ export interface IProps extends WithTranslation {
|
||||
*/
|
||||
_screenshotCaptureEnabled: boolean;
|
||||
|
||||
/**
|
||||
* The selected language for subtitles.
|
||||
*/
|
||||
_subtitlesLanguage: string | null;
|
||||
|
||||
/**
|
||||
* The dropbox access token.
|
||||
*/
|
||||
@@ -336,8 +346,10 @@ class AbstractStartRecordingDialog extends Component<IProps, IState> {
|
||||
const {
|
||||
_appKey,
|
||||
_conference,
|
||||
_displaySubtitles,
|
||||
_isDropboxEnabled,
|
||||
_rToken,
|
||||
_subtitlesLanguage,
|
||||
_token,
|
||||
dispatch
|
||||
} = this.props;
|
||||
@@ -397,8 +409,9 @@ class AbstractStartRecordingDialog extends Component<IProps, IState> {
|
||||
});
|
||||
}
|
||||
|
||||
if (this.state.shouldRecordTranscription) {
|
||||
dispatch(setRequestingSubtitles(true, false, null));
|
||||
if (this.state.selectedRecordingService === RECORDING_TYPES.JITSI_REC_SERVICE
|
||||
&& this.state.shouldRecordTranscription) {
|
||||
dispatch(setRequestingSubtitles(true, _displaySubtitles, _subtitlesLanguage));
|
||||
}
|
||||
|
||||
_conference?.getMetadataHandler().setMetadata(RECORDING_METADATA_ID, {
|
||||
@@ -433,17 +446,7 @@ class AbstractStartRecordingDialog extends Component<IProps, IState> {
|
||||
* @param {Object} state - The Redux state.
|
||||
* @param {any} _ownProps - Component's own props.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _appKey: string,
|
||||
* _autoTranscribeOnRecord: boolean,
|
||||
* _conference: JitsiConference,
|
||||
* _fileRecordingsServiceEnabled: boolean,
|
||||
* _fileRecordingsServiceSharingEnabled: boolean,
|
||||
* _isDropboxEnabled: boolean,
|
||||
* _rToken:string,
|
||||
* _tokenExpireDate: number,
|
||||
* _token: string
|
||||
* }}
|
||||
* @returns {IProps}
|
||||
*/
|
||||
export function mapStateToProps(state: IReduxState, _ownProps: any) {
|
||||
const {
|
||||
@@ -451,16 +454,22 @@ export function mapStateToProps(state: IReduxState, _ownProps: any) {
|
||||
dropbox = { appKey: undefined },
|
||||
localRecording
|
||||
} = state['features/base/config'];
|
||||
const {
|
||||
_displaySubtitles,
|
||||
_language: _subtitlesLanguage
|
||||
} = state['features/subtitles'];
|
||||
|
||||
return {
|
||||
_appKey: dropbox.appKey ?? '',
|
||||
_autoTranscribeOnRecord: shouldAutoTranscribeOnRecord(state),
|
||||
_conference: state['features/base/conference'].conference,
|
||||
_displaySubtitles,
|
||||
_fileRecordingsServiceEnabled: recordingService?.enabled ?? false,
|
||||
_fileRecordingsServiceSharingEnabled: isRecordingSharingEnabled(state),
|
||||
_isDropboxEnabled: isDropboxEnabled(state),
|
||||
_localRecordingEnabled: !localRecording?.disable,
|
||||
_rToken: state['features/dropbox'].rToken ?? '',
|
||||
_subtitlesLanguage,
|
||||
_tokenExpireDate: state['features/dropbox'].expireDate,
|
||||
_token: state['features/dropbox'].token ?? ''
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@ import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
|
||||
import { setVideoMuted } from '../../../base/media/actions';
|
||||
import { setRequestingSubtitles } from '../../../subtitles/actions.any';
|
||||
import { stopLocalVideoRecording } from '../../actions';
|
||||
import { RECORDING_METADATA_ID } from '../../constants';
|
||||
import { getActiveSession } from '../../functions';
|
||||
import { ISessionData } from '../../reducer';
|
||||
|
||||
@@ -25,6 +26,11 @@ export interface IProps extends WithTranslation {
|
||||
*/
|
||||
_conference?: IJitsiConference;
|
||||
|
||||
/**
|
||||
* Whether subtitles should be displayed or not.
|
||||
*/
|
||||
_displaySubtitles?: boolean;
|
||||
|
||||
/**
|
||||
* The redux representation of the recording session to be stopped.
|
||||
*/
|
||||
@@ -35,6 +41,11 @@ export interface IProps extends WithTranslation {
|
||||
*/
|
||||
_localRecording: boolean;
|
||||
|
||||
/**
|
||||
* The selected language for subtitles.
|
||||
*/
|
||||
_subtitlesLanguage: string | null;
|
||||
|
||||
/**
|
||||
* The redux dispatch function.
|
||||
*/
|
||||
@@ -76,22 +87,32 @@ export default class AbstractStopRecordingDialog<P extends IProps>
|
||||
_onSubmit() {
|
||||
sendAnalytics(createRecordingDialogEvent('stop', 'confirm.button'));
|
||||
|
||||
if (this.props._localRecording) {
|
||||
this.props.dispatch(stopLocalVideoRecording());
|
||||
if (this.props.localRecordingVideoStop) {
|
||||
this.props.dispatch(setVideoMuted(true));
|
||||
}
|
||||
} else {
|
||||
const { _fileRecordingSession } = this.props;
|
||||
const {
|
||||
_conference,
|
||||
_displaySubtitles,
|
||||
_fileRecordingSession,
|
||||
_localRecording,
|
||||
_subtitlesLanguage,
|
||||
dispatch,
|
||||
localRecordingVideoStop
|
||||
} = this.props;
|
||||
|
||||
if (_fileRecordingSession) {
|
||||
this.props._conference?.stopRecording(_fileRecordingSession.id);
|
||||
this._toggleScreenshotCapture();
|
||||
if (_localRecording) {
|
||||
dispatch(stopLocalVideoRecording());
|
||||
if (localRecordingVideoStop) {
|
||||
dispatch(setVideoMuted(true));
|
||||
}
|
||||
} else if (_fileRecordingSession) {
|
||||
_conference?.stopRecording(_fileRecordingSession.id);
|
||||
this._toggleScreenshotCapture();
|
||||
}
|
||||
|
||||
// TODO: this should be an action in transcribing. -saghul
|
||||
this.props.dispatch(setRequestingSubtitles(false, false, null));
|
||||
this.props.dispatch(setRequestingSubtitles(Boolean(_displaySubtitles), _displaySubtitles, _subtitlesLanguage));
|
||||
|
||||
this.props._conference?.getMetadataHandler().setMetadata(RECORDING_METADATA_ID, {
|
||||
isTranscribingEnabled: false
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -112,16 +133,20 @@ export default class AbstractStopRecordingDialog<P extends IProps>
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _conference: JitsiConference,
|
||||
* _fileRecordingSession: Object
|
||||
* }}
|
||||
* @returns {IProps}
|
||||
*/
|
||||
export function _mapStateToProps(state: IReduxState) {
|
||||
const {
|
||||
_displaySubtitles,
|
||||
_language: _subtitlesLanguage
|
||||
} = state['features/subtitles'];
|
||||
|
||||
return {
|
||||
_conference: state['features/base/conference'].conference,
|
||||
_displaySubtitles,
|
||||
_fileRecordingSession:
|
||||
getActiveSession(state, JitsiRecordingConstants.mode.FILE),
|
||||
_localRecording: LocalRecordingManager.isRecordingLocally()
|
||||
_localRecording: LocalRecordingManager.isRecordingLocally(),
|
||||
_subtitlesLanguage
|
||||
};
|
||||
}
|
||||
|
||||
@@ -36,9 +36,6 @@ interface ILocalRecordingManager {
|
||||
|
||||
const getMimeType = (): string => {
|
||||
const possibleTypes = [
|
||||
'video/mp4;codecs=h264',
|
||||
'video/webm;codecs=h264',
|
||||
'video/webm;codecs=vp9',
|
||||
'video/webm;codecs=vp8'
|
||||
];
|
||||
|
||||
@@ -164,7 +161,11 @@ const LocalRecordingManager: ILocalRecordingManager = {
|
||||
this.audioContext = undefined;
|
||||
this.audioDestination = undefined;
|
||||
this.totalSize = MAX_SIZE;
|
||||
setTimeout(() => this.saveRecording(this.recordingData, this.getFilename()), 1000);
|
||||
setTimeout(() => {
|
||||
if (this.recordingData.length > 0) {
|
||||
this.saveRecording(this.recordingData, this.getFilename());
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -51,7 +51,9 @@ class StartRecordingDialogContent extends AbstractStartRecordingDialogContent {
|
||||
* @returns {React$Component}
|
||||
*/
|
||||
_renderAdvancedOptions() {
|
||||
if (!this._canStartTranscribing()) {
|
||||
const { selectedRecordingService } = this.props;
|
||||
|
||||
if (selectedRecordingService !== RECORDING_TYPES.JITSI_REC_SERVICE || !this._canStartTranscribing()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Theme } from '@mui/material';
|
||||
import { withStyles } from '@mui/styles';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { withStyles } from 'tss-react/mui';
|
||||
|
||||
import { openDialog } from '../../../../base/dialog/actions';
|
||||
import { translate } from '../../../../base/i18n/functions';
|
||||
@@ -30,7 +30,10 @@ interface IProps extends AbstractProps {
|
||||
*/
|
||||
_visible: boolean;
|
||||
|
||||
classes: any;
|
||||
/**
|
||||
* An object containing the CSS classes.
|
||||
*/
|
||||
classes?: Partial<Record<keyof ReturnType<typeof styles>, string>>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,7 +72,7 @@ const styles = (theme: Theme) => {
|
||||
boxSizing: 'border-box' as const,
|
||||
color: theme.palette.uiBackground,
|
||||
fontSize: '14px',
|
||||
fontWeight: '400',
|
||||
fontWeight: 400,
|
||||
left: '4px',
|
||||
padding: '16px',
|
||||
position: 'absolute' as const,
|
||||
@@ -79,7 +82,7 @@ const styles = (theme: Theme) => {
|
||||
highlightNotificationButton: {
|
||||
color: theme.palette.action01,
|
||||
cursor: 'pointer',
|
||||
fontWeight: '600',
|
||||
fontWeight: 600,
|
||||
marginTop: '8px'
|
||||
}
|
||||
};
|
||||
@@ -181,9 +184,9 @@ export class HighlightButton extends AbstractHighlightButton<IProps, IState> {
|
||||
const {
|
||||
_disabled,
|
||||
_visible,
|
||||
classes,
|
||||
t
|
||||
} = this.props;
|
||||
const classes = withStyles.getClasses(this.props);
|
||||
|
||||
if (!_visible) {
|
||||
return null;
|
||||
@@ -219,4 +222,4 @@ export class HighlightButton extends AbstractHighlightButton<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(translate(connect(_abstractMapStateToProps)(HighlightButton)));
|
||||
export default withStyles(translate(connect(_abstractMapStateToProps)(HighlightButton)), styles);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../../app/types';
|
||||
import { getToolbarButtons } from '../../../../base/config/functions.web';
|
||||
import { openDialog } from '../../../../base/dialog/actions';
|
||||
import { translate } from '../../../../base/i18n/functions';
|
||||
import AbstractRecordButton, {
|
||||
@@ -49,8 +48,8 @@ class RecordingButton extends AbstractRecordButton<IProps> {
|
||||
*/
|
||||
export function _mapStateToProps(state: IReduxState) {
|
||||
const abstractProps = _abstractMapStateToProps(state);
|
||||
const toolbarButtons = getToolbarButtons(state);
|
||||
const visible = toolbarButtons.includes('recording') && abstractProps.visible;
|
||||
const { toolbarButtons } = state['features/toolbox'];
|
||||
const visible = Boolean(toolbarButtons?.includes('recording') && abstractProps.visible);
|
||||
|
||||
return {
|
||||
...abstractProps,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user