mirror of https://github.com/vector-im/riot-web
Support for sending voice messages as replies and in threads (#9097)
* Support for sending voice messages as replies and in threads Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com> * Add tests Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>pull/28217/head
parent
b4b146f551
commit
60696d78ca
|
@ -71,26 +71,27 @@ describe("Timeline", () => {
|
|||
let oldAvatarUrl: string;
|
||||
let newAvatarUrl: string;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.startSynapse("default").then(data => {
|
||||
synapse = data;
|
||||
cy.initTestUser(synapse, OLD_NAME).then(() =>
|
||||
cy.window({ log: false }).then(() => {
|
||||
cy.createRoom({ name: ROOM_NAME }).then(_room1Id => {
|
||||
roomId = _room1Id;
|
||||
});
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("useOnlyCurrentProfiles", () => {
|
||||
beforeEach(() => {
|
||||
cy.startSynapse("default").then(data => {
|
||||
synapse = data;
|
||||
cy.initTestUser(synapse, OLD_NAME).then(() =>
|
||||
cy.window({ log: false }).then(() => {
|
||||
cy.createRoom({ name: ROOM_NAME }).then(_room1Id => {
|
||||
roomId = _room1Id;
|
||||
});
|
||||
}),
|
||||
).then(() => {
|
||||
cy.uploadContent(OLD_AVATAR).then((url) => {
|
||||
oldAvatarUrl = url;
|
||||
cy.setAvatarUrl(url);
|
||||
});
|
||||
}).then(() => {
|
||||
cy.uploadContent(NEW_AVATAR).then((url) => {
|
||||
newAvatarUrl = url;
|
||||
});
|
||||
});
|
||||
cy.uploadContent(OLD_AVATAR).then((url) => {
|
||||
oldAvatarUrl = url;
|
||||
cy.setAvatarUrl(url);
|
||||
});
|
||||
cy.uploadContent(NEW_AVATAR).then((url) => {
|
||||
newAvatarUrl = url;
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -142,7 +143,9 @@ describe("Timeline", () => {
|
|||
expectAvatar(e, newAvatarUrl);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("message displaying", () => {
|
||||
it("should create and configure a room on IRC layout", () => {
|
||||
cy.visit("/#/room/" + roomId);
|
||||
cy.setSettingValue("layout", null, SettingLevel.DEVICE, Layout.IRC);
|
||||
|
@ -216,4 +219,45 @@ describe("Timeline", () => {
|
|||
cy.get(".mx_GenericEventListSummary_toggle[aria-expanded=false]");
|
||||
});
|
||||
});
|
||||
|
||||
describe("message sending", () => {
|
||||
const MESSAGE = "Hello world";
|
||||
const viewRoomSendMessageAndSetupReply = () => {
|
||||
// View room
|
||||
cy.visit("/#/room/" + roomId);
|
||||
|
||||
// Send a message
|
||||
cy.getComposer().type(`${MESSAGE}{enter}`);
|
||||
|
||||
// Reply to the message
|
||||
cy.get(".mx_RoomView_body .mx_EventTile").contains(".mx_EventTile_line", "Hello world").within(() => {
|
||||
cy.get('[aria-label="Reply"]').click({ force: true }); // Cypress has no ability to hover
|
||||
});
|
||||
};
|
||||
|
||||
it("can reply with a text message", () => {
|
||||
const reply = "Reply";
|
||||
viewRoomSendMessageAndSetupReply();
|
||||
|
||||
cy.getComposer().type(`${reply}{enter}`);
|
||||
|
||||
cy.get(".mx_RoomView_body .mx_EventTile .mx_EventTile_line").find(".mx_ReplyTile .mx_MTextBody")
|
||||
.should("contain", MESSAGE);
|
||||
cy.get(".mx_RoomView_body .mx_EventTile > .mx_EventTile_line > .mx_MTextBody").contains(reply)
|
||||
.should("have.length", 1);
|
||||
});
|
||||
|
||||
it("can reply with a voice message", () => {
|
||||
viewRoomSendMessageAndSetupReply();
|
||||
|
||||
cy.openMessageComposerOptions().find(`[aria-label="Voice Message"]`).click();
|
||||
cy.wait(3000);
|
||||
cy.getComposer().find(".mx_MessageComposer_sendMessage").click();
|
||||
|
||||
cy.get(".mx_RoomView_body .mx_EventTile .mx_EventTile_line").find(".mx_ReplyTile .mx_MTextBody")
|
||||
.should("contain", MESSAGE);
|
||||
cy.get(".mx_RoomView_body .mx_EventTile > .mx_EventTile_line > .mx_MVoiceMessageBody")
|
||||
.should("have.length", 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -213,6 +213,34 @@ describe("Threads", () => {
|
|||
.should("contain", "I'm very good thanks :)");
|
||||
});
|
||||
|
||||
it("can send voice messages", () => {
|
||||
// Increase viewport size and right-panel size, so that voice messages fit
|
||||
cy.viewport(1280, 720);
|
||||
cy.window().then((window) => {
|
||||
window.localStorage.setItem("mx_rhs_size", "600");
|
||||
});
|
||||
|
||||
let roomId: string;
|
||||
cy.createRoom({}).then(_roomId => {
|
||||
roomId = _roomId;
|
||||
cy.visit("/#/room/" + roomId);
|
||||
});
|
||||
|
||||
// Send message
|
||||
cy.get(".mx_RoomView_body .mx_BasicMessageComposer_input").type("Hello Mr. Bot{enter}");
|
||||
|
||||
// Create thread
|
||||
cy.get(".mx_RoomView_body .mx_EventTile").contains(".mx_EventTile[data-scroll-tokens]", "Hello Mr. Bot")
|
||||
.realHover().find(".mx_MessageActionBar_threadButton").click();
|
||||
cy.get(".mx_ThreadView_timelinePanelWrapper").should("have.length", 1);
|
||||
|
||||
cy.openMessageComposerOptions(true).find(`[aria-label="Voice Message"]`).click();
|
||||
cy.wait(3000);
|
||||
cy.getComposer(true).find(".mx_MessageComposer_sendMessage").click();
|
||||
|
||||
cy.get(".mx_ThreadView .mx_MVoiceMessageBody").should("have.length", 1);
|
||||
});
|
||||
|
||||
it("right panel behaves correctly", () => {
|
||||
// Create room
|
||||
let roomId: string;
|
||||
|
|
|
@ -383,7 +383,10 @@ export default class MessageComposer extends React.Component<IProps, IState> {
|
|||
controls.push(<VoiceRecordComposerTile
|
||||
key="controls_voice_record"
|
||||
ref={this.voiceRecordingButton}
|
||||
room={this.props.room} />);
|
||||
room={this.props.room}
|
||||
permalinkCreator={this.props.permalinkCreator}
|
||||
relation={this.props.relation}
|
||||
replyToEvent={this.props.replyToEvent} />);
|
||||
} else if (this.context.tombstone) {
|
||||
const replacementRoomId = this.context.tombstone.getContent()['replacement_room'];
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import { Room } from "matrix-js-sdk/src/models/room";
|
|||
import { MsgType } from "matrix-js-sdk/src/@types/event";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { Optional } from "matrix-events-sdk";
|
||||
import { IEventRelation, MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
|
||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||
import { _t } from "../../../languageHandler";
|
||||
|
@ -38,9 +39,17 @@ import { NotificationColor } from "../../../stores/notifications/NotificationCol
|
|||
import InlineSpinner from "../elements/InlineSpinner";
|
||||
import { PlaybackManager } from "../../../audio/PlaybackManager";
|
||||
import { doMaybeLocalRoomAction } from "../../../utils/local-room";
|
||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||
import { attachRelation } from "./SendMessageComposer";
|
||||
import { addReplyToMessageContent } from "../../../utils/Reply";
|
||||
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
|
||||
import RoomContext from "../../../contexts/RoomContext";
|
||||
|
||||
interface IProps {
|
||||
room: Room;
|
||||
permalinkCreator?: RoomPermalinkCreator;
|
||||
relation?: IEventRelation;
|
||||
replyToEvent?: MatrixEvent;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
|
@ -53,7 +62,10 @@ interface IState {
|
|||
* Container tile for rendering the voice message recorder in the composer.
|
||||
*/
|
||||
export default class VoiceRecordComposerTile extends React.PureComponent<IProps, IState> {
|
||||
public constructor(props) {
|
||||
static contextType = RoomContext;
|
||||
public context!: React.ContextType<typeof RoomContext>;
|
||||
|
||||
public constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
|
@ -88,6 +100,8 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
|||
throw new Error("No recording started - cannot send anything");
|
||||
}
|
||||
|
||||
const { replyToEvent, relation, permalinkCreator } = this.props;
|
||||
|
||||
await this.state.recorder.stop();
|
||||
|
||||
let upload: IUpload;
|
||||
|
@ -135,6 +149,21 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
|||
"org.matrix.msc3245.voice": {}, // No content, this is a rendering hint
|
||||
};
|
||||
|
||||
attachRelation(content, relation);
|
||||
if (replyToEvent) {
|
||||
addReplyToMessageContent(content, replyToEvent, {
|
||||
permalinkCreator,
|
||||
includeLegacyFallback: true,
|
||||
});
|
||||
// Clear reply_to_event as we put the message into the queue
|
||||
// if the send fails, retry will handle resending.
|
||||
defaultDispatcher.dispatch({
|
||||
action: 'reply_to_event',
|
||||
event: null,
|
||||
context: this.context.timelineRenderingType,
|
||||
});
|
||||
}
|
||||
|
||||
doMaybeLocalRoomAction(
|
||||
this.props.room.roomId,
|
||||
(actualRoomId: string) => MatrixClientPeg.get().sendMessage(actualRoomId, content),
|
||||
|
|
Loading…
Reference in New Issue