Compare commits
25 Commits
ios_locksc
...
6829
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bce0bc917 | ||
|
|
93566e313e | ||
|
|
a7c653bc30 | ||
|
|
4b969cf4ab | ||
|
|
3081b41d0d | ||
|
|
30e5d213cb | ||
|
|
752da71387 | ||
|
|
645609974a | ||
|
|
4f2f6df2bb | ||
|
|
e93c480e7c | ||
|
|
a795e0797a | ||
|
|
94ec2c720d | ||
|
|
b11e14ea34 | ||
|
|
f5f55c4f23 | ||
|
|
243a330318 | ||
|
|
98bc87ea18 | ||
|
|
f7926c9cfb | ||
|
|
533501deb6 | ||
|
|
f38c9f5450 | ||
|
|
55b80c948f | ||
|
|
971fe0481f | ||
|
|
1259e54d46 | ||
|
|
0cb95f1dd6 | ||
|
|
5cde9a138b | ||
|
|
867c488e10 |
@@ -76,7 +76,7 @@ android {
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.5.1'
|
||||
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import groovy.json.JsonSlurper
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
import org.gradle.util.VersionNumber
|
||||
|
||||
// Top-level build file where you can add configuration options common to all
|
||||
@@ -12,16 +11,16 @@ buildscript {
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.0.4'
|
||||
classpath 'com.google.gms:google-services:4.3.10'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
|
||||
classpath 'com.google.gms:google-services:4.3.14'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2'
|
||||
}
|
||||
}
|
||||
|
||||
ext {
|
||||
buildToolsVersion = "31.0.0"
|
||||
compileSdkVersion = 31
|
||||
compileSdkVersion = 32
|
||||
minSdkVersion = 23
|
||||
targetSdkVersion = 31
|
||||
targetSdkVersion = 32
|
||||
supportLibVersion = "28.0.0"
|
||||
|
||||
if (System.properties['os.arch'] == "aarch64") {
|
||||
|
||||
@@ -42,10 +42,10 @@ public class WebRTCVideoDecoderFactory implements VideoDecoderFactory {
|
||||
public VideoCodecInfo[] getSupportedCodecs() {
|
||||
List<VideoCodecInfo> codecs = new ArrayList<>();
|
||||
|
||||
codecs.add(H264Utils.DEFAULT_H264_BASELINE_PROFILE_CODEC);
|
||||
codecs.add(new VideoCodecInfo(VideoCodecMimeType.VP8.name(), new HashMap<>()));
|
||||
codecs.add(new VideoCodecInfo(VideoCodecMimeType.VP9.name(), new HashMap<>()));
|
||||
codecs.add(new VideoCodecInfo(VideoCodecMimeType.AV1.name(), new HashMap<>()));
|
||||
codecs.add(H264Utils.DEFAULT_H264_BASELINE_PROFILE_CODEC);
|
||||
|
||||
return codecs.toArray(new VideoCodecInfo[codecs.size()]);
|
||||
}
|
||||
|
||||
@@ -43,10 +43,10 @@ public class WebRTCVideoEncoderFactory implements VideoEncoderFactory {
|
||||
public VideoCodecInfo[] getSupportedCodecs() {
|
||||
List<VideoCodecInfo> codecs = new ArrayList<>();
|
||||
|
||||
codecs.add(H264Utils.DEFAULT_H264_BASELINE_PROFILE_CODEC);
|
||||
codecs.add(new VideoCodecInfo(VideoCodecMimeType.VP8.name(), new HashMap<>()));
|
||||
codecs.add(new VideoCodecInfo(VideoCodecMimeType.VP9.name(), new HashMap<>()));
|
||||
codecs.add(new VideoCodecInfo(VideoCodecMimeType.AV1.name(), new HashMap<>()));
|
||||
codecs.add(H264Utils.DEFAULT_H264_BASELINE_PROFILE_CODEC);
|
||||
|
||||
return codecs.toArray(new VideoCodecInfo[codecs.size()]);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ import {
|
||||
conferenceUniqueIdSet,
|
||||
conferenceWillJoin,
|
||||
conferenceWillLeave,
|
||||
dataChannelClosed,
|
||||
dataChannelOpened,
|
||||
e2eRttChanged,
|
||||
getConferenceOptions,
|
||||
@@ -54,10 +55,7 @@ import {
|
||||
p2pStatusChanged,
|
||||
sendLocalParticipant
|
||||
} from './react/features/base/conference';
|
||||
import {
|
||||
getMultipleVideoSendingSupportFeatureFlag,
|
||||
getReplaceParticipant
|
||||
} from './react/features/base/config/functions';
|
||||
import { getReplaceParticipant } from './react/features/base/config/functions';
|
||||
import {
|
||||
checkAndNotifyForNewDevice,
|
||||
getAvailableDevices,
|
||||
@@ -134,9 +132,12 @@ import {
|
||||
import { maybeSetLobbyChatMessageListener } from './react/features/lobby/actions.any';
|
||||
import { setNoiseSuppressionEnabled } from './react/features/noise-suppression/actions';
|
||||
import {
|
||||
DATA_CHANNEL_CLOSED_NOTIFICATION_ID,
|
||||
NOTIFICATION_TIMEOUT_TYPE,
|
||||
hideNotification,
|
||||
isModerationNotificationDisplayed,
|
||||
showNotification
|
||||
showNotification,
|
||||
showWarningNotification
|
||||
} from './react/features/notifications';
|
||||
import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay';
|
||||
import { suspendDetected } from './react/features/power-monitor';
|
||||
@@ -1418,30 +1419,13 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
// In the multi-stream mode, add the track to the conference if there is no existing track, replace it
|
||||
// otherwise.
|
||||
if (getMultipleVideoSendingSupportFeatureFlag(state)) {
|
||||
const trackAction = oldTrack
|
||||
? replaceLocalTrack(oldTrack, newTrack, room)
|
||||
: addLocalTrack(newTrack);
|
||||
// Add the track to the conference if there is no existing track, replace it otherwise.
|
||||
const trackAction = oldTrack
|
||||
? replaceLocalTrack(oldTrack, newTrack, room)
|
||||
: addLocalTrack(newTrack);
|
||||
|
||||
APP.store.dispatch(trackAction)
|
||||
.then(() => {
|
||||
this.setVideoMuteStatus();
|
||||
})
|
||||
.then(resolve)
|
||||
.catch(error => {
|
||||
logger.error(`useVideoStream failed: ${error}`);
|
||||
reject(error);
|
||||
})
|
||||
.then(onFinish);
|
||||
|
||||
return;
|
||||
}
|
||||
APP.store.dispatch(
|
||||
replaceLocalTrack(oldTrack, newTrack, room))
|
||||
APP.store.dispatch(trackAction)
|
||||
.then(() => {
|
||||
this._setSharingScreen(newTrack);
|
||||
this.setVideoMuteStatus();
|
||||
})
|
||||
.then(resolve)
|
||||
@@ -2067,6 +2051,18 @@ export default {
|
||||
room.on(
|
||||
JitsiConferenceEvents.DATA_CHANNEL_OPENED, () => {
|
||||
APP.store.dispatch(dataChannelOpened());
|
||||
APP.store.dispatch(hideNotification(DATA_CHANNEL_CLOSED_NOTIFICATION_ID));
|
||||
}
|
||||
);
|
||||
|
||||
room.on(
|
||||
JitsiConferenceEvents.DATA_CHANNEL_CLOSED, ev => {
|
||||
APP.store.dispatch(dataChannelClosed(ev.code, ev.reason));
|
||||
APP.store.dispatch(showWarningNotification({
|
||||
descriptionKey: 'notify.dataChannelClosedDescription',
|
||||
titleKey: 'notify.dataChannelClosed',
|
||||
uid: DATA_CHANNEL_CLOSED_NOTIFICATION_ID
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
2
globals.native.d.ts
vendored
@@ -23,6 +23,8 @@ interface IWindow {
|
||||
onerror: (event: string, source: any, lineno: any, colno: any, e: Error) => void;
|
||||
onunhandledrejection: (event: any) => void;
|
||||
|
||||
setInterval: typeof setInterval;
|
||||
clearInterval: typeof clearInterval;
|
||||
setTimeout: typeof setTimeout;
|
||||
clearTimeout: typeof clearTimeout;
|
||||
setImmediate: typeof setImmediate;
|
||||
|
||||
430
ios/Podfile.lock
@@ -13,14 +13,14 @@ PODS:
|
||||
- CocoaLumberjack/Core (= 3.7.2)
|
||||
- CocoaLumberjack/Core (3.7.2)
|
||||
- DoubleConversion (1.1.6)
|
||||
- FBLazyVector (0.68.4)
|
||||
- FBReactNativeSpec (0.68.4):
|
||||
- FBLazyVector (0.68.5)
|
||||
- FBReactNativeSpec (0.68.5):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTRequired (= 0.68.4)
|
||||
- RCTTypeSafety (= 0.68.4)
|
||||
- React-Core (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- ReactCommon/turbomodule/core (= 0.68.4)
|
||||
- RCTRequired (= 0.68.5)
|
||||
- RCTTypeSafety (= 0.68.5)
|
||||
- React-Core (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- Firebase/Analytics (8.15.0):
|
||||
- Firebase/Core
|
||||
- Firebase/Core (8.15.0):
|
||||
@@ -163,201 +163,201 @@ PODS:
|
||||
- DoubleConversion
|
||||
- fmt (~> 6.2.1)
|
||||
- glog
|
||||
- RCTRequired (0.68.4)
|
||||
- RCTTypeSafety (0.68.4):
|
||||
- FBLazyVector (= 0.68.4)
|
||||
- RCTRequired (0.68.5)
|
||||
- RCTTypeSafety (0.68.5):
|
||||
- FBLazyVector (= 0.68.5)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTRequired (= 0.68.4)
|
||||
- React-Core (= 0.68.4)
|
||||
- React (0.68.4):
|
||||
- React-Core (= 0.68.4)
|
||||
- React-Core/DevSupport (= 0.68.4)
|
||||
- React-Core/RCTWebSocket (= 0.68.4)
|
||||
- React-RCTActionSheet (= 0.68.4)
|
||||
- React-RCTAnimation (= 0.68.4)
|
||||
- React-RCTBlob (= 0.68.4)
|
||||
- React-RCTImage (= 0.68.4)
|
||||
- React-RCTLinking (= 0.68.4)
|
||||
- React-RCTNetwork (= 0.68.4)
|
||||
- React-RCTSettings (= 0.68.4)
|
||||
- React-RCTText (= 0.68.4)
|
||||
- React-RCTVibration (= 0.68.4)
|
||||
- React-callinvoker (0.68.4)
|
||||
- React-Codegen (0.68.4):
|
||||
- FBReactNativeSpec (= 0.68.4)
|
||||
- RCTRequired (= 0.68.5)
|
||||
- React-Core (= 0.68.5)
|
||||
- React (0.68.5):
|
||||
- React-Core (= 0.68.5)
|
||||
- React-Core/DevSupport (= 0.68.5)
|
||||
- React-Core/RCTWebSocket (= 0.68.5)
|
||||
- React-RCTActionSheet (= 0.68.5)
|
||||
- React-RCTAnimation (= 0.68.5)
|
||||
- React-RCTBlob (= 0.68.5)
|
||||
- React-RCTImage (= 0.68.5)
|
||||
- React-RCTLinking (= 0.68.5)
|
||||
- React-RCTNetwork (= 0.68.5)
|
||||
- React-RCTSettings (= 0.68.5)
|
||||
- React-RCTText (= 0.68.5)
|
||||
- React-RCTVibration (= 0.68.5)
|
||||
- React-callinvoker (0.68.5)
|
||||
- React-Codegen (0.68.5):
|
||||
- FBReactNativeSpec (= 0.68.5)
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTRequired (= 0.68.4)
|
||||
- RCTTypeSafety (= 0.68.4)
|
||||
- React-Core (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsiexecutor (= 0.68.4)
|
||||
- ReactCommon/turbomodule/core (= 0.68.4)
|
||||
- React-Core (0.68.4):
|
||||
- RCTRequired (= 0.68.5)
|
||||
- RCTTypeSafety (= 0.68.5)
|
||||
- React-Core (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-Core (0.68.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default (= 0.68.4)
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsiexecutor (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-Core/Default (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- Yoga
|
||||
- React-Core/CoreModulesHeaders (0.68.4):
|
||||
- React-Core/CoreModulesHeaders (0.68.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsiexecutor (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- Yoga
|
||||
- React-Core/Default (0.68.4):
|
||||
- React-Core/Default (0.68.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsiexecutor (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- Yoga
|
||||
- React-Core/DevSupport (0.68.4):
|
||||
- React-Core/DevSupport (0.68.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default (= 0.68.4)
|
||||
- React-Core/RCTWebSocket (= 0.68.4)
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsiexecutor (= 0.68.4)
|
||||
- React-jsinspector (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-Core/Default (= 0.68.5)
|
||||
- React-Core/RCTWebSocket (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-jsinspector (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- Yoga
|
||||
- React-Core/RCTActionSheetHeaders (0.68.4):
|
||||
- React-Core/RCTActionSheetHeaders (0.68.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsiexecutor (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- Yoga
|
||||
- React-Core/RCTAnimationHeaders (0.68.4):
|
||||
- React-Core/RCTAnimationHeaders (0.68.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsiexecutor (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- Yoga
|
||||
- React-Core/RCTBlobHeaders (0.68.4):
|
||||
- React-Core/RCTBlobHeaders (0.68.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsiexecutor (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- Yoga
|
||||
- React-Core/RCTImageHeaders (0.68.4):
|
||||
- React-Core/RCTImageHeaders (0.68.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsiexecutor (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- Yoga
|
||||
- React-Core/RCTLinkingHeaders (0.68.4):
|
||||
- React-Core/RCTLinkingHeaders (0.68.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsiexecutor (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- Yoga
|
||||
- React-Core/RCTNetworkHeaders (0.68.4):
|
||||
- React-Core/RCTNetworkHeaders (0.68.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsiexecutor (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- Yoga
|
||||
- React-Core/RCTSettingsHeaders (0.68.4):
|
||||
- React-Core/RCTSettingsHeaders (0.68.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsiexecutor (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- Yoga
|
||||
- React-Core/RCTTextHeaders (0.68.4):
|
||||
- React-Core/RCTTextHeaders (0.68.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsiexecutor (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- Yoga
|
||||
- React-Core/RCTVibrationHeaders (0.68.4):
|
||||
- React-Core/RCTVibrationHeaders (0.68.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsiexecutor (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- Yoga
|
||||
- React-Core/RCTWebSocket (0.68.4):
|
||||
- React-Core/RCTWebSocket (0.68.5):
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Core/Default (= 0.68.4)
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsiexecutor (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-Core/Default (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsiexecutor (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- Yoga
|
||||
- React-CoreModules (0.68.4):
|
||||
- React-CoreModules (0.68.5):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.68.4)
|
||||
- React-Codegen (= 0.68.4)
|
||||
- React-Core/CoreModulesHeaders (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-RCTImage (= 0.68.4)
|
||||
- ReactCommon/turbomodule/core (= 0.68.4)
|
||||
- React-cxxreact (0.68.4):
|
||||
- RCTTypeSafety (= 0.68.5)
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/CoreModulesHeaders (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-RCTImage (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-cxxreact (0.68.5):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-callinvoker (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-jsinspector (= 0.68.4)
|
||||
- React-logger (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-runtimeexecutor (= 0.68.4)
|
||||
- React-jsi (0.68.4):
|
||||
- React-callinvoker (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-jsinspector (= 0.68.5)
|
||||
- React-logger (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-runtimeexecutor (= 0.68.5)
|
||||
- React-jsi (0.68.5):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-jsi/Default (= 0.68.4)
|
||||
- React-jsi/Default (0.68.4):
|
||||
- React-jsi/Default (= 0.68.5)
|
||||
- React-jsi/Default (0.68.5):
|
||||
- boost (= 1.76.0)
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-jsiexecutor (0.68.4):
|
||||
- React-jsiexecutor (0.68.5):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-jsinspector (0.68.4)
|
||||
- React-logger (0.68.4):
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- React-jsinspector (0.68.5)
|
||||
- React-logger (0.68.5):
|
||||
- glog
|
||||
- react-native-background-timer (2.4.1):
|
||||
- React-Core
|
||||
@@ -390,71 +390,71 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-webview (11.15.1):
|
||||
- React-Core
|
||||
- React-perflogger (0.68.4)
|
||||
- React-RCTActionSheet (0.68.4):
|
||||
- React-Core/RCTActionSheetHeaders (= 0.68.4)
|
||||
- React-RCTAnimation (0.68.4):
|
||||
- React-perflogger (0.68.5)
|
||||
- React-RCTActionSheet (0.68.5):
|
||||
- React-Core/RCTActionSheetHeaders (= 0.68.5)
|
||||
- React-RCTAnimation (0.68.5):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.68.4)
|
||||
- React-Codegen (= 0.68.4)
|
||||
- React-Core/RCTAnimationHeaders (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- ReactCommon/turbomodule/core (= 0.68.4)
|
||||
- React-RCTBlob (0.68.4):
|
||||
- RCTTypeSafety (= 0.68.5)
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/RCTAnimationHeaders (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-RCTBlob (0.68.5):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Codegen (= 0.68.4)
|
||||
- React-Core/RCTBlobHeaders (= 0.68.4)
|
||||
- React-Core/RCTWebSocket (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-RCTNetwork (= 0.68.4)
|
||||
- ReactCommon/turbomodule/core (= 0.68.4)
|
||||
- React-RCTImage (0.68.4):
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/RCTBlobHeaders (= 0.68.5)
|
||||
- React-Core/RCTWebSocket (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-RCTNetwork (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-RCTImage (0.68.5):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.68.4)
|
||||
- React-Codegen (= 0.68.4)
|
||||
- React-Core/RCTImageHeaders (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-RCTNetwork (= 0.68.4)
|
||||
- ReactCommon/turbomodule/core (= 0.68.4)
|
||||
- React-RCTLinking (0.68.4):
|
||||
- React-Codegen (= 0.68.4)
|
||||
- React-Core/RCTLinkingHeaders (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- ReactCommon/turbomodule/core (= 0.68.4)
|
||||
- React-RCTNetwork (0.68.4):
|
||||
- RCTTypeSafety (= 0.68.5)
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/RCTImageHeaders (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-RCTNetwork (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-RCTLinking (0.68.5):
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/RCTLinkingHeaders (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-RCTNetwork (0.68.5):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.68.4)
|
||||
- React-Codegen (= 0.68.4)
|
||||
- React-Core/RCTNetworkHeaders (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- ReactCommon/turbomodule/core (= 0.68.4)
|
||||
- React-RCTSettings (0.68.4):
|
||||
- RCTTypeSafety (= 0.68.5)
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/RCTNetworkHeaders (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-RCTSettings (0.68.5):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- RCTTypeSafety (= 0.68.4)
|
||||
- React-Codegen (= 0.68.4)
|
||||
- React-Core/RCTSettingsHeaders (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- ReactCommon/turbomodule/core (= 0.68.4)
|
||||
- React-RCTText (0.68.4):
|
||||
- React-Core/RCTTextHeaders (= 0.68.4)
|
||||
- React-RCTVibration (0.68.4):
|
||||
- RCTTypeSafety (= 0.68.5)
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/RCTSettingsHeaders (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-RCTText (0.68.5):
|
||||
- React-Core/RCTTextHeaders (= 0.68.5)
|
||||
- React-RCTVibration (0.68.5):
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-Codegen (= 0.68.4)
|
||||
- React-Core/RCTVibrationHeaders (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- ReactCommon/turbomodule/core (= 0.68.4)
|
||||
- React-runtimeexecutor (0.68.4):
|
||||
- React-jsi (= 0.68.4)
|
||||
- ReactCommon/turbomodule/core (0.68.4):
|
||||
- React-Codegen (= 0.68.5)
|
||||
- React-Core/RCTVibrationHeaders (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- React-runtimeexecutor (0.68.5):
|
||||
- React-jsi (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (0.68.5):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- RCT-Folly (= 2021.06.28.00-v2)
|
||||
- React-callinvoker (= 0.68.4)
|
||||
- React-Core (= 0.68.4)
|
||||
- React-cxxreact (= 0.68.4)
|
||||
- React-jsi (= 0.68.4)
|
||||
- React-logger (= 0.68.4)
|
||||
- React-perflogger (= 0.68.4)
|
||||
- React-callinvoker (= 0.68.5)
|
||||
- React-Core (= 0.68.5)
|
||||
- React-cxxreact (= 0.68.5)
|
||||
- React-jsi (= 0.68.5)
|
||||
- React-logger (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- RNCalendarEvents (2.2.0):
|
||||
- React
|
||||
- RNCAsyncStorage (1.17.3):
|
||||
@@ -706,8 +706,8 @@ SPEC CHECKSUMS:
|
||||
boost: a7c83b31436843459a1961bfd74b96033dc77234
|
||||
CocoaLumberjack: b7e05132ff94f6ae4dfa9d5bce9141893a21d9da
|
||||
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
|
||||
FBLazyVector: 023a2028f218d648b588348bfa9261b4914b93db
|
||||
FBReactNativeSpec: 9f4902cc009389d3704ff75de2aa513dee34d5c2
|
||||
FBLazyVector: 2b47ff52037bd9ae07cc9b051c9975797814b736
|
||||
FBReactNativeSpec: 0e0d384ef17a33b385f13f0c7f97702c7cd17858
|
||||
Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d
|
||||
FirebaseAnalytics: 7761cbadb00a717d8d0939363eb46041526474fa
|
||||
FirebaseCore: 5743c5785c074a794d35f2fff7ecc254a91e08b1
|
||||
@@ -732,18 +732,18 @@ SPEC CHECKSUMS:
|
||||
PromisesObjC: ab77feca74fa2823e7af4249b8326368e61014cb
|
||||
PromisesSwift: 99fddfe4a0ec88a56486644c0da106694c92a604
|
||||
RCT-Folly: 4d8508a426467c48885f1151029bc15fa5d7b3b8
|
||||
RCTRequired: e6003505912d056f21f64465063cf4b79418f2b9
|
||||
RCTTypeSafety: d7ef4745c8d9c9faa65c26b4b6230fc5cd4c4424
|
||||
React: 6692c30fb74ab29078b25c31c9841d863e08cdd9
|
||||
React-callinvoker: fe2b234fa518d8bb7600707c536ab0a3e1f5edba
|
||||
React-Codegen: 9964bb2422c7014894182ac50068caae05f68551
|
||||
React-Core: a07bcd2f15ff93cddc9ceb07eddeec3d2ff8d990
|
||||
React-CoreModules: 7fb4ee0fc35ad2b7daf775f0ef6309efdd8d3d82
|
||||
React-cxxreact: 51a8058a35a2f02ad4175334a7cd24aa5558ced4
|
||||
React-jsi: 69b974b418d2658a3f1799903be7cbcb8ac59755
|
||||
React-jsiexecutor: 4f35a29798ba9d0d892a84001d11f626688dbb8e
|
||||
React-jsinspector: 6f75220cd4b6020976d340ab21c63458dd3cad9e
|
||||
React-logger: 7013d2499df6346e6a72802d4084badaaa82543b
|
||||
RCTRequired: 0f06b6068f530932d10e1a01a5352fad4eaacb74
|
||||
RCTTypeSafety: b0ee81f10ef1b7d977605a2b266823dabd565e65
|
||||
React: 3becd12bd51ea8a43bdde7e09d0f40fba7820e03
|
||||
React-callinvoker: 11abfff50e6bf7a55b3a90b4dc2187f71f224593
|
||||
React-Codegen: f8946ce0768fb8e92e092e30944489c4b2955b2d
|
||||
React-Core: 203cdb6ee2657b198d97d41031c249161060e6ca
|
||||
React-CoreModules: 6eb0c06a4a223fde2cb6a8d0f44f58b67e808942
|
||||
React-cxxreact: afb0c6c07d19adbd850747fedeac20c6832d40b9
|
||||
React-jsi: 14d37a6db2af2c1a49f6f5c2e4ee667c364ae45c
|
||||
React-jsiexecutor: 45c0496ca8cef6b02d9fa0274c25cf458fe91a56
|
||||
React-jsinspector: eb202e43b3879aba9a14f3f65788aec85d4e1ea9
|
||||
React-logger: 98f663b292a60967ebbc6d803ae96c1381183b6d
|
||||
react-native-background-timer: 17ea5e06803401a379ebf1f20505b793ac44d0fe
|
||||
react-native-get-random-values: 30b3f74ca34e30e2e480de48e4add2706a40ac8f
|
||||
react-native-keep-awake: afad8a51dfef9fe9655a6344771be32c8596d774
|
||||
@@ -757,18 +757,18 @@ SPEC CHECKSUMS:
|
||||
react-native-video: bb6f12a7198db53b261fefb5d609dc77417acc8b
|
||||
react-native-webrtc: 4a4c31be61f88d1d3356526eebce72f462a6760e
|
||||
react-native-webview: ea4899a1056c782afa96dd082179a66cbebf5504
|
||||
React-perflogger: 0b0500685176e53ea582c45179a653aa82e4ae49
|
||||
React-RCTActionSheet: 38469be9d20242f9c717e43c2983e8e3e6c640c4
|
||||
React-RCTAnimation: 93774f3e8857e7c3c1cbbd277056d02be4496be1
|
||||
React-RCTBlob: 6d0567d7a6561b62feb8c3b1cc33b3c591ba85ab
|
||||
React-RCTImage: 1006a91318a6181a0256b89d2e321b6ea0e2e6e3
|
||||
React-RCTLinking: 0b2300493c879c3bcac2d4c6b0178e8d0e5e2202
|
||||
React-RCTNetwork: b9a33a95703651abed92490e50396d54b7270a17
|
||||
React-RCTSettings: e6464123e5b5062fc23bb5adb51188a6061e9601
|
||||
React-RCTText: 188d6f0ae20cd28891f59ecad41028ee2f793757
|
||||
React-RCTVibration: a67beb7d2f3c73e9b74c4124ef61b84c601be649
|
||||
React-runtimeexecutor: 088723cf020113e64736a709f52719dbb359c73e
|
||||
ReactCommon: 1a4f19f3b4366feec03a98bdbb200b6085c5000f
|
||||
React-perflogger: 0458a87ea9a7342079e7a31b0d32b3734fb8415f
|
||||
React-RCTActionSheet: 22538001ea2926dea001111dd2846c13a0730bc9
|
||||
React-RCTAnimation: 732ce66878d4aa151d56a0d142b1105aa12fd313
|
||||
React-RCTBlob: 9cb9e3e9a41d27be34aaf89b0e0f52c7ca415d57
|
||||
React-RCTImage: 6bd16627eb9c4bb79903c4cdec7c551266ee1a5b
|
||||
React-RCTLinking: e9edfc8919c8fa9a3f3c7b34362811f58a2ebba4
|
||||
React-RCTNetwork: 880eccd21bbe2660a0b63da5ccba75c46eceeaa6
|
||||
React-RCTSettings: 8c85d8188c97d6c6bd470af6631a6c4555b79bb3
|
||||
React-RCTText: bbd275ee287730c5acbab1aadc0db39c25c5c64e
|
||||
React-RCTVibration: 9819a3bf6230e4b2a99877c21268b0b2416157a1
|
||||
React-runtimeexecutor: b1f1995089b90696dbc2a7ffe0059a80db5c8eb1
|
||||
ReactCommon: 149e2c0acab9bac61378da0db5b2880a1b5ff59b
|
||||
RNCalendarEvents: 7e65eb4a94f53c1744d1e275f7fafcfaa619f7a3
|
||||
RNCAsyncStorage: 005c0e2f09575360f142d0d1f1f15e4ec575b1af
|
||||
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
|
||||
@@ -781,7 +781,7 @@ SPEC CHECKSUMS:
|
||||
RNSound: 27e8268bdb0a1f191f219a33267f7e0445e8d62f
|
||||
RNSVG: f3b60aeeaa81960e2e0536c3a9eef50b667ef3a9
|
||||
RNWatch: dae6c858a2051dbdcfb00b9a86cf4d90400263b4
|
||||
Yoga: c926c8eec5c78a788b51e6c8a604825d00d694d7
|
||||
Yoga: c4d61225a466f250c35c1ee78d2d0b3d41fe661c
|
||||
|
||||
PODFILE CHECKSUM: e671cdcdb80fab67e305861c36bfae8ed5a5b0ef
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "end_call_button.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "microphone_off_button.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "microphone_on_button.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
//
|
||||
// DarwinNotificationsObserver.swift
|
||||
// WidgetsExtension
|
||||
//
|
||||
// Created by Alex Bumbu on 17.10.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum DarwinNotification: String {
|
||||
case meetingMutedChanged = "iOS_MeetingMutedChanged"
|
||||
}
|
||||
|
||||
extension DarwinNotification {
|
||||
|
||||
var name: String { rawValue }
|
||||
}
|
||||
|
||||
class DarwinNotificationsObserver {
|
||||
|
||||
private static var observers = Array<ProxyObserver>()
|
||||
|
||||
private let queue = DispatchQueue(label: "org.jitsi.meet.darwinNotificationObserver", qos: .default, autoreleaseFrequency: .workItem)
|
||||
private var notificationCenter: CFNotificationCenter
|
||||
|
||||
init() {
|
||||
notificationCenter = CFNotificationCenterGetDarwinNotifyCenter()
|
||||
}
|
||||
|
||||
func observe(notification: DarwinNotification, handler: @escaping () -> Void) {
|
||||
let proxyObserver = ProxyObserver(observer: self, notificationName: notification.name, handler: handler)
|
||||
queue.async {
|
||||
DarwinNotificationsObserver.observers.append(proxyObserver)
|
||||
}
|
||||
|
||||
let callback: CFNotificationCallback = { _, observer, name, _, _ in
|
||||
guard let observer = observer else {
|
||||
return
|
||||
}
|
||||
|
||||
// Extract pointer to `observer` from void pointer:
|
||||
let proxyObserver = Unmanaged<ProxyObserver>.fromOpaque(observer).takeUnretainedValue()
|
||||
var observers = DarwinNotificationsObserver.observers
|
||||
if !proxyObserver.forwardNotification(), let index = observers.firstIndex(of: proxyObserver) {
|
||||
// cleanup if `forwardNotification` fails
|
||||
observers.remove(at: index)
|
||||
}
|
||||
}
|
||||
|
||||
CFNotificationCenterAddObserver(notificationCenter,
|
||||
Unmanaged.passUnretained(proxyObserver).toOpaque(),
|
||||
callback,
|
||||
notification.name as CFString,
|
||||
nil,
|
||||
.deliverImmediately)
|
||||
}
|
||||
|
||||
func stopObserving(notification: DarwinNotification) {
|
||||
queue.sync {
|
||||
DarwinNotificationsObserver.observers.removeAll { $0.observer == nil }
|
||||
}
|
||||
|
||||
if let index = DarwinNotificationsObserver.observers.firstIndex(where: { $0.observer === self && $0.notificationName == notification.name }) {
|
||||
let proxyObserver = DarwinNotificationsObserver.observers[index]
|
||||
CFNotificationCenterRemoveObserver(notificationCenter,
|
||||
Unmanaged.passUnretained(proxyObserver).toOpaque(),
|
||||
CFNotificationName(notification.name as CFString),
|
||||
nil)
|
||||
queue.async {
|
||||
DarwinNotificationsObserver.observers.remove(at: index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ProxyObserver: Equatable {
|
||||
|
||||
let notificationName: String
|
||||
weak var observer: AnyObject?
|
||||
|
||||
private let handler: () -> (Void)
|
||||
|
||||
static func == (lhs: ProxyObserver, rhs: ProxyObserver) -> Bool {
|
||||
lhs.observer === rhs.observer && lhs.notificationName == rhs.notificationName
|
||||
}
|
||||
|
||||
init(observer: AnyObject? = nil, notificationName: String, handler: @escaping () -> Void) {
|
||||
self.notificationName = notificationName
|
||||
self.handler = handler
|
||||
self.observer = observer
|
||||
}
|
||||
|
||||
func forwardNotification() -> Bool {
|
||||
guard observer != nil else {
|
||||
return false
|
||||
}
|
||||
|
||||
handler()
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.widgetkit-extension</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,54 +0,0 @@
|
||||
//
|
||||
// LockScreenLeaveMeetingWidget.swift
|
||||
// WidgetsExtension
|
||||
//
|
||||
// Created by Alex Bumbu on 31.10.2022.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import WidgetKit
|
||||
|
||||
struct LockScreenLeaveMeetingWidget: Widget {
|
||||
let kind: String = "LockScreenLeaveMeetingWidget"
|
||||
|
||||
var body: some WidgetConfiguration {
|
||||
StaticConfiguration(kind: kind, provider: Provider()) { entry in
|
||||
WidgetsEntryView(entry: entry)
|
||||
}
|
||||
.configurationDisplayName("Leave Jitsi Meeting Widget")
|
||||
.description("This is a lockscreen widget for leaving the ongoing Jitsi meeting.")
|
||||
.supportedFamilies([.accessoryCircular])
|
||||
}
|
||||
}
|
||||
|
||||
//struct LockScreenLeaveMeetingWidget_Preview: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// let meetingState = MeetingState(audioMuted: true)
|
||||
//
|
||||
// WidgetsEntryView(entry: CurrentMeetingEntry(date: Date(), meetingState: meetingState))
|
||||
// .previewContext(WidgetPreviewContext(family: .accessoryCircular))
|
||||
// .previewDisplayName("Circular")
|
||||
// }
|
||||
//}
|
||||
|
||||
private struct WidgetsEntryView: View {
|
||||
@Environment(\.widgetFamily) var widgetFamily
|
||||
var entry: Provider.Entry
|
||||
|
||||
var body: some View {
|
||||
if entry.meetingState != nil, widgetFamily == .accessoryCircular {
|
||||
AccessoryCircularWidgetView()
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct AccessoryCircularWidgetView: View {
|
||||
var body: some View {
|
||||
Image("leave_meeting")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.widgetURL(URL(string: "meet/leaveMeeting")!)
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
//
|
||||
// LockScreenMuteAudioWidget.swift
|
||||
// WidgetsExtension
|
||||
//
|
||||
// Created by Alex Bumbu on 31.10.2022.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import WidgetKit
|
||||
|
||||
struct LockScreenMuteAudioWidget: Widget {
|
||||
let kind: String = "LockScreenMuteAudioWidget"
|
||||
|
||||
var body: some WidgetConfiguration {
|
||||
StaticConfiguration(kind: kind, provider: Provider()) { entry in
|
||||
WidgetsEntryView(entry: entry)
|
||||
}
|
||||
.configurationDisplayName("Mute Jitsi Audio Widget")
|
||||
.description("This is a lockscreen widget for muting or unmuting the audio for the ongoing Jitsi meeting.")
|
||||
.supportedFamilies([.accessoryCircular])
|
||||
}
|
||||
}
|
||||
|
||||
//struct LockScreenMuteAudioWidget_Preview: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// let meetingState = MeetingState(audioMuted: true)
|
||||
//
|
||||
// WidgetsEntryView(entry: CurrentMeetingEntry(date: Date(), meetingState: meetingState))
|
||||
// .previewContext(WidgetPreviewContext(family: .accessoryInline))
|
||||
// .previewDisplayName("Inline")
|
||||
//
|
||||
// WidgetsEntryView(entry: CurrentMeetingEntry(date: Date(), meetingState: meetingState))
|
||||
// .previewContext(WidgetPreviewContext(family: .accessoryCircular))
|
||||
// .previewDisplayName("Circular")
|
||||
//
|
||||
// WidgetsEntryView(entry: CurrentMeetingEntry(date: Date(), meetingState: meetingState))
|
||||
// .previewContext(WidgetPreviewContext(family: .accessoryRectangular))
|
||||
// .previewDisplayName("Rectangular")
|
||||
// }
|
||||
//}
|
||||
|
||||
private struct WidgetsEntryView: View {
|
||||
@Environment(\.widgetFamily) var widgetFamily
|
||||
var entry: Provider.Entry
|
||||
|
||||
var body: some View {
|
||||
if let meetingState = entry.meetingState {
|
||||
switch widgetFamily {
|
||||
case .accessoryInline:
|
||||
Text("Some meeting name")
|
||||
case .accessoryRectangular:
|
||||
AccessoryCircularWidgetView(audioMuted: meetingState.audioMuted)
|
||||
case .accessoryCircular:
|
||||
AccessoryCircularWidgetView(audioMuted: meetingState.audioMuted)
|
||||
default:
|
||||
EmptyView()
|
||||
}
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct AccessoryRectangularWidgetView: View {
|
||||
var audioMuted: Bool
|
||||
|
||||
var body: some View {
|
||||
let imageName: String = audioMuted ? "microphone_on" : "microphone_off"
|
||||
let caption: String = audioMuted ? "Unmute \naudio" : "Mute \naudio"
|
||||
HStack {
|
||||
Image(imageName)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
Text(caption)
|
||||
}.widgetURL(URL(string: "meet/toggleAudioMute")!)
|
||||
}
|
||||
}
|
||||
|
||||
private struct AccessoryCircularWidgetView: View {
|
||||
var audioMuted: Bool
|
||||
|
||||
var body: some View {
|
||||
let imageName: String = audioMuted ? "microphone_on" : "microphone_off"
|
||||
Image(imageName)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.widgetURL(URL(string: "meet/toggleAudioMute")!)
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// MeetingState.swift
|
||||
// WidgetsExtension
|
||||
//
|
||||
// Created by Alex Bumbu on 28.10.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct MeetingState: Decodable {
|
||||
var audioMuted: Bool
|
||||
}
|
||||
|
||||
extension MeetingState {
|
||||
private static var stateFileURL: URL? {
|
||||
return FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.org.jitsi.meet.appgroup")?.appending(component: "widgetState")
|
||||
}
|
||||
|
||||
static func load() -> MeetingState? {
|
||||
guard
|
||||
let stateFileURL = stateFileURL,
|
||||
let data = try? Data(contentsOf: stateFileURL)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let decoder = PropertyListDecoder()
|
||||
return try? decoder.decode(MeetingState.self, from: data)
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
//
|
||||
// Provider.swift
|
||||
// WidgetsExtension
|
||||
//
|
||||
// Created by Alex Bumbu on 31.10.2022.
|
||||
//
|
||||
|
||||
import WidgetKit
|
||||
import SwiftUI
|
||||
|
||||
struct CurrentMeetingEntry: TimelineEntry {
|
||||
let date: Date
|
||||
var meetingState: MeetingState?
|
||||
}
|
||||
|
||||
class Provider: TimelineProvider {
|
||||
private var currentMeetingState: MeetingState? {
|
||||
return MeetingState.load()
|
||||
}
|
||||
|
||||
func placeholder(in context: Context) -> CurrentMeetingEntry {
|
||||
CurrentMeetingEntry(date: Date(),
|
||||
meetingState: MeetingState(audioMuted: false))
|
||||
}
|
||||
|
||||
func getSnapshot(in context: Context, completion: @escaping (CurrentMeetingEntry) -> ()) {
|
||||
var meetingState = currentMeetingState
|
||||
if context.isPreview {
|
||||
meetingState = MeetingState(audioMuted: false)
|
||||
}
|
||||
|
||||
let entry = CurrentMeetingEntry(date: Date(), meetingState: meetingState)
|
||||
completion(entry)
|
||||
}
|
||||
|
||||
func getTimeline(in context: Context, completion: @escaping (Timeline<CurrentMeetingEntry>) -> ()) {
|
||||
var entries: [CurrentMeetingEntry] = []
|
||||
let entry = CurrentMeetingEntry(date: Date(), meetingState: currentMeetingState)
|
||||
entries.append(entry)
|
||||
|
||||
let timeline = Timeline(entries: entries, policy: .atEnd)
|
||||
completion(timeline)
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
//
|
||||
// Widgets.swift
|
||||
// Widgets
|
||||
//
|
||||
// Created by Alex Bumbu on 17.10.2022.
|
||||
// Copyright © 2022 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
import WidgetKit
|
||||
import SwiftUI
|
||||
|
||||
@main
|
||||
struct Widgets: WidgetBundle {
|
||||
@WidgetBundleBuilder
|
||||
var body: some Widget {
|
||||
LockScreenMuteAudioWidget()
|
||||
LockScreenLeaveMeetingWidget()
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.org.jitsi.meet.appgroup</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -23,26 +23,14 @@
|
||||
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
4E46D952290FF39E00761DEF /* LockScreenMuteAudioWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E46D951290FF39E00761DEF /* LockScreenMuteAudioWidget.swift */; };
|
||||
4E46D954290FF55600761DEF /* LockScreenLeaveMeetingWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E46D953290FF55600761DEF /* LockScreenLeaveMeetingWidget.swift */; };
|
||||
4E6920B828FD84D700645D9E /* DarwinNotificationsObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E6920B728FD84D700645D9E /* DarwinNotificationsObserver.swift */; };
|
||||
4E6A3E17291024B900E6B0B5 /* Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E6A3E16291024B900E6B0B5 /* Provider.swift */; };
|
||||
2681BB562C7A0B42CFBA6719 /* libPods-JitsiMeet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D6152FF9E9F7B0E86F70A21D /* libPods-JitsiMeet.a */; };
|
||||
4E90F9402632D1AB001102D4 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E90F93F2632D1AB001102D4 /* Atomic.swift */; };
|
||||
4EA73DA3290C1D6C00A16FF8 /* MeetingState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EA73DA2290C1D6C00A16FF8 /* MeetingState.swift */; };
|
||||
4EB06024260E026600F524C5 /* ReplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4EC49B8625BED71300E76218 /* ReplayKit.framework */; };
|
||||
4EB06027260E026600F524C5 /* SampleHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB06026260E026600F524C5 /* SampleHandler.swift */; };
|
||||
4EB0602B260E026600F524C5 /* JitsiMeetBroadcastExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 4EB06023260E026600F524C5 /* JitsiMeetBroadcastExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
4EB0603C260E09D000F524C5 /* SocketConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB06039260E09D000F524C5 /* SocketConnection.swift */; };
|
||||
4EB0603D260E09D000F524C5 /* DarwinNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB0603A260E09D000F524C5 /* DarwinNotificationCenter.swift */; };
|
||||
4EB0603E260E09D000F524C5 /* SampleUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB0603B260E09D000F524C5 /* SampleUploader.swift */; };
|
||||
4EBB458A28FFFD4100855769 /* RoutesHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EBB458928FFFD4100855769 /* RoutesHandler.m */; };
|
||||
4EBB458E2902E85B00855769 /* WidgetKitHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EBB458D2902E85B00855769 /* WidgetKitHelper.swift */; };
|
||||
4ECA496628FD590000085365 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4ECA496528FD590000085365 /* WidgetKit.framework */; };
|
||||
4ECA496828FD590000085365 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4ECA496728FD590000085365 /* SwiftUI.framework */; };
|
||||
4ECA496B28FD590000085365 /* Widgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ECA496A28FD590000085365 /* Widgets.swift */; };
|
||||
4ECA496D28FD590000085365 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4ECA496C28FD590000085365 /* Assets.xcassets */; };
|
||||
4ECA497128FD590000085365 /* WidgetsExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 4ECA496428FD590000085365 /* WidgetsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
C2116A7673E01A1CCD5DC1F4 /* libPods-JitsiMeet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BF9FEBA4DEAB800AD735681 /* libPods-JitsiMeet.a */; };
|
||||
DE4C456121DE1E4E00EA0709 /* FIRUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = DE4C455F21DE1E4E00EA0709 /* FIRUtilities.m */; };
|
||||
DEA9F289258A6EA800D4CD74 /* JitsiMeetSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DEA9F288258A6EA800D4CD74 /* JitsiMeetSDK.framework */; };
|
||||
DEA9F28A258A6EA800D4CD74 /* JitsiMeetSDK.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DEA9F288258A6EA800D4CD74 /* JitsiMeetSDK.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
@@ -76,13 +64,6 @@
|
||||
remoteGlobalIDString = 4EB06022260E026600F524C5;
|
||||
remoteInfo = "JitsiMeetBroadcast Extension";
|
||||
};
|
||||
4ECA496F28FD590000085365 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 4ECA496328FD590000085365;
|
||||
remoteInfo = WidgetsExtension;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -127,7 +108,6 @@
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
4ECA497128FD590000085365 /* WidgetsExtension.appex in Embed App Extensions */,
|
||||
4EB0602B260E026600F524C5 /* JitsiMeetBroadcastExtension.appex in Embed App Extensions */,
|
||||
);
|
||||
name = "Embed App Extensions";
|
||||
@@ -154,7 +134,6 @@
|
||||
0BEA5C3A1F7B8F73000D0AB4 /* ComplicationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplicationController.swift; sourceTree = "<group>"; };
|
||||
0BEA5C3C1F7B8F73000D0AB4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
0BEA5C3E1F7B8F73000D0AB4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
0BF9FEBA4DEAB800AD735681 /* libPods-JitsiMeet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-JitsiMeet.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07F961A680F5B00A75B9A /* jitsi-meet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "jitsi-meet.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
@@ -162,12 +141,8 @@
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
4E46D951290FF39E00761DEF /* LockScreenMuteAudioWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockScreenMuteAudioWidget.swift; sourceTree = "<group>"; };
|
||||
4E46D953290FF55600761DEF /* LockScreenLeaveMeetingWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockScreenLeaveMeetingWidget.swift; sourceTree = "<group>"; };
|
||||
4E6920B728FD84D700645D9E /* DarwinNotificationsObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DarwinNotificationsObserver.swift; sourceTree = "<group>"; };
|
||||
4E6A3E16291024B900E6B0B5 /* Provider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Provider.swift; sourceTree = "<group>"; };
|
||||
3E0F4ED943C0B12BE77F6B45 /* Pods-JitsiMeet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.release.xcconfig"; path = "Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.release.xcconfig"; sourceTree = "<group>"; };
|
||||
4E90F93F2632D1AB001102D4 /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = "<group>"; };
|
||||
4EA73DA2290C1D6C00A16FF8 /* MeetingState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingState.swift; sourceTree = "<group>"; };
|
||||
4EB06023260E026600F524C5 /* JitsiMeetBroadcastExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = JitsiMeetBroadcastExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4EB06026260E026600F524C5 /* SampleHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleHandler.swift; sourceTree = "<group>"; };
|
||||
4EB06028260E026600F524C5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
@@ -175,21 +150,10 @@
|
||||
4EB06039260E09D000F524C5 /* SocketConnection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketConnection.swift; sourceTree = "<group>"; };
|
||||
4EB0603A260E09D000F524C5 /* DarwinNotificationCenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DarwinNotificationCenter.swift; sourceTree = "<group>"; };
|
||||
4EB0603B260E09D000F524C5 /* SampleUploader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SampleUploader.swift; sourceTree = "<group>"; };
|
||||
4EBB458828FFFD4100855769 /* RoutesHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RoutesHandler.h; sourceTree = "<group>"; };
|
||||
4EBB458928FFFD4100855769 /* RoutesHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RoutesHandler.m; sourceTree = "<group>"; };
|
||||
4EBB458B2902A94700855769 /* WidgetsExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WidgetsExtension.entitlements; sourceTree = "<group>"; };
|
||||
4EBB458C2902E85B00855769 /* JitsiMeet-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeet-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
4EBB458D2902E85B00855769 /* WidgetKitHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetKitHelper.swift; sourceTree = "<group>"; };
|
||||
4EC49B8625BED71300E76218 /* ReplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReplayKit.framework; path = System/Library/Frameworks/ReplayKit.framework; sourceTree = SDKROOT; };
|
||||
4ECA496428FD590000085365 /* WidgetsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4ECA496528FD590000085365 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
|
||||
4ECA496728FD590000085365 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
||||
4ECA496A28FD590000085365 /* Widgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Widgets.swift; sourceTree = "<group>"; };
|
||||
4ECA496C28FD590000085365 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
4ECA496E28FD590000085365 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
7052390E12D7319D36D8E4CA /* Pods-JitsiMeet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.debug.xcconfig"; path = "Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
8CAA3C5A38E868335D1C1EC1 /* Pods-JitsiMeet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.release.xcconfig"; path = "Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.release.xcconfig"; sourceTree = "<group>"; };
|
||||
756FCE06C08D9B947653C98A /* Pods-JitsiMeet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.debug.xcconfig"; path = "Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
B3B083EB1D4955FF0069CEE7 /* app.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = app.entitlements; sourceTree = "<group>"; };
|
||||
D6152FF9E9F7B0E86F70A21D /* libPods-JitsiMeet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-JitsiMeet.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DE050388256E904600DEE3A5 /* WebRTC.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = WebRTC.xcframework; path = "../../node_modules/react-native-webrtc/apple/WebRTC.xcframework"; sourceTree = "<group>"; };
|
||||
DE4C455F21DE1E4E00EA0709 /* FIRUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRUtilities.m; sourceTree = "<group>"; };
|
||||
DE4C456021DE1E4E00EA0709 /* FIRUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FIRUtilities.h; sourceTree = "<group>"; };
|
||||
@@ -216,7 +180,7 @@
|
||||
DED016F128ECBC9D009D5E8D /* WebRTC.xcframework in Frameworks */,
|
||||
DEA9F289258A6EA800D4CD74 /* JitsiMeetSDK.framework in Frameworks */,
|
||||
FD572B9827EDF32300A800FB /* GiphyUISDK.xcframework in Frameworks */,
|
||||
C2116A7673E01A1CCD5DC1F4 /* libPods-JitsiMeet.a in Frameworks */,
|
||||
2681BB562C7A0B42CFBA6719 /* libPods-JitsiMeet.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -235,15 +199,6 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
4ECA496128FD590000085365 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4ECA496828FD590000085365 /* SwiftUI.framework in Frameworks */,
|
||||
4ECA496628FD590000085365 /* WidgetKit.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
@@ -258,9 +213,7 @@
|
||||
DEFDBBDB25656E3B00344B23 /* WebRTC.xcframework */,
|
||||
0BD6B4361EF82A6B00D1F4CD /* WebRTC.framework */,
|
||||
4EC49B8625BED71300E76218 /* ReplayKit.framework */,
|
||||
4ECA496528FD590000085365 /* WidgetKit.framework */,
|
||||
4ECA496728FD590000085365 /* SwiftUI.framework */,
|
||||
0BF9FEBA4DEAB800AD735681 /* libPods-JitsiMeet.a */,
|
||||
D6152FF9E9F7B0E86F70A21D /* libPods-JitsiMeet.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -308,10 +261,6 @@
|
||||
0BBD021F212EB69D00CCB19F /* Types.h */,
|
||||
0B412F1D1EDEE6E800B1A0A6 /* ViewController.h */,
|
||||
0B412F1E1EDEE6E800B1A0A6 /* ViewController.m */,
|
||||
4EBB458828FFFD4100855769 /* RoutesHandler.h */,
|
||||
4EBB458928FFFD4100855769 /* RoutesHandler.m */,
|
||||
4EBB458D2902E85B00855769 /* WidgetKitHelper.swift */,
|
||||
4EBB458C2902E85B00855769 /* JitsiMeet-Bridging-Header.h */,
|
||||
);
|
||||
path = src;
|
||||
sourceTree = "<group>";
|
||||
@@ -333,25 +282,9 @@
|
||||
sourceTree = "<group>";
|
||||
tabWidth = 4;
|
||||
};
|
||||
4ECA496928FD590000085365 /* Widgets Extension */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4ECA496A28FD590000085365 /* Widgets.swift */,
|
||||
4E46D951290FF39E00761DEF /* LockScreenMuteAudioWidget.swift */,
|
||||
4E46D953290FF55600761DEF /* LockScreenLeaveMeetingWidget.swift */,
|
||||
4E6A3E16291024B900E6B0B5 /* Provider.swift */,
|
||||
4EA73DA2290C1D6C00A16FF8 /* MeetingState.swift */,
|
||||
4E6920B728FD84D700645D9E /* DarwinNotificationsObserver.swift */,
|
||||
4ECA496C28FD590000085365 /* Assets.xcassets */,
|
||||
4ECA496E28FD590000085365 /* Info.plist */,
|
||||
);
|
||||
path = "Widgets Extension";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
83CBB9F61A601CBA00E9B192 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4EBB458B2902A94700855769 /* WidgetsExtension.entitlements */,
|
||||
B3B083EB1D4955FF0069CEE7 /* app.entitlements */,
|
||||
0B26BE711EC5BC4D00EEFB41 /* Frameworks */,
|
||||
83CBBA001A601CBA00E9B192 /* Products */,
|
||||
@@ -359,12 +292,11 @@
|
||||
0BEA5C261F7B8F73000D0AB4 /* Watch app */,
|
||||
0BEA5C351F7B8F73000D0AB4 /* WatchKit extension */,
|
||||
4EB06025260E026600F524C5 /* JitsiMeetBroadcast Extension */,
|
||||
4ECA496928FD590000085365 /* Widgets Extension */,
|
||||
BD4E28FA984EA7018FD927DF /* Pods */,
|
||||
CDD71F5E1157E9F283DF92A8 /* Pods */,
|
||||
);
|
||||
indentWidth = 4;
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
tabWidth = 4;
|
||||
tabWidth = 2;
|
||||
};
|
||||
83CBBA001A601CBA00E9B192 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
@@ -373,16 +305,15 @@
|
||||
0BEA5C251F7B8F73000D0AB4 /* JitsiMeetCompanion.app */,
|
||||
0BEA5C311F7B8F73000D0AB4 /* JitsiMeetCompanion Extension.appex */,
|
||||
4EB06023260E026600F524C5 /* JitsiMeetBroadcastExtension.appex */,
|
||||
4ECA496428FD590000085365 /* WidgetsExtension.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BD4E28FA984EA7018FD927DF /* Pods */ = {
|
||||
CDD71F5E1157E9F283DF92A8 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7052390E12D7319D36D8E4CA /* Pods-JitsiMeet.debug.xcconfig */,
|
||||
8CAA3C5A38E868335D1C1EC1 /* Pods-JitsiMeet.release.xcconfig */,
|
||||
756FCE06C08D9B947653C98A /* Pods-JitsiMeet.debug.xcconfig */,
|
||||
3E0F4ED943C0B12BE77F6B45 /* Pods-JitsiMeet.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = ../Pods;
|
||||
@@ -430,7 +361,7 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "JitsiMeet" */;
|
||||
buildPhases = (
|
||||
58E2CB346F2C2A873294F481 /* [CP] Check Pods Manifest.lock */,
|
||||
69BC5020DBE393B56BD76636 /* [CP] Check Pods Manifest.lock */,
|
||||
0BBA83C41EC9F7600075A103 /* Run React packager */,
|
||||
13B07F871A680F5B00A75B9A /* Sources */,
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */,
|
||||
@@ -449,7 +380,6 @@
|
||||
dependencies = (
|
||||
0BEA5C401F7B8F73000D0AB4 /* PBXTargetDependency */,
|
||||
4EB0602A260E026600F524C5 /* PBXTargetDependency */,
|
||||
4ECA497028FD590000085365 /* PBXTargetDependency */,
|
||||
);
|
||||
name = JitsiMeet;
|
||||
productName = "Jitsi Meet";
|
||||
@@ -473,32 +403,15 @@
|
||||
productReference = 4EB06023260E026600F524C5 /* JitsiMeetBroadcastExtension.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
4ECA496328FD590000085365 /* WidgetsExtension */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 4ECA497428FD590100085365 /* Build configuration list for PBXNativeTarget "WidgetsExtension" */;
|
||||
buildPhases = (
|
||||
4ECA496028FD590000085365 /* Sources */,
|
||||
4ECA496128FD590000085365 /* Frameworks */,
|
||||
4ECA496228FD590000085365 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = WidgetsExtension;
|
||||
productName = WidgetsExtension;
|
||||
productReference = 4ECA496428FD590000085365 /* WidgetsExtension.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
83CBB9F71A601CBA00E9B192 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1400;
|
||||
LastSwiftUpdateCheck = 1240;
|
||||
LastUpgradeCheck = 1020;
|
||||
ORGANIZATIONNAME = "";
|
||||
ORGANIZATIONNAME = Facebook;
|
||||
TargetAttributes = {
|
||||
0BEA5C241F7B8F73000D0AB4 = {
|
||||
CreatedOnToolsVersion = 9.0;
|
||||
@@ -511,7 +424,6 @@
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
13B07F861A680F5B00A75B9A = {
|
||||
LastSwiftMigration = 1400;
|
||||
SystemCapabilities = {
|
||||
com.apple.SafariKeychain = {
|
||||
enabled = 1;
|
||||
@@ -524,9 +436,6 @@
|
||||
4EB06022260E026600F524C5 = {
|
||||
CreatedOnToolsVersion = 12.4;
|
||||
};
|
||||
4ECA496328FD590000085365 = {
|
||||
CreatedOnToolsVersion = 14.0.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "app" */;
|
||||
@@ -546,7 +455,6 @@
|
||||
0BEA5C241F7B8F73000D0AB4 /* JitsiMeetCompanion */,
|
||||
0BEA5C301F7B8F73000D0AB4 /* JitsiMeetCompanion Extension */,
|
||||
4EB06022260E026600F524C5 /* JitsiMeetBroadcastExtension */,
|
||||
4ECA496328FD590000085365 /* WidgetsExtension */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@@ -586,14 +494,6 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
4ECA496228FD590000085365 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4ECA496D28FD590000085365 /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
@@ -643,7 +543,7 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if test \"$PRODUCT_BUNDLE_IDENTIFIER\" = \"com.atlassian.JitsiMeet.ios\"; then\n ENTITLEMENTS_PLIST=\"$PROJECT_DIR/app.entitlements\"\n \n /usr/libexec/PlistBuddy -c \"Add :com.apple.developer.avfoundation.multitasking-camera-access bool 1\" $ENTITLEMENTS_PLIST\nfi\n";
|
||||
};
|
||||
58E2CB346F2C2A873294F481 /* [CP] Check Pods Manifest.lock */ = {
|
||||
69BC5020DBE393B56BD76636 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -742,10 +642,8 @@
|
||||
files = (
|
||||
0B412F1F1EDEE6E800B1A0A6 /* ViewController.m in Sources */,
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
|
||||
4EBB458E2902E85B00855769 /* WidgetKitHelper.swift in Sources */,
|
||||
DE4C456121DE1E4E00EA0709 /* FIRUtilities.m in Sources */,
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */,
|
||||
4EBB458A28FFFD4100855769 /* RoutesHandler.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -761,19 +659,6 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
4ECA496028FD590000085365 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4ECA496B28FD590000085365 /* Widgets.swift in Sources */,
|
||||
4E6920B828FD84D700645D9E /* DarwinNotificationsObserver.swift in Sources */,
|
||||
4E46D954290FF55600761DEF /* LockScreenLeaveMeetingWidget.swift in Sources */,
|
||||
4EA73DA3290C1D6C00A16FF8 /* MeetingState.swift in Sources */,
|
||||
4E6A3E17291024B900E6B0B5 /* Provider.swift in Sources */,
|
||||
4E46D952290FF39E00761DEF /* LockScreenMuteAudioWidget.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
@@ -792,11 +677,6 @@
|
||||
target = 4EB06022260E026600F524C5 /* JitsiMeetBroadcastExtension */;
|
||||
targetProxy = 4EB06029260E026600F524C5 /* PBXContainerItemProxy */;
|
||||
};
|
||||
4ECA497028FD590000085365 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 4ECA496328FD590000085365 /* WidgetsExtension */;
|
||||
targetProxy = 4ECA496F28FD590000085365 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
@@ -965,12 +845,11 @@
|
||||
};
|
||||
13B07F941A680F5B00A75B9A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7052390E12D7319D36D8E4CA /* Pods-JitsiMeet.debug.xcconfig */;
|
||||
baseConfigurationReference = 756FCE06C08D9B947653C98A /* Pods-JitsiMeet.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconDebug;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = app.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
@@ -992,20 +871,16 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet;
|
||||
PRODUCT_NAME = "jitsi-meet";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "src/JitsiMeet-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
13B07F951A680F5B00A75B9A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 8CAA3C5A38E868335D1C1EC1 /* Pods-JitsiMeet.release.xcconfig */;
|
||||
baseConfigurationReference = 3E0F4ED943C0B12BE77F6B45 /* Pods-JitsiMeet.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconRelease;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = app.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
@@ -1026,8 +901,6 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet;
|
||||
PRODUCT_NAME = "jitsi-meet";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "src/JitsiMeet-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -1100,91 +973,6 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
4ECA497228FD590100085365 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = WidgetsExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = FC967L3QRG;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "Widgets Extension/Info.plist";
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Widgets;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Facebook. All rights reserved.";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet.widgets.extension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
4ECA497328FD590100085365 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = WidgetsExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = FC967L3QRG;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "Widgets Extension/Info.plist";
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Widgets;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Facebook. All rights reserved.";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet.widgets.extension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
83CBBA201A601CBA00E9B192 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -1338,15 +1126,6 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
4ECA497428FD590100085365 /* Build configuration list for PBXNativeTarget "WidgetsExtension" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
4ECA497228FD590100085365 /* Debug */,
|
||||
4ECA497328FD590100085365 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "app" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1400"
|
||||
wasCreatedForAppExtension = "YES"
|
||||
version = "2.0">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "4ECA496328FD590000085365"
|
||||
BuildableName = "WidgetsExtension.appex"
|
||||
BlueprintName = "WidgetsExtension"
|
||||
ReferencedContainer = "container:app.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "jitsi-meet.app"
|
||||
BlueprintName = "JitsiMeet"
|
||||
ReferencedContainer = "container:app.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = ""
|
||||
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||
launchStyle = "0"
|
||||
askForAppToLaunch = "Yes"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES"
|
||||
launchAutomaticallySubstyle = "2">
|
||||
<RemoteRunnable
|
||||
runnableDebuggingMode = "2"
|
||||
BundleIdentifier = "com.apple.springboard">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "4ECA496328FD590000085365"
|
||||
BuildableName = "WidgetsExtension.appex"
|
||||
BlueprintName = "WidgetsExtension"
|
||||
ReferencedContainer = "container:app.xcodeproj">
|
||||
</BuildableReference>
|
||||
</RemoteRunnable>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "jitsi-meet.app"
|
||||
BlueprintName = "JitsiMeet"
|
||||
ReferencedContainer = "container:app.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "_XCWidgetKind"
|
||||
value = "LockScreenLeaveMeetingWidget"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
key = "_XCWidgetDefaultView"
|
||||
value = "timeline"
|
||||
isEnabled = "NO">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
key = "_XCWidgetFamily"
|
||||
value = "medium"
|
||||
isEnabled = "NO">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
askForAppToLaunch = "Yes"
|
||||
launchAutomaticallySubstyle = "2">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "jitsi-meet.app"
|
||||
BlueprintName = "JitsiMeet"
|
||||
ReferencedContainer = "container:app.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "FIRUtilities.h"
|
||||
#import "RoutesHandler.h"
|
||||
#import "Types.h"
|
||||
#import "ViewController.h"
|
||||
|
||||
@@ -70,7 +69,7 @@
|
||||
- (BOOL)application:(UIApplication *)application
|
||||
continueUserActivity:(NSUserActivity *)userActivity
|
||||
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *restorableObjects))restorationHandler {
|
||||
|
||||
|
||||
if ([FIRUtilities appContainsRealServiceInfoPlist]) {
|
||||
// 1. Attempt to handle Universal Links through Firebase in order to support
|
||||
// its Dynamic Links (which we utilize for the purposes of deferred deep
|
||||
@@ -108,10 +107,6 @@
|
||||
if ([[url absoluteString] containsString:@"google/link/?dismiss=1&is_weak_match=1"]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if ([[RoutesHandler sharedInstance] routeURL:url]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSURL *openUrl = url;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
//
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
//
|
||||
// RoutesHandler.h
|
||||
// JitsiMeet
|
||||
//
|
||||
// Created by Alex Bumbu on 19.10.2022.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol RouteObserving <NSObject>
|
||||
|
||||
@property (nonatomic, readonly) void (^didRouteCallback)(NSString *route);
|
||||
|
||||
@end
|
||||
|
||||
@interface RoutesHandler : NSObject
|
||||
|
||||
+ (instancetype)sharedInstance;
|
||||
- (void)registerObserver:(id<RouteObserving>)observer forRoute:(NSString *)route;
|
||||
- (void)unregisterObserver:(id<RouteObserving>)observer;
|
||||
- (BOOL)routeURL:(NSURL *)url;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,123 +0,0 @@
|
||||
//
|
||||
// RoutesHandler.m
|
||||
// JitsiMeet
|
||||
//
|
||||
// Created by Alex Bumbu on 19.10.2022.
|
||||
//
|
||||
|
||||
#import "RoutesHandler.h"
|
||||
|
||||
@protocol Routing <NSObject>
|
||||
|
||||
@property (nonatomic, readonly) NSString *route;
|
||||
@property (nonatomic, readonly) id<RouteObserving> observer;
|
||||
|
||||
@end
|
||||
|
||||
@interface Route: NSObject <Routing>
|
||||
|
||||
@property (nonatomic, readonly) NSString *route;
|
||||
@property (nonatomic, readonly, weak) id<RouteObserving> observer;
|
||||
|
||||
+ (instancetype)routeWithString:(nonnull NSString *)route observer:(id<RouteObserving>)observer;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation RoutesHandler {
|
||||
NSMutableArray *routes;
|
||||
}
|
||||
|
||||
+ (instancetype)sharedInstance {
|
||||
static RoutesHandler *sharedInstance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedInstance = [[self alloc] init];
|
||||
});
|
||||
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
routes = [[NSMutableArray alloc] init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)registerObserver:(id<RouteObserving>)observer forRoute:(NSString *)route {
|
||||
[routes addObject:[Route routeWithString:route observer:observer]];
|
||||
}
|
||||
|
||||
- (void)unregisterObserver:(id<RouteObserving>)observer {
|
||||
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id<Routing> _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
|
||||
return evaluatedObject.observer == nil || evaluatedObject.observer == observer;
|
||||
}];
|
||||
NSArray *routesToClear = [routes filteredArrayUsingPredicate:predicate];
|
||||
[routes removeObjectsInArray:routesToClear];
|
||||
}
|
||||
|
||||
- (BOOL)routeURL:(NSURL *)url {
|
||||
[self clearRoutes];
|
||||
|
||||
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:false];
|
||||
if (!components) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NSString *route = components.path;
|
||||
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id<Routing> _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
|
||||
return [evaluatedObject.route isEqualToString:route];
|
||||
}];
|
||||
NSArray *routesToHandle = [routes filteredArrayUsingPredicate:predicate];
|
||||
if ([routesToHandle count] == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (id<Routing> route in routesToHandle) {
|
||||
route.observer.didRouteCallback(route.route);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
- (void)clearRoutes {
|
||||
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id<Routing> _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
|
||||
return evaluatedObject.observer == nil;
|
||||
}];
|
||||
NSArray *routesToClear = [routes filteredArrayUsingPredicate:predicate];
|
||||
[routes removeObjectsInArray:routesToClear];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface Route()
|
||||
|
||||
@property (nonatomic, nonnull, copy) NSString *route;
|
||||
@property (nonatomic, weak) id<RouteObserving> observer;
|
||||
|
||||
@end
|
||||
|
||||
@implementation Route
|
||||
|
||||
+ (instancetype)routeWithString:(nonnull NSString *)route observer:(nonnull id<RouteObserving>)observer {
|
||||
return [[Route alloc] initWithString:route observer:observer];
|
||||
}
|
||||
|
||||
- (instancetype)initWithString:(nonnull NSString *)route observer:(nonnull id<RouteObserving>)observer {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.route = route;
|
||||
self.observer = observer;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -21,16 +21,8 @@
|
||||
@import JitsiMeetSDK;
|
||||
|
||||
#import "Types.h"
|
||||
#import "RoutesHandler.h"
|
||||
#import "ViewController.h"
|
||||
#import "jitsi_meet-Swift.h"
|
||||
|
||||
@interface ViewController() <RouteObserving>
|
||||
|
||||
@property (nonatomic, nonnull, copy) void (^didRouteCallback)(NSString *);
|
||||
@property (nonatomic, assign) BOOL audioMuted;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ViewController
|
||||
|
||||
@@ -41,8 +33,6 @@
|
||||
view.delegate = self;
|
||||
|
||||
[view join:[[JitsiMeet sharedInstance] getInitialConferenceOptions]];
|
||||
|
||||
[self registerRouteObserver];
|
||||
}
|
||||
|
||||
// JitsiMeetViewDelegate
|
||||
@@ -63,10 +53,6 @@
|
||||
|
||||
- (void)conferenceJoined:(NSDictionary *)data {
|
||||
[self _onJitsiMeetViewDelegateEvent:@"CONFERENCE_JOINED" withData:data];
|
||||
|
||||
self.audioMuted = [[data objectForKey:@"isAudioMuted"] boolValue];
|
||||
|
||||
[self refreshWidgetState:self.audioMuted];
|
||||
|
||||
// Register a NSUserActivity for this conference so it can be invoked as a
|
||||
// Siri shortcut.
|
||||
@@ -96,12 +82,6 @@
|
||||
|
||||
- (void)conferenceTerminated:(NSDictionary *)data {
|
||||
[self _onJitsiMeetViewDelegateEvent:@"CONFERENCE_TERMINATED" withData:data];
|
||||
|
||||
NSURL *sharedContainer = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.org.jitsi.meet.appgroup"];
|
||||
NSURL *widgetStateFileURL = [sharedContainer URLByAppendingPathComponent:@"widgetState"];
|
||||
[[NSFileManager defaultManager] removeItemAtURL:widgetStateFileURL error:nil];
|
||||
|
||||
[WidgetKitHelper reloadAllWidgets];
|
||||
}
|
||||
|
||||
- (void)conferenceWillJoin:(NSDictionary *)data {
|
||||
@@ -127,16 +107,7 @@
|
||||
}
|
||||
|
||||
- (void)audioMutedChanged:(NSDictionary *)data {
|
||||
NSLog(@"%@%@", @"Audio muted changed: ", data[@"muted"]);
|
||||
// CFNotificationCenterRef notificationCenter = CFNotificationCenterGetDarwinNotifyCenter();
|
||||
// CFNotificationCenterPostNotification(notificationCenter,
|
||||
// (__bridge CFStringRef)@"iOS_MeetingMutedChanged",
|
||||
// NULL,
|
||||
// NULL,
|
||||
// true);
|
||||
|
||||
self.audioMuted = [[data objectForKey:@"muted"] boolValue];
|
||||
[self refreshWidgetState:self.audioMuted];
|
||||
NSLog(@"%@%@", @"Audio muted changed: ", data[@"muted"]);
|
||||
}
|
||||
|
||||
- (void)endpointTextMessageReceived:(NSDictionary *)data {
|
||||
@@ -161,40 +132,9 @@
|
||||
|
||||
#pragma mark - Helpers
|
||||
|
||||
- (void)registerRouteObserver {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
__weak JitsiMeetView *view = (JitsiMeetView *)self.view;
|
||||
self.didRouteCallback = ^(NSString *route) {
|
||||
if ([route isEqual:@"meet/toggleAudioMute"]) {
|
||||
weakSelf.audioMuted = !weakSelf.audioMuted;
|
||||
[view setAudioMuted:weakSelf.audioMuted];
|
||||
} else if ([route isEqualToString:@"meet/leaveMeeting"]) {
|
||||
[weakSelf terminate];
|
||||
}
|
||||
};
|
||||
|
||||
[[RoutesHandler sharedInstance] registerObserver:self forRoute:@"meet/toggleAudioMute"];
|
||||
[[RoutesHandler sharedInstance] registerObserver:self forRoute:@"meet/leaveMeeting"];
|
||||
}
|
||||
|
||||
- (void)terminate {
|
||||
JitsiMeetView *view = (JitsiMeetView *) self.view;
|
||||
[view leave];
|
||||
}
|
||||
|
||||
- (void)refreshWidgetState:(BOOL)audioMuted {
|
||||
// let sharedContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: Constants.appGroupIdentifier)
|
||||
// return sharedContainer?.appendingPathComponent("rtc_SSFD").path ?? ""
|
||||
|
||||
NSURL *sharedContainer = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.org.jitsi.meet.appgroup"];
|
||||
NSURL *widgetStateFileURL = [sharedContainer URLByAppendingPathComponent:@"widgetState"];
|
||||
|
||||
NSDictionary *meetingState = @{@"audioMuted": @(audioMuted)};
|
||||
if (![meetingState writeToURL:widgetStateFileURL atomically:true]) {
|
||||
NSLog(@"error saving state file");
|
||||
}
|
||||
|
||||
[WidgetKitHelper reloadAllWidgets];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
//
|
||||
// WidgetKitHelper.swift
|
||||
// JitsiMeet
|
||||
//
|
||||
// Created by Alex Bumbu on 21.10.2022.
|
||||
//
|
||||
|
||||
import WidgetKit
|
||||
|
||||
@available(iOS 14.0, *)
|
||||
@objcMembers final class WidgetKitHelper: NSObject {
|
||||
|
||||
class func reloadAllWidgets(){
|
||||
|
||||
#if arch(arm64) || arch(i386) || arch(x86_64)
|
||||
WidgetCenter.shared.reloadAllTimelines()
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
@@ -365,7 +365,7 @@
|
||||
"mute": "Mute or unmute your microphone",
|
||||
"pushToTalk": "Press to transmit",
|
||||
"raiseHand": "Raise or lower your hand",
|
||||
"showSpeakerStats": "Show speaker stats",
|
||||
"showSpeakerStats": "Show participants stats",
|
||||
"toggleChat": "Open or close the chat",
|
||||
"toggleFilmstrip": "Show or hide video thumbnails",
|
||||
"toggleScreensharing": "Switch between camera and screen sharing",
|
||||
@@ -579,7 +579,7 @@
|
||||
"minutes": "{{count}}m",
|
||||
"name": "Name",
|
||||
"seconds": "{{count}}s",
|
||||
"speakerStats": "Speaker Stats",
|
||||
"speakerStats": "Participants Stats",
|
||||
"speakerTime": "Speaker Time"
|
||||
},
|
||||
"startupoverlay": {
|
||||
@@ -626,7 +626,7 @@
|
||||
"sharedvideo": "Toggle video sharing",
|
||||
"shortcuts": "Toggle shortcuts",
|
||||
"show": "Show on stage",
|
||||
"speakerStats": "Toggle speaker statistics",
|
||||
"speakerStats": "Toggle participants statistics",
|
||||
"tileView": "Toggle tile view",
|
||||
"toggleCamera": "Toggle camera",
|
||||
"videoblur": "",
|
||||
@@ -662,7 +662,7 @@
|
||||
"shareRoom": "Invite someone",
|
||||
"sharedvideo": "Share video",
|
||||
"shortcuts": "View shortcuts",
|
||||
"speakerStats": "Speaker stats",
|
||||
"speakerStats": "Participants stats",
|
||||
"startScreenSharing": "Start screen sharing",
|
||||
"startSubtitles": "Start subtitles",
|
||||
"startvideoblur": "",
|
||||
|
||||
@@ -657,7 +657,7 @@
|
||||
"login": "Bejelentkezés",
|
||||
"logout": "Kijelentkezés",
|
||||
"lowerYourHand": "Kéz leengedése",
|
||||
"moreActions": "További műveltek",
|
||||
"moreActions": "További műveletek",
|
||||
"moreOptions": "További beállítások",
|
||||
"mute": "Némítás / Visszahangosítás",
|
||||
"muteEveryone": "Mindenki elnémítása",
|
||||
|
||||
@@ -511,7 +511,7 @@
|
||||
"mute": "Mute or unmute your microphone",
|
||||
"pushToTalk": "Push to talk",
|
||||
"raiseHand": "Raise or lower your hand",
|
||||
"showSpeakerStats": "Show speaker stats",
|
||||
"showSpeakerStats": "Show participants stats",
|
||||
"toggleChat": "Open or close the chat",
|
||||
"toggleFilmstrip": "Show or hide video thumbnails",
|
||||
"toggleParticipantsPane": "Show or hide the participants pane",
|
||||
@@ -649,6 +649,8 @@
|
||||
"connectedOneMember": "{{name}} joined the meeting",
|
||||
"connectedThreePlusMembers": "{{name}} and many others joined the meeting",
|
||||
"connectedTwoMembers": "{{first}} and {{second}} joined the meeting",
|
||||
"dataChannelClosed": "Video quality impaired",
|
||||
"dataChannelClosedDescription": "The bridge channel has been disconnected and thus video quality is limited to its lowest setting.",
|
||||
"disconnected": "disconnected",
|
||||
"displayNotifications": "Display notifications for",
|
||||
"focus": "Conference focus",
|
||||
@@ -1036,7 +1038,7 @@
|
||||
"sad": "Sad",
|
||||
"search": "Search",
|
||||
"seconds": "{{count}}s",
|
||||
"speakerStats": "Speaker Stats",
|
||||
"speakerStats": "Participants Stats",
|
||||
"speakerTime": "Speaker Time",
|
||||
"surprised": "Surprised"
|
||||
},
|
||||
@@ -1117,7 +1119,7 @@
|
||||
"shortcuts": "Toggle shortcuts",
|
||||
"show": "Show on stage",
|
||||
"silence": "Silence",
|
||||
"speakerStats": "Toggle speaker statistics",
|
||||
"speakerStats": "Toggle participants statistics",
|
||||
"surprised": "Surprised",
|
||||
"tileView": "Toggle tile view",
|
||||
"toggleCamera": "Toggle camera",
|
||||
@@ -1204,7 +1206,7 @@
|
||||
"shortcuts": "View shortcuts",
|
||||
"showWhiteboard": "Show whiteboard",
|
||||
"silence": "Silence",
|
||||
"speakerStats": "Speaker stats",
|
||||
"speakerStats": "Participants stats",
|
||||
"startScreenSharing": "Start screen sharing",
|
||||
"startSubtitles": "Subtitles • {{language}}",
|
||||
"stopAudioSharing": "Stop audio sharing",
|
||||
|
||||
@@ -1450,6 +1450,22 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application that the data channel has been closed.
|
||||
*
|
||||
* @param {number} code - The close code.
|
||||
* @param {string} reason - The close reason.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyDataChannelClosed(code: number, reason: string) {
|
||||
this._sendEvent({
|
||||
name: 'data-channel-closed',
|
||||
code,
|
||||
reason
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application that the data channel has been opened.
|
||||
*
|
||||
@@ -1920,6 +1936,27 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the external application that a PeerConnection lost connectivity. This event is fired only if
|
||||
* a PC `failed` but connectivity to the rtcstats server is still maintained signaling that there is a
|
||||
* problem establishing a link between the app and the JVB server or the remote peer in case of P2P.
|
||||
* Will only fire if rtcstats is enabled.
|
||||
*
|
||||
* @param {boolean} isP2P - Type of PC.
|
||||
* @param {boolean} wasConnected - Was this connection previously connected. If it was it could mean
|
||||
* that connectivity was disrupted, if not it most likely means that the app could not reach
|
||||
* the JVB server, or the other peer in case of P2P.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyPeerConnectionFailure(isP2P, wasConnected) {
|
||||
this._sendEvent({
|
||||
name: 'peer-connection-failure',
|
||||
isP2P,
|
||||
wasConnected
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the allocated resources.
|
||||
*
|
||||
|
||||
2
modules/API/external/external_api.js
vendored
@@ -106,6 +106,7 @@ const events = {
|
||||
'camera-error': 'cameraError',
|
||||
'chat-updated': 'chatUpdated',
|
||||
'content-sharing-participants-changed': 'contentSharingParticipantsChanged',
|
||||
'data-channel-closed': 'dataChannelClosed',
|
||||
'data-channel-opened': 'dataChannelOpened',
|
||||
'device-list-changed': 'deviceListChanged',
|
||||
'display-name-change': 'displayNameChange',
|
||||
@@ -134,6 +135,7 @@ const events = {
|
||||
'participant-role-changed': 'participantRoleChanged',
|
||||
'participants-pane-toggled': 'participantsPaneToggled',
|
||||
'password-required': 'passwordRequired',
|
||||
'peer-connection-failure': 'peerConnectionFailure',
|
||||
'prejoin-screen-loaded': 'prejoinScreenLoaded',
|
||||
'proxy-connection-event': 'proxyConnectionEvent',
|
||||
'raise-hand-updated': 'raiseHandUpdated',
|
||||
|
||||
66
package-lock.json
generated
@@ -31,7 +31,7 @@
|
||||
"@jitsi/js-utils": "2.0.4",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
"@jitsi/rnnoise-wasm": "0.1.0",
|
||||
"@jitsi/rtcstats": "9.4.1",
|
||||
"@jitsi/rtcstats": "9.5.0",
|
||||
"@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.10.2",
|
||||
@@ -55,7 +55,7 @@
|
||||
"@types/w3c-image-capture": "1.0.6",
|
||||
"@vladmandic/human": "2.6.5",
|
||||
"@vladmandic/human-models": "2.5.9",
|
||||
"@xmldom/xmldom": "0.7.6",
|
||||
"@xmldom/xmldom": "0.7.9",
|
||||
"amplitude-js": "8.2.1",
|
||||
"base64-js": "1.3.1",
|
||||
"bc-css-flags": "3.0.0",
|
||||
@@ -74,7 +74,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/v1535.0.0+e6263e7c/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1539.0.0+eb4873d2/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -88,7 +88,7 @@
|
||||
"react-focus-lock": "2.5.1",
|
||||
"react-i18next": "10.11.4",
|
||||
"react-linkify": "1.0.0-alpha",
|
||||
"react-native": "0.68.4",
|
||||
"react-native": "0.68.5",
|
||||
"react-native-background-timer": "2.4.1",
|
||||
"react-native-calendar-events": "2.2.0",
|
||||
"react-native-callstats": "3.73.7",
|
||||
@@ -147,7 +147,7 @@
|
||||
"@types/js-md5": "0.4.3",
|
||||
"@types/lodash": "4.14.182",
|
||||
"@types/react": "17.0.14",
|
||||
"@types/react-native": "0.68.7",
|
||||
"@types/react-native": "0.68.9",
|
||||
"@types/react-redux": "7.1.24",
|
||||
"@types/react-window": "1.8.5",
|
||||
"@types/unorm": "1.3.28",
|
||||
@@ -3780,9 +3780,9 @@
|
||||
"integrity": "sha512-JujivPbOUvdRYa2xqByHYKfKGNGa7ZPyNLaNuh8hEp9XsiNfjaJAHdboq6M1VY9TP+765nyxC0LjpAw1VkikOQ=="
|
||||
},
|
||||
"node_modules/@jitsi/rtcstats": {
|
||||
"version": "9.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.4.1.tgz",
|
||||
"integrity": "sha512-JrRBk9xLAnRgBP9aqTjR41DBAQYMkupOfy8XMIumdjxlDqf8dQygvYRc253xdHejr/kSHCvnaFoVIM3hHfeooQ==",
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.5.0.tgz",
|
||||
"integrity": "sha512-jKB+1IzKuqynA2etmWAA4uDFF0oAFUZWxRq+m+rOt8FfBp6pXojWbWA7xblcjxerj/3njGc8nEQbcK9qck1How==",
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "^2.0.0",
|
||||
"sdp": "^3.0.3",
|
||||
@@ -6493,9 +6493,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-native": {
|
||||
"version": "0.68.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.68.7.tgz",
|
||||
"integrity": "sha512-icGr0/iTPLsvIrUoLvu5uluDFBMZEir+DbwgrHnvazO3fJv1C/kpZZLGplQ3noYyDLjuBynwOUgoaZpGyFI4Iw==",
|
||||
"version": "0.68.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.68.9.tgz",
|
||||
"integrity": "sha512-/1nbdoynVMjNsudurxHiEf9rSdviKAkV+pVgwpNk21v7gKJfzoHyT3nFunPuMoDgvvdZR5ofUrOJuCPbzF2GUw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/react": "^17"
|
||||
@@ -7349,9 +7349,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@xmldom/xmldom": {
|
||||
"version": "0.7.6",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.6.tgz",
|
||||
"integrity": "sha512-HHXP9hskkFQHy8QxxUXkS7946FFIhYVfGqsk0WLwllmexN9x/+R4UBLvurHEuyXRfVEObVR8APuQehykLviwSQ==",
|
||||
"version": "0.7.9",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.9.tgz",
|
||||
"integrity": "sha512-yceMpm/xd4W2a85iqZyO09gTnHvXF6pyiWjD2jcOJs7hRoZtNNOO1eJlhHj1ixA+xip2hOyGn+LgcvLCMo5zXA==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
@@ -13497,8 +13497,8 @@
|
||||
},
|
||||
"node_modules/lib-jitsi-meet": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1535.0.0+e6263e7c/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-RgMoesoWyscWi2fL9Hxp8PUwDlUtHbo+GhXosD3GeKR0zmihu/kxTONMUifGQnF8XdtcjaZfL2jCJynLwYKlkw==",
|
||||
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1539.0.0+eb4873d2/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-hEu5nmljbOVKPHIcCpW6GTFzZpWDOAfplKTkNdvrIyNgMiIjHhUgmMzF+IGicd7KPud3z8aQ+0HFnpcxO/T6ZA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
@@ -16128,9 +16128,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-native": {
|
||||
"version": "0.68.4",
|
||||
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.68.4.tgz",
|
||||
"integrity": "sha512-Hp5qwztQ1XNnV43QTz1kUx33iZHmJqbbe7L19V9psaWtX/h9j6SEtZ3UHBrigIPlppkIP1E5x3CDr9FdD4d6CA==",
|
||||
"version": "0.68.5",
|
||||
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.68.5.tgz",
|
||||
"integrity": "sha512-t3kiQ/gumFV+0r/NRSIGtYxanjY4da0utFqHgkMcRPJVwXFWC0Fr8YiOeRGYO1dp8EfrSsOjtfWic/inqVYlbQ==",
|
||||
"dependencies": {
|
||||
"@jest/create-cache-key-function": "^27.0.1",
|
||||
"@react-native-community/cli": "^7.0.3",
|
||||
@@ -23208,9 +23208,9 @@
|
||||
"integrity": "sha512-JujivPbOUvdRYa2xqByHYKfKGNGa7ZPyNLaNuh8hEp9XsiNfjaJAHdboq6M1VY9TP+765nyxC0LjpAw1VkikOQ=="
|
||||
},
|
||||
"@jitsi/rtcstats": {
|
||||
"version": "9.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.4.1.tgz",
|
||||
"integrity": "sha512-JrRBk9xLAnRgBP9aqTjR41DBAQYMkupOfy8XMIumdjxlDqf8dQygvYRc253xdHejr/kSHCvnaFoVIM3hHfeooQ==",
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jitsi/rtcstats/-/rtcstats-9.5.0.tgz",
|
||||
"integrity": "sha512-jKB+1IzKuqynA2etmWAA4uDFF0oAFUZWxRq+m+rOt8FfBp6pXojWbWA7xblcjxerj/3njGc8nEQbcK9qck1How==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "^2.0.0",
|
||||
"sdp": "^3.0.3",
|
||||
@@ -25178,9 +25178,9 @@
|
||||
}
|
||||
},
|
||||
"@types/react-native": {
|
||||
"version": "0.68.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.68.7.tgz",
|
||||
"integrity": "sha512-icGr0/iTPLsvIrUoLvu5uluDFBMZEir+DbwgrHnvazO3fJv1C/kpZZLGplQ3noYyDLjuBynwOUgoaZpGyFI4Iw==",
|
||||
"version": "0.68.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.68.9.tgz",
|
||||
"integrity": "sha512-/1nbdoynVMjNsudurxHiEf9rSdviKAkV+pVgwpNk21v7gKJfzoHyT3nFunPuMoDgvvdZR5ofUrOJuCPbzF2GUw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "^17"
|
||||
@@ -25794,9 +25794,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@xmldom/xmldom": {
|
||||
"version": "0.7.6",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.6.tgz",
|
||||
"integrity": "sha512-HHXP9hskkFQHy8QxxUXkS7946FFIhYVfGqsk0WLwllmexN9x/+R4UBLvurHEuyXRfVEObVR8APuQehykLviwSQ=="
|
||||
"version": "0.7.9",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.9.tgz",
|
||||
"integrity": "sha512-yceMpm/xd4W2a85iqZyO09gTnHvXF6pyiWjD2jcOJs7hRoZtNNOO1eJlhHj1ixA+xip2hOyGn+LgcvLCMo5zXA=="
|
||||
},
|
||||
"@xobotyi/scrollbar-width": {
|
||||
"version": "1.9.5",
|
||||
@@ -30510,8 +30510,8 @@
|
||||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1535.0.0+e6263e7c/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-RgMoesoWyscWi2fL9Hxp8PUwDlUtHbo+GhXosD3GeKR0zmihu/kxTONMUifGQnF8XdtcjaZfL2jCJynLwYKlkw==",
|
||||
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1539.0.0+eb4873d2/lib-jitsi-meet.tgz",
|
||||
"integrity": "sha512-hEu5nmljbOVKPHIcCpW6GTFzZpWDOAfplKTkNdvrIyNgMiIjHhUgmMzF+IGicd7KPud3z8aQ+0HFnpcxO/T6ZA==",
|
||||
"requires": {
|
||||
"@jitsi/js-utils": "2.0.0",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
@@ -32535,9 +32535,9 @@
|
||||
}
|
||||
},
|
||||
"react-native": {
|
||||
"version": "0.68.4",
|
||||
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.68.4.tgz",
|
||||
"integrity": "sha512-Hp5qwztQ1XNnV43QTz1kUx33iZHmJqbbe7L19V9psaWtX/h9j6SEtZ3UHBrigIPlppkIP1E5x3CDr9FdD4d6CA==",
|
||||
"version": "0.68.5",
|
||||
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.68.5.tgz",
|
||||
"integrity": "sha512-t3kiQ/gumFV+0r/NRSIGtYxanjY4da0utFqHgkMcRPJVwXFWC0Fr8YiOeRGYO1dp8EfrSsOjtfWic/inqVYlbQ==",
|
||||
"requires": {
|
||||
"@jest/create-cache-key-function": "^27.0.1",
|
||||
"@react-native-community/cli": "^7.0.3",
|
||||
|
||||
10
package.json
@@ -36,7 +36,7 @@
|
||||
"@jitsi/js-utils": "2.0.4",
|
||||
"@jitsi/logger": "2.0.0",
|
||||
"@jitsi/rnnoise-wasm": "0.1.0",
|
||||
"@jitsi/rtcstats": "9.4.1",
|
||||
"@jitsi/rtcstats": "9.5.0",
|
||||
"@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.10.2",
|
||||
@@ -60,7 +60,7 @@
|
||||
"@types/w3c-image-capture": "1.0.6",
|
||||
"@vladmandic/human": "2.6.5",
|
||||
"@vladmandic/human-models": "2.5.9",
|
||||
"@xmldom/xmldom": "0.7.6",
|
||||
"@xmldom/xmldom": "0.7.9",
|
||||
"amplitude-js": "8.2.1",
|
||||
"base64-js": "1.3.1",
|
||||
"bc-css-flags": "3.0.0",
|
||||
@@ -79,7 +79,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/v1535.0.0+e6263e7c/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1539.0.0+eb4873d2/lib-jitsi-meet.tgz",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
"moment-duration-format": "2.2.2",
|
||||
@@ -93,7 +93,7 @@
|
||||
"react-focus-lock": "2.5.1",
|
||||
"react-i18next": "10.11.4",
|
||||
"react-linkify": "1.0.0-alpha",
|
||||
"react-native": "0.68.4",
|
||||
"react-native": "0.68.5",
|
||||
"react-native-background-timer": "2.4.1",
|
||||
"react-native-calendar-events": "2.2.0",
|
||||
"react-native-callstats": "3.73.7",
|
||||
@@ -152,7 +152,7 @@
|
||||
"@types/js-md5": "0.4.3",
|
||||
"@types/lodash": "4.14.182",
|
||||
"@types/react": "17.0.14",
|
||||
"@types/react-native": "0.68.7",
|
||||
"@types/react-native": "0.68.9",
|
||||
"@types/react-redux": "7.1.24",
|
||||
"@types/react-window": "1.8.5",
|
||||
"@types/unorm": "1.3.28",
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import { ColorPalette, getRGBAFormat } from '../styles';
|
||||
|
||||
/**
|
||||
@@ -14,21 +12,6 @@ export default {
|
||||
icon: 'rgb(28, 32, 37)',
|
||||
text: 'rgb(28, 32, 37)'
|
||||
},
|
||||
'Chat': {
|
||||
displayName: 'rgb(94, 109, 121)',
|
||||
localMsgBackground: 'rgb(215, 230, 249)',
|
||||
lobbyMsgBackground: 'rgb(106, 80, 211)',
|
||||
lobbyMsgNotice: 'rgb(16, 10, 41)',
|
||||
privateMsgBackground: 'rgb(250, 219, 219)',
|
||||
privateMsgNotice: 'rgb(186, 39, 58)',
|
||||
remoteMsgBackground: 'rgb(241, 242, 246)',
|
||||
replyBorder: 'rgb(219, 197, 200)',
|
||||
replyIcon: 'rgb(94, 109, 121)'
|
||||
},
|
||||
'Conference': {
|
||||
inviteButtonBackground: 'rgb(0, 119, 225)',
|
||||
onVideoText: 'white'
|
||||
},
|
||||
'Dialog': {},
|
||||
'Header': {
|
||||
background: ColorPalette.blue,
|
||||
|
||||
@@ -138,6 +138,18 @@ export const CONFERENCE_WILL_LEAVE = 'CONFERENCE_WILL_LEAVE';
|
||||
*/
|
||||
export const DATA_CHANNEL_OPENED = 'DATA_CHANNEL_OPENED';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which signals that the data channel with the
|
||||
* bridge has been closed.
|
||||
*
|
||||
* {
|
||||
* type: DATA_CHANNEL_CLOSED,
|
||||
* code: number,
|
||||
* reason: string
|
||||
* }
|
||||
*/
|
||||
export const DATA_CHANNEL_CLOSED = 'DATA_CHANNEL_CLOSED';
|
||||
|
||||
/**
|
||||
* The type of action which signals that the user has been kicked out from
|
||||
* the conference.
|
||||
|
||||
@@ -41,6 +41,7 @@ import {
|
||||
CONFERENCE_UNIQUE_ID_SET,
|
||||
CONFERENCE_WILL_JOIN,
|
||||
CONFERENCE_WILL_LEAVE,
|
||||
DATA_CHANNEL_CLOSED,
|
||||
DATA_CHANNEL_OPENED,
|
||||
E2E_RTT_CHANGED,
|
||||
KICKED_OUT,
|
||||
@@ -581,6 +582,26 @@ export function dataChannelOpened() {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals the data channel with the bridge was abruptly closed.
|
||||
*
|
||||
* @param {number} code - Close code.
|
||||
* @param {string} reason - Close reason.
|
||||
*
|
||||
* @returns {{
|
||||
* type: DATA_CHANNEL_CLOSED,
|
||||
* code: number,
|
||||
* reason: string
|
||||
* }}
|
||||
*/
|
||||
export function dataChannelClosed(code: number, reason: string) {
|
||||
return {
|
||||
type: DATA_CHANNEL_CLOSED,
|
||||
code,
|
||||
reason
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to end a conference for all participants.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { FaceLandmarks } from '../../face-landmarks/types';
|
||||
import { LOCKED_LOCALLY, LOCKED_REMOTELY } from '../../room-lock/constants';
|
||||
import { ISpeakerStats } from '../../speaker-stats/reducer';
|
||||
import { CONNECTION_WILL_CONNECT, SET_LOCATION_URL } from '../connection/actionTypes';
|
||||
import { JitsiConferenceErrors } from '../lib-jitsi-meet';
|
||||
import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
@@ -53,6 +55,7 @@ export interface IJitsiConference {
|
||||
getMeetingUniqueId: Function;
|
||||
getParticipantById: Function;
|
||||
getParticipants: Function;
|
||||
getSpeakerStats: () => ISpeakerStats;
|
||||
grantOwner: Function;
|
||||
isAVModerationSupported: Function;
|
||||
isCallstatsEnabled: Function;
|
||||
@@ -74,6 +77,7 @@ export interface IJitsiConference {
|
||||
sendCommand: Function;
|
||||
sendCommandOnce: Function;
|
||||
sendEndpointMessage: Function;
|
||||
sendFaceLandmarks: (faceLandmarks: FaceLandmarks) => void;
|
||||
sendFeedback: Function;
|
||||
sendLobbyMessage: Function;
|
||||
sessionId: string;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { AnyAction } from 'redux';
|
||||
|
||||
import { IStore } from '../../app/types';
|
||||
import { getFeatureFlag } from '../flags/functions';
|
||||
import Platform from '../react/Platform';
|
||||
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
import { updateSettings } from '../settings/actions';
|
||||
|
||||
@@ -52,7 +53,7 @@ function _setConfig({ dispatch, getState }: IStore, next: Function, action: AnyA
|
||||
const settings = state['features/base/settings'];
|
||||
const config: IConfig = {};
|
||||
|
||||
if (typeof settings.disableP2P !== 'undefined') {
|
||||
if (Platform.OS !== 'android' && typeof settings.disableP2P !== 'undefined') {
|
||||
config.p2p = { enabled: !settings.disableP2P };
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
import { CONFERENCE_INFO } from '../../conference/components/constants';
|
||||
import Platform from '../react/Platform';
|
||||
import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
import { equals } from '../redux/functions';
|
||||
|
||||
@@ -48,6 +49,8 @@ const INITIAL_RN_STATE: IConfig = {
|
||||
disableAudioLevels: true,
|
||||
|
||||
p2p: {
|
||||
// Temporarily disable P2P on Android while we sort out some (codec?) issues.
|
||||
...(Platform.OS === 'android' ? { enabled: false } : {}), // eslint-disable-line no-extra-parens
|
||||
preferredCodec: 'h264'
|
||||
},
|
||||
|
||||
|
||||
10
react/features/base/icons/svg/emotions-angry.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="10" cy="10" r="10" fill="url(#paint0_radial_72_1897)"/>
|
||||
<path opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" d="M5.46845 5.14411C5.08781 4.88541 4.56951 4.98428 4.31081 5.36492C4.05212 5.74557 4.15098 6.26387 4.53163 6.52257L5.47766 7.16551C5.18224 7.46624 5.00002 7.87855 5.00002 8.33341C5.00002 9.25388 5.74622 10.0001 6.66669 10.0001C7.58716 10.0001 8.33336 9.25388 8.33336 8.33341C8.33336 8.23415 8.32468 8.13691 8.30804 8.04242C8.54426 7.66462 8.44124 7.16449 8.06956 6.91188L5.46845 5.14411ZM6.66305 14.7842C6.30373 14.5781 6.1795 14.1198 6.38556 13.7605C6.75032 13.1244 7.27645 12.5959 7.91081 12.2283C8.54518 11.8607 9.26532 11.6669 9.99852 11.6667C10.7317 11.6664 11.452 11.8596 12.0866 12.2268C12.7213 12.5939 13.2478 13.1221 13.613 13.7578C13.8193 14.117 13.6954 14.5754 13.3362 14.7818C12.9771 14.9881 12.5186 14.8642 12.3123 14.505C12.0786 14.0981 11.7416 13.7601 11.3354 13.5251C10.9293 13.2901 10.4683 13.1665 9.99906 13.1667C9.52981 13.1668 9.06892 13.2908 8.66293 13.5261C8.25693 13.7614 7.92021 14.0996 7.68677 14.5067C7.4807 14.866 7.02237 14.9902 6.66305 14.7842ZM15.7903 5.36492C15.5316 4.98428 15.0134 4.88541 14.6327 5.14411L12.0316 6.91188C11.7043 7.13434 11.5853 7.54876 11.7229 7.90254C11.6862 8.03998 11.6667 8.18441 11.6667 8.33341C11.6667 9.25388 12.4129 10.0001 13.3334 10.0001C14.2538 10.0001 15 9.25388 15 8.33341C15 7.89926 14.834 7.50388 14.562 7.20728L15.5695 6.52257C15.9502 6.26387 16.049 5.74557 15.7903 5.36492Z" fill="black"/>
|
||||
<defs>
|
||||
<radialGradient id="paint0_radial_72_1897" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(10 4.58333) rotate(90) scale(15.4167)">
|
||||
<stop offset="0.359375" stop-color="#F26325"/>
|
||||
<stop offset="1" stop-color="#F24A25"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
10
react/features/base/icons/svg/emotions-disgusted.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="10" cy="10" r="10" fill="url(#paint0_radial_351_6183)"/>
|
||||
<path opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" d="M4.16669 7.50001C4.16669 7.03977 4.53978 6.66667 5.00002 6.66667H7.50002C7.96026 6.66667 8.33335 7.03977 8.33335 7.50001C8.33335 7.96024 7.96026 8.33334 7.50002 8.33334H5.00002C4.53978 8.33334 4.16669 7.96024 4.16669 7.50001ZM6.66669 15C6.66669 13.1591 8.15907 11.6667 10 11.6667C11.841 11.6667 13.3334 13.1591 13.3334 15H6.66669ZM12.5 6.66667C12.0398 6.66667 11.6667 7.03977 11.6667 7.50001C11.6667 7.96024 12.0398 8.33334 12.5 8.33334H15C15.4603 8.33334 15.8334 7.96024 15.8334 7.50001C15.8334 7.03977 15.4603 6.66667 15 6.66667H12.5Z" fill="black"/>
|
||||
<defs>
|
||||
<radialGradient id="paint0_radial_351_6183" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(10 4.58333) rotate(90) scale(15.4167)">
|
||||
<stop offset="0.359375" stop-color="#98E791"/>
|
||||
<stop offset="1" stop-color="#3C9845"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
10
react/features/base/icons/svg/emotions-fearful.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="10" cy="10" r="10" fill="url(#paint0_radial_72_1884)"/>
|
||||
<path opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" d="M8.33333 7.49999C8.33333 8.42047 7.58714 9.16666 6.66667 9.16666C5.74619 9.16666 5 8.42047 5 7.49999C5 6.57952 5.74619 5.83333 6.66667 5.83333C7.58714 5.83333 8.33333 6.57952 8.33333 7.49999ZM15 7.49999C15 8.42047 14.2538 9.16666 13.3333 9.16666C12.4129 9.16666 11.6667 8.42047 11.6667 7.49999C11.6667 6.57952 12.4129 5.83333 13.3333 5.83333C14.2538 5.83333 15 6.57952 15 7.49999ZM10 11.6667C8.15905 11.6667 6.66667 13.159 6.66667 15H13.3333C13.3333 13.159 11.8409 11.6667 10 11.6667Z" fill="black"/>
|
||||
<defs>
|
||||
<radialGradient id="paint0_radial_72_1884" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(10 4.58333) rotate(90) scale(15.4167)">
|
||||
<stop offset="0.359375" stop-color="#6BEBD4"/>
|
||||
<stop offset="1" stop-color="#077EA4"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1018 B |
10
react/features/base/icons/svg/emotions-happy.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="10" cy="10" r="10" fill="url(#paint0_radial_72_1844)"/>
|
||||
<path opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" d="M8.33333 7.49999C8.33333 8.42047 7.58714 9.16666 6.66667 9.16666C5.74619 9.16666 5 8.42047 5 7.49999C5 6.57952 5.74619 5.83333 6.66667 5.83333C7.58714 5.83333 8.33333 6.57952 8.33333 7.49999ZM15 7.49999C15 8.42047 14.2538 9.16666 13.3333 9.16666C12.4129 9.16666 11.6667 8.42047 11.6667 7.49999C11.6667 6.57952 12.4129 5.83333 13.3333 5.83333C14.2538 5.83333 15 6.57952 15 7.49999ZM7.53238 12.6776C7.37535 12.2943 6.93734 12.1109 6.55404 12.2679C6.17075 12.4249 5.98732 12.8629 6.14435 13.2462C6.45676 14.0088 6.98828 14.6616 7.6717 15.1221C8.35513 15.5826 9.15976 15.8301 9.98384 15.8333C10.8079 15.8365 11.6144 15.5953 12.3014 15.1401C12.9884 14.6849 13.525 14.0362 13.8433 13.2761C14.0033 12.894 13.8233 12.4546 13.4412 12.2946C13.0591 12.1346 12.6197 12.3146 12.4597 12.6967C12.256 13.1832 11.9126 13.5983 11.4729 13.8896C11.0332 14.181 10.5171 14.3354 9.98966 14.3333C9.46224 14.3313 8.94728 14.1729 8.50989 13.8782C8.0725 13.5834 7.73232 13.1656 7.53238 12.6776Z" fill="black"/>
|
||||
<defs>
|
||||
<radialGradient id="paint0_radial_72_1844" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(10 4.58333) rotate(90) scale(15.4167)">
|
||||
<stop offset="0.359375" stop-color="#F2AD25"/>
|
||||
<stop offset="1" stop-color="#F27B25"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
10
react/features/base/icons/svg/emotions-neutral.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="10" cy="10" r="10" fill="url(#paint0_radial_72_1850)"/>
|
||||
<path opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" d="M8.33333 7.49999C8.33333 8.42047 7.58714 9.16666 6.66667 9.16666C5.74619 9.16666 5 8.42047 5 7.49999C5 6.57952 5.74619 5.83333 6.66667 5.83333C7.58714 5.83333 8.33333 6.57952 8.33333 7.49999ZM15 7.49999C15 8.42047 14.2538 9.16666 13.3333 9.16666C12.4129 9.16666 11.6667 8.42047 11.6667 7.49999C11.6667 6.57952 12.4129 5.83333 13.3333 5.83333C14.2538 5.83333 15 6.57952 15 7.49999ZM7.5 13.3333C7.03976 13.3333 6.66667 13.7064 6.66667 14.1667C6.66667 14.6269 7.03976 15 7.5 15H12.5C12.9602 15 13.3333 14.6269 13.3333 14.1667C13.3333 13.7064 12.9602 13.3333 12.5 13.3333H7.5Z" fill="black"/>
|
||||
<defs>
|
||||
<radialGradient id="paint0_radial_72_1850" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(10 4.58333) rotate(90) scale(15.4167)">
|
||||
<stop offset="0.359375" stop-color="#AAAAAA"/>
|
||||
<stop offset="1" stop-color="#5E5E5E"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
10
react/features/base/icons/svg/emotions-sad.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="10" cy="10" r="10" fill="url(#paint0_radial_72_1862)"/>
|
||||
<path opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" d="M8.33333 7.49999C8.33333 8.42047 7.58714 9.16666 6.66667 9.16666C5.74619 9.16666 5 8.42047 5 7.49999C5 6.57952 5.74619 5.83333 6.66667 5.83333C7.58714 5.83333 8.33333 6.57952 8.33333 7.49999ZM15 7.49999C15 8.42047 14.2538 9.16666 13.3333 9.16666C12.4129 9.16666 11.6667 8.42047 11.6667 7.49999C11.6667 6.57952 12.4129 5.83333 13.3333 5.83333C14.2538 5.83333 15 6.57952 15 7.49999ZM6.38554 13.7605C6.17948 14.1198 6.30371 14.5781 6.66303 14.7842C7.02235 14.9902 7.48068 14.866 7.68675 14.5067C7.92019 14.0996 8.25691 13.7614 8.66291 13.5261C9.0689 13.2908 9.52979 13.1668 9.99904 13.1667C10.4683 13.1665 10.9293 13.2901 11.3354 13.5251C11.7416 13.7601 12.0786 14.0981 12.3123 14.505C12.5186 14.8642 12.977 14.9881 13.3362 14.7818C13.6954 14.5754 13.8193 14.117 13.613 13.7578C13.2477 13.1221 12.7212 12.5939 12.0866 12.2268C11.452 11.8596 10.7317 11.6664 9.9985 11.6667C9.2653 11.6669 8.54516 11.8607 7.91079 12.2283C7.27643 12.5959 6.7503 13.1244 6.38554 13.7605Z" fill="black"/>
|
||||
<defs>
|
||||
<radialGradient id="paint0_radial_72_1862" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(10 4.58333) rotate(90) scale(15.4167)">
|
||||
<stop offset="0.359375" stop-color="#65B3FB"/>
|
||||
<stop offset="1" stop-color="#256BF2"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
10
react/features/base/icons/svg/emotions-surprised.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="10" cy="10" r="10" fill="url(#paint0_radial_72_1873)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.33333 7.49999C8.33333 8.42047 7.58714 9.16666 6.66667 9.16666C5.74619 9.16666 5 8.42047 5 7.49999C5 6.57952 5.74619 5.83333 6.66667 5.83333C7.58714 5.83333 8.33333 6.57952 8.33333 7.49999ZM15 7.49999C15 8.42047 14.2538 9.16666 13.3333 9.16666C12.4129 9.16666 11.6667 8.42047 11.6667 7.49999C11.6667 6.57952 12.4129 5.83333 13.3333 5.83333C14.2538 5.83333 15 6.57952 15 7.49999ZM10 15C11.3807 15 12.5 14.403 12.5 13.6667C12.5 12.9303 11.3807 11.6667 10 11.6667C8.61929 11.6667 7.5 12.9303 7.5 13.6667C7.5 14.403 8.61929 15 10 15Z" fill="black"/>
|
||||
<defs>
|
||||
<radialGradient id="paint0_radial_72_1873" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(10 4.58333) rotate(90) scale(15.4167)">
|
||||
<stop offset="0.359375" stop-color="#CC86E4"/>
|
||||
<stop offset="1" stop-color="#933CD8"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -29,6 +29,13 @@ export { default as IconE2EE } from './e2ee.svg';
|
||||
export { default as IconEnlarge } from './enlarge.svg';
|
||||
export { default as IconEnterFullscreen } from './enter-fullscreen.svg';
|
||||
export { default as IconEnvelope } from './envelope.svg';
|
||||
export { default as IconEmotionsAngry } from './emotions-angry.svg';
|
||||
export { default as IconEmotionsDisgusted } from './emotions-disgusted.svg';
|
||||
export { default as IconEmotionsFearful } from './emotions-fearful.svg';
|
||||
export { default as IconEmotionsHappy } from './emotions-happy.svg';
|
||||
export { default as IconEmotionsNeutral } from './emotions-neutral.svg';
|
||||
export { default as IconEmotionsSad } from './emotions-sad.svg';
|
||||
export { default as IconEmotionsSurprised } from './emotions-surprised.svg';
|
||||
export { default as IconExclamationSolid } from './exclamation-solid.svg';
|
||||
export { default as IconExclamationTriangle } from './exclamation-triangle.svg';
|
||||
export { default as IconExitFullscreen } from './exit-fullscreen.svg';
|
||||
|
||||
@@ -53,9 +53,9 @@ const JitsiKeyboardAvoidingView = (
|
||||
addBottomPadding = true,
|
||||
children,
|
||||
contentContainerStyle,
|
||||
disableForcedKeyboardDismiss,
|
||||
hasTabNavigator,
|
||||
hasBottomTextInput,
|
||||
disableForcedKeyboardDismiss,
|
||||
style
|
||||
}: Props) => {
|
||||
const headerHeight = useHeaderHeight();
|
||||
|
||||
@@ -60,10 +60,10 @@ const JitsiScreen = ({
|
||||
addBottomPadding,
|
||||
contentContainerStyle,
|
||||
children,
|
||||
disableForcedKeyboardDismiss = false,
|
||||
footerComponent,
|
||||
hasTabNavigator = false,
|
||||
hasBottomTextInput = false,
|
||||
disableForcedKeyboardDismiss = false,
|
||||
safeAreaInsets = [ 'left', 'right' ],
|
||||
style
|
||||
}: Props) => {
|
||||
|
||||
@@ -19,7 +19,12 @@ type Props = {
|
||||
/**
|
||||
* The extra styles to be applied to links.
|
||||
*/
|
||||
linkStyle: StyleType
|
||||
linkStyle: StyleType,
|
||||
|
||||
/**
|
||||
* The extra styles to be applied to text.
|
||||
*/
|
||||
style?: StyleType
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -46,7 +51,9 @@ export default class Linkify extends Component<Props> {
|
||||
return (
|
||||
<ReactLinkify
|
||||
componentDecorator = { this._componentDecorator }>
|
||||
<Text selectable = { true }>
|
||||
<Text
|
||||
selectable = { true }
|
||||
style = { this.props.style }>
|
||||
{ this.props.children }
|
||||
</Text>
|
||||
</ReactLinkify>
|
||||
|
||||
@@ -66,12 +66,15 @@ const Button: React.FC<IProps> = ({
|
||||
}
|
||||
|
||||
if (type === TERTIARY) {
|
||||
buttonLabelStyles
|
||||
= disabled ? styles.buttonLabelTertiaryDisabled : styles.buttonLabelTertiary;
|
||||
|
||||
return (
|
||||
<TouchableRipple
|
||||
accessibilityLabel = { accessibilityLabel }
|
||||
disabled = { disabled }
|
||||
onPress = { onPress }
|
||||
rippleColor = 'transparent'
|
||||
rippleColor = { BaseTheme.palette.action03Active }
|
||||
style = { [
|
||||
buttonStyles,
|
||||
style
|
||||
|
||||
@@ -23,15 +23,15 @@ export default {
|
||||
...buttonLabel
|
||||
},
|
||||
|
||||
buttonContent: {
|
||||
height: BUTTON_HEIGHT
|
||||
},
|
||||
|
||||
buttonLabelDisabled: {
|
||||
...buttonLabel,
|
||||
color: BaseTheme.palette.text03
|
||||
},
|
||||
|
||||
buttonContent: {
|
||||
height: BUTTON_HEIGHT
|
||||
},
|
||||
|
||||
buttonDisabled: {
|
||||
...button,
|
||||
backgroundColor: BaseTheme.palette.actionDisabled
|
||||
@@ -54,6 +54,13 @@ export default {
|
||||
|
||||
buttonLabelTertiary: {
|
||||
...buttonLabel,
|
||||
color: BaseTheme.palette.text01
|
||||
color: BaseTheme.palette.text01,
|
||||
textAlign: 'center'
|
||||
},
|
||||
|
||||
buttonLabelTertiaryDisabled: {
|
||||
...buttonLabel,
|
||||
color: BaseTheme.palette.text03,
|
||||
textAlign: 'center'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import Icon from '../../../icons/components/Icon';
|
||||
|
||||
interface IProps {
|
||||
accessibilityLabel: string;
|
||||
className?: string;
|
||||
icon: Function;
|
||||
id?: string;
|
||||
onClick: () => void;
|
||||
@@ -40,14 +41,14 @@ const useStyles = makeStyles()(theme => {
|
||||
};
|
||||
});
|
||||
|
||||
const ClickableIcon = ({ accessibilityLabel, icon, id, onClick }: IProps) => {
|
||||
const ClickableIcon = ({ accessibilityLabel, className, icon, id, onClick }: IProps) => {
|
||||
const { classes: styles, cx } = useStyles();
|
||||
const isMobile = isMobileBrowser();
|
||||
|
||||
return (
|
||||
<button
|
||||
aria-label = { accessibilityLabel }
|
||||
className = { cx(styles.button, isMobile && 'is-mobile') }
|
||||
className = { cx(styles.button, isMobile && 'is-mobile', className) }
|
||||
id = { id }
|
||||
onClick = { onClick }>
|
||||
<Icon
|
||||
|
||||
@@ -67,7 +67,7 @@ const useStyles = makeStyles()(theme => {
|
||||
flexDirection: 'column',
|
||||
height: 'auto',
|
||||
minHeight: '200px',
|
||||
maxHeight: '560px',
|
||||
maxHeight: '760px',
|
||||
marginTop: '64px',
|
||||
animation: `${keyframes`
|
||||
0% {
|
||||
@@ -137,6 +137,12 @@ const useStyles = makeStyles()(theme => {
|
||||
justifyContent: 'space-between'
|
||||
},
|
||||
|
||||
closeIcon: {
|
||||
'&:focus': {
|
||||
boxShadow: 'none'
|
||||
}
|
||||
},
|
||||
|
||||
title: {
|
||||
color: theme.palette.text01,
|
||||
...withPixelLineHeight(theme.typography.heading5),
|
||||
@@ -278,6 +284,7 @@ const Dialog = ({
|
||||
{!hideCloseButton && (
|
||||
<ClickableIcon
|
||||
accessibilityLabel = { t('dialog.close') }
|
||||
className = { classes.closeIcon }
|
||||
icon = { IconCloseLarge }
|
||||
id = 'modal-header-close-button'
|
||||
onClick = { onClose } />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @flow
|
||||
/* eslint-disable react/no-multi-comp */
|
||||
|
||||
import { useIsFocused } from '@react-navigation/native';
|
||||
import React, { useEffect } from 'react';
|
||||
@@ -6,7 +6,8 @@ import React, { useEffect } from 'react';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { closeChat } from '../../actions.any';
|
||||
import { TabBarLabelCounter } from '../../../mobile/navigation/components/TabBarLabelCounter';
|
||||
import { closeChat } from '../../actions.native';
|
||||
import AbstractChat, {
|
||||
type Props as AbstractProps,
|
||||
_mapStateToProps
|
||||
@@ -17,14 +18,8 @@ import MessageContainer from './MessageContainer';
|
||||
import MessageRecipient from './MessageRecipient';
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
type Props = AbstractProps & {
|
||||
|
||||
/**
|
||||
* Is this screen focused or not(React Navigation).
|
||||
*/
|
||||
isChatScreenFocused: boolean,
|
||||
|
||||
/**
|
||||
* Default prop for navigating between screen components(React Navigation).
|
||||
*/
|
||||
@@ -41,7 +36,6 @@ type Props = AbstractProps & {
|
||||
* the mobile client.
|
||||
*/
|
||||
class Chat extends AbstractChat<Props> {
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
@@ -49,7 +43,7 @@ class Chat extends AbstractChat<Props> {
|
||||
*/
|
||||
render() {
|
||||
const { _messages, route } = this.props;
|
||||
const privateMessageRecipient = route.params?.privateMessageRecipient;
|
||||
const privateMessageRecipient = route?.params?.privateMessageRecipient;
|
||||
|
||||
return (
|
||||
<JitsiScreen
|
||||
@@ -68,28 +62,26 @@ class Chat extends AbstractChat<Props> {
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(props => {
|
||||
const {
|
||||
_nbUnreadMessages,
|
||||
navigation,
|
||||
t
|
||||
} = props;
|
||||
const isChatScreenFocused = useIsFocused();
|
||||
const { _nbUnreadMessages, dispatch, navigation, t } = props;
|
||||
const unreadMessagesNr = _nbUnreadMessages > 0;
|
||||
|
||||
const nrUnreadMessages
|
||||
= !isChatScreenFocused && _nbUnreadMessages > 0
|
||||
? `(${_nbUnreadMessages})` : '';
|
||||
const isFocused = useIsFocused();
|
||||
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
tabBarLabel: `${t('chat.tabs.chat')} ${nrUnreadMessages}`
|
||||
navigation?.setOptions({
|
||||
tabBarLabel: () => (
|
||||
<TabBarLabelCounter
|
||||
activeUnreadNr = { unreadMessagesNr }
|
||||
isFocused = { isFocused }
|
||||
label = { t('chat.tabs.chat') }
|
||||
nbUnread = { _nbUnreadMessages } />
|
||||
)
|
||||
});
|
||||
|
||||
return () => props.dispatch(closeChat());
|
||||
}, [ nrUnreadMessages ]);
|
||||
return () => isFocused && dispatch(closeChat());
|
||||
}, [ isFocused, _nbUnreadMessages ]);
|
||||
|
||||
return (
|
||||
<Chat
|
||||
{ ...props }
|
||||
isChatScreenFocused = { isChatScreenFocused } />
|
||||
<Chat { ...props } />
|
||||
);
|
||||
}));
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import { CHAT_ENABLED, getFeatureFlag } from '../../../base/flags';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { IconChatUnread, IconMessage } from '../../../base/icons';
|
||||
@@ -10,9 +8,9 @@ import {
|
||||
} from '../../../base/toolbox/components';
|
||||
import { navigate } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
import { screen } from '../../../mobile/navigation/routes';
|
||||
import { getUnreadPollCount } from '../../../polls/functions';
|
||||
import { getUnreadCount } from '../../functions';
|
||||
|
||||
|
||||
type Props = AbstractButtonProps & {
|
||||
|
||||
/**
|
||||
@@ -72,7 +70,9 @@ function _mapStateToProps(state, ownProps) {
|
||||
|
||||
return {
|
||||
_isPollsDisabled: disablePolls,
|
||||
_unreadMessageCount: getUnreadCount(state),
|
||||
|
||||
// The toggled icon should also be available for new polls
|
||||
_unreadMessageCount: getUnreadCount(state) || getUnreadPollCount(state),
|
||||
visible
|
||||
};
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ class ChatInputBar extends Component<Props, State> {
|
||||
] }>
|
||||
<Input
|
||||
blurOnSubmit = { false }
|
||||
customStyles = {{ input: styles.customInput }}
|
||||
customStyles = {{ container: styles.customInputContainer }}
|
||||
multiline = { false }
|
||||
onBlur = { this._onFocused(false) }
|
||||
onChange = { this._onChangeText }
|
||||
|
||||
@@ -1,30 +1,19 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
|
||||
import { Avatar } from '../../../base/avatar';
|
||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { Linkify } from '../../../base/react';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { type StyleType } from '../../../base/styles';
|
||||
import { isGifMessage } from '../../../gifs/functions';
|
||||
import { MESSAGE_TYPE_ERROR, MESSAGE_TYPE_LOCAL } from '../../constants';
|
||||
import { replaceNonUnicodeEmojis } from '../../functions';
|
||||
import AbstractChatMessage, { type Props as AbstractProps } from '../AbstractChatMessage';
|
||||
import AbstractChatMessage, { type Props } from '../AbstractChatMessage';
|
||||
|
||||
import GifMessage from './GifMessage';
|
||||
import PrivateMessageButton from './PrivateMessageButton';
|
||||
import styles from './styles';
|
||||
|
||||
type Props = AbstractProps & {
|
||||
|
||||
/**
|
||||
* The color-schemed stylesheet of the feature.
|
||||
*/
|
||||
_styles: StyleType
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a single chat message.
|
||||
@@ -36,7 +25,7 @@ class ChatMessage extends AbstractChatMessage<Props> {
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
const { _styles, message, knocking } = this.props;
|
||||
const { message, knocking } = this.props;
|
||||
const localMessage = message.messageType === MESSAGE_TYPE_LOCAL;
|
||||
const { privateMessage, lobbyChat } = message;
|
||||
|
||||
@@ -56,7 +45,7 @@ class ChatMessage extends AbstractChatMessage<Props> {
|
||||
detailsWrapperStyle.push(styles.ownMessageDetailsWrapper);
|
||||
|
||||
// The bubble needs some additional styling
|
||||
messageBubbleStyle.push(_styles.localMessageBubble);
|
||||
messageBubbleStyle.push(styles.localMessageBubble);
|
||||
} else if (message.messageType === MESSAGE_TYPE_ERROR) {
|
||||
// This is a system message.
|
||||
|
||||
@@ -66,15 +55,15 @@ class ChatMessage extends AbstractChatMessage<Props> {
|
||||
// This is a remote message sent by a remote participant.
|
||||
|
||||
// The bubble needs some additional styling
|
||||
messageBubbleStyle.push(_styles.remoteMessageBubble);
|
||||
messageBubbleStyle.push(styles.remoteMessageBubble);
|
||||
}
|
||||
|
||||
if (privateMessage) {
|
||||
messageBubbleStyle.push(_styles.privateMessageBubble);
|
||||
messageBubbleStyle.push(styles.privateMessageBubble);
|
||||
}
|
||||
|
||||
if (lobbyChat && !knocking) {
|
||||
messageBubbleStyle.push(_styles.lobbyMessageBubble);
|
||||
messageBubbleStyle.push(styles.lobbyMessageBubble);
|
||||
}
|
||||
|
||||
const messageText = replaceNonUnicodeEmojis(this._getMessageText());
|
||||
@@ -86,11 +75,13 @@ class ChatMessage extends AbstractChatMessage<Props> {
|
||||
<View style = { messageBubbleStyle }>
|
||||
<View style = { styles.textWrapper } >
|
||||
{ this._renderDisplayName() }
|
||||
{isGifMessage(messageText)
|
||||
{ isGifMessage(messageText)
|
||||
? <GifMessage message = { messageText } />
|
||||
: (
|
||||
<Linkify linkStyle = { styles.chatLink }>
|
||||
{messageText}
|
||||
<Linkify
|
||||
linkStyle = { styles.chatLink }
|
||||
style = { styles.chatMessage }>
|
||||
{ messageText }
|
||||
</Linkify>
|
||||
)}
|
||||
{ this._renderPrivateNotice() }
|
||||
@@ -134,14 +125,14 @@ class ChatMessage extends AbstractChatMessage<Props> {
|
||||
* @returns {React$Element<*> | null}
|
||||
*/
|
||||
_renderDisplayName() {
|
||||
const { _styles, message, showDisplayName } = this.props;
|
||||
const { message, showDisplayName } = this.props;
|
||||
|
||||
if (!showDisplayName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Text style = { _styles.displayName }>
|
||||
<Text style = { styles.senderDisplayName }>
|
||||
{ message.displayName }
|
||||
</Text>
|
||||
);
|
||||
@@ -153,14 +144,14 @@ class ChatMessage extends AbstractChatMessage<Props> {
|
||||
* @returns {React$Element<*> | null}
|
||||
*/
|
||||
_renderPrivateNotice() {
|
||||
const { _styles, message, knocking } = this.props;
|
||||
const { message, knocking } = this.props;
|
||||
|
||||
if (!(message.privateMessage || (message.lobbyChat && !knocking))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Text style = { message.lobbyChat ? _styles.lobbyMsgNotice : _styles.privateNotice }>
|
||||
<Text style = { message.lobbyChat ? styles.lobbyMsgNotice : styles.privateNotice }>
|
||||
{ this._getPrivateNoticeMessage() }
|
||||
</Text>
|
||||
);
|
||||
@@ -172,7 +163,7 @@ class ChatMessage extends AbstractChatMessage<Props> {
|
||||
* @returns {React$Element<*> | null}
|
||||
*/
|
||||
_renderPrivateReplyButton() {
|
||||
const { _styles, message, knocking } = this.props;
|
||||
const { message, knocking } = this.props;
|
||||
const { messageType, privateMessage, lobbyChat } = message;
|
||||
|
||||
if (!(privateMessage || lobbyChat) || messageType === MESSAGE_TYPE_LOCAL || knocking) {
|
||||
@@ -180,13 +171,13 @@ class ChatMessage extends AbstractChatMessage<Props> {
|
||||
}
|
||||
|
||||
return (
|
||||
<View style = { _styles.replyContainer }>
|
||||
<View style = { styles.replyContainer }>
|
||||
<PrivateMessageButton
|
||||
isLobbyMessage = { lobbyChat }
|
||||
participantID = { message.id }
|
||||
reply = { true }
|
||||
showLabel = { false }
|
||||
toggledStyles = { _styles.replyStyles } />
|
||||
toggledStyles = { styles.replyStyles } />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -217,7 +208,6 @@ class ChatMessage extends AbstractChatMessage<Props> {
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
return {
|
||||
_styles: ColorSchemeRegistry.get(state, 'Chat'),
|
||||
knocking: state['features/lobby'].knocking
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import React, { Component, ReactElement } from 'react';
|
||||
import { FlatList } from 'react-native';
|
||||
|
||||
import { MESSAGE_TYPE_LOCAL, MESSAGE_TYPE_REMOTE } from '../../constants';
|
||||
@@ -60,7 +58,7 @@ export default class ChatMessageGroup extends Component<Props> {
|
||||
return `key_${index}`;
|
||||
}
|
||||
|
||||
_renderMessage: Object => React$Element<*>;
|
||||
_renderMessage: Object => ReactElement;
|
||||
|
||||
/**
|
||||
* Renders a single chat message.
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { ConfirmDialog } from '../../../base/dialog';
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import React, { ReactElement } from 'react';
|
||||
import { FlatList, Text, View } from 'react-native';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { StyleType } from '../../../base/styles';
|
||||
import AbstractMessageContainer, { type Props as AbstractProps }
|
||||
from '../AbstractMessageContainer';
|
||||
|
||||
@@ -15,11 +11,6 @@ import styles from './styles';
|
||||
|
||||
type Props = AbstractProps & {
|
||||
|
||||
/**
|
||||
* The color-schemed stylesheet of the feature.
|
||||
*/
|
||||
_styles: StyleType,
|
||||
|
||||
/**
|
||||
* Function to be used to translate i18n labels.
|
||||
*/
|
||||
@@ -82,7 +73,7 @@ class MessageContainer extends AbstractMessageContainer<Props> {
|
||||
return `key_${index}`;
|
||||
}
|
||||
|
||||
_renderListEmptyComponent: () => React$Element<any>;
|
||||
_renderListEmptyComponent: () => ReactElement;
|
||||
|
||||
/**
|
||||
* Renders a message when there are no messages in the chat yet.
|
||||
@@ -90,18 +81,18 @@ class MessageContainer extends AbstractMessageContainer<Props> {
|
||||
* @returns {React$Element<any>}
|
||||
*/
|
||||
_renderListEmptyComponent() {
|
||||
const { _styles, t } = this.props;
|
||||
const { t } = this.props;
|
||||
|
||||
return (
|
||||
<View style = { styles.emptyComponentWrapper }>
|
||||
<Text style = { _styles.emptyComponentText }>
|
||||
<Text style = { styles.emptyComponentText }>
|
||||
{ t('chat.noMessagesMessage') }
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_renderMessageGroup: Object => React$Element<any>;
|
||||
_renderMessageGroup: Object => ReactElement;
|
||||
|
||||
/**
|
||||
* Renders a single chat message.
|
||||
@@ -114,16 +105,4 @@ class MessageContainer extends AbstractMessageContainer<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps part of the redux state to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
return {
|
||||
_styles: ColorSchemeRegistry.get(state, 'Chat')
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(MessageContainer));
|
||||
export default translate(connect()(MessageContainer));
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Text, TouchableHighlight, View } from 'react-native';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { Icon, IconCloseCircle } from '../../../base/icons';
|
||||
import { Icon, IconCloseLarge } from '../../../base/icons';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { type StyleType } from '../../../base/styles';
|
||||
import {
|
||||
setParams
|
||||
} from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
@@ -16,14 +12,11 @@ import AbstractMessageRecipient, {
|
||||
type Props as AbstractProps
|
||||
} from '../AbstractMessageRecipient';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
type Props = AbstractProps & {
|
||||
|
||||
/**
|
||||
* The color-schemed stylesheet of the feature.
|
||||
*/
|
||||
_styles: StyleType,
|
||||
|
||||
/**
|
||||
* The Redux dispatch function.
|
||||
*/
|
||||
@@ -99,14 +92,17 @@ class MessageRecipient extends AbstractMessageRecipient<Props> {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { _styles, privateMessageRecipient, t,
|
||||
isLobbyChatActive, lobbyMessageRecipient } = this.props;
|
||||
|
||||
const {
|
||||
isLobbyChatActive,
|
||||
lobbyMessageRecipient,
|
||||
privateMessageRecipient,
|
||||
t
|
||||
} = this.props;
|
||||
|
||||
if (isLobbyChatActive) {
|
||||
return (
|
||||
<View style = { _styles.lobbyMessageRecipientContainer }>
|
||||
<Text style = { _styles.messageRecipientText }>
|
||||
<View style = { styles.lobbyMessageRecipientContainer }>
|
||||
<Text style = { styles.messageRecipientText }>
|
||||
{ t('chat.lobbyChatMessageTo', {
|
||||
recipient: lobbyMessageRecipient.name
|
||||
}) }
|
||||
@@ -114,8 +110,8 @@ class MessageRecipient extends AbstractMessageRecipient<Props> {
|
||||
<TouchableHighlight
|
||||
onPress = { this._onResetLobbyMessageRecipient }>
|
||||
<Icon
|
||||
src = { IconCloseCircle }
|
||||
style = { _styles.messageRecipientCancelIcon } />
|
||||
src = { IconCloseLarge }
|
||||
style = { styles.messageRecipientCancelIcon } />
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
);
|
||||
@@ -126,8 +122,8 @@ class MessageRecipient extends AbstractMessageRecipient<Props> {
|
||||
}
|
||||
|
||||
return (
|
||||
<View style = { _styles.messageRecipientContainer }>
|
||||
<Text style = { _styles.messageRecipientText }>
|
||||
<View style = { styles.messageRecipientContainer }>
|
||||
<Text style = { styles.messageRecipientText }>
|
||||
{ t('chat.messageTo', {
|
||||
recipient: privateMessageRecipient.name
|
||||
}) }
|
||||
@@ -136,8 +132,8 @@ class MessageRecipient extends AbstractMessageRecipient<Props> {
|
||||
onPress = { this._onResetPrivateMessageRecipient }
|
||||
underlayColor = { 'transparent' }>
|
||||
<Icon
|
||||
src = { IconCloseCircle }
|
||||
style = { _styles.messageRecipientCancelIcon } />
|
||||
src = { IconCloseLarge }
|
||||
style = { styles.messageRecipientCancelIcon } />
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
);
|
||||
@@ -154,7 +150,6 @@ function _mapStateToProps(state) {
|
||||
const { lobbyMessageRecipient, isLobbyChatActive } = state['features/chat'];
|
||||
|
||||
return {
|
||||
_styles: ColorSchemeRegistry.get(state, 'Chat'),
|
||||
isLobbyChatActive,
|
||||
lobbyMessageRecipient
|
||||
};
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import { CHAT_ENABLED, getFeatureFlag } from '../../../base/flags';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { IconMessage, IconReply } from '../../../base/icons';
|
||||
@@ -10,7 +8,6 @@ import { handleLobbyChatInitialized, openChat } from '../../../chat/actions';
|
||||
import { navigate } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
import { screen } from '../../../mobile/navigation/routes';
|
||||
|
||||
|
||||
export type Props = AbstractButtonProps & {
|
||||
|
||||
/**
|
||||
@@ -103,7 +100,7 @@ class PrivateMessageButton extends AbstractButton<Props, any> {
|
||||
* @param {Props} ownProps - The own props of the component.
|
||||
* @returns {Props}
|
||||
*/
|
||||
export function _mapStateToProps(state: Object, ownProps: Props): $Shape<Props> {
|
||||
export function _mapStateToProps(state: Object, ownProps: Props) {
|
||||
const enabled = getFeatureFlag(state, CHAT_ENABLED, true);
|
||||
const { disablePolls } = state['features/base/config'];
|
||||
const { visible = enabled, isLobbyMessage, participantID } = ownProps;
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
// @flow
|
||||
|
||||
import { ColorSchemeRegistry, schemeColor } from '../../../base/color-scheme';
|
||||
import { BoxModel, ColorPalette } from '../../../base/styles';
|
||||
import { BoxModel } from '../../../base/styles';
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
|
||||
const BUBBLE_RADIUS = 8;
|
||||
|
||||
const recipientContainer = {
|
||||
alignItems: 'center',
|
||||
backgroundColor: BaseTheme.palette.support05,
|
||||
borderRadius: BaseTheme.shape.borderRadius,
|
||||
flexDirection: 'row',
|
||||
height: 48,
|
||||
marginBottom: BaseTheme.spacing[3],
|
||||
marginHorizontal: BaseTheme.spacing[3],
|
||||
padding: BaseTheme.spacing[2]
|
||||
};
|
||||
|
||||
/**
|
||||
* The styles of the feature chat.
|
||||
*
|
||||
@@ -16,16 +24,72 @@ const BUBBLE_RADIUS = 8;
|
||||
*/
|
||||
export default {
|
||||
|
||||
/**
|
||||
* Background of the chat screen.
|
||||
*/
|
||||
backdrop: {
|
||||
backgroundColor: BaseTheme.palette.ui10,
|
||||
flex: 1
|
||||
},
|
||||
|
||||
emptyComponentText: {
|
||||
color: BaseTheme.palette.text03,
|
||||
textAlign: 'center'
|
||||
},
|
||||
|
||||
lobbyMessageBubble: {
|
||||
backgroundColor: BaseTheme.palette.support06
|
||||
},
|
||||
|
||||
lobbyMsgNotice: {
|
||||
color: BaseTheme.palette.text04,
|
||||
fontSize: 11,
|
||||
marginTop: 6
|
||||
},
|
||||
|
||||
privateNotice: {
|
||||
...BaseTheme.palette.bodyShortRegular,
|
||||
color: BaseTheme.palette.text02
|
||||
},
|
||||
|
||||
privateMessageBubble: {
|
||||
backgroundColor: BaseTheme.palette.support05
|
||||
},
|
||||
|
||||
remoteMessageBubble: {
|
||||
backgroundColor: BaseTheme.palette.ui02,
|
||||
borderTopLeftRadius: 0
|
||||
},
|
||||
|
||||
replyContainer: {
|
||||
alignSelf: 'stretch',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
|
||||
replyStyles: {
|
||||
iconStyle: {
|
||||
color: BaseTheme.palette.icon01,
|
||||
fontSize: 22,
|
||||
padding: BaseTheme.spacing[2]
|
||||
},
|
||||
underlayColor: 'transparent'
|
||||
},
|
||||
|
||||
/**
|
||||
* Wrapper View for the avatar.
|
||||
*/
|
||||
avatarWrapper: {
|
||||
marginRight: 8,
|
||||
marginRight: BaseTheme.spacing[2],
|
||||
width: 32
|
||||
},
|
||||
|
||||
chatLink: {
|
||||
color: ColorPalette.blue
|
||||
color: BaseTheme.palette.link01
|
||||
},
|
||||
|
||||
chatMessage: {
|
||||
...BaseTheme.typography.bodyShortRegular,
|
||||
color: BaseTheme.palette.text01
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -60,8 +124,8 @@ export default {
|
||||
width: '100%'
|
||||
},
|
||||
|
||||
customInput: {
|
||||
width: 280
|
||||
customInputContainer: {
|
||||
width: '75%'
|
||||
},
|
||||
|
||||
messageBubble: {
|
||||
@@ -117,7 +181,7 @@ export default {
|
||||
* Text node for the timestamp.
|
||||
*/
|
||||
timeText: {
|
||||
color: 'rgb(164, 184, 209)',
|
||||
color: BaseTheme.palette.text03,
|
||||
fontSize: 13
|
||||
},
|
||||
|
||||
@@ -154,97 +218,35 @@ export default {
|
||||
width: 250,
|
||||
height: undefined,
|
||||
flexGrow: 1
|
||||
}
|
||||
};
|
||||
|
||||
ColorSchemeRegistry.register('Chat', {
|
||||
/**
|
||||
* Background of the chat screen.
|
||||
*/
|
||||
backdrop: {
|
||||
backgroundColor: schemeColor('background'),
|
||||
flex: 1
|
||||
},
|
||||
|
||||
/**
|
||||
* The text node for the display name.
|
||||
*/
|
||||
displayName: {
|
||||
color: schemeColor('displayName'),
|
||||
fontSize: 13
|
||||
},
|
||||
|
||||
emptyComponentText: {
|
||||
color: BaseTheme.palette.text03,
|
||||
textAlign: 'center'
|
||||
},
|
||||
|
||||
lobbyMessageBubble: {
|
||||
backgroundColor: schemeColor('lobbyMsgBackground')
|
||||
},
|
||||
|
||||
lobbyMsgNotice: {
|
||||
color: schemeColor('lobbyMsgNotice'),
|
||||
fontSize: 11,
|
||||
marginTop: 6
|
||||
},
|
||||
|
||||
lobbyMessageRecipientContainer: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: schemeColor('lobbyMsgBackground'),
|
||||
flexDirection: 'row',
|
||||
padding: BoxModel.padding
|
||||
senderDisplayName: {
|
||||
...BaseTheme.typography.bodyShortBold,
|
||||
color: BaseTheme.palette.text02
|
||||
},
|
||||
|
||||
localMessageBubble: {
|
||||
backgroundColor: schemeColor('localMsgBackground'),
|
||||
backgroundColor: BaseTheme.palette.ui04,
|
||||
borderTopRightRadius: 0
|
||||
},
|
||||
|
||||
lobbyMessageRecipientContainer: {
|
||||
...recipientContainer,
|
||||
backgroundColor: BaseTheme.palette.support06
|
||||
},
|
||||
|
||||
messageRecipientCancelIcon: {
|
||||
color: schemeColor('icon'),
|
||||
color: BaseTheme.palette.icon01,
|
||||
fontSize: 18
|
||||
},
|
||||
|
||||
messageRecipientContainer: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: schemeColor('privateMsgBackground'),
|
||||
flexDirection: 'row',
|
||||
padding: BoxModel.padding
|
||||
...recipientContainer
|
||||
},
|
||||
|
||||
messageRecipientText: {
|
||||
color: schemeColor('text'),
|
||||
...BaseTheme.typography.bodyShortRegular,
|
||||
color: BaseTheme.palette.text01,
|
||||
flex: 1
|
||||
},
|
||||
|
||||
privateNotice: {
|
||||
color: schemeColor('privateMsgNotice'),
|
||||
fontSize: 11,
|
||||
marginTop: 6
|
||||
},
|
||||
|
||||
privateMessageBubble: {
|
||||
backgroundColor: schemeColor('privateMsgBackground')
|
||||
},
|
||||
|
||||
remoteMessageBubble: {
|
||||
backgroundColor: schemeColor('remoteMsgBackground'),
|
||||
borderTopLeftRadius: 0
|
||||
},
|
||||
|
||||
replyContainer: {
|
||||
alignSelf: 'stretch',
|
||||
borderLeftColor: schemeColor('replyBorder'),
|
||||
borderLeftWidth: 1,
|
||||
justifyContent: 'center'
|
||||
},
|
||||
|
||||
replyStyles: {
|
||||
iconStyle: {
|
||||
color: schemeColor('replyIcon'),
|
||||
fontSize: 22,
|
||||
padding: 8
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { TouchableOpacity, View } from 'react-native';
|
||||
|
||||
|
||||
@@ -100,7 +100,6 @@ class LonelyMeetingExperience extends PureComponent<Props> {
|
||||
icon = { this._renderAddPeopleIcon }
|
||||
labelKey = 'lonelyMeetingExperience.button'
|
||||
onClick = { this._onPress }
|
||||
style = { styles.lonelyButton }
|
||||
type = { BUTTON_TYPES.PRIMARY } />
|
||||
) }
|
||||
</View>
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { IconRaiseHand } from '../../../base/icons';
|
||||
import { Label } from '../../../base/label';
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme';
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
@@ -66,14 +66,13 @@ const TitleBar = (props: IProps): JSX.Element => {
|
||||
<RecordingLabel mode = { JitsiRecordingConstants.mode.FILE } />
|
||||
<RecordingLabel mode = { JitsiRecordingConstants.mode.STREAM } />
|
||||
</View>
|
||||
|
||||
{
|
||||
props._meetingNameEnabled
|
||||
&& <View style = { styles.roomNameView as StyleProp<ViewStyle> }>
|
||||
<Text
|
||||
numberOfLines = { 1 }
|
||||
style = { styles.roomName }>
|
||||
{props._meetingName}
|
||||
{ props._meetingName }
|
||||
</Text>
|
||||
</View>
|
||||
}
|
||||
|
||||
@@ -71,8 +71,7 @@ export default {
|
||||
},
|
||||
|
||||
qualityLabelContainer: {
|
||||
borderBottomLeftRadius: 3,
|
||||
borderTopLeftRadius: 3,
|
||||
borderRadius: BaseTheme.shape.borderRadius,
|
||||
flexShrink: 1,
|
||||
paddingHorizontal: 2,
|
||||
justifyContent: 'center',
|
||||
|
||||
@@ -4,7 +4,6 @@ import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
export const INSECURE_ROOM_NAME_LABEL_COLOR = BaseTheme.palette.actionDanger;
|
||||
|
||||
const TITLE_BAR_BUTTON_SIZE = 24;
|
||||
const HEADER_ACTION_BUTTON_SIZE = 17;
|
||||
|
||||
|
||||
/**
|
||||
@@ -35,29 +34,6 @@ export default {
|
||||
margin: 10
|
||||
},
|
||||
|
||||
headerNavigationButton: {
|
||||
height: BaseTheme.spacing[6],
|
||||
marginTop: 20,
|
||||
width: BaseTheme.spacing[6]
|
||||
},
|
||||
|
||||
headerNavigationIcon: {
|
||||
marginLeft: 12
|
||||
},
|
||||
|
||||
headerNavigationText: {
|
||||
color: BaseTheme.palette.text01,
|
||||
marginLeft: BaseTheme.spacing[3],
|
||||
fontSize: HEADER_ACTION_BUTTON_SIZE
|
||||
},
|
||||
|
||||
headerNavigationTextBold: {
|
||||
...BaseTheme.typography.labelButton,
|
||||
color: BaseTheme.palette.text01,
|
||||
marginRight: BaseTheme.spacing[3],
|
||||
fontSize: HEADER_ACTION_BUTTON_SIZE
|
||||
},
|
||||
|
||||
/**
|
||||
* View that contains the indicators.
|
||||
*/
|
||||
@@ -84,10 +60,6 @@ export default {
|
||||
underlayColor: 'transparent'
|
||||
},
|
||||
|
||||
lonelyButton: {
|
||||
borderRadius: BaseTheme.spacing[4]
|
||||
},
|
||||
|
||||
lonelyMeetingContainer: {
|
||||
alignSelf: 'stretch',
|
||||
alignItems: 'center',
|
||||
@@ -157,8 +129,8 @@ export default {
|
||||
},
|
||||
|
||||
roomTimer: {
|
||||
color: BaseTheme.palette.text01,
|
||||
...BaseTheme.typography.bodyShortBold,
|
||||
color: BaseTheme.palette.text01,
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 6,
|
||||
textAlign: 'center'
|
||||
@@ -166,8 +138,9 @@ export default {
|
||||
|
||||
roomTimerView: {
|
||||
backgroundColor: BaseTheme.palette.ui03,
|
||||
borderRadius: 3,
|
||||
borderRadius: BaseTheme.shape.borderRadius,
|
||||
justifyContent: 'center',
|
||||
minHeight: 32,
|
||||
minWidth: 50
|
||||
},
|
||||
|
||||
@@ -210,16 +183,18 @@ export default {
|
||||
},
|
||||
|
||||
insecureRoomNameLabel: {
|
||||
backgroundColor: INSECURE_ROOM_NAME_LABEL_COLOR
|
||||
backgroundColor: INSECURE_ROOM_NAME_LABEL_COLOR,
|
||||
borderRadius: BaseTheme.shape.borderRadius,
|
||||
height: 32
|
||||
},
|
||||
|
||||
raisedHandsCountLabel: {
|
||||
backgroundColor: BaseTheme.palette.warning02,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: BaseTheme.palette.warning02,
|
||||
borderRadius: BaseTheme.shape.borderRadius,
|
||||
flexDirection: 'row',
|
||||
marginLeft: BaseTheme.spacing[0],
|
||||
marginBottom: BaseTheme.spacing[0],
|
||||
marginRight: BaseTheme.spacing[1]
|
||||
marginBottom: BaseTheme.spacing[0]
|
||||
},
|
||||
|
||||
raisedHandsCountLabelText: {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { getJitsiMeetTransport } from '../../../modules/transport';
|
||||
import {
|
||||
CONFERENCE_FAILED,
|
||||
CONFERENCE_JOINED,
|
||||
DATA_CHANNEL_CLOSED,
|
||||
DATA_CHANNEL_OPENED,
|
||||
KICKED_OUT
|
||||
} from '../base/conference/actionTypes';
|
||||
@@ -124,6 +125,10 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
break;
|
||||
}
|
||||
|
||||
case DATA_CHANNEL_CLOSED:
|
||||
APP.API.notifyDataChannelClosed(action.code, action.reason);
|
||||
break;
|
||||
|
||||
case DATA_CHANNEL_OPENED:
|
||||
APP.API.notifyDataChannelOpened();
|
||||
break;
|
||||
|
||||
@@ -5,20 +5,21 @@ import { getLocalVideoTrack } from '../base/tracks/functions';
|
||||
import { getBaseUrl } from '../base/util/helpers';
|
||||
|
||||
import {
|
||||
addFaceExpression,
|
||||
addFaceLandmarks,
|
||||
clearFaceExpressionBuffer,
|
||||
newFaceBox
|
||||
} from './actions';
|
||||
import {
|
||||
DETECTION_TYPES,
|
||||
DETECT_FACE,
|
||||
FACE_LANDMARK_DETECTION_ERROR_THRESHOLD,
|
||||
FACE_LANDMARKS_DETECTION_ERROR_THRESHOLD,
|
||||
INIT_WORKER,
|
||||
NO_DETECTION,
|
||||
NO_FACE_DETECTION_THRESHOLD,
|
||||
WEBHOOK_SEND_TIME_INTERVAL
|
||||
} from './constants';
|
||||
import {
|
||||
getDetectionInterval,
|
||||
getFaceExpressionDuration,
|
||||
sendFaceExpressionsWebhook
|
||||
} from './functions';
|
||||
import logger from './logger';
|
||||
@@ -33,13 +34,14 @@ class FaceLandmarksDetector {
|
||||
private worker: Worker | null = null;
|
||||
private lastFaceExpression: string | null = null;
|
||||
private lastFaceExpressionTimestamp: number | null = null;
|
||||
private duplicateConsecutiveExpressions = 0;
|
||||
private webhookSendInterval: number | null = null;
|
||||
private detectionInterval: number | null = null;
|
||||
private recognitionActive = false;
|
||||
private canvas?: HTMLCanvasElement;
|
||||
private context?: CanvasRenderingContext2D | null;
|
||||
private errorCount = 0;
|
||||
private noDetectionCount = 0;
|
||||
private noDetectionStartTimestamp: number | null = null;
|
||||
|
||||
/**
|
||||
* Constructor for class, checks if the environment supports OffscreenCanvas.
|
||||
@@ -97,27 +99,48 @@ class FaceLandmarksDetector {
|
||||
|
||||
// @ts-ignore
|
||||
const workerBlob = new Blob([ `importScripts("${workerUrl}");` ], { type: 'application/javascript' });
|
||||
const state = getState();
|
||||
const addToBuffer = Boolean(state['features/base/config'].webhookProxyUrl);
|
||||
|
||||
// @ts-ignore
|
||||
workerUrl = window.URL.createObjectURL(workerBlob);
|
||||
this.worker = new Worker(workerUrl, { name: 'Face Recognition Worker' });
|
||||
this.worker = new Worker(workerUrl, { name: 'Face Landmarks Worker' });
|
||||
this.worker.onmessage = ({ data }: MessageEvent<any>) => {
|
||||
const { faceExpression, faceBox } = data;
|
||||
const { faceExpression, faceBox, faceCount } = data;
|
||||
const messageTimestamp = Date.now();
|
||||
|
||||
if (faceExpression) {
|
||||
if (faceExpression === this.lastFaceExpression) {
|
||||
this.duplicateConsecutiveExpressions++;
|
||||
} else {
|
||||
if (this.lastFaceExpression && this.lastFaceExpressionTimestamp) {
|
||||
dispatch(addFaceExpression(
|
||||
this.lastFaceExpression,
|
||||
getFaceExpressionDuration(getState(), this.duplicateConsecutiveExpressions + 1),
|
||||
this.lastFaceExpressionTimestamp
|
||||
));
|
||||
}
|
||||
this.lastFaceExpression = faceExpression;
|
||||
this.lastFaceExpressionTimestamp = Date.now();
|
||||
this.duplicateConsecutiveExpressions = 0;
|
||||
// if the number of faces detected is different from 1 we do not take into consideration that detection
|
||||
if (faceCount !== 1) {
|
||||
if (this.noDetectionCount === 0) {
|
||||
this.noDetectionStartTimestamp = messageTimestamp;
|
||||
}
|
||||
this.noDetectionCount++;
|
||||
|
||||
if (this.noDetectionCount === NO_FACE_DETECTION_THRESHOLD && this.noDetectionStartTimestamp) {
|
||||
this.addFaceLandmarks(
|
||||
dispatch,
|
||||
this.noDetectionStartTimestamp,
|
||||
NO_DETECTION,
|
||||
addToBuffer
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (this.noDetectionCount > 0) {
|
||||
this.noDetectionCount = 0;
|
||||
this.noDetectionStartTimestamp = null;
|
||||
}
|
||||
|
||||
if (faceExpression?.expression) {
|
||||
const { expression } = faceExpression;
|
||||
|
||||
if (expression !== this.lastFaceExpression) {
|
||||
this.addFaceLandmarks(
|
||||
dispatch,
|
||||
messageTimestamp,
|
||||
expression,
|
||||
addToBuffer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +151,7 @@ class FaceLandmarksDetector {
|
||||
APP.API.notifyFaceLandmarkDetected(faceBox, faceExpression);
|
||||
};
|
||||
|
||||
const { faceLandmarks } = getState()['features/base/config'];
|
||||
const { faceLandmarks } = state['features/base/config'];
|
||||
const detectionTypes = [
|
||||
faceLandmarks?.enableFaceCentering && DETECTION_TYPES.FACE_BOX,
|
||||
faceLandmarks?.enableFaceExpressionsDetection && DETECTION_TYPES.FACE_EXPRESSIONS
|
||||
@@ -162,7 +185,7 @@ class FaceLandmarksDetector {
|
||||
}
|
||||
|
||||
if (this.recognitionActive) {
|
||||
logger.log('Face detection already active.');
|
||||
logger.log('Face landmarks detection already active.');
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -179,7 +202,7 @@ class FaceLandmarksDetector {
|
||||
|
||||
this.imageCapture = new ImageCapture(firstVideoTrack);
|
||||
this.recognitionActive = true;
|
||||
logger.log('Start face detection');
|
||||
logger.log('Start face landmarks detection');
|
||||
|
||||
const { faceLandmarks } = state['features/base/config'];
|
||||
|
||||
@@ -191,7 +214,7 @@ class FaceLandmarksDetector {
|
||||
).then(status => {
|
||||
if (status) {
|
||||
this.errorCount = 0;
|
||||
} else if (++this.errorCount > FACE_LANDMARK_DETECTION_ERROR_THRESHOLD) {
|
||||
} else if (++this.errorCount > FACE_LANDMARKS_DETECTION_ERROR_THRESHOLD) {
|
||||
/* this prevents the detection from stopping immediately after occurring an error
|
||||
* sometimes due to the small detection interval when starting the detection some errors
|
||||
* might occur due to the track not being ready
|
||||
@@ -228,18 +251,11 @@ class FaceLandmarksDetector {
|
||||
if (!this.recognitionActive || !this.isInitialized()) {
|
||||
return;
|
||||
}
|
||||
const stopTimestamp = Date.now();
|
||||
const addToBuffer = Boolean(getState()['features/base/config'].webhookProxyUrl);
|
||||
|
||||
if (this.lastFaceExpression && this.lastFaceExpressionTimestamp) {
|
||||
dispatch(
|
||||
addFaceExpression(
|
||||
this.lastFaceExpression,
|
||||
getFaceExpressionDuration(getState(), this.duplicateConsecutiveExpressions + 1),
|
||||
this.lastFaceExpressionTimestamp
|
||||
)
|
||||
);
|
||||
this.duplicateConsecutiveExpressions = 0;
|
||||
this.lastFaceExpression = null;
|
||||
this.lastFaceExpressionTimestamp = null;
|
||||
this.addFaceLandmarks(dispatch, stopTimestamp, null, addToBuffer);
|
||||
}
|
||||
|
||||
this.webhookSendInterval && window.clearInterval(this.webhookSendInterval);
|
||||
@@ -248,7 +264,36 @@ class FaceLandmarksDetector {
|
||||
this.detectionInterval = null;
|
||||
this.imageCapture = null;
|
||||
this.recognitionActive = false;
|
||||
logger.log('Stop face detection');
|
||||
logger.log('Stop face landmarks detection');
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the action for adding new face landmarks and changes the state of the class.
|
||||
*
|
||||
* @param {IStore.dispatch} dispatch - The redux dispatch function.
|
||||
* @param {number} endTimestamp - The timestamp when the face landmarks ended.
|
||||
* @param {string} newFaceExpression - The new face expression.
|
||||
* @param {boolean} addToBuffer - Flag for adding the face landmarks to the buffer.
|
||||
* @returns {void}
|
||||
*/
|
||||
private addFaceLandmarks(
|
||||
dispatch: IStore['dispatch'],
|
||||
endTimestamp: number,
|
||||
newFaceExpression: string | null,
|
||||
addToBuffer = false) {
|
||||
if (this.lastFaceExpression && this.lastFaceExpressionTimestamp) {
|
||||
dispatch(addFaceLandmarks(
|
||||
{
|
||||
duration: endTimestamp - this.lastFaceExpressionTimestamp,
|
||||
faceExpression: this.lastFaceExpression,
|
||||
timestamp: this.lastFaceExpressionTimestamp
|
||||
},
|
||||
addToBuffer
|
||||
));
|
||||
}
|
||||
|
||||
this.lastFaceExpression = newFaceExpression;
|
||||
this.lastFaceExpressionTimestamp = endTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,7 +2,7 @@ import { setWasmPaths } from '@tensorflow/tfjs-backend-wasm';
|
||||
import { Config, FaceResult, Human } from '@vladmandic/human';
|
||||
|
||||
import { DETECTION_TYPES, FACE_DETECTION_SCORE_THRESHOLD, FACE_EXPRESSIONS_NAMING_MAPPING } from './constants';
|
||||
import { DetectInput, DetectOutput, FaceBox, InitInput } from './types';
|
||||
import { DetectInput, DetectOutput, FaceBox, FaceExpression, InitInput } from './types';
|
||||
|
||||
export interface IFaceLandmarksHelper {
|
||||
detect: ({ image, threshold }: DetectInput) => Promise<DetectOutput>;
|
||||
@@ -10,7 +10,7 @@ export interface IFaceLandmarksHelper {
|
||||
getDetections: (image: ImageBitmap | ImageData) => Promise<Array<FaceResult>>;
|
||||
getFaceBox: (detections: Array<FaceResult>, threshold: number) => FaceBox | undefined;
|
||||
getFaceCount: (detections: Array<FaceResult>) => number;
|
||||
getFaceExpression: (detections: Array<FaceResult>) => string | undefined;
|
||||
getFaceExpression: (detections: Array<FaceResult>) => FaceExpression | undefined;
|
||||
init: () => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -144,13 +144,18 @@ export class HumanHelper implements IFaceLandmarksHelper {
|
||||
* @param {Array<FaceResult>} detections - The array with the detections.
|
||||
* @returns {string | undefined}
|
||||
*/
|
||||
getFaceExpression(detections: Array<FaceResult>): string | undefined {
|
||||
getFaceExpression(detections: Array<FaceResult>): FaceExpression | undefined {
|
||||
if (this.getFaceCount(detections) !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (detections[0].emotion) {
|
||||
return FACE_EXPRESSIONS_NAMING_MAPPING[detections[0].emotion[0].emotion];
|
||||
const detection = detections[0];
|
||||
|
||||
if (detection.emotion) {
|
||||
return {
|
||||
expression: FACE_EXPRESSIONS_NAMING_MAPPING[detection.emotion[0].emotion],
|
||||
score: detection.emotion[0].score
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,32 +1,21 @@
|
||||
/**
|
||||
* Redux action type dispatched in order to add a face expression.
|
||||
* Redux action type dispatched in order to add real-time faceLandmarks to timeline.
|
||||
*
|
||||
* {
|
||||
* type: ADD_FACE_EXPRESSION,
|
||||
* faceExpression: string,
|
||||
* duration: number
|
||||
* type: ADD_FACE_LANDMARKS,
|
||||
* faceLandmarks: FaceLandmarks
|
||||
* }
|
||||
*/
|
||||
export const ADD_FACE_EXPRESSION = 'ADD_FACE_EXPRESSION';
|
||||
export const ADD_FACE_LANDMARKS = 'ADD_FACE_LANDMARKS';
|
||||
|
||||
/**
|
||||
* Redux action type dispatched in order to add a expression to the face expressions buffer.
|
||||
* Redux action type dispatched in order to clear the faceLandmarks buffer for webhook in the state.
|
||||
*
|
||||
* {
|
||||
* type: ADD_TO_FACE_EXPRESSIONS_BUFFER,
|
||||
* faceExpression: string
|
||||
* type: CLEAR_FACE_LANDMARKS_BUFFER
|
||||
* }
|
||||
*/
|
||||
export const ADD_TO_FACE_EXPRESSIONS_BUFFER = 'ADD_TO_FACE_EXPRESSIONS_BUFFER';
|
||||
|
||||
/**
|
||||
* Redux action type dispatched in order to clear the face expressions buffer in the state.
|
||||
*
|
||||
* {
|
||||
* type: CLEAR_FACE_EXPRESSIONS_BUFFER
|
||||
* }
|
||||
*/
|
||||
export const CLEAR_FACE_EXPRESSIONS_BUFFER = 'CLEAR_FACE_EXPRESSIONS_BUFFER';
|
||||
export const CLEAR_FACE_LANDMARKS_BUFFER = 'CLEAR_FACE_LANDMARKS_BUFFER';
|
||||
|
||||
/**
|
||||
* Redux action type dispatched in order to update coordinates of a detected face.
|
||||
|
||||
@@ -3,56 +3,35 @@ import './createImageBitmap';
|
||||
import { AnyAction } from 'redux';
|
||||
|
||||
import {
|
||||
ADD_FACE_EXPRESSION,
|
||||
ADD_TO_FACE_EXPRESSIONS_BUFFER,
|
||||
CLEAR_FACE_EXPRESSIONS_BUFFER,
|
||||
ADD_FACE_LANDMARKS,
|
||||
CLEAR_FACE_LANDMARKS_BUFFER,
|
||||
NEW_FACE_COORDINATES
|
||||
} from './actionTypes';
|
||||
import { FaceBox } from './types';
|
||||
import { FaceBox, FaceLandmarks } from './types';
|
||||
|
||||
/**
|
||||
* Adds a new face expression and its duration.
|
||||
* Adds new face landmarks to the timeline.
|
||||
*
|
||||
* @param {string} faceExpression - Face expression to be added.
|
||||
* @param {number} duration - Duration in seconds of the face expression.
|
||||
* @param {number} timestamp - Duration in seconds of the face expression.
|
||||
* @param {FaceLandmarks} faceLandmarks - The new face landmarks to timeline.
|
||||
* @param {boolean} addToBuffer - If true adds the face landmarks to a buffer in the reducer for webhook.
|
||||
* @returns {AnyAction}
|
||||
*/
|
||||
export function addFaceExpression(faceExpression: string, duration: number, timestamp: number): AnyAction {
|
||||
export function addFaceLandmarks(faceLandmarks: FaceLandmarks, addToBuffer: boolean): AnyAction {
|
||||
return {
|
||||
type: ADD_FACE_EXPRESSION,
|
||||
faceExpression,
|
||||
duration,
|
||||
timestamp
|
||||
type: ADD_FACE_LANDMARKS,
|
||||
faceLandmarks,
|
||||
addToBuffer
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a face expression with its timestamp to the face expression buffer.
|
||||
* Clears the face landmarks array in the state.
|
||||
*
|
||||
* @param {Object} faceExpression - Object containing face expression string and its timestamp.
|
||||
* @returns {AnyAction}
|
||||
*/
|
||||
export function addToFaceExpressionsBuffer(
|
||||
faceExpression: {
|
||||
emotion: string;
|
||||
timestamp: number;
|
||||
}
|
||||
): AnyAction {
|
||||
export function clearFaceExpressionBuffer(): AnyAction {
|
||||
return {
|
||||
type: ADD_TO_FACE_EXPRESSIONS_BUFFER,
|
||||
faceExpression
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the face expressions array in the state.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function clearFaceExpressionBuffer() {
|
||||
return {
|
||||
type: CLEAR_FACE_EXPRESSIONS_BUFFER
|
||||
type: CLEAR_FACE_LANDMARKS_BUFFER
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,11 @@ export const INIT_WORKER = 'INIT_WORKER';
|
||||
*/
|
||||
export const FACE_BOX_EVENT_TYPE = 'face-box';
|
||||
|
||||
/**
|
||||
* Type of event sent on the data channel.
|
||||
*/
|
||||
export const FACE_LANDMARKS_EVENT_TYPE = 'face-landmarks';
|
||||
|
||||
/**
|
||||
* Milliseconds interval value for sending new image data to the worker.
|
||||
*/
|
||||
@@ -64,4 +69,15 @@ export const FACE_DETECTION_SCORE_THRESHOLD = 0.75;
|
||||
/**
|
||||
* Threshold for stopping detection after a certain number of consecutive errors have occurred.
|
||||
*/
|
||||
export const FACE_LANDMARK_DETECTION_ERROR_THRESHOLD = 4;
|
||||
export const FACE_LANDMARKS_DETECTION_ERROR_THRESHOLD = 4;
|
||||
|
||||
/**
|
||||
* Threshold for number of consecutive detections with no face,
|
||||
* so that when achieved there will be dispatched an action.
|
||||
*/
|
||||
export const NO_FACE_DETECTION_THRESHOLD = 5;
|
||||
|
||||
/**
|
||||
* Constant type used for signaling that no valid face detection is found.
|
||||
*/
|
||||
export const NO_DETECTION = 'no-detection';
|
||||
|
||||
@@ -12,10 +12,9 @@ onmessage = async function({ data }: MessageEvent<any>) {
|
||||
|
||||
const detections = await helper.detect(data);
|
||||
|
||||
if (detections && (detections.faceBox || detections.faceExpression || detections.faceCount)) {
|
||||
if (detections) {
|
||||
self.postMessage(detections);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +1,27 @@
|
||||
import { IReduxState } from '../app/types';
|
||||
import { IJitsiConference } from '../base/conference/reducer';
|
||||
import { getLocalParticipant } from '../base/participants/functions';
|
||||
import { extractFqnFromPath } from '../dynamic-branding/functions.any';
|
||||
|
||||
import { DETECT_FACE, FACE_BOX_EVENT_TYPE, SEND_IMAGE_INTERVAL_MS } from './constants';
|
||||
import { FACE_BOX_EVENT_TYPE, FACE_LANDMARKS_EVENT_TYPE, SEND_IMAGE_INTERVAL_MS } from './constants';
|
||||
import logger from './logger';
|
||||
import { FaceBox } from './types';
|
||||
|
||||
let canvas: HTMLCanvasElement;
|
||||
let context: CanvasRenderingContext2D | null;
|
||||
|
||||
if (typeof OffscreenCanvas === 'undefined') {
|
||||
canvas = document.createElement('canvas');
|
||||
context = canvas.getContext('2d');
|
||||
}
|
||||
import { FaceBox, FaceLandmarks } from './types';
|
||||
|
||||
/**
|
||||
* Sends the face expression with its duration to all the other participants.
|
||||
* Sends the face landmarks to other participants via the data channel.
|
||||
*
|
||||
* @param {any} conference - The current conference.
|
||||
* @param {string} faceExpression - Face expression to be sent.
|
||||
* @param {number} duration - The duration of the face expression in seconds.
|
||||
* @param {FaceLandmarks} faceLandmarks - Face landmarks to be sent.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function sendFaceExpressionToParticipants(
|
||||
conference: any,
|
||||
faceExpression: string,
|
||||
duration: number
|
||||
): void {
|
||||
export function sendFaceExpressionToParticipants(conference: any, faceLandmarks: FaceLandmarks): void {
|
||||
try {
|
||||
conference.sendEndpointMessage('', {
|
||||
type: 'face_landmark',
|
||||
faceExpression,
|
||||
duration
|
||||
type: FACE_LANDMARKS_EVENT_TYPE,
|
||||
faceLandmarks
|
||||
});
|
||||
} catch (err) {
|
||||
logger.warn('Could not broadcast the face expression to the other participants', err);
|
||||
logger.warn('Could not broadcast the face landmarks to the other participants', err);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -61,30 +48,22 @@ export function sendFaceBoxToParticipants(
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the face expression with its duration to xmpp server.
|
||||
* Sends the face landmarks to prosody.
|
||||
*
|
||||
* @param {any} conference - The current conference.
|
||||
* @param {string} faceExpression - Face expression to be sent.
|
||||
* @param {number} duration - The duration of the face expression in seconds.
|
||||
* @param {FaceLandmarks} faceLandmarks - Face landmarks to be sent.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function sendFaceExpressionToServer(
|
||||
conference: any,
|
||||
faceExpression: string,
|
||||
duration: number
|
||||
): void {
|
||||
export function sendFaceExpressionToServer(conference: IJitsiConference, faceLandmarks: FaceLandmarks): void {
|
||||
try {
|
||||
conference.sendFaceLandmarks({
|
||||
faceExpression,
|
||||
duration
|
||||
});
|
||||
conference.sendFaceLandmarks(faceLandmarks);
|
||||
} catch (err) {
|
||||
logger.warn('Could not send the face expression to xmpp server', err);
|
||||
logger.warn('Could not send the face landmarks to prosody', err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends face expression to backend.
|
||||
* Sends face landmarks to backend.
|
||||
*
|
||||
* @param {Object} state - Redux state.
|
||||
* @returns {boolean} - True if sent, false otherwise.
|
||||
@@ -96,9 +75,9 @@ export async function sendFaceExpressionsWebhook(state: IReduxState) {
|
||||
const { connection } = state['features/base/connection'];
|
||||
const jid = connection?.getJid();
|
||||
const localParticipant = getLocalParticipant(state);
|
||||
const { faceExpressionsBuffer } = state['features/face-landmarks'];
|
||||
const { faceLandmarksBuffer } = state['features/face-landmarks'];
|
||||
|
||||
if (faceExpressionsBuffer.length === 0) {
|
||||
if (faceLandmarksBuffer.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -111,7 +90,7 @@ export async function sendFaceExpressionsWebhook(state: IReduxState) {
|
||||
meetingFqn: extractFqnFromPath(),
|
||||
sessionId: conference?.sessionId,
|
||||
submitted: Date.now(),
|
||||
emotions: faceExpressionsBuffer,
|
||||
emotions: faceLandmarksBuffer,
|
||||
participantId: localParticipant?.jwtId,
|
||||
participantName: localParticipant?.name,
|
||||
participantJid: jid
|
||||
@@ -138,55 +117,6 @@ export async function sendFaceExpressionsWebhook(state: IReduxState) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sends the image data a canvas from the track in the image capture to the face recognition worker.
|
||||
*
|
||||
* @param {Worker} worker - Face recognition worker.
|
||||
* @param {Object} imageCapture - Image capture that contains the current track.
|
||||
* @param {number} threshold - Movement threshold as percentage for sharing face coordinates.
|
||||
* @returns {Promise<boolean>} - True if sent, false otherwise.
|
||||
*/
|
||||
export async function sendDataToWorker(
|
||||
worker: Worker,
|
||||
imageCapture: ImageCapture,
|
||||
threshold = 10
|
||||
): Promise<boolean> {
|
||||
if (imageCapture === null || imageCapture === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let imageBitmap;
|
||||
let image;
|
||||
|
||||
try {
|
||||
imageBitmap = await imageCapture.grabFrame();
|
||||
} catch (err) {
|
||||
logger.warn(err);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof OffscreenCanvas === 'undefined') {
|
||||
canvas.width = imageBitmap.width;
|
||||
canvas.height = imageBitmap.height;
|
||||
context?.drawImage(imageBitmap, 0, 0);
|
||||
|
||||
image = context?.getImageData(0, 0, imageBitmap.width, imageBitmap.height);
|
||||
} else {
|
||||
image = imageBitmap;
|
||||
}
|
||||
|
||||
worker.postMessage({
|
||||
type: DETECT_FACE,
|
||||
image,
|
||||
threshold
|
||||
});
|
||||
|
||||
imageBitmap.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets face box for a participant id.
|
||||
*
|
||||
@@ -230,14 +160,3 @@ export function getDetectionInterval(state: IReduxState) {
|
||||
|
||||
return Math.max(faceLandmarks?.captureInterval || SEND_IMAGE_INTERVAL_MS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration in seconds of a face expression.
|
||||
*
|
||||
* @param {IReduxState} state - The redux state.
|
||||
* @param {number} faceExpressionCount - The number of consecutive face expressions.
|
||||
* @returns {number} - Duration of face expression in seconds.
|
||||
*/
|
||||
export function getFaceExpressionDuration(state: IReduxState, faceExpressionCount: number) {
|
||||
return faceExpressionCount * (getDetectionInterval(state) / 1000);
|
||||
}
|
||||
|
||||
@@ -11,18 +11,15 @@ import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
|
||||
import { TRACK_ADDED, TRACK_REMOVED, TRACK_UPDATED } from '../base/tracks/actionTypes';
|
||||
|
||||
import FaceLandmarksDetector from './FaceLandmarksDetector';
|
||||
import { ADD_FACE_EXPRESSION, NEW_FACE_COORDINATES, UPDATE_FACE_COORDINATES } from './actionTypes';
|
||||
import {
|
||||
addToFaceExpressionsBuffer
|
||||
} from './actions';
|
||||
import { ADD_FACE_LANDMARKS, NEW_FACE_COORDINATES, UPDATE_FACE_COORDINATES } from './actionTypes';
|
||||
import { FACE_BOX_EVENT_TYPE } from './constants';
|
||||
import { sendFaceBoxToParticipants, sendFaceExpressionToParticipants, sendFaceExpressionToServer } from './functions';
|
||||
|
||||
|
||||
MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: any) => {
|
||||
const { dispatch, getState } = store;
|
||||
const { faceLandmarks } = getState()['features/base/config'];
|
||||
const isEnabled = faceLandmarks?.enableFaceCentering || faceLandmarks?.enableFaceExpressionsDetection;
|
||||
const { faceLandmarks: faceLandmarksConfig } = getState()['features/base/config'];
|
||||
const isEnabled = faceLandmarksConfig?.enableFaceCentering || faceLandmarksConfig?.enableFaceExpressionsDetection;
|
||||
|
||||
if (action.type === CONFERENCE_JOINED) {
|
||||
if (isEnabled) {
|
||||
@@ -99,19 +96,16 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: any)
|
||||
|
||||
return next(action);
|
||||
}
|
||||
case ADD_FACE_EXPRESSION: {
|
||||
case ADD_FACE_LANDMARKS: {
|
||||
const state = getState();
|
||||
const { faceExpression, duration, timestamp } = action;
|
||||
const { faceLandmarks } = action;
|
||||
const conference = getCurrentConference(state);
|
||||
|
||||
if (getParticipantCount(state) > 1) {
|
||||
sendFaceExpressionToParticipants(conference, faceExpression, duration);
|
||||
sendFaceExpressionToParticipants(conference, faceLandmarks);
|
||||
}
|
||||
sendFaceExpressionToServer(conference, faceExpression, duration);
|
||||
dispatch(addToFaceExpressionsBuffer({
|
||||
emotion: faceExpression,
|
||||
timestamp
|
||||
}));
|
||||
|
||||
sendFaceExpressionToServer(conference, faceLandmarks);
|
||||
|
||||
return next(action);
|
||||
}
|
||||
|
||||
@@ -1,42 +1,25 @@
|
||||
import ReducerRegistry from '../base/redux/ReducerRegistry';
|
||||
|
||||
import {
|
||||
ADD_FACE_EXPRESSION,
|
||||
ADD_TO_FACE_EXPRESSIONS_BUFFER,
|
||||
CLEAR_FACE_EXPRESSIONS_BUFFER,
|
||||
ADD_FACE_LANDMARKS,
|
||||
CLEAR_FACE_LANDMARKS_BUFFER,
|
||||
UPDATE_FACE_COORDINATES
|
||||
} from './actionTypes';
|
||||
import { FaceBox } from './types';
|
||||
import { FaceBox, FaceLandmarks } from './types';
|
||||
|
||||
const defaultState = {
|
||||
faceBoxes: {},
|
||||
faceExpressions: {
|
||||
happy: 0,
|
||||
neutral: 0,
|
||||
surprised: 0,
|
||||
angry: 0,
|
||||
fearful: 0,
|
||||
disgusted: 0,
|
||||
sad: 0
|
||||
},
|
||||
faceExpressionsBuffer: [],
|
||||
faceLandmarks: [],
|
||||
faceLandmarksBuffer: [],
|
||||
recognitionActive: false
|
||||
};
|
||||
|
||||
export interface IFaceLandmarksState {
|
||||
faceBoxes: { [key: string]: FaceBox; };
|
||||
faceExpressions: {
|
||||
angry: number;
|
||||
disgusted: number;
|
||||
fearful: number;
|
||||
happy: number;
|
||||
neutral: number;
|
||||
sad: number;
|
||||
surprised: number;
|
||||
};
|
||||
faceExpressionsBuffer: Array<{
|
||||
faceLandmarks: Array<FaceLandmarks>;
|
||||
faceLandmarksBuffer: Array<{
|
||||
emotion: string;
|
||||
timestamp: string;
|
||||
timestamp: number;
|
||||
}>;
|
||||
recognitionActive: boolean;
|
||||
}
|
||||
@@ -44,26 +27,23 @@ export interface IFaceLandmarksState {
|
||||
ReducerRegistry.register<IFaceLandmarksState>('features/face-landmarks',
|
||||
(state = defaultState, action): IFaceLandmarksState => {
|
||||
switch (action.type) {
|
||||
case ADD_FACE_EXPRESSION: {
|
||||
case ADD_FACE_LANDMARKS: {
|
||||
const { addToBuffer, faceLandmarks }: { addToBuffer: boolean; faceLandmarks: FaceLandmarks; } = action;
|
||||
|
||||
return {
|
||||
...state,
|
||||
faceExpressions: {
|
||||
...state.faceExpressions,
|
||||
[action.faceExpression]: state.faceExpressions[
|
||||
action.faceExpression as keyof typeof state.faceExpressions] + action.duration
|
||||
}
|
||||
faceLandmarks: [ ...state.faceLandmarks, faceLandmarks ],
|
||||
faceLandmarksBuffer: addToBuffer ? [ ...state.faceLandmarksBuffer,
|
||||
{
|
||||
emotion: faceLandmarks.faceExpression,
|
||||
timestamp: faceLandmarks.timestamp
|
||||
} ] : state.faceLandmarksBuffer
|
||||
};
|
||||
}
|
||||
case ADD_TO_FACE_EXPRESSIONS_BUFFER: {
|
||||
case CLEAR_FACE_LANDMARKS_BUFFER: {
|
||||
return {
|
||||
...state,
|
||||
faceExpressionsBuffer: [ ...state.faceExpressionsBuffer, action.faceExpression ]
|
||||
};
|
||||
}
|
||||
case CLEAR_FACE_EXPRESSIONS_BUFFER: {
|
||||
return {
|
||||
...state,
|
||||
faceExpressionsBuffer: []
|
||||
faceLandmarksBuffer: []
|
||||
};
|
||||
}
|
||||
case UPDATE_FACE_COORDINATES: {
|
||||
|
||||
@@ -19,5 +19,21 @@ export type InitInput = {
|
||||
export type DetectOutput = {
|
||||
faceBox?: FaceBox;
|
||||
faceCount: number;
|
||||
faceExpression?: string;
|
||||
faceExpression?: FaceExpression;
|
||||
};
|
||||
|
||||
export type FaceExpression = {
|
||||
expression: string;
|
||||
score: number;
|
||||
};
|
||||
|
||||
export type FaceLandmarks = {
|
||||
|
||||
// duration in milliseconds of the face landmarks
|
||||
duration: number;
|
||||
faceExpression: string;
|
||||
score?: number;
|
||||
|
||||
// the start timestamp of the expression
|
||||
timestamp: number;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Image, View } from 'react-native';
|
||||
import type { Dispatch } from 'redux';
|
||||
@@ -226,11 +224,11 @@ class Thumbnail extends PureComponent<Props> {
|
||||
] }>
|
||||
{ !_isVirtualScreenshare && <ConnectionIndicator participantId = { participantId } /> }
|
||||
{ !_isVirtualScreenshare && <RaisedHandIndicator participantId = { participantId } /> }
|
||||
{tileView && isScreenShare && (
|
||||
{ tileView && isScreenShare && (
|
||||
<View style = { styles.indicatorContainer }>
|
||||
<ScreenShareIndicator />
|
||||
</View>
|
||||
)}
|
||||
) }
|
||||
</View>);
|
||||
indicators.push(<Container
|
||||
key = 'bottom-indicators'
|
||||
@@ -369,7 +367,7 @@ class Thumbnail extends PureComponent<Props> {
|
||||
_renderDominantSpeakerIndicator && !_isVirtualScreenshare ? styles.thumbnailDominantSpeaker : null
|
||||
] }
|
||||
touchFeedback = { false }>
|
||||
{_gifSrc ? <Image
|
||||
{ _gifSrc ? <Image
|
||||
source = {{ uri: _gifSrc }}
|
||||
style = { styles.thumbnailGif } />
|
||||
: <>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
import { SMALL_THUMBNAIL_SIZE } from '../../constants';
|
||||
|
||||
@@ -10,7 +8,7 @@ export const AVATAR_SIZE = 50;
|
||||
|
||||
const indicatorContainer = {
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
||||
borderRadius: 4,
|
||||
borderRadius: BaseTheme.shape.borderRadius,
|
||||
margin: 2,
|
||||
padding: 2
|
||||
};
|
||||
@@ -119,7 +117,16 @@ export default {
|
||||
width: SMALL_THUMBNAIL_SIZE
|
||||
},
|
||||
|
||||
indicatorContainer,
|
||||
indicatorContainer: {
|
||||
...indicatorContainer,
|
||||
flexShrink: 1,
|
||||
height: 32,
|
||||
justifyContent: 'center',
|
||||
marginBottom: BaseTheme.spacing[0],
|
||||
marginHorizontal: BaseTheme.spacing[1],
|
||||
marginTop: BaseTheme.spacing[2],
|
||||
width: 32
|
||||
},
|
||||
|
||||
/**
|
||||
* The thumbnails indicator container.
|
||||
|
||||
@@ -198,6 +198,11 @@ export interface IProps {
|
||||
*/
|
||||
_raisedHand: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not to display a tint background over tile.
|
||||
*/
|
||||
_shouldDisplayTintBackground: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not the current layout is stage filmstrip layout.
|
||||
*/
|
||||
@@ -360,6 +365,15 @@ const defaultStyles = (theme: Theme) => {
|
||||
objectFit: 'contain',
|
||||
flexGrow: '1'
|
||||
}
|
||||
},
|
||||
|
||||
tintBackground: {
|
||||
position: 'absolute' as const,
|
||||
zIndex: 1,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: `${theme.palette.uiBackground}`,
|
||||
opacity: 0.8
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -965,6 +979,7 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
_isTestModeEnabled,
|
||||
_localFlipX,
|
||||
_participant,
|
||||
_shouldDisplayTintBackground,
|
||||
_thumbnailType,
|
||||
_videoTrack,
|
||||
classes,
|
||||
@@ -1043,6 +1058,7 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
showPopover = { this._showPopover }
|
||||
thumbnailType = { _thumbnailType } />
|
||||
</div>
|
||||
{_shouldDisplayTintBackground && <div className = { classes.tintBackground } />}
|
||||
<div
|
||||
className = { clsx(classes.indicatorsContainer,
|
||||
classes.indicatorsBottomContainer,
|
||||
@@ -1090,7 +1106,12 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { _participant, _isTestModeEnabled, _isVirtualScreenshareParticipant } = this.props;
|
||||
const {
|
||||
_isTestModeEnabled,
|
||||
_isVirtualScreenshareParticipant,
|
||||
_participant,
|
||||
_shouldDisplayTintBackground
|
||||
} = this.props;
|
||||
const videoEventListeners: any = {};
|
||||
|
||||
if (!_participant) {
|
||||
@@ -1136,6 +1157,7 @@ class Thumbnail extends Component<IProps, IState> {
|
||||
onTouchMove = { this._onTouchMove }
|
||||
onTouchStart = { this._onTouchStart }
|
||||
participantId = { _participant.id }
|
||||
shouldDisplayTintBackground = { _shouldDisplayTintBackground }
|
||||
styles = { this._getStyles() }
|
||||
thumbnailType = { _thumbnailType }
|
||||
videoTrack = { _videoTrack } />
|
||||
@@ -1264,6 +1286,11 @@ function _mapStateToProps(state: IReduxState, ownProps: any): Object {
|
||||
const { gifUrl: gifSrc } = getGifForParticipant(state, id ?? '');
|
||||
const mode = getGifDisplayMode(state);
|
||||
const participantId = isLocal ? getLocalParticipant(state)?.id : participantID;
|
||||
const isActiveParticipant = activeParticipants.find((pId: string) => pId === participantId);
|
||||
const participantCurrentlyOnLargeVideo = state['features/large-video']?.participantId === id;
|
||||
const shouldDisplayTintBackground
|
||||
= _currentLayout !== LAYOUTS.TILE_VIEW && filmstripType === FILMSTRIP_TYPE.MAIN
|
||||
&& (isActiveParticipant || participantCurrentlyOnLargeVideo);
|
||||
|
||||
return {
|
||||
_audioTrack,
|
||||
@@ -1271,10 +1298,10 @@ function _mapStateToProps(state: IReduxState, ownProps: any): Object {
|
||||
_defaultLocalDisplayName: defaultLocalDisplayName,
|
||||
_disableLocalVideoFlip: Boolean(disableLocalVideoFlip),
|
||||
_disableTileEnlargement: Boolean(disableTileEnlargement),
|
||||
_isActiveParticipant: activeParticipants.find((pId: string) => pId === participantId),
|
||||
_isActiveParticipant: isActiveParticipant,
|
||||
_isHidden: isLocal && iAmRecorder && !iAmSipGateway,
|
||||
_isAudioOnly: Boolean(state['features/base/audio-only'].enabled),
|
||||
_isCurrentlyOnLargeVideo: state['features/large-video']?.participantId === id,
|
||||
_isCurrentlyOnLargeVideo: participantCurrentlyOnLargeVideo,
|
||||
_isDominantSpeakerDisabled: interfaceConfig.DISABLE_DOMINANT_SPEAKER_INDICATOR,
|
||||
_isMobile,
|
||||
_isMobilePortrait,
|
||||
@@ -1287,6 +1314,7 @@ function _mapStateToProps(state: IReduxState, ownProps: any): Object {
|
||||
_raisedHand: hasRaisedHand(participant),
|
||||
_stageFilmstripLayout: isStageFilmstripAvailable(state),
|
||||
_stageParticipantsVisible: _currentLayout === LAYOUTS.STAGE_FILMSTRIP_VIEW,
|
||||
_shouldDisplayTintBackground: shouldDisplayTintBackground,
|
||||
_thumbnailType: tileType,
|
||||
_videoObjectPosition: getVideoObjectPosition(state, participant?.id),
|
||||
_videoTrack,
|
||||
|
||||
@@ -77,6 +77,11 @@ type Props = {
|
||||
*/
|
||||
participantId: string,
|
||||
|
||||
/**
|
||||
* Whether or not to display a tint background over tile.
|
||||
*/
|
||||
shouldDisplayTintBackground: boolean,
|
||||
|
||||
/**
|
||||
* An object with the styles for thumbnail.
|
||||
*/
|
||||
@@ -107,6 +112,7 @@ const VirtualScreenshareParticipant = ({
|
||||
onTouchMove,
|
||||
onTouchStart,
|
||||
participantId,
|
||||
shouldDisplayTintBackground,
|
||||
styles,
|
||||
videoTrack,
|
||||
thumbnailType
|
||||
@@ -150,6 +156,7 @@ const VirtualScreenshareParticipant = ({
|
||||
participantId = { participantId }
|
||||
thumbnailType = { thumbnailType } />
|
||||
</div>
|
||||
{shouldDisplayTintBackground && <div className = { classes.tintBackground } />}
|
||||
<div
|
||||
className = { clsx(classes.indicatorsContainer,
|
||||
classes.indicatorsBottomContainer,
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Text, TouchableRipple } from 'react-native-paper';
|
||||
|
||||
import { Icon } from '../../../base/icons';
|
||||
import type { StyleType } from '../../../base/styles';
|
||||
import styles from '../../../conference/components/native/styles';
|
||||
|
||||
import { navigationStyles } from './styles';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Style of the header button .
|
||||
*/
|
||||
buttonStyle?: StyleType,
|
||||
|
||||
/**
|
||||
* Is the button disabled?
|
||||
*/
|
||||
@@ -42,7 +35,6 @@ type Props = {
|
||||
|
||||
const HeaderNavigationButton
|
||||
= ({
|
||||
buttonStyle,
|
||||
disabled,
|
||||
label,
|
||||
onPress,
|
||||
@@ -55,25 +47,21 @@ const HeaderNavigationButton
|
||||
src ? (
|
||||
<TouchableRipple
|
||||
onPress = { onPress }
|
||||
rippleColor = { 'transparent' }
|
||||
style = { [
|
||||
buttonStyle,
|
||||
styles.headerNavigationButton ] } >
|
||||
style = { navigationStyles.headerNavigationButtonIcon } >
|
||||
<Icon
|
||||
size = { 24 }
|
||||
src = { src }
|
||||
style = { styles.headerNavigationIcon } />
|
||||
src = { src } />
|
||||
</TouchableRipple>
|
||||
) : (
|
||||
<TouchableRipple
|
||||
disabled = { disabled }
|
||||
onPress = { onPress }
|
||||
rippleColor = { 'transparent' }>
|
||||
style = { navigationStyles.headerNavigationButtonText } >
|
||||
<Text
|
||||
style = {
|
||||
twoActions
|
||||
? styles.headerNavigationTextBold
|
||||
: styles.headerNavigationText
|
||||
? navigationStyles.headerNavigationTextBold
|
||||
: navigationStyles.headerNavigationText
|
||||
}>
|
||||
{ label }
|
||||
</Text>
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// @ts-ignore
|
||||
import React from 'react';
|
||||
import { StyleProp, Text, TextStyle, View } from 'react-native';
|
||||
|
||||
// @ts-ignore
|
||||
import { navigationStyles } from './styles';
|
||||
|
||||
interface ITabBarLabelCounterProps {
|
||||
activeUnreadNr: boolean;
|
||||
isFocused: boolean;
|
||||
label: string;
|
||||
nbUnread?: number;
|
||||
}
|
||||
|
||||
export const TabBarLabelCounter = ({ activeUnreadNr, isFocused, label, nbUnread }: ITabBarLabelCounterProps) => {
|
||||
const labelStyles = isFocused
|
||||
? navigationStyles.unreadCounterDescriptionFocused
|
||||
: navigationStyles.unreadCounterDescription;
|
||||
|
||||
return (
|
||||
<View
|
||||
style = {
|
||||
navigationStyles.unreadCounterContainer as StyleProp<TextStyle> }>
|
||||
<Text
|
||||
style = { labelStyles }>
|
||||
{ label && label }
|
||||
</Text>
|
||||
{
|
||||
activeUnreadNr && (
|
||||
<View
|
||||
style = { navigationStyles.unreadCounterCircle as StyleProp<TextStyle> }>
|
||||
<Text
|
||||
style = { navigationStyles.unreadCounter as StyleProp<TextStyle> }>
|
||||
{ nbUnread }
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
@@ -1,9 +1,11 @@
|
||||
/* eslint-disable lines-around-comment */
|
||||
|
||||
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
|
||||
// @ts-ignore
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../../../app/types';
|
||||
import {
|
||||
getClientHeight,
|
||||
getClientWidth
|
||||
@@ -11,6 +13,8 @@ import {
|
||||
} from '../../../../../base/modal/components/functions';
|
||||
// @ts-ignore
|
||||
import { Chat } from '../../../../../chat';
|
||||
import { setIsPollsTabFocused } from '../../../../../chat/actions.native';
|
||||
import { resetNbUnreadPollsMessages } from '../../../../../polls/actions';
|
||||
// @ts-ignore
|
||||
import { PollsPane } from '../../../../../polls/components';
|
||||
// @ts-ignore
|
||||
@@ -23,6 +27,11 @@ const ChatTab = createMaterialTopTabNavigator();
|
||||
const ChatAndPolls = () => {
|
||||
const clientHeight = useSelector(getClientHeight);
|
||||
const clientWidth = useSelector(getClientWidth);
|
||||
const dispatch = useDispatch();
|
||||
const { isPollsTabFocused } = useSelector((state: IReduxState) => state['features/chat']);
|
||||
const initialRouteName = isPollsTabFocused
|
||||
? screen.conference.chatandpolls.tab.polls
|
||||
: screen.conference.chatandpolls.tab.chat;
|
||||
|
||||
return (
|
||||
// @ts-ignore
|
||||
@@ -32,12 +41,24 @@ const ChatAndPolls = () => {
|
||||
height: clientHeight,
|
||||
width: clientWidth
|
||||
}}
|
||||
initialRouteName = { initialRouteName }
|
||||
screenOptions = { chatTabBarOptions }>
|
||||
<ChatTab.Screen
|
||||
component = { Chat }
|
||||
listeners = {{
|
||||
tabPress: () => {
|
||||
dispatch(setIsPollsTabFocused(false));
|
||||
}
|
||||
}}
|
||||
name = { screen.conference.chatandpolls.tab.chat } />
|
||||
<ChatTab.Screen
|
||||
component = { PollsPane }
|
||||
listeners = {{
|
||||
tabPress: () => {
|
||||
dispatch(setIsPollsTabFocused(true));
|
||||
dispatch(resetNbUnreadPollsMessages);
|
||||
}
|
||||
}}
|
||||
name = { screen.conference.chatandpolls.tab.polls } />
|
||||
</ChatTab.Navigator>
|
||||
);
|
||||
|
||||
@@ -1,9 +1,27 @@
|
||||
import { BoxModel } from '../../../base/styles';
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme';
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
|
||||
|
||||
export const TEXT_COLOR = BaseTheme.palette.text01;
|
||||
|
||||
const HEADER_ACTION_BUTTON_SIZE = 17;
|
||||
|
||||
const headerNavigationButton = {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
};
|
||||
|
||||
const headerNavigationText = {
|
||||
...BaseTheme.typography.bodyShortBoldLarge,
|
||||
color: BaseTheme.palette.link01,
|
||||
fontSize: HEADER_ACTION_BUTTON_SIZE
|
||||
};
|
||||
|
||||
const unreadCounterDescription = {
|
||||
...BaseTheme.typography.bodyShortBoldLarge,
|
||||
color: BaseTheme.palette.text03
|
||||
};
|
||||
|
||||
/**
|
||||
* Styles of the navigation feature.
|
||||
*/
|
||||
@@ -27,5 +45,59 @@ export const navigationStyles = {
|
||||
|
||||
connectingScreenText: {
|
||||
color: TEXT_COLOR
|
||||
},
|
||||
|
||||
headerNavigationButtonIcon: {
|
||||
...headerNavigationButton,
|
||||
height: BaseTheme.spacing[5],
|
||||
paddingLeft: BaseTheme.spacing[3],
|
||||
width: BaseTheme.spacing[5]
|
||||
},
|
||||
|
||||
headerNavigationButtonText: {
|
||||
...headerNavigationButton,
|
||||
height: BaseTheme.spacing[9],
|
||||
width: BaseTheme.spacing[9]
|
||||
},
|
||||
|
||||
headerNavigationText: {
|
||||
...headerNavigationText,
|
||||
marginLeft: BaseTheme.spacing[2]
|
||||
},
|
||||
|
||||
headerNavigationTextBold: {
|
||||
...headerNavigationText,
|
||||
...BaseTheme.typography.bodyShortRegularLarge,
|
||||
marginRight: BaseTheme.spacing[1]
|
||||
},
|
||||
|
||||
unreadCounterContainer: {
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
|
||||
unreadCounterDescription: {
|
||||
...unreadCounterDescription
|
||||
},
|
||||
|
||||
unreadCounterDescriptionFocused: {
|
||||
...unreadCounterDescription,
|
||||
color: BaseTheme.palette.text01
|
||||
},
|
||||
|
||||
unreadCounterCircle: {
|
||||
backgroundColor: BaseTheme.palette.warning01,
|
||||
borderRadius: BaseTheme.spacing[4] / 2,
|
||||
height: BaseTheme.spacing[4],
|
||||
justifyContent: 'center',
|
||||
marginLeft: BaseTheme.spacing[2],
|
||||
width: BaseTheme.spacing[4]
|
||||
},
|
||||
|
||||
unreadCounter: {
|
||||
...BaseTheme.typography.bodyShortBold,
|
||||
alignSelf: 'center',
|
||||
color: BaseTheme.palette.text04
|
||||
}
|
||||
};
|
||||
|
||||
@@ -67,19 +67,14 @@ export const conferenceScreenOptions = fullScreenOptions;
|
||||
* Tab bar options for chat screen.
|
||||
*/
|
||||
export const chatTabBarOptions = {
|
||||
tabBarActiveTintColor: BaseTheme.palette.field02,
|
||||
tabBarLabelStyle: {
|
||||
fontSize: BaseTheme.typography.labelRegular.fontSize,
|
||||
textTransform: 'capitalize'
|
||||
},
|
||||
tabBarInactiveTintColor: BaseTheme.palette.text03,
|
||||
swipeEnabled: false,
|
||||
tabBarIndicatorStyle: {
|
||||
backgroundColor: BaseTheme.palette.field02
|
||||
backgroundColor: BaseTheme.palette.link01Active
|
||||
},
|
||||
tabBarStyle: {
|
||||
backgroundColor: BaseTheme.palette.ui01,
|
||||
borderBottomColor: BaseTheme.palette.border05,
|
||||
borderBottomWidth: 1
|
||||
borderBottomWidth: 0.4
|
||||
}
|
||||
};
|
||||
|
||||
|
||||