Use context provided RoomViewStore within the RoomView component hierarchy (#31077)
* Update ContentMessages.ts Update ContentMessages.ts * update PlaybackQueue.ts * Update SpaceHierarchy.tsx * Update ThreadView.tsx * Update RoomCallBanner.tsx * Update useRoomCall.tsx * Update DateSeparator.tsx * Update TimelineCard.tsx * Update UserInfoBasicOptions * Update slask-commands/utils.ts * lint * Update PlaybackQueue, MVoiceMessageBody and UserInfoBasicOptionsView tests. * Update RoomHeader-test.tsx * lint * Add ts docs * Update utils-test.tsx * Update message-test.ts * coverage * lint * Improve naming --------- Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
@@ -20,7 +20,7 @@ import { useCall } from "../../../hooks/useCall";
|
||||
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
|
||||
import { OwnBeaconStore, OwnBeaconStoreEvent } from "../../../stores/OwnBeaconStore";
|
||||
import { SessionDuration } from "../voip/CallDuration";
|
||||
import { SdkContextClass } from "../../../contexts/SDKContext";
|
||||
import { useScopedRoomContext } from "../../../contexts/ScopedRoomContext";
|
||||
|
||||
interface RoomCallBannerProps {
|
||||
roomId: Room["roomId"];
|
||||
@@ -83,7 +83,7 @@ interface Props {
|
||||
|
||||
const RoomCallBanner: React.FC<Props> = ({ roomId }) => {
|
||||
const call = useCall(roomId);
|
||||
|
||||
const { roomViewStore } = useScopedRoomContext("roomViewStore");
|
||||
// this section is to check if we have a live location share. If so, we dont show the call banner
|
||||
const isMonitoringLiveLocation = useEventEmitterState(
|
||||
OwnBeaconStore.instance,
|
||||
@@ -100,7 +100,7 @@ const RoomCallBanner: React.FC<Props> = ({ roomId }) => {
|
||||
}
|
||||
|
||||
// Check if the call is already showing. No banner is needed in this case.
|
||||
if (SdkContextClass.instance.roomViewStore.isViewingCall()) {
|
||||
if (roomViewStore.isViewingCall()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,20 @@ import { type Command, CommandCategories, Commands } from "../../../SlashCommand
|
||||
import InfoDialog from "./InfoDialog";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
|
||||
/**
|
||||
* Props for {@link SlashCommandHelpDialog}
|
||||
* @param roomId - The room ID to check whether commands are enabled
|
||||
* @param onFinished - Callback called when the dialog is closed
|
||||
*/
|
||||
interface IProps {
|
||||
roomId: string;
|
||||
onFinished(): void;
|
||||
}
|
||||
|
||||
const SlashCommandHelpDialog: React.FC<IProps> = ({ onFinished }) => {
|
||||
const SlashCommandHelpDialog: React.FC<IProps> = ({ roomId, onFinished }) => {
|
||||
const categories: Record<string, Command[]> = {};
|
||||
Commands.forEach((cmd) => {
|
||||
if (!cmd.isEnabled(MatrixClientPeg.get())) return;
|
||||
if (!cmd.isEnabled(MatrixClientPeg.get(), roomId)) return;
|
||||
if (!categories[cmd.category]) {
|
||||
categories[cmd.category] = [];
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ import IconizedContextMenu, {
|
||||
} from "../context_menus/IconizedContextMenu";
|
||||
import JumpToDatePicker from "./JumpToDatePicker";
|
||||
import { type ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
|
||||
import { SdkContextClass } from "../../../contexts/SDKContext";
|
||||
import TimelineSeparator from "./TimelineSeparator";
|
||||
import RoomContext from "../../../contexts/RoomContext";
|
||||
|
||||
interface IProps {
|
||||
roomId: string;
|
||||
@@ -51,6 +51,8 @@ interface IState {
|
||||
* Has additional jump to date functionality when labs flag is enabled
|
||||
*/
|
||||
export default class DateSeparator extends React.Component<IProps, IState> {
|
||||
public static contextType = RoomContext;
|
||||
declare public context: React.ContextType<typeof RoomContext>;
|
||||
private settingWatcherRef?: string;
|
||||
|
||||
public constructor(props: IProps) {
|
||||
@@ -143,7 +145,7 @@ export default class DateSeparator extends React.Component<IProps, IState> {
|
||||
// Only try to navigate to the room if the user is still viewing the same
|
||||
// room. We don't want to jump someone back to a room after a slow request
|
||||
// if they've already navigated away to another room.
|
||||
const currentRoomId = SdkContextClass.instance.roomViewStore.getRoomId();
|
||||
const currentRoomId = this.context.roomViewStore.getRoomId();
|
||||
if (currentRoomId === roomIdForJumpRequest) {
|
||||
dispatcher.dispatch<ViewRoomPayload>({
|
||||
action: Action.ViewRoom,
|
||||
@@ -169,7 +171,7 @@ export default class DateSeparator extends React.Component<IProps, IState> {
|
||||
// don't want to worry someone about an error in a room they no longer care
|
||||
// about after a slow request if they've already navigated away to another
|
||||
// room.
|
||||
const currentRoomId = SdkContextClass.instance.roomViewStore.getRoomId();
|
||||
const currentRoomId = this.context.roomViewStore.getRoomId();
|
||||
if (currentRoomId === roomIdForJumpRequest) {
|
||||
let friendlyErrorMessage = "An error occured while trying to find and jump to the given date.";
|
||||
let submitDebugLogsContent: JSX.Element = <></>;
|
||||
|
||||
@@ -17,11 +17,18 @@ import MediaProcessingError from "./shared/MediaProcessingError";
|
||||
import { isVoiceMessage } from "../../../utils/EventUtils";
|
||||
import { PlaybackQueue } from "../../../audio/PlaybackQueue";
|
||||
import { type Playback } from "../../../audio/Playback";
|
||||
import RoomContext from "../../../contexts/RoomContext";
|
||||
|
||||
export default class MVoiceMessageBody extends MAudioBody {
|
||||
public static contextType = RoomContext;
|
||||
declare public context: React.ContextType<typeof RoomContext>;
|
||||
|
||||
protected onMount(playback: Playback): void {
|
||||
if (isVoiceMessage(this.props.mxEvent)) {
|
||||
PlaybackQueue.forRoom(this.props.mxEvent.getRoomId()!).unsortedEnqueue(this.props.mxEvent, playback);
|
||||
PlaybackQueue.forRoom(this.props.mxEvent.getRoomId()!, this.context.roomViewStore).unsortedEnqueue(
|
||||
this.props.mxEvent,
|
||||
playback,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ import JumpToBottomButton from "../rooms/JumpToBottomButton";
|
||||
import { type ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
|
||||
import Measured from "../elements/Measured";
|
||||
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
|
||||
import { SdkContextClass } from "../../../contexts/SDKContext";
|
||||
import { ScopedRoomContextProvider } from "../../../contexts/ScopedRoomContext.tsx";
|
||||
|
||||
interface IProps {
|
||||
@@ -88,7 +87,7 @@ export default class TimelineCard extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
SdkContextClass.instance.roomViewStore.addListener(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
||||
this.context.roomViewStore.addListener(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
this.readReceiptsSettingWatcher = SettingsStore.watchSetting("showReadReceipts", null, (...[, , , value]) =>
|
||||
this.setState({ showReadReceipts: value as boolean }),
|
||||
@@ -99,7 +98,7 @@ export default class TimelineCard extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
SdkContextClass.instance.roomViewStore.removeListener(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
||||
this.context.roomViewStore.removeListener(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
||||
|
||||
SettingsStore.unwatchSetting(this.readReceiptsSettingWatcher);
|
||||
SettingsStore.unwatchSetting(this.layoutWatcherRef);
|
||||
@@ -109,9 +108,9 @@ export default class TimelineCard extends React.Component<IProps, IState> {
|
||||
|
||||
private onRoomViewStoreUpdate = async (_initial?: boolean): Promise<void> => {
|
||||
const newState: Pick<IState, any> = {
|
||||
initialEventId: SdkContextClass.instance.roomViewStore.getInitialEventId(),
|
||||
isInitialEventHighlighted: SdkContextClass.instance.roomViewStore.isInitialEventHighlighted(),
|
||||
replyToEvent: SdkContextClass.instance.roomViewStore.getQuotingEvent(),
|
||||
initialEventId: this.context.roomViewStore.getInitialEventId(),
|
||||
isInitialEventHighlighted: this.context.roomViewStore.isInitialEventHighlighted(),
|
||||
replyToEvent: this.context.roomViewStore.getQuotingEvent(),
|
||||
};
|
||||
|
||||
this.setState(newState);
|
||||
|
||||
@@ -88,7 +88,7 @@ export const UserInfoBasicOptionsView: React.FC<{
|
||||
role="button"
|
||||
onSelect={async (ev) => {
|
||||
ev.preventDefault();
|
||||
vm.onInviteUserButton(ev);
|
||||
vm.onInviteUserButton(room.roomId, ev);
|
||||
}}
|
||||
label={_t("action|invite")}
|
||||
Icon={InviteIcon}
|
||||
|
||||
@@ -244,7 +244,10 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
||||
if (isTyping && this.props.model.parts[0].type === "command") {
|
||||
const { cmd } = parseCommandString(this.props.model.parts[0].text);
|
||||
const command = CommandMap.get(cmd!);
|
||||
if (!command?.isEnabled(MatrixClientPeg.get()) || command.category !== CommandCategories.messages) {
|
||||
if (
|
||||
!command?.isEnabled(MatrixClientPeg.get(), this.props.room.roomId) ||
|
||||
command.category !== CommandCategories.messages
|
||||
) {
|
||||
isTyping = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
||||
if (this.isContentModified(newContent)) {
|
||||
const roomId = editedEvent.getRoomId()!;
|
||||
if (!containsEmote(this.model) && isSlashCommand(this.model)) {
|
||||
const [cmd, args, commandText] = getSlashCommand(this.model);
|
||||
const [cmd, args, commandText] = getSlashCommand(roomId, this.model);
|
||||
if (cmd) {
|
||||
const threadId = editedEvent?.getThread()?.id || null;
|
||||
const [content, commandSuccessful] = await runSlashCommand(
|
||||
|
||||
@@ -170,7 +170,7 @@ interface IUploadButtonProps {
|
||||
// We put the file input outside the UploadButton component so that it doesn't get killed when the context menu closes.
|
||||
const UploadButtonContextProvider: React.FC<IUploadButtonProps> = ({ roomId, relation, children }) => {
|
||||
const cli = useContext(MatrixClientContext);
|
||||
const roomContext = useScopedRoomContext("timelineRenderingType");
|
||||
const roomContext = useScopedRoomContext("timelineRenderingType", "replyToEvent");
|
||||
const uploadInput = useRef<HTMLInputElement>(null);
|
||||
|
||||
const onUploadClick = (): void => {
|
||||
@@ -195,6 +195,7 @@ const UploadButtonContextProvider: React.FC<IUploadButtonProps> = ({ roomId, rel
|
||||
Array.from(ev.target.files!),
|
||||
roomId,
|
||||
relation,
|
||||
roomContext.replyToEvent,
|
||||
cli,
|
||||
roomContext.timelineRenderingType,
|
||||
);
|
||||
|
||||
@@ -356,7 +356,7 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
||||
let content: RoomMessageEventContent | null = null;
|
||||
|
||||
if (!containsEmote(model) && isSlashCommand(this.model)) {
|
||||
const [cmd, args, commandText] = getSlashCommand(this.model);
|
||||
const [cmd, args, commandText] = getSlashCommand(this.props.room.roomId, this.model);
|
||||
if (cmd) {
|
||||
const threadId =
|
||||
this.props.relation?.rel_type === THREAD_RELATION_TYPE.name ? this.props.relation?.event_id : null;
|
||||
@@ -565,6 +565,7 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
||||
Array.from(data.files),
|
||||
this.props.room.roomId,
|
||||
this.props.relation,
|
||||
this.context.replyToEvent,
|
||||
this.props.mxClient,
|
||||
this.context.timelineRenderingType,
|
||||
);
|
||||
|
||||
@@ -148,7 +148,14 @@ export function handleClipboardEvent(
|
||||
// it puts the filename in as text/plain which we want to ignore.
|
||||
if (data.files.length && !data.types.includes("text/rtf")) {
|
||||
ContentMessages.sharedInstance()
|
||||
.sendContentListToRoom(Array.from(data.files), room.roomId, eventRelation, mxClient, timelineRenderingType)
|
||||
.sendContentListToRoom(
|
||||
Array.from(data.files),
|
||||
room.roomId,
|
||||
eventRelation,
|
||||
roomContext.replyToEvent,
|
||||
mxClient,
|
||||
timelineRenderingType,
|
||||
)
|
||||
.catch(handleError);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ export async function sendMessage(
|
||||
// Slash command handling here approximates what can be found in SendMessageComposer.sendMessage()
|
||||
// but note that the /me and // special cases are handled by the call to createMessageContent
|
||||
if (message.startsWith("/") && !message.startsWith("//") && !message.startsWith(EMOTE_PREFIX)) {
|
||||
const { cmd, args } = getCommand(message);
|
||||
const { cmd, args } = getCommand(roomId, message);
|
||||
if (cmd) {
|
||||
const threadId = relation?.rel_type === THREAD_RELATION_TYPE.name ? relation?.event_id : null;
|
||||
let commandSuccessful: boolean;
|
||||
|
||||
Reference in New Issue
Block a user