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

Enable reactions and replies for broadcasts #9856

Merged
merged 1 commit into from
Jan 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/components/views/messages/MessageActionBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import { Action } from "../../../dispatcher/actions";
import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload";
import useFavouriteMessages from "../../../hooks/useFavouriteMessages";
import { GetRelationsForEvent } from "../rooms/EventTile";
import { VoiceBroadcastInfoEventType } from "../../../voice-broadcast/types";

interface IOptionsButtonProps {
mxEvent: MatrixEvent;
Expand Down Expand Up @@ -394,7 +395,8 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
* until cross-platform support
* (PSF-1041)
*/
!M_BEACON_INFO.matches(this.props.mxEvent.getType());
!M_BEACON_INFO.matches(this.props.mxEvent.getType()) &&
!(this.props.mxEvent.getType() === VoiceBroadcastInfoEventType);

return inNotThreadTimeline && isAllowedMessageType;
}
Expand Down
3 changes: 3 additions & 0 deletions src/events/forward/getForwardableEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { MatrixEvent, MatrixClient } from "matrix-js-sdk/src/matrix";

import { getShareableLocationEventForBeacon } from "../../utils/beacon/getShareableLocation";
import { VoiceBroadcastInfoEventType } from "../../voice-broadcast/types";

/**
* Get forwardable event for a given event
Expand All @@ -29,6 +30,8 @@ export const getForwardableEvent = (event: MatrixEvent, cli: MatrixClient): Matr
return null;
}

if (event.getType() === VoiceBroadcastInfoEventType) return null;

// Live location beacons should forward their latest location as a static pin location
// If the beacon is not live, or doesn't have a location forwarding is not allowed
if (M_BEACON_INFO.matches(event.getType())) {
Expand Down
5 changes: 4 additions & 1 deletion src/utils/EventUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { TimelineRenderingType } from "../contexts/RoomContext";
import { launchPollEditor } from "../components/views/messages/MPollBody";
import { Action } from "../dispatcher/actions";
import { ViewRoomPayload } from "../dispatcher/payloads/ViewRoomPayload";
import { VoiceBroadcastInfoEventType, VoiceBroadcastInfoState } from "../voice-broadcast/types";

/**
* Returns whether an event should allow actions like reply, reactions, edit, etc.
Expand All @@ -56,7 +57,9 @@ export function isContentActionable(mxEvent: MatrixEvent): boolean {
} else if (
mxEvent.getType() === "m.sticker" ||
M_POLL_START.matches(mxEvent.getType()) ||
M_BEACON_INFO.matches(mxEvent.getType())
M_BEACON_INFO.matches(mxEvent.getType()) ||
(mxEvent.getType() === VoiceBroadcastInfoEventType &&
mxEvent.getContent()?.state === VoiceBroadcastInfoState.Started)
) {
return true;
}
Expand Down
16 changes: 14 additions & 2 deletions test/components/views/context_menus/MessageContextMenu-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,15 @@ import dispatcher from "../../../../src/dispatcher/dispatcher";
import SettingsStore from "../../../../src/settings/SettingsStore";
import { ReadPinsEventId } from "../../../../src/components/views/right_panel/types";
import { Action } from "../../../../src/dispatcher/actions";
import { mkVoiceBroadcastInfoStateEvent } from "../../../voice-broadcast/utils/test-utils";
import { VoiceBroadcastInfoState } from "../../../../src/voice-broadcast";

jest.mock("../../../../src/utils/strings", () => ({
copyPlaintext: jest.fn(),
getSelectedText: jest.fn(),
}));
jest.mock("../../../../src/utils/EventUtils", () => ({
// @ts-ignore don't mock everything
...jest.requireActual("../../../../src/utils/EventUtils"),
...(jest.requireActual("../../../../src/utils/EventUtils") as object),
canEditContent: jest.fn(),
}));
jest.mock("../../../../src/dispatcher/dispatcher");
Expand Down Expand Up @@ -241,6 +242,17 @@ describe("MessageContextMenu", () => {
expect(menu.find('div[aria-label="Forward"]')).toHaveLength(0);
});

it("should not allow forwarding a voice broadcast", () => {
const broadcastStartEvent = mkVoiceBroadcastInfoStateEvent(
roomId,
VoiceBroadcastInfoState.Started,
"@user:example.com",
"ABC123",
);
const menu = createMenu(broadcastStartEvent);
expect(menu.find('div[aria-label="Forward"]')).toHaveLength(0);
});

describe("forwarding beacons", () => {
const aliceId = "@alice:server.org";

Expand Down
16 changes: 14 additions & 2 deletions test/components/views/messages/MessageActionBar-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ limitations under the License.
*/

import React from "react";
import { render, fireEvent } from "@testing-library/react";
import { act } from "react-test-renderer";
import { act, render, fireEvent } from "@testing-library/react";
import { EventType, EventStatus, MatrixEvent, MatrixEventEvent, MsgType, Room } from "matrix-js-sdk/src/matrix";
import { FeatureSupport, Thread } from "matrix-js-sdk/src/models/thread";

Expand All @@ -34,6 +33,8 @@ import dispatcher from "../../../../src/dispatcher/dispatcher";
import SettingsStore from "../../../../src/settings/SettingsStore";
import { Action } from "../../../../src/dispatcher/actions";
import { UserTab } from "../../../../src/components/views/dialogs/UserTab";
import { mkVoiceBroadcastInfoStateEvent } from "../../../voice-broadcast/utils/test-utils";
import { VoiceBroadcastInfoState } from "../../../../src/voice-broadcast";

jest.mock("../../../../src/dispatcher/dispatcher");

Expand Down Expand Up @@ -405,6 +406,17 @@ describe("<MessageActionBar />", () => {
expect(queryByLabelText("Reply in thread")).toBeTruthy();
});

it("does not render thread button for a voice broadcast", () => {
const broadcastEvent = mkVoiceBroadcastInfoStateEvent(
roomId,
VoiceBroadcastInfoState.Started,
userId,
"ABC123",
);
const { queryByLabelText } = getComponent({ mxEvent: broadcastEvent });
expect(queryByLabelText("Reply in thread")).not.toBeInTheDocument();
});

it("opens user settings on click", () => {
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
const { getByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
Expand Down
18 changes: 18 additions & 0 deletions test/utils/EventUtils-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import {
import { getMockClientWithEventEmitter, makeBeaconInfoEvent, makePollStartEvent, stubClient } from "../test-utils";
import dis from "../../src/dispatcher/dispatcher";
import { Action } from "../../src/dispatcher/actions";
import { mkVoiceBroadcastInfoStateEvent } from "../voice-broadcast/utils/test-utils";
import { VoiceBroadcastInfoState } from "../../src/voice-broadcast/types";

jest.mock("../../src/dispatcher/dispatcher");

Expand Down Expand Up @@ -151,6 +153,20 @@ describe("EventUtils", () => {
},
});

const voiceBroadcastStart = mkVoiceBroadcastInfoStateEvent(
"!room:example.com",
VoiceBroadcastInfoState.Started,
"@user:example.com",
"ABC123",
);

const voiceBroadcastStop = mkVoiceBroadcastInfoStateEvent(
"!room:example.com",
VoiceBroadcastInfoState.Stopped,
"@user:example.com",
"ABC123",
);

describe("isContentActionable()", () => {
type TestCase = [string, MatrixEvent];
it.each<TestCase>([
Expand All @@ -161,6 +177,7 @@ describe("EventUtils", () => {
["room member event", roomMemberEvent],
["event without msgtype", noMsgType],
["event without content body property", noContentBody],
["broadcast stop event", voiceBroadcastStop],
])("returns false for %s", (_description, event) => {
expect(isContentActionable(event)).toBe(false);
});
Expand All @@ -171,6 +188,7 @@ describe("EventUtils", () => {
["event with empty content body", emptyContentBody],
["event with a content body", niceTextMessage],
["beacon_info event", beaconInfoEvent],
["broadcast start event", voiceBroadcastStart],
])("returns true for %s", (_description, event) => {
expect(isContentActionable(event)).toBe(true);
});
Expand Down
2 changes: 1 addition & 1 deletion test/voice-broadcast/utils/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
VoiceBroadcastChunkEventType,
VoiceBroadcastInfoEventType,
VoiceBroadcastInfoState,
} from "../../../src/voice-broadcast";
} from "../../../src/voice-broadcast/types";
import { mkEvent } from "../../test-utils";

// timestamp incremented on each call to prevent duplicate timestamp
Expand Down