Add voice broadcast ended message (#9728)
This commit is contained in:
parent
9de5654353
commit
57e1822add
11 changed files with 286 additions and 23 deletions
|
@ -37,15 +37,14 @@ import SettingsStore from "./settings/SettingsStore";
|
|||
import { ALL_RULE_TYPES, ROOM_RULE_TYPES, SERVER_RULE_TYPES, USER_RULE_TYPES } from "./mjolnir/BanList";
|
||||
import { WIDGET_LAYOUT_EVENT_TYPE } from "./stores/widgets/WidgetLayoutStore";
|
||||
import { RightPanelPhases } from './stores/right-panel/RightPanelStorePhases';
|
||||
import { Action } from './dispatcher/actions';
|
||||
import defaultDispatcher from './dispatcher/dispatcher';
|
||||
import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||
import { ROOM_SECURITY_TAB } from "./components/views/dialogs/RoomSettingsDialog";
|
||||
import AccessibleButton from './components/views/elements/AccessibleButton';
|
||||
import RightPanelStore from './stores/right-panel/RightPanelStore';
|
||||
import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
|
||||
import { isLocationEvent } from './utils/EventUtils';
|
||||
import { highlightEvent, isLocationEvent } from './utils/EventUtils';
|
||||
import { ElementCall } from "./models/Call";
|
||||
import { textForVoiceBroadcastStoppedEvent, VoiceBroadcastInfoEventType } from './voice-broadcast';
|
||||
|
||||
export function getSenderName(event: MatrixEvent): string {
|
||||
return event.sender?.name ?? event.getSender() ?? _t("Someone");
|
||||
|
@ -497,16 +496,6 @@ function textForPowerEvent(event: MatrixEvent): () => string | null {
|
|||
});
|
||||
}
|
||||
|
||||
const onPinnedOrUnpinnedMessageClick = (messageId: string, roomId: string): void => {
|
||||
defaultDispatcher.dispatch<ViewRoomPayload>({
|
||||
action: Action.ViewRoom,
|
||||
event_id: messageId,
|
||||
highlighted: true,
|
||||
room_id: roomId,
|
||||
metricsTrigger: undefined, // room doesn't change
|
||||
});
|
||||
};
|
||||
|
||||
const onPinnedMessagesClick = (): void => {
|
||||
RightPanelStore.instance.setCard({ phase: RightPanelPhases.PinnedMessages }, false);
|
||||
};
|
||||
|
@ -533,7 +522,7 @@ function textForPinnedEvent(event: MatrixEvent, allowJSX: boolean): () => Render
|
|||
{ senderName },
|
||||
{
|
||||
"a": (sub) =>
|
||||
<AccessibleButton kind='link_inline' onClick={(e) => onPinnedOrUnpinnedMessageClick(messageId, roomId)}>
|
||||
<AccessibleButton kind='link_inline' onClick={(e) => highlightEvent(roomId, messageId)}>
|
||||
{ sub }
|
||||
</AccessibleButton>,
|
||||
"b": (sub) =>
|
||||
|
@ -561,7 +550,7 @@ function textForPinnedEvent(event: MatrixEvent, allowJSX: boolean): () => Render
|
|||
{ senderName },
|
||||
{
|
||||
"a": (sub) =>
|
||||
<AccessibleButton kind='link_inline' onClick={(e) => onPinnedOrUnpinnedMessageClick(messageId, roomId)}>
|
||||
<AccessibleButton kind='link_inline' onClick={(e) => highlightEvent(roomId, messageId)}>
|
||||
{ sub }
|
||||
</AccessibleButton>,
|
||||
"b": (sub) =>
|
||||
|
@ -765,7 +754,7 @@ function textForPollEndEvent(event: MatrixEvent): () => string | null {
|
|||
});
|
||||
}
|
||||
|
||||
type Renderable = string | JSX.Element | null;
|
||||
type Renderable = string | React.ReactNode | null;
|
||||
|
||||
interface IHandlers {
|
||||
[type: string]:
|
||||
|
@ -801,6 +790,7 @@ const stateHandlers: IHandlers = {
|
|||
// TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
|
||||
'im.vector.modular.widgets': textForWidgetEvent,
|
||||
[WIDGET_LAYOUT_EVENT_TYPE]: textForWidgetLayoutEvent,
|
||||
[VoiceBroadcastInfoEventType]: textForVoiceBroadcastStoppedEvent,
|
||||
};
|
||||
|
||||
// Add all the Mjolnir stuff to the renderer
|
||||
|
@ -832,8 +822,8 @@ export function hasText(ev: MatrixEvent, showHiddenEvents?: boolean): boolean {
|
|||
* to avoid hitting the settings store
|
||||
*/
|
||||
export function textForEvent(ev: MatrixEvent): string;
|
||||
export function textForEvent(ev: MatrixEvent, allowJSX: true, showHiddenEvents?: boolean): string | JSX.Element;
|
||||
export function textForEvent(ev: MatrixEvent, allowJSX = false, showHiddenEvents?: boolean): string | JSX.Element {
|
||||
export function textForEvent(ev: MatrixEvent, allowJSX: true, showHiddenEvents?: boolean): string | React.ReactNode;
|
||||
export function textForEvent(ev: MatrixEvent, allowJSX = false, showHiddenEvents?: boolean): string | React.ReactNode {
|
||||
const handler = (ev.isState() ? stateHandlers : handlers)[ev.getType()];
|
||||
return handler?.(ev, allowJSX, showHiddenEvents)?.() || '';
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ import ViewSourceEvent from "../components/views/messages/ViewSourceEvent";
|
|||
import { shouldDisplayAsBeaconTile } from "../utils/beacon/timeline";
|
||||
import { shouldDisplayAsVoiceBroadcastTile } from "../voice-broadcast/utils/shouldDisplayAsVoiceBroadcastTile";
|
||||
import { ElementCall } from "../models/Call";
|
||||
import { VoiceBroadcastChunkEventType } from "../voice-broadcast";
|
||||
import { shouldDisplayAsVoiceBroadcastStoppedText, VoiceBroadcastChunkEventType } from "../voice-broadcast";
|
||||
|
||||
// Subset of EventTile's IProps plus some mixins
|
||||
export interface EventTileTypeProps {
|
||||
|
@ -232,6 +232,8 @@ export function pickFactory(
|
|||
|
||||
if (shouldDisplayAsVoiceBroadcastTile(mxEvent)) {
|
||||
return MessageEventFactory;
|
||||
} else if (shouldDisplayAsVoiceBroadcastStoppedText(mxEvent)) {
|
||||
return TextualEventFactory;
|
||||
}
|
||||
|
||||
if (SINGULAR_STATE_EVENTS.has(evType) && mxEvent.getStateKey() !== '') {
|
||||
|
|
|
@ -648,6 +648,8 @@
|
|||
"You are already recording a voice broadcast. Please end your current voice broadcast to start a new one.": "You are already recording a voice broadcast. Please end your current voice broadcast to start a new one.",
|
||||
"You don't have the required permissions to start a voice broadcast in this room. Contact a room administrator to upgrade your permissions.": "You don't have the required permissions to start a voice broadcast in this room. Contact a room administrator to upgrade your permissions.",
|
||||
"Someone else is already recording a voice broadcast. Wait for their voice broadcast to end to start a new one.": "Someone else is already recording a voice broadcast. Wait for their voice broadcast to end to start a new one.",
|
||||
"You ended a <a>voice broadcast</a>": "You ended a <a>voice broadcast</a>",
|
||||
"%(senderName)s ended a <a>voice broadcast</a>": "%(senderName)s ended a <a>voice broadcast</a>",
|
||||
"Stop live broadcasting?": "Stop live broadcasting?",
|
||||
"Are you sure you want to stop your live broadcast?This will end the broadcast and the full recording will be available in the room.": "Are you sure you want to stop your live broadcast?This will end the broadcast and the full recording will be available in the room.",
|
||||
"Yes, stop broadcast": "Yes, stop broadcast",
|
||||
|
|
|
@ -31,6 +31,7 @@ import defaultDispatcher from "../dispatcher/dispatcher";
|
|||
import { TimelineRenderingType } from "../contexts/RoomContext";
|
||||
import { launchPollEditor } from "../components/views/messages/MPollBody";
|
||||
import { Action } from "../dispatcher/actions";
|
||||
import { ViewRoomPayload } from '../dispatcher/payloads/ViewRoomPayload';
|
||||
|
||||
/**
|
||||
* Returns whether an event should allow actions like reply, reactions, edit, etc.
|
||||
|
@ -292,3 +293,13 @@ export function hasThreadSummary(event: MatrixEvent): boolean {
|
|||
export function canPinEvent(event: MatrixEvent): boolean {
|
||||
return !M_BEACON_INFO.matches(event.getType());
|
||||
}
|
||||
|
||||
export const highlightEvent = (roomId: string, eventId: string): void => {
|
||||
defaultDispatcher.dispatch<ViewRoomPayload>({
|
||||
action: Action.ViewRoom,
|
||||
event_id: eventId,
|
||||
highlighted: true,
|
||||
room_id: roomId,
|
||||
metricsTrigger: undefined, // room doesn't change
|
||||
});
|
||||
};
|
||||
|
|
|
@ -50,7 +50,9 @@ export * from "./utils/hasRoomLiveVoiceBroadcast";
|
|||
export * from "./utils/findRoomLiveVoiceBroadcastFromUserAndDevice";
|
||||
export * from "./utils/shouldDisplayAsVoiceBroadcastRecordingTile";
|
||||
export * from "./utils/shouldDisplayAsVoiceBroadcastTile";
|
||||
export * from "./utils/shouldDisplayAsVoiceBroadcastStoppedText";
|
||||
export * from "./utils/startNewVoiceBroadcastRecording";
|
||||
export * from "./utils/textForVoiceBroadcastStoppedEvent";
|
||||
export * from "./utils/VoiceBroadcastResumer";
|
||||
|
||||
export const VoiceBroadcastInfoEventType = "io.element.voice_broadcast_info";
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
Copyright 2022 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 { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { VoiceBroadcastInfoEventType, VoiceBroadcastInfoState } from "..";
|
||||
|
||||
export const shouldDisplayAsVoiceBroadcastStoppedText = (event: MatrixEvent): boolean => (
|
||||
event.getType() === VoiceBroadcastInfoEventType
|
||||
&& event.getContent()?.state === VoiceBroadcastInfoState.Stopped
|
||||
&& !event.isRedacted()
|
||||
);
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
Copyright 2022 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 React, { ReactNode } from "react";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
||||
import AccessibleButton from "../../components/views/elements/AccessibleButton";
|
||||
import { highlightEvent } from "../../utils/EventUtils";
|
||||
import { getSenderName } from "../../TextForEvent";
|
||||
import { _t } from "../../languageHandler";
|
||||
|
||||
export const textForVoiceBroadcastStoppedEvent = (event: MatrixEvent): () => ReactNode => {
|
||||
return (): ReactNode => {
|
||||
const ownUserId = MatrixClientPeg.get()?.getUserId();
|
||||
const startEventId = event.getRelation()?.event_id;
|
||||
const roomId = event.getRoomId();
|
||||
|
||||
const templateTags = {
|
||||
a: (text: string) => startEventId && roomId
|
||||
? (
|
||||
<AccessibleButton
|
||||
kind="link_inline"
|
||||
onClick={() => highlightEvent(roomId, startEventId)}
|
||||
>
|
||||
{ text }
|
||||
</AccessibleButton>
|
||||
)
|
||||
: text,
|
||||
};
|
||||
|
||||
if (ownUserId && ownUserId === event.getSender()) {
|
||||
return _t("You ended a <a>voice broadcast</a>", {}, templateTags);
|
||||
}
|
||||
|
||||
return _t(
|
||||
"%(senderName)s ended a <a>voice broadcast</a>",
|
||||
{ senderName: getSenderName(event) },
|
||||
templateTags,
|
||||
);
|
||||
};
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue