feat: Add jitsi auth info (#5231)
* migrate JitsiMeetView to hooks * create JitsiAuthModal component * Update app/i18n/locales/en.json Co-authored-by: Diego Mello <diegolmello@gmail.com> * Update JitsiAuthModal.tsx * typo * fix colors --------- Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
4ccf815746
commit
9fa29047dd
|
@ -743,6 +743,11 @@
|
|||
"accept": "Accept",
|
||||
"Incoming_call_from": "Incoming call from",
|
||||
"Call_started": "Call started",
|
||||
"Jitsi_may_require_authentication": "Jitsi may require authentication",
|
||||
"Jitsi_authentication_before_making_calls_admin": "Jitsi may require authentication before making calls. To learn more about their policies, visit the Jitsi website. You can also update the default app for video calls in the preferences.",
|
||||
"Jitsi_authentication_before_making_calls": "Jitsi may require authentication before making calls. To learn more about their policies, visit the Jitsi website.",
|
||||
"Jitsi_authentication_before_making_calls_ask_admin": "If you believe there are problems with Jitsi and its authentication, ask a workspace administrator for help.",
|
||||
"Continue": "Continue",
|
||||
"Message_has_been_shared": "Message has been shared",
|
||||
"No_channels_in_team": "No Channels on this team"
|
||||
}
|
|
@ -726,10 +726,15 @@
|
|||
"Select": "Selecionar",
|
||||
"Nickname": "Apelido",
|
||||
"Bio": "Biografia",
|
||||
"Message_has_been_shared":"Menssagem foi compartilhada",
|
||||
"No_channels_in_team": "Nenhum canal nesta equipe",
|
||||
"Jitsi_may_requires_authentication": "Jitsi pode exigir autenticação",
|
||||
"Jitsi_authentication_before_making_calls_admin": "Jitsi pode exigir autenticação antes de fazer chamadas. Para saber mais sobre as políticas deles, visite o site do Jitsi. Você também pode atualizar o aplicativo padrão para chamadas de vídeo nas preferências.",
|
||||
"Jitsi_authentication_before_making_calls": "Jitsi pode exigir autenticação antes de fazer chamadas. Para saber mais sobre suas políticas, visite o site do Jitsi.",
|
||||
"Jitsi_authentication_before_making_calls_ask_admin": "Se você acredita que há problemas com o Jitsi e sua autenticação, peça ajuda a um administrador do espaço de trabalho.",
|
||||
"Continue": "Continuar",
|
||||
"decline": "Recusar",
|
||||
"accept": "Aceitar",
|
||||
"Incoming_call_from": "Chamada recebida de",
|
||||
"Call_started": "Chamada Iniciada",
|
||||
"Message_has_been_shared": "Menssagem foi compartilhada",
|
||||
"No_channels_in_team": "Nenhum canal nesta equipe"
|
||||
"Call_started": "Chamada Iniciada"
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake';
|
||||
import React from 'react';
|
||||
import { BackHandler, Linking, NativeEventSubscription, SafeAreaView } from 'react-native';
|
||||
import WebView from 'react-native-webview';
|
||||
import { WebViewNavigation } from 'react-native-webview/lib/WebViewTypes';
|
||||
|
||||
import { IBaseScreen } from '../definitions';
|
||||
import { userAgent } from '../lib/constants';
|
||||
import { isIOS } from '../lib/methods/helpers';
|
||||
import { getRoomIdFromJitsiCallUrl } from '../lib/methods/helpers/getRoomIdFromJitsiCall';
|
||||
import { events, logEvent } from '../lib/methods/helpers/log';
|
||||
import { endVideoConfTimer, initVideoConfTimer } from '../lib/methods/videoConfTimer';
|
||||
import { ChatsStackParamList } from '../stacks/types';
|
||||
import { withTheme } from '../theme';
|
||||
|
||||
type TJitsiMeetViewProps = IBaseScreen<ChatsStackParamList, 'JitsiMeetView'>;
|
||||
|
||||
class JitsiMeetView extends React.Component<TJitsiMeetViewProps> {
|
||||
private rid: string;
|
||||
private url: string;
|
||||
private videoConf: boolean;
|
||||
private backHandler!: NativeEventSubscription;
|
||||
|
||||
constructor(props: TJitsiMeetViewProps) {
|
||||
super(props);
|
||||
this.rid = props.route.params?.rid;
|
||||
this.url = props.route.params?.url;
|
||||
this.videoConf = !!props.route.params?.videoConf;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.handleJitsiApp();
|
||||
this.onConferenceJoined();
|
||||
activateKeepAwake();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
logEvent(this.videoConf ? events.LIVECHAT_VIDEOCONF_TERMINATE : events.JM_CONFERENCE_TERMINATE);
|
||||
if (!this.videoConf) {
|
||||
endVideoConfTimer();
|
||||
}
|
||||
if (this.backHandler) {
|
||||
this.backHandler.remove();
|
||||
}
|
||||
deactivateKeepAwake();
|
||||
}
|
||||
|
||||
handleJitsiApp = async () => {
|
||||
const { route, navigation } = this.props;
|
||||
const callUrl = route.params.url.replace(/^https?:\/\//, '');
|
||||
try {
|
||||
await Linking.openURL(`org.jitsi.meet://${callUrl}`);
|
||||
navigation.pop();
|
||||
} catch (error) {
|
||||
// As the jitsi app was not opened disable the backhandler on android
|
||||
this.backHandler = BackHandler.addEventListener('hardwareBackPress', () => true);
|
||||
}
|
||||
};
|
||||
|
||||
// Jitsi Update Timeout needs to be called every 10 seconds to make sure
|
||||
// call is not ended and is available to web users.
|
||||
onConferenceJoined = () => {
|
||||
logEvent(this.videoConf ? events.LIVECHAT_VIDEOCONF_JOIN : events.JM_CONFERENCE_JOIN);
|
||||
if (this.rid && !this.videoConf) {
|
||||
initVideoConfTimer(this.rid);
|
||||
}
|
||||
};
|
||||
|
||||
onNavigationStateChange = (webViewState: WebViewNavigation) => {
|
||||
const { navigation, route } = this.props;
|
||||
|
||||
const roomId = getRoomIdFromJitsiCallUrl(route.params.url);
|
||||
|
||||
if ((roomId && !webViewState.url.includes(roomId)) || webViewState.url.includes('close')) {
|
||||
if (isIOS) {
|
||||
if (webViewState.navigationType) {
|
||||
navigation.pop();
|
||||
}
|
||||
} else {
|
||||
navigation.pop();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const uri = `${this.url}${this.url.includes('#config') ? '&' : '#'}config.disableDeepLinking=true`;
|
||||
return (
|
||||
<SafeAreaView style={{ flex: 1 }}>
|
||||
<WebView
|
||||
source={{ uri: uri.replace(/"/g, "'") }}
|
||||
onNavigationStateChange={this.onNavigationStateChange}
|
||||
// Jitsi default background color
|
||||
style={{ flex: 1, backgroundColor: 'rgb(62,62,62)' }}
|
||||
userAgent={userAgent}
|
||||
javaScriptEnabled
|
||||
domStorageEnabled
|
||||
allowsInlineMediaPlayback
|
||||
mediaCapturePermissionGrantType={'grant'}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTheme(JitsiMeetView);
|
|
@ -0,0 +1,81 @@
|
|||
import { useNavigation } from '@react-navigation/native';
|
||||
import React from 'react';
|
||||
import { Linking, StyleSheet, Text, View } from 'react-native';
|
||||
import Modal from 'react-native-modal';
|
||||
|
||||
import sharedStyles from '../Styles';
|
||||
import Button from '../../containers/Button';
|
||||
import { useTheme } from '../../theme';
|
||||
import { useAppSelector } from '../../lib/hooks';
|
||||
import { getUserSelector } from '../../selectors/login';
|
||||
import i18n from '../../i18n';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
title: {
|
||||
...sharedStyles.textBold,
|
||||
fontSize: 24,
|
||||
marginBottom: 24
|
||||
},
|
||||
regular: {
|
||||
...sharedStyles.textRegular,
|
||||
fontSize: 16,
|
||||
marginBottom: 24
|
||||
},
|
||||
min: {
|
||||
...sharedStyles.textRegular,
|
||||
fontSize: 12,
|
||||
marginBottom: 24
|
||||
},
|
||||
container: { padding: 24, borderRadius: 8 },
|
||||
buttonContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between'
|
||||
}
|
||||
});
|
||||
|
||||
const JitsiAuthModal = ({
|
||||
setAuthModal,
|
||||
callUrl
|
||||
}: {
|
||||
setAuthModal: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
callUrl: string;
|
||||
}): React.ReactElement => {
|
||||
const { goBack } = useNavigation();
|
||||
const { colors } = useTheme();
|
||||
const user = useAppSelector(state => getUserSelector(state));
|
||||
|
||||
const isAdmin = !!user.roles?.includes('admin');
|
||||
|
||||
return (
|
||||
<Modal isVisible>
|
||||
<View style={[styles.container, { backgroundColor: colors.backgroundColor }]}>
|
||||
<Text style={[styles.title, { color: colors.titleText }]}>{i18n.t('Jitsi_may_require_authentication')}</Text>
|
||||
{isAdmin ? (
|
||||
<Text style={[styles.regular, { color: colors.titleText }]}>
|
||||
{i18n.t('Jitsi_authentication_before_making_calls_admin')}
|
||||
</Text>
|
||||
) : (
|
||||
<Text style={[styles.regular, { color: colors.titleText }]}>{i18n.t('Jitsi_authentication_before_making_calls')}</Text>
|
||||
)}
|
||||
{!isAdmin ? (
|
||||
<Text style={[styles.min, { color: colors.auxiliaryText }]}>
|
||||
{i18n.t('Jitsi_authentication_before_making_calls_ask_admin')}
|
||||
</Text>
|
||||
) : null}
|
||||
<View style={styles.buttonContainer}>
|
||||
<Button title={i18n.t('Cancel')} type='secondary' onPress={() => setAuthModal(false)} />
|
||||
<Button
|
||||
title={i18n.t('Continue')}
|
||||
onPress={() => {
|
||||
setAuthModal(false);
|
||||
goBack();
|
||||
Linking.openURL(callUrl);
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default JitsiAuthModal;
|
|
@ -0,0 +1,94 @@
|
|||
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native';
|
||||
import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { BackHandler, Linking, SafeAreaView } from 'react-native';
|
||||
import WebView from 'react-native-webview';
|
||||
|
||||
import { userAgent } from '../../lib/constants';
|
||||
import { isIOS } from '../../lib/methods/helpers';
|
||||
import { getRoomIdFromJitsiCallUrl } from '../../lib/methods/helpers/getRoomIdFromJitsiCall';
|
||||
import { events, logEvent } from '../../lib/methods/helpers/log';
|
||||
import { endVideoConfTimer, initVideoConfTimer } from '../../lib/methods/videoConfTimer';
|
||||
import { ChatsStackParamList } from '../../stacks/types';
|
||||
import JitsiAuthModal from './JitsiAuthModal';
|
||||
|
||||
const JitsiMeetView = (): React.ReactElement => {
|
||||
const {
|
||||
params: { rid, url, videoConf }
|
||||
} = useRoute<RouteProp<ChatsStackParamList, 'JitsiMeetView'>>();
|
||||
const { goBack } = useNavigation();
|
||||
|
||||
const [authModal, setAuthModal] = useState(false);
|
||||
|
||||
const handleJitsiApp = useCallback(async () => {
|
||||
const callUrl = url.replace(/^https?:\/\//, '');
|
||||
try {
|
||||
await Linking.openURL(`org.jitsi.meet://${callUrl}`);
|
||||
goBack();
|
||||
} catch (error) {
|
||||
// As the jitsi app was not opened, disable the backhandler on android
|
||||
BackHandler.addEventListener('hardwareBackPress', () => true);
|
||||
}
|
||||
}, [goBack, url]);
|
||||
|
||||
const onConferenceJoined = useCallback(() => {
|
||||
logEvent(videoConf ? events.LIVECHAT_VIDEOCONF_JOIN : events.JM_CONFERENCE_JOIN);
|
||||
if (rid && !videoConf) {
|
||||
initVideoConfTimer(rid);
|
||||
}
|
||||
}, [rid, videoConf]);
|
||||
|
||||
const onNavigationStateChange = useCallback(
|
||||
webViewState => {
|
||||
const roomId = getRoomIdFromJitsiCallUrl(url);
|
||||
if (webViewState.url.includes('auth-static')) {
|
||||
setAuthModal(true);
|
||||
return false;
|
||||
}
|
||||
if ((roomId && !webViewState.url.includes(roomId)) || webViewState.url.includes('close')) {
|
||||
if (isIOS) {
|
||||
if (webViewState.navigationType) {
|
||||
goBack();
|
||||
}
|
||||
} else {
|
||||
goBack();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
[goBack, url]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
handleJitsiApp();
|
||||
onConferenceJoined();
|
||||
activateKeepAwake();
|
||||
|
||||
return () => {
|
||||
logEvent(videoConf ? events.LIVECHAT_VIDEOCONF_TERMINATE : events.JM_CONFERENCE_TERMINATE);
|
||||
if (!videoConf) endVideoConfTimer();
|
||||
deactivateKeepAwake();
|
||||
};
|
||||
}, [handleJitsiApp, onConferenceJoined, videoConf]);
|
||||
|
||||
const callUrl = `${url}${url.includes('#config') ? '&' : '#'}config.disableDeepLinking=true`;
|
||||
|
||||
return (
|
||||
<SafeAreaView style={{ flex: 1 }}>
|
||||
{authModal && <JitsiAuthModal setAuthModal={setAuthModal} callUrl={callUrl} />}
|
||||
<WebView
|
||||
source={{ uri: callUrl.replace(/"/g, "'") }}
|
||||
onNavigationStateChange={onNavigationStateChange}
|
||||
onShouldStartLoadWithRequest={onNavigationStateChange}
|
||||
style={{ flex: 1, backgroundColor: 'rgb(62,62,62)' }}
|
||||
userAgent={userAgent}
|
||||
javaScriptEnabled
|
||||
domStorageEnabled
|
||||
allowsInlineMediaPlayback
|
||||
mediaCapturePermissionGrantType={'grant'}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
export default JitsiMeetView;
|
Loading…
Reference in New Issue