Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Improve voice messages uploading state
Browse files Browse the repository at this point in the history
  • Loading branch information
turt2live committed Aug 3, 2021
1 parent 3ea0571 commit c5d11a9
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 13 deletions.
11 changes: 11 additions & 0 deletions res/css/views/rooms/_VoiceRecordComposerTile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ limitations under the License.
mask-image: url('$(res)/img/element-icons/trashcan.svg');
}

.mx_VoiceRecordComposerTile_uploadState {
margin-right: 21px;
color: $secondary-fg-color;

.mx_VoiceRecordComposerTile_uploadState_badge {
display: inline-block;
margin-right: 4px;
vertical-align: middle;
}
}

.mx_MessageComposer_row .mx_VoiceMessagePrimaryContainer {
// Note: remaining class properties are in the PlayerContainer CSS.

Expand Down
54 changes: 42 additions & 12 deletions src/components/views/rooms/VoiceRecordComposerTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ limitations under the License.
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { _t } from "../../../languageHandler";
import React, { ReactNode } from "react";
import {
RecordingState,
VoiceRecording,
} from "../../../audio/VoiceRecording";
import { IUpload, RecordingState, VoiceRecording } from "../../../audio/VoiceRecording";
import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import classNames from "classnames";
Expand All @@ -34,6 +31,10 @@ import { MsgType } from "matrix-js-sdk/src/@types/event";
import Modal from "../../../Modal";
import ErrorDialog from "../dialogs/ErrorDialog";
import MediaDeviceHandler, { MediaDeviceKindEnum } from "../../../MediaDeviceHandler";
import NotificationBadge from "./NotificationBadge";
import { StaticNotificationState } from "../../../stores/notifications/StaticNotificationState";
import { NotificationColor } from "../../../stores/notifications/NotificationColor";
import InlineSpinner from "../elements/InlineSpinner";

interface IProps {
room: Room;
Expand All @@ -42,6 +43,7 @@ interface IProps {
interface IState {
recorder?: VoiceRecording;
recordingPhase?: RecordingState;
didUploadFail?: boolean;
}

/**
Expand Down Expand Up @@ -69,9 +71,19 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,

await this.state.recorder.stop();

let upload: IUpload;
try {
const upload = await this.state.recorder.upload(this.props.room.roomId);
upload = await this.state.recorder.upload(this.props.room.roomId);
} catch (e) {
console.error("Error uploading voice message:", e);

// Flag error and move on. The recording phase will be reset by the upload function.
this.setState({ didUploadFail: true });

return; // don't dispose the recording: the user has a chance to re-upload
}

try {
// noinspection ES6MissingAwait - we don't care if it fails, it'll get queued.
MatrixClientPeg.get().sendMessage(this.props.room.roomId, {
"body": "Voice message",
Expand Down Expand Up @@ -104,12 +116,11 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
"org.matrix.msc3245.voice": {}, // No content, this is a rendering hint
});
} catch (e) {
console.error("Error sending/uploading voice message:", e);
Modal.createTrackedDialog('Upload failed', '', ErrorDialog, {
title: _t('Upload Failed'),
description: _t("The voice message failed to upload."),
});
return; // don't dispose the recording so the user can retry, maybe
console.error("Error sending voice message:", e);

// Voice message should be in the timeline at this point, so let other things take care
// of error handling. We also shouldn't need the recording anymore, so fall through to
// disposal.
}
await this.disposeRecording();
}
Expand All @@ -118,7 +129,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
await VoiceRecordingStore.instance.disposeRecording();

// Reset back to no recording, which means no phase (ie: restart component entirely)
this.setState({ recorder: null, recordingPhase: null });
this.setState({ recorder: null, recordingPhase: null, didUploadFail: false });
}

private onCancel = async () => {
Expand Down Expand Up @@ -234,7 +245,26 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
/>;
}

let uploadIndicator;
if (this.state.recordingPhase === RecordingState.Uploading) {
uploadIndicator = <span className='mx_VoiceRecordComposerTile_uploadState'>
<InlineSpinner w={16} h={16} />
{ _t("Uploading...") }
</span>;
} else if (this.state.didUploadFail && this.state.recordingPhase === RecordingState.Ended) {
uploadIndicator = <span className='mx_VoiceRecordComposerTile_uploadState'>
<span className='mx_VoiceRecordComposerTile_uploadState_badge'>
{ /* Need to stick the badge in a span to ensure it doesn't create a block component */ }
<NotificationBadge
notification={StaticNotificationState.forSymbol("!", NotificationColor.Red)}
/>
</span>
<span className='text-warning'>{ _t("Failed to upload voice message") }</span>
</span>;
}

return (<>
{ uploadIndicator }
{ deleteButton }
{ this.renderWaveformArea() }
{ recordingInfo }
Expand Down
3 changes: 2 additions & 1 deletion src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1701,14 +1701,15 @@
"Invited by %(sender)s": "Invited by %(sender)s",
"Jump to first unread message.": "Jump to first unread message.",
"Mark all as read": "Mark all as read",
"The voice message failed to upload.": "The voice message failed to upload.",
"Unable to access your microphone": "Unable to access your microphone",
"We were unable to access your microphone. Please check your browser settings and try again.": "We were unable to access your microphone. Please check your browser settings and try again.",
"No microphone found": "No microphone found",
"We didn't find a microphone on your device. Please check your settings and try again.": "We didn't find a microphone on your device. Please check your settings and try again.",
"Record a voice message": "Record a voice message",
"Stop the recording": "Stop the recording",
"Delete recording": "Delete recording",
"Uploading...": "Uploading...",
"Failed to upload voice message": "Failed to upload voice message",
"Error updating main address": "Error updating main address",
"There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.",
"There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.": "There was an error updating the room's alternative addresses. It may not be allowed by the server or a temporary failure occurred.",
Expand Down

0 comments on commit c5d11a9

Please sign in to comment.