mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-02-18 11:50:20 +00:00
Compare commits
227 Commits
saghul-pat
...
android-sd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ca22ddb75 | ||
|
|
eb2e6ad641 | ||
|
|
6cedba2793 | ||
|
|
58be0f6914 | ||
|
|
529b182666 | ||
|
|
067ff0729e | ||
|
|
6d3d65da03 | ||
|
|
fd4819aeca | ||
|
|
7ca04ccb0f | ||
|
|
bf3726cb93 | ||
|
|
524af5ca67 | ||
|
|
af28080058 | ||
|
|
927b40ec71 | ||
|
|
3bbfdb2846 | ||
|
|
e38ebc6628 | ||
|
|
62cf3099a7 | ||
|
|
b135e2a06a | ||
|
|
7656985fe1 | ||
|
|
5599454ea9 | ||
|
|
807a5ab893 | ||
|
|
c4766125bb | ||
|
|
ba41745d1e | ||
|
|
8eed42c273 | ||
|
|
e803e8cfd9 | ||
|
|
86dd35b927 | ||
|
|
32ecd6310c | ||
|
|
e5277deed5 | ||
|
|
8b315846b9 | ||
|
|
c687f41a89 | ||
|
|
31c0ba4481 | ||
|
|
fc3a743372 | ||
|
|
8b038716a5 | ||
|
|
9662b2ae67 | ||
|
|
6275439a91 | ||
|
|
d9693117f2 | ||
|
|
21382ea6d5 | ||
|
|
6df67694d1 | ||
|
|
08756bc6d0 | ||
|
|
1b1d650b75 | ||
|
|
b1eff72394 | ||
|
|
357bbd1158 | ||
|
|
0ca47e9ffb | ||
|
|
1123b4f2fe | ||
|
|
1224597ede | ||
|
|
58b7663a97 | ||
|
|
cf8ab5e13b | ||
|
|
f99c919416 | ||
|
|
ae21a09bd6 | ||
|
|
39011d8fd3 | ||
|
|
77f1a24344 | ||
|
|
3453e49182 | ||
|
|
b1d7debfb9 | ||
|
|
b826fc1d5a | ||
|
|
c5626e99e9 | ||
|
|
ae28fcc12f | ||
|
|
987760abbd | ||
|
|
a3b364f8d7 | ||
|
|
2ea317d721 | ||
|
|
eb41a306a6 | ||
|
|
3426290bf2 | ||
|
|
dfd33521bf | ||
|
|
be3bc75403 | ||
|
|
4621fad832 | ||
|
|
e4b34e1c89 | ||
|
|
0067f6b077 | ||
|
|
989044b3a9 | ||
|
|
a78ca5fcad | ||
|
|
1ad40de487 | ||
|
|
2c9078985f | ||
|
|
77ee4b13e1 | ||
|
|
a3a2ce3875 | ||
|
|
e0c77dcd95 | ||
|
|
e035d33fa9 | ||
|
|
11202595bd | ||
|
|
415670e24b | ||
|
|
05f3b4390d | ||
|
|
cff0a619f5 | ||
|
|
f7c0d4f1fe | ||
|
|
8fccb05519 | ||
|
|
b4155ab6d2 | ||
|
|
a1d3870634 | ||
|
|
07f16a7a51 | ||
|
|
0e7bde2ff0 | ||
|
|
e9d00acad8 | ||
|
|
911aaed052 | ||
|
|
5fd9dc74e4 | ||
|
|
eb68467e15 | ||
|
|
6a5d6afc94 | ||
|
|
2a9b6a7d28 | ||
|
|
67beafc9af | ||
|
|
6175a5cad5 | ||
|
|
678f3e232b | ||
|
|
f3c1b8ac08 | ||
|
|
f225ce886f | ||
|
|
6a4417c6cc | ||
|
|
6b66c8dd20 | ||
|
|
d3680bbebd | ||
|
|
7933d4b4d6 | ||
|
|
e7297714c6 | ||
|
|
8da154b185 | ||
|
|
3c94a5ccfd | ||
|
|
78d4af6bf2 | ||
|
|
33fc3833f9 | ||
|
|
b179542c39 | ||
|
|
49c38a73aa | ||
|
|
fc27300132 | ||
|
|
57ecdff9eb | ||
|
|
effa878fa4 | ||
|
|
9d4e49a5af | ||
|
|
6b4d25c0d3 | ||
|
|
2f5ab2757f | ||
|
|
bde26c4fbb | ||
|
|
68c2c9be40 | ||
|
|
5b21051c6b | ||
|
|
8806269af0 | ||
|
|
3a8bd852b2 | ||
|
|
f50872285d | ||
|
|
e937e99284 | ||
|
|
3972e076f0 | ||
|
|
81cf79e643 | ||
|
|
a22d054b10 | ||
|
|
7fce181080 | ||
|
|
92735478d1 | ||
|
|
7dabfc21b4 | ||
|
|
1395f84550 | ||
|
|
d080460f9b | ||
|
|
61567f47c0 | ||
|
|
4f3058eae2 | ||
|
|
3a073d9af4 | ||
|
|
aef0287605 | ||
|
|
bb19567efa | ||
|
|
79ab973694 | ||
|
|
7046785ca3 | ||
|
|
b817bd19d5 | ||
|
|
817d54b0b9 | ||
|
|
3f0bb6818c | ||
|
|
4fa47c8070 | ||
|
|
0dcb8a025b | ||
|
|
8defaa9aec | ||
|
|
d214079148 | ||
|
|
096ee3cb53 | ||
|
|
fd606896b8 | ||
|
|
226581a81a | ||
|
|
e1c5b1e626 | ||
|
|
831c5ba59d | ||
|
|
bad1bc91cf | ||
|
|
30d0aabaca | ||
|
|
22b6d32174 | ||
|
|
31ace267ce | ||
|
|
194d357005 | ||
|
|
c2ad06c5e6 | ||
|
|
e40b02ab3c | ||
|
|
2587eefefc | ||
|
|
b87c433e99 | ||
|
|
751644db16 | ||
|
|
c508572cc5 | ||
|
|
b86c271a80 | ||
|
|
5efbe5f0ec | ||
|
|
2784c43a1b | ||
|
|
f5a34183e9 | ||
|
|
29f5d87d77 | ||
|
|
ab6790bdaa | ||
|
|
2e308d67d8 | ||
|
|
91ba835f78 | ||
|
|
2643029ac8 | ||
|
|
e40e078a29 | ||
|
|
6df5a4cf31 | ||
|
|
c7c7d7a155 | ||
|
|
8f06866646 | ||
|
|
b559cb8ec6 | ||
|
|
30a2e84da1 | ||
|
|
3122983000 | ||
|
|
407021e258 | ||
|
|
1a62a7b1cc | ||
|
|
0ee03f1538 | ||
|
|
572beb8382 | ||
|
|
d0d32b8a19 | ||
|
|
82ff988c18 | ||
|
|
8fa5d09612 | ||
|
|
508f1e0da9 | ||
|
|
dcda89012e | ||
|
|
d93a402cc2 | ||
|
|
b7b260f4c9 | ||
|
|
4db3f04c0c | ||
|
|
126a2bd0d7 | ||
|
|
29bbcf8590 | ||
|
|
5c46b03251 | ||
|
|
eeb5abbbe8 | ||
|
|
49583b611c | ||
|
|
9e29dd063f | ||
|
|
a2e2d31dfd | ||
|
|
62c06441b1 | ||
|
|
f718a3e050 | ||
|
|
899968d3a9 | ||
|
|
696f509f18 | ||
|
|
430591bd1e | ||
|
|
8ee324b37f | ||
|
|
399d6b6a4b | ||
|
|
ffad21cb59 | ||
|
|
ce6debac45 | ||
|
|
5d8bf0c1e7 | ||
|
|
7bbd06c9f4 | ||
|
|
79a67049a9 | ||
|
|
b1a3c5cd7b | ||
|
|
9573a615b1 | ||
|
|
5d09102e48 | ||
|
|
cc0ecc1fdd | ||
|
|
cecf324023 | ||
|
|
943d5dca35 | ||
|
|
dd1f8339b1 | ||
|
|
159f59b665 | ||
|
|
23bb824731 | ||
|
|
42d926eef3 | ||
|
|
87a110b9c3 | ||
|
|
a7db7ecaff | ||
|
|
79bb98dab3 | ||
|
|
d22792c9e3 | ||
|
|
41e6af3464 | ||
|
|
f50fd7b7bd | ||
|
|
43761fc398 | ||
|
|
4c39d83ff1 | ||
|
|
e525c2b2ec | ||
|
|
f69a31d9c6 | ||
|
|
67930edae2 | ||
|
|
c11a94f7d7 | ||
|
|
bfd093b0ba | ||
|
|
861935c9d7 |
@@ -5,8 +5,9 @@ build/*
|
||||
# modify as little as possible.
|
||||
flow-typed/*
|
||||
libs/*
|
||||
|
||||
react/features/stream-effects/blur/vendor/*
|
||||
resources/*
|
||||
react/features/stream-effects/virtual-background/vendor/*
|
||||
load-test/*
|
||||
|
||||
# ESLint will by default ignore its own configuration file. However, there does
|
||||
# not seem to be a reason why we will want to risk being inconsistent with our
|
||||
|
||||
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
@@ -12,5 +12,6 @@ jobs:
|
||||
with:
|
||||
node-version: '12.x'
|
||||
- run: npm install
|
||||
- run: git status -s --untracked-files=no
|
||||
- run: npm run lint
|
||||
- run: make
|
||||
|
||||
8
Makefile
8
Makefile
@@ -5,8 +5,8 @@ LIBJITSIMEET_DIR = node_modules/lib-jitsi-meet/
|
||||
LIBFLAC_DIR = node_modules/libflacjs/dist/min/
|
||||
OLM_DIR = node_modules/olm
|
||||
RNNOISE_WASM_DIR = node_modules/rnnoise-wasm/dist/
|
||||
TFLITE_WASM = react/features/stream-effects/blur/vendor/tflite
|
||||
MEET_MODELS_DIR = react/features/stream-effects/blur/vendor/models/
|
||||
TFLITE_WASM = react/features/stream-effects/virtual-background/vendor/tflite
|
||||
MEET_MODELS_DIR = react/features/stream-effects/virtual-background/vendor/models/
|
||||
NODE_SASS = ./node_modules/.bin/sass
|
||||
NPM = npm
|
||||
OUTPUT_DIR = .
|
||||
@@ -51,10 +51,6 @@ deploy-appbundle:
|
||||
$(OUTPUT_DIR)/analytics-ga.js \
|
||||
$(BUILD_DIR)/analytics-ga.min.js \
|
||||
$(BUILD_DIR)/analytics-ga.min.map \
|
||||
$(BUILD_DIR)/video-blur-effect.min.js \
|
||||
$(BUILD_DIR)/video-blur-effect.min.map \
|
||||
$(BUILD_DIR)/rnnoise-processor.min.js \
|
||||
$(BUILD_DIR)/rnnoise-processor.min.map \
|
||||
$(BUILD_DIR)/close3.min.js \
|
||||
$(BUILD_DIR)/close3.min.map \
|
||||
$(DEPLOY_DIR)
|
||||
|
||||
@@ -122,7 +122,7 @@ gradle.projectsEvaluated {
|
||||
android.applicationVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
output.getProcessManifestProvider().get().doLast {
|
||||
def outputDir = manifestOutputDirectory.get().asFile
|
||||
def outputDir = multiApkManifestOutputDirectory.get().asFile
|
||||
def manifestPath = new File(outputDir, 'AndroidManifest.xml')
|
||||
def charset = 'UTF-8'
|
||||
def text
|
||||
|
||||
@@ -25,5 +25,5 @@ android.enableDexingArtifactTransform.desugaring=false
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
appVersion=21.0.0
|
||||
sdkVersion=3.1.0
|
||||
appVersion=21.1.0
|
||||
sdkVersion=3.4.0
|
||||
|
||||
@@ -70,7 +70,6 @@ dependencies {
|
||||
implementation project(':react-native-default-preference')
|
||||
implementation project(':react-native-immersive')
|
||||
implementation project(':react-native-keep-awake')
|
||||
implementation project(':react-native-linear-gradient')
|
||||
implementation project(':react-native-sound')
|
||||
implementation project(':react-native-svg')
|
||||
implementation project(':react-native-webrtc')
|
||||
|
||||
@@ -36,8 +36,17 @@ public class BroadcastAction {
|
||||
|
||||
for (String key : this.data.keySet()) {
|
||||
try {
|
||||
// TODO add support for different types of objects
|
||||
nativeMap.putString(key, this.data.get(key).toString());
|
||||
if (this.data.get(key) instanceof Boolean) {
|
||||
nativeMap.putBoolean(key, (Boolean) this.data.get(key));
|
||||
} else if (this.data.get(key) instanceof Integer) {
|
||||
nativeMap.putInt(key, (Integer) this.data.get(key));
|
||||
} else if (this.data.get(key) instanceof Double) {
|
||||
nativeMap.putDouble(key, (Double) this.data.get(key));
|
||||
} else if (this.data.get(key) instanceof String) {
|
||||
nativeMap.putString(key, (String) this.data.get(key));
|
||||
} else {
|
||||
throw new Exception("Unsupported extra data type");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
JitsiMeetLogger.w(TAG + " invalid extra data in event", e);
|
||||
}
|
||||
@@ -66,7 +75,8 @@ public class BroadcastAction {
|
||||
RETRIEVE_PARTICIPANTS_INFO("org.jitsi.meet.RETRIEVE_PARTICIPANTS_INFO"),
|
||||
OPEN_CHAT("org.jitsi.meet.OPEN_CHAT"),
|
||||
CLOSE_CHAT("org.jitsi.meet.CLOSE_CHAT"),
|
||||
SEND_CHAT_MESSAGE("org.jitsi.meet.SEND_CHAT_MESSAGE");
|
||||
SEND_CHAT_MESSAGE("org.jitsi.meet.SEND_CHAT_MESSAGE"),
|
||||
SET_VIDEO_MUTED("org.jitsi.meet.SET_VIDEO_MUTED");
|
||||
|
||||
private final String action;
|
||||
|
||||
|
||||
@@ -85,7 +85,9 @@ public class BroadcastEvent {
|
||||
SCREEN_SHARE_TOGGLED("org.jitsi.meet.SCREEN_SHARE_TOGGLED"),
|
||||
PARTICIPANTS_INFO_RETRIEVED("org.jitsi.meet.PARTICIPANTS_INFO_RETRIEVED"),
|
||||
CHAT_MESSAGE_RECEIVED("org.jitsi.meet.CHAT_MESSAGE_RECEIVED"),
|
||||
CHAT_TOGGLED("org.jitsi.meet.CHAT_TOGGLED");
|
||||
CHAT_TOGGLED("org.jitsi.meet.CHAT_TOGGLED"),
|
||||
VIDEO_MUTED_CHANGED("org.jitsi.meet.VIDEO_MUTED_CHANGED");
|
||||
|
||||
|
||||
private static final String CONFERENCE_WILL_JOIN_NAME = "CONFERENCE_WILL_JOIN";
|
||||
private static final String CONFERENCE_JOINED_NAME = "CONFERENCE_JOINED";
|
||||
@@ -98,6 +100,7 @@ public class BroadcastEvent {
|
||||
private static final String PARTICIPANTS_INFO_RETRIEVED_NAME = "PARTICIPANTS_INFO_RETRIEVED";
|
||||
private static final String CHAT_MESSAGE_RECEIVED_NAME = "CHAT_MESSAGE_RECEIVED";
|
||||
private static final String CHAT_TOGGLED_NAME = "CHAT_TOGGLED";
|
||||
private static final String VIDEO_MUTED_CHANGED_NAME = "VIDEO_MUTED_CHANGED";
|
||||
|
||||
private final String action;
|
||||
|
||||
@@ -142,6 +145,8 @@ public class BroadcastEvent {
|
||||
return CHAT_MESSAGE_RECEIVED;
|
||||
case CHAT_TOGGLED_NAME:
|
||||
return CHAT_TOGGLED;
|
||||
case VIDEO_MUTED_CHANGED_NAME:
|
||||
return VIDEO_MUTED_CHANGED;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -40,4 +40,10 @@ public class BroadcastIntentHelper {
|
||||
intent.putExtra("message", message);
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static Intent buildSetVideoMutedIntent(boolean muted) {
|
||||
Intent intent = new Intent(BroadcastAction.Type.SET_VIDEO_MUTED.getAction());
|
||||
intent.putExtra("muted", muted);
|
||||
return intent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ class ExternalAPIModule
|
||||
constants.put("OPEN_CHAT", BroadcastAction.Type.OPEN_CHAT.getAction());
|
||||
constants.put("CLOSE_CHAT", BroadcastAction.Type.CLOSE_CHAT.getAction());
|
||||
constants.put("SEND_CHAT_MESSAGE", BroadcastAction.Type.SEND_CHAT_MESSAGE.getAction());
|
||||
constants.put("SET_VIDEO_MUTED", BroadcastAction.Type.SET_VIDEO_MUTED.getAction());
|
||||
|
||||
return constants;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.facebook.react.modules.core.PermissionListener;
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import java.util.HashMap;
|
||||
import android.app.Activity;
|
||||
|
||||
/**
|
||||
* A base activity for SDK users to embed. It uses {@link JitsiMeetFragment} to do the heavy
|
||||
@@ -58,6 +59,9 @@ public class JitsiMeetActivity extends FragmentActivity
|
||||
Intent intent = new Intent(context, JitsiMeetActivity.class);
|
||||
intent.setAction(ACTION_JITSI_MEET_CONFERENCE);
|
||||
intent.putExtra(JITSI_MEET_CONFERENCE_OPTIONS, options);
|
||||
if (!(context instanceof Activity)) {
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
}
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
|
||||
@@ -132,6 +132,7 @@ public class JitsiMeetOngoingConferenceService extends Service
|
||||
public void onCurrentConferenceChanged(String conferenceUrl) {
|
||||
if (conferenceUrl == null) {
|
||||
stopSelf();
|
||||
OngoingNotification.resetStartingtime();
|
||||
JitsiMeetLogger.i(TAG + "Service stopped");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ class OngoingNotification {
|
||||
private static final String CHANNEL_NAME = "Ongoing Conference Notifications";
|
||||
|
||||
static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
|
||||
private static long startingTime = 0;
|
||||
|
||||
static void createOngoingConferenceNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
@@ -85,6 +86,10 @@ class OngoingNotification {
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
|
||||
|
||||
if (startingTime == 0) {
|
||||
startingTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
builder
|
||||
.setCategory(NotificationCompat.CATEGORY_CALL)
|
||||
.setContentTitle(context.getString(R.string.ongoing_notification_title))
|
||||
@@ -92,6 +97,8 @@ class OngoingNotification {
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setOngoing(true)
|
||||
.setWhen(startingTime)
|
||||
.setUsesChronometer(true)
|
||||
.setAutoCancel(false)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setOnlyAlertOnce(true)
|
||||
@@ -110,6 +117,10 @@ class OngoingNotification {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static void resetStartingtime() {
|
||||
startingTime = 0;
|
||||
}
|
||||
|
||||
private static NotificationCompat.Action createAction(Context context, JitsiMeetOngoingConferenceService.Action action, @StringRes int titleId) {
|
||||
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
|
||||
intent.setAction(action.getName());
|
||||
|
||||
@@ -178,7 +178,6 @@ class ReactInstanceManagerHolder {
|
||||
|
||||
List<ReactPackage> packages
|
||||
= new ArrayList<>(Arrays.asList(
|
||||
new com.BV.LinearGradient.LinearGradientPackage(),
|
||||
new com.calendarevents.CalendarEventsPackage(),
|
||||
new com.corbt.keepawake.KCKeepAwakePackage(),
|
||||
new com.facebook.react.shell.MainReactPackage(),
|
||||
|
||||
@@ -19,8 +19,6 @@ include ':react-native-immersive'
|
||||
project(':react-native-immersive').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-immersive/android')
|
||||
include ':react-native-keep-awake'
|
||||
project(':react-native-keep-awake').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keep-awake/android')
|
||||
include ':react-native-linear-gradient'
|
||||
project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android')
|
||||
include ':react-native-sound'
|
||||
project(':react-native-sound').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sound/android')
|
||||
include ':react-native-splash-screen'
|
||||
|
||||
1
app.js
1
app.js
@@ -1,7 +1,6 @@
|
||||
/* application specific logic */
|
||||
|
||||
import 'jquery';
|
||||
import 'jquery-contextmenu';
|
||||
import 'jQuery-Impromptu';
|
||||
|
||||
import 'olm';
|
||||
|
||||
241
conference.js
241
conference.js
@@ -1,10 +1,12 @@
|
||||
/* global APP, JitsiMeetJS, config, interfaceConfig */
|
||||
|
||||
import { jitsiLocalStorage } from '@jitsi/js-utils';
|
||||
import EventEmitter from 'events';
|
||||
import Logger from 'jitsi-meet-logger';
|
||||
|
||||
import { openConnection } from './connection';
|
||||
import { ENDPOINT_TEXT_MESSAGE_NAME } from './modules/API/constants';
|
||||
import { AUDIO_ONLY_SCREEN_SHARE_NO_TRACK } from './modules/UI/UIErrors';
|
||||
import AuthHandler from './modules/UI/authentication/AuthHandler';
|
||||
import UIUtil from './modules/UI/util/UIUtil';
|
||||
import mediaDeviceHelper from './modules/devices/mediaDeviceHelper';
|
||||
@@ -99,6 +101,7 @@ import {
|
||||
destroyLocalTracks,
|
||||
getLocalJitsiAudioTrack,
|
||||
getLocalJitsiVideoTrack,
|
||||
getLocalTracks,
|
||||
isLocalCameraTrackMuted,
|
||||
isLocalTrackMuted,
|
||||
isUserInteractionRequiredForUnmute,
|
||||
@@ -115,7 +118,7 @@ import {
|
||||
submitFeedback
|
||||
} from './react/features/feedback';
|
||||
import { showNotification } from './react/features/notifications';
|
||||
import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay';
|
||||
import { mediaPermissionPromptVisibilityChanged, toggleSlowGUMOverlay } from './react/features/overlay';
|
||||
import { suspendDetected } from './react/features/power-monitor';
|
||||
import {
|
||||
initPrejoin,
|
||||
@@ -124,8 +127,9 @@ import {
|
||||
makePrecallTest
|
||||
} from './react/features/prejoin';
|
||||
import { disableReceiver, stopReceiver } from './react/features/remote-control';
|
||||
import { setScreenAudioShareState, isScreenAudioShared } from './react/features/screen-share/';
|
||||
import { toggleScreenshotCaptureEffect } from './react/features/screenshot-capture';
|
||||
import { setSharedVideoStatus } from './react/features/shared-video';
|
||||
import { setSharedVideoStatus } from './react/features/shared-video/actions';
|
||||
import { AudioMixerEffect } from './react/features/stream-effects/audio-mixer/AudioMixerEffect';
|
||||
import { createPresenterEffect } from './react/features/stream-effects/presenter';
|
||||
import { endpointMessageReceived } from './react/features/subtitles';
|
||||
@@ -308,11 +312,6 @@ class ConferenceConnector {
|
||||
room.join();
|
||||
}, 5000);
|
||||
|
||||
const { password }
|
||||
= APP.store.getState()['features/base/conference'];
|
||||
|
||||
AuthHandler.requireAuth(room, password);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -377,7 +376,6 @@ class ConferenceConnector {
|
||||
if (this.reconnectTimeout !== null) {
|
||||
clearTimeout(this.reconnectTimeout);
|
||||
}
|
||||
AuthHandler.closeAuth();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -392,7 +390,8 @@ class ConferenceConnector {
|
||||
*
|
||||
*/
|
||||
connect() {
|
||||
room.join();
|
||||
// the local storage overrides here and in connection.js can be used by jibri
|
||||
room.join(jitsiLocalStorage.getItem('xmpp_conference_password_override'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,18 +472,13 @@ export default {
|
||||
*/
|
||||
createInitialLocalTracks(options = {}) {
|
||||
const errors = {};
|
||||
|
||||
// Always get a handle on the audio input device so that we have statistics (such as "No audio input" or
|
||||
// "Are you trying to speak?" ) even if the user joins the conference muted.
|
||||
const initialDevices = config.disableInitialGUM ? [] : [ 'audio' ];
|
||||
const requestedAudio = !config.disableInitialGUM;
|
||||
let requestedVideo = false;
|
||||
|
||||
// Always get a handle on the audio input device so that we have statistics even if the user joins the
|
||||
// conference muted. Previous implementation would only acquire the handle when the user first unmuted,
|
||||
// which would results in statistics ( such as "No audio input" or "Are you trying to speak?") being available
|
||||
// only after that point.
|
||||
if (options.startWithAudioMuted) {
|
||||
this.muteAudio(true, true);
|
||||
}
|
||||
|
||||
if (!config.disableInitialGUM
|
||||
&& !options.startWithVideoMuted
|
||||
&& !options.startAudioOnly
|
||||
@@ -502,10 +496,15 @@ export default {
|
||||
);
|
||||
}
|
||||
|
||||
JitsiMeetJS.mediaDevices.addEventListener(
|
||||
JitsiMediaDevicesEvents.SLOW_GET_USER_MEDIA,
|
||||
() => APP.store.dispatch(toggleSlowGUMOverlay(true))
|
||||
);
|
||||
|
||||
let tryCreateLocalTracks;
|
||||
|
||||
// On Electron there is no permission prompt for granting permissions. That's why we don't need to
|
||||
// spend much time displaying the overlay screen. If GUM is not resolved withing 15 seconds it will
|
||||
// spend much time displaying the overlay screen. If GUM is not resolved within 15 seconds it will
|
||||
// probably never resolve.
|
||||
const timeout = browser.isElectron() ? 15000 : 60000;
|
||||
|
||||
@@ -519,8 +518,10 @@ export default {
|
||||
|
||||
return createLocalTracksF({
|
||||
devices: [ 'audio' ],
|
||||
timeout
|
||||
}, true)
|
||||
timeout,
|
||||
firePermissionPromptIsShownEvent: true,
|
||||
fireSlowPromiseEvent: true
|
||||
})
|
||||
.then(([ audioStream ]) =>
|
||||
[ desktopStream, audioStream ])
|
||||
.catch(error => {
|
||||
@@ -536,8 +537,10 @@ export default {
|
||||
return requestedAudio
|
||||
? createLocalTracksF({
|
||||
devices: [ 'audio' ],
|
||||
timeout
|
||||
}, true)
|
||||
timeout,
|
||||
firePermissionPromptIsShownEvent: true,
|
||||
fireSlowPromiseEvent: true
|
||||
})
|
||||
: [];
|
||||
})
|
||||
.catch(error => {
|
||||
@@ -551,8 +554,10 @@ export default {
|
||||
} else {
|
||||
tryCreateLocalTracks = createLocalTracksF({
|
||||
devices: initialDevices,
|
||||
timeout
|
||||
}, true)
|
||||
timeout,
|
||||
firePermissionPromptIsShownEvent: true,
|
||||
fireSlowPromiseEvent: true
|
||||
})
|
||||
.catch(err => {
|
||||
if (requestedAudio && requestedVideo) {
|
||||
|
||||
@@ -561,7 +566,7 @@ export default {
|
||||
|
||||
if (err.name === JitsiTrackErrors.TIMEOUT && !browser.isElectron()) {
|
||||
// In this case we expect that the permission prompt is still visible. There is no point of
|
||||
// executing GUM with different source. Also at the time of writting the following
|
||||
// executing GUM with different source. Also at the time of writing the following
|
||||
// inconsistency have been noticed in some browsers - if the permissions prompt is visible
|
||||
// and another GUM is executed the prompt does not change its content but if the user
|
||||
// clicks allow the user action isassociated with the latest GUM call.
|
||||
@@ -574,8 +579,10 @@ export default {
|
||||
return (
|
||||
createLocalTracksF({
|
||||
devices: [ 'audio' ],
|
||||
timeout
|
||||
}, true));
|
||||
timeout,
|
||||
firePermissionPromptIsShownEvent: true,
|
||||
fireSlowPromiseEvent: true
|
||||
}));
|
||||
} else if (requestedAudio && !requestedVideo) {
|
||||
errors.audioOnlyError = err;
|
||||
|
||||
@@ -598,8 +605,9 @@ export default {
|
||||
return requestedVideo
|
||||
? createLocalTracksF({
|
||||
devices: [ 'video' ],
|
||||
timeout
|
||||
}, true)
|
||||
firePermissionPromptIsShownEvent: true,
|
||||
fireSlowPromiseEvent: true
|
||||
})
|
||||
: [];
|
||||
})
|
||||
.catch(err => {
|
||||
@@ -615,10 +623,11 @@ export default {
|
||||
|
||||
// Hide the permissions prompt/overlay as soon as the tracks are
|
||||
// created. Don't wait for the connection to be made, since in some
|
||||
// cases, when auth is rquired, for instance, that won't happen until
|
||||
// cases, when auth is required, for instance, that won't happen until
|
||||
// the user inputs their credentials, but the dialog would be
|
||||
// overshadowed by the overlay.
|
||||
tryCreateLocalTracks.then(tracks => {
|
||||
APP.store.dispatch(toggleSlowGUMOverlay(false));
|
||||
APP.store.dispatch(mediaPermissionPromptVisibilityChanged(false));
|
||||
|
||||
return tracks;
|
||||
@@ -809,12 +818,16 @@ export default {
|
||||
return this._setLocalAudioVideoStreams(tracks);
|
||||
}
|
||||
|
||||
const [ tracks, con ] = await this.createInitialLocalTracksAndConnect(
|
||||
roomName, initialOptions);
|
||||
const [ tracks, con ] = await this.createInitialLocalTracksAndConnect(roomName, initialOptions);
|
||||
let localTracks = tracks;
|
||||
|
||||
this._initDeviceList(true);
|
||||
|
||||
return this.startConference(con, tracks);
|
||||
if (initialOptions.startWithAudioMuted) {
|
||||
localTracks = localTracks.filter(track => track.getType() !== MEDIA_TYPE.AUDIO);
|
||||
}
|
||||
|
||||
return this.startConference(con, localTracks);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -882,7 +895,7 @@ export default {
|
||||
showUI && APP.store.dispatch(notifyMicError(error));
|
||||
};
|
||||
|
||||
createLocalTracksF({ devices: [ 'audio' ] }, false)
|
||||
createLocalTracksF({ devices: [ 'audio' ] })
|
||||
.then(([ audioTrack ]) => audioTrack)
|
||||
.catch(error => {
|
||||
maybeShowErrorDialog(error);
|
||||
@@ -996,7 +1009,7 @@ export default {
|
||||
//
|
||||
// FIXME when local track creation is moved to react/redux
|
||||
// it should take care of the use case described above
|
||||
createLocalTracksF({ devices: [ 'video' ] }, false)
|
||||
createLocalTracksF({ devices: [ 'video' ] })
|
||||
.then(([ videoTrack ]) => videoTrack)
|
||||
.catch(error => {
|
||||
// FIXME should send some feedback to the API on error ?
|
||||
@@ -1005,7 +1018,11 @@ export default {
|
||||
// Rollback the video muted status by using null track
|
||||
return null;
|
||||
})
|
||||
.then(videoTrack => this.useVideoStream(videoTrack));
|
||||
.then(videoTrack => {
|
||||
logger.debug(`muteVideo: calling useVideoStream for track: ${videoTrack}`);
|
||||
|
||||
return this.useVideoStream(videoTrack);
|
||||
});
|
||||
} else {
|
||||
// FIXME show error dialog if it fails (should be handled by react)
|
||||
muteLocalVideo(mute);
|
||||
@@ -1305,7 +1322,11 @@ export default {
|
||||
this._getConferenceOptions());
|
||||
|
||||
APP.store.dispatch(conferenceWillJoin(room));
|
||||
this._setLocalAudioVideoStreams(localTracks);
|
||||
|
||||
// Filter out the tracks that are muted.
|
||||
const tracks = localTracks.filter(track => !track.isMuted());
|
||||
|
||||
this._setLocalAudioVideoStreams(tracks);
|
||||
this._room = room; // FIXME do not use this
|
||||
|
||||
sendLocalParticipant(APP.store, room);
|
||||
@@ -1324,8 +1345,11 @@ export default {
|
||||
if (track.isAudioTrack()) {
|
||||
return this.useAudioStream(track);
|
||||
} else if (track.isVideoTrack()) {
|
||||
logger.debug(`_setLocalAudioVideoStreams is calling useVideoStream with track: ${track}`);
|
||||
|
||||
return this.useVideoStream(track);
|
||||
}
|
||||
|
||||
logger.error(
|
||||
'Ignored not an audio nor a video track: ', track);
|
||||
|
||||
@@ -1345,6 +1369,8 @@ export default {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
useVideoStream(newTrack) {
|
||||
logger.debug(`useVideoStream: ${newTrack}`);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
_replaceLocalVideoTrackQueue.enqueue(onFinish => {
|
||||
const state = APP.store.getState();
|
||||
@@ -1354,24 +1380,30 @@ export default {
|
||||
if (isPrejoinPageVisible(state)) {
|
||||
const oldTrack = getLocalJitsiVideoTrack(state);
|
||||
|
||||
logger.debug(`useVideoStream on the prejoin screen: Replacing ${oldTrack} with ${newTrack}`);
|
||||
|
||||
return APP.store.dispatch(replaceLocalTrack(oldTrack, newTrack))
|
||||
.then(resolve)
|
||||
.catch(reject)
|
||||
.catch(error => {
|
||||
logger.error(`useVideoStream failed on the prejoin screen: ${error}`);
|
||||
reject(error);
|
||||
})
|
||||
.then(onFinish);
|
||||
}
|
||||
|
||||
logger.debug(`useVideoStream: Replacing ${this.localVideo} with ${newTrack}`);
|
||||
APP.store.dispatch(
|
||||
replaceLocalTrack(this.localVideo, newTrack, room))
|
||||
replaceLocalTrack(this.localVideo, newTrack, room))
|
||||
.then(() => {
|
||||
this.localVideo = newTrack;
|
||||
this._setSharingScreen(newTrack);
|
||||
if (newTrack) {
|
||||
APP.UI.addLocalVideoStream(newTrack);
|
||||
}
|
||||
this.setVideoMuteStatus(this.isLocalVideoMuted());
|
||||
})
|
||||
.then(resolve)
|
||||
.catch(reject)
|
||||
.catch(error => {
|
||||
logger.error(`useVideoStream failed: ${error}`);
|
||||
reject(error);
|
||||
})
|
||||
.then(onFinish);
|
||||
});
|
||||
});
|
||||
@@ -1516,9 +1548,15 @@ export default {
|
||||
this._desktopAudioStream = undefined;
|
||||
}
|
||||
|
||||
APP.store.dispatch(setScreenAudioShareState(false));
|
||||
|
||||
if (didHaveVideo) {
|
||||
promise = promise.then(() => createLocalTracksF({ devices: [ 'video' ] }))
|
||||
.then(([ stream ]) => this.useVideoStream(stream))
|
||||
.then(([ stream ]) => {
|
||||
logger.debug(`_turnScreenSharingOff using ${stream} for useVideoStream`);
|
||||
|
||||
return this.useVideoStream(stream);
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('failed to switch back to local video', error);
|
||||
|
||||
@@ -1529,7 +1567,11 @@ export default {
|
||||
);
|
||||
});
|
||||
} else {
|
||||
promise = promise.then(() => this.useVideoStream(null));
|
||||
promise = promise.then(() => {
|
||||
logger.debug('_turnScreenSharingOff using null for useVideoStream');
|
||||
|
||||
return this.useVideoStream(null);
|
||||
});
|
||||
}
|
||||
|
||||
return promise.then(
|
||||
@@ -1540,6 +1582,8 @@ export default {
|
||||
},
|
||||
error => {
|
||||
this.videoSwitchInProgress = false;
|
||||
logger.error(`_turnScreenSharingOff failed: ${error}`);
|
||||
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
@@ -1560,6 +1604,7 @@ export default {
|
||||
* @return {Promise.<T>}
|
||||
*/
|
||||
async toggleScreenSharing(toggle = !this._untoggleScreenSharing, options = {}) {
|
||||
logger.debug(`toggleScreenSharing: ${toggle}`);
|
||||
if (this.videoSwitchInProgress) {
|
||||
return Promise.reject('Switch in progress.');
|
||||
}
|
||||
@@ -1621,11 +1666,30 @@ export default {
|
||||
= this._turnScreenSharingOff.bind(this, didHaveVideo);
|
||||
|
||||
const desktopVideoStream = desktopStreams.find(stream => stream.getType() === MEDIA_TYPE.VIDEO);
|
||||
const dekstopAudioStream = desktopStreams.find(stream => stream.getType() === MEDIA_TYPE.AUDIO);
|
||||
|
||||
if (dekstopAudioStream) {
|
||||
dekstopAudioStream.on(
|
||||
JitsiTrackEvents.LOCAL_TRACK_STOPPED,
|
||||
() => {
|
||||
logger.debug(`Local screensharing audio track stopped. ${this.isSharingScreen}`);
|
||||
|
||||
// Handle case where screen share was stopped from the browsers 'screen share in progress'
|
||||
// window. If audio screen sharing is stopped via the normal UX flow this point shouldn't
|
||||
// be reached.
|
||||
isScreenAudioShared(APP.store.getState())
|
||||
&& this._untoggleScreenSharing
|
||||
&& this._untoggleScreenSharing();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (desktopVideoStream) {
|
||||
desktopVideoStream.on(
|
||||
JitsiTrackEvents.LOCAL_TRACK_STOPPED,
|
||||
() => {
|
||||
logger.debug(`Local screensharing track stopped. ${this.isSharingScreen}`);
|
||||
|
||||
// If the stream was stopped during screen sharing
|
||||
// session then we should switch back to video.
|
||||
this.isSharingScreen
|
||||
@@ -1729,7 +1793,7 @@ export default {
|
||||
};
|
||||
}
|
||||
|
||||
// Apply the contraints on the desktop track.
|
||||
// Apply the constraints on the desktop track.
|
||||
try {
|
||||
await this.localVideo.track.applyConstraints(desktopResizeConstraints);
|
||||
} catch (err) {
|
||||
@@ -1787,13 +1851,28 @@ export default {
|
||||
|
||||
return this._createDesktopTrack(options)
|
||||
.then(async streams => {
|
||||
const desktopVideoStream = streams.find(stream => stream.getType() === MEDIA_TYPE.VIDEO);
|
||||
let desktopVideoStream = streams.find(stream => stream.getType() === MEDIA_TYPE.VIDEO);
|
||||
|
||||
this._desktopAudioStream = streams.find(stream => stream.getType() === MEDIA_TYPE.AUDIO);
|
||||
|
||||
const { audioOnly = false } = options;
|
||||
|
||||
// If we're in audio only mode dispose of the video track otherwise the screensharing state will be
|
||||
// inconsistent.
|
||||
if (audioOnly) {
|
||||
desktopVideoStream.dispose();
|
||||
desktopVideoStream = undefined;
|
||||
|
||||
if (!this._desktopAudioStream) {
|
||||
return Promise.reject(AUDIO_ONLY_SCREEN_SHARE_NO_TRACK);
|
||||
}
|
||||
}
|
||||
|
||||
if (desktopVideoStream) {
|
||||
logger.debug(`_switchToScreenSharing is using ${desktopVideoStream} for useVideoStream`);
|
||||
await this.useVideoStream(desktopVideoStream);
|
||||
}
|
||||
|
||||
this._desktopAudioStream = streams.find(stream => stream.getType() === MEDIA_TYPE.AUDIO);
|
||||
|
||||
if (this._desktopAudioStream) {
|
||||
// If there is a localAudio stream, mix in the desktop audio stream captured by the screen sharing
|
||||
@@ -1806,7 +1885,9 @@ export default {
|
||||
// If no local stream is present ( i.e. no input audio devices) we use the screen share audio
|
||||
// stream as we would use a regular stream.
|
||||
await this.useAudioStream(this._desktopAudioStream);
|
||||
|
||||
}
|
||||
APP.store.dispatch(setScreenAudioShareState(true));
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
@@ -1874,6 +1955,9 @@ export default {
|
||||
} else if (error.name === JitsiTrackErrors.SCREENSHARING_GENERIC_ERROR) {
|
||||
descriptionKey = 'dialog.screenSharingFailed';
|
||||
titleKey = 'dialog.screenSharingFailedTitle';
|
||||
} else if (error === AUDIO_ONLY_SCREEN_SHARE_NO_TRACK) {
|
||||
descriptionKey = 'notify.screenShareNoAudio';
|
||||
titleKey = 'notify.screenShareNoAudioTitle';
|
||||
}
|
||||
|
||||
APP.UI.messageHandler.showError({
|
||||
@@ -1919,7 +2003,7 @@ export default {
|
||||
}
|
||||
|
||||
APP.store.dispatch(updateRemoteParticipantFeatures(user));
|
||||
logger.log(`USER ${id} connnected:`, user);
|
||||
logger.log(`USER ${id} connected:`, user);
|
||||
APP.UI.addUser(user);
|
||||
});
|
||||
|
||||
@@ -1993,7 +2077,11 @@ export default {
|
||||
|
||||
room.on(JitsiConferenceEvents.TRACK_MUTE_CHANGED, (track, participantThatMutedUs) => {
|
||||
if (participantThatMutedUs) {
|
||||
APP.store.dispatch(participantMutedUs(participantThatMutedUs));
|
||||
APP.store.dispatch(participantMutedUs(participantThatMutedUs, track));
|
||||
if (this.isSharingScreen && track.isVideoTrack()) {
|
||||
logger.debug('TRACK_MUTE_CHANGED while screen sharing');
|
||||
this._turnScreenSharingOff(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2145,8 +2233,26 @@ export default {
|
||||
}
|
||||
);
|
||||
room.on(JitsiConferenceEvents.STARTED_MUTED, () => {
|
||||
(room.isStartAudioMuted() || room.isStartVideoMuted())
|
||||
&& APP.UI.notifyInitiallyMuted();
|
||||
const audioMuted = room.isStartAudioMuted();
|
||||
const videoMuted = room.isStartVideoMuted();
|
||||
const localTracks = getLocalTracks(APP.store.getState()['features/base/tracks']);
|
||||
const promises = [];
|
||||
|
||||
APP.store.dispatch(setAudioMuted(audioMuted));
|
||||
APP.store.dispatch(setVideoMuted(videoMuted));
|
||||
|
||||
// Remove the tracks from the peerconnection.
|
||||
for (const track of localTracks) {
|
||||
if (audioMuted && track.jitsiTrack?.getType() === MEDIA_TYPE.AUDIO) {
|
||||
promises.push(this.useAudioStream(null));
|
||||
}
|
||||
if (videoMuted && track.jitsiTrack?.getType() === MEDIA_TYPE.VIDEO) {
|
||||
promises.push(this.useVideoStream(null));
|
||||
}
|
||||
}
|
||||
|
||||
Promise.allSettled(promises)
|
||||
.then(() => APP.UI.notifyInitiallyMuted());
|
||||
});
|
||||
|
||||
room.on(
|
||||
@@ -2172,7 +2278,7 @@ export default {
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.AUTH_CLICKED, () => {
|
||||
AuthHandler.authenticate(room);
|
||||
AuthHandler.authenticateExternal(room);
|
||||
});
|
||||
|
||||
APP.UI.addListener(
|
||||
@@ -2197,7 +2303,7 @@ export default {
|
||||
.then(effect => this.localVideo.setEffect(effect))
|
||||
.then(() => {
|
||||
this.setVideoMuteStatus(false);
|
||||
logger.log('switched local video device');
|
||||
logger.log('Switched local video device while screen sharing and the video is unmuted');
|
||||
this._updateVideoDeviceId();
|
||||
})
|
||||
.catch(err => APP.store.dispatch(notifyCameraError(err)));
|
||||
@@ -2206,7 +2312,7 @@ export default {
|
||||
// id for video, dispose the existing presenter track and create a new effect
|
||||
// that can be applied on un-mute.
|
||||
} else if (this.isSharingScreen && videoWasMuted) {
|
||||
logger.log('switched local video device');
|
||||
logger.log('Switched local video device: while screen sharing and the video is muted');
|
||||
const { height } = this.localVideo.track.getSettings();
|
||||
|
||||
this._updateVideoDeviceId();
|
||||
@@ -2233,12 +2339,20 @@ export default {
|
||||
|
||||
return stream;
|
||||
})
|
||||
.then(stream => this.useVideoStream(stream))
|
||||
.then(stream => {
|
||||
logger.log('Switching the local video device.');
|
||||
|
||||
return this.useVideoStream(stream);
|
||||
})
|
||||
.then(() => {
|
||||
logger.log('switched local video device');
|
||||
logger.log('Switched local video device.');
|
||||
this._updateVideoDeviceId();
|
||||
})
|
||||
.catch(err => APP.store.dispatch(notifyCameraError(err)));
|
||||
.catch(error => {
|
||||
logger.error(`Switching the local video device failed: ${error}`);
|
||||
|
||||
return APP.store.dispatch(notifyCameraError(error));
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -2327,11 +2441,17 @@ export default {
|
||||
// There is no guarantee another event will trigger the update
|
||||
// immediately and in all situations, for example because a remote
|
||||
// participant is having connection trouble so no status changes.
|
||||
APP.UI.updateAllVideos();
|
||||
const displayedUserId = APP.UI.getLargeVideoID();
|
||||
|
||||
if (displayedUserId) {
|
||||
APP.UI.updateLargeVideo(displayedUserId, true);
|
||||
}
|
||||
});
|
||||
|
||||
APP.UI.addListener(
|
||||
UIEvents.TOGGLE_SCREENSHARING, this.toggleScreenSharing.bind(this)
|
||||
UIEvents.TOGGLE_SCREENSHARING, audioOnly => {
|
||||
this.toggleScreenSharing(undefined, { audioOnly });
|
||||
}
|
||||
);
|
||||
|
||||
/* eslint-disable max-params */
|
||||
@@ -2590,6 +2710,7 @@ export default {
|
||||
delete newDevices.videoinput;
|
||||
|
||||
// Removing the current video track in order to force the unmute to select the preferred device.
|
||||
logger.debug('_onDeviceListChanged: Removing the current video track.');
|
||||
this.useVideoStream(null);
|
||||
|
||||
}
|
||||
|
||||
57
config.js
57
config.js
@@ -123,7 +123,7 @@ var config = {
|
||||
// opusMaxAverageBitrate: 20000,
|
||||
|
||||
// Enables support for opus-red (redundancy for Opus).
|
||||
// enableOpusRed: false
|
||||
// enableOpusRed: false,
|
||||
|
||||
// Video
|
||||
|
||||
@@ -240,6 +240,12 @@ var config = {
|
||||
// 90: 2
|
||||
// },
|
||||
|
||||
// Provides a way to translate the legacy bridge signaling messages, 'LastNChangedEvent',
|
||||
// 'SelectedEndpointsChangedEvent' and 'ReceiverVideoConstraint' into the new 'ReceiverVideoConstraints' message
|
||||
// that invokes the new bandwidth allocation algorithm in the bridge which is described here
|
||||
// - https://github.com/jitsi/jitsi-videobridge/blob/master/doc/allocation.md.
|
||||
// useNewBandwidthAllocationStrategy: false,
|
||||
|
||||
// Specify the settings for video quality optimizations on the client.
|
||||
// videoQuality: {
|
||||
// // Provides a way to prevent a video codec from being negotiated on the JVB connection. The codec specified
|
||||
@@ -406,7 +412,26 @@ var config = {
|
||||
// enableAutomaticUrlCopy: false,
|
||||
|
||||
// Base URL for a Gravatar-compatible service. Defaults to libravatar.
|
||||
// gravatarBaseURL: 'https://seccdn.libravatar.org/avatar/';
|
||||
// gravatarBaseURL: 'https://seccdn.libravatar.org/avatar/',
|
||||
|
||||
// Moved from interfaceConfig(TOOLBAR_BUTTONS).
|
||||
// The name of the toolbar buttons to display in the toolbar, including the
|
||||
// "More actions" menu. If present, the button will display. Exceptions are
|
||||
// "livestreaming" and "recording" which also require being a moderator and
|
||||
// some other values in config.js to be enabled. Also, the "profile" button will
|
||||
// not display for users with a JWT.
|
||||
// Notes:
|
||||
// - it's impossible to choose which buttons go in the "More actions" menu
|
||||
// - it's impossible to control the placement of buttons
|
||||
// - 'desktop' controls the "Share your screen" button
|
||||
// - if `toolbarButtons` is undefined, we fallback to enabling all buttons on the UI
|
||||
// toolbarButtons: [
|
||||
// 'microphone', 'camera', 'closedcaptions', 'desktop', 'embedmeeting', 'fullscreen',
|
||||
// 'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
|
||||
// 'livestreaming', 'etherpad', 'sharedvideo', 'shareaudio', 'settings', 'raisehand',
|
||||
// 'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
|
||||
// 'tileview', 'select-background', 'download', 'help', 'mute-everyone', 'mute-video-everyone', 'security'
|
||||
// ],
|
||||
|
||||
// Stats
|
||||
//
|
||||
@@ -431,6 +456,10 @@ var config = {
|
||||
// Enables sending participants' emails (if available) to callstats and other analytics
|
||||
// enableEmailInStats: false,
|
||||
|
||||
// Controls the percentage of automatic feedback shown to participants when callstats is enabled.
|
||||
// The default value is 100%. If set to 0, no automatic feedback will be requested
|
||||
// feedbackPercentage: 100,
|
||||
|
||||
// Privacy
|
||||
//
|
||||
|
||||
@@ -469,7 +498,7 @@ var config = {
|
||||
|
||||
// If set to true, it will prefer to use H.264 for P2P calls (if H.264
|
||||
// is supported). This setting is deprecated, use preferredCodec instead.
|
||||
// preferH264: true
|
||||
// preferH264: true,
|
||||
|
||||
// Provides a way to set the video codec preference on the p2p connection. Acceptable
|
||||
// codec values are 'VP8', 'VP9' and 'H264'.
|
||||
@@ -511,7 +540,7 @@ var config = {
|
||||
// The interval at which rtcstats will poll getStats, defaults to 1000ms.
|
||||
// If the value is set to 0 getStats won't be polled and the rtcstats client
|
||||
// will only send data related to RTCPeerConnection events.
|
||||
// rtcstatsPolIInterval: 1000
|
||||
// rtcstatsPolIInterval: 1000,
|
||||
|
||||
// Array of script URLs to load as lib-jitsi-meet "analytics handlers".
|
||||
// scriptURLs: [
|
||||
@@ -534,6 +563,10 @@ var config = {
|
||||
// Decides whether the start/stop recording audio notifications should play on record.
|
||||
// disableRecordAudioNotification: false,
|
||||
|
||||
// Disables the sounds that play when other participants join or leave the
|
||||
// conference (if set to true, these sounds will not be played).
|
||||
// disableJoinLeaveSounds: false,
|
||||
|
||||
// Information for the chrome extension banner
|
||||
// chromeExtensionBanner: {
|
||||
// // The chrome extension to be installed address
|
||||
@@ -593,6 +626,10 @@ var config = {
|
||||
// the menu has option to flip the locally seen video for local presentations
|
||||
// disableLocalVideoFlip: false,
|
||||
|
||||
// A property used to unset the default flip state of the local video.
|
||||
// When it is set to 'true', the local(self) video will not be mirrored anymore.
|
||||
// doNotFlipLocalVideo: false,
|
||||
|
||||
// Mainly privacy related settings
|
||||
|
||||
// Disables all invite functions from the app (share, invite, dial out...etc)
|
||||
@@ -640,6 +677,9 @@ var config = {
|
||||
*/
|
||||
// dynamicBrandingUrl: '',
|
||||
|
||||
// Sets the background transparency level. '0' is fully transparent, '1' is opaque.
|
||||
// backgroundAlpha: 1,
|
||||
|
||||
// The URL of the moderated rooms microservice, if available. If it
|
||||
// is present, a link to the service will be rendered on the welcome page,
|
||||
// otherwise the app doesn't render it.
|
||||
@@ -649,17 +689,22 @@ var config = {
|
||||
// disableTileView: true,
|
||||
|
||||
// Hides the conference subject
|
||||
// hideConferenceSubject: true
|
||||
// hideConferenceSubject: true,
|
||||
|
||||
// Hides the conference timer.
|
||||
// hideConferenceTimer: true,
|
||||
|
||||
// Hides the participants stats
|
||||
// hideParticipantsStats: true
|
||||
// hideParticipantsStats: true,
|
||||
|
||||
// Sets the conference subject
|
||||
// subject: 'Conference Subject',
|
||||
|
||||
// This property is related to the use case when jitsi-meet is used via the IFrame API. When the property is true
|
||||
// jitsi-meet will use the local storage of the host page instead of its own. This option is useful if the browser
|
||||
// is not persisting the local storage inside the iframe.
|
||||
// useHostPageLocalStorage: true,
|
||||
|
||||
// List of undocumented settings used in jitsi-meet
|
||||
/**
|
||||
_immediateReloadThreshold
|
||||
|
||||
@@ -3,18 +3,21 @@
|
||||
import { jitsiLocalStorage } from '@jitsi/js-utils';
|
||||
import Logger from 'jitsi-meet-logger';
|
||||
|
||||
import AuthHandler from './modules/UI/authentication/AuthHandler';
|
||||
import { redirectToTokenAuthService } from './modules/UI/authentication/AuthHandler';
|
||||
import { hideLoginDialog } from './react/features/authentication/actions.web';
|
||||
import { LoginDialog } from './react/features/authentication/components';
|
||||
import { isTokenAuthEnabled } from './react/features/authentication/functions';
|
||||
import {
|
||||
connectionEstablished,
|
||||
connectionFailed
|
||||
} from './react/features/base/connection/actions';
|
||||
import { openDialog } from './react/features/base/dialog/actions';
|
||||
import {
|
||||
isFatalJitsiConnectionError,
|
||||
JitsiConnectionErrors,
|
||||
JitsiConnectionEvents
|
||||
} from './react/features/base/lib-jitsi-meet';
|
||||
import { setPrejoinDisplayNameRequired } from './react/features/prejoin/actions';
|
||||
|
||||
const logger = Logger.getLogger(__filename);
|
||||
|
||||
/**
|
||||
@@ -80,7 +83,7 @@ function checkForAttachParametersAndConnect(id, password, connection) {
|
||||
* @returns {Promise<JitsiConnection>} connection if
|
||||
* everything is ok, else error.
|
||||
*/
|
||||
function connect(id, password, roomName) {
|
||||
export function connect(id, password, roomName) {
|
||||
const connectionConfig = Object.assign({}, config);
|
||||
const { jwt } = APP.store.getState()['features/base/jwt'];
|
||||
|
||||
@@ -214,10 +217,39 @@ export function openConnection({ id, password, retry, roomName }) {
|
||||
const { jwt } = APP.store.getState()['features/base/jwt'];
|
||||
|
||||
if (err === JitsiConnectionErrors.PASSWORD_REQUIRED && !jwt) {
|
||||
return AuthHandler.requestAuth(roomName, connect);
|
||||
return requestAuth(roomName);
|
||||
}
|
||||
}
|
||||
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show Authentication Dialog and try to connect with new credentials.
|
||||
* If failed to connect because of PASSWORD_REQUIRED error
|
||||
* then ask for password again.
|
||||
* @param {string} [roomName] name of the conference room
|
||||
*
|
||||
* @returns {Promise<JitsiConnection>}
|
||||
*/
|
||||
function requestAuth(roomName) {
|
||||
const config = APP.store.getState()['features/base/config'];
|
||||
|
||||
if (isTokenAuthEnabled(config)) {
|
||||
// This Promise never resolves as user gets redirected to another URL
|
||||
return new Promise(() => redirectToTokenAuthService(roomName));
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
const onSuccess = connection => {
|
||||
APP.store.dispatch(hideLoginDialog());
|
||||
resolve(connection);
|
||||
};
|
||||
|
||||
APP.store.dispatch(
|
||||
openDialog(LoginDialog, { onSuccess,
|
||||
roomName })
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
/**
|
||||
* Mixins that mimic the way Atlaskit fills the screen with modals at low screen widths.
|
||||
*/
|
||||
@mixin full-size-modal-positioner() {
|
||||
height: 100%;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@mixin full-size-modal-dialog() {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the @atlaskit/flag container up a little bit so it does not cover the
|
||||
* toolbar with the first notification.
|
||||
@@ -54,6 +72,63 @@
|
||||
* Keep overflow menu within screen vertical bounds and make it scrollable.
|
||||
*/
|
||||
.toolbox-button-wth-dialog > div:nth-child(2) {
|
||||
background: $menuBG;
|
||||
max-height: calc(100vh - #{$newToolbarSizeWithPadding} - 46px);
|
||||
margin-bottom: 4px;
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.audio-preview > div:nth-child(2),
|
||||
.video-preview > div:nth-child(2) {
|
||||
margin-bottom: 4px;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The following selectors keep the chat modal full-size anywhere between 100px
|
||||
* and 580px for desktop or 680px for mobile.
|
||||
*/
|
||||
@media (min-width: 100px) and (max-width: 320px) {
|
||||
.smiley-input {
|
||||
display: none;
|
||||
}
|
||||
.shift-right .focus-lock > div > div {
|
||||
@include full-size-modal-positioner();
|
||||
}
|
||||
|
||||
.shift-right .focus-lock [role="dialog"] {
|
||||
@include full-size-modal-dialog();
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 480px) and (max-width: 580px) {
|
||||
.shift-right .focus-lock > div > div {
|
||||
@include full-size-modal-positioner();
|
||||
}
|
||||
|
||||
.shift-right .focus-lock [role="dialog"] {
|
||||
@include full-size-modal-dialog();
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 580px) {
|
||||
// Override Atlaskit inline style for the modal background.
|
||||
// Important is unfortunately needed for that.
|
||||
.shift-right .focus-lock [role="dialog"][style] {
|
||||
background-color: $chatBackgroundColor !important;
|
||||
}
|
||||
|
||||
// Remove Atlaskit padding from the chat dialog.
|
||||
.shift-right .focus-lock [role="dialog"] > div:first-child > div:nth-child(2) {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
div.Tooltip {
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
@@ -1,26 +1,37 @@
|
||||
.audio-preview {
|
||||
display: inline-block;
|
||||
|
||||
&-content {
|
||||
background: #2A3A4B;
|
||||
font-size: 15px;
|
||||
background: $menuBG;
|
||||
border-radius: 3px;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
max-height: 456px;
|
||||
overflow: auto;
|
||||
width: 328px;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
&-header {
|
||||
color: #fff;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
margin-top: 8px;
|
||||
padding: 8px 16px;
|
||||
|
||||
&-icon {
|
||||
color: #A4B8D1;
|
||||
display: inline-block;
|
||||
|
||||
svg {
|
||||
fill: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&--bordered {
|
||||
border-bottom: 1px solid #4C4D50;
|
||||
}
|
||||
|
||||
&-text {
|
||||
font-weight: bold;
|
||||
margin-left: 8px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,19 +40,18 @@
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
padding: 12px 0;
|
||||
padding: 8px 0;
|
||||
margin-left: 48px;
|
||||
|
||||
&--selected {
|
||||
background: #1C2025;
|
||||
background: #131519;
|
||||
cursor: initial;
|
||||
margin-left: 0;
|
||||
padding-left: 21px;
|
||||
padding-left: 18px;
|
||||
}
|
||||
|
||||
&-text {
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
display: inline-block;
|
||||
line-height: 24px;
|
||||
text-overflow: ellipsis;
|
||||
@@ -56,12 +66,13 @@
|
||||
|
||||
&:hover {
|
||||
.audio-preview-entry {
|
||||
background: #3F4E5E;
|
||||
background: #36383C;
|
||||
margin-left: 0;
|
||||
padding-left: 48px;
|
||||
|
||||
&--selected {
|
||||
padding-left: 21px;
|
||||
padding-left: 18px;
|
||||
background: $newToolbarBackgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +85,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.audio-preview-entry-text {
|
||||
max-width: 256px;
|
||||
}
|
||||
@@ -84,18 +99,19 @@
|
||||
|
||||
&:hover {
|
||||
.audio-preview-entry {
|
||||
background: #3F4E5E;
|
||||
background: #36383C;
|
||||
margin-left: 0;
|
||||
padding-left: 48px;
|
||||
|
||||
&--selected {
|
||||
padding-left: 21px;
|
||||
background: $newToolbarBackgroundColor;
|
||||
padding-left: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.audio-preview-entry-text {
|
||||
max-width: 196px;
|
||||
max-width: 178px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +126,7 @@
|
||||
|
||||
&--check {
|
||||
background: #31B76A;
|
||||
margin-right: 13px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
&--exclamation {
|
||||
@@ -121,6 +137,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-hr {
|
||||
border-top: 1px solid #4C4D50;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
&-test-button {
|
||||
display: none;
|
||||
background: #FFF;
|
||||
@@ -129,23 +150,16 @@
|
||||
color: #1C2025;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
padding: 4px 16px;
|
||||
padding: 2px 16px;
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 8px;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
&-meter-mic {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 18px;
|
||||
}
|
||||
|
||||
// Override @atlaskit/InlineDialog container which is made with styled components
|
||||
& > div:nth-child(2) {
|
||||
outline: none;
|
||||
padding: 0;
|
||||
top: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,10 @@ body {
|
||||
fill: white;
|
||||
}
|
||||
|
||||
.disabled .jitsi-icon svg {
|
||||
fill: #929292;
|
||||
}
|
||||
|
||||
.jitsi-icon.gray svg {
|
||||
fill: #5E6D7A;
|
||||
cursor: pointer;
|
||||
|
||||
174
css/_chat.scss
174
css/_chat.scss
@@ -1,5 +1,5 @@
|
||||
#sideToolbarContainer {
|
||||
background-color: $newToolbarBackgroundColor;
|
||||
background-color: $chatBackgroundColor;
|
||||
box-sizing: border-box;
|
||||
color: #FFF;
|
||||
display: flex;
|
||||
@@ -32,6 +32,13 @@
|
||||
width: $sidebarWidth;
|
||||
word-wrap: break-word;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
& > :first-child {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
}
|
||||
@@ -98,13 +105,12 @@
|
||||
}
|
||||
|
||||
.chat-header {
|
||||
background-color: $chatHeaderBackgroundColor;
|
||||
height: 70px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
justify-content: flex-end;
|
||||
padding: 16px;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
@@ -116,22 +122,85 @@
|
||||
.jitsi-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.jitsi-icon > svg {
|
||||
fill: #A4B8D1;
|
||||
.chat-input-container {
|
||||
padding: 0 16px 16px;
|
||||
|
||||
&.populated {
|
||||
#chat-input {
|
||||
.send-button {
|
||||
background: #1B67EC;
|
||||
cursor: pointer;
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
background: #3D82FB;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: #0852D4;
|
||||
}
|
||||
|
||||
path {
|
||||
fill: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#chat-input {
|
||||
border-top: 1px solid $chatInputSeparatorColor;
|
||||
border: 1px solid $chatInputSeparatorColor;
|
||||
display: flex;
|
||||
padding: 5px 10px;
|
||||
padding: 4px;
|
||||
border-radius: 3px;
|
||||
|
||||
&:focus-within {
|
||||
border: 1px solid #619CF4;
|
||||
}
|
||||
|
||||
* {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.send-button-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.send-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border-radius: 3px;
|
||||
|
||||
path {
|
||||
fill: $chatInputSeparatorColor;
|
||||
}
|
||||
}
|
||||
|
||||
.smiley-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#chat-input .smiley-button {
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
background-color: #484A4F;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remoteuser {
|
||||
color: #B8C7E0;
|
||||
}
|
||||
@@ -145,7 +214,7 @@
|
||||
border-radius:0;
|
||||
box-shadow: none;
|
||||
color: white;
|
||||
font-size: 15px;
|
||||
font-size: 14px;
|
||||
padding: 10px;
|
||||
overflow-y: auto;
|
||||
resize: none;
|
||||
@@ -161,10 +230,55 @@
|
||||
#nickname {
|
||||
text-align: center;
|
||||
color: #9d9d9d;
|
||||
font-size: 18px;
|
||||
margin-top: 30px;
|
||||
left: 5px;
|
||||
right: 5px;
|
||||
font-size: 16px;
|
||||
margin: auto 0;
|
||||
padding: 0 16px;
|
||||
|
||||
input {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
label {
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.enter-chat {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 16px;
|
||||
height: 40px;
|
||||
background: #1B67EC;
|
||||
border-radius: 3px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
|
||||
&.disabled {
|
||||
color: #757575;
|
||||
background: #11336E;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-browser {
|
||||
#nickname {
|
||||
input {
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.enter-chat {
|
||||
height: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
#usermsg {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.chatmessage .usermessage {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.sideToolbarContainer {
|
||||
@@ -174,8 +288,8 @@
|
||||
}
|
||||
|
||||
.display-name {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 5px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
@@ -203,6 +317,7 @@
|
||||
|
||||
.usermessage {
|
||||
white-space: pre-wrap;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&.error {
|
||||
@@ -225,12 +340,16 @@
|
||||
}
|
||||
|
||||
.messagecontent {
|
||||
margin: 5px 10px;
|
||||
margin: 8px;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.timestamp {
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
.smiley {
|
||||
font-size: 14pt;
|
||||
}
|
||||
@@ -266,7 +385,9 @@
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
width: $sidebarWidth;
|
||||
width: calc(#{$sidebarWidth} - 32px);
|
||||
margin-bottom: 5px;
|
||||
margin-left: -5px;
|
||||
|
||||
/**
|
||||
* CSS transitions do not apply for auto dimensions. So to produce the css
|
||||
@@ -281,9 +402,8 @@
|
||||
}
|
||||
|
||||
#smileysContainer {
|
||||
background-color: $newToolbarBackgroundColor;
|
||||
border-bottom: 1px solid;
|
||||
border-top: 1px solid;
|
||||
background-color: $chatBackgroundColor;
|
||||
border-top: 1px solid $chatInputSeparatorColor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,9 +509,9 @@
|
||||
|
||||
&-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin: 16px 16px 24px;
|
||||
margin: 16px;
|
||||
width: calc(100% - 32px);
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
@@ -402,10 +522,6 @@
|
||||
.jitsi-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.jitsi-icon > svg {
|
||||
fill: #A4B8D1;
|
||||
}
|
||||
}
|
||||
|
||||
#chatconversation {
|
||||
@@ -413,6 +529,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.touchmove-hack {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make header close button more easily tappable on mobile.
|
||||
*/
|
||||
@@ -421,6 +543,6 @@
|
||||
place-items: center;
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
background: #2a3a4b;
|
||||
background: #36383C;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
}
|
||||
|
||||
.drawer-menu {
|
||||
padding: 0 16px;
|
||||
max-height: 50vh;
|
||||
background: #242528;
|
||||
border-radius: 16px 16px 0 0;
|
||||
@@ -24,12 +23,6 @@
|
||||
height: 44px;
|
||||
cursor: pointer;
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
background-color: $overflowMenuItemHoverBG;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: none;
|
||||
}
|
||||
@@ -67,13 +60,6 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
background-color: $overflowMenuItemHoverBG;
|
||||
color: $overflowMenuItemHoverColor;
|
||||
}
|
||||
}
|
||||
|
||||
&.unclickable {
|
||||
cursor: default;
|
||||
}
|
||||
@@ -88,42 +74,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.beta-tag {
|
||||
background: $overflowMenuItemColor;
|
||||
border-radius: 2px;
|
||||
color: $overflowMenuBG;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
margin-left: 8px;
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
.overflow-menu-item-icon {
|
||||
margin-right: 16px;
|
||||
|
||||
i {
|
||||
display: inline;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
i:hover {
|
||||
background-color: initial;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 24px;
|
||||
max-height: 24px;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: #B8C7E0 !important;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-text {
|
||||
max-width: 100%;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
@@ -1,68 +1,37 @@
|
||||
.large-video-labels {
|
||||
.label {
|
||||
align-items: center;
|
||||
background: #36383C;
|
||||
border-radius: 3px;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
right: 30px;
|
||||
transition: right 0.5s;
|
||||
z-index: $labelsZ;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
height: 28px;
|
||||
margin: 0 0 4px 4px;
|
||||
padding: 0 8px;
|
||||
|
||||
.circular-label {
|
||||
align-items: center;
|
||||
color: white;
|
||||
display: flex;
|
||||
font-weight: bold;
|
||||
justify-content: center;
|
||||
margin-left: 8px;
|
||||
opacity: 0.8;
|
||||
&--green {
|
||||
background: #31B76A;
|
||||
}
|
||||
|
||||
.circular-label {
|
||||
background: #B8C7E0;
|
||||
&--red {
|
||||
background: #E34F56
|
||||
}
|
||||
|
||||
.circular-label.e2ee {
|
||||
align-items: center;
|
||||
background: #76CF9C;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
&--white {
|
||||
background: #fff;
|
||||
color: #5e6d7a;
|
||||
|
||||
.circular-label.file {
|
||||
background: #FF5630;
|
||||
}
|
||||
|
||||
.circular-label.local-rec {
|
||||
background: #FF5630;
|
||||
}
|
||||
|
||||
.circular-label.stream {
|
||||
background: #0065FF;
|
||||
}
|
||||
|
||||
.circular-label.insecure {
|
||||
background: $defaultWarningColor;
|
||||
}
|
||||
|
||||
.recording-label.center-message {
|
||||
background: $videoStateIndicatorBackground;
|
||||
bottom: 50%;
|
||||
display: block;
|
||||
left: 50%;
|
||||
padding: 10px;
|
||||
position: fixed;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: $centeredVideoLabelZ;
|
||||
svg {
|
||||
fill: #5e6d7a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.circular-label {
|
||||
background: $videoStateIndicatorBackground;
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
cursor: default;
|
||||
font-size: 13px;
|
||||
height: $videoStateIndicatorSize;
|
||||
line-height: $videoStateIndicatorSize;
|
||||
text-align: center;
|
||||
min-width: $videoStateIndicatorSize;
|
||||
}
|
||||
.label-text-with-icon {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.participants-count {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
.spinner {
|
||||
margin: 30px;
|
||||
}
|
||||
|
||||
|
||||
.joining-message {
|
||||
margin: 10px;
|
||||
}
|
||||
@@ -49,7 +49,7 @@
|
||||
position: fixed;
|
||||
top: 20;
|
||||
transition: top 1s ease;
|
||||
z-index: 100;
|
||||
z-index: $toolbarZ + 1;
|
||||
|
||||
&.toolbox-visible {
|
||||
// Same as toolbox subject position
|
||||
@@ -62,31 +62,6 @@
|
||||
padding: 15px
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0 15px 15px 15px;
|
||||
|
||||
li {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 8px 0;
|
||||
|
||||
.details {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
margin: 0 30px 0 10px;
|
||||
}
|
||||
|
||||
button {
|
||||
align-self: unset;
|
||||
margin: 0 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
align-self: stretch;
|
||||
margin: 8px 0;
|
||||
@@ -116,3 +91,50 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.knocking-participants-container {
|
||||
list-style-type: none;
|
||||
max-height: 600px;
|
||||
overflow-y: scroll;
|
||||
padding: 0 15px 15px 15px;
|
||||
}
|
||||
|
||||
.knocking-participant {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 8px 0;
|
||||
|
||||
.details {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
margin: 0 30px 0 10px;
|
||||
}
|
||||
|
||||
button {
|
||||
align-self: unset;
|
||||
margin: 0 5px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 300px) {
|
||||
#knocking-participant-list {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
|
||||
.avatar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.knocking-participant {
|
||||
flex-direction: column;
|
||||
|
||||
.details {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,44 +23,10 @@
|
||||
flex-direction: row;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
bottom: 10px;
|
||||
transform: translateX(-50%);
|
||||
|
||||
.toolbox-button {
|
||||
&:first-child {
|
||||
.toolbox-icon {
|
||||
border-top-left-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
svg {
|
||||
fill: $hangupColor;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
.toolbox-icon {
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filmstrip-toolbox {
|
||||
flex-direction: column;
|
||||
|
||||
.toolbox-button {
|
||||
&:nth-child(1) {
|
||||
svg {
|
||||
fill: $hangupColor;
|
||||
}
|
||||
}
|
||||
|
||||
.toolbox-icon {
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
.participants-count {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
color: #5e6d7a;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
margin-left: 16px;
|
||||
padding: 4px 8px;
|
||||
pointer-events: auto;
|
||||
|
||||
&-number {
|
||||
margin-right: 8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&-icon {
|
||||
background: url('../images/user-groups.svg');
|
||||
background-repeat: no-repeat;
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
**/
|
||||
|
||||
.popupmenu {
|
||||
min-width: 75px;
|
||||
background-color: $menuBG;
|
||||
border-radius: 3px;
|
||||
min-width: 150px;
|
||||
text-align: left;
|
||||
padding: 0px;
|
||||
width: 180px;
|
||||
white-space: nowrap;
|
||||
|
||||
&__item {
|
||||
@@ -39,6 +40,7 @@
|
||||
|
||||
&__text {
|
||||
display: inline-block;
|
||||
margin-left: 8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
@@ -110,6 +112,6 @@ ul.popupmenu {
|
||||
margin: -16px -24px;
|
||||
}
|
||||
|
||||
span.remotevideomenu:hover ul.popupmenu, ul.popupmenu:hover {
|
||||
span.localvideomenu:hover ul.popupmenu, span.remotevideomenu:hover ul.popupmenu, ul.popupmenu:hover {
|
||||
display:block !important;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
text {
|
||||
fill: black;
|
||||
font-size: 26px;
|
||||
font-weight: 400;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,14 +197,6 @@
|
||||
&> div {
|
||||
margin: 0 12px;
|
||||
}
|
||||
|
||||
.settings-button-small-icon {
|
||||
right: -8px;
|
||||
|
||||
&--hovered {
|
||||
right: -10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,73 +1,3 @@
|
||||
@mixin small-button-size() {
|
||||
.new-toolbox {
|
||||
.toolbox-content {
|
||||
.button-group-center, .button-group-left, .button-group-right {
|
||||
.toolbox-button {
|
||||
.toolbox-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
.toolbox-icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin very-small-button-size() {
|
||||
.new-toolbox {
|
||||
.toolbox-content {
|
||||
.button-group-center, .button-group-left, .button-group-right {
|
||||
.settings-button-small-icon {
|
||||
display: none;
|
||||
}
|
||||
.toolbox-button {
|
||||
.toolbox-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
svg {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
.toolbox-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin full-size-modal-positioner() {
|
||||
height: 100%;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@mixin full-size-modal-dialog() {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $verySmallScreen) {
|
||||
.welcome {
|
||||
display: block;
|
||||
@@ -137,21 +67,9 @@
|
||||
}
|
||||
|
||||
.desktop-browser {
|
||||
@media only screen and (max-width: $smallScreen) {
|
||||
@include small-button-size();
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $verySmallScreen) {
|
||||
@include very-small-button-size();
|
||||
}
|
||||
|
||||
&.shift-right {
|
||||
@media only screen and (max-width: $smallScreen + $sidebarWidth) {
|
||||
@include small-button-size()
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $verySmallScreen + $sidebarWidth) {
|
||||
@include very-small-button-size();
|
||||
|
||||
#videoResolutionLabel {
|
||||
display: none;
|
||||
@@ -165,25 +83,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 480px) and (max-width: 580px) {
|
||||
.shift-right .focus-lock > div > div {
|
||||
@include full-size-modal-positioner();
|
||||
}
|
||||
|
||||
.shift-right .focus-lock [role="dialog"] {
|
||||
@include full-size-modal-dialog();
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 580px) and (max-width: 680px) {
|
||||
.mobile-browser {
|
||||
&.shift-right .focus-lock > div > div {
|
||||
@include full-size-modal-positioner();
|
||||
}
|
||||
|
||||
&.shift-right .focus-lock [role="dialog"] {
|
||||
@include full-size-modal-dialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +1,62 @@
|
||||
.settings-button {
|
||||
&-container {
|
||||
position: relative;
|
||||
.settings-button-container {
|
||||
position: relative;
|
||||
|
||||
.toolbox-icon {
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #d1dbe8;
|
||||
justify-content: center;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
.toolbox-icon {
|
||||
align-items: center;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
&.disabled, .disabled & {
|
||||
cursor: initial;
|
||||
color: #929292;
|
||||
background-color: #36383c;
|
||||
|
||||
&:hover {
|
||||
background-color: #daebfa;
|
||||
border: 1px solid #daebfa;
|
||||
}
|
||||
|
||||
&.toggled {
|
||||
background: #2a3a4b;
|
||||
border: 1px solid #5e6d7a;
|
||||
|
||||
svg {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #5e6d7a;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled, .disabled & {
|
||||
cursor: initial;
|
||||
color: #fff;
|
||||
background-color: #a4b8d1;
|
||||
|
||||
&:hover {
|
||||
background-color: #a4b8d1;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: #5e6d7a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-small-icon {
|
||||
background: #FFF;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
border-radius: 50%;
|
||||
bottom: 0;
|
||||
box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.25);
|
||||
cursor: pointer;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
right: 4px;
|
||||
width: 16px;
|
||||
|
||||
&> svg {
|
||||
fill: #5e6d7a;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
background-color: #a4b8d1;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&--hovered {
|
||||
bottom: -1px;
|
||||
height: 20px;
|
||||
right: 2px;
|
||||
width: 20px;
|
||||
|
||||
&> svg {
|
||||
margin-top: 6px;
|
||||
background-color: #36383c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.settings-button-small-icon {
|
||||
background: #36383C;
|
||||
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
position: absolute;
|
||||
right: -4px;
|
||||
top: -3px;
|
||||
|
||||
&:hover {
|
||||
background: #F2F3F4;
|
||||
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
|
||||
|
||||
&> svg {
|
||||
fill: #000;
|
||||
}
|
||||
|
||||
&.settings-button-small-icon--disabled {
|
||||
background: #36383C;
|
||||
|
||||
&> svg {
|
||||
fill: #929292;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&> svg {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
background-color: #36383c;
|
||||
cursor: default;
|
||||
|
||||
&> svg {
|
||||
fill: #929292;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,60 @@
|
||||
.subject {
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
margin-top: 20px;
|
||||
position: absolute;
|
||||
top: -120px;
|
||||
transition: top .3s ease-in;
|
||||
height: 95px;
|
||||
width: 100%;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
padding: 25px 140px 0 140px;
|
||||
text-align: center;
|
||||
font-size: 17px;
|
||||
color: #fff;
|
||||
z-index: $zindex10;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
z-index: $zindex3;
|
||||
|
||||
&.visible {
|
||||
top: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
&.gradient {
|
||||
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
|
||||
.subject-info-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
max-width: calc(100% - 280px);
|
||||
margin: 0 auto;
|
||||
|
||||
&--full-width {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
&-text {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&-conference-timer {
|
||||
display: block;
|
||||
font-size: 15px;
|
||||
opacity: 0.6;
|
||||
@media (max-width: 500px) {
|
||||
flex-wrap: wrap;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.subject-info {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
margin-bottom: 4px;
|
||||
max-width: 80%;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.subject-text {
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
border-radius: 3px 0px 0px 3px;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
padding: 2px 16px;
|
||||
height: 24px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.subject-timer {
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
border-radius: 0px 3px 3px 0px;
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
min-width: 34px;
|
||||
padding: 6px 8px;
|
||||
}
|
||||
|
||||
@@ -33,9 +33,6 @@
|
||||
|
||||
&.visible {
|
||||
bottom: 0;
|
||||
.toolbox-background {
|
||||
bottom: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
&.no-buttons {
|
||||
@@ -48,253 +45,233 @@
|
||||
width: calc(100% - #{$sidebarWidth});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toolbox-background {
|
||||
background-image: linear-gradient(to top, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0));
|
||||
transition: bottom .3s ease-in;
|
||||
height: 160px;
|
||||
width: 100%;
|
||||
bottom: -160px;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
z-index: $toolbarBackgroundZ;
|
||||
.toolbox-content {
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
margin-bottom: 16px;
|
||||
position: relative;
|
||||
z-index: $toolbarZ;
|
||||
|
||||
.button-group-center,
|
||||
.button-group-left,
|
||||
.button-group-right {
|
||||
display: flex;
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
.toolbox-content {
|
||||
box-sizing: border-box;
|
||||
.button-group-center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.button-group-right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.toolbox-button-wth-dialog {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.toolbox-button {
|
||||
color: $toolbarButtonColor;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
line-height: $newToolbarSize;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.toolbar-button-with-badge {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
||||
.badge-round {
|
||||
bottom: -5px;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
min-width: 20px;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
right: -5px;
|
||||
}
|
||||
}
|
||||
|
||||
.toolbox-content-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.toolbox-content-items {
|
||||
background: $newToolbarBackgroundColor;
|
||||
box-shadow: 0px 2px 8px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.15);
|
||||
border-radius: 6px;
|
||||
margin: 0 auto;
|
||||
padding: 6px;
|
||||
text-align: center;
|
||||
|
||||
>div {
|
||||
margin-left: 8px;
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overflow-menu {
|
||||
font-size: 14px;
|
||||
list-style-type: none;
|
||||
padding: 8px 0;
|
||||
background-color: $menuBG;
|
||||
|
||||
.profile-text {
|
||||
max-width: 150px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.overflow-menu-item {
|
||||
align-items: center;
|
||||
color: $overflowMenuItemColor;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
height: 40px;
|
||||
line-height: 24px;
|
||||
padding: 8px 16px;
|
||||
box-sizing: border-box;
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
background: $overflowMenuItemBackground;
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 20px 16px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
z-index: $toolbarZ;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.button-group-center,
|
||||
.button-group-left,
|
||||
.button-group-right {
|
||||
display: flex;
|
||||
width: 33%;
|
||||
&.unclickable {
|
||||
cursor: default;
|
||||
}
|
||||
&.disabled {
|
||||
cursor: initial;
|
||||
color: #929292;
|
||||
|
||||
&:hover {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.button-group-center {
|
||||
justify-content: center;
|
||||
|
||||
.toolbox-button {
|
||||
|
||||
.toolbox-icon {
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #d1dbe8;
|
||||
margin: 0px 4px;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
background-color: #daebfa;
|
||||
border: 1px solid #daebfa;
|
||||
}
|
||||
}
|
||||
|
||||
&.toggled {
|
||||
background: #2a3a4b;
|
||||
border: 1px solid #5e6d7a;
|
||||
|
||||
svg {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
background-color: #5e6d7a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled, .disabled & {
|
||||
cursor: initial;
|
||||
color: #fff;
|
||||
background-color: #a4b8d1;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: #5e6d7a;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
.toolbox-icon {
|
||||
background-color: $hangupColor;
|
||||
border: 1px solid $hangupColor;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
background-color: $hangupColor;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
svg {
|
||||
fill: #929292;
|
||||
}
|
||||
|
||||
.button-group-right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&.unclickable:hover {
|
||||
background: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overflow-menu {
|
||||
font-size: 1.2em;
|
||||
list-style-type: none;
|
||||
background-color: $overflowMenuBG;
|
||||
/**
|
||||
* Undo atlaskit padding by reducing margins.
|
||||
*/
|
||||
margin: -16px -24px;
|
||||
padding: 4px 0;
|
||||
.beta-tag {
|
||||
background: #36383C;
|
||||
border-radius: 3px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
margin-left: 8px;
|
||||
padding: 0 4px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.overflow-menu-item {
|
||||
align-items: center;
|
||||
color: $overflowMenuItemColor;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
height: 40px;
|
||||
padding: 5px 12px;
|
||||
box-sizing: border-box;
|
||||
.overflow-menu-item-icon {
|
||||
margin-right: 16px;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
i {
|
||||
display: inline;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
background-color: $overflowMenuItemHoverBG;
|
||||
color: $overflowMenuItemHoverColor;
|
||||
}
|
||||
}
|
||||
|
||||
&.unclickable {
|
||||
cursor: default;
|
||||
}
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&.unclickable:hover {
|
||||
background: inherit;
|
||||
}
|
||||
}
|
||||
&.disabled {
|
||||
cursor: initial;
|
||||
color: #3b475c;
|
||||
}
|
||||
}
|
||||
|
||||
.beta-tag {
|
||||
background: $overflowMenuItemColor;
|
||||
border-radius: 2px;
|
||||
color: $overflowMenuBG;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
margin-left: 8px;
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
.overflow-menu-item-icon {
|
||||
margin-right: 16px;
|
||||
|
||||
i {
|
||||
display: inline;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
i:hover {
|
||||
background-color: initial;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 24px;
|
||||
max-height: 24px;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: #B8C7E0 !important;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-text {
|
||||
max-width: 150px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
i:hover {
|
||||
background-color: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.toolbox-button {
|
||||
color: $toolbarButtonColor;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
line-height: $newToolbarSize;
|
||||
margin: 0 8px;
|
||||
text-align: center;
|
||||
img {
|
||||
max-width: 24px;
|
||||
max-height: 24px;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: #fff;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.overflow-menu-hr {
|
||||
border-top: 1px solid #4C4D50;
|
||||
border-bottom: 0;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.toolbox-icon {
|
||||
display: flex;
|
||||
border-radius: 3px;
|
||||
flex-direction: column;
|
||||
font-size: 24px;
|
||||
height: $newToolbarSize;
|
||||
justify-content: center;
|
||||
width: $newToolbarSize;
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
background: $newToolbarButtonHoverColor;
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar-button-with-badge {
|
||||
position: relative;
|
||||
@media (max-width: 320px) {
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
}
|
||||
|
||||
.badge-round {
|
||||
bottom: -5px;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
min-width: 20px;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
right: -5px;
|
||||
}
|
||||
&.toggled {
|
||||
background: $newToolbarButtonToggleColor;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: initial !important;
|
||||
background-color: #36383c !important;
|
||||
|
||||
svg {
|
||||
fill: #929292 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toolbox-button-wth-dialog {
|
||||
display: inline-block;
|
||||
.hangup-button {
|
||||
background-color: $hangupColor;
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
background-color: $hangupHoverColor;
|
||||
}
|
||||
}
|
||||
|
||||
.toolbox-icon {
|
||||
display: flex;
|
||||
border-radius: 5px;
|
||||
flex-direction: column;
|
||||
font-size: 24px;
|
||||
height: $newToolbarSize;
|
||||
justify-content: center;
|
||||
width: $newToolbarSize;
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
background: $newToolbarButtonHoverColor;
|
||||
}
|
||||
}
|
||||
|
||||
&.toggled {
|
||||
background: $newToolbarButtonHoverColor;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: initial !important;
|
||||
background-color: #a4b8d1 !important;
|
||||
|
||||
svg {
|
||||
fill: #fff !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
svg {
|
||||
fill: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,3 +289,47 @@
|
||||
|
||||
@include transition(all .3s ease-out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Audio and video buttons do not have toggled state.
|
||||
*/
|
||||
.audio-preview,
|
||||
.video-preview {
|
||||
.toolbox-icon.toggled {
|
||||
background: none;
|
||||
|
||||
&:hover {
|
||||
background: $newToolbarButtonHoverColor;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* On small mobile devices make the toolbar full width and pad the invite prompt.
|
||||
*/
|
||||
.toolbox-content-mobile {
|
||||
@media (max-width: 500px) {
|
||||
margin-bottom: 0;
|
||||
|
||||
.toolbox-content-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.toolbox-content-items {
|
||||
border-radius: 0;
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
padding: 6px 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.invite-more-container {
|
||||
margin: 0 16px 8px;
|
||||
}
|
||||
|
||||
.invite-more-container.elevated {
|
||||
margin-bottom: 52px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
.transcription-subtitles{
|
||||
bottom: 10%;
|
||||
.transcription-subtitles {
|
||||
bottom: $newToolbarSize + 40px;
|
||||
font-size: 16px;
|
||||
font-weight: 1000;
|
||||
left: 50%;
|
||||
max-width: 50vw;
|
||||
opacity: 0.80;
|
||||
overflow-wrap: break-word;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
text-shadow: 0px 0px 1px rgba(0,0,0,0.3),
|
||||
@@ -14,6 +15,11 @@
|
||||
transform: translateX(-50%);
|
||||
z-index: $subtitlesZ;
|
||||
|
||||
&.lifted {
|
||||
// Lift subtitle above toolbar+invite box.
|
||||
bottom: $newToolbarSize + 112px + 40px;
|
||||
}
|
||||
|
||||
span {
|
||||
background: black;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* Style variables
|
||||
*/
|
||||
$baseFontFamily: -apple-system, BlinkMacSystemFont, 'open_sanslight', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
$hangupColor: #bf2117;
|
||||
$hangupColor:#DD3849;
|
||||
$hangupHoverColor: #F25363;
|
||||
$hangupFontSize: 2em;
|
||||
|
||||
/**
|
||||
@@ -37,20 +38,20 @@ $presence-idle: rgb(172, 172, 172);
|
||||
/**
|
||||
* Toolbar
|
||||
*/
|
||||
$newToolbarBackgroundColor: rgba(22, 38, 55, 0.8);
|
||||
$newToolbarButtonHoverColor: rgba(255, 255, 255, 0.15);
|
||||
$newToolbarButtonToggleColor: rgba(255, 255, 255, 0.2);
|
||||
$newToolbarBackgroundColor: #131519;
|
||||
$newToolbarButtonHoverColor: rgba(255, 255, 255, 0.2);
|
||||
$newToolbarButtonToggleColor: rgba(255, 255, 255, 0.15);
|
||||
$AOTToolbarButtonHoverColor: rgba(14, 20, 35, 0.6);
|
||||
$AOTToolbarButtonToggleColor: rgba(14, 20, 35, 1);
|
||||
$menuBG:#242528;
|
||||
$newToolbarFontSize: 24px;
|
||||
$newToolbarHangupFontSize: 32px;
|
||||
$newToolbarSize: 40px;
|
||||
$newToolbarSize: 48px;
|
||||
$newToolbarSizeWithPadding: calc(#{$newToolbarSize} + 24px);
|
||||
$toolbarTitleFontSize: 19px;
|
||||
$overflowMenuBG: initial;
|
||||
$overflowMenuItemHoverBG: #313D52;
|
||||
$overflowMenuItemHoverColor: #B8C7E0;
|
||||
$overflowMenuItemColor: #B8C7E0;
|
||||
$overflowMenuItemColor: #fff;
|
||||
$overflowMenuItemBackground: #36383C;
|
||||
|
||||
|
||||
/**
|
||||
* Video layout
|
||||
@@ -90,12 +91,12 @@ $modalTextColor: #333;
|
||||
* Chat
|
||||
*/
|
||||
$chatActionsSeparatorColor: rgb(173, 105, 112);
|
||||
$chatHeaderBackgroundColor: rgba(42, 58, 75, 0.9);
|
||||
$chatBackgroundColor: #131519;
|
||||
$chatInputSeparatorColor: #A4B8D1;
|
||||
$chatLocalMessageBackgroundColor: rgb(4, 98, 178);
|
||||
$chatLocalMessageBackgroundColor: #484A4F;
|
||||
$chatPrivateMessageBackgroundColor: rgb(153, 69, 77);
|
||||
$chatRemoteMessageBackgroundColor: rgb(86, 101, 114);
|
||||
$sidebarWidth: 375px;
|
||||
$chatRemoteMessageBackgroundColor: #242528;
|
||||
$sidebarWidth: 315px;
|
||||
|
||||
/**
|
||||
* Misc.
|
||||
@@ -122,8 +123,8 @@ $zindex10: 10;
|
||||
$reloadZ: 20;
|
||||
$poweredByZ: 100;
|
||||
$ringingZ: 300;
|
||||
$sideToolbarContainerZ: 300;
|
||||
$toolbarZ: 350;
|
||||
$sideToolbarContainerZ: 200;
|
||||
$toolbarZ: 250;
|
||||
$drawerZ: 351;
|
||||
$tooltipsZ: 401;
|
||||
$dropdownMaskZ: 900;
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
.video-preview {
|
||||
background: none;
|
||||
max-height: 290px;
|
||||
display: inline-block;
|
||||
max-height: 344px;
|
||||
|
||||
&-container {
|
||||
background: $menuBG;
|
||||
border-radius: 3px;
|
||||
overflow: auto;
|
||||
padding: 16px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
&-entry {
|
||||
cursor: pointer;
|
||||
height: 135px;
|
||||
margin-bottom: 16px;
|
||||
height: 168px;
|
||||
margin-bottom: 8px;
|
||||
position: relative;
|
||||
width: 240px;
|
||||
width: 284px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
@@ -20,13 +23,15 @@
|
||||
|
||||
&--selected {
|
||||
border: 3px solid #31B76A;
|
||||
border-radius: 3px;
|
||||
cursor: default;
|
||||
height: 129px;
|
||||
width: 234px;
|
||||
height: 162px;
|
||||
width: 278px;
|
||||
}
|
||||
}
|
||||
|
||||
&-video {
|
||||
border-radius: 3px;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
@@ -50,21 +55,28 @@
|
||||
}
|
||||
|
||||
&-label {
|
||||
bottom: 8px;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
overflow: hidden;
|
||||
padding: 8px;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
width: 220px;
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
// Override @atlaskit/InlineDialog container which is made with styled components
|
||||
& > div:nth-child(2) {
|
||||
outline: none;
|
||||
padding: 0;
|
||||
&-container {
|
||||
margin: 0 16px;
|
||||
}
|
||||
|
||||
&-text {
|
||||
background-color: #131519;
|
||||
border-radius: 3px;
|
||||
padding: 2px 8px;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
margin: 0 auto;
|
||||
max-width: calc(100% - 16px);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: fit-content;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,7 +400,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
.local-video-menu-trigger,
|
||||
.remote-video-menu-trigger,
|
||||
.localvideomenu,
|
||||
.remotevideomenu
|
||||
{
|
||||
display: inline-block;
|
||||
@@ -418,6 +420,7 @@
|
||||
cursor: hand;
|
||||
}
|
||||
}
|
||||
.local-video-menu-trigger,
|
||||
.remote-video-menu-trigger {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
@@ -208,6 +208,11 @@ body.welcome-page {
|
||||
cursor: pointer;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.toolbox-icon {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.welcome-watermark {
|
||||
@@ -228,6 +233,10 @@ body.welcome-page {
|
||||
}
|
||||
}
|
||||
|
||||
&.without-footer {
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
.welcome-cards-container {
|
||||
color:#131519;
|
||||
padding-top: 40px;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
0 0 3px $videoThumbnailSelected;
|
||||
}
|
||||
|
||||
.remotevideomenu > .icon-menu {
|
||||
.remotevideomenu > .icon-menu, .localvideomenu > .icon-menu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
box-shadow: inset 0 0 3px $videoThumbnailHovered,
|
||||
0 0 3px $videoThumbnailHovered;
|
||||
|
||||
.remotevideomenu > .icon-menu {
|
||||
.remotevideomenu > .icon-menu, .localvideomenu > .icon-menu {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,3 +121,15 @@
|
||||
align-self: baseline;
|
||||
}
|
||||
}
|
||||
|
||||
.shift-right #filmstripRemoteVideosContainer {
|
||||
/**
|
||||
* Max-width corresponding to the ASPECT_RATIO_BREAKPOINT from features/filmstrip/constants,
|
||||
* from which we subtract the chat size.
|
||||
*/
|
||||
@media only screen and (max-width: calc(500px + #{$sidebarWidth})) {
|
||||
video {
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
* specifically the various status icons.
|
||||
*/
|
||||
.remotevideomenu,
|
||||
.localvideomenu,
|
||||
.videocontainer__toptoolbar {
|
||||
z-index: auto;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
* and tooltips from getting a new location context due to translate3d.
|
||||
*/
|
||||
.connection-indicator,
|
||||
.local-video-menu-trigger,
|
||||
.remote-video-menu-trigger,
|
||||
.indicator-icon-container {
|
||||
transform: translate3d(0, 0, 0);
|
||||
@@ -68,7 +69,9 @@
|
||||
* Move the remote video menu trigger to the bottom left of the video
|
||||
* thumbnail.
|
||||
*/
|
||||
.localvideomenu,
|
||||
.remotevideomenu,
|
||||
.local-video-menu-trigger,
|
||||
.remote-video-menu-trigger {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
@@ -76,6 +79,7 @@
|
||||
right: auto;
|
||||
}
|
||||
|
||||
.local-video-menu-trigger,
|
||||
.remote-video-menu-trigger {
|
||||
margin-bottom: 7px;
|
||||
margin-left: $remoteVideoMenuIconMargin;
|
||||
|
||||
@@ -43,11 +43,11 @@ $flagsImagePath: "../images/";
|
||||
@import 'modals/settings/settings';
|
||||
@import 'modals/speaker_stats/speaker_stats';
|
||||
@import 'modals/video-quality/video-quality';
|
||||
@import 'modals/virtual-background/virtual-background';
|
||||
@import 'modals/local-recording/local-recording';
|
||||
@import 'videolayout_default';
|
||||
@import 'notice';
|
||||
@import 'subject';
|
||||
@import 'participants-count';
|
||||
@import 'popup_menu';
|
||||
@import 'recording';
|
||||
@import 'login_menu';
|
||||
|
||||
@@ -1,31 +1,42 @@
|
||||
.invite-more {
|
||||
&-container {
|
||||
margin-bottom: 8px;
|
||||
transition: margin-bottom 0.3s;
|
||||
|
||||
&.elevated {
|
||||
margin-bottom: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
border-radius: 8px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
font-weight: 600;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
z-index: $zindex2;
|
||||
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
|
||||
}
|
||||
|
||||
&-header {
|
||||
font-size: 19px;
|
||||
line-height: 28px;
|
||||
margin: 24px 0 16px 0;
|
||||
max-width: 100%;
|
||||
margin-bottom: 16px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&-button {
|
||||
display: flex;
|
||||
margin: auto;
|
||||
max-width: 100%;
|
||||
height: 40px;
|
||||
box-sizing: border-box;
|
||||
padding: 8px 16px;
|
||||
width: fit-content;
|
||||
width: -moz-fit-content;
|
||||
height: 24px;
|
||||
background: #0376DA;
|
||||
border-radius: 3px;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
cursor: pointer;
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
@@ -36,8 +47,9 @@
|
||||
|
||||
&-text {
|
||||
margin-left: 8px;
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
&-dialog {
|
||||
@@ -195,3 +207,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-browser {
|
||||
.invite-more-content {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.invite-more-button {
|
||||
height: 48px;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
|
||||
.language-settings {
|
||||
max-width: 50%;
|
||||
width: 35%;
|
||||
}
|
||||
|
||||
.calendar-tab {
|
||||
|
||||
93
css/modals/virtual-background/_virtual-background.scss
Normal file
93
css/modals/virtual-background/_virtual-background.scss
Normal file
@@ -0,0 +1,93 @@
|
||||
.virtual-background-dialog {
|
||||
display: inline-grid;
|
||||
grid-template-columns: auto auto auto auto auto auto auto auto;
|
||||
max-width: 370px;
|
||||
cursor: pointer;
|
||||
.thumbnail {
|
||||
border-radius: 10px;
|
||||
object-fit: cover;
|
||||
padding: 5px;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.thumbnail:hover ~ .delete-image-icon {
|
||||
display: block;
|
||||
}
|
||||
.thumbnail-selected {
|
||||
border-radius: 10px;
|
||||
object-fit: cover;
|
||||
padding: 5px;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border: 2px solid #a4b8d1;
|
||||
}
|
||||
.blur-selected {
|
||||
border-radius: 10px;
|
||||
border: 2px solid #a4b8d1;
|
||||
}
|
||||
.virtual-background-none {
|
||||
font-weight: bold;
|
||||
padding: 5px;
|
||||
height: 34px;
|
||||
width: 34px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #a4b8d1;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
line-height: 35px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.none-selected {
|
||||
font-weight: bold;
|
||||
padding: 5px;
|
||||
height: 34px;
|
||||
width: 34px;
|
||||
border-radius: 10px;
|
||||
border: 2px solid #a4b8d1;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
line-height: 35px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-dialog-form .virtual-background-loading {
|
||||
overflow: hidden;
|
||||
}
|
||||
.file-upload-btn {
|
||||
display: none;
|
||||
}
|
||||
.custom-file-upload {
|
||||
font-size: x-large;
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
padding: 4px;
|
||||
height: 35px;
|
||||
width: 35px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #a4b8d1;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
line-height: 35px;
|
||||
margin-left: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.delete-image-icon {
|
||||
position: absolute;
|
||||
display: none;
|
||||
left: 36;
|
||||
bottom: 36;
|
||||
}
|
||||
.delete-image-icon:hover {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.thumbnail-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.loading-content-text{
|
||||
margin-right: 15px;
|
||||
}
|
||||
@@ -33,4 +33,12 @@
|
||||
bottom: 24px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__spinner-container {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
4
debian/jitsi-meet-prosody.postinst
vendored
4
debian/jitsi-meet-prosody.postinst
vendored
@@ -35,7 +35,7 @@ case "$1" in
|
||||
db_input critical jitsi-videobridge/jvb-hostname || true
|
||||
db_go
|
||||
fi
|
||||
JVB_HOSTNAME="$RET"
|
||||
JVB_HOSTNAME=$(echo "$RET" | xargs echo -n)
|
||||
|
||||
db_get jitsi-videobridge/jvbsecret
|
||||
if [ -z "$RET" ] ; then
|
||||
@@ -64,7 +64,7 @@ case "$1" in
|
||||
|
||||
# detect dpkg-reconfigure, just delete old links
|
||||
db_get jitsi-meet-prosody/jvb-hostname
|
||||
JVB_HOSTNAME_OLD=$RET
|
||||
JVB_HOSTNAME_OLD=$(echo "$RET" | xargs echo -n)
|
||||
if [ -n "$RET" ] && [ ! "$JVB_HOSTNAME_OLD" = "$JVB_HOSTNAME" ] ; then
|
||||
rm -f /etc/prosody/conf.d/$JVB_HOSTNAME_OLD.cfg.lua
|
||||
rm -f /etc/prosody/certs/$JVB_HOSTNAME_OLD.key
|
||||
|
||||
2
debian/jitsi-meet-prosody.postrm
vendored
2
debian/jitsi-meet-prosody.postrm
vendored
@@ -31,7 +31,7 @@ case "$1" in
|
||||
|
||||
purge)
|
||||
db_get jitsi-meet-prosody/jvb-hostname
|
||||
JVB_HOSTNAME=$RET
|
||||
JVB_HOSTNAME=$(echo "$RET" | xargs echo -n)
|
||||
if [ -n "$RET" ]; then
|
||||
rm -f /etc/prosody/conf.avail/$JVB_HOSTNAME.cfg.lua
|
||||
rm -f /etc/prosody/conf.d/$JVB_HOSTNAME.cfg.lua
|
||||
|
||||
2
debian/jitsi-meet-tokens.postinst
vendored
2
debian/jitsi-meet-tokens.postinst
vendored
@@ -25,7 +25,7 @@ case "$1" in
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
db_get jitsi-meet-prosody/jvb-hostname
|
||||
JVB_HOSTNAME="$RET"
|
||||
JVB_HOSTNAME=$(echo "$RET" | xargs echo -n)
|
||||
|
||||
db_get jitsi-meet-tokens/appid
|
||||
if [ "$RET" = "false" ] ; then
|
||||
|
||||
4
debian/jitsi-meet-turnserver.postinst
vendored
4
debian/jitsi-meet-turnserver.postinst
vendored
@@ -30,7 +30,7 @@ case "$1" in
|
||||
db_input critical jitsi-videobridge/jvb-hostname || true
|
||||
db_go
|
||||
fi
|
||||
JVB_HOSTNAME="$RET"
|
||||
JVB_HOSTNAME=$(echo "$RET" | xargs echo -n)
|
||||
|
||||
TURN_CONFIG="/etc/turnserver.conf"
|
||||
NGINX_CONFIG="/etc/nginx/sites-available/$JVB_HOSTNAME.conf"
|
||||
@@ -44,7 +44,7 @@ case "$1" in
|
||||
|
||||
# detect dpkg-reconfigure, just delete old links
|
||||
db_get jitsi-meet-turnserver/jvb-hostname
|
||||
JVB_HOSTNAME_OLD=$RET
|
||||
JVB_HOSTNAME_OLD=$(echo "$RET" | xargs echo -n)
|
||||
if [ -n "$RET" ] && [ ! "$JVB_HOSTNAME_OLD" = "$JVB_HOSTNAME" ] ; then
|
||||
if [[ -f $TURN_CONFIG ]] && grep -q "jitsi-meet coturn config" "$TURN_CONFIG" ; then
|
||||
rm -f $TURN_CONFIG
|
||||
|
||||
4
debian/jitsi-meet-web-config.postinst
vendored
4
debian/jitsi-meet-web-config.postinst
vendored
@@ -32,12 +32,12 @@ case "$1" in
|
||||
db_go
|
||||
db_get jitsi-videobridge/jvb-hostname
|
||||
fi
|
||||
JVB_HOSTNAME="$RET"
|
||||
JVB_HOSTNAME=$(echo "$RET" | xargs echo -n)
|
||||
|
||||
# detect dpkg-reconfigure
|
||||
RECONFIGURING="false"
|
||||
db_get jitsi-meet/jvb-hostname
|
||||
JVB_HOSTNAME_OLD=$RET
|
||||
JVB_HOSTNAME_OLD=$(echo "$RET" | xargs echo -n)
|
||||
if [ -n "$RET" ] && [ ! "$JVB_HOSTNAME_OLD" = "$JVB_HOSTNAME" ] ; then
|
||||
RECONFIGURING="true"
|
||||
rm -f /etc/jitsi/meet/$JVB_HOSTNAME_OLD-config.js
|
||||
|
||||
2
debian/jitsi-meet-web-config.postrm
vendored
2
debian/jitsi-meet-web-config.postrm
vendored
@@ -33,7 +33,7 @@ case "$1" in
|
||||
;;
|
||||
purge)
|
||||
db_get jitsi-meet/jvb-hostname
|
||||
JVB_HOSTNAME=$RET
|
||||
JVB_HOSTNAME=$(echo "$RET" | xargs echo -n)
|
||||
if [ -n "$RET" ]; then
|
||||
rm -f /etc/jitsi/meet/$JVB_HOSTNAME-config.js
|
||||
rm -f /etc/nginx/sites-available/$JVB_HOSTNAME.conf
|
||||
|
||||
1
debian/jitsi-meet-web.install
vendored
1
debian/jitsi-meet-web.install
vendored
@@ -1,6 +1,5 @@
|
||||
interface_config.js /usr/share/jitsi-meet/
|
||||
logging_config.js /usr/share/jitsi-meet/
|
||||
*.json /usr/share/jitsi-meet/
|
||||
*.html /usr/share/jitsi-meet/
|
||||
*.ico /usr/share/jitsi-meet/
|
||||
libs /usr/share/jitsi-meet/
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
<VirtualHost *:80>
|
||||
ServerName jitsi-meet.example.com
|
||||
Redirect permanent / https://jitsi-meet.example.com/
|
||||
RewriteEngine On
|
||||
RewriteCond %{HTTPS} off
|
||||
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
|
||||
</VirtualHost>
|
||||
|
||||
<VirtualHost *:443>
|
||||
@@ -42,11 +39,12 @@
|
||||
</Location>
|
||||
|
||||
ProxyPreserveHost on
|
||||
ProxyPass /http-bind http://localhost:5280/http-bind/
|
||||
ProxyPassReverse /http-bind http://localhost:5280/http-bind/
|
||||
ProxyPass /http-bind http://localhost:5280/http-bind
|
||||
ProxyPassReverse /http-bind http://localhost:5280/http-bind
|
||||
ProxyPass /xmpp-websocket ws://localhost:5280/xmpp-websocket
|
||||
ProxyPassReverse /xmpp-websocket ws://localhost:5280/xmpp-websocket
|
||||
ProxyPassMatch ^/colibri-ws/default-id ws://localhost:9090
|
||||
ProxyPass /colibri-ws/default-id ws://localhost:9090/colibri-ws/default-id
|
||||
ProxyPassReverse /colibri-ws/default-id ws://localhost:9090/colibri-ws/default-id
|
||||
|
||||
RewriteEngine on
|
||||
RewriteRule ^/([a-zA-Z0-9]+)$ /index.html
|
||||
|
||||
BIN
images/virtual-background/background-1.jpg
Normal file
BIN
images/virtual-background/background-1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 437 KiB |
BIN
images/virtual-background/background-2.jpg
Normal file
BIN
images/virtual-background/background-2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 284 KiB |
BIN
images/virtual-background/background-3.jpg
Normal file
BIN
images/virtual-background/background-3.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 216 KiB |
BIN
images/virtual-background/background-4.jpg
Normal file
BIN
images/virtual-background/background-4.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 341 KiB |
@@ -1,6 +1,13 @@
|
||||
/* eslint-disable no-unused-vars, no-var, max-len */
|
||||
/* eslint sort-keys: ["error", "asc", {"caseSensitive": false}] */
|
||||
|
||||
/**
|
||||
* !!!IMPORTANT!!!
|
||||
*
|
||||
* This file is considered deprecated. All options will eventually be moved to
|
||||
* config.js, and no new options should be added here.
|
||||
*/
|
||||
|
||||
var interfaceConfig = {
|
||||
APP_NAME: 'Jitsi Meet',
|
||||
AUDIO_LEVEL_PRIMARY_COLOR: 'rgba(255,255,255,0.4)',
|
||||
@@ -168,6 +175,13 @@ var interfaceConfig = {
|
||||
REMOTE_THUMBNAIL_RATIO: 1, // 1:1
|
||||
|
||||
SETTINGS_SECTIONS: [ 'devices', 'language', 'moderator', 'profile', 'calendar' ],
|
||||
|
||||
/**
|
||||
* Specify which sharing features should be displayed. If the value is not set
|
||||
* all sharing features will be shown. You can set [] to disable all.
|
||||
*/
|
||||
// SHARING_FEATURES: ['email', 'url', 'dial-in', 'embed'],
|
||||
|
||||
SHOW_BRAND_WATERMARK: false,
|
||||
|
||||
/**
|
||||
@@ -191,23 +205,16 @@ var interfaceConfig = {
|
||||
TOOLBAR_ALWAYS_VISIBLE: false,
|
||||
|
||||
/**
|
||||
* The name of the toolbar buttons to display in the toolbar, including the
|
||||
* "More actions" menu. If present, the button will display. Exceptions are
|
||||
* "livestreaming" and "recording" which also require being a moderator and
|
||||
* some values in config.js to be enabled. Also, the "profile" button will
|
||||
* not display for users with a JWT.
|
||||
* Notes:
|
||||
* - it's impossible to choose which buttons go in the "More actions" menu
|
||||
* - it's impossible to control the placement of buttons
|
||||
* - 'desktop' controls the "Share your screen" button
|
||||
* DEPRECATED!
|
||||
* This config was moved to config.js as `toolbarButtons`.
|
||||
*/
|
||||
TOOLBAR_BUTTONS: [
|
||||
'microphone', 'camera', 'closedcaptions', 'desktop', 'embedmeeting', 'fullscreen',
|
||||
'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
|
||||
'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
|
||||
'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
|
||||
'tileview', 'videobackgroundblur', 'download', 'help', 'mute-everyone', 'security'
|
||||
],
|
||||
// TOOLBAR_BUTTONS: [
|
||||
// 'microphone', 'camera', 'closedcaptions', 'desktop', 'embedmeeting', 'fullscreen',
|
||||
// 'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
|
||||
// 'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
|
||||
// 'videoquality', 'filmstrip', 'invite', 'feedback', 'stats', 'shortcuts',
|
||||
// 'tileview', 'select-background', 'download', 'help', 'mute-everyone', 'mute-video-everyone', 'security'
|
||||
// ],
|
||||
|
||||
TOOLBAR_TIMEOUT: 4000,
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ target 'JitsiMeetSDK' do
|
||||
pod 'react-native-splash-screen', :path => '../node_modules/react-native-splash-screen'
|
||||
pod 'react-native-webview', :path => '../node_modules/react-native-webview'
|
||||
pod 'react-native-webrtc', :path => '../node_modules/react-native-webrtc'
|
||||
pod 'BVLinearGradient', :path => '../node_modules/react-native-linear-gradient'
|
||||
pod 'RNCAsyncStorage', :path => '../node_modules/@react-native-async-storage/async-storage'
|
||||
pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info'
|
||||
pod 'RNGoogleSignin', :path => '../node_modules/@react-native-community/google-signin'
|
||||
|
||||
@@ -5,8 +5,6 @@ PODS:
|
||||
- AppAuth/Core (1.2.0)
|
||||
- AppAuth/ExternalUserAgent (1.2.0)
|
||||
- boost-for-react-native (1.63.0)
|
||||
- BVLinearGradient (2.5.6):
|
||||
- React
|
||||
- CocoaLumberjack (3.5.3):
|
||||
- CocoaLumberjack/Core (= 3.5.3)
|
||||
- CocoaLumberjack/Core (3.5.3)
|
||||
@@ -292,7 +290,7 @@ PODS:
|
||||
- React
|
||||
- react-native-splash-screen (3.2.0):
|
||||
- React
|
||||
- react-native-webrtc (1.87.3):
|
||||
- react-native-webrtc (1.89.1):
|
||||
- React-Core
|
||||
- react-native-webview (11.0.2):
|
||||
- React-Core
|
||||
@@ -371,7 +369,6 @@ PODS:
|
||||
- Yoga (1.14.0)
|
||||
|
||||
DEPENDENCIES:
|
||||
- BVLinearGradient (from `../node_modules/react-native-linear-gradient`)
|
||||
- CocoaLumberjack (~> 3.5.3)
|
||||
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector/`)
|
||||
@@ -442,8 +439,6 @@ SPEC REPOS:
|
||||
- PromisesObjC
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
BVLinearGradient:
|
||||
:path: "../node_modules/react-native-linear-gradient"
|
||||
DoubleConversion:
|
||||
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
|
||||
FBLazyVector:
|
||||
@@ -526,7 +521,6 @@ EXTERNAL SOURCES:
|
||||
SPEC CHECKSUMS:
|
||||
AppAuth: bce82c76043657c99d91e7882e8a9e1a93650cd4
|
||||
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
|
||||
BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872
|
||||
CocoaLumberjack: 2f44e60eb91c176d471fdba43b9e3eae6a721947
|
||||
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
|
||||
FBLazyVector: ca7f56c8ff6cd8590f7a673d7903b06019805581
|
||||
@@ -563,7 +557,7 @@ SPEC CHECKSUMS:
|
||||
react-native-keep-awake: eba3137546b10003361b37c761f6c429b59814ae
|
||||
react-native-netinfo: 8d8db463bcc5db66a8ac5c48a7d86beb3b92f61a
|
||||
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
|
||||
react-native-webrtc: dc1208bdca2c4d091f7b57859e69332bff6f1986
|
||||
react-native-webrtc: ccb0c21eb4fb04326648fbdb4a5d49977e2cf274
|
||||
react-native-webview: b2542d6fd424bcc3e3b2ec5f854f0abb4ec86c87
|
||||
React-RCTActionSheet: bcbc311dc3b47bc8efb2737ff0940239a45789a9
|
||||
React-RCTAnimation: 65f61080ce632f6dea23d52e354ffac9948396c6
|
||||
@@ -584,6 +578,6 @@ SPEC CHECKSUMS:
|
||||
RNWatch: a5320c959c75e72845c07985f3e935e58998f1d3
|
||||
Yoga: 96b469c5e81ff51b917b92e8c3390642d4ded30c
|
||||
|
||||
PODFILE CHECKSUM: 5be5132e41831a98362eeed760558227a4df89ae
|
||||
PODFILE CHECKSUM: d059cebf82da14a53940a16c24c3330752d4b0c8
|
||||
|
||||
COCOAPODS: 1.10.0
|
||||
COCOAPODS: 1.10.1
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
<string>applinks:beta.meet.jit.si</string>
|
||||
<string>applinks:meet.jit.si</string>
|
||||
</array>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.org.jitsi.meet.appgroup</string>
|
||||
</array>
|
||||
<key>com.apple.developer.siri</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|
||||
@@ -23,6 +23,12 @@
|
||||
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 */; };
|
||||
4E51B75E25E4115F0038575A /* DarwinNotificationCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E51B75D25E4115F0038575A /* DarwinNotificationCenter.m */; };
|
||||
4EC49BB725BEDAC100E76218 /* ReplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4EC49B8625BED71300E76218 /* ReplayKit.framework */; };
|
||||
4EC49BBB25BEDAC100E76218 /* SampleHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EC49BBA25BEDAC100E76218 /* SampleHandler.m */; };
|
||||
4EC49BBF25BEDAC100E76218 /* JitsiMeetBroadcast Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 4EC49BB625BEDAC100E76218 /* JitsiMeetBroadcast Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
4EC49BCB25BEDB6400E76218 /* SocketConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EC49BCA25BEDB6400E76218 /* SocketConnection.m */; };
|
||||
4EC49BD125BF19CF00E76218 /* SampleUploader.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EC49BD025BF19CF00E76218 /* SampleUploader.m */; };
|
||||
55BEDABDA92D47D399A70A5E /* libPods-JitsiMeet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D878B07B3FBD6E305EAA6B27 /* libPods-JitsiMeet.a */; };
|
||||
DE050389256E904600DEE3A5 /* WebRTC.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE050388256E904600DEE3A5 /* WebRTC.xcframework */; };
|
||||
DE05038A256E904600DEE3A5 /* WebRTC.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DE050388256E904600DEE3A5 /* WebRTC.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
@@ -48,6 +54,13 @@
|
||||
remoteGlobalIDString = 0BEA5C241F7B8F73000D0AB4;
|
||||
remoteInfo = JitsiMeetCompanion;
|
||||
};
|
||||
4EC49BBD25BEDAC100E76218 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 4EC49BB525BEDAC100E76218;
|
||||
remoteInfo = "JitsiMeetBroadcast Extension";
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -85,6 +98,17 @@
|
||||
name = "Embed Watch Content";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
4EC49B9025BED71300E76218 /* Embed App Extensions */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
4EC49BBF25BEDAC100E76218 /* JitsiMeetBroadcast Extension.appex in Embed App Extensions */,
|
||||
);
|
||||
name = "Embed App Extensions";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@@ -115,6 +139,18 @@
|
||||
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>"; };
|
||||
4670A512A688E2DC34528282 /* Pods-jitsi-meet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-jitsi-meet.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-jitsi-meet/Pods-jitsi-meet.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
4E51B75C25E4115F0038575A /* DarwinNotificationCenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinNotificationCenter.h; sourceTree = "<group>"; };
|
||||
4E51B75D25E4115F0038575A /* DarwinNotificationCenter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DarwinNotificationCenter.m; sourceTree = "<group>"; };
|
||||
4EC49B8625BED71300E76218 /* ReplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReplayKit.framework; path = System/Library/Frameworks/ReplayKit.framework; sourceTree = SDKROOT; };
|
||||
4EC49BB625BEDAC100E76218 /* JitsiMeetBroadcast Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "JitsiMeetBroadcast Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4EC49BB925BEDAC100E76218 /* SampleHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SampleHandler.h; sourceTree = "<group>"; };
|
||||
4EC49BBA25BEDAC100E76218 /* SampleHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SampleHandler.m; sourceTree = "<group>"; };
|
||||
4EC49BBC25BEDAC100E76218 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
4EC49BC925BEDB6400E76218 /* SocketConnection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SocketConnection.h; sourceTree = "<group>"; };
|
||||
4EC49BCA25BEDB6400E76218 /* SocketConnection.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SocketConnection.m; sourceTree = "<group>"; };
|
||||
4EC49BCF25BF19CF00E76218 /* SampleUploader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SampleUploader.h; sourceTree = "<group>"; };
|
||||
4EC49BD025BF19CF00E76218 /* SampleUploader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SampleUploader.m; sourceTree = "<group>"; };
|
||||
4EC49BDB25BF280A00E76218 /* extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = extension.entitlements; sourceTree = "<group>"; };
|
||||
609CB2080B75F75A89923F3D /* Pods-JitsiMeet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.debug.xcconfig"; path = "../Pods/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>"; };
|
||||
D878B07B3FBD6E305EAA6B27 /* libPods-JitsiMeet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-JitsiMeet.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -153,6 +189,14 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
4EC49BB325BEDAC100E76218 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4EC49BB725BEDAC100E76218 /* ReplayKit.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
@@ -165,6 +209,7 @@
|
||||
DEFDBBDB25656E3B00344B23 /* WebRTC.xcframework */,
|
||||
0BD6B4361EF82A6B00D1F4CD /* WebRTC.framework */,
|
||||
D878B07B3FBD6E305EAA6B27 /* libPods-JitsiMeet.a */,
|
||||
4EC49B8625BED71300E76218 /* ReplayKit.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -216,6 +261,24 @@
|
||||
path = src;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4EC49BB825BEDAC100E76218 /* JitsiMeetBroadcast Extension */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4EC49BDB25BF280A00E76218 /* extension.entitlements */,
|
||||
4EC49BB925BEDAC100E76218 /* SampleHandler.h */,
|
||||
4EC49BBA25BEDAC100E76218 /* SampleHandler.m */,
|
||||
4EC49BC925BEDB6400E76218 /* SocketConnection.h */,
|
||||
4EC49BCA25BEDB6400E76218 /* SocketConnection.m */,
|
||||
4EC49BCF25BF19CF00E76218 /* SampleUploader.h */,
|
||||
4EC49BD025BF19CF00E76218 /* SampleUploader.m */,
|
||||
4EC49BBC25BEDAC100E76218 /* Info.plist */,
|
||||
4E51B75C25E4115F0038575A /* DarwinNotificationCenter.h */,
|
||||
4E51B75D25E4115F0038575A /* DarwinNotificationCenter.m */,
|
||||
);
|
||||
name = "JitsiMeetBroadcast Extension";
|
||||
path = "broadcast-extension";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5E96ADD5E49F3B3822EF9A52 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -236,6 +299,7 @@
|
||||
13B07FAE1A68108700A75B9A /* src */,
|
||||
5E96ADD5E49F3B3822EF9A52 /* Pods */,
|
||||
0BEA5C261F7B8F73000D0AB4 /* Watch app */,
|
||||
4EC49BB825BEDAC100E76218 /* JitsiMeetBroadcast Extension */,
|
||||
0BEA5C351F7B8F73000D0AB4 /* WatchKit extension */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
@@ -248,6 +312,7 @@
|
||||
13B07F961A680F5B00A75B9A /* jitsi-meet.app */,
|
||||
0BEA5C251F7B8F73000D0AB4 /* JitsiMeetCompanion.app */,
|
||||
0BEA5C311F7B8F73000D0AB4 /* JitsiMeetCompanion Extension.appex */,
|
||||
4EC49BB625BEDAC100E76218 /* JitsiMeetBroadcast Extension.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -305,17 +370,36 @@
|
||||
DE11877A21EE09640078D059 /* Setup Google reverse URL handler */,
|
||||
DE4F6D6E22005C0400DE699E /* Setup Dropbox */,
|
||||
0BEA5C491F7B8F73000D0AB4 /* Embed Watch Content */,
|
||||
4EC49B9025BED71300E76218 /* Embed App Extensions */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
0BEA5C401F7B8F73000D0AB4 /* PBXTargetDependency */,
|
||||
4EC49BBE25BEDAC100E76218 /* PBXTargetDependency */,
|
||||
);
|
||||
name = JitsiMeet;
|
||||
productName = "Jitsi Meet";
|
||||
productReference = 13B07F961A680F5B00A75B9A /* jitsi-meet.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
4EC49BB525BEDAC100E76218 /* JitsiMeetBroadcast Extension */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 4EC49BC025BEDAC100E76218 /* Build configuration list for PBXNativeTarget "JitsiMeetBroadcast Extension" */;
|
||||
buildPhases = (
|
||||
4EC49BB225BEDAC100E76218 /* Sources */,
|
||||
4EC49BB325BEDAC100E76218 /* Frameworks */,
|
||||
4EC49BB425BEDAC100E76218 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "JitsiMeetBroadcast Extension";
|
||||
productName = "JitsiMeetBroadcast Extension";
|
||||
productReference = 4EC49BB625BEDAC100E76218 /* JitsiMeetBroadcast Extension.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
@@ -336,8 +420,6 @@
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
13B07F861A680F5B00A75B9A = {
|
||||
DevelopmentTeam = FC967L3QRG;
|
||||
ProvisioningStyle = Automatic;
|
||||
SystemCapabilities = {
|
||||
com.apple.SafariKeychain = {
|
||||
enabled = 1;
|
||||
@@ -347,6 +429,9 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
4EC49BB525BEDAC100E76218 = {
|
||||
CreatedOnToolsVersion = 12.2;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "app" */;
|
||||
@@ -365,6 +450,7 @@
|
||||
13B07F861A680F5B00A75B9A /* JitsiMeet */,
|
||||
0BEA5C241F7B8F73000D0AB4 /* JitsiMeetCompanion */,
|
||||
0BEA5C301F7B8F73000D0AB4 /* JitsiMeetCompanion Extension */,
|
||||
4EC49BB525BEDAC100E76218 /* JitsiMeetBroadcast Extension */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@@ -397,6 +483,13 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
4EC49BB425BEDAC100E76218 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
@@ -532,6 +625,17 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
4EC49BB225BEDAC100E76218 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4EC49BCB25BEDB6400E76218 /* SocketConnection.m in Sources */,
|
||||
4EC49BBB25BEDAC100E76218 /* SampleHandler.m in Sources */,
|
||||
4E51B75E25E4115F0038575A /* DarwinNotificationCenter.m in Sources */,
|
||||
4EC49BD125BF19CF00E76218 /* SampleUploader.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
@@ -545,6 +649,11 @@
|
||||
target = 0BEA5C241F7B8F73000D0AB4 /* JitsiMeetCompanion */;
|
||||
targetProxy = 0BEA5C3F1F7B8F73000D0AB4 /* PBXContainerItemProxy */;
|
||||
};
|
||||
4EC49BBE25BEDAC100E76218 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 4EC49BB525BEDAC100E76218 /* JitsiMeetBroadcast Extension */;
|
||||
targetProxy = 4EC49BBD25BEDAC100E76218 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
@@ -718,7 +827,7 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconDebug;
|
||||
CODE_SIGN_ENTITLEMENTS = app.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEAD_CODE_STRIPPING = NO;
|
||||
@@ -748,7 +857,7 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconRelease;
|
||||
CODE_SIGN_ENTITLEMENTS = app.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = FC967L3QRG;
|
||||
@@ -770,6 +879,70 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
4EC49BC125BEDAC100E76218 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
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 = "broadcast-extension/extension.entitlements";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = FC967L3QRG;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = "broadcast-extension/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet.broadcast.extension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
4EC49BC225BEDAC100E76218 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
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 = "broadcast-extension/extension.entitlements";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = FC967L3QRG;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = "broadcast-extension/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet.broadcast.extension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
83CBBA201A601CBA00E9B192 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -914,6 +1087,15 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
4EC49BC025BEDAC100E76218 /* Build configuration list for PBXNativeTarget "JitsiMeetBroadcast Extension" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
4EC49BC125BEDAC100E76218 /* Debug */,
|
||||
4EC49BC225BEDAC100E76218 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "app" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
||||
31
ios/app/broadcast-extension/DarwinNotificationCenter.h
Normal file
31
ios/app/broadcast-extension/DarwinNotificationCenter.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright @ 2021-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern NSNotificationName const kBroadcastStartedNotification;
|
||||
extern NSNotificationName const kBroadcastStoppedNotification;
|
||||
|
||||
@interface DarwinNotificationCenter: NSObject
|
||||
|
||||
+ (instancetype)sharedInstance;
|
||||
- (void)postNotificationWithName:(NSNotificationName)name;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
50
ios/app/broadcast-extension/DarwinNotificationCenter.m
Normal file
50
ios/app/broadcast-extension/DarwinNotificationCenter.m
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright @ 2021-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "DarwinNotificationCenter.h"
|
||||
|
||||
NSNotificationName const kBroadcastStartedNotification = @"iOS_BroadcastStarted";
|
||||
NSNotificationName const kBroadcastStoppedNotification = @"iOS_BroadcastStopped";
|
||||
|
||||
@implementation DarwinNotificationCenter {
|
||||
CFNotificationCenterRef _notificationCenter;
|
||||
}
|
||||
|
||||
+ (instancetype)sharedInstance {
|
||||
static DarwinNotificationCenter *sharedInstance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedInstance = [[self alloc] init];
|
||||
});
|
||||
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_notificationCenter = CFNotificationCenterGetDarwinNotifyCenter();
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)postNotificationWithName:(NSString*)name {
|
||||
CFNotificationCenterPostNotification(_notificationCenter, (__bridge CFStringRef)name, NULL, NULL, true);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
33
ios/app/broadcast-extension/Info.plist
Normal file
33
ios/app/broadcast-extension/Info.plist
Normal file
@@ -0,0 +1,33 @@
|
||||
<?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>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>JitsiMeet Broadcast Extension</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>21.1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.broadcast-services-upload</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>SampleHandler</string>
|
||||
<key>RPBroadcastProcessMode</key>
|
||||
<string>RPBroadcastProcessModeSampleBuffer</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
21
ios/app/broadcast-extension/SampleHandler.h
Normal file
21
ios/app/broadcast-extension/SampleHandler.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright @ 2021-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <ReplayKit/ReplayKit.h>
|
||||
|
||||
@interface SampleHandler : RPBroadcastSampleHandler
|
||||
|
||||
@end
|
||||
123
ios/app/broadcast-extension/SampleHandler.m
Normal file
123
ios/app/broadcast-extension/SampleHandler.m
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright @ 2021-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "SampleHandler.h"
|
||||
#import "SocketConnection.h"
|
||||
#import "SampleUploader.h"
|
||||
#import "DarwinNotificationCenter.h"
|
||||
|
||||
@interface SampleHandler ()
|
||||
|
||||
@property (nonatomic, retain) SocketConnection *clientConnection;
|
||||
@property (nonatomic, retain) SampleUploader *uploader;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SampleHandler
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.clientConnection = [[SocketConnection alloc] initWithFilePath:self.socketFilePath];
|
||||
[self setupConnection];
|
||||
|
||||
self.uploader = [[SampleUploader alloc] initWithConnection:self.clientConnection];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
|
||||
// User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
|
||||
NSLog(@"broadcast started");
|
||||
|
||||
[[DarwinNotificationCenter sharedInstance] postNotificationWithName:kBroadcastStartedNotification];
|
||||
[self openConnection];
|
||||
}
|
||||
|
||||
- (void)broadcastPaused {
|
||||
// User has requested to pause the broadcast. Samples will stop being delivered.
|
||||
}
|
||||
|
||||
- (void)broadcastResumed {
|
||||
// User has requested to resume the broadcast. Samples delivery will resume.
|
||||
}
|
||||
|
||||
- (void)broadcastFinished {
|
||||
// User has requested to finish the broadcast.
|
||||
[[DarwinNotificationCenter sharedInstance] postNotificationWithName:kBroadcastStoppedNotification];
|
||||
[self.clientConnection close];
|
||||
}
|
||||
|
||||
- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
|
||||
static NSUInteger frameCount = 0;
|
||||
switch (sampleBufferType) {
|
||||
case RPSampleBufferTypeVideo:
|
||||
// adjust frame rate by using every third frame
|
||||
if (++frameCount%3 == 0 && self.uploader.isReady) {
|
||||
[self.uploader sendSample:sampleBuffer];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Private Methods
|
||||
|
||||
- (NSString *)socketFilePath {
|
||||
// the appGroupIdentifier must match the value provided in the app's info.plist for the RTCAppGroupIdentifier key
|
||||
NSString *appGroupIdentifier = @"group.org.jitsi.meet.appgroup";
|
||||
NSURL *sharedContainer = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:appGroupIdentifier];
|
||||
NSString *socketFilePath = [[sharedContainer URLByAppendingPathComponent:@"rtc_SSFD"] path];
|
||||
|
||||
return socketFilePath;
|
||||
}
|
||||
|
||||
- (void)setupConnection {
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
self.clientConnection.didClose = ^(NSError *error) {
|
||||
NSLog(@"client connection did close: %@", error);
|
||||
if (error) {
|
||||
[weakSelf finishBroadcastWithError:error];
|
||||
}
|
||||
else {
|
||||
NSInteger JMScreenSharingStopped = 10001;
|
||||
NSError *customError = [NSError errorWithDomain:RPRecordingErrorDomain
|
||||
code:JMScreenSharingStopped
|
||||
userInfo:@{NSLocalizedDescriptionKey: @"Screen sharing stopped"}];
|
||||
[weakSelf finishBroadcastWithError:customError];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
- (void)openConnection {
|
||||
dispatch_queue_t queue = dispatch_queue_create("org.jitsi.meet.broadcast.connectTimer", 0);
|
||||
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
|
||||
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), 0.1 * NSEC_PER_SEC, 0.1 * NSEC_PER_SEC);
|
||||
|
||||
dispatch_source_set_event_handler(timer, ^{
|
||||
BOOL success = [self.clientConnection open];
|
||||
if (success) {
|
||||
dispatch_source_cancel(timer);
|
||||
}
|
||||
});
|
||||
|
||||
dispatch_resume(timer);
|
||||
}
|
||||
|
||||
@end
|
||||
33
ios/app/broadcast-extension/SampleUploader.h
Normal file
33
ios/app/broadcast-extension/SampleUploader.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright @ 2021-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <ReplayKit/ReplayKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class SocketConnection;
|
||||
|
||||
@interface SampleUploader : NSObject
|
||||
|
||||
@property (nonatomic, assign, readonly) BOOL isReady;
|
||||
|
||||
- (instancetype)initWithConnection:(SocketConnection *)connection;
|
||||
- (void)sendSample:(CMSampleBufferRef)sampleBuffer;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
157
ios/app/broadcast-extension/SampleUploader.m
Normal file
157
ios/app/broadcast-extension/SampleUploader.m
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright @ 2021-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <MessageUI/MessageUI.h>
|
||||
#import <ReplayKit/ReplayKit.h>
|
||||
|
||||
#import "SampleUploader.h"
|
||||
#import "SocketConnection.h"
|
||||
|
||||
static const NSInteger kBufferMaxLenght = 10 * 1024;
|
||||
|
||||
@interface SampleUploader ()
|
||||
|
||||
@property (nonatomic, assign) BOOL isReady;
|
||||
|
||||
@property (nonatomic, strong) dispatch_queue_t serialQueue;
|
||||
@property (nonatomic, strong) SocketConnection *connection;
|
||||
@property (nonatomic, strong) CIContext *imageContext;
|
||||
|
||||
@property (nonatomic, strong) NSData *dataToSend;
|
||||
@property (nonatomic, assign) NSUInteger byteIndex;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SampleUploader
|
||||
|
||||
- (instancetype)initWithConnection:(SocketConnection *)connection {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.serialQueue = dispatch_queue_create("org.jitsi.meet.broadcast.sampleUploader", DISPATCH_QUEUE_SERIAL);
|
||||
|
||||
self.connection = connection;
|
||||
[self setupConnection];
|
||||
|
||||
self.imageContext = [[CIContext alloc] initWithOptions:nil];
|
||||
self.isReady = false;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)sendSample:(CMSampleBufferRef)sampleBuffer {
|
||||
self.isReady = false;
|
||||
|
||||
self.dataToSend = [self prepareSample:sampleBuffer];
|
||||
self.byteIndex = 0;
|
||||
|
||||
dispatch_async(self.serialQueue, ^{
|
||||
[self sendData];
|
||||
});
|
||||
}
|
||||
|
||||
// MARK: Private Methods
|
||||
|
||||
- (void)setupConnection {
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
self.connection.didOpen = ^{
|
||||
weakSelf.isReady = true;
|
||||
};
|
||||
self.connection.streamHasSpaceAvailable = ^{
|
||||
dispatch_async(weakSelf.serialQueue, ^{
|
||||
weakSelf.isReady = ![weakSelf sendData];
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
This function downscales and converts to jpeg the provided sample buffer, then wraps the resulted image data into a CFHTTPMessageRef. Returns the serialized CFHTTPMessageRef.
|
||||
*/
|
||||
- (NSData *)prepareSample:(CMSampleBufferRef)sampleBuffer {
|
||||
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
|
||||
|
||||
CVPixelBufferLockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly);
|
||||
|
||||
CGFloat scaleFactor = 2;
|
||||
size_t width = CVPixelBufferGetWidth(imageBuffer)/scaleFactor;
|
||||
size_t height = CVPixelBufferGetHeight(imageBuffer)/scaleFactor;
|
||||
CGImagePropertyOrientation orientation = ((__bridge NSNumber*)CMGetAttachment(sampleBuffer, (__bridge CFStringRef)RPVideoSampleOrientationKey , NULL)).unsignedIntValue;
|
||||
|
||||
CGAffineTransform scaleTransform = CGAffineTransformMakeScale(1/scaleFactor, 1/scaleFactor);
|
||||
NSData *bufferData = [self jpegDataFromPixelBuffer:imageBuffer withScaling:scaleTransform];
|
||||
|
||||
CVPixelBufferUnlockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly);
|
||||
|
||||
if (bufferData) {
|
||||
CFHTTPMessageRef httpResponse = CFHTTPMessageCreateResponse(kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1);
|
||||
CFHTTPMessageSetHeaderFieldValue(httpResponse, (__bridge CFStringRef)@"Content-Length", (__bridge CFStringRef)[NSString stringWithFormat:@"%ld", bufferData.length]);
|
||||
CFHTTPMessageSetHeaderFieldValue(httpResponse, (__bridge CFStringRef)@"Buffer-Width", (__bridge CFStringRef)[NSString stringWithFormat:@"%ld", width]);
|
||||
CFHTTPMessageSetHeaderFieldValue(httpResponse, (__bridge CFStringRef)@"Buffer-Height", (__bridge CFStringRef)[NSString stringWithFormat:@"%ld", height]);
|
||||
CFHTTPMessageSetHeaderFieldValue(httpResponse, (__bridge CFStringRef)@"Buffer-Orientation", (__bridge CFStringRef)[NSString stringWithFormat:@"%u", orientation]);
|
||||
|
||||
CFHTTPMessageSetBody(httpResponse, (__bridge CFDataRef)bufferData);
|
||||
|
||||
CFDataRef serializedMessage = CFHTTPMessageCopySerializedMessage(httpResponse);
|
||||
CFRelease(httpResponse);
|
||||
|
||||
return CFBridgingRelease(serializedMessage);
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)sendData {
|
||||
if (!self.dataToSend) {
|
||||
NSLog(@"no data to send");
|
||||
return false;
|
||||
}
|
||||
|
||||
NSUInteger bytesLeft = self.dataToSend.length - self.byteIndex;
|
||||
|
||||
NSInteger length = bytesLeft > kBufferMaxLenght ? kBufferMaxLenght : bytesLeft;
|
||||
uint8_t buffer[length];
|
||||
[self.dataToSend getBytes:&buffer range:NSMakeRange(self.byteIndex, length)];
|
||||
|
||||
length = [self.connection writeBufferToStream:buffer maxLength:length];
|
||||
if (length > 0) {
|
||||
self.byteIndex += length;
|
||||
bytesLeft -= length;
|
||||
|
||||
if (bytesLeft == 0) {
|
||||
NSLog(@"video sample processed successfully");
|
||||
self.dataToSend = nil;
|
||||
self.byteIndex = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
NSLog(@"writeBufferToStream failure");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
- (NSData *)jpegDataFromPixelBuffer:(CVPixelBufferRef)pixelBuffer withScaling:(CGAffineTransform)scaleTransform {
|
||||
CIImage *image = [[CIImage alloc] initWithCVPixelBuffer:pixelBuffer];
|
||||
image = [image imageByApplyingTransform:scaleTransform];
|
||||
|
||||
NSDictionary *options = @{(NSString *)kCGImageDestinationLossyCompressionQuality: [NSNumber numberWithFloat:1.0]};
|
||||
NSData *imageData = [self.imageContext JPEGRepresentationOfImage:image
|
||||
colorSpace:image.colorSpace
|
||||
options:options];
|
||||
return imageData;
|
||||
}
|
||||
|
||||
@end
|
||||
34
ios/app/broadcast-extension/SocketConnection.h
Normal file
34
ios/app/broadcast-extension/SocketConnection.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright @ 2021-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SocketConnection : NSObject
|
||||
|
||||
@property (nonatomic, copy, nullable) void (^didOpen)(void);
|
||||
@property (nonatomic, copy, nullable) void (^didClose)(NSError*);
|
||||
@property (nonatomic, copy, nullable) void (^streamHasSpaceAvailable)(void);
|
||||
|
||||
- (instancetype)initWithFilePath:(nonnull NSString *)filePath;
|
||||
- (BOOL)open;
|
||||
- (void)close;
|
||||
- (NSInteger)writeBufferToStream:(const uint8_t*)buffer maxLength:(NSInteger)length;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
189
ios/app/broadcast-extension/SocketConnection.m
Normal file
189
ios/app/broadcast-extension/SocketConnection.m
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright @ 2021-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#import "SocketConnection.h"
|
||||
|
||||
@interface SocketConnection () <NSStreamDelegate>
|
||||
|
||||
@property (nonatomic, copy) NSString *filePath;
|
||||
|
||||
@property (nonatomic, strong) NSInputStream *inputStream;
|
||||
@property (nonatomic, strong) NSOutputStream *outputStream;
|
||||
|
||||
@property (nonatomic, strong) NSThread *networkThread;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SocketConnection {
|
||||
int _socket;
|
||||
struct sockaddr_un _socketAddr;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFilePath:(NSString *)path {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.filePath = path;
|
||||
|
||||
[self setupSocketWithFilePath:path];
|
||||
[self setupNetworkThread];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)open {
|
||||
NSLog(@"Open socket connection");
|
||||
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:self.filePath]) {
|
||||
NSLog(@"failure: socket file missing");
|
||||
return false;
|
||||
}
|
||||
|
||||
int status = connect(_socket, (struct sockaddr *)&_socketAddr, sizeof(_socketAddr));
|
||||
if (status < 0) {
|
||||
NSLog(@"failure: socket connect (%d)", status);
|
||||
return false;
|
||||
}
|
||||
|
||||
[self.networkThread start];
|
||||
|
||||
CFReadStreamRef readStream;
|
||||
CFWriteStreamRef writeStream;
|
||||
|
||||
CFStreamCreatePairWithSocket(kCFAllocatorDefault, _socket, &readStream, &writeStream);
|
||||
|
||||
self.inputStream = (__bridge_transfer NSInputStream *)readStream;
|
||||
self.inputStream.delegate = self;
|
||||
[self.inputStream setProperty:@"kCFBooleanTrue" forKey:@"kCFStreamPropertyShouldCloseNativeSocket"];
|
||||
|
||||
self.outputStream = (__bridge_transfer NSOutputStream *)writeStream;
|
||||
self.outputStream.delegate = self;
|
||||
[self.outputStream setProperty:@"kCFBooleanTrue" forKey:@"kCFStreamPropertyShouldCloseNativeSocket"];
|
||||
|
||||
[self performSelector:@selector(scheduleStreams) onThread:self.networkThread withObject:nil waitUntilDone:true];
|
||||
|
||||
[self.inputStream open];
|
||||
[self.outputStream open];
|
||||
|
||||
NSLog(@"read stream status: %ld", CFReadStreamGetStatus(readStream));
|
||||
NSLog(@"write stream status: %ld", CFWriteStreamGetStatus(writeStream));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
- (void)close {
|
||||
[self performSelector:@selector(unscheduleStreams) onThread:self.networkThread withObject:nil waitUntilDone:true];
|
||||
|
||||
self.inputStream.delegate = nil;
|
||||
self.outputStream.delegate = nil;
|
||||
|
||||
[self.inputStream close];
|
||||
[self.outputStream close];
|
||||
|
||||
[self.networkThread cancel];
|
||||
}
|
||||
|
||||
- (NSInteger)writeBufferToStream:(const uint8_t*)buffer maxLength:(NSInteger)length {
|
||||
return [self.outputStream write:buffer maxLength:length];
|
||||
}
|
||||
|
||||
// MARK: Private Methods
|
||||
|
||||
- (BOOL)isOpen {
|
||||
return self.inputStream.streamStatus == NSStreamStatusOpen && self.outputStream.streamStatus == NSStreamStatusOpen;
|
||||
}
|
||||
|
||||
- (void)setupSocketWithFilePath:(NSString*)path {
|
||||
_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
memset(&_socketAddr, 0, sizeof(_socketAddr));
|
||||
_socketAddr.sun_family = AF_UNIX;
|
||||
strncpy(_socketAddr.sun_path, path.UTF8String, sizeof(_socketAddr.sun_path) - 1);
|
||||
}
|
||||
|
||||
- (void)setupNetworkThread {
|
||||
self.networkThread = [[NSThread alloc] initWithBlock:^{
|
||||
do {
|
||||
@autoreleasepool {
|
||||
[[NSRunLoop currentRunLoop] run];
|
||||
}
|
||||
} while (![NSThread currentThread].isCancelled);
|
||||
}];
|
||||
self.networkThread.qualityOfService = NSQualityOfServiceUserInitiated;
|
||||
}
|
||||
|
||||
- (void)scheduleStreams {
|
||||
[self.inputStream scheduleInRunLoop:NSRunLoop.currentRunLoop forMode:NSRunLoopCommonModes];
|
||||
[self.outputStream scheduleInRunLoop:NSRunLoop.currentRunLoop forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
|
||||
- (void)unscheduleStreams {
|
||||
[self.inputStream removeFromRunLoop:NSRunLoop.currentRunLoop forMode:NSRunLoopCommonModes];
|
||||
[self.outputStream removeFromRunLoop:NSRunLoop.currentRunLoop forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
|
||||
- (void)notifyDidClose:(NSError *)error {
|
||||
if (self.didClose) {
|
||||
self.didClose(error);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - NSStreamDelegate
|
||||
|
||||
@implementation SocketConnection (NSStreamDelegate)
|
||||
|
||||
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
|
||||
switch (eventCode) {
|
||||
case NSStreamEventOpenCompleted:
|
||||
NSLog(@"client stream open completed");
|
||||
if (aStream == self.outputStream && self.didOpen) {
|
||||
self.didOpen();
|
||||
}
|
||||
break;
|
||||
case NSStreamEventHasBytesAvailable:
|
||||
if (aStream == self.inputStream) {
|
||||
uint8_t buffer;
|
||||
NSInteger numberOfBytesRead = [(NSInputStream *)aStream read:&buffer maxLength:sizeof(buffer)];
|
||||
if (!numberOfBytesRead && aStream.streamStatus == NSStreamStatusAtEnd) {
|
||||
NSLog(@"server socket closed");
|
||||
[self close];
|
||||
[self notifyDidClose:nil];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NSStreamEventHasSpaceAvailable:
|
||||
if (aStream == self.outputStream && self.streamHasSpaceAvailable) {
|
||||
NSLog(@"client stream has space available");
|
||||
self.streamHasSpaceAvailable();
|
||||
}
|
||||
break;
|
||||
case NSStreamEventErrorOccurred:
|
||||
NSLog(@"client stream error occurred: %@", aStream.streamError);
|
||||
[self close];
|
||||
[self notifyDidClose:aStream.streamError];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
10
ios/app/broadcast-extension/extension.entitlements
Normal file
10
ios/app/broadcast-extension/extension.entitlements
Normal file
@@ -0,0 +1,10 @@
|
||||
<?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>
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
jitsiMeet.defaultConferenceOptions = [JitsiMeetConferenceOptions fromBuilder:^(JitsiMeetConferenceOptionsBuilder *builder) {
|
||||
[builder setFeatureFlag:@"resolution" withValue:@(360)];
|
||||
[builder setFeatureFlag:@"ios.screensharing.enabled" withBoolean:YES];
|
||||
builder.serverURL = [NSURL URLWithString:@"https://meet.jit.si"];
|
||||
builder.welcomePageEnabled = YES;
|
||||
|
||||
@@ -51,7 +52,7 @@
|
||||
if ([FIRUtilities appContainsRealServiceInfoPlist]) {
|
||||
NSLog(@"Enabling Firebase");
|
||||
[FIRApp configure];
|
||||
// Crashlytics defaults to disabled wirth the FirebaseCrashlyticsCollectionEnabled Info.plist key.
|
||||
// Crashlytics defaults to disabled with the FirebaseCrashlyticsCollectionEnabled Info.plist key.
|
||||
[[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:![jitsiMeet isCrashReportingDisabled]];
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>21.0.0</string>
|
||||
<string>21.1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
@@ -45,6 +45,8 @@
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>FirebaseCrashlyticsCollectionEnabled</key>
|
||||
<string>false</string>
|
||||
<key>FirebaseScreenReportingEnabled</key>
|
||||
<false/>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
@@ -66,14 +68,18 @@
|
||||
<string>See your scheduled meetings in the app.</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Participate in meetings with video.</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Participate in meetings with voice.</string>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>Local network is used for establishing Peer-to-Peer connections.</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Participate in meetings with voice.</string>
|
||||
<key>NSUserActivityTypes</key>
|
||||
<array>
|
||||
<string>org.jitsi.JitsiMeet.ios.conference</string>
|
||||
</array>
|
||||
<key>RTCAppGroupIdentifier</key>
|
||||
<string>group.org.jitsi.meet.appgroup</string>
|
||||
<key>RTCScreenSharingExtension</key>
|
||||
<string>org.jitsi.meet.broadcast.extension</string>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>audio</string>
|
||||
@@ -99,7 +105,5 @@
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>FirebaseCrashlyticsCollectionEnabled</key>
|
||||
<string>false</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -131,6 +131,10 @@
|
||||
NSLog(@"%@%@", @"Chat toggled: ", data);
|
||||
}
|
||||
|
||||
- (void)videoMutedChanged:(NSDictionary *)data {
|
||||
NSLog(@"%@%@", @"Video muted changed: ", data[@"muted"]);
|
||||
}
|
||||
|
||||
#pragma mark - Helpers
|
||||
|
||||
- (void)terminate {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>21.0.0</string>
|
||||
<string>21.1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>21.0.0</string>
|
||||
<string>21.1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>CLKComplicationPrincipalClass</key>
|
||||
|
||||
@@ -35,7 +35,7 @@ fi
|
||||
|
||||
echo "PR_REPO_SLUG=${PR_REPO_SLUG} PR_BRANCH=${PR_BRANCH}"
|
||||
|
||||
# do the marge and git log
|
||||
# do the merge and git log
|
||||
|
||||
if [ $PR_BRANCH != "master" ]; then
|
||||
echo "Will merge ${PR_REPO_SLUG}/${PR_BRANCH} into master"
|
||||
|
||||
@@ -90,7 +90,7 @@ echo "importing dev-key.p12"
|
||||
security import ${CERT_DIR}/dev-key.p12 -k ios-build.keychain -P $IOS_SIGNING_CERT_PASSWORD -A
|
||||
|
||||
echo "will set-key-partition-list"
|
||||
# Fix for OS X Sierra that hungs in the codesign step
|
||||
# Fix for OS X Sierra that hangs in the codesign step
|
||||
security set-key-partition-list -S apple-tool:,apple: -s -k $ENCRYPTION_PASSWORD ios-build.keychain > /dev/null
|
||||
echo "done set-key-partition-list"
|
||||
|
||||
|
||||
@@ -9,6 +9,15 @@ platform :ios do
|
||||
# Make sure we are on a clean tree
|
||||
ensure_git_status_clean
|
||||
|
||||
# Connect to Apple Store Connect
|
||||
app_store_connect_api_key(
|
||||
key_id: ENV["ASC_KEY_ID"],
|
||||
issuer_id: ENV["ASC_ISSUER_ID"],
|
||||
key_content: ENV["ASC_KEY_CONTENT"],
|
||||
duration: 1200,
|
||||
in_house: false
|
||||
)
|
||||
|
||||
# Set the app identifier
|
||||
update_app_identifier(
|
||||
xcodeproj: "app/app.xcodeproj",
|
||||
@@ -16,6 +25,20 @@ platform :ios do
|
||||
app_identifier: "com.atlassian.JitsiMeet.ios"
|
||||
)
|
||||
|
||||
# Set the broadcast extension identifier
|
||||
update_app_identifier(
|
||||
xcodeproj: "app/app.xcodeproj",
|
||||
plist_path: "broadcast-extension/Info.plist",
|
||||
app_identifier: "com.atlassian.JitsiMeet.ios.broadcast"
|
||||
)
|
||||
update_info_plist(
|
||||
xcodeproj: "app/app.xcodeproj",
|
||||
plist_path: "src/Info.plist",
|
||||
block: proc do |plist|
|
||||
plist["RTCScreenSharingExtension"] = "com.atlassian.JitsiMeet.ios.broadcast"
|
||||
end
|
||||
)
|
||||
|
||||
# Set the (watch) app identifier
|
||||
update_app_identifier(
|
||||
xcodeproj: "app/app.xcodeproj",
|
||||
@@ -80,12 +103,24 @@ platform :ios do
|
||||
uses_non_exempt_encryption: false
|
||||
)
|
||||
|
||||
# Upload dSYMs to Crashlytics
|
||||
download_dsyms
|
||||
upload_symbols_to_crashlytics
|
||||
|
||||
# Cleanup
|
||||
clean_build_artifacts
|
||||
reset_git_repo(skip_clean: true)
|
||||
end
|
||||
|
||||
lane :refresh_dsyms do
|
||||
# Connect to Apple Store Connect
|
||||
app_store_connect_api_key(
|
||||
key_id: ENV["ASC_KEY_ID"],
|
||||
issuer_id: ENV["ASC_ISSUER_ID"],
|
||||
key_content: ENV["ASC_KEY_CONTENT"],
|
||||
duration: 1200,
|
||||
in_house: false
|
||||
)
|
||||
|
||||
# Upload dSYMs to Crashlytics
|
||||
download_dsyms(min_version: ENV["DSYMS_MIN_VERSION"]) # Download dSYM files from iTC
|
||||
upload_symbols_to_crashlytics # Upload them to Crashlytics
|
||||
clean_build_artifacts # Delete the local dSYM files
|
||||
end
|
||||
end
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
0BCA49601EC4B6C600B793EE /* POSIX.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BCA495D1EC4B6C600B793EE /* POSIX.m */; };
|
||||
0BCA49611EC4B6C600B793EE /* Proximity.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BCA495E1EC4B6C600B793EE /* Proximity.m */; };
|
||||
0BD906EA1EC0C00300C8C18E /* JitsiMeet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BD906E81EC0C00300C8C18E /* JitsiMeet.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
4E51B76425E5345E0038575A /* ScheenshareEventEmiter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E51B76225E5345E0038575A /* ScheenshareEventEmiter.h */; };
|
||||
4E51B76525E5345E0038575A /* ScheenshareEventEmiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E51B76325E5345E0038575A /* ScheenshareEventEmiter.m */; };
|
||||
6C31EDC820C06D490089C899 /* recordingOn.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 6C31EDC720C06D490089C899 /* recordingOn.mp3 */; };
|
||||
6C31EDCA20C06D530089C899 /* recordingOff.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 6C31EDC920C06D530089C899 /* recordingOff.mp3 */; };
|
||||
6F08DF7D4458EE3CF3F36F6D /* libPods-JitsiMeetSDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E4376CA6886DE68FD7A4294B /* libPods-JitsiMeetSDK.a */; };
|
||||
@@ -85,6 +87,8 @@
|
||||
0BD906E51EC0C00300C8C18E /* JitsiMeetSDK.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JitsiMeetSDK.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0BD906E81EC0C00300C8C18E /* JitsiMeet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeet.h; sourceTree = "<group>"; };
|
||||
0BD906E91EC0C00300C8C18E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
4E51B76225E5345E0038575A /* ScheenshareEventEmiter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScheenshareEventEmiter.h; sourceTree = "<group>"; };
|
||||
4E51B76325E5345E0038575A /* ScheenshareEventEmiter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ScheenshareEventEmiter.m; sourceTree = "<group>"; };
|
||||
6C31EDC720C06D490089C899 /* recordingOn.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = recordingOn.mp3; path = ../../sounds/recordingOn.mp3; sourceTree = "<group>"; };
|
||||
6C31EDC920C06D530089C899 /* recordingOff.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = recordingOff.mp3; path = ../../sounds/recordingOff.mp3; sourceTree = "<group>"; };
|
||||
75635B0820751D6D00F29C9F /* joined.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = joined.wav; path = ../../sounds/joined.wav; sourceTree = "<group>"; };
|
||||
@@ -231,6 +235,8 @@
|
||||
C8AFD27D2462C613000293D2 /* InfoPlistUtil.h */,
|
||||
C8AFD27E2462C613000293D2 /* InfoPlistUtil.m */,
|
||||
C81E9AB825AC5AD800B134D9 /* ExternalAPI.h */,
|
||||
4E51B76225E5345E0038575A /* ScheenshareEventEmiter.h */,
|
||||
4E51B76325E5345E0038575A /* ScheenshareEventEmiter.m */,
|
||||
);
|
||||
path = src;
|
||||
sourceTree = "<group>";
|
||||
@@ -298,6 +304,7 @@
|
||||
0B93EF7E1EC9DDCD0030D24D /* RCTBridgeWrapper.h in Headers */,
|
||||
DE81A2DE2317ED5400AE1940 /* JitsiMeetBaseLogHandler.h in Headers */,
|
||||
DEA9F284258A5D9900D4CD74 /* JitsiMeetSDK.h in Headers */,
|
||||
4E51B76425E5345E0038575A /* ScheenshareEventEmiter.h in Headers */,
|
||||
DE65AACC2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h in Headers */,
|
||||
0B412F221EDEF6EA00B1A0A6 /* JitsiMeetViewDelegate.h in Headers */,
|
||||
0BD906EA1EC0C00300C8C18E /* JitsiMeet.h in Headers */,
|
||||
@@ -466,6 +473,7 @@
|
||||
C69EFA0C209A0F660027712B /* JMCallKitEmitter.swift in Sources */,
|
||||
DEFE535621FB2E8300011A3A /* ReactUtils.m in Sources */,
|
||||
C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */,
|
||||
4E51B76525E5345E0038575A /* ScheenshareEventEmiter.m in Sources */,
|
||||
A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */,
|
||||
C69EFA0D209A0F660027712B /* JMCallKitProxy.swift in Sources */,
|
||||
DE81A2D52316AC4D00AE1940 /* JitsiMeetLogger.m in Sources */,
|
||||
|
||||
@@ -20,11 +20,12 @@
|
||||
|
||||
- (void)sendHangUp;
|
||||
- (void)sendSetAudioMuted:(BOOL)muted;
|
||||
- (void)sendEndpointTextMessage:(NSString*)to :(NSString*)message;
|
||||
- (void)sendEndpointTextMessage:(NSString*)message :(NSString*)to;
|
||||
- (void)toggleScreenShare;
|
||||
- (void)retrieveParticipantsInfo:(void (^)(NSArray*))completion;
|
||||
- (void)openChat:(NSString*)to;
|
||||
- (void)closeChat;
|
||||
- (void)sendChatMessage:(NSString*)to :(NSString*)message;
|
||||
- (void)sendChatMessage:(NSString*)message :(NSString*)to ;
|
||||
- (void)sendSetVideoMuted:(BOOL)muted;
|
||||
|
||||
@end
|
||||
|
||||
@@ -26,6 +26,7 @@ static NSString * const retrieveParticipantsInfoAction = @"org.jitsi.meet.RETRIE
|
||||
static NSString * const openChatAction = @"org.jitsi.meet.OPEN_CHAT";
|
||||
static NSString * const closeChatAction = @"org.jitsi.meet.CLOSE_CHAT";
|
||||
static NSString * const sendChatMessageAction = @"org.jitsi.meet.SEND_CHAT_MESSAGE";
|
||||
static NSString * const setVideoMutedAction = @"org.jitsi.meet.SET_VIDEO_MUTED";
|
||||
|
||||
@implementation ExternalAPI
|
||||
|
||||
@@ -47,7 +48,8 @@ RCT_EXPORT_MODULE();
|
||||
@"RETRIEVE_PARTICIPANTS_INFO": retrieveParticipantsInfoAction,
|
||||
@"OPEN_CHAT": openChatAction,
|
||||
@"CLOSE_CHAT": closeChatAction,
|
||||
@"SEND_CHAT_MESSAGE": sendChatMessageAction
|
||||
@"SEND_CHAT_MESSAGE": sendChatMessageAction,
|
||||
@"SET_VIDEO_MUTED" : setVideoMutedAction
|
||||
};
|
||||
};
|
||||
|
||||
@@ -70,7 +72,8 @@ RCT_EXPORT_MODULE();
|
||||
retrieveParticipantsInfoAction,
|
||||
openChatAction,
|
||||
closeChatAction,
|
||||
sendChatMessageAction
|
||||
sendChatMessageAction,
|
||||
setVideoMutedAction
|
||||
];
|
||||
}
|
||||
|
||||
@@ -153,7 +156,7 @@ RCT_EXPORT_METHOD(sendEvent:(NSString *)name
|
||||
[self sendEventWithName:setAudioMutedAction body:data];
|
||||
}
|
||||
|
||||
- (void)sendEndpointTextMessage:(NSString*)to :(NSString*)message {
|
||||
- (void)sendEndpointTextMessage:(NSString*)message :(NSString*)to {
|
||||
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
|
||||
data[@"to"] = to;
|
||||
data[@"message"] = message;
|
||||
@@ -185,7 +188,7 @@ RCT_EXPORT_METHOD(sendEvent:(NSString *)name
|
||||
[self sendEventWithName:closeChatAction body:nil];
|
||||
}
|
||||
|
||||
- (void)sendChatMessage:(NSString*)to :(NSString*)message {
|
||||
- (void)sendChatMessage:(NSString*)message :(NSString*)to {
|
||||
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
|
||||
data[@"to"] = to;
|
||||
data[@"message"] = message;
|
||||
@@ -193,4 +196,11 @@ RCT_EXPORT_METHOD(sendEvent:(NSString *)name
|
||||
[self sendEventWithName:sendChatMessageAction body:data];
|
||||
}
|
||||
|
||||
- (void)sendSetVideoMuted:(BOOL)muted {
|
||||
NSDictionary *data = @{ @"muted": [NSNumber numberWithBool:muted]};
|
||||
|
||||
[self sendEventWithName:setVideoMutedAction body:data];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.1.0</string>
|
||||
<string>3.4.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#import "RCTBridgeWrapper.h"
|
||||
#import "ReactUtils.h"
|
||||
#import "RNSplashScreen.h"
|
||||
#import "ScheenshareEventEmiter.h"
|
||||
|
||||
#import <RNGoogleSignin/RNGoogleSignin.h>
|
||||
#import <WebRTC/RTCLogging.h>
|
||||
@@ -31,6 +32,7 @@
|
||||
@implementation JitsiMeet {
|
||||
RCTBridgeWrapper *_bridgeWrapper;
|
||||
NSDictionary *_launchOptions;
|
||||
ScheenshareEventEmiter *_screenshareEventEmiter;
|
||||
}
|
||||
|
||||
#pragma mak - This class is a singleton
|
||||
@@ -50,6 +52,9 @@
|
||||
if (self = [super init]) {
|
||||
// Initialize the on and only bridge for interfacing with React Native.
|
||||
_bridgeWrapper = [[RCTBridgeWrapper alloc] init];
|
||||
|
||||
// Initialize the listener for handling start/stop screensharing notifications.
|
||||
_screenshareEventEmiter = [[ScheenshareEventEmiter alloc] init];
|
||||
|
||||
// Register a fatal error handler for React.
|
||||
registerReactFatalErrorHandler();
|
||||
|
||||
@@ -38,11 +38,12 @@
|
||||
- (void)leave;
|
||||
- (void)hangUp;
|
||||
- (void)setAudioMuted:(BOOL)muted;
|
||||
- (void)sendEndpointTextMessage:(NSString*)to :(NSString*)message;
|
||||
- (void)sendEndpointTextMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to;
|
||||
- (void)toggleScreenShare;
|
||||
- (void)retrieveParticipantsInfo:(void (^)(NSArray*))completionHandler;
|
||||
- (void)openChat:(NSString*)to;
|
||||
- (void)retrieveParticipantsInfo:(void (^ _Nonnull)(NSArray * _Nullable))completionHandler;
|
||||
- (void)openChat:(NSString * _Nullable)to;
|
||||
- (void)closeChat;
|
||||
- (void)sendChatMessage:(NSString*)to :(NSString*)message;
|
||||
- (void)sendChatMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to;
|
||||
- (void)setVideoMuted:(BOOL)muted;
|
||||
|
||||
@end
|
||||
|
||||
@@ -125,9 +125,9 @@ static void initializeViewsMap() {
|
||||
[externalAPI sendSetAudioMuted:muted];
|
||||
}
|
||||
|
||||
- (void)sendEndpointTextMessage:(NSString*)to :(NSString*)message {
|
||||
- (void)sendEndpointTextMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI sendEndpointTextMessage:to :message];
|
||||
[externalAPI sendEndpointTextMessage:message :to];
|
||||
}
|
||||
|
||||
- (void)toggleScreenShare {
|
||||
@@ -135,7 +135,7 @@ static void initializeViewsMap() {
|
||||
[externalAPI toggleScreenShare];
|
||||
}
|
||||
|
||||
- (void)retrieveParticipantsInfo:(void (^)(NSArray*))completionHandler {
|
||||
- (void)retrieveParticipantsInfo:(void (^ _Nonnull)(NSArray * _Nullable))completionHandler {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI retrieveParticipantsInfo:completionHandler];
|
||||
}
|
||||
@@ -150,9 +150,14 @@ static void initializeViewsMap() {
|
||||
[externalAPI closeChat];
|
||||
}
|
||||
|
||||
- (void)sendChatMessage:(NSString*)to :(NSString*)message {
|
||||
- (void)sendChatMessage:(NSString * _Nonnull)message :(NSString * _Nullable)to {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI sendChatMessage:to :message];
|
||||
[externalAPI sendChatMessage:message :to];
|
||||
}
|
||||
|
||||
- (void)setVideoMuted:(BOOL)muted {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI sendSetVideoMuted:muted];
|
||||
}
|
||||
|
||||
#pragma mark Private methods
|
||||
@@ -184,7 +189,7 @@ static void initializeViewsMap() {
|
||||
// conference. However, React and, respectively,
|
||||
// appProperties/initialProperties are declarative expressions i.e. one and
|
||||
// the same URL will not trigger an automatic re-render in the JavaScript
|
||||
// source code. The workaround implemented bellow introduces imperativeness
|
||||
// source code. The workaround implemented below introduces imperativeness
|
||||
// in React Component props by defining a unique value per invocation.
|
||||
props[@"timestamp"] = @(mach_absolute_time());
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
*
|
||||
* The `data` dictionary contains `message`, `senderId` and `isPrivate` keys.
|
||||
*/
|
||||
- (void)chatMessaageReceived:(NSDictionary *)data;
|
||||
- (void)chatMessageReceived:(NSDictionary *)data;
|
||||
|
||||
/**
|
||||
* Called when the chat dialog is displayed/hidden.
|
||||
@@ -104,4 +104,11 @@
|
||||
*/
|
||||
- (void)chatToggled:(NSDictionary *)data;
|
||||
|
||||
/**
|
||||
* Called when videoMuted state changed.
|
||||
*
|
||||
* The `data` dictionary contains a `muted` key with state of the videoMuted for the localParticipant.
|
||||
*/
|
||||
- (void)videoMutedChanged:(NSDictionary *)data;
|
||||
|
||||
@end
|
||||
|
||||
25
ios/sdk/src/ScheenshareEventEmiter.h
Normal file
25
ios/sdk/src/ScheenshareEventEmiter.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright @ 2021-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ScheenshareEventEmiter : NSObject
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
63
ios/sdk/src/ScheenshareEventEmiter.m
Normal file
63
ios/sdk/src/ScheenshareEventEmiter.m
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright @ 2021-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "ScheenshareEventEmiter.h"
|
||||
#import "JitsiMeet+Private.h"
|
||||
#import "ExternalAPI.h"
|
||||
|
||||
NSNotificationName const kBroadcastStartedNotification = @"iOS_BroadcastStarted";
|
||||
NSNotificationName const kBroadcastStoppedNotification = @"iOS_BroadcastStopped";
|
||||
|
||||
@implementation ScheenshareEventEmiter {
|
||||
CFNotificationCenterRef _notificationCenter;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_notificationCenter = CFNotificationCenterGetDarwinNotifyCenter();
|
||||
[self setupObserver];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self clearObserver];
|
||||
}
|
||||
|
||||
// MARK: Private Methods
|
||||
|
||||
- (void)setupObserver {
|
||||
CFNotificationCenterAddObserver(_notificationCenter, (__bridge const void *)(self), broadcastToggleNotificationCallback, (__bridge CFStringRef)kBroadcastStartedNotification, NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
|
||||
CFNotificationCenterAddObserver(_notificationCenter, (__bridge const void *)(self), broadcastToggleNotificationCallback, (__bridge CFStringRef)kBroadcastStoppedNotification, NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
|
||||
}
|
||||
|
||||
- (void)clearObserver {
|
||||
CFNotificationCenterRemoveObserver(_notificationCenter, (__bridge const void *)(self), (__bridge CFStringRef)kBroadcastStartedNotification, NULL);
|
||||
CFNotificationCenterRemoveObserver(_notificationCenter, (__bridge const void *)(self), (__bridge CFStringRef)kBroadcastStoppedNotification, NULL);
|
||||
}
|
||||
|
||||
void broadcastToggleNotificationCallback(CFNotificationCenterRef center,
|
||||
void *observer,
|
||||
CFStringRef name,
|
||||
const void *object,
|
||||
CFDictionaryRef userInfo) {
|
||||
ExternalAPI *externalAPI = [[JitsiMeet sharedInstance] getExternalAPI];
|
||||
[externalAPI toggleScreenShare];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -76,7 +76,7 @@ internal final class JMCallKitEmitter: NSObject, CXProviderDelegate {
|
||||
|
||||
// Avoid mute actions ping-pong: if the mute action was caused by
|
||||
// the JS side (we requested a transaction) don't call the delegate
|
||||
// method. If it was called by the provder itself (when the user presses
|
||||
// method. If it was called by the provider itself (when the user presses
|
||||
// the mute button in the CallKit view) then call the delegate method.
|
||||
//
|
||||
// NOTE: don't try to be clever and remove this. Been there, done that.
|
||||
|
||||
@@ -29,7 +29,7 @@ public protocol PiPViewCoordinatorDelegate: class {
|
||||
/// when is presented in Picure in Picture mode.
|
||||
public class PiPViewCoordinator {
|
||||
|
||||
/// Limits the boundries of view position on screen when minimized
|
||||
/// Limits the boundaries of view position on screen when minimized
|
||||
public var dragBoundInsets: UIEdgeInsets = UIEdgeInsets(top: 25,
|
||||
left: 5,
|
||||
bottom: 5,
|
||||
|
||||
@@ -60,7 +60,7 @@ fi
|
||||
|
||||
echo "PR_REPO_SLUG=${PR_REPO_SLUG} PR_BRANCH=${PR_BRANCH}"
|
||||
|
||||
# do the marge and git log
|
||||
# do the merge and git log
|
||||
|
||||
if [ $PR_BRANCH != "master" ]; then
|
||||
echo "Will merge ${PR_REPO_SLUG}/${PR_BRANCH} into master"
|
||||
|
||||
53
lang/languages-hi.json
Normal file
53
lang/languages-hi.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"en": "अंग्रेज़ी",
|
||||
"hi": "हिन्दी",
|
||||
"mr":"मराठी",
|
||||
"ml": "मलयालम",
|
||||
"enGB": "अंग्रेज़ी (UK)",
|
||||
"af": "Afrikaans",
|
||||
"ar": "Arabic",
|
||||
"bg": "Bulgarian",
|
||||
"ca": "Catalan",
|
||||
"cs": "Czech",
|
||||
"da": "Danish",
|
||||
"de": "German",
|
||||
"el": "Greek",
|
||||
"eo": "Esperanto",
|
||||
"es": "Spanish",
|
||||
"esUS": "Spanish (Latin America)",
|
||||
"et": "Estonian",
|
||||
"eu": "Basque",
|
||||
"fi": "Finnish",
|
||||
"fr": "French",
|
||||
"frCA": "French (Canadian)",
|
||||
"he": "Hebrew",
|
||||
"hr": "Croatian",
|
||||
"hu": "Hungarian",
|
||||
"hy": "Armenian",
|
||||
"id": "Indonesian",
|
||||
"it": "Italian",
|
||||
"ja": "Japanese",
|
||||
"kab": "Kabyle",
|
||||
"ko": "Korean",
|
||||
"lt": "Lithuanian",
|
||||
"lv": "Latvian",
|
||||
"nl": "Dutch",
|
||||
"oc": "Occitan",
|
||||
"fa": "Persian",
|
||||
"pl": "Polish",
|
||||
"pt": "Portuguese",
|
||||
"ptBR": "Portuguese (Brazil)",
|
||||
"ru": "Russian",
|
||||
"ro": "Romanian",
|
||||
"sc": "Sardinian",
|
||||
"sk": "Slovak",
|
||||
"sl": "Slovenian",
|
||||
"sr": "Serbian",
|
||||
"sv": "Swedish",
|
||||
"th": "Thailand",
|
||||
"tr": "Turkish",
|
||||
"uk": "Ukrainian",
|
||||
"vi": "Vietnamese",
|
||||
"zhCN": "Chinese (China)",
|
||||
"zhTW": "Chinese (Taiwan)"
|
||||
}
|
||||
@@ -1,27 +1,52 @@
|
||||
{
|
||||
"en": "영어",
|
||||
"af": "",
|
||||
"af": "아프리칸스어",
|
||||
"ar": "아랍어",
|
||||
"az": "아제르바이잔어",
|
||||
"bg": "불가리어",
|
||||
"cs": "체코어",
|
||||
"ca": "카탈루냐어",
|
||||
"cs": "체코어",
|
||||
"da": "덴마크어",
|
||||
"de": "독일어",
|
||||
"el": "그리스어",
|
||||
"enGB": "영어(영국)",
|
||||
"eo": "에스페란토어",
|
||||
"es": "스페인어",
|
||||
"esUS": "스페인어(라틴 아메리카)",
|
||||
"et": "에스토니아어",
|
||||
"eu": "바스크어",
|
||||
"fi": "핀란드어",
|
||||
"fr": "프랑스어",
|
||||
"frCA": "프랑스어(캐나다)",
|
||||
"he": "히브리어",
|
||||
"mr":"마라티어",
|
||||
"hr": "크로아티아어",
|
||||
"hu": "헝가리어",
|
||||
"hy": "아르메니아어",
|
||||
"id": "인도네시아어",
|
||||
"it": "이탈리아어",
|
||||
"ja": "일본어",
|
||||
"kab": "커바일어",
|
||||
"ko": "한국어",
|
||||
"nb": "노르웨이어",
|
||||
"oc": "",
|
||||
"lt": "리투아니아어",
|
||||
"ml": "말라얄람어",
|
||||
"lv": "라트비아어",
|
||||
"nl": "네덜란드어",
|
||||
"oc": "오크어",
|
||||
"fa": "페르시아어",
|
||||
"pl": "폴란드어",
|
||||
"ptBR": "포르투갈어(브라질)",
|
||||
"ru": "러시아어",
|
||||
"ro": "루마니아어",
|
||||
"sc": "사르데냐어",
|
||||
"sk": "슬로바키아어",
|
||||
"sl": "슬로베니아어",
|
||||
"sr": "세르비아어",
|
||||
"sv": "스웨덴어",
|
||||
"th": "태국어",
|
||||
"tr": "터키어",
|
||||
"uk": "우크라이나어",
|
||||
"vi": "베트남어",
|
||||
"zhCN": "중국어(중국)"
|
||||
}
|
||||
"zhCN": "중국어(중국)",
|
||||
"zhTW": "중국어(대만)"
|
||||
}
|
||||
|
||||
@@ -32,7 +32,9 @@
|
||||
"lv": "Leton",
|
||||
"nl": "Neerlandés",
|
||||
"oc": "Occitan",
|
||||
"fa": "Persa",
|
||||
"pl": "Polonés",
|
||||
"pt": "Portugués",
|
||||
"ptBR": "Portugués (Brasil)",
|
||||
"ru": "Rus",
|
||||
"ro": "Romanian",
|
||||
@@ -48,5 +50,3 @@
|
||||
"zhCN": "Chinés (China)",
|
||||
"zhTW": "Chinés (Taiwan)"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"fr": "French",
|
||||
"frCA": "French (Canadian)",
|
||||
"he": "Hebrew",
|
||||
"hi": "Hindi",
|
||||
"mr":"Marathi",
|
||||
"hr": "Croatian",
|
||||
"hu": "Hungarian",
|
||||
@@ -34,6 +35,7 @@
|
||||
"oc": "Occitan",
|
||||
"fa": "Persian",
|
||||
"pl": "Polish",
|
||||
"pt": "Portuguese",
|
||||
"ptBR": "Portuguese (Brazil)",
|
||||
"ru": "Russian",
|
||||
"ro": "Romanian",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user