Improve thread partitioning for 2nd degree relations (#7748)
This commit is contained in:
parent
87ca70edb1
commit
15a9303d29
6 changed files with 56 additions and 17 deletions
|
@ -467,6 +467,16 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
// TODO: Implement granular (per-room) hide options
|
// TODO: Implement granular (per-room) hide options
|
||||||
public shouldShowEvent(mxEv: MatrixEvent, forceHideEvents = false): boolean {
|
public shouldShowEvent(mxEv: MatrixEvent, forceHideEvents = false): boolean {
|
||||||
|
if (this.props.hideThreadedMessages && SettingsStore.getValue("feature_thread")) {
|
||||||
|
if (mxEv.isThreadRelation) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.shouldLiveInThreadOnly(mxEv)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (MatrixClientPeg.get().isUserIgnored(mxEv.getSender())) {
|
if (MatrixClientPeg.get().isUserIgnored(mxEv.getSender())) {
|
||||||
return false; // ignored = no show (only happens if the ignore happens after an event was received)
|
return false; // ignored = no show (only happens if the ignore happens after an event was received)
|
||||||
}
|
}
|
||||||
|
@ -482,17 +492,25 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||||
// Always show highlighted event
|
// Always show highlighted event
|
||||||
if (this.props.highlightedEventId === mxEv.getId()) return true;
|
if (this.props.highlightedEventId === mxEv.getId()) return true;
|
||||||
|
|
||||||
// Checking if the message has a "parentEventId" as we do not
|
return !shouldHideEvent(mxEv, this.context);
|
||||||
// want to hide the root event of the thread
|
}
|
||||||
if (mxEv.isThreadRelation &&
|
|
||||||
!mxEv.isThreadRoot &&
|
private shouldLiveInThreadOnly(event: MatrixEvent): boolean {
|
||||||
this.props.hideThreadedMessages &&
|
const associatedId = event.getAssociatedId();
|
||||||
SettingsStore.getValue("feature_thread")
|
|
||||||
) {
|
const targetsThreadRoot = event.threadRootId === associatedId;
|
||||||
|
if (event.isThreadRoot || targetsThreadRoot || !event.isThreadRelation) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !shouldHideEvent(mxEv, this.context);
|
// If this is a reply, then we use the associated event to decide whether
|
||||||
|
// this should be thread only or not
|
||||||
|
const parentEvent = this.props.room.findEventById(associatedId);
|
||||||
|
if (parentEvent) {
|
||||||
|
return this.shouldLiveInThreadOnly(parentEvent);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public readMarkerForEvent(eventId: string, isLastEvent: boolean): ReactNode {
|
public readMarkerForEvent(eventId: string, isLastEvent: boolean): ReactNode {
|
||||||
|
|
|
@ -209,6 +209,7 @@ export interface IRoomState {
|
||||||
wasContextSwitch?: boolean;
|
wasContextSwitch?: boolean;
|
||||||
editState?: EditorStateTransfer;
|
editState?: EditorStateTransfer;
|
||||||
timelineRenderingType: TimelineRenderingType;
|
timelineRenderingType: TimelineRenderingType;
|
||||||
|
threadId?: string;
|
||||||
liveTimeline?: EventTimeline;
|
liveTimeline?: EventTimeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -264,6 +264,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
||||||
<RoomContext.Provider value={{
|
<RoomContext.Provider value={{
|
||||||
...this.context,
|
...this.context,
|
||||||
timelineRenderingType: TimelineRenderingType.Thread,
|
timelineRenderingType: TimelineRenderingType.Thread,
|
||||||
|
threadId: this.state.thread?.id,
|
||||||
liveTimeline: this.state?.thread?.timelineSet?.getLiveTimeline(),
|
liveTimeline: this.state?.thread?.timelineSet?.getLiveTimeline(),
|
||||||
}}>
|
}}>
|
||||||
|
|
||||||
|
|
|
@ -1285,11 +1285,30 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
// should use this list, so that they don't advance into pending events.
|
// should use this list, so that they don't advance into pending events.
|
||||||
const liveEvents = [...events];
|
const liveEvents = [...events];
|
||||||
|
|
||||||
const thread = events[0]?.getThread();
|
|
||||||
|
|
||||||
// if we're at the end of the live timeline, append the pending events
|
// if we're at the end of the live timeline, append the pending events
|
||||||
if (!this.timelineWindow.canPaginate(EventTimeline.FORWARDS)) {
|
if (!this.timelineWindow.canPaginate(EventTimeline.FORWARDS)) {
|
||||||
events.push(...this.props.timelineSet.getPendingEvents(thread));
|
const pendingEvents = this.props.timelineSet.getPendingEvents();
|
||||||
|
if (this.context.timelineRenderingType === TimelineRenderingType.Thread) {
|
||||||
|
events.push(...pendingEvents.filter(e => e.threadRootId === this.context.threadId));
|
||||||
|
} else {
|
||||||
|
events.push(...pendingEvents.filter(e => {
|
||||||
|
const hasNoRelation = !e.getRelation();
|
||||||
|
if (hasNoRelation) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.isThreadRelation) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentEvent = this.props.timelineSet.findEventById(e.getAssociatedId());
|
||||||
|
if (!parentEvent) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return !parentEvent.isThreadRelation;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -649,13 +649,13 @@ export default class EventTile extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderThreadPanelSummary(): JSX.Element | null {
|
private renderThreadPanelSummary(): JSX.Element | null {
|
||||||
if (!this.thread) {
|
if (!this.state.thread) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="mx_ThreadPanel_replies">
|
return <div className="mx_ThreadPanel_replies">
|
||||||
<span className="mx_ThreadPanel_repliesSummary">
|
<span className="mx_ThreadPanel_repliesSummary">
|
||||||
{ this.thread.length }
|
{ this.state.thread.length }
|
||||||
</span>
|
</span>
|
||||||
{ this.renderThreadLastMessagePreview() }
|
{ this.renderThreadLastMessagePreview() }
|
||||||
</div>;
|
</div>;
|
||||||
|
@ -665,7 +665,7 @@ export default class EventTile extends React.Component<IProps, IState> {
|
||||||
const { threadLastReply } = this.state;
|
const { threadLastReply } = this.state;
|
||||||
const threadMessagePreview = MessagePreviewStore.instance.generatePreviewForEvent(threadLastReply);
|
const threadMessagePreview = MessagePreviewStore.instance.generatePreviewForEvent(threadLastReply);
|
||||||
|
|
||||||
const sender = this.thread.roomState.getSentinelMember(threadLastReply.getSender());
|
const sender = this.state.thread?.roomState.getSentinelMember(threadLastReply.getSender());
|
||||||
return <>
|
return <>
|
||||||
<MemberAvatar
|
<MemberAvatar
|
||||||
member={sender}
|
member={sender}
|
||||||
|
@ -689,7 +689,7 @@ export default class EventTile extends React.Component<IProps, IState> {
|
||||||
return (
|
return (
|
||||||
<p className="mx_ThreadSummaryIcon">{ _t("From a thread") }</p>
|
<p className="mx_ThreadSummaryIcon">{ _t("From a thread") }</p>
|
||||||
);
|
);
|
||||||
} else if (this.state.threadReplyCount) {
|
} else if (this.state.threadReplyCount && this.props.mxEvent.isThreadRoot) {
|
||||||
return (
|
return (
|
||||||
<CardContext.Consumer>
|
<CardContext.Consumer>
|
||||||
{ context =>
|
{ context =>
|
||||||
|
@ -1092,11 +1092,10 @@ export default class EventTile extends React.Component<IProps, IState> {
|
||||||
return this.props.getRelationsForEvent(eventId, "m.annotation", "m.reaction");
|
return this.props.getRelationsForEvent(eventId, "m.annotation", "m.reaction");
|
||||||
};
|
};
|
||||||
|
|
||||||
private onReactionsCreated = (relationType: string, eventType: string) => {
|
private onReactionsCreated = (relationType: string, eventType: string): void => {
|
||||||
if (relationType !== "m.annotation" || eventType !== "m.reaction") {
|
if (relationType !== "m.annotation" || eventType !== "m.reaction") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.props.mxEvent.removeListener("Event.relationsCreated", this.onReactionsCreated);
|
|
||||||
this.setState({
|
this.setState({
|
||||||
reactions: this.getReactions(),
|
reactions: this.getReactions(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -63,6 +63,7 @@ const RoomContext = createContext<IRoomState>({
|
||||||
matrixClientIsReady: false,
|
matrixClientIsReady: false,
|
||||||
dragCounter: 0,
|
dragCounter: 0,
|
||||||
timelineRenderingType: TimelineRenderingType.Room,
|
timelineRenderingType: TimelineRenderingType.Room,
|
||||||
|
threadId: undefined,
|
||||||
liveTimeline: undefined,
|
liveTimeline: undefined,
|
||||||
});
|
});
|
||||||
RoomContext.displayName = "RoomContext";
|
RoomContext.displayName = "RoomContext";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue