Skip to content

Commit

Permalink
Adds error dialog when voice recorder cannot start
Browse files Browse the repository at this point in the history
  • Loading branch information
josh-signal committed Sep 30, 2021
1 parent 6614206 commit 31d1f25
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 27 deletions.
4 changes: 4 additions & 0 deletions _locales/en/messages.json
Expand Up @@ -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",
Expand Down
18 changes: 18 additions & 0 deletions 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 <Toast onClose={onClose}>{i18n('voiceNoteError')}</Toast>;
};
64 changes: 41 additions & 23 deletions ts/components/conversation/AudioCapture.tsx
Expand Up @@ -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 = (
<ConfirmationDialog
i18n={i18n}
onCancel={clickCancel}
onClose={noop}
cancelText={i18n('discard')}
actions={[
{
text: i18n('sendAnyway'),
style: 'affirmative',
action: clickSend,
},
]}
>
{confirmationDialogText}
</ConfirmationDialog>
);
} else if (
errorDialogAudioRecorderType === ErrorDialogAudioRecorderType.ErrorRecording
) {
confirmationDialog = (
<ConfirmationDialog
i18n={i18n}
onCancel={clickCancel}
onClose={noop}
cancelText={i18n('ok')}
actions={[]}
>
{i18n('voiceNoteError')}
</ConfirmationDialog>
);
}

if (isRecording && !confirmationDialogText) {
if (isRecording && !confirmationDialog) {
return (
<>
<div className="AudioCapture">
Expand Down Expand Up @@ -203,23 +237,7 @@ export const AudioCapture = ({
title={i18n('voiceRecording--start')}
type="button"
/>
{confirmationDialogText ? (
<ConfirmationDialog
i18n={i18n}
onCancel={clickCancel}
onClose={noop}
cancelText={i18n('discard')}
actions={[
{
text: i18n('sendAnyway'),
style: 'affirmative',
action: clickSend,
},
]}
>
{confirmationDialogText}
</ConfirmationDialog>
) : null}
{confirmationDialog}
</div>
{toastElement}
</>
Expand Down
6 changes: 5 additions & 1 deletion ts/services/audioRecorder.ts
Expand Up @@ -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) {
Expand Down
15 changes: 12 additions & 3 deletions ts/state/ducks/audioRecorder.ts
Expand Up @@ -14,6 +14,7 @@ import { useBoundActions } from '../../hooks/useBoundActions';

export enum ErrorDialogAudioRecorderType {
Blur,
ErrorRecording,
Timeout,
}

Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 31d1f25

Please sign in to comment.