Adds error dialog when voice recorder cannot start
This commit is contained in:
parent
6614206921
commit
31d1f25b18
5 changed files with 80 additions and 27 deletions
|
@ -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",
|
||||
|
|
18
ts/components/ToastVoiceNoteError.tsx
Normal file
18
ts/components/ToastVoiceNoteError.tsx
Normal file
|
@ -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>;
|
||||
};
|
|
@ -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">
|
||||
|
@ -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}
|
||||
</>
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue