Compare commits
13 Commits
develop
...
start-a-ne
Author | SHA1 | Date |
---|---|---|
GleidsonDaniel | 14481b368d | |
GleidsonDaniel | 1d144cf19c | |
GleidsonDaniel | 60defec633 | |
GleidsonDaniel | 4c4a0ba9b9 | |
GleidsonDaniel | 76c41474a6 | |
GleidsonDaniel | c6658d570b | |
GleidsonDaniel | 0cb9897bdf | |
GleidsonDaniel | d47de6193b | |
GleidsonDaniel | 1b3796ef17 | |
GleidsonDaniel | 9722550c9f | |
GleidsonDaniel | d36d5fd4e3 | |
GleidsonDaniel | 7a1aa58925 | |
GleidsonDaniel | 1fb060a982 |
|
@ -61,6 +61,11 @@ allprojects {
|
|||
maven {
|
||||
url "$rootDir/../node_modules/detox/Detox-android"
|
||||
}
|
||||
|
||||
maven {
|
||||
// expo-camera bundles a custom com.google.android:cameraview
|
||||
url "$rootDir/../node_modules/expo-camera/android/maven"
|
||||
}
|
||||
|
||||
mavenCentral {
|
||||
content {
|
||||
|
|
|
@ -84,3 +84,10 @@ export const ENCRYPTION = createRequestTypes('ENCRYPTION', ['INIT', 'STOP', 'DEC
|
|||
|
||||
export const PERMISSIONS = createRequestTypes('PERMISSIONS', ['SET', 'UPDATE']);
|
||||
export const ROLES = createRequestTypes('ROLES', ['SET', 'UPDATE', 'REMOVE']);
|
||||
export const VIDEO_CONF = createRequestTypes('VIDEO_CONF', [
|
||||
'HANDLE_INCOMING_WEBSOCKET_MESSAGES',
|
||||
'SET',
|
||||
'REMOVE',
|
||||
'CLEAR',
|
||||
'INIT_CALL'
|
||||
]);
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
import { Action } from 'redux';
|
||||
|
||||
import { ICallInfo } from '../reducers/videoConf';
|
||||
import { VIDEO_CONF } from './actionsTypes';
|
||||
|
||||
interface IHandleVideoConfIncomingWebsocketMessages extends Action {
|
||||
data: any;
|
||||
}
|
||||
|
||||
export type TCallProps = { mic: boolean; cam: boolean; direct: boolean; roomId: string };
|
||||
|
||||
export interface IVideoConfGenericAction extends Action {
|
||||
payload: ICallInfo;
|
||||
}
|
||||
|
||||
export type TActionVideoConf = IHandleVideoConfIncomingWebsocketMessages & IVideoConfGenericAction & Action;
|
||||
|
||||
export function handleVideoConfIncomingWebsocketMessages(data: any): IHandleVideoConfIncomingWebsocketMessages {
|
||||
return {
|
||||
type: VIDEO_CONF.HANDLE_INCOMING_WEBSOCKET_MESSAGES,
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
export function setVideoConfCall(payload: ICallInfo): IVideoConfGenericAction {
|
||||
return {
|
||||
type: VIDEO_CONF.SET,
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export function removeVideoConfCall(payload: ICallInfo): IVideoConfGenericAction {
|
||||
return {
|
||||
type: VIDEO_CONF.REMOVE,
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export function clearVideoConfCalls(): Action {
|
||||
return {
|
||||
type: VIDEO_CONF.CLEAR
|
||||
};
|
||||
}
|
||||
|
||||
export function initVideoCall(payload: TCallProps): Action & { payload: TCallProps } {
|
||||
return {
|
||||
type: VIDEO_CONF.INIT_CALL,
|
||||
payload
|
||||
};
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
import { Camera, CameraType } from 'expo-camera';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
|
@ -7,7 +8,6 @@ import { getSubscriptionByRoomId } from '../../../../lib/database/services/Subsc
|
|||
import { useAppSelector } from '../../../../lib/hooks';
|
||||
import { getRoomAvatar, getUidDirectMessage } from '../../../../lib/methods/helpers';
|
||||
import { useTheme } from '../../../../theme';
|
||||
import { useActionSheet } from '../../../ActionSheet';
|
||||
import AvatarContainer from '../../../Avatar';
|
||||
import Button from '../../../Button';
|
||||
import { CustomIcon } from '../../../CustomIcon';
|
||||
|
@ -15,16 +15,20 @@ import { BUTTON_HIT_SLOP } from '../../../message/utils';
|
|||
import StatusContainer from '../../../Status';
|
||||
import useStyle from './styles';
|
||||
|
||||
const CAM_SIZE = { height: 220, width: 148 };
|
||||
// fixed colors, do not change with theme change.
|
||||
const gray300 = '#5f656e';
|
||||
const gray100 = '#CBCED1';
|
||||
|
||||
export default function StartACallActionSheet({ rid, initCall }: { rid: string; initCall: Function }): React.ReactElement {
|
||||
const style = useStyle();
|
||||
const { colors } = useTheme();
|
||||
const [user, setUser] = useState({ username: '', avatar: '', uid: '' });
|
||||
const [mic, setMic] = useState(true);
|
||||
const [cam, setCam] = useState(false);
|
||||
const [calling, setCalling] = useState(true);
|
||||
const username = useAppSelector(state => state.login.user.username);
|
||||
|
||||
const { hideActionSheet } = useActionSheet();
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const room = await getSubscriptionByRoomId(rid);
|
||||
|
@ -34,26 +38,37 @@ export default function StartACallActionSheet({ rid, initCall }: { rid: string;
|
|||
})();
|
||||
}, [rid]);
|
||||
|
||||
const handleColor = (enabled: boolean) => (enabled ? colors.conferenceCallEnabledIcon : colors.conferenceCallDisabledIcon);
|
||||
const handleColors = (enabled: boolean) => {
|
||||
if (calling) {
|
||||
if (enabled) {
|
||||
return { button: colors.conferenceCallCallBackButton, icon: gray300 };
|
||||
}
|
||||
return { button: 'transparent', icon: gray100 };
|
||||
}
|
||||
if (enabled) {
|
||||
return { button: colors.conferenceCallEnabledIconBackground, icon: colors.conferenceCallEnabledIcon };
|
||||
}
|
||||
return { button: 'transparent', icon: colors.conferenceCallDisabledIcon };
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={style.actionSheetContainer}>
|
||||
<View style={style.actionSheetHeader}>
|
||||
<Text style={style.actionSheetHeaderTitle}>{i18n.t('Start_a_call')}</Text>
|
||||
<Text style={style.actionSheetHeaderTitle}>{calling ? i18n.t('Calling') : i18n.t('Start_a_call')}</Text>
|
||||
<View style={style.actionSheetHeaderButtons}>
|
||||
<Touchable
|
||||
onPress={() => setCam(!cam)}
|
||||
style={[style.iconCallContainer, cam && style.enabledBackground, { marginRight: 6 }]}
|
||||
style={[style.iconCallContainer, { backgroundColor: handleColors(cam).button }, { marginRight: 6 }]}
|
||||
hitSlop={BUTTON_HIT_SLOP}
|
||||
>
|
||||
<CustomIcon name={cam ? 'camera' : 'camera-disabled'} size={20} color={handleColor(cam)} />
|
||||
<CustomIcon name={cam ? 'camera' : 'camera-disabled'} size={20} color={handleColors(cam).icon} />
|
||||
</Touchable>
|
||||
<Touchable
|
||||
onPress={() => setMic(!mic)}
|
||||
style={[style.iconCallContainer, mic && style.enabledBackground]}
|
||||
style={[style.iconCallContainer, { backgroundColor: handleColors(mic).button }]}
|
||||
hitSlop={BUTTON_HIT_SLOP}
|
||||
>
|
||||
<CustomIcon name={mic ? 'microphone' : 'microphone-disabled'} size={20} color={handleColor(mic)} />
|
||||
<CustomIcon name={mic ? 'microphone' : 'microphone-disabled'} size={20} color={handleColors(mic).icon} />
|
||||
</Touchable>
|
||||
</View>
|
||||
</View>
|
||||
|
@ -64,17 +79,27 @@ export default function StartACallActionSheet({ rid, initCall }: { rid: string;
|
|||
{user.username}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={style.actionSheetPhotoContainer}>
|
||||
<AvatarContainer size={62} text={username} />
|
||||
<View
|
||||
style={[
|
||||
style.actionSheetPhotoContainer,
|
||||
CAM_SIZE,
|
||||
{ backgroundColor: cam ? undefined : colors.conferenceCallPhotoBackground }
|
||||
]}
|
||||
>
|
||||
{cam ? <Camera style={CAM_SIZE} type={CameraType.front} /> : <AvatarContainer size={62} text={username} />}
|
||||
</View>
|
||||
<Button
|
||||
backgroundColor={calling ? colors.conferenceCallCallBackButton : colors.actionTintColor}
|
||||
color={calling ? gray300 : colors.conferenceCallEnabledIcon}
|
||||
onPress={() => {
|
||||
hideActionSheet();
|
||||
setTimeout(() => {
|
||||
if (!calling) {
|
||||
setCalling(true);
|
||||
initCall({ cam, mic });
|
||||
}, 100);
|
||||
} else {
|
||||
setCalling(false);
|
||||
}
|
||||
}}
|
||||
title={i18n.t('Call')}
|
||||
title={calling ? i18n.t('Cancel') : i18n.t('Call')}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
|
|
@ -116,12 +116,12 @@ export default function useStyle() {
|
|||
actionSheetPhotoContainer: {
|
||||
height: 220,
|
||||
width: 148,
|
||||
backgroundColor: colors.conferenceCallPhotoBackground,
|
||||
borderRadius: 8,
|
||||
margin: 24,
|
||||
alignSelf: 'center',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
alignItems: 'center',
|
||||
overflow: 'hidden'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import database from '..';
|
||||
import { TSubscriptionModel } from '../../../definitions';
|
||||
import { TAppDatabase } from '../interfaces';
|
||||
import { SUBSCRIPTIONS_TABLE } from '../model/Subscription';
|
||||
|
||||
const getCollection = (db: TAppDatabase) => db.get(SUBSCRIPTIONS_TABLE);
|
||||
|
||||
export const getSubscriptionByRoomId = async (rid: string) => {
|
||||
export const getSubscriptionByRoomId = async (rid: string): Promise<TSubscriptionModel | null> => {
|
||||
const db = database.active;
|
||||
const subCollection = getCollection(db);
|
||||
try {
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
import { TypedUseSelectorHook, useSelector } from 'react-redux';
|
||||
import { select } from 'redux-saga/effects';
|
||||
|
||||
import { IApplicationState } from '../../definitions';
|
||||
|
||||
export const useAppSelector: TypedUseSelectorHook<IApplicationState> = useSelector;
|
||||
|
||||
export function* appSelector<TSelected>(selector: (state: IApplicationState) => TSelected): Generator<any, TSelected, TSelected> {
|
||||
return yield select(selector);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useDimensions } from '@react-native-community/hooks';
|
||||
import { useWindowDimensions } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
|
||||
// Not sure if it's worth adding this here in the context of the actionSheet
|
||||
|
@ -8,7 +8,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|||
*/
|
||||
export const useSnaps = (snaps: number[]): string[] => {
|
||||
const insets = useSafeAreaInsets();
|
||||
const { screen } = useDimensions();
|
||||
const { height, scale } = useWindowDimensions();
|
||||
const percentage = insets.bottom + insets.top > 75 ? 110 : 100;
|
||||
return snaps.map(snap => `${((percentage * snap) / (screen.height * screen.scale)).toFixed(2)}%`);
|
||||
return snaps.map(snap => `${((percentage * snap) / (height * scale)).toFixed(2)}%`);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import { Camera } from 'expo-camera';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { useActionSheet } from '../../containers/ActionSheet';
|
||||
import StartACallActionSheet from '../../containers/UIKit/VideoConferenceBlock/components/StartACallActionSheet';
|
||||
|
@ -10,7 +11,7 @@ import database from '../database';
|
|||
import { getSubscriptionByRoomId } from '../database/services/Subscription';
|
||||
import { callJitsi } from '../methods';
|
||||
import { compareServerVersion, showErrorAlert } from '../methods/helpers';
|
||||
import { videoConfStartAndJoin } from '../methods/videoConf';
|
||||
import { handleAndroidBltPermission, videoConfStartAndJoin } from '../methods/videoConf';
|
||||
import { Services } from '../services';
|
||||
import { useAppSelector } from './useAppSelector';
|
||||
import { useSnaps } from './useSnaps';
|
||||
|
@ -35,6 +36,8 @@ export const useVideoConf = (rid: string): { showInitCallActionSheet: () => Prom
|
|||
const jitsiEnableChannels = useAppSelector(state => state.settings.Jitsi_Enable_Channels);
|
||||
const user = useAppSelector(state => getUserSelector(state));
|
||||
|
||||
const [permission, requestPermission] = Camera.useCameraPermissions();
|
||||
|
||||
const isServer5OrNewer = compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '5.0.0');
|
||||
|
||||
const { showActionSheet } = useActionSheet();
|
||||
|
@ -87,6 +90,10 @@ export const useVideoConf = (rid: string): { showInitCallActionSheet: () => Prom
|
|||
children: <StartACallActionSheet rid={rid} initCall={initCall} />,
|
||||
snaps
|
||||
});
|
||||
if (!permission?.granted) {
|
||||
requestPermission();
|
||||
handleAndroidBltPermission();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ import { E2E_MESSAGE_TYPE } from '../../constants';
|
|||
import { getRoom } from '../getRoom';
|
||||
import { merge } from '../helpers/mergeSubscriptionsRooms';
|
||||
import { getRoomAvatar, getRoomTitle, getSenderName, random } from '../helpers';
|
||||
import { handleVideoConfIncomingWebsocketMessages } from '../../../actions/videoConf';
|
||||
|
||||
const removeListener = (listener: { stop: () => void }) => listener.stop();
|
||||
|
||||
|
@ -402,6 +403,11 @@ export default function subscribeRooms() {
|
|||
log(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (/video-conference/.test(ev)) {
|
||||
const [action, params] = ddpMessage.fields.args;
|
||||
store.dispatch(handleVideoConfIncomingWebsocketMessages({ action, params }));
|
||||
}
|
||||
});
|
||||
|
||||
const stop = () => {
|
||||
|
|
|
@ -19,18 +19,17 @@ const handleBltPermission = async (): Promise<Permission[]> => {
|
|||
return [PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION];
|
||||
};
|
||||
|
||||
export const handleAndroidBltPermission = async (): Promise<void> => {
|
||||
if (isAndroid) {
|
||||
const bltPermission = await handleBltPermission();
|
||||
await PermissionsAndroid.requestMultiple(bltPermission);
|
||||
}
|
||||
};
|
||||
|
||||
export const videoConfJoin = async (callId: string, cam?: boolean, mic?: boolean): Promise<void> => {
|
||||
try {
|
||||
const result = await Services.videoConferenceJoin(callId, cam, mic);
|
||||
if (result.success) {
|
||||
if (isAndroid) {
|
||||
const bltPermission = await handleBltPermission();
|
||||
await PermissionsAndroid.requestMultiple([
|
||||
PermissionsAndroid.PERMISSIONS.CAMERA,
|
||||
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
|
||||
...bltPermission
|
||||
]);
|
||||
}
|
||||
const { url, providerName } = result;
|
||||
if (providerName === 'jitsi') {
|
||||
navigation.navigate('JitsiMeetView', { url, onlyAudio: !cam, videoConf: true });
|
||||
|
|
|
@ -21,6 +21,7 @@ import enterpriseModules from './enterpriseModules';
|
|||
import encryption from './encryption';
|
||||
import permissions from './permissions';
|
||||
import roles from './roles';
|
||||
import videoConf from './videoConf';
|
||||
|
||||
export default combineReducers({
|
||||
settings,
|
||||
|
@ -43,5 +44,6 @@ export default combineReducers({
|
|||
enterpriseModules,
|
||||
encryption,
|
||||
permissions,
|
||||
roles
|
||||
roles,
|
||||
videoConf
|
||||
});
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import { clearVideoConfCalls, removeVideoConfCall, setVideoConfCall } from '../actions/videoConf';
|
||||
import { mockedStore } from './mockedStore';
|
||||
import { initialState, ICallInfo } from './videoConf';
|
||||
|
||||
describe('test videoConf reducer', () => {
|
||||
it('should return initial state', () => {
|
||||
const state = mockedStore.getState().settings;
|
||||
expect(state).toEqual(initialState);
|
||||
});
|
||||
|
||||
const call1: ICallInfo = {
|
||||
callId: '123',
|
||||
rid: '123',
|
||||
type: 'accepted',
|
||||
uid: '123'
|
||||
};
|
||||
|
||||
const call2: ICallInfo = {
|
||||
callId: '321',
|
||||
rid: '321',
|
||||
type: 'accepted',
|
||||
uid: '321'
|
||||
};
|
||||
|
||||
it('should return call1 after call addSettings action with call1 as parameter', () => {
|
||||
mockedStore.dispatch(setVideoConfCall(call1));
|
||||
const state = mockedStore.getState().videoConf;
|
||||
expect(state[call1.callId]).toEqual(call1);
|
||||
});
|
||||
|
||||
it('should return call2 after call addSettings action with call2 as parameter', () => {
|
||||
mockedStore.dispatch(setVideoConfCall(call2));
|
||||
const state = mockedStore.getState().videoConf;
|
||||
expect(state[call2.callId]).toEqual(call2);
|
||||
});
|
||||
|
||||
it('should remove call1 after call removeVideoConfCall action with call1 as parameter', () => {
|
||||
mockedStore.dispatch(removeVideoConfCall(call1));
|
||||
const state = mockedStore.getState().videoConf;
|
||||
expect(state[call1.callId]).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('should return initial state after clearSettings', () => {
|
||||
mockedStore.dispatch(clearVideoConfCalls());
|
||||
const state = mockedStore.getState().videoConf;
|
||||
expect(state).toEqual({});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,33 @@
|
|||
import { VIDEO_CONF } from '../actions/actionsTypes';
|
||||
import { TActionVideoConf } from '../actions/videoConf';
|
||||
|
||||
export type TSupportedCallStatus = 'call' | 'canceled' | 'accepted' | 'rejected' | 'confirmed' | 'join' | 'end';
|
||||
|
||||
export interface ICallInfo {
|
||||
callId: string;
|
||||
rid: string;
|
||||
uid: string;
|
||||
type: TSupportedCallStatus;
|
||||
}
|
||||
|
||||
interface ICallInfoRecord {
|
||||
[key: string]: ICallInfo;
|
||||
}
|
||||
|
||||
export const initialState: ICallInfoRecord = {};
|
||||
|
||||
export default (state = initialState, action: TActionVideoConf): ICallInfoRecord => {
|
||||
switch (action.type) {
|
||||
case VIDEO_CONF.SET:
|
||||
return {
|
||||
...state,
|
||||
[action.payload.callId]: action.payload
|
||||
};
|
||||
case VIDEO_CONF.REMOVE:
|
||||
return Object.fromEntries(Object.entries(state).filter(([key]) => key !== action.payload.callId));
|
||||
case VIDEO_CONF.CLEAR:
|
||||
return initialState;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
|
@ -13,6 +13,7 @@ import deepLinking from './deepLinking';
|
|||
import inviteLinks from './inviteLinks';
|
||||
import createDiscussion from './createDiscussion';
|
||||
import encryption from './encryption';
|
||||
import videoConf from './videoConf';
|
||||
|
||||
const root = function* root() {
|
||||
yield all([
|
||||
|
@ -28,7 +29,8 @@ const root = function* root() {
|
|||
inviteLinks(),
|
||||
createDiscussion(),
|
||||
inquiry(),
|
||||
encryption()
|
||||
encryption(),
|
||||
videoConf()
|
||||
]);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
import { Action } from 'redux';
|
||||
import { call, takeLatest } from 'typed-redux-saga';
|
||||
|
||||
import { VIDEO_CONF } from '../actions/actionsTypes';
|
||||
import { IVideoConfGenericAction, TCallProps } from '../actions/videoConf';
|
||||
import i18n from '../i18n';
|
||||
import { getSubscriptionByRoomId } from '../lib/database/services/Subscription';
|
||||
import { appSelector } from '../lib/hooks';
|
||||
import { callJitsi } from '../lib/methods';
|
||||
import { compareServerVersion, showErrorAlert } from '../lib/methods/helpers';
|
||||
import log from '../lib/methods/helpers/log';
|
||||
import { videoConfJoin } from '../lib/methods/videoConf';
|
||||
import { Services } from '../lib/services';
|
||||
import { ICallInfo } from '../reducers/videoConf';
|
||||
|
||||
type TGenerator = Generator<IVideoConfGenericAction>;
|
||||
|
||||
function* onDirectCall(payload: ICallInfo): TGenerator {
|
||||
return null;
|
||||
}
|
||||
|
||||
function* onDirectCallCanceled(payload: ICallInfo): TGenerator {
|
||||
return null;
|
||||
}
|
||||
|
||||
function* onDirectCallAccepted(payload: ICallInfo): TGenerator {
|
||||
return null;
|
||||
}
|
||||
|
||||
function* onDirectCallRejected(payload: ICallInfo): TGenerator {
|
||||
return null;
|
||||
}
|
||||
|
||||
function* onDirectCallConfirmed(payload: ICallInfo): TGenerator {
|
||||
return null;
|
||||
}
|
||||
|
||||
function* onDirectCallJoined(payload: ICallInfo): TGenerator {
|
||||
return null;
|
||||
}
|
||||
|
||||
function* onDirectCallEnded(payload: ICallInfo): TGenerator {
|
||||
return null;
|
||||
}
|
||||
|
||||
function* handleVideoConfIncomingWebsocketMessages({ data }: { data: any }) {
|
||||
const { action, params } = data.action;
|
||||
|
||||
if (!action || typeof action !== 'string') {
|
||||
return;
|
||||
}
|
||||
if (!params || typeof params !== 'object' || !params.callId || !params.uid || !params.rid) {
|
||||
return;
|
||||
}
|
||||
const prop = { ...params, action };
|
||||
switch (action) {
|
||||
case 'call':
|
||||
yield call(onDirectCall, prop);
|
||||
break;
|
||||
case 'canceled':
|
||||
yield call(onDirectCallCanceled, prop);
|
||||
break;
|
||||
case 'accepted':
|
||||
yield call(onDirectCallAccepted, prop);
|
||||
break;
|
||||
case 'rejected':
|
||||
yield call(onDirectCallRejected, prop);
|
||||
break;
|
||||
case 'confirmed':
|
||||
yield call(onDirectCallConfirmed, prop);
|
||||
break;
|
||||
case 'join':
|
||||
yield call(onDirectCallJoined, prop);
|
||||
break;
|
||||
case 'end':
|
||||
yield call(onDirectCallEnded, prop);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function* initCall({ payload: { mic, cam, direct, roomId } }: { payload: TCallProps }) {
|
||||
const serverVersion = yield* appSelector(state => state.server.version);
|
||||
const isServer5OrNewer = compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '5.0.0');
|
||||
if (isServer5OrNewer) {
|
||||
try {
|
||||
const videoConfResponse = yield* call(Services.videoConferenceStart, roomId);
|
||||
if (videoConfResponse.success) {
|
||||
if (direct) {
|
||||
// callUser({ uid: data.calleeId, rid: roomId, callId: data.callId });
|
||||
} else {
|
||||
videoConfJoin(videoConfResponse.data.callId, cam, mic);
|
||||
}
|
||||
// setCalling(false);
|
||||
}
|
||||
} catch (e) {
|
||||
// setCalling(false);
|
||||
showErrorAlert(i18n.t('error-init-video-conf'));
|
||||
log(e);
|
||||
}
|
||||
} else {
|
||||
const sub = yield* call(getSubscriptionByRoomId, roomId);
|
||||
if (sub) {
|
||||
callJitsi({ room: sub, cam });
|
||||
// setCalling(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface IGenericAction extends Action {
|
||||
type: string;
|
||||
}
|
||||
|
||||
export default function* root(): Generator {
|
||||
yield takeLatest<
|
||||
IGenericAction & {
|
||||
data: any;
|
||||
}
|
||||
>(VIDEO_CONF.HANDLE_INCOMING_WEBSOCKET_MESSAGES, handleVideoConfIncomingWebsocketMessages);
|
||||
yield takeLatest<IGenericAction & { payload: TCallProps }>(VIDEO_CONF.INIT_CALL, initCall);
|
||||
}
|
|
@ -47,7 +47,7 @@
|
|||
"@react-native-community/blur": "^4.1.0",
|
||||
"@react-native-community/cameraroll": "4.1.2",
|
||||
"@react-native-community/datetimepicker": "3.5.2",
|
||||
"@react-native-community/hooks": "2.6.0",
|
||||
"@react-native-community/hooks": "3.0.0",
|
||||
"@react-native-community/netinfo": "6.0.0",
|
||||
"@react-native-community/picker": "^1.8.1",
|
||||
"@react-native-community/slider": "4.2.2",
|
||||
|
@ -73,6 +73,7 @@
|
|||
"expo": "^46.0.9",
|
||||
"expo-apple-authentication": "4.2.1",
|
||||
"expo-av": "11.2.3",
|
||||
"expo-camera": "12.5.0",
|
||||
"expo-file-system": "14.0.0",
|
||||
"expo-haptics": "11.2.0",
|
||||
"expo-keep-awake": "10.1.1",
|
||||
|
@ -145,6 +146,7 @@
|
|||
"rn-fetch-blob": "^0.12.0",
|
||||
"rn-root-view": "RocketChat/rn-root-view",
|
||||
"semver": "^7.3.8",
|
||||
"typed-redux-saga": "^1.5.0",
|
||||
"ua-parser-js": "^1.0.32",
|
||||
"uri-js": "^4.4.1",
|
||||
"url-parse": "1.5.10",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "esnext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */,
|
||||
"target": "ESNEXT" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */,
|
||||
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
"allowJs": true /* Allow javascript files to be compiled. */,
|
||||
|
|
53
yarn.lock
53
yarn.lock
|
@ -801,6 +801,13 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.14.5"
|
||||
|
||||
"@babel/helper-module-imports@^7.14.5", "@babel/helper-module-imports@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
|
||||
integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==
|
||||
dependencies:
|
||||
"@babel/types" "^7.18.6"
|
||||
|
||||
"@babel/helper-module-imports@^7.16.7":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437"
|
||||
|
@ -808,13 +815,6 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.16.7"
|
||||
|
||||
"@babel/helper-module-imports@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
|
||||
integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==
|
||||
dependencies:
|
||||
"@babel/types" "^7.18.6"
|
||||
|
||||
"@babel/helper-module-transforms@^7.10.4":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.10.4.tgz#ca1f01fdb84e48c24d7506bb818c961f1da8805d"
|
||||
|
@ -4831,6 +4831,13 @@
|
|||
"@jridgewell/resolve-uri" "^3.0.3"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
|
||||
"@koale/useworker@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@koale/useworker/-/useworker-4.0.2.tgz#cb540a2581cd6025307c3ca6685bc60748773e58"
|
||||
integrity sha512-xPIPADtom8/3/4FLNj7MvNcBM/Z2FleH85Fdx2O869eoKW8+PoEgtSVvoxWjCWMA46Sm9A5/R1TyzNGc+yM0wg==
|
||||
dependencies:
|
||||
dequal "^1.0.0"
|
||||
|
||||
"@mdx-js/mdx@^1.6.22":
|
||||
version "1.6.22"
|
||||
resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-1.6.22.tgz#8a723157bf90e78f17dc0f27995398e6c731f1ba"
|
||||
|
@ -5176,10 +5183,10 @@
|
|||
dependencies:
|
||||
invariant "^2.2.4"
|
||||
|
||||
"@react-native-community/hooks@2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-native-community/hooks/-/hooks-2.6.0.tgz#dd5f19601eb3684c6bcdd3df3d0c04cf44c24cff"
|
||||
integrity sha512-emBGKvhJ0h++lLJQ5ejsj+od9G67nEaihjvfSx7/JWvNrQGAhP9U0OZqgb9dkKzor9Ufaj9SGt8RNY97cGzttw==
|
||||
"@react-native-community/hooks@3.0.0":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-native-community/hooks/-/hooks-3.0.0.tgz#af5f2ca32eea59b792ce9e3d9a4cf0354f9b195f"
|
||||
integrity sha512-g2OyxXHfwIytXUJitBR6Z/ISoOfp0WKx5FOv+NqJ/CrWjRDcTw6zXE5I1C9axfuh30kJqzWchVfCDrkzZYTxqg==
|
||||
|
||||
"@react-native-community/netinfo@6.0.0":
|
||||
version "6.0.0"
|
||||
|
@ -7698,7 +7705,7 @@ babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.8.0:
|
|||
cosmiconfig "^6.0.0"
|
||||
resolve "^1.12.0"
|
||||
|
||||
babel-plugin-macros@^3.0.1:
|
||||
babel-plugin-macros@^3.0.1, babel-plugin-macros@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1"
|
||||
integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==
|
||||
|
@ -9762,6 +9769,11 @@ deprecated-react-native-prop-types@^2.3.0:
|
|||
invariant "*"
|
||||
prop-types "*"
|
||||
|
||||
dequal@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/dequal/-/dequal-1.0.1.tgz#dbbf9795ec626e9da8bd68782f4add1d23700d8b"
|
||||
integrity sha512-Fx8jxibzkJX2aJgyfSdLhr9tlRoTnHKrRJuu2XHlAgKioN2j19/Bcbe0d4mFXYZ3+wpE2KVobUVTfDutcD17xQ==
|
||||
|
||||
dequal@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.2.tgz#85ca22025e3a87e65ef75a7a437b35284a7e319d"
|
||||
|
@ -10878,6 +10890,15 @@ expo-av@11.2.3:
|
|||
dependencies:
|
||||
"@expo/config-plugins" "^4.0.14"
|
||||
|
||||
expo-camera@12.5.0:
|
||||
version "12.5.0"
|
||||
resolved "https://registry.yarnpkg.com/expo-camera/-/expo-camera-12.5.0.tgz#aac8441ea661ed21becf064e715dd50d5448aaae"
|
||||
integrity sha512-oiQccJ9d2FnGdlLKaRphZ2DpwI9C1yD4HUZDacsAR+8904xv3Mhf6u78mh9yBPs6Z7dbtgSjOFtFu5s29PeTxA==
|
||||
dependencies:
|
||||
"@expo/config-plugins" "~5.0.0"
|
||||
"@koale/useworker" "^4.0.2"
|
||||
invariant "^2.2.4"
|
||||
|
||||
expo-constants@~13.2.2, expo-constants@~13.2.4:
|
||||
version "13.2.4"
|
||||
resolved "https://registry.yarnpkg.com/expo-constants/-/expo-constants-13.2.4.tgz#eab4a553f074b2c60ad7a158d3b82e3484a94606"
|
||||
|
@ -20114,6 +20135,14 @@ type-is@~1.6.17, type-is@~1.6.18:
|
|||
media-typer "0.3.0"
|
||||
mime-types "~2.1.24"
|
||||
|
||||
typed-redux-saga@^1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/typed-redux-saga/-/typed-redux-saga-1.5.0.tgz#f70b47c92c6e29e0184d0c30d563c18d6ad0ae54"
|
||||
integrity sha512-XHKliNtRNUegYAAztbVDb5Q+FMqYNQPaed6Xq2N8kz8AOmiOCVxW3uIj7TEptR1/ms6M9u3HEDfJr4qqz/PYrw==
|
||||
optionalDependencies:
|
||||
"@babel/helper-module-imports" "^7.14.5"
|
||||
babel-plugin-macros "^3.1.0"
|
||||
|
||||
typedarray-to-buffer@^3.1.5:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
|
||||
|
|
Loading…
Reference in New Issue