Skip to content

Commit 280c017

Browse files
authored
Merge pull request matrix-org#6530 from matrix-org/travis/voice-messages/uploading
Improve voice messages uploading state
2 parents 51bd740 + c4e6cc7 commit 280c017

File tree

3 files changed

+56
-13
lines changed

3 files changed

+56
-13
lines changed

res/css/views/rooms/_VoiceRecordComposerTile.scss

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,21 @@ limitations under the License.
4646
mask-image: url('$(res)/img/element-icons/trashcan.svg');
4747
}
4848

49+
.mx_VoiceRecordComposerTile_uploadingState {
50+
margin-right: 10px;
51+
color: $secondary-fg-color;
52+
}
53+
54+
.mx_VoiceRecordComposerTile_failedState {
55+
margin-right: 21px;
56+
57+
.mx_VoiceRecordComposerTile_uploadState_badge {
58+
display: inline-block;
59+
margin-right: 4px;
60+
vertical-align: middle;
61+
}
62+
}
63+
4964
.mx_MessageComposer_row .mx_VoiceMessagePrimaryContainer {
5065
// Note: remaining class properties are in the PlayerContainer CSS.
5166

src/components/views/rooms/VoiceRecordComposerTile.tsx

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@ limitations under the License.
1717
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
1818
import { _t } from "../../../languageHandler";
1919
import React, { ReactNode } from "react";
20-
import {
21-
RecordingState,
22-
VoiceRecording,
23-
} from "../../../audio/VoiceRecording";
20+
import { IUpload, RecordingState, VoiceRecording } from "../../../audio/VoiceRecording";
2421
import { Room } from "matrix-js-sdk/src/models/room";
2522
import { MatrixClientPeg } from "../../../MatrixClientPeg";
2623
import classNames from "classnames";
@@ -34,6 +31,10 @@ import { MsgType } from "matrix-js-sdk/src/@types/event";
3431
import Modal from "../../../Modal";
3532
import ErrorDialog from "../dialogs/ErrorDialog";
3633
import MediaDeviceHandler, { MediaDeviceKindEnum } from "../../../MediaDeviceHandler";
34+
import NotificationBadge from "./NotificationBadge";
35+
import { StaticNotificationState } from "../../../stores/notifications/StaticNotificationState";
36+
import { NotificationColor } from "../../../stores/notifications/NotificationColor";
37+
import InlineSpinner from "../elements/InlineSpinner";
3738

3839
interface IProps {
3940
room: Room;
@@ -42,6 +43,7 @@ interface IProps {
4243
interface IState {
4344
recorder?: VoiceRecording;
4445
recordingPhase?: RecordingState;
46+
didUploadFail?: boolean;
4547
}
4648

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

7072
await this.state.recorder.stop();
7173

74+
let upload: IUpload;
7275
try {
73-
const upload = await this.state.recorder.upload(this.props.room.roomId);
76+
upload = await this.state.recorder.upload(this.props.room.roomId);
77+
} catch (e) {
78+
console.error("Error uploading voice message:", e);
79+
80+
// Flag error and move on. The recording phase will be reset by the upload function.
81+
this.setState({ didUploadFail: true });
7482

83+
return; // don't dispose the recording: the user has a chance to re-upload
84+
}
85+
86+
try {
7587
// noinspection ES6MissingAwait - we don't care if it fails, it'll get queued.
7688
MatrixClientPeg.get().sendMessage(this.props.room.roomId, {
7789
"body": "Voice message",
@@ -104,12 +116,11 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
104116
"org.matrix.msc3245.voice": {}, // No content, this is a rendering hint
105117
});
106118
} catch (e) {
107-
console.error("Error sending/uploading voice message:", e);
108-
Modal.createTrackedDialog('Upload failed', '', ErrorDialog, {
109-
title: _t('Upload Failed'),
110-
description: _t("The voice message failed to upload."),
111-
});
112-
return; // don't dispose the recording so the user can retry, maybe
119+
console.error("Error sending voice message:", e);
120+
121+
// Voice message should be in the timeline at this point, so let other things take care
122+
// of error handling. We also shouldn't need the recording anymore, so fall through to
123+
// disposal.
113124
}
114125
await this.disposeRecording();
115126
}
@@ -118,7 +129,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
118129
await VoiceRecordingStore.instance.disposeRecording();
119130

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

124135
private onCancel = async () => {
@@ -234,7 +245,25 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
234245
/>;
235246
}
236247

248+
let uploadIndicator;
249+
if (this.state.recordingPhase === RecordingState.Uploading) {
250+
uploadIndicator = <span className='mx_VoiceRecordComposerTile_uploadingState'>
251+
<InlineSpinner w={16} h={16} />
252+
</span>;
253+
} else if (this.state.didUploadFail && this.state.recordingPhase === RecordingState.Ended) {
254+
uploadIndicator = <span className='mx_VoiceRecordComposerTile_failedState'>
255+
<span className='mx_VoiceRecordComposerTile_uploadState_badge'>
256+
{ /* Need to stick the badge in a span to ensure it doesn't create a block component */ }
257+
<NotificationBadge
258+
notification={StaticNotificationState.forSymbol("!", NotificationColor.Red)}
259+
/>
260+
</span>
261+
<span className='text-warning'>{ _t("Failed to send") }</span>
262+
</span>;
263+
}
264+
237265
return (<>
266+
{ uploadIndicator }
238267
{ deleteButton }
239268
{ this.renderWaveformArea() }
240269
{ recordingInfo }

src/i18n/strings/en_EN.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1697,7 +1697,6 @@
16971697
"Invited by %(sender)s": "Invited by %(sender)s",
16981698
"Jump to first unread message.": "Jump to first unread message.",
16991699
"Mark all as read": "Mark all as read",
1700-
"The voice message failed to upload.": "The voice message failed to upload.",
17011700
"Unable to access your microphone": "Unable to access your microphone",
17021701
"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.",
17031702
"No microphone found": "No microphone found",

0 commit comments

Comments
 (0)