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.",
|
"message": "A voice message must have only one attachment.",
|
||||||
"description": "Shown in toast if tries to record a voice note with any staged attachments"
|
"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": {
|
"attachmentSaved": {
|
||||||
"message": "Attachment saved. Click to show in folder.",
|
"message": "Attachment saved. Click to show in folder.",
|
||||||
"description": "Shown after user selects to save to downloads",
|
"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;
|
let confirmationDialog: JSX.Element | undefined;
|
||||||
if (errorDialogAudioRecorderType === ErrorDialogAudioRecorderType.Blur) {
|
if (
|
||||||
confirmationDialogText = i18n('voiceRecordingInterruptedBlur');
|
errorDialogAudioRecorderType === ErrorDialogAudioRecorderType.Blur ||
|
||||||
} else if (
|
|
||||||
errorDialogAudioRecorderType === ErrorDialogAudioRecorderType.Timeout
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="AudioCapture">
|
<div className="AudioCapture">
|
||||||
|
@ -203,23 +237,7 @@ export const AudioCapture = ({
|
||||||
title={i18n('voiceRecording--start')}
|
title={i18n('voiceRecording--start')}
|
||||||
type="button"
|
type="button"
|
||||||
/>
|
/>
|
||||||
{confirmationDialogText ? (
|
{confirmationDialog}
|
||||||
<ConfirmationDialog
|
|
||||||
i18n={i18n}
|
|
||||||
onCancel={clickCancel}
|
|
||||||
onClose={noop}
|
|
||||||
cancelText={i18n('discard')}
|
|
||||||
actions={[
|
|
||||||
{
|
|
||||||
text: i18n('sendAnyway'),
|
|
||||||
style: 'affirmative',
|
|
||||||
action: clickSend,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{confirmationDialogText}
|
|
||||||
</ConfirmationDialog>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
{toastElement}
|
{toastElement}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -68,8 +68,12 @@ export class RecorderClass {
|
||||||
this.source = this.context.createMediaStreamSource(stream);
|
this.source = this.context.createMediaStreamSource(stream);
|
||||||
this.source.connect(this.input);
|
this.source.connect(this.input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error('Recorder.onGetUserMediaError:', err);
|
log.error(
|
||||||
|
'Recorder.onGetUserMediaError:',
|
||||||
|
err && err.stack ? err.stack : err
|
||||||
|
);
|
||||||
this.clear();
|
this.clear();
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.recorder) {
|
if (this.recorder) {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { useBoundActions } from '../../hooks/useBoundActions';
|
||||||
|
|
||||||
export enum ErrorDialogAudioRecorderType {
|
export enum ErrorDialogAudioRecorderType {
|
||||||
Blur,
|
Blur,
|
||||||
|
ErrorRecording,
|
||||||
Timeout,
|
Timeout,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,14 +70,22 @@ function startRecording(): ThunkAction<
|
||||||
void,
|
void,
|
||||||
RootStateType,
|
RootStateType,
|
||||||
unknown,
|
unknown,
|
||||||
StartRecordingAction
|
StartRecordingAction | ErrorRecordingAction
|
||||||
> {
|
> {
|
||||||
return (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
if (getState().composer.attachments.length) {
|
if (getState().composer.attachments.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
recorder.start();
|
try {
|
||||||
|
await recorder.start();
|
||||||
|
} catch (err) {
|
||||||
|
dispatch({
|
||||||
|
type: ERROR_RECORDING,
|
||||||
|
payload: ErrorDialogAudioRecorderType.ErrorRecording,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: START_RECORDING,
|
type: START_RECORDING,
|
||||||
|
|
Loading…
Reference in a new issue