feat: audio recording permission handling in MicOrSendButton component (#5515)

This commit is contained in:
Gleidson Daniel Silva 2024-01-31 11:28:34 -03:00 committed by GitHub
parent 7b73eac895
commit 39f8a92059
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 67 additions and 13 deletions

View File

@ -1,14 +1,18 @@
import React, { useContext } from 'react';
import { Audio } from 'expo-av'; import { Audio } from 'expo-av';
import React, { useContext } from 'react';
import { Alert } from 'react-native';
import { PermissionStatus } from 'expo-camera';
import { BaseButton } from './BaseButton'; import i18n from '../../../../i18n';
import { MessageInnerContext, useMessageComposerApi, useMicOrSend } from '../../context';
import { useTheme } from '../../../../theme';
import { useAppSelector } from '../../../../lib/hooks'; import { useAppSelector } from '../../../../lib/hooks';
import { useCanUploadFile } from '../../hooks'; import { openAppSettings } from '../../../../lib/methods/helpers/openAppSettings';
import { useTheme } from '../../../../theme';
import { useRoomContext } from '../../../../views/RoomView/context'; import { useRoomContext } from '../../../../views/RoomView/context';
import { MessageInnerContext, useMessageComposerApi, useMicOrSend } from '../../context';
import { useCanUploadFile } from '../../hooks';
import { BaseButton } from './BaseButton';
export const MicOrSendButton = () => { export const MicOrSendButton = (): React.ReactElement | null => {
const { rid, sharing } = useRoomContext(); const { rid, sharing } = useRoomContext();
const micOrSend = useMicOrSend(); const micOrSend = useMicOrSend();
const { sendMessage } = useContext(MessageInnerContext); const { sendMessage } = useContext(MessageInnerContext);
@ -17,11 +21,32 @@ export const MicOrSendButton = () => {
const { colors } = useTheme(); const { colors } = useTheme();
const { setRecordingAudio } = useMessageComposerApi(); const { setRecordingAudio } = useMessageComposerApi();
const requestPermissionAndStartToRecordAudio = () =>
Audio.requestPermissionsAsync()
.then(({ granted }) => setRecordingAudio(granted))
.catch(() => {});
const startRecording = async () => { const startRecording = async () => {
const permission = await Audio.requestPermissionsAsync(); const { status, granted, canAskAgain } = await Audio.getPermissionsAsync();
if (permission.granted) { if (granted) return setRecordingAudio(true);
setRecordingAudio(true); if (status === PermissionStatus.UNDETERMINED) return requestPermissionAndStartToRecordAudio();
} if (canAskAgain) return requestPermissionAndStartToRecordAudio();
Alert.alert(
i18n.t('Microphone_access_needed_to_record_audio'),
i18n.t('Go_to_your_device_settings_and_allow_microphone'),
[
{
text: i18n.t('Cancel'),
style: 'cancel'
},
{
text: i18n.t('Settings'),
onPress: openAppSettings
}
],
{ cancelable: false }
);
}; };
if (micOrSend === 'send' || sharing) { if (micOrSend === 'send' || sharing) {

View File

@ -27,6 +27,7 @@ export const RecordAudio = (): ReactElement | null => {
const [styles, colors] = useStyle(); const [styles, colors] = useStyle();
const recordingRef = useRef<Audio.Recording>(); const recordingRef = useRef<Audio.Recording>();
const durationRef = useRef<IDurationRef>({} as IDurationRef); const durationRef = useRef<IDurationRef>({} as IDurationRef);
const numberOfTriesRef = useRef(0);
const [status, setStatus] = React.useState<'recording' | 'reviewing'>('recording'); const [status, setStatus] = React.useState<'recording' | 'reviewing'>('recording');
const { setRecordingAudio } = useMessageComposerApi(); const { setRecordingAudio } = useMessageComposerApi();
const { rid, tmid } = useRoomContext(); const { rid, tmid } = useRoomContext();
@ -43,8 +44,21 @@ export const RecordAudio = (): ReactElement | null => {
await recordingRef.current.prepareToRecordAsync(RECORDING_SETTINGS); await recordingRef.current.prepareToRecordAsync(RECORDING_SETTINGS);
recordingRef.current.setOnRecordingStatusUpdate(durationRef.current.onRecordingStatusUpdate); recordingRef.current.setOnRecordingStatusUpdate(durationRef.current.onRecordingStatusUpdate);
await recordingRef.current.startAsync(); await recordingRef.current.startAsync();
} catch (error) { } catch (error: any) {
console.error(error); // error only occurs on iOS devices
if (error?.code === 'E_AUDIO_RECORDERNOTCREATED') {
if (numberOfTriesRef.current <= 5) {
recordingRef.current = undefined;
numberOfTriesRef.current += 1;
setTimeout(() => {
record();
}, 100);
} else {
console.error(error);
}
} else {
console.error(error);
}
} }
}; };
record(); record();

View File

@ -803,5 +803,7 @@
"Inline_code": "Inline code", "Inline_code": "Inline code",
"Code_block": "Code block", "Code_block": "Code block",
"Add_thread_reply": "Add thread reply", "Add_thread_reply": "Add thread reply",
"Message_roomname": "Message {{roomName}}" "Message_roomname": "Message {{roomName}}",
"Microphone_access_needed_to_record_audio": "Microphone access needed to record audio",
"Go_to_your_device_settings_and_allow_microphone": "Go to your device settings and allow microphone access for Rocket.Chat"
} }

View File

@ -794,6 +794,8 @@
"You_dont_have_permission_to_perform_this_action": "Você não tem permissão para realizar esta ação. Verifique com um administrador do espaço de trabalho.", "You_dont_have_permission_to_perform_this_action": "Você não tem permissão para realizar esta ação. Verifique com um administrador do espaço de trabalho.",
"Jump_to_message": "Ir para mensagem", "Jump_to_message": "Ir para mensagem",
"Missed_call": "Chamada perdida", "Missed_call": "Chamada perdida",
"Microphone_access_needed_to_record_audio": "Acesso ao microfone necessário para gravar áudio",
"Go_to_your_device_settings_and_allow_microphone": "Vá para as configurações do seu dispositivo e permita o acesso ao microfone pelo aplicativo Rocket.Chat",
"In_app_message_notifications": "Notificações de mensagens in-app", "In_app_message_notifications": "Notificações de mensagens in-app",
"Vibrate": "Vibrar" "Vibrate": "Vibrar"
} }

View File

@ -0,0 +1,11 @@
import { Linking } from 'react-native';
import { isIOS } from './deviceInfo';
export const openAppSettings = (): void => {
if (isIOS) {
Linking.openURL('app-settings:');
} else {
Linking.openSettings();
}
};