Merge pull request #6453 from matrix-org/travis/voice-messages/code-cleanup-1
Clean up voice messages code
This commit is contained in:
commit
2c4ab507d6
23 changed files with 92 additions and 102 deletions
|
@ -14,9 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Playback, PlaybackState } from "../../../voice/Playback";
|
|
||||||
import React, { createRef, ReactNode, RefObject } from "react";
|
import React, { createRef, ReactNode, RefObject } from "react";
|
||||||
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
|
|
||||||
import PlayPauseButton from "./PlayPauseButton";
|
import PlayPauseButton from "./PlayPauseButton";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { formatBytes } from "../../../utils/FormattingUtils";
|
import { formatBytes } from "../../../utils/FormattingUtils";
|
||||||
|
@ -25,47 +23,13 @@ import { Key } from "../../../Keyboard";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import SeekBar from "./SeekBar";
|
import SeekBar from "./SeekBar";
|
||||||
import PlaybackClock from "./PlaybackClock";
|
import PlaybackClock from "./PlaybackClock";
|
||||||
|
import AudioPlayerBase from "./AudioPlayerBase";
|
||||||
interface IProps {
|
|
||||||
// Playback instance to render. Cannot change during component lifecycle: create
|
|
||||||
// an all-new component instead.
|
|
||||||
playback: Playback;
|
|
||||||
|
|
||||||
mediaName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IState {
|
|
||||||
playbackPhase: PlaybackState;
|
|
||||||
error?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
@replaceableComponent("views.audio_messages.AudioPlayer")
|
@replaceableComponent("views.audio_messages.AudioPlayer")
|
||||||
export default class AudioPlayer extends React.PureComponent<IProps, IState> {
|
export default class AudioPlayer extends AudioPlayerBase {
|
||||||
private playPauseRef: RefObject<PlayPauseButton> = createRef();
|
private playPauseRef: RefObject<PlayPauseButton> = createRef();
|
||||||
private seekRef: RefObject<SeekBar> = createRef();
|
private seekRef: RefObject<SeekBar> = createRef();
|
||||||
|
|
||||||
constructor(props: IProps) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
playbackPhase: PlaybackState.Decoding, // default assumption
|
|
||||||
};
|
|
||||||
|
|
||||||
// We don't need to de-register: the class handles this for us internally
|
|
||||||
this.props.playback.on(UPDATE_EVENT, this.onPlaybackUpdate);
|
|
||||||
|
|
||||||
// Don't wait for the promise to complete - it will emit a progress update when it
|
|
||||||
// is done, and it's not meant to take long anyhow.
|
|
||||||
this.props.playback.prepare().catch(e => {
|
|
||||||
console.error("Error processing audio file:", e);
|
|
||||||
this.setState({ error: true });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private onPlaybackUpdate = (ev: PlaybackState) => {
|
|
||||||
this.setState({ playbackPhase: ev });
|
|
||||||
};
|
|
||||||
|
|
||||||
private onKeyDown = (ev: React.KeyboardEvent) => {
|
private onKeyDown = (ev: React.KeyboardEvent) => {
|
||||||
// stopPropagation() prevents the FocusComposer catch-all from triggering,
|
// stopPropagation() prevents the FocusComposer catch-all from triggering,
|
||||||
// but we need to do it on key down instead of press (even though the user
|
// but we need to do it on key down instead of press (even though the user
|
||||||
|
@ -91,10 +55,10 @@ export default class AudioPlayer extends React.PureComponent<IProps, IState> {
|
||||||
return `(${formatBytes(bytes)})`;
|
return `(${formatBytes(bytes)})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(): ReactNode {
|
protected renderComponent(): ReactNode {
|
||||||
// tabIndex=0 to ensure that the whole component becomes a tab stop, where we handle keyboard
|
// tabIndex=0 to ensure that the whole component becomes a tab stop, where we handle keyboard
|
||||||
// events for accessibility
|
// events for accessibility
|
||||||
return <>
|
return (
|
||||||
<div className='mx_MediaBody mx_AudioPlayer_container' tabIndex={0} onKeyDown={this.onKeyDown}>
|
<div className='mx_MediaBody mx_AudioPlayer_container' tabIndex={0} onKeyDown={this.onKeyDown}>
|
||||||
<div className='mx_AudioPlayer_primaryContainer'>
|
<div className='mx_AudioPlayer_primaryContainer'>
|
||||||
<PlayPauseButton
|
<PlayPauseButton
|
||||||
|
@ -124,7 +88,6 @@ export default class AudioPlayer extends React.PureComponent<IProps, IState> {
|
||||||
<PlaybackClock playback={this.props.playback} defaultDisplaySeconds={0} />
|
<PlaybackClock playback={this.props.playback} defaultDisplaySeconds={0} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{ this.state.error && <div className="text-warning">{ _t("Error downloading audio") }</div> }
|
);
|
||||||
</>;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
70
src/components/views/audio_messages/AudioPlayerBase.tsx
Normal file
70
src/components/views/audio_messages/AudioPlayerBase.tsx
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Playback, PlaybackState } from "../../../audio/Playback";
|
||||||
|
import { TileShape } from "../rooms/EventTile";
|
||||||
|
import React, { ReactNode } from "react";
|
||||||
|
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
|
||||||
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import { _t } from "../../../languageHandler";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
// Playback instance to render. Cannot change during component lifecycle: create
|
||||||
|
// an all-new component instead.
|
||||||
|
playback: Playback;
|
||||||
|
|
||||||
|
mediaName?: string;
|
||||||
|
tileShape?: TileShape;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
playbackPhase: PlaybackState;
|
||||||
|
error?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
@replaceableComponent("views.audio_messages.AudioPlayerBase")
|
||||||
|
export default abstract class AudioPlayerBase extends React.PureComponent<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
playbackPhase: PlaybackState.Decoding, // default assumption
|
||||||
|
};
|
||||||
|
|
||||||
|
// We don't need to de-register: the class handles this for us internally
|
||||||
|
this.props.playback.on(UPDATE_EVENT, this.onPlaybackUpdate);
|
||||||
|
|
||||||
|
// Don't wait for the promise to complete - it will emit a progress update when it
|
||||||
|
// is done, and it's not meant to take long anyhow.
|
||||||
|
this.props.playback.prepare().catch(e => {
|
||||||
|
console.error("Error processing audio file:", e);
|
||||||
|
this.setState({ error: true });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private onPlaybackUpdate = (ev: PlaybackState) => {
|
||||||
|
this.setState({ playbackPhase: ev });
|
||||||
|
};
|
||||||
|
|
||||||
|
protected abstract renderComponent(): ReactNode;
|
||||||
|
|
||||||
|
public render(): ReactNode {
|
||||||
|
return <>
|
||||||
|
{ this.renderComponent() }
|
||||||
|
{ this.state.error && <div className="text-warning">{ _t("Error downloading audio") }</div> }
|
||||||
|
</>;
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import Clock from "./Clock";
|
import Clock from "./Clock";
|
||||||
import { Playback } from "../../../voice/Playback";
|
import { Playback } from "../../../audio/Playback";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
playback: Playback;
|
playback: Playback;
|
||||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { IRecordingUpdate, VoiceRecording } from "../../../voice/VoiceRecording";
|
import { IRecordingUpdate, VoiceRecording } from "../../../audio/VoiceRecording";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import Clock from "./Clock";
|
import Clock from "./Clock";
|
||||||
import { MarkedExecution } from "../../../utils/MarkedExecution";
|
import { MarkedExecution } from "../../../utils/MarkedExecution";
|
||||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { IRecordingUpdate, RECORDING_PLAYBACK_SAMPLES, VoiceRecording } from "../../../voice/VoiceRecording";
|
import { IRecordingUpdate, RECORDING_PLAYBACK_SAMPLES, VoiceRecording } from "../../../audio/VoiceRecording";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { arrayFastResample } from "../../../utils/arrays";
|
import { arrayFastResample } from "../../../utils/arrays";
|
||||||
import { percentageOf } from "../../../utils/numbers";
|
import { percentageOf } from "../../../utils/numbers";
|
||||||
|
|
|
@ -18,7 +18,7 @@ import React, { ReactNode } from "react";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import { Playback, PlaybackState } from "../../../voice/Playback";
|
import { Playback, PlaybackState } from "../../../audio/Playback";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
// omitted props are handled by render function
|
// omitted props are handled by render function
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import Clock from "./Clock";
|
import Clock from "./Clock";
|
||||||
import { Playback, PlaybackState } from "../../../voice/Playback";
|
import { Playback, PlaybackState } from "../../../audio/Playback";
|
||||||
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
|
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
|
|
|
@ -18,7 +18,7 @@ import React from "react";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { arraySeed, arrayTrimFill } from "../../../utils/arrays";
|
import { arraySeed, arrayTrimFill } from "../../../utils/arrays";
|
||||||
import Waveform from "./Waveform";
|
import Waveform from "./Waveform";
|
||||||
import { Playback, PLAYBACK_WAVEFORM_SAMPLES } from "../../../voice/Playback";
|
import { Playback, PLAYBACK_WAVEFORM_SAMPLES } from "../../../audio/Playback";
|
||||||
import { percentageOf } from "../../../utils/numbers";
|
import { percentageOf } from "../../../utils/numbers";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
|
|
|
@ -14,68 +14,30 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Playback, PlaybackState } from "../../../voice/Playback";
|
|
||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from "react";
|
||||||
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
|
|
||||||
import PlayPauseButton from "./PlayPauseButton";
|
import PlayPauseButton from "./PlayPauseButton";
|
||||||
import PlaybackClock from "./PlaybackClock";
|
import PlaybackClock from "./PlaybackClock";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { TileShape } from "../rooms/EventTile";
|
import { TileShape } from "../rooms/EventTile";
|
||||||
import PlaybackWaveform from "./PlaybackWaveform";
|
import PlaybackWaveform from "./PlaybackWaveform";
|
||||||
import { _t } from "../../../languageHandler";
|
import AudioPlayerBase from "./AudioPlayerBase";
|
||||||
|
|
||||||
interface IProps {
|
|
||||||
// Playback instance to render. Cannot change during component lifecycle: create
|
|
||||||
// an all-new component instead.
|
|
||||||
playback: Playback;
|
|
||||||
|
|
||||||
tileShape?: TileShape;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IState {
|
|
||||||
playbackPhase: PlaybackState;
|
|
||||||
error?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
@replaceableComponent("views.audio_messages.RecordingPlayback")
|
@replaceableComponent("views.audio_messages.RecordingPlayback")
|
||||||
export default class RecordingPlayback extends React.PureComponent<IProps, IState> {
|
export default class RecordingPlayback extends AudioPlayerBase {
|
||||||
constructor(props: IProps) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
playbackPhase: PlaybackState.Decoding, // default assumption
|
|
||||||
};
|
|
||||||
|
|
||||||
// We don't need to de-register: the class handles this for us internally
|
|
||||||
this.props.playback.on(UPDATE_EVENT, this.onPlaybackUpdate);
|
|
||||||
|
|
||||||
// Don't wait for the promise to complete - it will emit a progress update when it
|
|
||||||
// is done, and it's not meant to take long anyhow.
|
|
||||||
this.props.playback.prepare().catch(e => {
|
|
||||||
console.error("Error processing audio file:", e);
|
|
||||||
this.setState({ error: true });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private get isWaveformable(): boolean {
|
private get isWaveformable(): boolean {
|
||||||
return this.props.tileShape !== TileShape.Notif
|
return this.props.tileShape !== TileShape.Notif
|
||||||
&& this.props.tileShape !== TileShape.FileGrid
|
&& this.props.tileShape !== TileShape.FileGrid
|
||||||
&& this.props.tileShape !== TileShape.Pinned;
|
&& this.props.tileShape !== TileShape.Pinned;
|
||||||
}
|
}
|
||||||
|
|
||||||
private onPlaybackUpdate = (ev: PlaybackState) => {
|
protected renderComponent(): ReactNode {
|
||||||
this.setState({ playbackPhase: ev });
|
|
||||||
};
|
|
||||||
|
|
||||||
public render(): ReactNode {
|
|
||||||
const shapeClass = !this.isWaveformable ? 'mx_VoiceMessagePrimaryContainer_noWaveform' : '';
|
const shapeClass = !this.isWaveformable ? 'mx_VoiceMessagePrimaryContainer_noWaveform' : '';
|
||||||
return <>
|
return (
|
||||||
<div className={'mx_MediaBody mx_VoiceMessagePrimaryContainer ' + shapeClass}>
|
<div className={'mx_MediaBody mx_VoiceMessagePrimaryContainer ' + shapeClass}>
|
||||||
<PlayPauseButton playback={this.props.playback} playbackPhase={this.state.playbackPhase} />
|
<PlayPauseButton playback={this.props.playback} playbackPhase={this.state.playbackPhase} />
|
||||||
<PlaybackClock playback={this.props.playback} />
|
<PlaybackClock playback={this.props.playback} />
|
||||||
{ this.isWaveformable && <PlaybackWaveform playback={this.props.playback} /> }
|
{ this.isWaveformable && <PlaybackWaveform playback={this.props.playback} /> }
|
||||||
</div>
|
</div>
|
||||||
{ this.state.error && <div className="text-warning">{ _t("Error downloading audio") }</div> }
|
);
|
||||||
</>;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Playback, PlaybackState } from "../../../voice/Playback";
|
import { Playback, PlaybackState } from "../../../audio/Playback";
|
||||||
import React, { ChangeEvent, CSSProperties, ReactNode } from "react";
|
import React, { ChangeEvent, CSSProperties, ReactNode } from "react";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { MarkedExecution } from "../../../utils/MarkedExecution";
|
import { MarkedExecution } from "../../../utils/MarkedExecution";
|
||||||
|
|
|
@ -16,14 +16,14 @@ limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { Playback } from "../../../voice/Playback";
|
import { Playback } from "../../../audio/Playback";
|
||||||
import InlineSpinner from '../elements/InlineSpinner';
|
import InlineSpinner from '../elements/InlineSpinner';
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import AudioPlayer from "../audio_messages/AudioPlayer";
|
import AudioPlayer from "../audio_messages/AudioPlayer";
|
||||||
import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent";
|
import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent";
|
||||||
import MFileBody from "./MFileBody";
|
import MFileBody from "./MFileBody";
|
||||||
import { IBodyProps } from "./IBodyProps";
|
import { IBodyProps } from "./IBodyProps";
|
||||||
import { PlaybackManager } from "../../../voice/PlaybackManager";
|
import { PlaybackManager } from "../../../audio/PlaybackManager";
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
error?: Error;
|
error?: Error;
|
||||||
|
@ -76,7 +76,6 @@ export default class MAudioBody extends React.PureComponent<IBodyProps, IState>
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
if (this.state.error) {
|
if (this.state.error) {
|
||||||
// TODO: @@TR: Verify error state
|
|
||||||
return (
|
return (
|
||||||
<span className="mx_MAudioBody">
|
<span className="mx_MAudioBody">
|
||||||
<img src={require("../../../../res/img/warning.svg")} width="16" height="16" />
|
<img src={require("../../../../res/img/warning.svg")} width="16" height="16" />
|
||||||
|
@ -86,7 +85,6 @@ export default class MAudioBody extends React.PureComponent<IBodyProps, IState>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.state.playback) {
|
if (!this.state.playback) {
|
||||||
// TODO: @@TR: Verify loading/decrypting state
|
|
||||||
return (
|
return (
|
||||||
<span className="mx_MAudioBody">
|
<span className="mx_MAudioBody">
|
||||||
<InlineSpinner />
|
<InlineSpinner />
|
||||||
|
|
|
@ -27,7 +27,6 @@ export default class MVoiceMessageBody extends MAudioBody {
|
||||||
// A voice message is an audio file but rendered in a special way.
|
// A voice message is an audio file but rendered in a special way.
|
||||||
public render() {
|
public render() {
|
||||||
if (this.state.error) {
|
if (this.state.error) {
|
||||||
// TODO: @@TR: Verify error state
|
|
||||||
return (
|
return (
|
||||||
<span className="mx_MVoiceMessageBody">
|
<span className="mx_MVoiceMessageBody">
|
||||||
<img src={require("../../../../res/img/warning.svg")} width="16" height="16" />
|
<img src={require("../../../../res/img/warning.svg")} width="16" height="16" />
|
||||||
|
@ -37,7 +36,6 @@ export default class MVoiceMessageBody extends MAudioBody {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.state.playback) {
|
if (!this.state.playback) {
|
||||||
// TODO: @@TR: Verify loading/decrypting state
|
|
||||||
return (
|
return (
|
||||||
<span className="mx_MVoiceMessageBody">
|
<span className="mx_MVoiceMessageBody">
|
||||||
<InlineSpinner />
|
<InlineSpinner />
|
||||||
|
|
|
@ -35,7 +35,7 @@ import { UPDATE_EVENT } from "../../../stores/AsyncStore";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import VoiceRecordComposerTile from "./VoiceRecordComposerTile";
|
import VoiceRecordComposerTile from "./VoiceRecordComposerTile";
|
||||||
import { VoiceRecordingStore } from "../../../stores/VoiceRecordingStore";
|
import { VoiceRecordingStore } from "../../../stores/VoiceRecordingStore";
|
||||||
import { RecordingState } from "../../../voice/VoiceRecording";
|
import { RecordingState } from "../../../audio/VoiceRecording";
|
||||||
import Tooltip, { Alignment } from "../elements/Tooltip";
|
import Tooltip, { Alignment } from "../elements/Tooltip";
|
||||||
import ResizeNotifier from "../../../utils/ResizeNotifier";
|
import ResizeNotifier from "../../../utils/ResizeNotifier";
|
||||||
import { E2EStatus } from '../../../utils/ShieldUtils';
|
import { E2EStatus } from '../../../utils/ShieldUtils';
|
||||||
|
|
|
@ -20,7 +20,7 @@ import React, { ReactNode } from "react";
|
||||||
import {
|
import {
|
||||||
RecordingState,
|
RecordingState,
|
||||||
VoiceRecording,
|
VoiceRecording,
|
||||||
} from "../../../voice/VoiceRecording";
|
} from "../../../audio/VoiceRecording";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
@ -189,7 +189,6 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
||||||
if (!this.state.recorder) return null; // no recorder means we're not recording: no waveform
|
if (!this.state.recorder) return null; // no recorder means we're not recording: no waveform
|
||||||
|
|
||||||
if (this.state.recordingPhase !== RecordingState.Started) {
|
if (this.state.recordingPhase !== RecordingState.Started) {
|
||||||
// TODO: @@ TR: Should we disable this during upload? What does a failed upload look like?
|
|
||||||
return <RecordingPlayback playback={this.state.recorder.getPlayback()} />;
|
return <RecordingPlayback playback={this.state.recorder.getPlayback()} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import { AsyncStoreWithClient } from "./AsyncStoreWithClient";
|
import { AsyncStoreWithClient } from "./AsyncStoreWithClient";
|
||||||
import defaultDispatcher from "../dispatcher/dispatcher";
|
import defaultDispatcher from "../dispatcher/dispatcher";
|
||||||
import { ActionPayload } from "../dispatcher/payloads";
|
import { ActionPayload } from "../dispatcher/payloads";
|
||||||
import { VoiceRecording } from "../voice/VoiceRecording";
|
import { VoiceRecording } from "../audio/VoiceRecording";
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
recording?: VoiceRecording;
|
recording?: VoiceRecording;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue