From 31d1f25b186b74063013935165dfba9e34e0ae38 Mon Sep 17 00:00:00 2001 From: Josh Perez <60019601+josh-signal@users.noreply.github.com> Date: Thu, 30 Sep 2021 16:13:47 -0400 Subject: [PATCH] Adds error dialog when voice recorder cannot start --- _locales/en/messages.json | 4 ++ ts/components/ToastVoiceNoteError.tsx | 18 ++++++ ts/components/conversation/AudioCapture.tsx | 64 +++++++++++++-------- ts/services/audioRecorder.ts | 6 +- ts/state/ducks/audioRecorder.ts | 15 ++++- 5 files changed, 80 insertions(+), 27 deletions(-) create mode 100644 ts/components/ToastVoiceNoteError.tsx diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 1df758d9288..898e5395528 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -937,6 +937,10 @@ "message": "A voice message must have only one attachment.", "description": "Shown in toast if tries to record a voice note with any staged attachments" }, + "voiceNoteError": { + "message": "There was an error with the voice recorder.", + "description": "Shown in a dialog to inform user that we experienced an unrecoverable error" + }, "attachmentSaved": { "message": "Attachment saved. Click to show in folder.", "description": "Shown after user selects to save to downloads", diff --git a/ts/components/ToastVoiceNoteError.tsx b/ts/components/ToastVoiceNoteError.tsx new file mode 100644 index 00000000000..b7eca40009e --- /dev/null +++ b/ts/components/ToastVoiceNoteError.tsx @@ -0,0 +1,18 @@ +// Copyright 2021 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import React from 'react'; +import { LocalizerType } from '../types/Util'; +import { Toast } from './Toast'; + +type PropsType = { + i18n: LocalizerType; + onClose: () => unknown; +}; + +export const ToastVoiceNoteLimit = ({ + i18n, + onClose, +}: PropsType): JSX.Element => { + return {i18n('voiceNoteError')}; +}; diff --git a/ts/components/conversation/AudioCapture.tsx b/ts/components/conversation/AudioCapture.tsx index bdc781c4cf5..83450c8a841 100644 --- a/ts/components/conversation/AudioCapture.tsx +++ b/ts/components/conversation/AudioCapture.tsx @@ -147,16 +147,50 @@ export const AudioCapture = ({ ); } - let confirmationDialogText: string | undefined; - if (errorDialogAudioRecorderType === ErrorDialogAudioRecorderType.Blur) { - confirmationDialogText = i18n('voiceRecordingInterruptedBlur'); - } else if ( + let confirmationDialog: JSX.Element | undefined; + if ( + errorDialogAudioRecorderType === ErrorDialogAudioRecorderType.Blur || errorDialogAudioRecorderType === ErrorDialogAudioRecorderType.Timeout ) { - confirmationDialogText = i18n('voiceRecordingInterruptedMax'); + const confirmationDialogText = + errorDialogAudioRecorderType === ErrorDialogAudioRecorderType.Blur + ? i18n('voiceRecordingInterruptedBlur') + : i18n('voiceRecordingInterruptedMax'); + + confirmationDialog = ( + + {confirmationDialogText} + + ); + } else if ( + errorDialogAudioRecorderType === ErrorDialogAudioRecorderType.ErrorRecording + ) { + confirmationDialog = ( + + {i18n('voiceNoteError')} + + ); } - if (isRecording && !confirmationDialogText) { + if (isRecording && !confirmationDialog) { return ( <>
@@ -203,23 +237,7 @@ export const AudioCapture = ({ title={i18n('voiceRecording--start')} type="button" /> - {confirmationDialogText ? ( - - {confirmationDialogText} - - ) : null} + {confirmationDialog}
{toastElement} diff --git a/ts/services/audioRecorder.ts b/ts/services/audioRecorder.ts index b770403a130..d6c29169e0e 100644 --- a/ts/services/audioRecorder.ts +++ b/ts/services/audioRecorder.ts @@ -68,8 +68,12 @@ export class RecorderClass { this.source = this.context.createMediaStreamSource(stream); this.source.connect(this.input); } catch (err) { - log.error('Recorder.onGetUserMediaError:', err); + log.error( + 'Recorder.onGetUserMediaError:', + err && err.stack ? err.stack : err + ); this.clear(); + throw err; } if (this.recorder) { diff --git a/ts/state/ducks/audioRecorder.ts b/ts/state/ducks/audioRecorder.ts index 31ba18eaac6..73b0eaaad46 100644 --- a/ts/state/ducks/audioRecorder.ts +++ b/ts/state/ducks/audioRecorder.ts @@ -14,6 +14,7 @@ import { useBoundActions } from '../../hooks/useBoundActions'; export enum ErrorDialogAudioRecorderType { Blur, + ErrorRecording, Timeout, } @@ -69,14 +70,22 @@ function startRecording(): ThunkAction< void, RootStateType, unknown, - StartRecordingAction + StartRecordingAction | ErrorRecordingAction > { - return (dispatch, getState) => { + return async (dispatch, getState) => { if (getState().composer.attachments.length) { return; } - recorder.start(); + try { + await recorder.start(); + } catch (err) { + dispatch({ + type: ERROR_RECORDING, + payload: ErrorDialogAudioRecorderType.ErrorRecording, + }); + return; + } dispatch({ type: START_RECORDING,