diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js
index b7078766fb..283b11a437 100644
--- a/src/components/views/rooms/MessageComposer.js
+++ b/src/components/views/rooms/MessageComposer.js
@@ -34,6 +34,7 @@ import {UPDATE_EVENT} from "../../../stores/AsyncStore";
import ActiveWidgetStore from "../../../stores/ActiveWidgetStore";
import {replaceableComponent} from "../../../utils/replaceableComponent";
import VoiceRecordComposerTile from "./VoiceRecordComposerTile";
+import {VoiceRecordingStore} from "../../../stores/VoiceRecordingStore";
function ComposerAvatar(props) {
const MemberStatusMessageAvatar = sdk.getComponent('avatars.MemberStatusMessageAvatar');
@@ -180,6 +181,7 @@ export default class MessageComposer extends React.Component {
this.renderPlaceholderText = this.renderPlaceholderText.bind(this);
WidgetStore.instance.on(UPDATE_EVENT, this._onWidgetUpdate);
ActiveWidgetStore.on('update', this._onActiveWidgetUpdate);
+ VoiceRecordingStore.instance.on(UPDATE_EVENT, this._onVoiceStoreUpdate);
this._dispatcherRef = null;
this.state = {
@@ -240,6 +242,7 @@ export default class MessageComposer extends React.Component {
}
WidgetStore.instance.removeListener(UPDATE_EVENT, this._onWidgetUpdate);
ActiveWidgetStore.removeListener('update', this._onActiveWidgetUpdate);
+ VoiceRecordingStore.instance.off(UPDATE_EVENT, this._onVoiceStoreUpdate);
dis.unregister(this.dispatcherRef);
}
@@ -327,8 +330,8 @@ export default class MessageComposer extends React.Component {
});
}
- onVoiceUpdate = (haveRecording: boolean) => {
- this.setState({haveRecording});
+ _onVoiceStoreUpdate = () => {
+ this.setState({haveRecording: !!VoiceRecordingStore.instance.activeRecording});
};
render() {
@@ -352,7 +355,6 @@ export default class MessageComposer extends React.Component {
permalinkCreator={this.props.permalinkCreator}
replyToEvent={this.props.replyToEvent}
onChange={this.onChange}
- // TODO: @@ TravisR - Disabling the composer doesn't work
disabled={this.state.haveRecording}
/>,
);
@@ -373,8 +375,7 @@ export default class MessageComposer extends React.Component {
if (SettingsStore.getValue("feature_voice_messages")) {
controls.push();
+ room={this.props.room} />);
}
if (!this.state.isComposerEmpty || this.state.haveRecording) {
diff --git a/src/components/views/rooms/VoiceRecordComposerTile.tsx b/src/components/views/rooms/VoiceRecordComposerTile.tsx
index e83aa8b994..1210a44958 100644
--- a/src/components/views/rooms/VoiceRecordComposerTile.tsx
+++ b/src/components/views/rooms/VoiceRecordComposerTile.tsx
@@ -24,10 +24,10 @@ import classNames from "classnames";
import LiveRecordingWaveform from "../voice_messages/LiveRecordingWaveform";
import {replaceableComponent} from "../../../utils/replaceableComponent";
import LiveRecordingClock from "../voice_messages/LiveRecordingClock";
+import {VoiceRecordingStore} from "../../../stores/VoiceRecordingStore";
interface IProps {
room: Room;
- onRecording: (haveRecording: boolean) => void;
}
interface IState {
@@ -57,13 +57,12 @@ export default class VoiceRecordComposerTile extends React.PureComponent {
+ private static internalInstance: VoiceRecordingStore;
+
+ public constructor() {
+ super(defaultDispatcher, {});
+ }
+
+ /**
+ * Gets the active recording instance, if any.
+ */
+ public get activeRecording(): VoiceRecording | null {
+ return this.state.recording;
+ }
+
+ public static get instance(): VoiceRecordingStore {
+ if (!VoiceRecordingStore.internalInstance) {
+ VoiceRecordingStore.internalInstance = new VoiceRecordingStore();
+ }
+ return VoiceRecordingStore.internalInstance;
+ }
+
+ protected async onAction(payload: ActionPayload): Promise {
+ // Nothing to do, but we're required to override the function
+ return;
+ }
+
+ /**
+ * Starts a new recording if one isn't already in progress. Note that this simply
+ * creates a recording instance - whether or not recording is actively in progress
+ * can be seen via the VoiceRecording class.
+ * @returns {VoiceRecording} The recording.
+ */
+ public startRecording(): VoiceRecording {
+ if (!this.matrixClient) throw new Error("Cannot start a recording without a MatrixClient");
+ if (this.state.recording) throw new Error("A recording is already in progress");
+
+ const recording = new VoiceRecording(this.matrixClient);
+
+ // noinspection JSIgnoredPromiseFromCall - we can safely run this async
+ this.updateState({recording});
+
+ return recording;
+ }
+
+ /**
+ * Disposes of the current recording, no matter the state of it.
+ * @returns {Promise} Resolves when complete.
+ */
+ public disposeRecording(): Promise {
+ if (this.state.recording) {
+ // Stop for good measure, but completely async because we're not concerned with this
+ // passing or failing.
+ this.state.recording.stop().catch(e => console.error("Error stopping recording", e));
+ }
+ return this.updateState({recording: null});
+ }
+}